diff --git a/lisp/bindings.el b/lisp/bindings.el index 8375bb9..c806cae 100644 --- a/lisp/bindings.el +++ b/lisp/bindings.el @@ -124,17 +124,56 @@ mode-line-eol-desc ;;; Mode line contents -(defcustom mode-line-default-help-echo - "mouse-1: Select (drag to resize)\n\ -mouse-2: Make current window occupy the whole frame\n\ -mouse-3: Remove current window from display" +(defun mode-line-default-help-echo (window) + "Return default help echo text for WINDOW's mode-line." + (let* ((frame (window-frame window)) + (line-1a + ;; Show text to select window only if the window is not + ;; selected. + (not (eq window (frame-selected-window frame)))) + (line-1b + ;; Show text to drag modeline if and only if it can be done. + (or (window-in-direction 'below window) + (let ((mini-window (minibuffer-window frame))) + (and (eq frame (window-frame mini-window)) + (or (minibuffer-window-active-p mini-window) + (not resize-mini-windows)))))) + (line-2 + ;; Show text make window occupy the whole frame + ;; only if it doesn't already do that. + (not (eq window (frame-root-window frame)))) + (line-3 + ;; Show text to delete window only if that's possible. + (not (eq window (frame-root-window frame))))) + (when (or line-1a line-1b line-2 line-3) + (concat + (when (or line-1a line-1b) + (concat + "mouse-1: " + (when line-1a "Select") + (when line-1b + (if line-1a " (drag to resize)" "Drag to resize")) + (when (or line-2 line-3) "\n"))) + (when line-2 + (concat + "mouse-2: Make window occupy whole frame" + (when line-3 "\n"))) + (when line-3 + "mouse-3: Remove window from frame"))))) + +(defcustom mode-line-default-help-echo #'mode-line-default-help-echo "Default help text for the mode line. If the value is a string, it specifies the tooltip or echo area message to display when the mouse is moved over the mode line. -If the text at the mouse position has a `help-echo' text -property, that overrides this variable." - :type '(choice (const :tag "No help" :value nil) string) - :version "24.3" +If the value is a function, call that function with one argument +- the window whose mode-line to display. If the text at the +mouse position has a `help-echo' text property, that overrides +this variable." + :type '(choice + (const :tag "No help" :value nil) + function + string) + :version "27.1" :group 'mode-line) (defvar mode-line-front-space '(:eval (if (display-graphic-p) " " "-")) diff --git a/src/dispextern.h b/src/dispextern.h index 25bd6b2..441361b 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3452,15 +3452,6 @@ int face_at_string_position (struct window *, Lisp_Object, ptrdiff_t, ptrdiff_t, void x_implicitly_set_name (struct frame *, Lisp_Object, Lisp_Object); void x_change_tool_bar_height (struct frame *f, int); -/* The frame used to display a tooltip. - - Note: In a GTK build with non-zero x_gtk_use_system_tooltips, this - variable holds the frame that shows the tooltip, not the frame of - the tooltip itself, so checking whether a frame is a tooltip frame - cannot just compare the frame to what this variable holds. */ -extern Lisp_Object tip_frame; - -extern Window tip_window; extern frame_parm_handler x_frame_parm_handlers[]; extern void start_hourglass (void); diff --git a/src/frame.c b/src/frame.c index 1c6289a..73b4b4e 100644 --- a/src/frame.c +++ b/src/frame.c @@ -832,6 +832,7 @@ struct frame * f->no_focus_on_map = false; f->no_accept_focus = false; f->z_group = z_group_none; + f->tooltip = false; #if ! defined (USE_GTK) && ! defined (HAVE_NS) f->last_tool_bar_item = -1; #endif @@ -1467,20 +1468,21 @@ of them (the selected terminal frame) is actually displayed. DEFUN ("frame-list", Fframe_list, Sframe_list, 0, 0, 0, - doc: /* Return a list of all live frames. */) + doc: /* Return a list of all live frames. +The return value does not include any tooltip frame. */) (void) { - Lisp_Object frames; - frames = Fcopy_sequence (Vframe_list); #ifdef HAVE_WINDOW_SYSTEM - if (FRAMEP (tip_frame) -#ifdef USE_GTK - && !NILP (Fframe_parameter (tip_frame, Qtooltip)) -#endif - ) - frames = Fdelq (tip_frame, frames); -#endif - return frames; + Lisp_Object list = Qnil, tail, frame; + + FOR_EACH_FRAME (tail, frame) + if (!FRAME_TOOLTIP_P (XFRAME (frame))) + list = Fcons (frame, list); + /* Reverse list for consistency with the !HAVE_WINDOW_SYSTEM case. */ + return Fnreverse (list); +#else /* !HAVE_WINDOW_SYSTEM */ + return Fcopy_sequence (Vframe_list); +#endif /* HAVE_WINDOW_SYSTEM */ } DEFUN ("frame-parent", Fframe_parent, Sframe_parent, @@ -1711,7 +1713,8 @@ of them (the selected terminal frame) is actually displayed. * other_frames: * * Return true if there exists at least one visible or iconified frame - * but F. Return false otherwise. + * but F. Tooltip frames do not qualify as candidates. Return false + * if no such frame exists. * * INVISIBLE true means we are called from make_frame_invisible where * such a frame must be visible or iconified. INVISIBLE nil means we @@ -1725,7 +1728,6 @@ of them (the selected terminal frame) is actually displayed. other_frames (struct frame *f, bool invisible, bool force) { Lisp_Object frames, frame, frame1; - struct frame *f1; Lisp_Object minibuffer_window = FRAME_MINIBUF_WINDOW (f); XSETFRAME (frame, f); @@ -1735,7 +1737,8 @@ of them (the selected terminal frame) is actually displayed. FOR_EACH_FRAME (frames, frame1) { - f1 = XFRAME (frame1); + struct frame *f1 = XFRAME (frame1); + if (f != f1) { /* Verify that we can still talk to the frame's X window, and @@ -1744,7 +1747,7 @@ of them (the selected terminal frame) is actually displayed. if (FRAME_WINDOW_P (f1)) x_sync (f1); #endif - if (NILP (Fframe_parameter (frame1, Qtooltip)) + if (!FRAME_TOOLTIP_P (f1) /* Tooltips and child frames count neither for invisibility nor for deletions. */ && !FRAME_PARENT_FRAME (f1) @@ -1877,7 +1880,7 @@ of them (the selected terminal frame) is actually displayed. } } - is_tooltip_frame = !NILP (Fframe_parameter (frame, Qtooltip)); + is_tooltip_frame = FRAME_TOOLTIP_P (f); /* Run `delete-frame-functions' unless FORCE is `noelisp' or frame is a tooltip. FORCE is set to `noelisp' when handling @@ -1925,27 +1928,31 @@ of them (the selected terminal frame) is actually displayed. Do not call next_frame here because it may loop forever. See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=15025. */ FOR_EACH_FRAME (tail, frame1) - if (!EQ (frame, frame1) - && NILP (Fframe_parameter (frame1, Qtooltip)) - && (FRAME_TERMINAL (XFRAME (frame)) - == FRAME_TERMINAL (XFRAME (frame1))) - && FRAME_VISIBLE_P (XFRAME (frame1))) - break; + { + struct frame *f1 = XFRAME (frame1); + + if (!EQ (frame, frame1) + && !FRAME_TOOLTIP_P (f1) + && FRAME_TERMINAL (f) == FRAME_TERMINAL (f1) + && FRAME_VISIBLE_P (f1)) + break; + } /* If there is none, find *some* other frame. */ if (NILP (frame1) || EQ (frame1, frame)) { FOR_EACH_FRAME (tail, frame1) { + struct frame *f1 = XFRAME (frame1); + if (!EQ (frame, frame1) - && FRAME_LIVE_P (XFRAME (frame1)) - && NILP (Fframe_parameter (frame1, Qtooltip))) + && FRAME_LIVE_P (f1) + && !FRAME_TOOLTIP_P (f1)) { - /* Do not change a text terminal's top-frame. */ - struct frame *f1 = XFRAME (frame1); if (FRAME_TERMCAP_P (f1) || FRAME_MSDOS_P (f1)) { Lisp_Object top_frame = FRAME_TTY (f1)->top_frame; + if (!EQ (top_frame, frame)) frame1 = top_frame; } @@ -5617,7 +5624,6 @@ or a list (- N) meaning -N pixels relative to bottom/right corner. DEFSYM (Qgeometry, "geometry"); DEFSYM (Qicon_left, "icon-left"); DEFSYM (Qicon_top, "icon-top"); - DEFSYM (Qtooltip, "tooltip"); DEFSYM (Quser_position, "user-position"); DEFSYM (Quser_size, "user-size"); DEFSYM (Qwindow_id, "window-id"); diff --git a/src/frame.h b/src/frame.h index 402d6c0..2c9c414 100644 --- a/src/frame.h +++ b/src/frame.h @@ -342,6 +342,9 @@ struct frame ENUM_BF (output_method) output_method : 3; #ifdef HAVE_WINDOW_SYSTEM + /* True if this frame is a tooltip frame. */ + bool_bf tooltip : 1; + /* See FULLSCREEN_ enum on top. */ ENUM_BF (fullscreen_type) want_fullscreen : 4; @@ -351,9 +354,7 @@ struct frame /* Nonzero if we should actually display horizontal scroll bars on this frame. */ bool_bf horizontal_scroll_bars : 1; -#endif /* HAVE_WINDOW_SYSTEM */ -#if defined (HAVE_WINDOW_SYSTEM) /* True if this is an undecorated frame. */ bool_bf undecorated : 1; @@ -967,6 +968,7 @@ struct frame #define FRAME_Z_GROUP_ABOVE_SUSPENDED(f) \ ((f)->z_group == z_group_above_suspended) #define FRAME_Z_GROUP_BELOW(f) ((f)->z_group == z_group_below) +#define FRAME_TOOLTIP_P(f) ((f)->tooltip) #ifdef NS_IMPL_COCOA #define FRAME_NS_APPEARANCE(f) ((f)->ns_appearance) #define FRAME_NS_TRANSPARENT_TITLEBAR(f) ((f)->ns_transparent_titlebar) @@ -983,6 +985,7 @@ struct frame #define FRAME_Z_GROUP_NONE(f) ((void) (f), true) #define FRAME_Z_GROUP_ABOVE(f) ((void) (f), false) #define FRAME_Z_GROUP_BELOW(f) ((void) (f), false) +#define FRAME_TOOLTIP_P(f) ((void) f, false) #endif /* HAVE_WINDOW_SYSTEM */ /* Whether horizontal scroll bars are currently enabled for frame F. */ diff --git a/src/gtkutil.c b/src/gtkutil.c index 047417f..34c0fcc 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -687,6 +687,7 @@ struct xg_frame_tb_info g_signal_connect (x->ttip_lbl, "hierarchy-changed", G_CALLBACK (hierarchy_ch_cb), f); } + return FALSE; } @@ -713,7 +714,8 @@ struct xg_frame_tb_info GtkRequisition req; Lisp_Object encoded_string; - if (!x->ttip_lbl) return 0; + if (!x->ttip_lbl) + return FALSE; block_input (); encoded_string = ENCODE_UTF_8 (string); @@ -745,7 +747,7 @@ struct xg_frame_tb_info unblock_input (); - return 1; + return TRUE; #endif /* USE_GTK_TOOLTIP */ } @@ -768,18 +770,18 @@ struct xg_frame_tb_info #endif } + /* Hide tooltip if shown. Do nothing if not shown. Return true if tip was hidden, false if not (i.e. not using system tooltips). */ - bool xg_hide_tooltip (struct frame *f) { - bool ret = 0; #ifdef USE_GTK_TOOLTIP if (f->output_data.x->ttip_window) { GtkWindow *win = f->output_data.x->ttip_window; + block_input (); gtk_widget_hide (GTK_WIDGET (win)); @@ -792,10 +794,10 @@ struct xg_frame_tb_info } unblock_input (); - ret = 1; + return TRUE; } #endif - return ret; + return FALSE; } diff --git a/src/nsfns.m b/src/nsfns.m index d5049a7..4c8376e 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -2753,10 +2753,6 @@ and GNUstep implementations ("distributor-specific release return make_number (1 << min (dpyinfo->n_planes, 24)); } - -/* Unused dummy def needed for compatibility. */ -Lisp_Object tip_frame; - /* TODO: move to xdisp or similar */ static void compute_tip_xy (struct frame *f, diff --git a/src/w32fns.c b/src/w32fns.c index ed375cd..55db4d5 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -6423,7 +6423,7 @@ DISPLAY should be either a frame or a display name (a string). { struct frame *f = XFRAME (frame); - if (FRAME_W32_P (f) && !EQ (frame, tip_frame)) + if (FRAME_W32_P (f) && !FRAME_TOOLTIP_P (f)) { HMONITOR monitor = monitor_from_window_fn (FRAME_W32_WINDOW (f), @@ -6510,7 +6510,7 @@ DISPLAY should be either a frame or a display name (a string). { struct frame *f = XFRAME (frame); - if (FRAME_W32_P (f) && !EQ (frame, tip_frame)) + if (FRAME_W32_P (f) && !FRAME_TOOLTIP_P (f)) frames = Fcons (frame, frames); } attributes = Fcons (Fcons (Qframes, frames), attributes); @@ -6916,20 +6916,25 @@ no value of TYPE (always string in the MS Windows case). */) static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, Lisp_Object, int, int, int *, int *); -/* The frame of a currently visible tooltip. */ - +/* The frame of the currently visible tooltip. */ Lisp_Object tip_frame; -/* If non-nil, a timer started that hides the last tooltip when it - fires. */ +/* The window-system window corresponding to the frame of the + currently visible tooltip. */ +Window tip_window; +/* A timer that hides or deletes the currently visible tooltip when it + fires. */ Lisp_Object tip_timer; -Window tip_window; -/* If non-nil, a vector of 3 elements containing the last args - with which x-show-tip was called. See there. */ +/* STRING argument of last `x-show-tip' call. */ +Lisp_Object tip_last_string; -Lisp_Object last_show_tip_args; +/* FRAME argument of last `x-show-tip' call. */ +Lisp_Object tip_last_frame; + +/* PARMS argument of last `x-show-tip' call. */ +Lisp_Object tip_last_parms; static void @@ -7002,6 +7007,7 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, FRAME_FONTSET (f) = -1; fset_icon_name (f, Qnil); + f->tooltip = true; #ifdef GLYPH_DEBUG image_cache_refcount = @@ -7113,9 +7119,6 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, SET_FRAME_LINES (f, 0); adjust_frame_size (f, width * FRAME_COLUMN_WIDTH (f), height * FRAME_LINE_HEIGHT (f), 0, true, Qtip_frame); - /* Add `tooltip' frame parameter's default value. */ - if (NILP (Fframe_parameter (frame, Qtooltip))) - Fmodify_frame_parameters (frame, Fcons (Fcons (Qtooltip, Qt), Qnil)); /* Set up faces after all frame parameters are known. This call also merges in face attributes specified for new frames. @@ -7261,7 +7264,17 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, *root_x = min_x; } -/* Hide tooltip. Delete its frame if DELETE is true. */ +/** + * x_hide_tip: + * + * Hide currently visible tooltip and cancel its timer. + * + * This will try to make tooltip_frame invisible (if DELETE is false) + * or delete tooltip_frame (if DELETE is true). + * + * Return Qt if the tooltip was either deleted or made invisible, Qnil + * otherwise. + */ static Lisp_Object x_hide_tip (bool delete) { @@ -7286,15 +7299,20 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, if (FRAMEP (tip_frame)) { - if (delete) + if (FRAME_LIVE_P (XFRAME (tip_frame))) { - delete_frame (tip_frame, Qnil); - tip_frame = Qnil; + if (delete) + { + delete_frame (tip_frame, Qnil); + tip_frame = Qnil; + } + else + x_make_frame_invisible (XFRAME (tip_frame)); + + was_open = Qt; } else - x_make_frame_invisible (XFRAME (tip_frame)); - - was_open = Qt; + tip_frame = Qnil; } else tip_frame = Qnil; @@ -7334,7 +7352,8 @@ with offset DY added (default is -10). A tooltip's maximum size is specified by `x-max-tooltip-size'. Text larger than the specified size is clipped. */) - (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) + (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, + Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) { struct frame *tip_f; struct window *w; @@ -7345,8 +7364,7 @@ with offset DY added (default is -10). int old_windows_or_buffers_changed = windows_or_buffers_changed; ptrdiff_t count = SPECPDL_INDEX (); ptrdiff_t count_1; - Lisp_Object window, size; - Lisp_Object tip_buf; + Lisp_Object window, size, tip_buf; AUTO_STRING (tip, " *tip*"); specbind (Qinhibit_redisplay, Qt); @@ -7368,19 +7386,12 @@ with offset DY added (default is -10). else CHECK_NUMBER (dy); - if (NILP (last_show_tip_args)) - last_show_tip_args = Fmake_vector (make_number (3), Qnil); - if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame))) { - Lisp_Object last_string = AREF (last_show_tip_args, 0); - Lisp_Object last_frame = AREF (last_show_tip_args, 1); - Lisp_Object last_parms = AREF (last_show_tip_args, 2); - if (FRAME_VISIBLE_P (XFRAME (tip_frame)) - && EQ (frame, last_frame) - && !NILP (Fequal_including_properties (last_string, string)) - && !NILP (Fequal (last_parms, parms))) + && EQ (frame, tip_last_frame) + && !NILP (Fequal_including_properties (string, tip_last_string)) + && !NILP (Fequal (parms, tip_last_parms))) { /* Only DX and DY have changed. */ tip_f = XFRAME (tip_frame); @@ -7414,14 +7425,14 @@ with offset DY added (default is -10). goto start_timer; } - else if (tooltip_reuse_hidden_frame && EQ (frame, last_frame)) + else if (tooltip_reuse_hidden_frame && EQ (frame, tip_last_frame)) { bool delete = false; Lisp_Object tail, elt, parm, last; /* Check if every parameter in PARMS has the same value in - last_parms. This may destruct last_parms which, however, - will be recreated below. */ + tip_last_parms. This may destruct tip_last_parms + which, however, will be recreated below. */ for (tail = parms; CONSP (tail); tail = XCDR (tail)) { elt = XCAR (tail); @@ -7431,7 +7442,7 @@ with offset DY added (default is -10). if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright) && !EQ (parm, Qbottom)) { - last = Fassq (parm, last_parms); + last = Fassq (parm, tip_last_parms); if (NILP (Fequal (Fcdr (elt), Fcdr (last)))) { /* We lost, delete the old tooltip. */ @@ -7439,15 +7450,17 @@ with offset DY added (default is -10). break; } else - last_parms = call2 (Qassq_delete_all, parm, last_parms); + tip_last_parms = + call2 (Qassq_delete_all, parm, tip_last_parms); } else - last_parms = call2 (Qassq_delete_all, parm, last_parms); + tip_last_parms = + call2 (Qassq_delete_all, parm, tip_last_parms); } - /* Now check if there's a parameter left in last_parms with a + /* Now check if there's a parameter left in tip_last_parms with a non-nil value. */ - for (tail = last_parms; CONSP (tail); tail = XCDR (tail)) + for (tail = tip_last_parms; CONSP (tail); tail = XCDR (tail)) { elt = XCAR (tail); parm = Fcar (elt); @@ -7468,9 +7481,9 @@ with offset DY added (default is -10). else x_hide_tip (true); - ASET (last_show_tip_args, 0, string); - ASET (last_show_tip_args, 1, frame); - ASET (last_show_tip_args, 2, parms); + tip_last_frame = frame; + tip_last_string = string; + tip_last_parms = parms; /* Block input until the tip has been fully drawn, to avoid crashes when drawing tips in menus. */ @@ -7486,7 +7499,8 @@ with offset DY added (default is -10). if (NILP (Fassq (Qborder_width, parms))) parms = Fcons (Fcons (Qborder_width, make_number (1)), parms); if (NILP (Fassq (Qborder_color, parms))) - parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms); + parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), + parms); if (NILP (Fassq (Qbackground_color, parms))) parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")), parms); @@ -10805,9 +10819,12 @@ successive mouse move (or scroll bar drag) events before they are staticpro (&tip_timer); tip_frame = Qnil; staticpro (&tip_frame); - - last_show_tip_args = Qnil; - staticpro (&last_show_tip_args); + tip_last_frame = Qnil; + staticpro (&tip_last_frame); + tip_last_string = Qnil; + staticpro (&tip_last_string); + tip_last_parms = Qnil; + staticpro (&tip_last_parms); defsubr (&Sx_file_dialog); #ifdef WINDOWSNT diff --git a/src/w32term.c b/src/w32term.c index db4ccf5..137c798 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -5569,7 +5569,7 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object struct frame *f = XFRAME (frame); /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED below. */ - if (EQ (frame, tip_frame)) + if (FRAME_TOOLTIP_P (f)) continue; /* Check "visible" frames and mark each as obscured or not. @@ -6046,7 +6046,7 @@ static void x_horizontal_scroll_bar_report_motion (struct frame **, Lisp_Object /* Don't change the size of a tip frame; there's no point in doing it because it's done in Fx_show_tip, and it leads to problems because the tip frame has no widget. */ - if (NILP (tip_frame) || XFRAME (tip_frame) != f) + if (!FRAME_TOOLTIP_P (f)) adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, false, Qfont); diff --git a/src/w32term.h b/src/w32term.h index e500b73..c69bebe 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -817,6 +817,8 @@ typedef BOOL (WINAPI * AppendMenuW_Proc) ( extern int w32_system_caret_hdr_height; extern int w32_system_caret_mode_height; +extern Window tip_window; + #ifdef _MSC_VER #ifndef EnumSystemLocales /* MSVC headers define these only for _WIN32_WINNT >= 0x0500. */ diff --git a/src/xdisp.c b/src/xdisp.c index 59fa00e..d2bb47f 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -11866,7 +11866,7 @@ static void ATTRIBUTE_FORMAT_PRINTF (1, 0) if ((FRAME_WINDOW_P (f) || FRAME_MINIBUF_ONLY_P (f) || f->explicit_name) - && NILP (Fframe_parameter (frame, Qtooltip))) + && !FRAME_TOOLTIP_P (f)) { /* Do we have more than one visible frame on this X display? */ Lisp_Object tail, other_frame, fmt; @@ -11883,8 +11883,8 @@ static void ATTRIBUTE_FORMAT_PRINTF (1, 0) if (tf != f && FRAME_KBOARD (tf) == FRAME_KBOARD (f) && !FRAME_MINIBUF_ONLY_P (tf) - && !EQ (other_frame, tip_frame) && !FRAME_PARENT_FRAME (tf) + && !FRAME_TOOLTIP_P (tf) && (FRAME_VISIBLE_P (tf) || FRAME_ICONIFIED_P (tf))) break; } @@ -11953,13 +11953,6 @@ static void ATTRIBUTE_FORMAT_PRINTF (1, 0) { bool all_windows = windows_or_buffers_changed || update_mode_lines; bool some_windows = REDISPLAY_SOME_P (); - Lisp_Object tooltip_frame; - -#ifdef HAVE_WINDOW_SYSTEM - tooltip_frame = tip_frame; -#else - tooltip_frame = Qnil; -#endif if (FUNCTIONP (Vpre_redisplay_function)) { @@ -12000,7 +11993,7 @@ static void ATTRIBUTE_FORMAT_PRINTF (1, 0) && !XBUFFER (w->contents)->text->redisplay) continue; - if (!EQ (frame, tooltip_frame) + if (!FRAME_TOOLTIP_P (f) && !FRAME_PARENT_FRAME (f) && (FRAME_ICONIFIED_P (f) || FRAME_VISIBLE_P (f) == 1 @@ -12038,7 +12031,7 @@ static void ATTRIBUTE_FORMAT_PRINTF (1, 0) struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f)); /* Ignore tooltip frame. */ - if (EQ (frame, tooltip_frame)) + if (FRAME_TOOLTIP_P (f)) continue; if (some_windows @@ -21160,13 +21153,7 @@ struct glyph_row * #ifdef HAVE_WINDOW_SYSTEM /* Don't display line number in tooltip frames. */ - if (FRAMEP (tip_frame) && EQ (WINDOW_FRAME (it->w), tip_frame) -#ifdef USE_GTK - /* GTK builds store in tip_frame the frame that shows the tip, - so we need an additional test. */ - && !NILP (Fframe_parameter (tip_frame, Qtooltip)) -#endif - ) + if (FRAME_TOOLTIP_P (XFRAME (WINDOW_FRAME (it->w)))) return false; #endif @@ -30841,9 +30828,11 @@ A polygon is a cons (poly . [x0 y0 x1 y1 ...]) where each pair in the = buffer_local_value (Qmode_line_default_help_echo, w->contents); - if (STRINGP (default_help)) + if (FUNCTIONP (default_help) || STRINGP (default_help)) { - help_echo_string = 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; diff --git a/src/xfns.c b/src/xfns.c index 12b7d83..0176e2b 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -4612,8 +4612,9 @@ struct mouse_cursor_data { { struct frame *f = XFRAME (frame); - if (FRAME_X_P (f) && FRAME_DISPLAY_INFO (f) == dpyinfo - && !EQ (frame, tip_frame)) + if (FRAME_X_P (f) + && FRAME_DISPLAY_INFO (f) == dpyinfo + && !FRAME_TOOLTIP_P (f)) { int i = x_get_monitor_for_frame (f, monitors, n_monitors); ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i))); @@ -4914,12 +4915,9 @@ struct mouse_cursor_data { { struct frame *f = XFRAME (frame); - if (FRAME_X_P (f) && FRAME_DISPLAY_INFO (f) == dpyinfo - && !(EQ (frame, tip_frame) -#ifdef USE_GTK - && !NILP (Fframe_parameter (tip_frame, Qtooltip)) -#endif - )) + if (FRAME_X_P (f) + && FRAME_DISPLAY_INFO (f) == dpyinfo + && !FRAME_TOOLTIP_P (f)) { GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_WIDGET (f)); @@ -6052,22 +6050,27 @@ no value of TYPE (always string in the MS Windows case). */) ***********************************************************************/ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, - Lisp_Object, int, int, int *, int *); - -/* The frame of a currently visible tooltip. */ + Lisp_Object, int, int, int *, int *); +/* The frame of the currently visible tooltip. */ Lisp_Object tip_frame; -/* If non-nil, a timer started that hides the last tooltip when it +/* The window-system window corresponding to the frame of the + currently visible tooltip. */ +Window tip_window; + +/* A timer that hides or deletes the currently visible tooltip when it fires. */ +Lisp_Object tip_timer; -static Lisp_Object tip_timer; -Window tip_window; +/* STRING argument of last `x-show-tip' call. */ +Lisp_Object tip_last_string; -/* If non-nil, a vector of 3 elements containing the last args - with which x-show-tip was called. See there. */ +/* FRAME argument of last `x-show-tip' call. */ +Lisp_Object tip_last_frame; -static Lisp_Object last_show_tip_args; +/* PARMS argument of last `x-show-tip' call. */ +Lisp_Object tip_last_parms; static void @@ -6141,6 +6144,7 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, f->output_data.x->white_relief.pixel = -1; f->output_data.x->black_relief.pixel = -1; + f->tooltip = true; fset_icon_name (f, Qnil); FRAME_DISPLAY_INFO (f) = dpyinfo; f->output_data.x->parent_desc = FRAME_DISPLAY_INFO (f)->root_window; @@ -6324,13 +6328,6 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, SET_FRAME_LINES (f, 0); change_frame_size (f, width, height, true, false, false, false); - /* Add `tooltip' frame parameter's default value. */ - if (NILP (Fframe_parameter (frame, Qtooltip))) - { - AUTO_FRAME_ARG (arg, Qtooltip, Qt); - Fmodify_frame_parameters (frame, arg); - } - /* FIXME - can this be done in a similar way to normal frames? https://lists.gnu.org/r/emacs-devel/2007-10/msg00641.html */ @@ -6405,7 +6402,9 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, the display in *ROOT_X, and *ROOT_Y. */ static void -compute_tip_xy (struct frame *f, Lisp_Object parms, Lisp_Object dx, Lisp_Object dy, int width, int height, int *root_x, int *root_y) +compute_tip_xy (struct frame *f, + Lisp_Object parms, Lisp_Object dx, Lisp_Object dy, + int width, int height, int *root_x, int *root_y) { Lisp_Object left, top, right, bottom; int win_x, win_y; @@ -6502,7 +6501,19 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, } -/* Hide tooltip. Delete its frame if DELETE is true. */ +/** + * x_hide_tip: + * + * Hide currently visible tooltip and cancel its timer. + * + * If GTK+ system tooltips are used, this will try to hide the tooltip + * referenced by the x_output structure of tooltip_last_frame. For + * Emacs tooltips this will try to make tooltip_frame invisible (if + * DELETE is false) or delete tooltip_frame (if DELETE is true). + * + * Return Qt if the tooltip was either deleted or made invisible, Qnil + * otherwise. + */ static Lisp_Object x_hide_tip (bool delete) { @@ -6512,10 +6523,17 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, tip_timer = Qnil; } - - if (NILP (tip_frame) - || (!delete && FRAMEP (tip_frame) - && !FRAME_VISIBLE_P (XFRAME (tip_frame)))) +#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))))) return Qnil; else { @@ -6526,61 +6544,114 @@ static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object, specbind (Qinhibit_redisplay, Qt); specbind (Qinhibit_quit, Qt); -#ifdef USE_GTK - { - /* When using system tooltip, tip_frame is the Emacs frame on - which the tip is shown. */ - struct frame *f = XFRAME (tip_frame); - - if (FRAME_LIVE_P (f) && xg_hide_tooltip (f)) - { - tip_frame = Qnil; - was_open = Qt; - } - } -#endif + if (x_gtk_use_system_tooltips) + { + /* The GTK+ system tooltip window is stored in the x_output + structure of tip_last_frame. */ + struct frame *f = XFRAME (tip_last_frame); - if (FRAMEP (tip_frame)) + if (FRAME_LIVE_P (f)) + { + if (xg_hide_tooltip (f)) + was_open = Qt; + } + else + tip_last_frame = Qnil; + } + else { - if (delete) + if (FRAMEP (tip_frame)) { - delete_frame (tip_frame, Qnil); - tip_frame = Qnil; + struct frame *f = XFRAME (tip_frame); + + if (FRAME_LIVE_P (f)) + { + if (delete) + { + delete_frame (tip_frame, Qnil); + tip_frame = Qnil; + } + else + x_make_frame_invisible (f); + + was_open = Qt; + } + else + tip_frame = Qnil; } else - x_make_frame_invisible (XFRAME (tip_frame)); + tip_frame = Qnil; + } + + return unbind_to (count, was_open); + } +#else /* not USE_GTK */ + if (NILP (tip_frame) + || (!delete + && FRAMEP (tip_frame) + && FRAME_LIVE_P (XFRAME (tip_frame)) + && !FRAME_VISIBLE_P (XFRAME (tip_frame)))) + return Qnil; + else + { + ptrdiff_t count; + Lisp_Object was_open = Qnil; + + count = SPECPDL_INDEX (); + specbind (Qinhibit_redisplay, Qt); + specbind (Qinhibit_quit, Qt); + + if (FRAMEP (tip_frame)) + { + struct frame *f = XFRAME (tip_frame); - was_open = Qt; + if (FRAME_LIVE_P (f)) + { + if (delete) + { + delete_frame (tip_frame, Qnil); + tip_frame = Qnil; + } + else + x_make_frame_invisible (XFRAME (tip_frame)); #ifdef USE_LUCID - /* Bloodcurdling hack alert: The Lucid menu bar widget's - redisplay procedure is not called when a tip frame over - menu items is unmapped. Redisplay the menu manually... */ - { - Widget w; - struct frame *f = SELECTED_FRAME (); - if (FRAME_X_P (f) && FRAME_LIVE_P (f)) + /* Bloodcurdling hack alert: The Lucid menu bar widget's + redisplay procedure is not called when a tip frame over + menu items is unmapped. Redisplay the menu manually... */ { - w = f->output_data.x->menubar_widget; + Widget w; + struct frame *f = SELECTED_FRAME (); - if (!DoesSaveUnders (FRAME_DISPLAY_INFO (f)->screen) - && w != NULL) + if (FRAME_X_P (f) && FRAME_LIVE_P (f)) { - block_input (); - xlwmenu_redisplay (w); - unblock_input (); + w = f->output_data.x->menubar_widget; + + if (!DoesSaveUnders (FRAME_DISPLAY_INFO (f)->screen) + && w != NULL) + { + block_input (); + xlwmenu_redisplay (w); + unblock_input (); + } } } - } #endif /* USE_LUCID */ + + was_open = Qt; + } + else + tip_frame = Qnil; } else tip_frame = Qnil; return unbind_to (count, was_open); } +#endif /* USE_GTK */ } + DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, doc: /* Show STRING in a "tooltip" window on frame FRAME. A tooltip window is a small X window displaying a string. @@ -6611,7 +6682,8 @@ with offset DY added (default is -10). A tooltip's maximum size is specified by `x-max-tooltip-size'. Text larger than the specified size is clipped. */) - (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) + (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, + Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) { struct frame *f, *tip_f; struct window *w; @@ -6622,8 +6694,7 @@ with offset DY added (default is -10). int old_windows_or_buffers_changed = windows_or_buffers_changed; ptrdiff_t count = SPECPDL_INDEX (); ptrdiff_t count_1; - Lisp_Object window, size; - Lisp_Object tip_buf; + Lisp_Object window, size, tip_buf; AUTO_STRING (tip, " *tip*"); specbind (Qinhibit_redisplay, Qt); @@ -6662,36 +6733,27 @@ with offset DY added (default is -10). { compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y); xg_show_tooltip (f, root_x, root_y); - /* This is used in Fx_hide_tip. */ - XSETFRAME (tip_frame, f); + tip_last_frame = frame; } + unblock_input (); if (ok) goto start_timer; } #endif /* USE_GTK */ - if (NILP (last_show_tip_args)) - last_show_tip_args = Fmake_vector (make_number (3), Qnil); - if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame))) { - Lisp_Object last_string = AREF (last_show_tip_args, 0); - Lisp_Object last_frame = AREF (last_show_tip_args, 1); - Lisp_Object last_parms = AREF (last_show_tip_args, 2); - if (FRAME_VISIBLE_P (XFRAME (tip_frame)) - && EQ (frame, last_frame) - && !NILP (Fequal_including_properties (last_string, string)) - && !NILP (Fequal (last_parms, parms))) + && EQ (frame, tip_last_frame) + && !NILP (Fequal_including_properties (tip_last_string, string)) + && !NILP (Fequal (tip_last_parms, parms))) { /* Only DX and DY have changed. */ tip_f = XFRAME (tip_frame); if (!NILP (tip_timer)) { - Lisp_Object timer = tip_timer; - + call1 (Qcancel_timer, tip_timer); tip_timer = Qnil; - call1 (Qcancel_timer, timer); } block_input (); @@ -6703,15 +6765,14 @@ with offset DY added (default is -10). goto start_timer; } - else if (tooltip_reuse_hidden_frame && EQ (frame, last_frame)) + else if (tooltip_reuse_hidden_frame && EQ (frame, tip_last_frame)) { bool delete = false; Lisp_Object tail, elt, parm, last; /* Check if every parameter in PARMS has the same value in - last_parms unless it should be ignored by means of - Vtooltip_reuse_hidden_frame_parameters. This may destruct - last_parms which, however, will be recreated below. */ + tip_last_parms. This may destruct tip_last_parms which, + however, will be recreated below. */ for (tail = parms; CONSP (tail); tail = XCDR (tail)) { elt = XCAR (tail); @@ -6721,7 +6782,7 @@ with offset DY added (default is -10). if (!EQ (parm, Qleft) && !EQ (parm, Qtop) && !EQ (parm, Qright) && !EQ (parm, Qbottom)) { - last = Fassq (parm, last_parms); + last = Fassq (parm, tip_last_parms); if (NILP (Fequal (Fcdr (elt), Fcdr (last)))) { /* We lost, delete the old tooltip. */ @@ -6729,17 +6790,18 @@ with offset DY added (default is -10). break; } else - last_parms = call2 (Qassq_delete_all, parm, last_parms); + tip_last_parms = + call2 (Qassq_delete_all, parm, tip_last_parms); } else - last_parms = call2 (Qassq_delete_all, parm, last_parms); + tip_last_parms = + call2 (Qassq_delete_all, parm, tip_last_parms); } - /* Now check if every parameter in what is left of last_parms - with a non-nil value has an association in PARMS unless it - should be ignored by means of - Vtooltip_reuse_hidden_frame_parameters. */ - for (tail = last_parms; CONSP (tail); tail = XCDR (tail)) + /* Now check if every parameter in what is left of + tip_last_parms with a non-nil value has an association in + PARMS. */ + for (tail = tip_last_parms; CONSP (tail); tail = XCDR (tail)) { elt = XCAR (tail); parm = Fcar (elt); @@ -6760,9 +6822,9 @@ with offset DY added (default is -10). else x_hide_tip (true); - ASET (last_show_tip_args, 0, string); - ASET (last_show_tip_args, 1, frame); - ASET (last_show_tip_args, 2, parms); + tip_last_frame = frame; + tip_last_string = string; + tip_last_parms = parms; if (!FRAMEP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame))) { @@ -7823,7 +7885,6 @@ FRAMES should be nil (the selected frame), a frame, or a list of defsubr (&Sx_display_list); defsubr (&Sx_synchronize); defsubr (&Sx_backspace_delete_keys_p); - defsubr (&Sx_show_tip); defsubr (&Sx_hide_tip); defsubr (&Sx_double_buffered_p); @@ -7831,9 +7892,12 @@ FRAMES should be nil (the selected frame), a frame, or a list of staticpro (&tip_timer); tip_frame = Qnil; staticpro (&tip_frame); - - last_show_tip_args = Qnil; - staticpro (&last_show_tip_args); + tip_last_frame = Qnil; + staticpro (&tip_last_frame); + tip_last_string = Qnil; + staticpro (&tip_last_string); + tip_last_parms = Qnil; + staticpro (&tip_last_parms); defsubr (&Sx_uses_old_gtk_dialog); #if defined (USE_MOTIF) || defined (USE_GTK) diff --git a/src/xterm.c b/src/xterm.c index f771631..0a2068d 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -996,12 +996,7 @@ struct x_display_info * x_update_begin (struct frame *f) { #ifdef USE_CAIRO - if (! NILP (tip_frame) && XFRAME (tip_frame) == f - && ! FRAME_VISIBLE_P (f) -#ifdef USE_GTK - && !NILP (Fframe_parameter (tip_frame, Qtooltip)) -#endif - ) + if (FRAME_TOOLTIP_P (f) && !FRAME_VISIBLE_P (f)) return; if (! FRAME_CR_SURFACE (f)) @@ -8091,7 +8086,7 @@ static void xembed_send_message (struct frame *f, Time, /* Redo the mouse-highlight after the tooltip has gone. */ if (event->xunmap.window == tip_window) { - tip_window = 0; + tip_window = None; x_redo_mouse_highlight (dpyinfo); } @@ -8733,7 +8728,7 @@ static void xembed_send_message (struct frame *f, Time, #ifdef USE_X_TOOLKIT /* Tip frames are pure X window, set size for them. */ - if (! NILP (tip_frame) && XFRAME (tip_frame) == f) + if (FRAME_TOOLTIP_P (f)) { if (FRAME_PIXEL_HEIGHT (f) != configureEvent.xconfigure.height || FRAME_PIXEL_WIDTH (f) != configureEvent.xconfigure.width) @@ -9971,11 +9966,7 @@ struct x_error_message_stack { /* Don't change the size of a tip frame; there's no point in doing it because it's done in Fx_show_tip, and it leads to problems because the tip frame has no widget. */ - if (NILP (tip_frame) || XFRAME (tip_frame) != f -#ifdef USE_GTK - || NILP (Fframe_parameter (tip_frame, Qtooltip)) -#endif - ) + if (!FRAME_TOOLTIP_P (f)) { adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, @@ -11204,7 +11195,7 @@ struct x_error_message_stack { /* The following breaks our calculations. If it's really needed, think of something else. */ #if false - if (NILP (tip_frame) || XFRAME (tip_frame) != f) + if (!FRAME_TOOLTIP_P (f)) { int text_width, text_height; diff --git a/src/xterm.h b/src/xterm.h index f73dd0e..1849a5c 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -503,6 +503,8 @@ struct x_display_info extern void select_visual (struct x_display_info *); +extern Window tip_window; + /* Each X frame object points to its own struct x_output object in the output_data.x field. The x_output structure contains the information that is specific to X windows. */