[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);
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- master 95ccd1ba47: Implement real menu help-echo text on Haiku,
Po Lu <=