From 4d342f36a6764aaf33c76d48d19899be621dc59b Mon Sep 17 00:00:00 2001 From: Po Lu Date: Tue, 25 Jan 2022 11:19:20 +0000 Subject: [PATCH] Improve reliability of menu bar updates on Haiku * src/haiku_support.cc (class EmacsWindow): New fields `menu_update_cv', `menu_update_mutex' and `menu_updated_p'. (~EmacsWindow): Destroy cv and mutex. (MenusBeginning): Release lock and wait for condition to be become true. (EmacsWindow_signal_menu_update_complete): New function. * src/haiku_support.h (struct haiku_menu_bar_state_event): New field `no_lock'. * src/haikumenu.c (Fhaiku_menu_bar_open): Always update menu bar. * src/haikuterm.c (haiku_read_socket): Always update menu bar and signal the window thread after update completion. --- src/haiku_support.cc | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/haiku_support.h | 4 ++++ src/haikumenu.c | 5 +---- src/haikuterm.c | 24 ++++++++++++------------ 4 files changed, 61 insertions(+), 16 deletions(-) diff --git a/src/haiku_support.cc b/src/haiku_support.cc index af30bc8b3cb..41e5b71182f 100644 --- a/src/haiku_support.cc +++ b/src/haiku_support.cc @@ -408,6 +408,9 @@ public: window_look pre_override_redirect_style; window_feel pre_override_redirect_feel; uint32 pre_override_redirect_workspaces; + pthread_mutex_t menu_update_mutex = PTHREAD_MUTEX_INITIALIZER; + pthread_cond_t menu_update_cv = PTHREAD_COND_INITIALIZER; + bool menu_updated_p = false; EmacsWindow () : BWindow (BRect (0, 0, 0, 0), "", B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, B_NO_SERVER_SIDE_WINDOW_MODIFIERS) @@ -433,6 +436,9 @@ public: if (this->parent) UnparentAndUnlink (); child_frame_lock.Unlock (); + + pthread_cond_destroy (&menu_update_cv); + pthread_mutex_destroy (&menu_update_mutex); } void @@ -805,9 +811,36 @@ public: MenusBeginning () { struct haiku_menu_bar_state_event rq; + int lock_count = 0; + thread_id current_thread = find_thread (NULL); + thread_id window_thread = Thread (); rq.window = this; + rq.no_lock = false; + + if (window_thread != current_thread) + rq.no_lock = true; haiku_write (MENU_BAR_OPEN, &rq); + + if (!rq.no_lock) + { + while (IsLocked ()) + { + ++lock_count; + UnlockLooper (); + } + pthread_mutex_lock (&menu_update_mutex); + while (!menu_updated_p) + pthread_cond_wait (&menu_update_cv, + &menu_update_mutex); + menu_updated_p = false; + pthread_mutex_unlock (&menu_update_mutex); + for (; lock_count; --lock_count) + { + if (!LockLooper ()) + gui_abort ("Failed to lock after cv signal denoting menu update"); + } + } menu_bar_active_p = true; } @@ -3212,3 +3245,14 @@ be_find_setting (const char *name) return value; } + +void +EmacsWindow_signal_menu_update_complete (void *window) +{ + EmacsWindow *w = (EmacsWindow *) window; + + pthread_mutex_lock (&w->menu_update_mutex); + w->menu_updated_p = true; + pthread_cond_signal (&w->menu_update_cv); + pthread_mutex_unlock (&w->menu_update_mutex); +} diff --git a/src/haiku_support.h b/src/haiku_support.h index 6ddc28759b5..8d4dddd90fa 100644 --- a/src/haiku_support.h +++ b/src/haiku_support.h @@ -299,6 +299,7 @@ struct haiku_menu_bar_resize_event struct haiku_menu_bar_state_event { void *window; + bool no_lock; }; #define HAIKU_THIN 0 @@ -864,6 +865,9 @@ extern "C" extern const char * be_find_setting (const char *name); + extern void + EmacsWindow_signal_menu_update_complete (void *window); + #ifdef __cplusplus extern void * find_appropriate_view_for_draw (void *vw); diff --git a/src/haikumenu.c b/src/haikumenu.c index 1c75e0f9a42..3fee5831608 100644 --- a/src/haikumenu.c +++ b/src/haikumenu.c @@ -644,10 +644,7 @@ the position of the last non-menu event instead. */) struct frame *f = decode_window_system_frame (frame); if (FRAME_EXTERNAL_MENU_BAR (f)) - { - if (!FRAME_OUTPUT_DATA (f)->menu_up_to_date_p) - set_frame_menubar (f, 1); - } + set_frame_menubar (f, 1); else { return call2 (Qpopup_menu, call0 (Qmouse_menu_bar_map), diff --git a/src/haikuterm.c b/src/haikuterm.c index 7ab41805ead..c8cc02a2988 100644 --- a/src/haikuterm.c +++ b/src/haikuterm.c @@ -3178,20 +3178,20 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit) if (type == MENU_BAR_OPEN) { - if (!FRAME_OUTPUT_DATA (f)->menu_up_to_date_p) - { - BView_draw_lock (FRAME_HAIKU_VIEW (f)); - /* 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)); - } + BView_draw_lock (FRAME_HAIKU_VIEW (f)); + /* 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)); FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 1; popup_activated_p += 1; + + if (!b->no_lock) + EmacsWindow_signal_menu_update_complete (b->window); } else { -- 2.39.2