]> git.eshelyaron.com Git - emacs.git/commitdiff
Implement real menu help-echo text on Haiku
authorPo Lu <luangruo@yahoo.com>
Sat, 29 Jan 2022 05:06:02 +0000 (05:06 +0000)
committerPo Lu <luangruo@yahoo.com>
Sat, 29 Jan 2022 05:11:04 +0000 (05:11 +0000)
* lisp/tooltip.el (tooltip-show-help): Remove Haiku-specific
conditional since that's now taken care of by C code.

* src/haiku_io.c (haiku_read_size):
(haiku_read_with_timeout):
(haiku_write_without_signal): Add parameter `popup_p'.  All
callers changed.
(port_popup_menu_to_emacs): New variable.

* src/haiku_support.cc (struct be_popup_menu_data): New
structure.
(be_popup_menu_thread_entry): New function.
(class EmacsMenuItem): New field `menu_ptr'.
(Highlight): Send help text to the popup port if this item
isn't for a menu bar.
(BMenu_add_item): Set menu_ptr appropriately.
(BMenu_run): Complete rewrite that allows to read help text from
the menu bar port.

* src/haiku_support.h (struct haiku_menu_bar_help_event): New
fields for popup menus.

* src/haikumenu.c (digest_menu_items): Only set help tooltip on
popup menus when system tooltips are enabled.
(haiku_menu_show_help):
(haiku_process_pending_signals_for_menu): New functions.
(haiku_menu_show): Pass new callbacks.

lisp/tooltip.el
src/haiku_io.c
src/haiku_support.cc
src/haiku_support.h
src/haikumenu.c
src/haikuterm.c

index 2aa487d0454d8189d532ea8059306b11892510c3..9d523e796792fe45a2419b7ef7c0279f00a82c2e 100644 (file)
@@ -375,12 +375,7 @@ It is also called if Tooltip mode is on, for text-only displays."
 (defun tooltip-show-help (msg)
   "Function installed as `show-help-function'.
 MSG is either a help string to display, or nil to cancel the display."
-  (if (and (display-graphic-p)
-           ;; On Haiku, system tooltips can't be displayed above
-           ;; menus.
-           (or (not (and (eq window-system 'haiku)
-                         haiku-use-system-tooltips))
-               (not (menu-or-popup-active-p))))
+  (if (and (display-graphic-p))
       (let ((previous-help tooltip-help-message))
        (setq tooltip-help-message msg)
        (cond ((null msg)
index cb7750634cf0ffa87c4426b32277f28b7ae10a65..109aca782ad147d2b8885810ca1812d71cfc5ed1 100644 (file)
@@ -36,6 +36,10 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    Emacs.  */
 port_id port_application_to_emacs;
 
+/* The port used to send popup menu messages from the application
+   thread to Emacs.  */
+port_id port_popup_menu_to_emacs;
+
 void
 haiku_io_init (void)
 {
@@ -98,9 +102,11 @@ haiku_len (enum haiku_event_type type)
 /* Read the size of the next message into len, returning -1 if the
    query fails or there is no next message.  */
 void
-haiku_read_size (ssize_t *len)
+haiku_read_size (ssize_t *len, bool popup_menu_p)
 {
-  port_id from = port_application_to_emacs;
+  port_id from = (popup_menu_p
+                 ? port_popup_menu_to_emacs
+                 : port_application_to_emacs);
   ssize_t size;
 
   size = port_buffer_size_etc (from, B_TIMEOUT, 0);
@@ -129,13 +135,16 @@ haiku_read (enum haiku_event_type *type, void *buf, ssize_t len)
 }
 
 /* The same as haiku_read, but time out after TIMEOUT microseconds.
+   POPUP_MENU_P means to read from the popup menu port instead.
    Input is blocked when an attempt to read is in progress.  */
 int
 haiku_read_with_timeout (enum haiku_event_type *type, void *buf, ssize_t len,
-                        time_t timeout)
+                        time_t timeout, bool popup_menu_p)
 {
   int32 typ;
-  port_id from = port_application_to_emacs;
+  port_id from = (popup_menu_p
+                 ? port_popup_menu_to_emacs
+                 : port_application_to_emacs);
 
   block_input ();
   if (read_port_etc (from, &typ, buf, len,
@@ -165,9 +174,12 @@ haiku_write (enum haiku_event_type type, void *buf)
 }
 
 int
-haiku_write_without_signal (enum haiku_event_type type, void *buf)
+haiku_write_without_signal (enum haiku_event_type type, void *buf,
+                           bool popup_menu_p)
 {
-  port_id to = port_application_to_emacs;
+  port_id to = (popup_menu_p
+               ? port_popup_menu_to_emacs
+               : port_application_to_emacs);
 
   if (write_port (to, (int32_t) type, buf, haiku_len (type)) < B_OK)
     return -1;
index 41e5b71182f0b280b80c1b67101f3ebad8b76a33..05bc410eb288a15248c2b384b92ea64994081003 100644 (file)
@@ -114,6 +114,8 @@ static BLocker child_frame_lock;
 
 static BLocker movement_locker;
 
+static BMessage volatile *popup_track_message;
+
 /* This could be a private API, but it's used by (at least) the Qt
    port, so it's probably here to stay.  */
 extern status_t get_subpixel_antialiasing (bool *);
@@ -137,6 +139,30 @@ gui_abort (const char *msg)
   emacs_abort ();
 }
 
+struct be_popup_menu_data
+{
+  int x, y;
+  BPopUpMenu *menu;
+};
+
+static int32
+be_popup_menu_thread_entry (void *thread_data)
+{
+  struct be_popup_menu_data *data;
+  BMenuItem *it;
+
+  data = (struct be_popup_menu_data *) thread_data;
+
+  it = data->menu->Go (BPoint (data->x, data->y));
+
+  if (it)
+    popup_track_message = it->Message ();
+  else
+    popup_track_message = NULL;
+
+  return 0;
+}
+
 /* Convert a raw character RAW produced by the keycode KEY into a key
    symbol and place it in KEYSYM.
 
@@ -656,8 +682,10 @@ public:
     else if (msg->GetPointer ("menuptr"))
       {
        struct haiku_menu_bar_select_event rq;
+
        rq.window = this;
        rq.ptr = (void *) msg->GetPointer ("menuptr");
+
        haiku_write (MENU_BAR_SELECT_EVENT, &rq);
       }
     else if (msg->what == 'FPSE'
@@ -1607,6 +1635,7 @@ class EmacsMenuItem : public BMenuItem
 {
 public:
   int menu_bar_id = -1;
+  void *menu_ptr = NULL;
   void *wind_ptr = NULL;
   char *key = NULL;
   char *help = NULL;
@@ -1675,16 +1704,23 @@ public:
 
     if (help)
       menu->SetToolTip (highlight_p ? help : NULL);
-    else if (menu_bar_id >= 0)
+    else
       {
        rq.window = wind_ptr;
        rq.mb_idx = highlight_p ? menu_bar_id : -1;
+       rq.highlight_p = highlight_p;
+       rq.data = menu_ptr;
 
        r = Frame ();
        menu->GetMouse (&pt, &buttons);
 
        if (!highlight_p || r.Contains (pt))
-         haiku_write (MENU_BAR_HELP_EVENT, &rq);
+         {
+           if (menu_bar_id > 0)
+             haiku_write (MENU_BAR_HELP_EVENT, &rq);
+           else
+             haiku_write_without_signal (MENU_BAR_HELP_EVENT, &rq, true);
+         }
       }
 
     BMenuItem::Highlight (highlight_p);
@@ -2353,6 +2389,7 @@ BMenu_add_item (void *menu, const char *label, void *ptr, bool enabled_p,
       it->menu_bar_id = (intptr_t) ptr;
       it->wind_ptr = mbw_ptr;
     }
+  it->menu_ptr = ptr;
   if (ptr)
     msg->AddPointer ("menuptr", ptr);
   m->AddItem (it);
@@ -2397,20 +2434,109 @@ BMenu_new_menu_bar_submenu (void *menu, const char *label)
    data of the selected item (if one exists), or NULL.  X, Y should
    be in the screen coordinate system.  */
 void *
-BMenu_run (void *menu, int x, int y)
+BMenu_run (void *menu, int x, int y,
+          void (*run_help_callback) (void *, void *),
+          void (*block_input_function) (void),
+          void (*unblock_input_function) (void),
+          void (*process_pending_signals_function) (void),
+          void *run_help_callback_data)
 {
   BPopUpMenu *mn = (BPopUpMenu *) menu;
+  enum haiku_event_type type;
+  void *buf;
+  void *ptr = NULL;
+  struct be_popup_menu_data data;
+  struct object_wait_info infos[2];
+  struct haiku_menu_bar_help_event *event;
+  BMessage *msg;
+  ssize_t stat;
+
+  block_input_function ();
+  port_popup_menu_to_emacs = create_port (1800, "popup menu port");
+  data.x = x;
+  data.y = y;
+  data.menu = mn;
+  unblock_input_function ();
+
+  if (port_popup_menu_to_emacs < B_OK)
+    return NULL;
+
+  block_input_function ();
   mn->SetRadioMode (0);
-  BMenuItem *it = mn->Go (BPoint (x, y));
-  if (it)
+  buf = alloca (200);
+
+  infos[0].object = port_popup_menu_to_emacs;
+  infos[0].type = B_OBJECT_TYPE_PORT;
+  infos[0].events = B_EVENT_READ;
+
+  infos[1].object = spawn_thread (be_popup_menu_thread_entry,
+                                 "Menu tracker", B_DEFAULT_MEDIA_PRIORITY,
+                                 (void *) &data);
+  infos[1].type = B_OBJECT_TYPE_THREAD;
+  infos[1].events = B_EVENT_INVALID;
+  unblock_input_function ();
+
+  if (infos[1].object < B_OK)
     {
-      BMessage *mg = it->Message ();
-      if (mg)
-       return (void *) mg->GetPointer ("menuptr");
-      else
-       return NULL;
+      block_input_function ();
+      delete_port (port_popup_menu_to_emacs);
+      unblock_input_function ();
+      return NULL;
+    }
+
+  block_input_function ();
+  resume_thread (infos[1].object);
+  unblock_input_function ();
+
+  while (true)
+    {
+      if ((stat = wait_for_objects_etc ((object_wait_info *) &infos, 2,
+                                       B_RELATIVE_TIMEOUT, 10000)) < B_OK)
+       {
+         if (stat == B_INTERRUPTED)
+           continue;
+         else if (stat == B_TIMED_OUT)
+           {
+             process_pending_signals_function ();
+             continue;
+           }
+         else
+           gui_abort ("Failed to wait for popup");
+       }
+
+      if (infos[0].events & B_EVENT_READ)
+       {
+         if (!haiku_read_with_timeout (&type, buf, 200, 1000000, true))
+           {
+             switch (type)
+               {
+               case MENU_BAR_HELP_EVENT:
+                 event = (struct haiku_menu_bar_help_event *) buf;
+                 run_help_callback (event->highlight_p
+                                    ? event->data
+                                    : NULL, run_help_callback_data);
+                 break;
+               default:
+                 gui_abort ("Unknown popup menu event");
+               }
+           }
+       }
+
+      if (infos[1].events & B_EVENT_INVALID)
+       {
+         block_input_function ();
+         msg = (BMessage *) popup_track_message;
+         if (popup_track_message)
+           ptr = (void *) msg->GetPointer ("menuptr");
+
+         delete_port (port_popup_menu_to_emacs);
+         unblock_input_function ();
+         return ptr;
+       }
+
+      infos[0].events = B_EVENT_READ;
+      infos[1].events = B_EVENT_INVALID;
     }
-  return NULL;
 }
 
 /* Delete the entire menu hierarchy of MENU, and then delete MENU
@@ -2864,7 +2990,7 @@ be_popup_file_dialog (int open_p, const char *default_dir, int must_match_p, int
       enum haiku_event_type type;
       char *ptr = NULL;
 
-      if (!haiku_read_with_timeout (&type, buf, 200, 1000000))
+      if (!haiku_read_with_timeout (&type, buf, 200, 1000000, false))
        {
          block_input_function ();
          if (type != FILE_PANEL_EVENT)
@@ -2878,7 +3004,7 @@ be_popup_file_dialog (int open_p, const char *default_dir, int must_match_p, int
 
       ssize_t b_s;
       block_input_function ();
-      haiku_read_size (&b_s);
+      haiku_read_size (&b_s, false);
       if (!b_s || ptr || panel->Window ()->IsHidden ())
        {
          c_unbind_to_nil_from_cxx (idx);
index 8d4dddd90fac039528206ec4c83604a12fe19e5f..4b0456168d0e4956afe125faaf50241a63d55bd5 100644 (file)
@@ -200,6 +200,8 @@ struct haiku_menu_bar_help_event
 {
   void *window;
   int mb_idx;
+  void *data;
+  bool highlight_p;
 };
 
 struct haiku_zoom_event
@@ -358,25 +360,27 @@ extern "C"
 #endif
 
   extern port_id port_application_to_emacs;
+  extern port_id port_popup_menu_to_emacs;
 
   extern void haiku_io_init (void);
   extern void haiku_io_init_in_app_thread (void);
 
   extern void
-  haiku_read_size (ssize_t *len);
+  haiku_read_size (ssize_t *len, bool popup_menu_p);
 
   extern int
   haiku_read (enum haiku_event_type *type, void *buf, ssize_t len);
 
   extern int
   haiku_read_with_timeout (enum haiku_event_type *type, void *buf, ssize_t len,
-                          time_t timeout);
+                          time_t timeout, bool popup_menu_p);
 
   extern int
   haiku_write (enum haiku_event_type type, void *buf);
 
   extern int
-  haiku_write_without_signal (enum haiku_event_type type, void *buf);
+  haiku_write_without_signal (enum haiku_event_type type, void *buf,
+                             bool popup_menu_p);
 
   extern void
   rgb_color_hsl (uint32_t rgb, double *h, double *s, double *l);
@@ -679,7 +683,12 @@ extern "C"
   BMenu_item_at (void *menu, int idx);
 
   extern void *
-  BMenu_run (void *menu, int x, int y);
+  BMenu_run (void *menu, int x, int y,
+            void (*run_help_callback) (void *, void *),
+            void (*block_input_function) (void),
+            void (*unblock_input_function) (void),
+            void (*process_pending_signals_function) (void),
+            void *run_help_callback_data);
 
   extern void
   BPopUpMenu_delete (void *menu);
index 875f1afb6a2d3754753ca290a30457f90e15bd77..26eb3dbfe1339a72f76fbb478df93c744f96cdf1 100644 (file)
@@ -150,11 +150,20 @@ digest_menu_items (void *first_menu, int start, int menu_items_used,
          else if (NILP (def) && menu_separator_name_p (SSDATA (item_name)))
            BMenu_add_separator (menu);
          else if (!mbar_p)
-           BMenu_add_item (menu, SSDATA (item_name),
-                           !NILP (def) ? aref_addr (menu_items, i) : NULL,
-                           !NILP (enable), !NILP (selected), 0, window,
-                           !NILP (descrip) ? SSDATA (descrip) : NULL,
-                           STRINGP (help) ? SSDATA (help) : NULL);
+           {
+             if (!use_system_tooltips || NILP (Fsymbol_value (Qtooltip_mode)))
+               BMenu_add_item (menu, SSDATA (item_name),
+                               !NILP (def) ? aref_addr (menu_items, i) : NULL,
+                               !NILP (enable), !NILP (selected), 0, window,
+                               !NILP (descrip) ? SSDATA (descrip) : NULL,
+                               NULL);
+             else
+               BMenu_add_item (menu, SSDATA (item_name),
+                               !NILP (def) ? aref_addr (menu_items, i) : NULL,
+                               !NILP (enable), !NILP (selected), 0, window,
+                               !NILP (descrip) ? SSDATA (descrip) : NULL,
+                               STRINGP (help) ? SSDATA (help) : NULL);
+           }
          else if (!use_system_tooltips || NILP (Fsymbol_value (Qtooltip_mode)))
            BMenu_add_item (menu, SSDATA (item_name),
                            !NILP (def) ? (void *) (intptr_t) i : NULL,
@@ -294,6 +303,27 @@ haiku_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents)
   return selection;
 }
 
+static void
+haiku_menu_show_help (void *help, void *data)
+{
+  Lisp_Object *id = (Lisp_Object *) help;
+
+  if (help)
+    show_help_echo (id[MENU_ITEMS_ITEM_HELP],
+                   Qnil, Qnil, Qnil);
+  else
+    show_help_echo (Qnil, Qnil, Qnil, Qnil);
+}
+
+static void
+haiku_process_pending_signals_for_menu (void)
+{
+  process_pending_signals ();
+
+  input_pending = false;
+  detect_input_pending_run_timers (true);
+}
+
 Lisp_Object
 haiku_menu_show (struct frame *f, int x, int y, int menuflags,
                 Lisp_Object title, const char **error_name)
@@ -327,9 +357,14 @@ haiku_menu_show (struct frame *f, int x, int y, int menuflags,
     }
   digest_menu_items (menu, 0, menu_items_used, 0);
   BView_convert_to_screen (view, &x, &y);
-  menu_item_selection = BMenu_run (menu, x, y);
   unblock_input ();
 
+  popup_activated_p++;
+  menu_item_selection = BMenu_run (menu, x, y,  haiku_menu_show_help,
+                                  block_input, unblock_input,
+                                  haiku_process_pending_signals_for_menu, NULL);
+  popup_activated_p--;
+
   FRAME_DISPLAY_INFO (f)->grabbed = 0;
 
   if (menu_item_selection)
index b9eb1d2fc5e414659d65b865c3ab213972f4ec13..6a84e61add4ba02ff78a991650b140b605127c86 100644 (file)
@@ -2559,7 +2559,7 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
 
   if (!buf)
     buf = xmalloc (200);
-  haiku_read_size (&b_size);
+  haiku_read_size (&b_size, false);
   while (b_size >= 0)
     {
       enum haiku_event_type type;
@@ -2831,6 +2831,8 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
                    || !NILP (previous_help_echo_string))
                  do_help = 1;
              }
+
+           need_flush = FRAME_DIRTY_P (f);
            break;
          }
        case BUTTON_UP:
@@ -3260,7 +3262,7 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
          break;
        }
 
-      haiku_read_size (&b_size);
+      haiku_read_size (&b_size, false);
 
       if (inev.kind != NO_EVENT)
        {
@@ -3285,7 +3287,7 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
 
   for (struct unhandled_event *ev = unhandled_events; ev;)
     {
-      haiku_write_without_signal (ev->type, &ev->buffer);
+      haiku_write_without_signal (ev->type, &ev->buffer, false);
       struct unhandled_event *old = ev;
       ev = old->next;
       xfree (old);