diff options
-rw-r--r-- | src/dispextern.h | 2 | ||||
-rw-r--r-- | src/frame.c | 19 | ||||
-rw-r--r-- | src/frame.h | 9 | ||||
-rw-r--r-- | src/gtkutil.c | 29 | ||||
-rw-r--r-- | src/gtkutil.h | 1 | ||||
-rw-r--r-- | src/menu.c | 7 | ||||
-rw-r--r-- | src/nsfns.m | 4 | ||||
-rw-r--r-- | src/w32fns.c | 213 | ||||
-rw-r--r-- | src/w32term.c | 15 | ||||
-rw-r--r-- | src/w32term.h | 3 | ||||
-rw-r--r-- | src/xdisp.c | 21 | ||||
-rw-r--r-- | src/xfns.c | 277 | ||||
-rw-r--r-- | src/xterm.c | 19 | ||||
-rw-r--r-- | src/xterm.h | 4 |
14 files changed, 319 insertions, 304 deletions
diff --git a/src/dispextern.h b/src/dispextern.h index 1325ff9da28..c2fcca5591a 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -3461,8 +3461,6 @@ 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 22143ab26bf..80e181f89ef 100644 --- a/src/frame.c +++ b/src/frame.c @@ -642,6 +642,7 @@ 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 @@ -1260,13 +1261,16 @@ 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 - if (FRAMEP (tip_frame)) - frames = Fdelq (tip_frame, frames); + 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); #endif - return frames; } /* Return CANDIDATE if it can be used as 'other-than-FRAME' frame on the @@ -1557,7 +1561,7 @@ delete_frame (Lisp_Object frame, Lisp_Object force) } } - 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 @@ -4900,7 +4904,6 @@ 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"); @@ -5022,6 +5025,8 @@ 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 5e3ee68942a..635a5ed7be4 100644 --- a/src/frame.h +++ b/src/frame.h @@ -309,6 +309,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; @@ -861,6 +864,9 @@ 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. */ @@ -869,6 +875,9 @@ 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 88e6d30bd9a..e08a4b53489 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -731,14 +731,23 @@ 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 - if (f->output_data.x->ttip_window) + struct x_output *x = FRAME_X_OUTPUT (f); + + if (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)); @@ -747,11 +756,21 @@ xg_hide_tooltip (struct frame *f) g_object_set (settings, "gtk-enable-tooltips", TRUE, NULL); } unblock_input (); - - ret = 1; + return 1; } #endif - return ret; + 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); +#endif + return FALSE; } diff --git a/src/gtkutil.h b/src/gtkutil.h index 8840fe76a85..d4dc295c512 100644 --- a/src/gtkutil.h +++ b/src/gtkutil.h @@ -178,6 +178,7 @@ 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 90bb19a2e94..675caff6b88 100644 --- a/src/menu.c +++ b/src/menu.c @@ -1400,7 +1400,12 @@ no quit occurs and `x-popup-menu' returns nil. */) #ifdef HAVE_WINDOW_SYSTEM /* Hide a previous tip, if any. */ if (!FRAME_TERMCAP_P (f)) - Fx_hide_tip (); + { + Lisp_Object frame; + + XSETFRAME (frame, f); + Fx_hide_tip (frame); + } #endif #ifdef HAVE_NTGUI /* FIXME: Is it really w32-specific? --Stef */ diff --git a/src/nsfns.m b/src/nsfns.m index 051e5091919..a017be5c1c5 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -2658,10 +2658,6 @@ 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 20e09d8a463..0eb720e1cbe 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -341,7 +341,6 @@ 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 *); @@ -5053,6 +5052,7 @@ 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); @@ -5200,9 +5200,8 @@ x_make_gc (struct frame *f) } -/* Handler for signals raised during x_create_frame and - x_create_tip_frame. FRAME is the frame which is partially - constructed. */ +/* Handler for signals raised during x_create_frame. + FRAME is the frame which is partially constructed. */ static Lisp_Object unwind_create_frame (Lisp_Object frame) @@ -5976,7 +5975,7 @@ w32_display_monitor_attributes_list (void) { 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), @@ -6063,7 +6062,7 @@ w32_display_monitor_attributes_list_fallback (struct w32_display_info *dpyinfo) { 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); @@ -6466,39 +6465,6 @@ 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. @@ -6543,7 +6509,7 @@ x_create_tip_frame (struct w32_display_info *dpyinfo, Lisp_Object parms) f->wants_modeline = false; XSETFRAME (frame, f); - record_unwind_protect (unwind_create_tip_frame, frame); + record_unwind_protect (do_unwind_create_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 @@ -6555,6 +6521,7 @@ 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 = @@ -6663,11 +6630,7 @@ 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); - 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)); + change_frame_size (f, width, height, true, false, false, false); /* Set up faces after all frame parameters are known. This call also merges in face attributes specified for new frames. @@ -6695,6 +6658,9 @@ 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++; @@ -6813,46 +6779,39 @@ compute_tip_xy (struct frame *f, *root_x = min_x; } -/* Hide tooltip. Delete its frame if DELETE is true. */ +/* Hide tooltip frame F and delete it if DELETE is true. */ + static Lisp_Object -x_hide_tip (bool delete) +x_hide_tip (struct frame *f, bool delete) { - if (!NILP (tip_timer)) + if (f) { - call1 (Qcancel_timer, tip_timer); - tip_timer = Qnil; - } + Lisp_Object frame, 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; + XSETFRAME (frame, f); + timer = Fframe_parameter (frame, Qtooltip_timer); - count = SPECPDL_INDEX (); - specbind (Qinhibit_redisplay, Qt); - specbind (Qinhibit_quit, Qt); + if (!NILP (timer)) + call1 (Qcancel_timer, timer); - if (FRAMEP (tip_frame)) + if (!delete && !FRAME_VISIBLE_P (f)) + return Qnil; + else { + ptrdiff_t count = SPECPDL_INDEX (); + + specbind (Qinhibit_redisplay, Qt); + specbind (Qinhibit_quit, Qt); + if (delete) - { - delete_frame (tip_frame, Qnil); - tip_frame = Qnil; - } + delete_frame (frame, Qnil); else - x_make_frame_invisible (XFRAME (tip_frame)); + x_make_frame_invisible (f); - was_open = Qt; + return unbind_to (count, Qt); } - else - tip_frame = Qnil; - - return unbind_to (count, was_open); } + return Qnil; } @@ -6886,7 +6845,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; @@ -6897,7 +6857,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; + Lisp_Object window, size, tip_frame, parameters; AUTO_STRING (tip, " *tip*"); specbind (Qinhibit_redisplay, Qt); @@ -6919,14 +6879,22 @@ Text larger than the specified size is clipped. */) else CHECK_NUMBER (dy); - if (NILP (last_show_tip_args)) - last_show_tip_args = Fmake_vector (make_number (3), Qnil); + parameters = Fframe_parameter (frame, Qtooltip_parameters); + if (NILP (parameters)) + parameters = Fmake_vector (make_number (3), Qnil); - if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame))) + /* 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)) { - 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); + Lisp_Object last_string = AREF (parameters, 0); + Lisp_Object last_frame = AREF (parameters, 1); + Lisp_Object last_parms = AREF (parameters, 2); if (FRAME_VISIBLE_P (XFRAME (tip_frame)) && EQ (frame, last_frame) @@ -6934,14 +6902,10 @@ Text larger than the specified size is clipped. */) && !NILP (Fequal (last_parms, parms))) { /* Only DX and DY have changed. */ - tip_f = XFRAME (tip_frame); - if (!NILP (tip_timer)) - { - Lisp_Object timer = tip_timer; + Lisp_Object timer = Fframe_parameter (tip_frame, Qtooltip_timer); - tip_timer = Qnil; - call1 (Qcancel_timer, timer); - } + if (!NILP (timer)) + call1 (Qcancel_timer, timer); block_input (); compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f), @@ -7011,17 +6975,22 @@ Text larger than the specified size is clipped. */) } } - x_hide_tip (delete); + x_hide_tip (tip_f, delete); } else - x_hide_tip (true); + x_hide_tip (tip_f, true); } else - x_hide_tip (true); + x_hide_tip (tip_f, true); - ASET (last_show_tip_args, 0, string); - ASET (last_show_tip_args, 1, frame); - ASET (last_show_tip_args, 2, parms); + /* 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); + } /* Block input until the tip has been fully drawn, to avoid crashes when drawing tips in menus. */ @@ -7041,11 +7010,8 @@ 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. */ - struct frame *f; /* The value is unused. */ - if (NILP (tip_frame = x_create_tip_frame (FRAME_DISPLAY_INFO (f), parms))) + if (NILP (tip_frame + = x_create_tip_frame (FRAME_DISPLAY_INFO (XFRAME (frame)), parms))) { /* Creating the tip frame failed. */ unblock_input (); @@ -7149,20 +7115,47 @@ 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. */ - tip_timer = call3 (intern ("run-at-time"), timeout, Qnil, - intern ("x-hide-tip")); - + { + /* 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); + } return unbind_to (count, Qnil); } -DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, +DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 1, 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. */) - (void) + (Lisp_Object frame) { - return x_hide_tip (!tooltip_reuse_hidden_frame); + 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; } /*********************************************************************** @@ -9765,7 +9758,6 @@ 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 @@ -10151,13 +10143,6 @@ 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 5a11e2a871a..8c2fdaf0f59 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -5024,11 +5024,10 @@ 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 && msg.msg.hwnd == tip_window) - { - tip_window = NULL; - x_redo_mouse_highlight (dpyinfo); - } + if (!msg.msg.wParam + && dpyinfo->w32_tooltip_frame + && FRAME_W32_WINDOW (dpyinfo->w32_tooltip_frame) == msg.msg.hwnd) + x_redo_mouse_highlight (dpyinfo); /* If window has been obscured or exposed by another window being maximized or minimized/restored, then recheck @@ -5394,7 +5393,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 (EQ (frame, tip_frame)) + if (FRAME_TOOLTIP_P (f)) continue; /* Check "visible" frames and mark each as obscured or not. @@ -5871,7 +5870,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 (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); @@ -6569,6 +6568,8 @@ 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 320477073a5..3934e8500a3 100644 --- a/src/w32term.h +++ b/src/w32term.h @@ -186,6 +186,9 @@ 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 14d6f8fcf93..b8dcdcec41f 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -2841,11 +2841,7 @@ 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. */ -#ifdef HAVE_WINDOW_SYSTEM - if (!(FRAME_WINDOW_P (it->f) - && FRAMEP (tip_frame) - && it->f == XFRAME (tip_frame))) -#endif + if (!FRAME_TOOLTIP_P (it->f)) { if (it->line_wrap == TRUNCATE) { @@ -11713,7 +11709,7 @@ x_consider_frame_title (Lisp_Object frame) 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; @@ -11730,7 +11726,7 @@ x_consider_frame_title (Lisp_Object frame) if (tf != f && FRAME_KBOARD (tf) == FRAME_KBOARD (f) && !FRAME_MINIBUF_ONLY_P (tf) - && !EQ (other_frame, tip_frame) + && !FRAME_TOOLTIP_P (tf) && (FRAME_VISIBLE_P (tf) || FRAME_ICONIFIED_P (tf))) break; } @@ -11793,13 +11789,6 @@ 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)) { @@ -11840,7 +11829,7 @@ prepare_menu_bars (void) && !XBUFFER (w->contents)->text->redisplay) continue; - if (!EQ (frame, tooltip_frame) + if (!FRAME_TOOLTIP_P (f) && (FRAME_ICONIFIED_P (f) || FRAME_VISIBLE_P (f) == 1 /* Exclude TTY frames that are obscured because they @@ -11877,7 +11866,7 @@ prepare_menu_bars (void) 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 diff --git a/src/xfns.c b/src/xfns.c index 798dc49bef5..16dbcfd5f84 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 - && !EQ (frame, tip_frame)) + && !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))); @@ -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 - && !EQ (frame, tip_frame)) + && !FRAME_TOOLTIP_P (f)) { GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_WIDGET (f)); @@ -5312,39 +5312,6 @@ 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. @@ -5381,7 +5348,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 (unwind_create_tip_frame, frame); + record_unwind_protect (do_unwind_create_frame, frame); f->terminal = dpyinfo->terminal; @@ -5402,6 +5369,7 @@ 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; @@ -5545,8 +5513,7 @@ 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; - tip_window - = FRAME_X_WINDOW (f) + FRAME_X_WINDOW (f) = XCreateWindow (FRAME_X_DISPLAY (f), FRAME_DISPLAY_INFO (f)->root_window, /* x, y, width, height */ @@ -5555,7 +5522,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), tip_window, + XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_DISPLAY_INFO (f)->Xatom_net_window_type, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type, 1); @@ -5582,13 +5549,6 @@ 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 */ @@ -5633,6 +5593,9 @@ 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++; @@ -5663,7 +5626,9 @@ 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; @@ -5759,56 +5724,39 @@ compute_tip_xy (struct frame *f, Lisp_Object parms, Lisp_Object dx, Lisp_Object *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 (bool delete) +x_hide_tip (struct frame *f, bool delete) { - if (!NILP (tip_timer)) + if (f) { - call1 (Qcancel_timer, tip_timer); - tip_timer = Qnil; - } + Lisp_Object frame, timer; + 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 + { + ptrdiff_t count = SPECPDL_INDEX (); -#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); + specbind (Qinhibit_redisplay, Qt); + specbind (Qinhibit_quit, Qt); - if (FRAME_LIVE_P (f) && xg_hide_tooltip (f)) - { - tip_frame = Qnil; - was_open = Qt; - } - } +#ifdef USE_GTK + if (x_gtk_use_system_tooltips) + /* Should be handled by xg_hide_tooltip. */ + emacs_abort (); #endif - - if (FRAMEP (tip_frame)) - { if (delete) - { - delete_frame (tip_frame, Qnil); - tip_frame = Qnil; - } + delete_frame (frame, Qnil); else - x_make_frame_invisible (XFRAME (tip_frame)); - - was_open = Qt; + x_make_frame_invisible (f); #ifdef USE_LUCID /* Bloodcurdling hack alert: The Lucid menu bar widget's @@ -5816,12 +5764,12 @@ x_hide_tip (bool delete) menu items is unmapped. Redisplay the menu manually... */ { Widget w; - struct frame *f = SELECTED_FRAME (); - if (FRAME_X_P (f) && FRAME_LIVE_P (f)) + struct frame *sf = SELECTED_FRAME (); + if (FRAME_X_P (sf) && FRAME_LIVE_P (sf)) { - w = f->output_data.x->menubar_widget; + w = sf->output_data.x->menubar_widget; - if (!DoesSaveUnders (FRAME_DISPLAY_INFO (f)->screen) + if (!DoesSaveUnders (FRAME_DISPLAY_INFO (sf)->screen) && w != NULL) { block_input (); @@ -5831,12 +5779,10 @@ x_hide_tip (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, @@ -5869,7 +5815,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; @@ -5880,7 +5827,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; + Lisp_Object window, size, tip_frame, parameters; AUTO_STRING (tip, " *tip*"); specbind (Qinhibit_redisplay, Qt); @@ -5910,8 +5857,8 @@ Text larger than the specified size is clipped. */) { bool ok; - /* Hide a previous tip, if any. */ - Fx_hide_tip (); + /* Hide a previous tip on this frame, if any. */ + xg_hide_tooltip (f); block_input (); ok = xg_prepare_tooltip (f, string, &width, &height); @@ -5919,37 +5866,47 @@ 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) goto start_timer; + 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); } #endif /* USE_GTK */ - if (NILP (last_show_tip_args)) - last_show_tip_args = Fmake_vector (make_number (3), Qnil); + parameters = Fframe_parameter (frame, Qtooltip_parameters); + if (NILP (parameters)) + parameters = Fmake_vector (make_number (3), Qnil); - if (FRAMEP (tip_frame) && FRAME_LIVE_P (XFRAME (tip_frame))) + /* 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)) { - 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); + Lisp_Object last_string = AREF (parameters, 0); + Lisp_Object last_frame = AREF (parameters, 1); + Lisp_Object last_parms = AREF (parameters, 2); - if (FRAME_VISIBLE_P (XFRAME (tip_frame)) + if (FRAME_VISIBLE_P (tip_f) && EQ (frame, last_frame) && !NILP (Fequal_including_properties (last_string, string)) && !NILP (Fequal (last_parms, parms))) { /* Only DX and DY have changed. */ - tip_f = XFRAME (tip_frame); - if (!NILP (tip_timer)) - { - Lisp_Object timer = tip_timer; + Lisp_Object timer = Fframe_parameter (tip_frame, Qtooltip_timer); - tip_timer = Qnil; - call1 (Qcancel_timer, timer); - } + if (!NILP (timer)) + call1 (Qcancel_timer, timer); block_input (); compute_tip_xy (tip_f, parms, dx, dy, FRAME_PIXEL_WIDTH (tip_f), @@ -6009,17 +5966,22 @@ Text larger than the specified size is clipped. */) } } - x_hide_tip (delete); + x_hide_tip (tip_f, delete); } else - x_hide_tip (true); + x_hide_tip (tip_f, true); } else - x_hide_tip (true); + x_hide_tip (tip_f, true); - ASET (last_show_tip_args, 0, string); - ASET (last_show_tip_args, 1, frame); - ASET (last_show_tip_args, 2, parms); + /* 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); + } if (!FRAMEP (tip_frame) || !FRAME_LIVE_P (XFRAME (tip_frame))) { @@ -6035,9 +5997,6 @@ 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); @@ -6115,20 +6074,69 @@ 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. */ - tip_timer = call3 (intern ("run-at-time"), timeout, Qnil, - intern ("x-hide-tip")); - + { + /* 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); + } return unbind_to (count, Qnil); } - -DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, +DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 1, 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. */) - (void) + (Lisp_Object frame) { - return x_hide_tip (!tooltip_reuse_hidden_frame); + 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; } @@ -6997,13 +7005,6 @@ 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 cd1d712f39a..ada1160ec90 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -987,8 +987,7 @@ static void x_update_begin (struct frame *f) { #ifdef USE_CAIRO - if (! NILP (tip_frame) && XFRAME (tip_frame) == f - && ! FRAME_VISIBLE_P (f)) + if (FRAME_TOOLTIP_P (f) && ! FRAME_VISIBLE_P (f)) return; if (! FRAME_CR_SURFACE (f)) @@ -7839,11 +7838,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, case UnmapNotify: /* Redo the mouse-highlight after the tooltip has gone. */ - if (event->xunmap.window == tip_window) - { - tip_window = 0; - x_redo_mouse_highlight (dpyinfo); - } + if (dpyinfo->x_tooltip_frame + && FRAME_X_WINDOW (dpyinfo->x_tooltip_frame) == event->xunmap.window) + x_redo_mouse_highlight (dpyinfo); f = x_top_window_to_frame (dpyinfo, event->xunmap.window); if (f) /* F may no longer exist if @@ -8433,7 +8430,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, #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) @@ -9614,7 +9611,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 (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, @@ -10689,7 +10686,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 (NILP (tip_frame) || XFRAME (tip_frame) != f) + if (!FRAME_TOOLTIP_P (f)) { int text_width, text_height; @@ -11340,6 +11337,8 @@ 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 675a48443dc..1eb3e304f84 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -362,6 +362,9 @@ 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; @@ -575,6 +578,7 @@ struct x_output GtkTooltip *ttip_widget; GtkWidget *ttip_lbl; GtkWindow *ttip_window; + guint ttip_timeout; #endif /* USE_GTK_TOOLTIP */ #endif /* USE_GTK */ |