emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 95ccd1ba47: Implement real menu help-echo text on Haiku


From: Po Lu
Subject: master 95ccd1ba47: Implement real menu help-echo text on Haiku
Date: Sat, 29 Jan 2022 00:13:47 -0500 (EST)

branch: master
commit 95ccd1ba47771349e23aedf0981861fd5074bd7e
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Implement real menu help-echo text on Haiku
    
    * 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      |   7 +--
 src/haiku_io.c       |  24 ++++++--
 src/haiku_support.cc | 152 ++++++++++++++++++++++++++++++++++++++++++++++-----
 src/haiku_support.h  |  17 ++++--
 src/haikumenu.c      |  47 ++++++++++++++--
 src/haikuterm.c      |   8 ++-
 6 files changed, 217 insertions(+), 38 deletions(-)

diff --git a/lisp/tooltip.el b/lisp/tooltip.el
index 2aa487d045..9d523e7967 100644
--- a/lisp/tooltip.el
+++ b/lisp/tooltip.el
@@ -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)
diff --git a/src/haiku_io.c b/src/haiku_io.c
index cb7750634c..109aca782a 100644
--- a/src/haiku_io.c
+++ b/src/haiku_io.c
@@ -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;
diff --git a/src/haiku_support.cc b/src/haiku_support.cc
index 41e5b71182..05bc410eb2 100644
--- a/src/haiku_support.cc
+++ b/src/haiku_support.cc
@@ -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);
diff --git a/src/haiku_support.h b/src/haiku_support.h
index 8d4dddd90f..4b0456168d 100644
--- a/src/haiku_support.h
+++ b/src/haiku_support.h
@@ -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);
diff --git a/src/haikumenu.c b/src/haikumenu.c
index 875f1afb6a..26eb3dbfe1 100644
--- a/src/haikumenu.c
+++ b/src/haikumenu.c
@@ -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)
diff --git a/src/haikuterm.c b/src/haikuterm.c
index b9eb1d2fc5..6a84e61add 100644
--- a/src/haikuterm.c
+++ b/src/haikuterm.c
@@ -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);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]