From: Jan D Date: Sun, 1 Aug 2010 13:57:07 +0000 (+0200) Subject: Use Gtk+ tooltips by default for Gtk+ Emacs. X-Git-Tag: emacs-pretest-24.0.90~104^2~275^2~438^2~49^2~83 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=aa1859f5cd51d760a1b30f01d1fc3928a8c10363;p=emacs.git Use Gtk+ tooltips by default for Gtk+ Emacs. * lisp/cus-start.el (x-gtk-use-system-tooltips): New variable. * src/gtkutil.c (hierarchy_ch_cb, qttip_cb, xg_prepare_tooltip) (xg_show_tooltip, xg_hide_tooltip, xg_free_frame_widgets): New functions. (xg_create_frame_widgets): Set ttip_* to 0. Set a dummy tooltip text so qttip_cb is called. Connect query-tooltip to qttip_cb. Remove code that is commented out. * src/gtkutil.h (xg_free_frame_widgets, xg_prepare_tooltip) (xg_show_tooltip, xg_hide_tooltip): Declare. * src/xfns.c (x_gtk_use_system_tooltips): New variable. (Fx_show_tip): If USE_GTK and x_gtk_use_system_tooltips, call new gtkutil tooltip functions to show the tooltip. (Fx_hide_tip): Call xg_hide_tooltip. (syms_of_xfns): Defvar x-gtk-use-system-tooltips. * src/xterm.c (x_clear_frame): Check FRAME_GTK_WIDGET (f) before calling gtk_widget_queue_draw. (x_free_frame_resources): Call xg_free_frame_widgets. * src/xterm.h (struct x_output): Add ttip_widget, ttip_window and ttip_lbl. --- diff --git a/etc/NEWS b/etc/NEWS index 2aed81de277..570fba192c7 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -104,6 +104,9 @@ The frame-parameter tool-bar-position controls this. It takes the values top, left, tight or bottom. The Options => Show/Hide menu has entries for this. +** Emacs uses GTK tooltips by default if built with GTK. You can turn that +off by customizing x-gtk-use-system-tooltips. + ** Lucid menus and dialogs can display antialiased fonts if Emacs is built with Xft. diff --git a/lisp/ChangeLog b/lisp/ChangeLog index e6d67c13934..5509b1598a4 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,7 @@ +2010-08-01 Jan Djärv + + * cus-start.el (x-gtk-use-system-tooltips): New variable. + 2010-08-01 Chong Yidong * emacs-lisp/package.el (package--list-packages): Fix column diff --git a/lisp/cus-start.el b/lisp/cus-start.el index 4778cf611e5..1e8898290fb 100644 --- a/lisp/cus-start.el +++ b/lisp/cus-start.el @@ -358,6 +358,7 @@ since it could result in memory overflow and make Emacs crash." (x-gtk-show-hidden-files menu boolean "22.1") (x-gtk-file-dialog-help-text menu boolean "22.1") (x-gtk-whole-detached-tool-bar x boolean "22.1") + (x-gtk-use-system-tooltips tooltip boolean "23.3") ;; xterm.c (x-use-underline-position-properties display boolean "22.1") (x-underline-at-descent-line display boolean "22.1") diff --git a/src/ChangeLog b/src/ChangeLog index a641336d7a6..c382f217a51 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,28 @@ +2010-08-01 Jan Djärv + + * xterm.h (struct x_output): Add ttip_widget, ttip_window and + ttip_lbl. + + * xterm.c (x_clear_frame): Check FRAME_GTK_WIDGET (f) before + calling gtk_widget_queue_draw. + (x_free_frame_resources): Call xg_free_frame_widgets. + + * xfns.c (x_gtk_use_system_tooltips): New variable. + (Fx_show_tip): If USE_GTK and x_gtk_use_system_tooltips, call + new gtkutil tooltip functions to show the tooltip. + (Fx_hide_tip): Call xg_hide_tooltip. + (syms_of_xfns): Defvar x-gtk-use-system-tooltips. + + * gtkutil.h (xg_free_frame_widgets, xg_prepare_tooltip) + (xg_show_tooltip, xg_hide_tooltip): Declare. + + * gtkutil.c (hierarchy_ch_cb, qttip_cb, xg_prepare_tooltip) + (xg_show_tooltip, xg_hide_tooltip, xg_free_frame_widgets): New + functions. + (xg_create_frame_widgets): Set ttip_* to 0. Set a dummy tooltip + text so qttip_cb is called. Connect query-tooltip to qttip_cb. + Remove code that is commented out. + 2010-08-01 Stefan Monnier * keymap.c (Fdefine_key, Flookup_key): Say what event is invalid. diff --git a/src/gtkutil.c b/src/gtkutil.c index b31eb2d21f2..48b013993a7 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -506,6 +506,161 @@ get_utf8_string (char *str) } + +/*********************************************************************** + Tooltips + ***********************************************************************/ +/* Gtk+ calls this callback when the parent of our tooltip dummy changes. + We use that to pop down the tooltip. This happens if Gtk+ for some + reason wants to change or hide the tooltip. */ + +static void +hierarchy_ch_cb (GtkWidget *widget, + GtkWidget *previous_toplevel, + gpointer user_data) +{ + FRAME_PTR f = (FRAME_PTR) user_data; + struct x_output *x = f->output_data.x; + GtkWidget *top = gtk_widget_get_toplevel (x->ttip_lbl); + + if (! top || ! GTK_IS_WINDOW (top)) + gtk_widget_hide (previous_toplevel); +} + +/* Callback called when Gtk+ thinks a tooltip should be displayed. + We use it to get the tooltip window and the tooltip widget so + we can manipulate the ourselves. + + Return FALSE ensures that the tooltip is not shown. */ + +static gboolean +qttip_cb (GtkWidget *widget, + gint xpos, + gint ypos, + gboolean keyboard_mode, + GtkTooltip *tooltip, + gpointer user_data) +{ + FRAME_PTR f = (FRAME_PTR) user_data; + struct x_output *x = f->output_data.x; + if (x->ttip_widget == NULL) + { + g_object_set (G_OBJECT (widget), "has-tooltip", FALSE, NULL); + x->ttip_widget = tooltip; + g_object_ref (G_OBJECT (tooltip)); + x->ttip_lbl = gtk_label_new (""); + g_object_ref (G_OBJECT (x->ttip_lbl)); + gtk_tooltip_set_custom (tooltip, x->ttip_lbl); + x->ttip_window = GTK_WINDOW (gtk_widget_get_toplevel (x->ttip_lbl)); + /* Realize so we can safely get screen later on. */ + gtk_widget_realize (GTK_WIDGET (x->ttip_window)); + gtk_widget_realize (x->ttip_lbl); + + g_signal_connect (x->ttip_lbl, "hierarchy-changed", + G_CALLBACK (hierarchy_ch_cb), f); + } + return FALSE; +} + +/* Prepare a tooltip to be shown, i.e. calculate WIDTH and HEIGHT. + Return zero if no system tooltip available, non-zero otherwise. */ + +int +xg_prepare_tooltip (FRAME_PTR f, + Lisp_Object string, + int *width, + int *height) +{ + struct x_output *x = f->output_data.x; + GtkWidget *widget; + GdkWindow *gwin; + GdkScreen *screen; + GtkSettings *settings; + gboolean tt_enabled = TRUE; + GtkRequisition req; + Lisp_Object encoded_string; + + if (!x->ttip_lbl) return 0; + + BLOCK_INPUT; + encoded_string = ENCODE_UTF_8 (string); + widget = GTK_WIDGET (x->ttip_lbl); + gwin = gtk_widget_get_window (GTK_WIDGET (x->ttip_window)); + screen = gdk_drawable_get_screen (gwin); + settings = gtk_settings_get_for_screen (screen); + g_object_get (settings, "gtk-enable-tooltips", &tt_enabled, NULL); + if (tt_enabled) + { + g_object_set (settings, "gtk-enable-tooltips", FALSE, NULL); + /* Record that we disabled it so it can be enabled again. */ + g_object_set_data (G_OBJECT (x->ttip_window), "restore-tt", + (gpointer)f); + } + + /* Prevent Gtk+ from hiding tooltip on mouse move and such. */ + g_object_set_data (G_OBJECT + (gtk_widget_get_display (GTK_WIDGET (x->ttip_window))), + "gdk-display-current-tooltip", NULL); + + /* Put out dummy widget in so we can get callbacks for unrealize and + hierarchy-changed. */ + gtk_tooltip_set_custom (x->ttip_widget, widget); + + gtk_tooltip_set_text (x->ttip_widget, SDATA (encoded_string)); + gtk_widget_size_request (GTK_WIDGET (x->ttip_window), &req); + if (width) *width = req.width; + if (height) *height = req.height; + + UNBLOCK_INPUT; + + return 1; +} + +/* Show the tooltip at ROOT_X and ROOT_Y. + xg_prepare_tooltip must have been called before this function. */ + +void +xg_show_tooltip (FRAME_PTR f, int root_x, int root_y) +{ + struct x_output *x = f->output_data.x; + if (x->ttip_window) + { + BLOCK_INPUT; + gtk_window_move (x->ttip_window, root_x, root_y); + gtk_widget_show_all (GTK_WIDGET (x->ttip_window)); + UNBLOCK_INPUT; + } +} + +/* Hide tooltip if shown. Do nothing if not shown. + Return non-zero if tip was hidden, non-ero if not (i.e. not using + system tooltips). */ + +int +xg_hide_tooltip (FRAME_PTR f) +{ + int ret = 0; + if (f->output_data.x->ttip_window) + { + GtkWindow *win = f->output_data.x->ttip_window; + BLOCK_INPUT; + gtk_widget_hide (GTK_WIDGET (win)); + + if (g_object_get_data (G_OBJECT (win), "restore-tt")) + { + GdkWindow *gwin = gtk_widget_get_window (GTK_WIDGET (win)); + GdkScreen *screen = gdk_drawable_get_screen (gwin); + GtkSettings *settings = gtk_settings_get_for_screen (screen); + g_object_set (settings, "gtk-enable-tooltips", TRUE, NULL); + } + UNBLOCK_INPUT; + + ret = 1; + } + + return ret; +} + /*********************************************************************** General functions for creating widgets, resizing, events, e.t.c. @@ -847,17 +1002,34 @@ xg_create_frame_widgets (FRAME_PTR f) style->bg_pixmap_name[GTK_STATE_NORMAL] = g_strdup (""); gtk_widget_modify_style (wfixed, style); - /* GTK does not set any border, and they look bad with GTK. */ - /* That they look bad is no excuse for imposing this here. --Stef - It should be done by providing the proper default in Fx_create_Frame. - f->border_width = 0; - f->internal_border_width = 0; */ + /* Steal a tool tip window we can move ourselves. */ + f->output_data.x->ttip_widget = 0; + f->output_data.x->ttip_lbl = 0; + f->output_data.x->ttip_window = 0; + gtk_widget_set_tooltip_text (wtop, "Dummy text"); + g_signal_connect (wtop, "query-tooltip", G_CALLBACK (qttip_cb), f); UNBLOCK_INPUT; return 1; } +void +xg_free_frame_widgets (FRAME_PTR f) +{ + if (FRAME_GTK_OUTER_WIDGET (f)) + { + struct x_output *x = f->output_data.x; + gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f)); + FRAME_X_WINDOW (f) = 0; /* Set to avoid XDestroyWindow in xterm.c */ + FRAME_GTK_OUTER_WIDGET (f) = 0; + if (x->ttip_lbl) + gtk_widget_destroy (x->ttip_lbl); + if (x->ttip_widget) + g_object_unref (G_OBJECT (x->ttip_widget)); + } +} + /* Set the normal size hints for the window manager, for frame F. FLAGS is the flags word to use--or 0 meaning preserve the flags that the window now has. diff --git a/src/gtkutil.h b/src/gtkutil.h index 3f1d1a2b856..9748b07cca0 100644 --- a/src/gtkutil.h +++ b/src/gtkutil.h @@ -194,6 +194,7 @@ extern void xg_display_close (Display *dpy); extern GdkCursor * xg_create_default_cursor (Display *dpy); extern int xg_create_frame_widgets (FRAME_PTR f); +extern void xg_free_frame_widgets (FRAME_PTR f); extern void x_wm_set_size_hint (FRAME_PTR f, long flags, int user_position); @@ -203,6 +204,14 @@ extern void xg_set_frame_icon (FRAME_PTR f, Pixmap icon_pixmap, Pixmap icon_mask); +extern int xg_prepare_tooltip (FRAME_PTR f, + Lisp_Object string, + int *width, + int *height); +extern void xg_show_tooltip (FRAME_PTR f, int root_x, int root_y); +extern int xg_hide_tooltip (FRAME_PTR f); + + /* Mark all callback data that are Lisp_object:s during GC. */ extern void xg_mark_data (void); diff --git a/src/xfns.c b/src/xfns.c index 28de53c5998..1496daa9f63 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -161,6 +161,10 @@ int x_gtk_file_dialog_help_text; int x_gtk_whole_detached_tool_bar; +/* If non-zero, use Gtk+ tooltips. */ + +static int x_gtk_use_system_tooltips; + /* The background and shape of the mouse pointer, and shape when not over text or in the modeline. */ @@ -4610,7 +4614,9 @@ unwind_create_tip_frame (Lisp_Object frame) when this happens. */ static Lisp_Object -x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms, Lisp_Object text) +x_create_tip_frame (struct x_display_info *dpyinfo, + Lisp_Object parms, + Lisp_Object text) { struct frame *f; Lisp_Object frame, tem; @@ -5037,6 +5043,27 @@ Text larger than the specified size is clipped. */) else CHECK_NUMBER (dy); +#ifdef USE_GTK + if (x_gtk_use_system_tooltips) + { + int ok; + + /* Hide a previous tip, if any. */ + Fx_hide_tip (); + + BLOCK_INPUT; + if ((ok = xg_prepare_tooltip (f, string, &width, &height)) != 0) + { + 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; + } +#endif /* USE_GTK */ + if (NILP (last_show_tip_args)) last_show_tip_args = Fmake_vector (make_number (3), Qnil); @@ -5197,6 +5224,7 @@ Value is t if tooltip was open, nil otherwise. */) int count; Lisp_Object deleted, frame, timer; struct gcpro gcpro1, gcpro2; + struct frame *f; /* Return quickly if nothing to do. */ if (NILP (tip_timer) && NILP (tip_frame)) @@ -5214,6 +5242,14 @@ Value is t if tooltip was open, nil otherwise. */) if (!NILP (timer)) call1 (Qcancel_timer, timer); +#ifdef USE_GTK + /* When using system tooltip, tip_frame is the Emacs frame on which + the tip is shown. */ + f = XFRAME (frame); + if (xg_hide_tooltip (f)) + frame = Qnil; +#endif + if (FRAMEP (frame)) { delete_frame (frame, Qnil); @@ -5224,8 +5260,9 @@ Value is t if tooltip was open, nil otherwise. */) redisplay procedure is not called when a tip frame over menu items is unmapped. Redisplay the menu manually... */ { - struct frame *f = SELECTED_FRAME (); - Widget w = f->output_data.x->menubar_widget; + Widget w; + f = SELECTED_FRAME (); + w = f->output_data.x->menubar_widget; if (!DoesSaveUnders (FRAME_X_DISPLAY_INFO (f)->screen) && w != NULL) @@ -5894,6 +5931,12 @@ The default is to just show an arrow and pressing on that arrow shows the tool bar buttons. */); x_gtk_whole_detached_tool_bar = 0; + DEFVAR_BOOL ("x-gtk-use-system-tooltips", &x_gtk_use_system_tooltips, + doc: /* *If non-nil with a Gtk+ built Emacs, the Gtk+ toolip is used. +Otherwise use Emacs own tooltip implementation. +When using Gtk+ tooltips, the tooltip face is not used. */); + x_gtk_use_system_tooltips = 1; + Fprovide (intern_c_string ("x"), Qnil); #ifdef USE_X_TOOLKIT diff --git a/src/xterm.c b/src/xterm.c index 61e93470cbd..f003fc7648d 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -2842,7 +2842,8 @@ x_clear_frame (struct frame *f) #if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS) /* Make sure scroll bars are redrawn. As they aren't redrawn by redisplay, do it here. */ - gtk_widget_queue_draw (FRAME_GTK_WIDGET (f)); + if (FRAME_GTK_WIDGET (f)) + gtk_widget_queue_draw (FRAME_GTK_WIDGET (f)); #endif XFlush (FRAME_X_DISPLAY (f)); @@ -9278,14 +9279,7 @@ x_free_frame_resources (struct frame *f) #else /* !USE_X_TOOLKIT */ #ifdef USE_GTK - /* In the GTK version, tooltips are normal X - frames. We must check and free both types. */ - if (FRAME_GTK_OUTER_WIDGET (f)) - { - gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f)); - FRAME_X_WINDOW (f) = 0; /* Set to avoid XDestroyWindow below */ - FRAME_GTK_OUTER_WIDGET (f) = 0; - } + xg_free_frame_widgets (f); #endif /* USE_GTK */ if (FRAME_X_WINDOW (f)) diff --git a/src/xterm.h b/src/xterm.h index c487ae4bd63..1674cdbac68 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -502,6 +502,10 @@ struct x_output /* The last size hints set. */ GdkGeometry size_hints; long hint_flags; + + GtkTooltip *ttip_widget; + GtkWidget *ttip_lbl; + GtkWindow *ttip_window; #endif /* If >=0, a bitmap index. The indicated bitmap is used for the