Fix freezes when trying to accelerate menu bar on Haiku

* src/haiku_support.cc (class EmacsWindow): New field
`menus_begun'.
(MenusBeginning): Don't send menu bar open events when that is
set, instead set it to true.
(BMenuBar_start_tracking): Stop locking the menu bar here and
send a special BE_MENU_BAR_OPEN event instead.
* src/haiku_support.h (struct haiku_menu_bar_state_event):
Delete field `no_lock'.
* src/haikumenu.c (Fhaiku_menu_bar_open):
* src/haikuterm.c (haiku_read_socket): Update accordingly.
This commit is contained in:
Po Lu 2022-04-13 00:47:00 +00:00
parent 33cc12498b
commit 2e0a2ecc29
4 changed files with 70 additions and 48 deletions

View file

@ -87,6 +87,8 @@ enum
WAIT_FOR_RELEASE = 3001,
RELEASE_NOW = 3002,
CANCEL_DROP = 3003,
SHOW_MENU_BAR = 3004,
BE_MENU_BAR_OPEN = 3005,
};
static color_space dpy_color_space = B_NO_COLOR_SPACE;
@ -423,6 +425,7 @@ class EmacsWindow : public BWindow
pthread_cond_t menu_update_cv = PTHREAD_COND_INITIALIZER;
bool menu_updated_p = false;
int window_id;
bool *menus_begun = NULL;
EmacsWindow () : BWindow (BRect (0, 0, 0, 0), "", B_TITLED_WINDOW_LOOK,
B_NORMAL_WINDOW_FEEL, B_NO_SERVER_SIDE_WINDOW_MODIFIERS)
@ -902,19 +905,14 @@ class EmacsWindow : public BWindow
MenusBeginning ()
{
struct haiku_menu_bar_state_event rq;
int lock_count = 0;
thread_id current_thread = find_thread (NULL);
thread_id window_thread = Thread ();
int lock_count;
rq.window = this;
rq.no_lock = false;
lock_count = 0;
if (window_thread != current_thread)
rq.no_lock = true;
haiku_write (MENU_BAR_OPEN, &rq);
if (!rq.no_lock)
if (!menus_begun)
{
haiku_write (MENU_BAR_OPEN, &rq);
while (IsLocked ())
{
++lock_count;
@ -932,6 +930,9 @@ class EmacsWindow : public BWindow
gui_abort ("Failed to lock after cv signal denoting menu update");
}
}
else
*menus_begun = true;
menu_bar_active_p = true;
}
@ -1244,6 +1245,37 @@ class EmacsMenuBar : public BMenuBar
BMenuBar::MouseMoved (point, transit, msg);
}
void
MessageReceived (BMessage *msg)
{
BRect frame;
BPoint pt, l;
EmacsWindow *window;
bool menus_begun;
if (msg->what == SHOW_MENU_BAR)
{
window = (EmacsWindow *) Window ();
frame = Frame ();
pt = frame.LeftTop ();
l = pt;
menus_begun = false;
Parent ()->ConvertToScreen (&pt);
window->menus_begun = &menus_begun;
set_mouse_position (pt.x, pt.y);
MouseDown (l);
window->menus_begun = NULL;
if (!menus_begun)
msg->SendReply (msg);
else
msg->SendReply (BE_MENU_BAR_OPEN);
}
else
BMenuBar::MessageReceived (msg);
}
};
class EmacsView : public BView
@ -3748,20 +3780,18 @@ EmacsWindow_unzoom (void *window)
w->UnZoom ();
}
/* Move the pointer into MBAR and start tracking. */
void
/* Move the pointer into MBAR and start tracking. Return whether the
menu bar was opened correctly. */
bool
BMenuBar_start_tracking (void *mbar)
{
EmacsMenuBar *mb = (EmacsMenuBar *) mbar;
if (!mb->LockLooper ())
gui_abort ("Couldn't lock menubar");
BRect frame = mb->Frame ();
BPoint pt = frame.LeftTop ();
BPoint l = pt;
mb->Parent ()->ConvertToScreen (&pt);
set_mouse_position (pt.x, pt.y);
mb->MouseDown (l);
mb->UnlockLooper ();
BMessenger messenger (mb);
BMessage reply;
messenger.SendMessage (SHOW_MENU_BAR, &reply);
return reply.what == BE_MENU_BAR_OPEN;
}
#ifdef HAVE_NATIVE_IMAGE_API

View file

@ -328,7 +328,6 @@ struct haiku_menu_bar_resize_event
struct haiku_menu_bar_state_event
{
void *window;
bool no_lock;
};
#define HAIKU_THIN 0
@ -869,7 +868,7 @@ extern "C"
be_translate_bitmap_from_memory (const void *buf, size_t bytes);
#endif
extern void
extern bool
BMenuBar_start_tracking (void *mbar);
extern size_t

View file

@ -752,19 +752,24 @@ the position of the last non-menu event instead. */)
(Lisp_Object frame)
{
struct frame *f = decode_window_system_frame (frame);
int rc;
if (FRAME_EXTERNAL_MENU_BAR (f))
{
block_input ();
set_frame_menubar (f, 1);
BMenuBar_start_tracking (FRAME_HAIKU_MENU_BAR (f));
rc = BMenuBar_start_tracking (FRAME_HAIKU_MENU_BAR (f));
unblock_input ();
if (!rc)
return Qnil;
FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 1;
popup_activated_p += 1;
}
else
{
return call2 (Qpopup_menu, call0 (Qmouse_menu_bar_map),
last_nonmenu_event);
}
return call2 (Qpopup_menu, call0 (Qmouse_menu_bar_map),
last_nonmenu_event);
return Qnil;
}

View file

@ -3517,36 +3517,24 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
{
struct haiku_menu_bar_state_event *b = buf;
struct frame *f = haiku_window_to_frame (b->window);
int was_waiting_for_input_p;
if (!f || !FRAME_EXTERNAL_MENU_BAR (f))
continue;
if (type == MENU_BAR_OPEN)
{
/* b->no_lock means that MenusBeginning was called
from the main thread, which means tracking was
started manually, and we have already updated the
menu bar. */
if (!b->no_lock)
{
BView_draw_lock (FRAME_HAIKU_VIEW (f), false, 0, 0, 0, 0);
/* This shouldn't be here, but nsmenu does it, so
it should probably be safe. */
int was_waiting_for_input_p = waiting_for_input;
if (waiting_for_input)
waiting_for_input = 0;
set_frame_menubar (f, 1);
waiting_for_input = was_waiting_for_input_p;
BView_draw_unlock (FRAME_HAIKU_VIEW (f));
}
was_waiting_for_input_p = waiting_for_input;
if (waiting_for_input)
waiting_for_input = 0;
set_frame_menubar (f, 1);
waiting_for_input = was_waiting_for_input_p;
/* But set the flag anyway, because the menu will end
from the window thread. */
FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 1;
popup_activated_p += 1;
if (!b->no_lock)
EmacsWindow_signal_menu_update_complete (b->window);
EmacsWindow_signal_menu_update_complete (b->window);
}
else
{