diff src/gtkutil.c @ 83550:17e0dd217877

Merged from emacs@sv.gnu.org. Patches applied: * emacs@sv.gnu.org/emacs--devo--0--patch-536 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-537 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-538 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-539 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-540 Merge from gnus--rel--5.10 * emacs@sv.gnu.org/emacs--devo--0--patch-541 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-542 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-543 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-544 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-545 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-546 Update from erc--emacs--22 * emacs@sv.gnu.org/emacs--devo--0--patch-547 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-548 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-549 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-550 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-551 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-552 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-553 Merge from gnus--rel--5.10 * emacs@sv.gnu.org/emacs--devo--0--patch-554 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-555 erc-iswitchb: Temporarily enable iswitchb mode * emacs@sv.gnu.org/emacs--devo--0--patch-556 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-557 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-558 Merge from gnus--rel--5.10 * emacs@sv.gnu.org/emacs--devo--0--patch-559 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-560 Merge from gnus--rel--5.10 * emacs@sv.gnu.org/emacs--devo--0--patch-561 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-562 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-563 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-564 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-565 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-566 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-567 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-568 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-569 Merge from gnus--rel--5.10 * emacs@sv.gnu.org/emacs--devo--0--patch-570 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-571 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-572 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-573 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-574 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-575 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-576 Merge from gnus--rel--5.10 * emacs@sv.gnu.org/emacs--devo--0--patch-577 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-578 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-579 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-580 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-581 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-582 Merge from gnus--rel--5.10 * emacs@sv.gnu.org/emacs--devo--0--patch-583 Update from CVS * emacs@sv.gnu.org/emacs--devo--0--patch-584 Fix admin/quick-install-emacs to work with recent versions of autoconf * emacs@sv.gnu.org/gnus--rel--5.10--patch-171 Update from CVS * emacs@sv.gnu.org/gnus--rel--5.10--patch-172 Merge from emacs--devo--0 * emacs@sv.gnu.org/gnus--rel--5.10--patch-173 Merge from emacs--devo--0 * emacs@sv.gnu.org/gnus--rel--5.10--patch-174 Update from CVS * emacs@sv.gnu.org/gnus--rel--5.10--patch-175 Update from CVS: lisp/legacy-gnus-agent.el: Add Copyright notice. * emacs@sv.gnu.org/gnus--rel--5.10--patch-176 Update from CVS * emacs@sv.gnu.org/gnus--rel--5.10--patch-177 Merge from emacs--devo--0 * emacs@sv.gnu.org/gnus--rel--5.10--patch-178 Update from CVS * emacs@sv.gnu.org/gnus--rel--5.10--patch-179 Update from CVS * emacs@sv.gnu.org/gnus--rel--5.10--patch-180 Update from CVS * emacs@sv.gnu.org/gnus--rel--5.10--patch-181 Update from CVS * emacs@sv.gnu.org/gnus--rel--5.10--patch-182 Update from CVS * emacs@sv.gnu.org/gnus--rel--5.10--patch-183 Update from CVS * emacs@sv.gnu.org/gnus--rel--5.10--patch-184 Update from CVS * emacs@sv.gnu.org/gnus--rel--5.10--patch-185 Merge from emacs--devo--0 git-archimport-id: lorentey@elte.hu--2004/emacs--multi-tty--0--patch-590
author Karoly Lorentey <lorentey@elte.hu>
date Mon, 01 Jan 2007 17:38:32 +0000
parents c71725faff1a 6ec19c8cca02
children d3099204c799
line wrap: on
line diff
--- a/src/gtkutil.c	Sun Dec 03 15:12:18 2006 +0000
+++ b/src/gtkutil.c	Mon Jan 01 17:38:32 2007 +0000
@@ -3350,11 +3350,8 @@
    get them.  */
 #define XG_TOOL_BAR_LAST_MODIFIER "emacs-tool-bar-modifier"
 
-
-/* Callback function invoked when a tool bar item is pressed.
-   W is the button widget in the tool bar that got pressed,
-   CLIENT_DATA is an integer that is the index of the button in the
-   tool bar.  0 is the first button.  */
+/* The key for storing the button widget in its proxy menu item. */
+#define XG_TOOL_BAR_PROXY_BUTTON "emacs-tool-bar-proxy-button"
 
 static gboolean
 xg_tool_bar_button_cb (widget, event, user_data)
@@ -3364,11 +3361,16 @@
 {
   /* Casts to avoid warnings when gpointer is 64 bits and int is 32 bits */
   gpointer ptr = (gpointer) (EMACS_INT) event->state;
-  g_object_set_data (G_OBJECT (user_data), XG_TOOL_BAR_LAST_MODIFIER, ptr);
+  g_object_set_data (G_OBJECT (widget), XG_TOOL_BAR_LAST_MODIFIER, ptr);
   return FALSE;
 }
 
 
+/* Callback function invoked when a tool bar item is pressed.
+   W is the button widget in the tool bar that got pressed,
+   CLIENT_DATA is an integer that is the index of the button in the
+   tool bar.  0 is the first button.  */
+
 static void
 xg_tool_bar_callback (w, client_data)
      GtkWidget *w;
@@ -3406,6 +3408,92 @@
   kbd_buffer_store_event (&event);
 }
 
+/* Callback function invoked when a tool bar item is pressed in a detached
+   tool bar or the overflow drop down menu.
+   We just call xg_tool_bar_callback.
+   W is the menu item widget that got pressed,
+   CLIENT_DATA is an integer that is the index of the button in the
+   tool bar.  0 is the first button.  */
+
+static void
+xg_tool_bar_proxy_callback (w, client_data)
+     GtkWidget *w;
+     gpointer client_data;
+{
+  GtkWidget *wbutton = GTK_WIDGET (g_object_get_data (G_OBJECT (w),
+                                                      XG_TOOL_BAR_PROXY_BUTTON));
+  xg_tool_bar_callback (wbutton, client_data);
+}
+
+/* This callback is called when a tool item should create a proxy item,
+   such as for the overflow menu.  Also called when the tool bar is detached.
+   If we don't create a proxy menu item, the detached tool bar will be
+   blank.  */
+
+static gboolean
+xg_tool_bar_menu_proxy (toolitem, user_data)
+     GtkToolItem *toolitem;
+     gpointer user_data;
+{
+  GtkWidget *weventbox = gtk_bin_get_child (GTK_BIN (toolitem));
+  GtkButton *wbutton = GTK_BUTTON (gtk_bin_get_child (GTK_BIN (weventbox)));
+  GtkWidget *wmenuitem = gtk_image_menu_item_new ();
+  GtkWidget *wmenuimage;
+
+  if (gtk_button_get_use_stock (wbutton)) 
+    wmenuimage = gtk_image_new_from_stock (gtk_button_get_label (wbutton),
+                                           GTK_ICON_SIZE_MENU);
+  else
+    {
+      GtkImage *wimage = GTK_IMAGE (gtk_bin_get_child (GTK_BIN (wbutton)));
+      GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (wbutton));
+      GtkImageType store_type = gtk_image_get_storage_type (wimage);
+      if (store_type == GTK_IMAGE_STOCK)
+        {
+          gchar *stock_id;
+          gtk_image_get_stock (wimage, &stock_id, NULL);
+          wmenuimage = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_MENU);
+        }
+      else if (store_type == GTK_IMAGE_ICON_SET)
+        {
+          GtkIconSet *icon_set;
+          gtk_image_get_icon_set (wimage, &icon_set, NULL);
+          wmenuimage = gtk_image_new_from_icon_set (icon_set,
+                                                    GTK_ICON_SIZE_MENU);
+        }
+      else if (store_type == GTK_IMAGE_PIXBUF)
+        {
+          gint width, height;
+      
+          if (settings &&
+              gtk_icon_size_lookup_for_settings (settings, GTK_ICON_SIZE_MENU,
+                                                 &width, &height))
+            {
+              GdkPixbuf *src_pixbuf, *dest_pixbuf;
+
+              src_pixbuf = gtk_image_get_pixbuf (wimage);
+              dest_pixbuf = gdk_pixbuf_scale_simple (src_pixbuf, width, height,
+                                                     GDK_INTERP_BILINEAR);
+
+              wmenuimage = gtk_image_new_from_pixbuf (dest_pixbuf);
+            }
+        }
+    }
+  if (wmenuimage)
+    gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (wmenuitem), wmenuimage);
+
+  g_signal_connect (G_OBJECT (wmenuitem),
+                    "activate",
+                    GTK_SIGNAL_FUNC (xg_tool_bar_proxy_callback),
+                    user_data);
+
+  g_object_set_data (G_OBJECT (wmenuitem), XG_TOOL_BAR_PROXY_BUTTON,
+                     (gpointer) wbutton);
+  gtk_tool_item_set_proxy_menu_item (toolitem, "Emacs toolbar item", wmenuitem);
+
+  return TRUE;
+}
+
 /* This callback is called when a tool bar is detached.  We must set
    the height of the tool bar to zero when this happens so frame sizes
    are correctly calculated.
@@ -3491,9 +3579,6 @@
   FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
   Lisp_Object help, frame;
 
-  if (! GTK_IS_BUTTON (w))
-    return FALSE;
-
   if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
     return FALSE;
 
@@ -3631,10 +3716,9 @@
 {
   int i;
   GtkRequisition old_req, new_req;
-  GList *icon_list;
-  GList *iter;
   struct x_output *x = f->output_data.x;
   int hmargin, vmargin;
+  GtkToolItem *ti;
 
   if (! FRAME_GTK_WIDGET (f))
     return;
@@ -3670,9 +3754,6 @@
 
   gtk_widget_size_request (x->toolbar_widget, &old_req);
 
-  icon_list = gtk_container_get_children (GTK_CONTAINER (x->toolbar_widget));
-  iter = icon_list;
-
   for (i = 0; i < f->n_tool_bar_items; ++i)
     {
 #define PROP(IDX) AREF (f->tool_bar_items, i * TOOL_BAR_ITEM_NSLOTS + (IDX))
@@ -3683,9 +3764,16 @@
       int img_id;
       struct image *img;
       Lisp_Object image;
-      GtkWidget *wicon = iter ? GTK_WIDGET (iter->data) : 0;
-
-      if (iter) iter = g_list_next (iter);
+      GtkWidget *wbutton;
+      GtkWidget *weventbox;
+
+      ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (x->toolbar_widget), i);
+
+      if (ti)
+        {
+          weventbox = gtk_bin_get_child (GTK_BIN (ti));
+          wbutton = gtk_bin_get_child (GTK_BIN (weventbox));
+        }
 
       /* If image is a vector, choose the image according to the
 	 button state.  */
@@ -3710,7 +3798,7 @@
       /* Ignore invalid image specifications.  */
       if (!valid_image_p (image))
         {
-          if (wicon) gtk_widget_hide (wicon);
+          if (ti) gtk_widget_hide_all (GTK_WIDGET (ti));
           continue;
         }
 
@@ -3720,39 +3808,55 @@
 
       if (img->load_failed_p || img->pixmap == None)
         {
-          if (wicon)
-	    gtk_widget_hide (wicon);
+          if (ti)
+	    gtk_widget_hide_all (GTK_WIDGET (ti));
 	  else
-	    gtk_toolbar_insert (GTK_TOOLBAR (x->toolbar_widget),
-				gtk_tool_button_new (NULL, ""),
-				i);
+            {
+              /* Insert an empty (non-image) button */
+              weventbox = gtk_event_box_new ();
+              wbutton = gtk_button_new ();
+              gtk_button_set_focus_on_click (GTK_BUTTON (wbutton), FALSE);
+              gtk_button_set_relief (GTK_BUTTON (wbutton), GTK_RELIEF_NONE);
+              gtk_container_add (GTK_CONTAINER (weventbox), wbutton);
+              ti = gtk_tool_item_new ();
+              gtk_container_add (GTK_CONTAINER (ti), weventbox);
+              gtk_toolbar_insert (GTK_TOOLBAR (x->toolbar_widget), ti, i);
+            }
           continue;
         }
 
-      if (! wicon)
+      if (ti == NULL)
         {
           GtkWidget *w = xg_get_image_for_pixmap (f, img, x->widget, NULL);
-          GtkToolItem *ti = gtk_tool_button_new (w, "");
-
           gtk_misc_set_padding (GTK_MISC (w), hmargin, vmargin);
-
-          gtk_toolbar_insert (GTK_TOOLBAR (x->toolbar_widget),
-                              ti,
-                              i);
+          wbutton = gtk_button_new ();
+          gtk_button_set_focus_on_click (GTK_BUTTON (wbutton), FALSE);
+          gtk_button_set_relief (GTK_BUTTON (wbutton), GTK_RELIEF_NONE);
+          gtk_container_add (GTK_CONTAINER (wbutton), w);
+          weventbox = gtk_event_box_new ();
+          gtk_container_add (GTK_CONTAINER (weventbox), wbutton);
+          ti = gtk_tool_item_new ();
+          gtk_container_add (GTK_CONTAINER (ti), weventbox);
+          gtk_toolbar_insert (GTK_TOOLBAR (x->toolbar_widget), ti, i);
+
+
           /* The EMACS_INT cast avoids a warning. */
-          g_signal_connect (GTK_WIDGET (ti), "clicked",
+          g_signal_connect (G_OBJECT (ti), "create-menu-proxy",
+                            GTK_SIGNAL_FUNC (xg_tool_bar_menu_proxy),
+                            (gpointer) (EMACS_INT) i);
+
+          g_signal_connect (G_OBJECT (wbutton), "clicked",
                             GTK_SIGNAL_FUNC (xg_tool_bar_callback),
                             (gpointer) (EMACS_INT) i);
 
-          gtk_widget_show (GTK_WIDGET (ti));
-          gtk_widget_show (GTK_WIDGET (w));
+          gtk_widget_show_all (GTK_WIDGET (ti));
 
           /* Save the image so we can see if an update is needed when
              this function is called again.  */
           g_object_set_data (G_OBJECT (w), XG_TOOL_BAR_IMAGE_DATA,
                              (gpointer)img->pixmap);
 
-          g_object_set_data (G_OBJECT (ti), XG_FRAME_DATA, (gpointer)f);
+          g_object_set_data (G_OBJECT (weventbox), XG_FRAME_DATA, (gpointer)f);
 
           /* Catch expose events to overcome an annoying redraw bug, see
              comment for xg_tool_bar_item_expose_callback.  */
@@ -3761,46 +3865,37 @@
                             G_CALLBACK (xg_tool_bar_item_expose_callback),
                             0);
 
-          gtk_widget_set_sensitive (GTK_WIDGET (ti), enabled_p);
-          gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (ti), FALSE);
+          gtk_widget_set_sensitive (wbutton, enabled_p);
+          gtk_tool_item_set_homogeneous (ti, FALSE);
           
-          while (! GTK_IS_BUTTON (w))
-            w = gtk_widget_get_parent (w);
-
           /* Callback to save modifyer mask (Shift/Control, etc).  GTK makes
              no distinction based on modifiers in the activate callback,
              so we have to do it ourselves.  */
-          g_signal_connect (w, "button-release-event",
+          g_signal_connect (wbutton, "button-release-event",
                             GTK_SIGNAL_FUNC (xg_tool_bar_button_cb),
-                            ti);
-
-          g_object_set_data (G_OBJECT (w), XG_FRAME_DATA, (gpointer)f);
+                            NULL);
+
+          g_object_set_data (G_OBJECT (wbutton), XG_FRAME_DATA, (gpointer)f);
 
           /* Use enter/leave notify to show help.  We use the events
              rather than the GtkButton specific signals "enter" and
              "leave", so we can have only one callback.  The event
              will tell us what kind of event it is.  */
           /* The EMACS_INT cast avoids a warning. */
-          g_signal_connect (G_OBJECT (w),
+          g_signal_connect (G_OBJECT (weventbox),
                             "enter-notify-event",
                             G_CALLBACK (xg_tool_bar_help_callback),
                             (gpointer) (EMACS_INT) i);
-          g_signal_connect (G_OBJECT (w),
+          g_signal_connect (G_OBJECT (weventbox),
                             "leave-notify-event",
                             G_CALLBACK (xg_tool_bar_help_callback),
                             (gpointer) (EMACS_INT) i);
         }
       else
         {
-          /* The child of the tool bar is a button.  Inside that button
-             is a vbox.  Inside that vbox is the GtkImage.  */
-          GtkWidget *wvbox = gtk_bin_get_child (GTK_BIN (wicon));
-          GList *chlist = gtk_container_get_children (GTK_CONTAINER (wvbox));
-          GtkImage *wimage = GTK_IMAGE (chlist->data);
+          GtkWidget *wimage = gtk_bin_get_child (GTK_BIN (wbutton));
           Pixmap old_img = (Pixmap)g_object_get_data (G_OBJECT (wimage),
                                                       XG_TOOL_BAR_IMAGE_DATA);
-          g_list_free (chlist);
-
           gtk_misc_set_padding (GTK_MISC (wimage), hmargin, vmargin);
 
           if (old_img != img->pixmap)
@@ -3809,21 +3904,20 @@
           g_object_set_data (G_OBJECT (wimage), XG_TOOL_BAR_IMAGE_DATA,
                              (gpointer)img->pixmap);
 
-          gtk_widget_set_sensitive (wicon, enabled_p);
-          gtk_widget_show (wicon);
-        }
+          gtk_widget_set_sensitive (wbutton, enabled_p);
+          gtk_widget_show_all (GTK_WIDGET (ti));
+       }
 
 #undef PROP
     }
 
   /* Remove buttons not longer needed.  We just hide them so they
      can be reused later on.  */
-  while (iter)
+  do
     {
-      GtkWidget *w = GTK_WIDGET (iter->data);
-      gtk_widget_hide (w);
-      iter = g_list_next (iter);
-    }
+      ti = gtk_toolbar_get_nth_item (GTK_TOOLBAR (x->toolbar_widget), i++);
+      if (ti) gtk_widget_hide_all (GTK_WIDGET (ti));
+    } while (ti != NULL);
 
   gtk_widget_size_request (x->toolbar_widget, &new_req);
   if (old_req.height != new_req.height
@@ -3833,8 +3927,6 @@
       xg_resize_outer_widget (f, FRAME_COLS (f), FRAME_LINES (f));
     }
 
-  if (icon_list) g_list_free (icon_list);
-
   UNBLOCK_INPUT;
 }