From 54b7eb0dee2397f1430e81b7356f8efb19946ba0 Mon Sep 17 00:00:00 2001 From: John Wiegley Date: Tue, 12 Jul 2016 15:27:25 -0700 Subject: [PATCH] Revert "Cleanup tooltips" This reverts commit 20038f8ab75dd1551412a43cd58520c483c22921. I am reverting this change because it was applied without prior discussion on emacs-devel, and has been found to break the NS port. It needs more testing and review before it should be applied here. --- src/dispextern.h | 2 + src/frame.c | 19 ++-- src/frame.h | 9 -- src/gtkutil.c | 29 +---- src/gtkutil.h | 1 - src/menu.c | 7 +- src/nsfns.m | 4 + src/w32fns.c | 213 +++++++++++++++++++----------------- src/w32term.c | 15 ++- src/w32term.h | 3 - src/xdisp.c | 21 +++- src/xfns.c | 277 +++++++++++++++++++++++------------------------ src/xterm.c | 19 ++-- src/xterm.h | 4 - 14 files changed, 304 insertions(+), 319 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index c2fcca5591..1325ff9da2 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3461,6 +3461,8 @@ void gamma_correct (struct frame *, COLORREF *); void x_implicitly_set_name (struct frame *, Lisp_Object, Lisp_Object); void x_change_tool_bar_height (struct frame *f, int); +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 80e181f89e..22143ab26b 100644 --- a/src/frame.c +++ b/src/frame.c @@ -642,7 +642,6 @@ make_frame (bool mini_p) f->vertical_scroll_bar_type = vertical_scroll_bar_none; f->horizontal_scroll_bars = false; f->want_fullscreen = FULLSCREEN_NONE; - f->tooltip = false; #if ! defined (USE_GTK) && ! defined (HAVE_NS) f->last_tool_bar_item = -1; #endif @@ -1261,16 +1260,13 @@ DEFUN ("frame-list", Fframe_list, Sframe_list, doc: /* Return a list of all live frames. */) (void) { + Lisp_Object frames; + frames = Fcopy_sequence (Vframe_list); #ifdef HAVE_WINDOW_SYSTEM - Lisp_Object list = Qnil, tail, frame; - - FOR_EACH_FRAME (tail, frame) - if (!FRAME_TOOLTIP_P (XFRAME (frame))) - list = Fcons (frame, list); - return list; -#else /* !HAVE_WINDOW_SYSTEM */ - return Fcopy_sequence (Vframe_list); + if (FRAMEP (tip_frame)) + frames = Fdelq (tip_frame, frames); #endif + return frames; } /* Return CANDIDATE if it can be used as 'other-than-FRAME' frame on the @@ -1561,7 +1557,7 @@ delete_frame (Lisp_Object frame, Lisp_Object force) } } - is_tooltip_frame = FRAME_TOOLTIP_P (f); + is_tooltip_frame = !NILP (Fframe_parameter (frame, Qtooltip)); /* Run `delete-frame-functions' unless FORCE is `noelisp' or frame is a tooltip. FORCE is set to `noelisp' when handling @@ -4904,6 +4900,7 @@ syms_of_frame (void) 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"); @@ -5025,8 +5022,6 @@ syms_of_frame (void) DEFSYM (Qvertical_scroll_bars, "vertical-scroll-bars"); DEFSYM (Qvisibility, "visibility"); DEFSYM (Qwait_for_wm, "wait-for-wm"); - DEFSYM (Qtooltip_timer, "tooltip-timer"); - DEFSYM (Qtooltip_parameters, "tooltip-parameters"); { int i; diff --git a/src/frame.h b/src/frame.h index 635a5ed7be..5e3ee68942 100644 --- a/src/frame.h +++ b/src/frame.h @@ -309,9 +309,6 @@ 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; @@ -864,9 +861,6 @@ default_pixels_per_inch_y (void) #define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT(f) \ ((f)->vertical_scroll_bar_type == vertical_scroll_bar_right) -/* Whether F is a tooltip frame. */ -#define FRAME_TOOLTIP_P(f) ((f)->tooltip) - #else /* not HAVE_WINDOW_SYSTEM */ /* If there is no window system, there are no scroll bars. */ @@ -875,9 +869,6 @@ default_pixels_per_inch_y (void) #define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT(f) ((void) f, 0) #define FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT(f) ((void) f, 0) -/* If there is no window system, there are no tooltips. */ -#define FRAME_TOOLTIP_P(f) ((void) f, 0) - #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 e08a4b5348..88e6d30bd9 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -731,23 +731,14 @@ xg_show_tooltip (struct frame *f, int root_x, int root_y) bool xg_hide_tooltip (struct frame *f) { + bool ret = 0; #ifdef USE_GTK_TOOLTIP - struct x_output *x = FRAME_X_OUTPUT (f); - - if (x->ttip_window) + if (f->output_data.x->ttip_window) { GtkWindow *win = f->output_data.x->ttip_window; - block_input (); gtk_widget_hide (GTK_WIDGET (win)); - /* Cancel call to xg_hide_tip. */ - if (x->ttip_timeout != 0) - { - g_source_remove (x->ttip_timeout); - x->ttip_timeout = 0; - } - if (g_object_get_data (G_OBJECT (win), "restore-tt")) { GdkWindow *gwin = gtk_widget_get_window (GTK_WIDGET (win)); @@ -756,21 +747,11 @@ xg_hide_tooltip (struct frame *f) g_object_set (settings, "gtk-enable-tooltips", TRUE, NULL); } unblock_input (); - return 1; - } -#endif - return 0; -} -/* One-shot timeout handler attached to GTK event loop in Fx_show_tip. */ - -gboolean -xg_hide_tip (gpointer data) -{ -#ifdef USE_GTK_TOOLTIP - xg_hide_tooltip ((struct frame *) data); + ret = 1; + } #endif - return FALSE; + return ret; } diff --git a/src/gtkutil.h b/src/gtkutil.h index d4dc295c51..8840fe76a8 100644 --- a/src/gtkutil.h +++ b/src/gtkutil.h @@ -178,7 +178,6 @@ extern bool xg_prepare_tooltip (struct frame *f, int *height); extern void xg_show_tooltip (struct frame *f, int root_x, int root_y); extern bool xg_hide_tooltip (struct frame *f); -extern gboolean xg_hide_tip (gpointer data); #ifdef USE_CAIRO extern void xg_page_setup_dialog (void); diff --git a/src/menu.c b/src/menu.c index 675caff6b8..90bb19a2e9 100644 --- a/src/menu.c +++ b/src/menu.c @@ -1400,12 +1400,7 @@ no quit occurs and `x-popup-menu' returns nil. */) #ifdef HAVE_WINDOW_SYSTEM /* Hide a previous tip, if any. */ if (!FRAME_TERMCAP_P (f)) - { - Lisp_Object frame; - - XSETFRAME (frame, f); - Fx_hide_tip (frame); - } + Fx_hide_tip (); #endif #ifdef HAVE_NTGUI /* FIXME: Is it really w32-specific? --Stef */ diff --git a/src/nsfns.m b/src/nsfns.m index a017be5c1c..051e509191 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -2658,6 +2658,10 @@ If omitted or nil, that stands for the selected frame's display. */) 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 f5e5b33556..d6b54d19a1 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -343,6 +343,7 @@ x_window_to_frame (struct w32_display_info *dpyinfo, HWND wdesc) static Lisp_Object unwind_create_frame (Lisp_Object); +static void unwind_create_tip_frame (Lisp_Object); static void my_create_window (struct frame *); static void my_create_tip_window (struct frame *); @@ -5067,7 +5068,6 @@ static void my_create_tip_window (struct frame *f) { RECT rect; - Window tip_window; rect.left = rect.top = 0; rect.right = FRAME_PIXEL_WIDTH (f); @@ -5215,8 +5215,9 @@ x_make_gc (struct frame *f) } -/* Handler for signals raised during x_create_frame. - FRAME is the frame which is partially constructed. */ +/* Handler for signals raised during x_create_frame and + x_create_tip_frame. FRAME is the frame which is partially + constructed. */ static Lisp_Object unwind_create_frame (Lisp_Object frame) @@ -5990,7 +5991,7 @@ w32_display_monitor_attributes_list (void) { struct frame *f = XFRAME (frame); - if (FRAME_W32_P (f) && !FRAME_TOOLTIP_P (f)) + if (FRAME_W32_P (f) && !EQ (frame, tip_frame)) { HMONITOR monitor = monitor_from_window_fn (FRAME_W32_WINDOW (f), @@ -6077,7 +6078,7 @@ w32_display_monitor_attributes_list_fallback (struct w32_display_info *dpyinfo) { struct frame *f = XFRAME (frame); - if (FRAME_W32_P (f) && FRAME_TOOLTIP_P (f)) + if (FRAME_W32_P (f) && !EQ (frame, tip_frame)) frames = Fcons (frame, frames); } attributes = Fcons (Fcons (Qframes, frames), attributes); @@ -6480,6 +6481,39 @@ no value of TYPE (always string in the MS Windows case). */) Tool tips ***********************************************************************/ +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 tip_frame; + +/* If non-nil, a timer started that hides the last 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. */ + +Lisp_Object last_show_tip_args; + + +static void +unwind_create_tip_frame (Lisp_Object frame) +{ + Lisp_Object deleted; + + deleted = unwind_create_frame (frame); + if (EQ (deleted, Qt)) + { + tip_window = NULL; + tip_frame = Qnil; + } +} + + /* Create a frame for a tooltip on the display described by DPYINFO. PARMS is a list of frame parameters. Value is the frame. @@ -6524,7 +6558,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms) f->wants_modeline = false; XSETFRAME (frame, f); - record_unwind_protect (do_unwind_create_frame, frame); + record_unwind_protect (unwind_create_tip_frame, frame); /* By setting the output method, we're essentially saying that the frame is live, as per FRAME_LIVE_P. If we get a signal @@ -6536,7 +6570,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms) FRAME_FONTSET (f) = -1; fset_icon_name (f, Qnil); - f->tooltip = true; #ifdef GLYPH_DEBUG image_cache_refcount = @@ -6645,7 +6678,11 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms) height = FRAME_LINES (f); SET_FRAME_COLS (f, 0); SET_FRAME_LINES (f, 0); - change_frame_size (f, width, height, true, false, false, false); + 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. @@ -6673,9 +6710,6 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms) f->no_split = true; - /* Now this is an official tooltip frame on this display. */ - dpyinfo->w32_tooltip_frame = f; - /* Now that the frame is official, it counts as a reference to its display. */ FRAME_DISPLAY_INFO (f)->reference_count++; @@ -6794,39 +6828,46 @@ compute_tip_xy (struct frame *f, *root_x = min_x; } -/* Hide tooltip frame F and delete it if DELETE is true. */ - +/* Hide tooltip. Delete its frame if DELETE is true. */ static Lisp_Object -x_hide_tip (struct frame *f, bool delete) +x_hide_tip (bool delete) { - if (f) + if (!NILP (tip_timer)) { - Lisp_Object frame, timer; + call1 (Qcancel_timer, tip_timer); + tip_timer = Qnil; + } - XSETFRAME (frame, f); - timer = Fframe_parameter (frame, Qtooltip_timer); + if (NILP (tip_frame) + || (!delete && FRAMEP (tip_frame) + && !FRAME_VISIBLE_P (XFRAME (tip_frame)))) + return Qnil; + else + { + ptrdiff_t count; + Lisp_Object was_open = Qnil; - if (!NILP (timer)) - call1 (Qcancel_timer, timer); + count = SPECPDL_INDEX (); + specbind (Qinhibit_redisplay, Qt); + specbind (Qinhibit_quit, Qt); - if (!delete && !FRAME_VISIBLE_P (f)) - return Qnil; - else + if (FRAMEP (tip_frame)) { - ptrdiff_t count = SPECPDL_INDEX (); - - specbind (Qinhibit_redisplay, Qt); - specbind (Qinhibit_quit, Qt); - if (delete) - delete_frame (frame, Qnil); + { + delete_frame (tip_frame, Qnil); + tip_frame = Qnil; + } else - x_make_frame_invisible (f); + x_make_frame_invisible (XFRAME (tip_frame)); - return unbind_to (count, Qt); + was_open = Qt; } + else + tip_frame = Qnil; + + return unbind_to (count, was_open); } - return Qnil; } @@ -6860,8 +6901,7 @@ 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; @@ -6872,7 +6912,7 @@ Text larger than the specified size is clipped. */) int old_windows_or_buffers_changed = windows_or_buffers_changed; ptrdiff_t count = SPECPDL_INDEX (); ptrdiff_t count_1; - Lisp_Object window, size, tip_frame, parameters; + Lisp_Object window, size; AUTO_STRING (tip, " *tip*"); specbind (Qinhibit_redisplay, Qt); @@ -6894,22 +6934,14 @@ Text larger than the specified size is clipped. */) else CHECK_NUMBER (dy); - parameters = Fframe_parameter (frame, Qtooltip_parameters); - if (NILP (parameters)) - parameters = Fmake_vector (make_number (3), Qnil); + if (NILP (last_show_tip_args)) + last_show_tip_args = Fmake_vector (make_number (3), Qnil); - /* Look at current tooltip frame, if any. */ - tip_f = FRAME_DISPLAY_INFO (XFRAME (frame))->w32_tooltip_frame; - if (tip_f) - XSETFRAME (tip_frame, tip_f); - else - tip_frame = Qnil; - - if (tip_f && FRAME_LIVE_P (tip_f)) + if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame))) { - Lisp_Object last_string = AREF (parameters, 0); - Lisp_Object last_frame = AREF (parameters, 1); - Lisp_Object last_parms = AREF (parameters, 2); + 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) @@ -6917,10 +6949,14 @@ Text larger than the specified size is clipped. */) && !NILP (Fequal (last_parms, parms))) { /* Only DX and DY have changed. */ - Lisp_Object timer = Fframe_parameter (tip_frame, Qtooltip_timer); + tip_f = XFRAME (tip_frame); + if (!NILP (tip_timer)) + { + Lisp_Object timer = tip_timer; - if (!NILP (timer)) - call1 (Qcancel_timer, timer); + tip_timer = Qnil; + call1 (Qcancel_timer, timer); + } block_input (); compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f), @@ -6990,22 +7026,17 @@ Text larger than the specified size is clipped. */) } } - x_hide_tip (tip_f, delete); + x_hide_tip (delete); } else - x_hide_tip (tip_f, true); + x_hide_tip (true); } else - x_hide_tip (tip_f, true); + x_hide_tip (true); - /* Update tooltip parameters. */ - { - AUTO_FRAME_ARG (arg, Qtooltip_parameters, parameters); - ASET (parameters, 0, string); - ASET (parameters, 1, frame); - ASET (parameters, 2, parms); - Fmodify_frame_parameters (frame, arg); - } + ASET (last_show_tip_args, 0, string); + ASET (last_show_tip_args, 1, frame); + ASET (last_show_tip_args, 2, parms); /* Block input until the tip has been fully drawn, to avoid crashes when drawing tips in menus. */ @@ -7025,8 +7056,11 @@ Text larger than the specified size is clipped. */) if (NILP (Fassq (Qbackground_color, parms))) parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")), parms); - if (NILP (tip_frame - = x_create_tip_frame (FRAME_DISPLAY_INFO (XFRAME (frame)), parms))) + + /* 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))) { /* Creating the tip frame failed. */ unblock_input (); @@ -7130,47 +7164,20 @@ Text larger than the specified size is clipped. */) windows_or_buffers_changed = old_windows_or_buffers_changed; start_timer: - { - /* Let the tip disappear after timeout seconds. */ - AUTO_FRAME_ARG (arg, Qtooltip_timer, - call3 (intern ("run-at-time"), timeout, - Qnil, intern ("x-hide-tip"))); - Fmodify_frame_parameters (tip_frame, arg); - } + /* Let the tip disappear after timeout seconds. */ + tip_timer = call3 (intern ("run-at-time"), timeout, Qnil, + intern ("x-hide-tip")); + return unbind_to (count, Qnil); } -DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 1, 0, +DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, doc: /* Hide the current tooltip window, if there is any. -Optional FRAME is the frame to hide tooltip on. Value is t if tooltip was open, nil otherwise. */) - (Lisp_Object frame) + (void) { - Lisp_Object obj = Qnil; - - if (NILP (frame)) - { - struct w32_display_info *dpyinfo; - - for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) - if (dpyinfo->w32_tooltip_frame) - if (!NILP (x_hide_tip (dpyinfo->w32_tooltip_frame, - !tooltip_reuse_hidden_frame))) - obj = Qt; - } - else - { - struct frame *f; - - CHECK_FRAME (frame); - f = XFRAME (frame); - if (FRAME_DISPLAY_INFO (f) - && FRAME_DISPLAY_INFO (f)->w32_tooltip_frame) - obj = x_hide_tip (FRAME_DISPLAY_INFO (f)->w32_tooltip_frame, - !tooltip_reuse_hidden_frame); - } - return obj; + return x_hide_tip (!tooltip_reuse_hidden_frame); } /*********************************************************************** @@ -9773,6 +9780,7 @@ syms_of_w32fns (void) DEFSYM (Qworkarea, "workarea"); DEFSYM (Qmm_size, "mm-size"); DEFSYM (Qframes, "frames"); + DEFSYM (Qtip_frame, "tip-frame"); DEFSYM (Qassq_delete_all, "assq-delete-all"); DEFSYM (Qunicode_sip, "unicode-sip"); #if defined WINDOWSNT && !defined HAVE_DBUS @@ -10158,6 +10166,13 @@ tip frame. */); defsubr (&Sset_message_beep); defsubr (&Sx_show_tip); defsubr (&Sx_hide_tip); + tip_timer = Qnil; + staticpro (&tip_timer); + tip_frame = Qnil; + staticpro (&tip_frame); + + last_show_tip_args = Qnil; + staticpro (&last_show_tip_args); defsubr (&Sx_file_dialog); #ifdef WINDOWSNT diff --git a/src/w32term.c b/src/w32term.c index 8c2fdaf0f5..5a11e2a871 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -5024,10 +5024,11 @@ w32_read_socket (struct terminal *terminal, /* wParam non-zero means Window is about to be shown, 0 means about to be hidden. */ /* Redo the mouse-highlight after the tooltip has gone. */ - if (!msg.msg.wParam - && dpyinfo->w32_tooltip_frame - && FRAME_W32_WINDOW (dpyinfo->w32_tooltip_frame) == msg.msg.hwnd) - x_redo_mouse_highlight (dpyinfo); + if (!msg.msg.wParam && msg.msg.hwnd == tip_window) + { + tip_window = NULL; + x_redo_mouse_highlight (dpyinfo); + } /* If window has been obscured or exposed by another window being maximized or minimized/restored, then recheck @@ -5393,7 +5394,7 @@ w32_read_socket (struct terminal *terminal, struct frame *f = XFRAME (frame); /* The tooltip has been drawn already. Avoid the SET_FRAME_GARBAGED below. */ - if (FRAME_TOOLTIP_P (f)) + if (EQ (frame, tip_frame)) continue; /* Check "visible" frames and mark each as obscured or not. @@ -5870,7 +5871,7 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) /* 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 (!FRAME_TOOLTIP_P (f)) + if (NILP (tip_frame) || XFRAME (tip_frame) != f) adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, false, Qfont); @@ -6568,8 +6569,6 @@ x_free_frame_resources (struct frame *f) dpyinfo->w32_focus_event_frame = 0; if (f == dpyinfo->x_highlight_frame) dpyinfo->x_highlight_frame = 0; - if (f == dpyinfo->w32_tooltip_frame) - dpyinfo->w32_tooltip_frame = 0; if (f == hlinfo->mouse_face_mouse_frame) reset_mouse_highlight (hlinfo); diff --git a/src/w32term.h b/src/w32term.h index 3934e8500a..320477073a 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -186,9 +186,6 @@ struct w32_display_info /* The frame waiting to be auto-raised in w32_read_socket. */ struct frame *w32_pending_autoraise_frame; - /* Tooltip frame on this display. */ - struct frame *w32_tooltip_frame; - /* The frame where the mouse was last time we reported a mouse event. */ struct frame *last_mouse_frame; diff --git a/src/xdisp.c b/src/xdisp.c index b8dcdcec41..14d6f8fcf9 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -2841,7 +2841,11 @@ init_iterator (struct it *it, struct window *w, frames when the fringes are turned off. But leave the dimensions zero for tooltip frames, as these glyphs look ugly there and also sabotage calculations of tooltip dimensions in x-show-tip. */ - if (!FRAME_TOOLTIP_P (it->f)) +#ifdef HAVE_WINDOW_SYSTEM + if (!(FRAME_WINDOW_P (it->f) + && FRAMEP (tip_frame) + && it->f == XFRAME (tip_frame))) +#endif { if (it->line_wrap == TRUNCATE) { @@ -11709,7 +11713,7 @@ x_consider_frame_title (Lisp_Object frame) if ((FRAME_WINDOW_P (f) || FRAME_MINIBUF_ONLY_P (f) || f->explicit_name) - && !FRAME_TOOLTIP_P (f)) + && NILP (Fframe_parameter (frame, Qtooltip))) { /* Do we have more than one visible frame on this X display? */ Lisp_Object tail, other_frame, fmt; @@ -11726,7 +11730,7 @@ x_consider_frame_title (Lisp_Object frame) if (tf != f && FRAME_KBOARD (tf) == FRAME_KBOARD (f) && !FRAME_MINIBUF_ONLY_P (tf) - && !FRAME_TOOLTIP_P (tf) + && !EQ (other_frame, tip_frame) && (FRAME_VISIBLE_P (tf) || FRAME_ICONIFIED_P (tf))) break; } @@ -11789,6 +11793,13 @@ prepare_menu_bars (void) { 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)) { @@ -11829,7 +11840,7 @@ prepare_menu_bars (void) && !XBUFFER (w->contents)->text->redisplay) continue; - if (!FRAME_TOOLTIP_P (f) + if (!EQ (frame, tooltip_frame) && (FRAME_ICONIFIED_P (f) || FRAME_VISIBLE_P (f) == 1 /* Exclude TTY frames that are obscured because they @@ -11866,7 +11877,7 @@ prepare_menu_bars (void) struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f)); /* Ignore tooltip frame. */ - if (FRAME_TOOLTIP_P (f)) + if (EQ (frame, tooltip_frame)) continue; if (some_windows diff --git a/src/xfns.c b/src/xfns.c index 16dbcfd5f8..798dc49bef 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -4151,7 +4151,7 @@ x_make_monitor_attribute_list (struct MonitorInfo *monitors, struct frame *f = XFRAME (frame); if (FRAME_X_P (f) && FRAME_DISPLAY_INFO (f) == dpyinfo - && !FRAME_TOOLTIP_P (f)) + && !EQ (frame, tip_frame)) { int i = x_get_monitor_for_frame (f, monitors, n_monitors); ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i))); @@ -4447,7 +4447,7 @@ Internal use only, use `display-monitor-attributes-list' instead. */) struct frame *f = XFRAME (frame); if (FRAME_X_P (f) && FRAME_DISPLAY_INFO (f) == dpyinfo - && !FRAME_TOOLTIP_P (f)) + && !EQ (frame, tip_frame)) { GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_WIDGET (f)); @@ -5312,6 +5312,39 @@ no value of TYPE (always string in the MS Windows case). */) Tool tips ***********************************************************************/ +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 tip_frame; + +/* If non-nil, a timer started that hides the last tooltip when it + fires. */ + +static 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. */ + +static Lisp_Object last_show_tip_args; + + +static void +unwind_create_tip_frame (Lisp_Object frame) +{ + Lisp_Object deleted; + + deleted = unwind_create_frame (frame); + if (EQ (deleted, Qt)) + { + tip_window = None; + tip_frame = Qnil; + } +} + + /* Create a frame for a tooltip on the display described by DPYINFO. PARMS is a list of frame parameters. TEXT is the string to display in the tip frame. Value is the frame. @@ -5348,7 +5381,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms) f = make_frame (false); f->wants_modeline = false; XSETFRAME (frame, f); - record_unwind_protect (do_unwind_create_frame, frame); + record_unwind_protect (unwind_create_tip_frame, frame); f->terminal = dpyinfo->terminal; @@ -5369,7 +5402,6 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms) 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; @@ -5513,7 +5545,8 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms) = f->output_data.x->text_cursor; /* Arrange for getting MapNotify and UnmapNotify events. */ attrs.event_mask = StructureNotifyMask; - FRAME_X_WINDOW (f) + tip_window + = FRAME_X_WINDOW (f) = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_DISPLAY_INFO (f)->root_window, /* x, y, width, height */ @@ -5522,7 +5555,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms) f->border_width, CopyFromParent, InputOutput, CopyFromParent, mask, &attrs); - XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + XChangeProperty (FRAME_X_DISPLAY (f), tip_window, FRAME_DISPLAY_INFO (f)->Xatom_net_window_type, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type, 1); @@ -5549,6 +5582,13 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms) 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? http://lists.gnu.org/archive/html/emacs-devel/2007-10/msg00641.html */ @@ -5593,9 +5633,6 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms) f->no_split = true; - /* Now this is an official tooltip frame on this display. */ - dpyinfo->x_tooltip_frame = f; - /* Now that the frame will be official, it counts as a reference to its display and terminal. */ FRAME_DISPLAY_INFO (f)->reference_count++; @@ -5626,9 +5663,7 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms) 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; @@ -5724,39 +5759,56 @@ compute_tip_xy (struct frame *f, *root_x = min_x; } -/* Hide tooltip frame F and delete it if DELETE is true. */ +/* Hide tooltip. Delete its frame if DELETE is true. */ static Lisp_Object -x_hide_tip (struct frame *f, bool delete) +x_hide_tip (bool delete) { - if (f) + if (!NILP (tip_timer)) { - Lisp_Object frame, timer; - - XSETFRAME (frame, f); - timer = Fframe_parameter (frame, Qtooltip_timer); + call1 (Qcancel_timer, tip_timer); + tip_timer = Qnil; + } - if (!NILP (timer)) - call1 (Qcancel_timer, timer); - if (!delete && !FRAME_VISIBLE_P (f)) - return Qnil; - else - { - ptrdiff_t count = SPECPDL_INDEX (); + if (NILP (tip_frame) + || (!delete && FRAMEP (tip_frame) + && !FRAME_VISIBLE_P (XFRAME (tip_frame)))) + return Qnil; + else + { + ptrdiff_t count; + Lisp_Object was_open = Qnil; - specbind (Qinhibit_redisplay, Qt); - specbind (Qinhibit_quit, Qt); + count = SPECPDL_INDEX (); + specbind (Qinhibit_redisplay, Qt); + specbind (Qinhibit_quit, Qt); #ifdef USE_GTK - if (x_gtk_use_system_tooltips) - /* Should be handled by xg_hide_tooltip. */ - emacs_abort (); + { + /* 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 (FRAMEP (tip_frame)) + { if (delete) - delete_frame (frame, Qnil); + { + delete_frame (tip_frame, Qnil); + tip_frame = Qnil; + } else - x_make_frame_invisible (f); + x_make_frame_invisible (XFRAME (tip_frame)); + + was_open = Qt; #ifdef USE_LUCID /* Bloodcurdling hack alert: The Lucid menu bar widget's @@ -5764,12 +5816,12 @@ x_hide_tip (struct frame *f, bool delete) menu items is unmapped. Redisplay the menu manually... */ { Widget w; - struct frame *sf = SELECTED_FRAME (); - if (FRAME_X_P (sf) && FRAME_LIVE_P (sf)) + struct frame *f = SELECTED_FRAME (); + if (FRAME_X_P (f) && FRAME_LIVE_P (f)) { - w = sf->output_data.x->menubar_widget; + w = f->output_data.x->menubar_widget; - if (!DoesSaveUnders (FRAME_DISPLAY_INFO (sf)->screen) + if (!DoesSaveUnders (FRAME_DISPLAY_INFO (f)->screen) && w != NULL) { block_input (); @@ -5779,10 +5831,12 @@ x_hide_tip (struct frame *f, bool delete) } } #endif /* USE_LUCID */ - return unbind_to (count, Qt); } + else + tip_frame = Qnil; + + return unbind_to (count, was_open); } - return Qnil; } DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, @@ -5815,8 +5869,7 @@ 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; @@ -5827,7 +5880,7 @@ Text larger than the specified size is clipped. */) int old_windows_or_buffers_changed = windows_or_buffers_changed; ptrdiff_t count = SPECPDL_INDEX (); ptrdiff_t count_1; - Lisp_Object window, size, tip_frame, parameters; + Lisp_Object window, size; AUTO_STRING (tip, " *tip*"); specbind (Qinhibit_redisplay, Qt); @@ -5857,8 +5910,8 @@ Text larger than the specified size is clipped. */) { bool ok; - /* Hide a previous tip on this frame, if any. */ - xg_hide_tooltip (f); + /* Hide a previous tip, if any. */ + Fx_hide_tip (); block_input (); ok = xg_prepare_tooltip (f, string, &width, &height); @@ -5866,47 +5919,37 @@ Text larger than the specified size is clipped. */) { 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); } unblock_input (); - if (ok) - /* Schedule call to xg_hide_tip from GTK event loop - to allow the tip disappear after timeout seconds. */ - FRAME_X_OUTPUT (f)->ttip_timeout - = g_timeout_add_seconds (XINT (timeout), xg_hide_tip, (gpointer) f); - else - /* FIXME: what if not ok? */ - FRAME_X_OUTPUT (f)->ttip_timeout = 0; - return unbind_to (count, Qnil); + if (ok) goto start_timer; } #endif /* USE_GTK */ - parameters = Fframe_parameter (frame, Qtooltip_parameters); - if (NILP (parameters)) - parameters = Fmake_vector (make_number (3), Qnil); + if (NILP (last_show_tip_args)) + last_show_tip_args = Fmake_vector (make_number (3), Qnil); - /* Look at current tooltip frame, if any. */ - tip_f = FRAME_DISPLAY_INFO (f)->x_tooltip_frame; - if (tip_f) - XSETFRAME (tip_frame, tip_f); - else - tip_frame = Qnil; - - if (tip_f && FRAME_LIVE_P (tip_f)) + if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame))) { - Lisp_Object last_string = AREF (parameters, 0); - Lisp_Object last_frame = AREF (parameters, 1); - Lisp_Object last_parms = AREF (parameters, 2); + 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 (tip_f) + if (FRAME_VISIBLE_P (XFRAME (tip_frame)) && EQ (frame, last_frame) && !NILP (Fequal_including_properties (last_string, string)) && !NILP (Fequal (last_parms, parms))) { /* Only DX and DY have changed. */ - Lisp_Object timer = Fframe_parameter (tip_frame, Qtooltip_timer); + tip_f = XFRAME (tip_frame); + if (!NILP (tip_timer)) + { + Lisp_Object timer = tip_timer; - if (!NILP (timer)) - call1 (Qcancel_timer, timer); + tip_timer = Qnil; + call1 (Qcancel_timer, timer); + } block_input (); compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f), @@ -5966,22 +6009,17 @@ Text larger than the specified size is clipped. */) } } - x_hide_tip (tip_f, delete); + x_hide_tip (delete); } else - x_hide_tip (tip_f, true); + x_hide_tip (true); } else - x_hide_tip (tip_f, true); + x_hide_tip (true); - /* Update tooltip parameters. */ - { - AUTO_FRAME_ARG (arg, Qtooltip_parameters, parameters); - ASET (parameters, 0, string); - ASET (parameters, 1, frame); - ASET (parameters, 2, parms); - Fmodify_frame_parameters (frame, arg); - } + ASET (last_show_tip_args, 0, string); + ASET (last_show_tip_args, 1, frame); + ASET (last_show_tip_args, 2, parms); if (!FRAMEP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame))) { @@ -5997,6 +6035,9 @@ Text larger than the specified size is clipped. */) if (NILP (Fassq (Qbackground_color, parms))) parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")), parms); + + /* Create a frame for the tooltip, and record it in the global + variable tip_frame. */ if (NILP (tip_frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms))) /* Creating the tip frame failed. */ return unbind_to (count, Qnil); @@ -6074,69 +6115,20 @@ Text larger than the specified size is clipped. */) windows_or_buffers_changed = old_windows_or_buffers_changed; start_timer: - { - /* Let the tip disappear after timeout seconds. */ - AUTO_FRAME_ARG (arg, Qtooltip_timer, - call3 (intern ("run-at-time"), timeout, - Qnil, intern ("x-hide-tip"))); - Fmodify_frame_parameters (tip_frame, arg); - } + /* Let the tip disappear after timeout seconds. */ + tip_timer = call3 (intern ("run-at-time"), timeout, Qnil, + intern ("x-hide-tip")); + return unbind_to (count, Qnil); } -DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 1, 0, + +DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, doc: /* Hide the current tooltip window, if there is any. -Optional FRAME is the frame to hide tooltip on. Value is t if tooltip was open, nil otherwise. */) - (Lisp_Object frame) + (void) { - Lisp_Object obj = Qnil; - -#ifdef USE_GTK - if (x_gtk_use_system_tooltips) - { - if (NILP (frame)) - { - Lisp_Object tail, frame; - - FOR_EACH_FRAME (tail, frame) - if (FRAME_X_P (XFRAME (frame))) - if (xg_hide_tooltip (XFRAME (frame))) - obj = Qt; - } - else - { - CHECK_FRAME (frame); - if (FRAME_X_P (XFRAME (frame))) - if (xg_hide_tooltip (XFRAME (frame))) - obj = Qt; - } - return obj; - } -#endif /* USE_GTK */ - - if (NILP (frame)) - { - struct x_display_info *dpyinfo; - - for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) - if (dpyinfo->x_tooltip_frame) - if (!NILP (x_hide_tip (dpyinfo->x_tooltip_frame, - !tooltip_reuse_hidden_frame))) - obj = Qt; - } - else - { - struct frame *f; - - CHECK_FRAME (frame); - f = XFRAME (frame); - if (FRAME_DISPLAY_INFO (f) - && FRAME_DISPLAY_INFO (f)->x_tooltip_frame) - obj = x_hide_tip (FRAME_DISPLAY_INFO (f)->x_tooltip_frame, - !tooltip_reuse_hidden_frame); - } - return obj; + return x_hide_tip (!tooltip_reuse_hidden_frame); } @@ -7005,6 +6997,13 @@ When using Gtk+ tooltips, the tooltip face is not used. */); defsubr (&Sx_show_tip); defsubr (&Sx_hide_tip); + tip_timer = Qnil; + staticpro (&tip_timer); + tip_frame = Qnil; + staticpro (&tip_frame); + + last_show_tip_args = Qnil; + staticpro (&last_show_tip_args); defsubr (&Sx_uses_old_gtk_dialog); #if defined (USE_MOTIF) || defined (USE_GTK) diff --git a/src/xterm.c b/src/xterm.c index ada1160ec9..cd1d712f39 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -987,7 +987,8 @@ static void x_update_begin (struct frame *f) { #ifdef USE_CAIRO - if (FRAME_TOOLTIP_P (f) && ! FRAME_VISIBLE_P (f)) + if (! NILP (tip_frame) && XFRAME (tip_frame) == f + && ! FRAME_VISIBLE_P (f)) return; if (! FRAME_CR_SURFACE (f)) @@ -7838,9 +7839,11 @@ handle_one_xevent (struct x_display_info *dpyinfo, case UnmapNotify: /* Redo the mouse-highlight after the tooltip has gone. */ - if (dpyinfo->x_tooltip_frame - && FRAME_X_WINDOW (dpyinfo->x_tooltip_frame) == event->xunmap.window) - x_redo_mouse_highlight (dpyinfo); + if (event->xunmap.window == tip_window) + { + tip_window = 0; + x_redo_mouse_highlight (dpyinfo); + } f = x_top_window_to_frame (dpyinfo, event->xunmap.window); if (f) /* F may no longer exist if @@ -8430,7 +8433,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifdef USE_X_TOOLKIT /* Tip frames are pure X window, set size for them. */ - if (FRAME_TOOLTIP_P (f)) + if (! NILP (tip_frame) && XFRAME (tip_frame) == f) { if (FRAME_PIXEL_HEIGHT (f) != configureEvent.xconfigure.height || FRAME_PIXEL_WIDTH (f) != configureEvent.xconfigure.width) @@ -9611,7 +9614,7 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) /* 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 (!FRAME_TOOLTIP_P (f)) + if (NILP (tip_frame) || XFRAME (tip_frame) != f) { adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, @@ -10686,7 +10689,7 @@ x_set_window_size (struct frame *f, bool change_gravity, /* The following breaks our calculations. If it's really needed, think of something else. */ #if false - if (!FRAME_TOOLTIP_P (f)) + if (NILP (tip_frame) || XFRAME (tip_frame) != f) { int text_width, text_height; @@ -11337,8 +11340,6 @@ x_free_frame_resources (struct frame *f) dpyinfo->x_focus_event_frame = 0; if (f == dpyinfo->x_highlight_frame) dpyinfo->x_highlight_frame = 0; - if (f == dpyinfo->x_tooltip_frame) - dpyinfo->x_tooltip_frame = 0; if (f == hlinfo->mouse_face_mouse_frame) reset_mouse_highlight (hlinfo); diff --git a/src/xterm.h b/src/xterm.h index 1eb3e304f8..675a48443d 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -362,9 +362,6 @@ struct x_display_info /* The frame waiting to be auto-raised in XTread_socket. */ struct frame *x_pending_autoraise_frame; - /* Tooltip frame on this display. */ - struct frame *x_tooltip_frame; - /* The frame where the mouse was last time we reported a ButtonPress event. */ struct frame *last_mouse_frame; @@ -578,7 +575,6 @@ struct x_output GtkTooltip *ttip_widget; GtkWidget *ttip_lbl; GtkWindow *ttip_window; - guint ttip_timeout; #endif /* USE_GTK_TOOLTIP */ #endif /* USE_GTK */ -- 2.39.2