]> code.delx.au - gnu-emacs/blobdiff - src/gtkutil.c
*** empty log message ***
[gnu-emacs] / src / gtkutil.c
index ce66c5de35eda4ffc6ee57d1520226f4462c2701..b8d37df22144ad16c4ee364900218e4327b36f48 100644 (file)
@@ -1,5 +1,5 @@
 /* Functions for creating and updating GTK widgets.
-   Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -199,7 +199,7 @@ malloc_widget_value ()
     }
   else
     {
-      wv = (widget_value *) malloc (sizeof (widget_value));
+      wv = (widget_value *) xmalloc (sizeof (widget_value));
       malloc_cpt++;
     }
   memset (wv, 0, sizeof (widget_value));
@@ -327,6 +327,7 @@ xg_get_image_for_pixmap (f, img, widget, old_widget)
      look good in all cases.  */
   Lisp_Object specified_file = Qnil;
   Lisp_Object tail;
+  Lisp_Object file;
   extern Lisp_Object QCfile;
 
   for (tail = XCDR (img->spec);
@@ -335,23 +336,18 @@ xg_get_image_for_pixmap (f, img, widget, old_widget)
     if (EQ (XCAR (tail), QCfile))
       specified_file = XCAR (XCDR (tail));
 
-  if (STRINGP (specified_file))
-    {
-      Lisp_Object file = Qnil;
-      struct gcpro gcpro1;
-      GCPRO1 (file);
-
-      file = x_find_image_file (specified_file);
-      /* We already loaded the image once before calling this
-         function, so this should not fail.  */
-      xassert (STRINGP (file) != 0);
+  /* We already loaded the image once before calling this
+     function, so this only fails if the image file has been removed.
+     In that case, use the pixmap already loaded.  */
 
+  if (STRINGP (specified_file)
+      && STRINGP (file = x_find_image_file (specified_file)))
+    {
       if (! old_widget)
         old_widget = GTK_IMAGE (gtk_image_new_from_file (SSDATA (file)));
       else
         gtk_image_set_from_file (old_widget, SSDATA (file));
 
-      UNGCPRO;
       return GTK_WIDGET (old_widget);
     }
 
@@ -1220,6 +1216,9 @@ xg_get_file_name_from_chooser (w)
   return gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (w));
 }
 
+/* Callback called when the "Show hidden files" toggle is pressed.
+   WIDGET is the toggle widget, DATA is the file chooser dialog.  */
+
 static void
 xg_toggle_visibility_cb (widget, data)
      GtkWidget *widget;
@@ -1227,10 +1226,47 @@ xg_toggle_visibility_cb (widget, data)
 {
   GtkFileChooser *dialog = GTK_FILE_CHOOSER (data);
   gboolean visible;
-  extern int x_gtk_show_hidden_files;
   g_object_get (G_OBJECT (dialog), "show-hidden", &visible, NULL);
   g_object_set (G_OBJECT (dialog), "show-hidden", !visible, NULL);
-  x_gtk_show_hidden_files = !visible;
+}
+
+
+/* Callback called when a property changes in a file chooser.
+   GOBJECT is the file chooser dialog, ARG1 describes the property.
+   USER_DATA is the toggle widget in the file chooser dialog.
+   We use this to update the "Show hidden files" toggle when the user
+   changes that property by right clicking in the file list.  */
+
+static void
+xg_toggle_notify_cb (gobject, arg1, user_data)
+     GObject *gobject;
+     GParamSpec *arg1;
+     gpointer user_data;
+{
+  extern int x_gtk_show_hidden_files;
+
+  if (strcmp (arg1->name, "show-hidden") == 0)
+    {
+      GtkFileChooser *dialog = GTK_FILE_CHOOSER (gobject);
+      GtkWidget *wtoggle = GTK_WIDGET (user_data);
+      gboolean visible, toggle_on;
+
+      g_object_get (G_OBJECT (gobject), "show-hidden", &visible, NULL);
+      toggle_on = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (wtoggle));
+
+      if (!!visible != !!toggle_on)
+        {
+          g_signal_handlers_block_by_func (G_OBJECT (wtoggle),
+                                           G_CALLBACK (xg_toggle_visibility_cb),
+                                           gobject);
+          gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wtoggle), visible);
+          g_signal_handlers_unblock_by_func
+            (G_OBJECT (wtoggle),
+             G_CALLBACK (xg_toggle_visibility_cb),
+             gobject);
+        }
+      x_gtk_show_hidden_files = visible;
+    }
 }
 
 /* Read a file name from the user using a file chooser dialog.
@@ -1283,7 +1319,9 @@ xg_get_file_with_chooser (f, prompt, default_filename,
     }
   gtk_widget_show (wtoggle);
   g_signal_connect (G_OBJECT (wtoggle), "clicked",
-                    G_CALLBACK (xg_toggle_visibility_cb), G_OBJECT(filewin));
+                    G_CALLBACK (xg_toggle_visibility_cb), filewin);
+  g_signal_connect (G_OBJECT (filewin), "notify",
+                    G_CALLBACK (xg_toggle_notify_cb), wtoggle);
 
   message[0] = '\0';
   if (action != GTK_FILE_CHOOSER_ACTION_SAVE)
@@ -3200,11 +3238,28 @@ xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole)
    the GtkImage with a new image.  */
 #define XG_TOOL_BAR_IMAGE_DATA "emacs-tool-bar-image"
 
+/* The key for storing the latest modifiers so the activate callback can
+   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.  */
 
+static gboolean
+xg_tool_bar_button_cb (widget, event, user_data)
+    GtkWidget      *widget;
+    GdkEventButton *event;
+    gpointer        user_data;
+{
+  g_object_set_data (G_OBJECT (user_data), XG_TOOL_BAR_LAST_MODIFIER,
+                     (gpointer) event->state);
+  return FALSE;
+}
+
+
 static void
 xg_tool_bar_callback (w, client_data)
      GtkWidget *w;
@@ -3212,6 +3267,8 @@ xg_tool_bar_callback (w, client_data)
 {
   /* The EMACS_INT cast avoids a warning. */
   int idx = (int) (EMACS_INT) client_data;
+  int mod = (int) g_object_get_data (G_OBJECT (w), XG_TOOL_BAR_LAST_MODIFIER);
+
   FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (w), XG_FRAME_DATA);
   Lisp_Object key, frame;
   struct input_event event;
@@ -3232,7 +3289,10 @@ xg_tool_bar_callback (w, client_data)
   event.kind = TOOL_BAR_EVENT;
   event.frame_or_window = frame;
   event.arg = key;
-  event.modifiers = 0;  /* These are not available.  */
+  /* Convert between the modifier bits GDK uses and the modifier bits
+     Emacs uses.  This assumes GDK an X masks are the same, which they are when
+     this is written.  */
+  event.modifiers = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), mod);
   kbd_buffer_store_event (&event);
 }
 
@@ -3250,6 +3310,10 @@ xg_tool_bar_detach_callback (wbox, w, client_data)
      gpointer client_data;
 {
   FRAME_PTR f = (FRAME_PTR) client_data;
+  extern int x_gtk_whole_detached_tool_bar;
+
+  g_object_set (G_OBJECT (w), "show-arrow", !x_gtk_whole_detached_tool_bar,
+               NULL);
 
   if (f)
     {
@@ -3280,6 +3344,7 @@ xg_tool_bar_attach_callback (wbox, w, client_data)
      gpointer client_data;
 {
   FRAME_PTR f = (FRAME_PTR) client_data;
+  g_object_set (G_OBJECT (w), "show-arrow", TRUE, NULL);
 
   if (f)
     {
@@ -3317,9 +3382,7 @@ xg_tool_bar_help_callback (w, event, client_data)
   Lisp_Object help, frame;
 
   if (! GTK_IS_BUTTON (w))
-    {
-      return FALSE;
-    }
+    return FALSE;
 
   if (! f || ! f->n_tool_bar_items || NILP (f->tool_bar_items))
     return FALSE;
@@ -3554,54 +3617,63 @@ update_frame_tool_bar (f)
       if (! wicon)
         {
           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);
           /* The EMACS_INT cast avoids a warning. */
-          gtk_toolbar_append_item (GTK_TOOLBAR (x->toolbar_widget),
-                                   0, 0, 0,
-                                   w,
-                                   GTK_SIGNAL_FUNC (xg_tool_bar_callback),
-                                   (gpointer) (EMACS_INT) i);
+          g_signal_connect (GTK_WIDGET (ti), "clicked",
+                            GTK_SIGNAL_FUNC (xg_tool_bar_callback),
+                            (gpointer) (EMACS_INT) i);
+
+          gtk_widget_show (GTK_WIDGET (ti));
+          gtk_widget_show (GTK_WIDGET (w));
 
           /* 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);
+
           /* Catch expose events to overcome an annoying redraw bug, see
              comment for xg_tool_bar_item_expose_callback.  */
-          g_signal_connect (G_OBJECT (w),
+          g_signal_connect (G_OBJECT (ti),
                             "expose-event",
                             G_CALLBACK (xg_tool_bar_item_expose_callback),
                             0);
 
-          /* We must set sensitive on the button that is the parent
-             of the GtkImage parent.  Go upwards until we find the button.  */
+          gtk_widget_set_sensitive (GTK_WIDGET (ti), enabled_p);
+          gtk_tool_item_set_homogeneous (GTK_TOOL_ITEM (ti), FALSE);
+          
           while (! GTK_IS_BUTTON (w))
             w = gtk_widget_get_parent (w);
 
-          if (w)
-            {
-              /* Save the frame in the button so the xg_tool_bar_callback
-                 can get at it.  */
-              g_object_set_data (G_OBJECT (w), XG_FRAME_DATA, (gpointer)f);
-              gtk_widget_set_sensitive (w, enabled_p);
-
-              /* 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),
-                                "enter-notify-event",
-                                G_CALLBACK (xg_tool_bar_help_callback),
-                                (gpointer) (EMACS_INT) i);
-              g_signal_connect (G_OBJECT (w),
-                                "leave-notify-event",
-                                G_CALLBACK (xg_tool_bar_help_callback),
-                                (gpointer) (EMACS_INT) i);
-            }
+          /* 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",
+                            GTK_SIGNAL_FUNC (xg_tool_bar_button_cb),
+                            ti);
+
+          g_object_set_data (G_OBJECT (w), 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),
+                            "enter-notify-event",
+                            G_CALLBACK (xg_tool_bar_help_callback),
+                            (gpointer) (EMACS_INT) i);
+          g_signal_connect (G_OBJECT (w),
+                            "leave-notify-event",
+                            G_CALLBACK (xg_tool_bar_help_callback),
+                            (gpointer) (EMACS_INT) i);
         }
       else
         {