summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPo Lu <luangruo@yahoo.com>2022-01-29 05:06:02 +0000
committerPo Lu <luangruo@yahoo.com>2022-01-29 05:11:04 +0000
commit95ccd1ba47771349e23aedf0981861fd5074bd7e (patch)
tree564a39fc44516cc3f95ddc79ddc991dd25035e32
parent70fc32f6ddef871dd2ae15a3333974f6d8231d6a (diff)
downloademacs-95ccd1ba47771349e23aedf0981861fd5074bd7e.tar.gz
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.
-rw-r--r--lisp/tooltip.el7
-rw-r--r--src/haiku_io.c24
-rw-r--r--src/haiku_support.cc152
-rw-r--r--src/haiku_support.h17
-rw-r--r--src/haikumenu.c47
-rw-r--r--src/haikuterm.c8
6 files changed, 217 insertions, 38 deletions
diff --git a/lisp/tooltip.el b/lisp/tooltip.el
index 2aa487d0454..9d523e79679 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 cb7750634cf..109aca782ad 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 41e5b71182f..05bc410eb28 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 8d4dddd90fa..4b0456168d0 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 875f1afb6a2..26eb3dbfe13 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 b9eb1d2fc5e..6a84e61add4 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);