]> git.eshelyaron.com Git - emacs.git/commitdiff
Use Gtk+ tooltips by default for Gtk+ Emacs.
authorJan D <jan.h.d@swipnet.se>
Sun, 1 Aug 2010 13:57:07 +0000 (15:57 +0200)
committerJan D <jan.h.d@swipnet.se>
Sun, 1 Aug 2010 13:57:07 +0000 (15:57 +0200)
* 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.

etc/NEWS
lisp/ChangeLog
lisp/cus-start.el
src/ChangeLog
src/gtkutil.c
src/gtkutil.h
src/xfns.c
src/xterm.c
src/xterm.h

index 2aed81de277620bcfd8645233e8fa349d7075657..570fba192c7bfca51ffa8cdfc35766ee93dc073d 100644 (file)
--- 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.
 
index e6d67c13934b91715383f7fde663e9abeb894b35..5509b1598a4a628c9426331e10523d799bab759c 100644 (file)
@@ -1,3 +1,7 @@
+2010-08-01  Jan Djärv  <jan.h.d@swipnet.se>
+
+       * cus-start.el (x-gtk-use-system-tooltips): New variable.
+
 2010-08-01  Chong Yidong  <cyd@stupidchicken.com>
 
        * emacs-lisp/package.el (package--list-packages): Fix column
index 4778cf611e511e1a5e296535c8f895d1f6bcc489..1e8898290fb381f9df09b3c81660224a1d46acf6 100644 (file)
@@ -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")
index a641336d7a6e853e8a2e91b8f16f9a2fc9edbf43..c382f217a51172daf78269395d531907d6d24202 100644 (file)
@@ -1,3 +1,28 @@
+2010-08-01  Jan Djärv  <jan.h.d@swipnet.se>
+
+       * 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  <monnier@iro.umontreal.ca>
 
        * keymap.c (Fdefine_key, Flookup_key): Say what event is invalid.
index b31eb2d21f28a0e8ddda9040bd8e05a5aadc9553..48b013993a715d6a2e27dd4e85aa620a9e577afb 100644 (file)
@@ -506,6 +506,161 @@ get_utf8_string (char *str)
 }
 
 
+\f
+/***********************************************************************
+                              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;
+}
+
 \f
 /***********************************************************************
     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 ("<none>");
   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.
index 3f1d1a2b8560a785ab9d34baff7a38fb226714e5..9748b07cca041a334159ff808c7bd1cde365f1ac 100644 (file)
@@ -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);
 
index 28de53c59986e448ae468bc40c7bfab9f00fbce3..1496daa9f6349940e3b397204c5b1063ad59d0b3 100644 (file)
@@ -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
index 61e93470cbd6ad718c9a54364a42f7e5734d1d00..f003fc7648d3c090f481e898379307b938d5f752 100644 (file)
@@ -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))
index c487ae4bd6362ecb71dd8bd0b83bf6e4065b0de4..1674cdbac689290d90360ed6f34adb98e86b8b6d 100644 (file)
@@ -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