From 479f51a63bb0de72453881d72a1b3ff5f30b4658 Mon Sep 17 00:00:00 2001 From: Martin Rudalics Date: Sat, 10 Feb 2018 10:18:38 +0100 Subject: [PATCH] Make tooltip code handle scenarios from Bug#30182 and Bug#30399 Move calculation of the mode line default help echo from note_mode_line_or_margin_highlight to display_mode_lines (Bug#30182). Fix cursor type for dragging the mode line. Normalize FRAME argument of Fx_show_tip before assigning it to tip_last_frame and handle the transition from GTK+ to Emacs tooltips and vice-versa in x_hide_tip (Bug#30399). * src/window.h (struct window): New Lisp member mode_line_help_echo. (wset_mode_line_help_echo): New function. * src/w32fns.c (Fx_show_tip): Normalize the FRAME argument bevore storing it in tip_last_frame (Bug#30399). * src/xdisp.c (display_mode_lines): Calculate mode line default help echo string here and store it in the window's mode_line_help_echo slot (Bug#30182). (note_mode_line_or_margin_highlight): Use value in window's mode_line_help_echo slot as mode line default help echo. When the window is resizable show a vertical drag cursor instead of the vertical scroll bar cursor. * src/xfns.c (x_hide_tip): Rewrite the GTK+ part to correctly handle the transition from GTK+ system to Emacs tooltips and vice-versa (Bug#30399). (Fx_show_tip): Normalize the FRAME argument bevore storing it in tip_last_frame (Bug#30399). --- src/w32fns.c | 8 ++++-- src/window.h | 9 +++++++ src/xdisp.c | 60 ++++++++++++++++++++++++------------------- src/xfns.c | 72 ++++++++++++++++++++++++++++++---------------------- 4 files changed, 90 insertions(+), 59 deletions(-) diff --git a/src/w32fns.c b/src/w32fns.c index 27c765ed920..2b8c34a5ab5 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -6930,7 +6930,7 @@ Lisp_Object tip_timer; /* STRING argument of last `x-show-tip' call. */ Lisp_Object tip_last_string; -/* FRAME argument of last `x-show-tip' call. */ +/* Normalized FRAME argument of last `x-show-tip' call. */ Lisp_Object tip_last_frame; /* PARMS argument of last `x-show-tip' call. */ @@ -7373,7 +7373,11 @@ Text larger than the specified size is clipped. */) specbind (Qinhibit_redisplay, Qt); CHECK_STRING (string); + + if (NILP (frame)) + frame = selected_frame; decode_window_system_frame (frame); + if (NILP (timeout)) timeout = make_number (5); else @@ -7508,7 +7512,7 @@ Text larger than the specified size is clipped. */) parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")), parms); - /* Create a frame for the tooltip, and record it in the global + /* Create a frame for the tooltip and record it in the global variable tip_frame. */ struct frame *f; /* The value is unused. */ if (NILP (tip_frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms))) diff --git a/src/window.h b/src/window.h index 629283ac40c..91ef7d90272 100644 --- a/src/window.h +++ b/src/window.h @@ -178,6 +178,9 @@ struct window /* An alist with parameters. */ Lisp_Object window_parameters; + /* The help echo text for this window. Qnil if there's none. */ + Lisp_Object mode_line_help_echo; + /* No Lisp data may follow below this point without changing mark_object in alloc.c. The member current_matrix must be the first non-Lisp member. */ @@ -444,6 +447,12 @@ wset_redisplay_end_trigger (struct window *w, Lisp_Object val) w->redisplay_end_trigger = val; } +INLINE void +wset_mode_line_help_echo (struct window *w, Lisp_Object val) +{ + w->mode_line_help_echo = val; +} + INLINE void wset_new_pixel (struct window *w, Lisp_Object val) { diff --git a/src/xdisp.c b/src/xdisp.c index 55f3151b4f2..9a5bd2eb96c 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -23209,6 +23209,23 @@ display_mode_lines (struct window *w) Lisp_Object old_frame_selected_window = XFRAME (new_frame)->selected_window; int n = 0; + if (window_wants_mode_line (w)) + { + Lisp_Object window; + Lisp_Object default_help + = buffer_local_value (Qmode_line_default_help_echo, w->contents); + + /* Set up mode line help echo. Do this before selecting w so it + can reasonably tell whether a mouse click will select w. */ + XSETWINDOW (window, w); + if (FUNCTIONP (default_help)) + wset_mode_line_help_echo (w, safe_call1 (default_help, window)); + else if (STRINGP (default_help)) + wset_mode_line_help_echo (w, default_help); + else + wset_mode_line_help_echo (w, Qnil); + } + selected_frame = new_frame; /* FIXME: If we were to allow the mode-line's computation changing the buffer or window's point, then we'd need select_window_1 here as well. */ @@ -23223,7 +23240,6 @@ display_mode_lines (struct window *w) { Lisp_Object window_mode_line_format = window_parameter (w, Qmode_line_format); - struct window *sel_w = XWINDOW (old_selected_window); /* Select mode line face based on the real selected window. */ @@ -30733,9 +30749,6 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, struct window *w = XWINDOW (window); struct frame *f = XFRAME (w->frame); Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); -#ifdef HAVE_WINDOW_SYSTEM - Display_Info *dpyinfo; -#endif Cursor cursor = No_Cursor; Lisp_Object pointer = Qnil; int dx, dy, width, height; @@ -30829,7 +30842,8 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, /* Set the help text and mouse pointer. If the mouse is on a part of the mode line without any text (e.g. past the right edge of - the mode line text), use the default help text and pointer. */ + the mode line text), use that windows's mode line help echo if it + has been set. */ if (STRINGP (string) || area == ON_MODE_LINE) { /* Arrange to display the help by setting the global variables @@ -30846,21 +30860,13 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, help_echo_object = string; help_echo_pos = charpos; } - else if (area == ON_MODE_LINE) + else if (area == ON_MODE_LINE + && !NILP (w->mode_line_help_echo)) { - Lisp_Object default_help - = buffer_local_value (Qmode_line_default_help_echo, - w->contents); - - if (FUNCTIONP (default_help) || STRINGP (default_help)) - { - help_echo_string = (FUNCTIONP (default_help) - ? safe_call1 (default_help, window) - : default_help); - XSETWINDOW (help_echo_window, w); - help_echo_object = Qnil; - help_echo_pos = -1; - } + help_echo_string = w->mode_line_help_echo; + XSETWINDOW (help_echo_window, w); + help_echo_object = Qnil; + help_echo_pos = -1; } } @@ -30872,7 +30878,6 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, || minibuf_level || NILP (Vresize_mini_windows)); - dpyinfo = FRAME_DISPLAY_INFO (f); if (STRINGP (string)) { cursor = FRAME_X_OUTPUT (f)->nontext_cursor; @@ -30882,25 +30887,28 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, /* Change the mouse pointer according to what is under X/Y. */ if (NILP (pointer) - && ((area == ON_MODE_LINE) || (area == ON_HEADER_LINE))) + && (area == ON_MODE_LINE || area == ON_HEADER_LINE)) { Lisp_Object map; + map = Fget_text_property (pos, Qlocal_map, string); if (!KEYMAPP (map)) map = Fget_text_property (pos, Qkeymap, string); - if (!KEYMAPP (map) && draggable) - cursor = dpyinfo->vertical_scroll_bar_cursor; + if (!KEYMAPP (map) && draggable && area == ON_MODE_LINE) + cursor = FRAME_X_OUTPUT (f)->vertical_drag_cursor; } } - else if (draggable) - /* Default mode-line pointer. */ - cursor = FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor; + else if (draggable && area == ON_MODE_LINE) + cursor = FRAME_X_OUTPUT (f)->vertical_drag_cursor; + else + cursor = FRAME_X_OUTPUT (f)->nontext_cursor; } #endif } /* Change the mouse face according to what is under X/Y. */ bool mouse_face_shown = false; + if (STRINGP (string)) { mouse_face = Fget_text_property (pos, Qmouse_face, string); diff --git a/src/xfns.c b/src/xfns.c index db1ce311021..9f0d9468c14 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -6077,7 +6077,7 @@ static Lisp_Object tip_timer; /* STRING argument of last `x-show-tip' call. */ static Lisp_Object tip_last_string; -/* FRAME argument of last `x-show-tip' call. */ +/* Normalized FRAME argument of last `x-show-tip' call. */ static Lisp_Object tip_last_frame; /* PARMS argument of last `x-show-tip' call. */ @@ -6542,16 +6542,20 @@ x_hide_tip (bool delete) } #ifdef USE_GTK - /* The GTK+ system tooltip window can be found via the x_output - structure of tip_last_frame, if it still exists. */ - if (x_gtk_use_system_tooltips && NILP (tip_last_frame)) - return Qnil; - else if (!x_gtk_use_system_tooltips - && (NILP (tip_frame) - || (!delete - && FRAMEP (tip_frame) - && FRAME_LIVE_P (XFRAME (tip_frame)) - && !FRAME_VISIBLE_P (XFRAME (tip_frame))))) + /* Any GTK+ system tooltip can be found via the x_output structure of + tip_last_frame, provided that frame is still live. Any Emacs + tooltip is found via the tip_frame variable. Note that the current + value of x_gtk_use_system_tooltips might not be the same as used + for the tooltip we have to hide, see Bug#30399. */ + if ((NILP (tip_last_frame) && NILP (tip_frame)) + || (!x_gtk_use_system_tooltips + && !delete + && FRAMEP (tip_frame) + && FRAME_LIVE_P (XFRAME (tip_frame)) + && !FRAME_VISIBLE_P (XFRAME (tip_frame)))) + /* Either there's no tooltip to hide or it's an already invisible + Emacs tooltip and we don't want to change its type. Return + quickly. */ return Qnil; else { @@ -6562,10 +6566,9 @@ x_hide_tip (bool delete) specbind (Qinhibit_redisplay, Qt); specbind (Qinhibit_quit, Qt); - if (x_gtk_use_system_tooltips) + /* Try to hide the GTK+ system tip first. */ + if (FRAMEP (tip_last_frame)) { - /* The GTK+ system tooltip window is stored in the x_output - structure of tip_last_frame. */ struct frame *f = XFRAME (tip_last_frame); if (FRAME_LIVE_P (f)) @@ -6573,33 +6576,37 @@ x_hide_tip (bool delete) if (xg_hide_tooltip (f)) was_open = Qt; } - else - tip_last_frame = Qnil; } - else + + /* Reset tip_last_frame, it will be reassigned when showing the + next GTK+ system tooltip. */ + tip_last_frame = Qnil; + + /* Now look whether there's an Emacs tip around. */ + if (FRAMEP (tip_frame)) { - if (FRAMEP (tip_frame)) - { - struct frame *f = XFRAME (tip_frame); + struct frame *f = XFRAME (tip_frame); - if (FRAME_LIVE_P (f)) + if (FRAME_LIVE_P (f)) + { + if (delete || x_gtk_use_system_tooltips) { - if (delete) - { - delete_frame (tip_frame, Qnil); - tip_frame = Qnil; - } - else - x_make_frame_invisible (f); - - was_open = Qt; + /* Delete the Emacs tooltip frame when DELETE is true + or we change the tooltip type from an Emacs one to + a GTK+ system one. */ + delete_frame (tip_frame, Qnil); + tip_frame = Qnil; } else - tip_frame = Qnil; + x_make_frame_invisible (f); + + was_open = Qt; } else tip_frame = Qnil; } + else + tip_frame = Qnil; return unbind_to (count, was_open); } @@ -6721,7 +6728,10 @@ Text larger than the specified size is clipped. */) if (SCHARS (string) == 0) string = make_unibyte_string (" ", 1); + if (NILP (frame)) + frame = selected_frame; f = decode_window_system_frame (frame); + if (NILP (timeout)) timeout = make_number (5); else -- 2.39.2