From e8b0808e20797f84fb2a720e38f315bfab39bde4 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sun, 17 Apr 2022 07:15:17 +0000 Subject: [PATCH] Fix hangs when clicking on Haiku menu bar to activate frame * src/haiku_io.c (haiku_len): Handle new event `MENU_BAR_CLICK'. * src/haiku_support.cc (class EmacsWindow): Remove most of the menu bar cv stuff. (MessageReceived): Handle REPLAY_MENU_BAR message. (EmacsWindow_signal_menu_update_complete): Delete function. (be_replay_menu_bar_event): New function. * src/haiku_support.h (enum haiku_event_type): New event type `MENU_BAR_CLICK'. (struct haiku_menu_bar_click_event): New struct. * src/haikumenu.c (haiku_activate_menubar): New function. * src/haikuterm.c (haiku_read_socket): Save a MENU_BAR_ACTIVATE_EVENT and the menu bar click event instead of handling the menu bar update synchronously. (haiku_create_terminal): Set `activate_menubar_hook'. (syms_of_haikuterm): Remove extraneous newline. * src/haikuterm.h (struct haiku_output): New field `saved_menu_event'. --- src/haiku_io.c | 2 ++ src/haiku_support.cc | 78 +++++++++++++++++++++----------------------- src/haiku_support.h | 10 +++++- src/haikumenu.c | 33 +++++++++++++++++++ src/haikuterm.c | 28 +++++++++------- src/haikuterm.h | 4 +++ 6 files changed, 103 insertions(+), 52 deletions(-) diff --git a/src/haiku_io.c b/src/haiku_io.c index 89f0877eb67..1830ac01e55 100644 --- a/src/haiku_io.c +++ b/src/haiku_io.c @@ -79,6 +79,8 @@ haiku_len (enum haiku_event_type type) return sizeof (struct haiku_wheel_move_event); case MENU_BAR_RESIZE: return sizeof (struct haiku_menu_bar_resize_event); + case MENU_BAR_CLICK: + return sizeof (struct haiku_menu_bar_click_event); case MENU_BAR_OPEN: case MENU_BAR_CLOSE: return sizeof (struct haiku_menu_bar_state_event); diff --git a/src/haiku_support.cc b/src/haiku_support.cc index e7c157dac84..673ae02ac9c 100644 --- a/src/haiku_support.cc +++ b/src/haiku_support.cc @@ -91,6 +91,7 @@ enum SHOW_MENU_BAR = 3004, BE_MENU_BAR_OPEN = 3005, QUIT_APPLICATION = 3006, + REPLAY_MENU_BAR = 3007, }; /* X11 keysyms that we use. */ @@ -496,9 +497,6 @@ public: window_look pre_override_redirect_look; 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; int window_id; bool *menus_begun = NULL; @@ -530,9 +528,6 @@ public: if (this->parent) UnparentAndUnlink (); child_frame_lock.Unlock (); - - pthread_cond_destroy (&menu_update_cv); - pthread_mutex_destroy (&menu_update_mutex); } BRect @@ -977,34 +972,13 @@ public: } void - MenusBeginning () + MenusBeginning (void) { struct haiku_menu_bar_state_event rq; - int lock_count; rq.window = this; - lock_count = 0; - if (!menus_begun) - { - haiku_write (MENU_BAR_OPEN, &rq); - 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"); - } - } + haiku_write (MENU_BAR_OPEN, &rq); else *menus_begun = true; @@ -1278,6 +1252,8 @@ public: class EmacsMenuBar : public BMenuBar { + bool tracking_p; + public: EmacsMenuBar () : BMenuBar (BRect (0, 0, 0, 0), NULL) { @@ -1303,6 +1279,22 @@ public: BMenuBar::FrameResized (newWidth, newHeight); } + void + MouseDown (BPoint point) + { + struct haiku_menu_bar_click_event rq; + EmacsWindow *ew = (EmacsWindow *) Window (); + + rq.window = ew; + rq.x = std::lrint (point.x); + rq.y = std::lrint (point.y); + + if (!ew->menu_bar_active_p) + haiku_write (MENU_BAR_CLICK, &rq); + else + BMenuBar::MouseDown (point); + } + void MouseMoved (BPoint point, uint32 transit, const BMessage *msg) { @@ -1351,6 +1343,11 @@ public: else msg->SendReply (BE_MENU_BAR_OPEN); } + else if (msg->what == REPLAY_MENU_BAR) + { + if (msg->FindPoint ("emacs:point", &pt) == B_OK) + BMenuBar::MouseDown (pt); + } else BMenuBar::MessageReceived (msg); } @@ -4147,17 +4144,6 @@ 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); -} - void BMessage_delete (void *message) { @@ -4274,3 +4260,15 @@ be_drag_and_drop_in_progress (void) { return drag_and_drop_in_progress; } + +void +be_replay_menu_bar_event (void *menu_bar, + struct haiku_menu_bar_click_event *event) +{ + BMenuBar *m = (BMenuBar *) menu_bar; + BMessenger messenger (m); + BMessage msg (REPLAY_MENU_BAR); + + msg.AddPoint ("emacs:point", BPoint (event->x, event->y)); + messenger.SendMessage (&msg); +} diff --git a/src/haiku_support.h b/src/haiku_support.h index 9935906f0e3..6b285cf3e0a 100644 --- a/src/haiku_support.h +++ b/src/haiku_support.h @@ -80,6 +80,7 @@ enum haiku_event_type SCROLL_BAR_DRAG_EVENT, WHEEL_MOVE_EVENT, MENU_BAR_RESIZE, + MENU_BAR_CLICK, MENU_BAR_OPEN, MENU_BAR_SELECT_EVENT, MENU_BAR_CLOSE, @@ -168,6 +169,12 @@ struct haiku_menu_bar_left_event int x, y; }; +struct haiku_menu_bar_click_event +{ + void *window; + int x, y; +}; + struct haiku_button_event { void *window; @@ -577,7 +584,6 @@ extern void EmacsWindow_unparent (void *); extern void EmacsWindow_move_weak_child (void *, void *, int, int); extern void EmacsWindow_make_fullscreen (void *, int); extern void EmacsWindow_unzoom (void *); -extern void EmacsWindow_signal_menu_update_complete (void *); extern void be_get_version_string (char *, int); extern int be_get_display_planes (void); @@ -630,6 +636,8 @@ extern bool be_drag_message (void *, void *, bool, void (*) (void), bool (*) (void)); extern bool be_drag_and_drop_in_progress (void); +extern void be_replay_menu_bar_event (void *, struct haiku_menu_bar_click_event *); + #ifdef __cplusplus extern void *find_appropriate_view_for_draw (void *); } diff --git a/src/haikumenu.c b/src/haikumenu.c index 22e9c4ecad3..8aced5f9d43 100644 --- a/src/haikumenu.c +++ b/src/haikumenu.c @@ -774,6 +774,39 @@ the position of the last non-menu event instead. */) return Qnil; } +void +haiku_activate_menubar (struct frame *f) +{ + int rc; + + if (!FRAME_HAIKU_MENU_BAR (f)) + return; + + set_frame_menubar (f, true); + + if (FRAME_OUTPUT_DATA (f)->saved_menu_event) + { + block_input (); + be_replay_menu_bar_event (FRAME_HAIKU_MENU_BAR (f), + FRAME_OUTPUT_DATA (f)->saved_menu_event); + xfree (FRAME_OUTPUT_DATA (f)->saved_menu_event); + FRAME_OUTPUT_DATA (f)->saved_menu_event = NULL; + unblock_input (); + } + else + { + block_input (); + rc = BMenuBar_start_tracking (FRAME_HAIKU_MENU_BAR (f)); + unblock_input (); + + if (!rc) + return; + + FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 1; + popup_activated_p += 1; + } +} + void syms_of_haikumenu (void) { diff --git a/src/haikuterm.c b/src/haikuterm.c index 559ec58926c..45d22ce22fb 100644 --- a/src/haikuterm.c +++ b/src/haikuterm.c @@ -3475,34 +3475,40 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit) } break; } + case MENU_BAR_CLICK: + { + struct haiku_menu_bar_click_event *b = buf; + struct frame *f = haiku_window_to_frame (b->window); + + if (!f || !FRAME_EXTERNAL_MENU_BAR (f)) + continue; + + if (!FRAME_OUTPUT_DATA (f)->saved_menu_event) + FRAME_OUTPUT_DATA (f)->saved_menu_event = xmalloc (sizeof *b); + *FRAME_OUTPUT_DATA (f)->saved_menu_event = *b; + inev.kind = MENU_BAR_ACTIVATE_EVENT; + XSETFRAME (inev.frame_or_window, f); + break; + } case MENU_BAR_OPEN: case MENU_BAR_CLOSE: { 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) { - 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; - FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 1; popup_activated_p += 1; - - EmacsWindow_signal_menu_update_complete (b->window); } else { if (!popup_activated_p) emacs_abort (); + if (FRAME_OUTPUT_DATA (f)->menu_bar_open_p) { FRAME_OUTPUT_DATA (f)->menu_bar_open_p = 0; @@ -3873,6 +3879,7 @@ haiku_create_terminal (struct haiku_display_info *dpyinfo) terminal->toggle_invisible_pointer_hook = haiku_toggle_invisible_pointer; terminal->fullscreen_hook = haiku_fullscreen; terminal->toolkit_position_hook = haiku_toolkit_position; + terminal->activate_menubar_hook = haiku_activate_menubar; return terminal; } @@ -4184,7 +4191,6 @@ This is either one of the symbols `shift', `control', `command', and Setting it to any other value is equivalent to `shift'. */); Vhaiku_shift_keysym = Qnil; - DEFSYM (Qx_use_underline_position_properties, "x-use-underline-position-properties"); diff --git a/src/haikuterm.h b/src/haikuterm.h index 7022ea77dec..e922743b18c 100644 --- a/src/haikuterm.h +++ b/src/haikuterm.h @@ -176,6 +176,9 @@ struct haiku_output /* The default cursor foreground color. */ uint32_t cursor_fg; + + /* If non-NULL, the last menu bar click event received. */ + struct haiku_menu_bar_click_event *saved_menu_event; }; struct x_output @@ -291,6 +294,7 @@ extern void haiku_put_pixel (haiku, int, int, unsigned long); extern Lisp_Object haiku_menu_show (struct frame *, int, int, int, Lisp_Object, const char **); extern Lisp_Object haiku_popup_dialog (struct frame *, Lisp_Object, Lisp_Object); +extern void haiku_activate_menubar (struct frame *); extern void haiku_note_drag_motion (void); extern void initialize_frame_menubar (struct frame *); -- 2.39.2