]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkaction.c
Fix the GtkBuildable implementation to allow setting column types.
[~andy/gtk] / gtk / gtkaction.c
index 076d8b4c6e2b2941c7aeab37128f7d5c18c382b2..99bfcb96d60ee249a1ebf004ed6cd4c8c8dcde5e 100644 (file)
@@ -34,6 +34,7 @@
 #include "gtkactiongroup.h"
 #include "gtkaccellabel.h"
 #include "gtkbutton.h"
+#include "gtkiconfactory.h"
 #include "gtkimage.h"
 #include "gtkimagemenuitem.h"
 #include "gtkintl.h"
@@ -45,6 +46,7 @@
 #include "gtktoolbutton.h"
 #include "gtktoolbar.h"
 #include "gtkprivate.h"
+#include "gtkbuildable.h"
 #include "gtkalias.h"
 
 
 
 struct _GtkActionPrivate 
 {
-  gchar *name;
+  const gchar *name; /* interned */
   gchar *label;
   gchar *short_label;
   gchar *tooltip;
-  gchar *stock_id; /* icon */
+  gchar *stock_id; /* stock icon */
+  gchar *icon_name; /* themed icon */
 
   guint sensitive          : 1;
   guint visible            : 1;
@@ -94,6 +97,7 @@ enum
   PROP_SHORT_LABEL,
   PROP_TOOLTIP,
   PROP_STOCK_ID,
+  PROP_ICON_NAME,
   PROP_VISIBLE_HORIZONTAL,
   PROP_VISIBLE_VERTICAL,
   PROP_VISIBLE_OVERFLOWN,
@@ -104,39 +108,21 @@ enum
   PROP_ACTION_GROUP
 };
 
-static void gtk_action_init       (GtkAction *action);
-static void gtk_action_class_init (GtkActionClass *class);
+/* GtkBuildable */
+static void gtk_action_buildable_init             (GtkBuildableIface *iface);
+static void gtk_action_buildable_set_name         (GtkBuildable *buildable,
+                                                  const gchar  *name);
+static const gchar* gtk_action_buildable_get_name (GtkBuildable *buildable);
 
-static GQuark       accel_path_id  = 0;
-static const gchar accel_path_key[] = "GtkAction::accel_path";
+G_DEFINE_TYPE_WITH_CODE (GtkAction, gtk_action, G_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+                                               gtk_action_buildable_init))
 
-GType
-gtk_action_get_type (void)
-{
-  static GtkType type = 0;
 
-  if (!type)
-    {
-      static const GTypeInfo type_info =
-      {
-        sizeof (GtkActionClass),
-        (GBaseInitFunc) NULL,
-        (GBaseFinalizeFunc) NULL,
-        (GClassInitFunc) gtk_action_class_init,
-        (GClassFinalizeFunc) NULL,
-        NULL,
-        
-        sizeof (GtkAction),
-        0, /* n_preallocs */
-        (GInstanceInitFunc) gtk_action_init,
-      };
-
-      type = g_type_register_static (G_TYPE_OBJECT,
-                                    I_("GtkAction"),
-                                    &type_info, 0);
-    }
-  return type;
-}
+static GQuark      accel_path_id  = 0;
+static GQuark      quark_gtk_action_proxy  = 0;
+static const gchar accel_path_key[] = "GtkAction::accel_path";
+static const gchar gtk_action_proxy_key[] = "gtk-action";
 
 static void gtk_action_finalize     (GObject *object);
 static void gtk_action_set_property (GObject         *object,
@@ -147,15 +133,34 @@ static void gtk_action_get_property (GObject         *object,
                                     guint            prop_id,
                                     GValue          *value,
                                     GParamSpec      *pspec);
-static void gtk_action_set_action_group (GtkAction         *action,
+static void gtk_action_set_action_group (GtkAction     *action,
                                         GtkActionGroup *action_group);
+static void gtk_action_set_is_important (GtkAction     *action,
+                                        gboolean        is_important);
+static void gtk_action_set_label        (GtkAction     *action,
+                                        const gchar    *label);
+static void gtk_action_set_short_label  (GtkAction     *action,
+                                        const gchar    *label);
+static void gtk_action_set_visible_horizontal (GtkAction *action,
+                                              gboolean   visible_horizontal);
+static void gtk_action_set_visible_vertical   (GtkAction *action,
+                                              gboolean   visible_vertical);
+static void gtk_action_set_tooltip      (GtkAction     *action,
+                                        const gchar    *tooltip);
+static void gtk_action_set_stock_id     (GtkAction     *action,
+                                        const gchar    *stock_id);
+static void gtk_action_set_icon_name     (GtkAction    *action,
+                                        const gchar    *icon_name);
+static void gtk_action_sync_tooltip     (GtkAction      *action,
+                                        GtkWidget      *proxy);
 
 static GtkWidget *create_menu_item    (GtkAction *action);
 static GtkWidget *create_tool_item    (GtkAction *action);
-static void       connect_proxy       (GtkAction     *action,
-                                      GtkWidget     *proxy);
+static void       connect_proxy       (GtkAction *action,
+                                      GtkWidget *proxy);
 static void       disconnect_proxy    (GtkAction *action,
                                       GtkWidget *proxy);
+
 static void       closure_accel_activate (GClosure     *closure,
                                          GValue       *return_value,
                                          guint         n_param_values,
@@ -163,7 +168,6 @@ static void       closure_accel_activate (GClosure     *closure,
                                          gpointer      invocation_hint,
                                          gpointer      marshal_data);
 
-static GObjectClass *parent_class = NULL;
 static guint         action_signals[LAST_SIGNAL] = { 0 };
 
 
@@ -173,8 +177,8 @@ gtk_action_class_init (GtkActionClass *klass)
   GObjectClass *gobject_class;
 
   accel_path_id = g_quark_from_static_string (accel_path_key);
+  quark_gtk_action_proxy = g_quark_from_static_string (gtk_action_proxy_key);
 
-  parent_class = g_type_class_peek_parent (klass);
   gobject_class = G_OBJECT_CLASS (klass);
 
   gobject_class->finalize     = gtk_action_finalize;
@@ -185,6 +189,7 @@ gtk_action_class_init (GtkActionClass *klass)
 
   klass->create_menu_item = create_menu_item;
   klass->create_tool_item = create_tool_item;
+  klass->create_menu = NULL;
   klass->connect_proxy = connect_proxy;
   klass->disconnect_proxy = disconnect_proxy;
 
@@ -199,6 +204,14 @@ gtk_action_class_init (GtkActionClass *klass)
                                                        NULL,
                                                        GTK_PARAM_READWRITE | 
                                                        G_PARAM_CONSTRUCT_ONLY));
+
+  /**
+   * GtkAction:label:
+   *
+   * The label used for menu items and buttons that activate
+   * this action. If the label is %NULL, GTK+ uses the stock 
+   * label specified via the stock-id property.
+   */
   g_object_class_install_property (gobject_class,
                                   PROP_LABEL,
                                   g_param_spec_string ("label",
@@ -229,6 +242,23 @@ gtk_action_class_init (GtkActionClass *klass)
                                                           "this action."),
                                                        NULL,
                                                        GTK_PARAM_READWRITE));
+  /**
+   * GtkAction:icon-name:
+   *
+   * The name of the icon from the icon theme. 
+   * Note that the stock icon is preferred, if
+   * the ::stock-id property holds the id of an
+   * existing stock icon.
+   *
+   * Since: 2.10
+   */
+  g_object_class_install_property (gobject_class,
+                                  PROP_ICON_NAME,
+                                  g_param_spec_string ("icon-name",
+                                                       P_("Icon Name"),
+                                                       P_("The name of the icon from the icon theme"),
+                                                       NULL,
+                                                       GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_VISIBLE_HORIZONTAL,
                                   g_param_spec_boolean ("visible-horizontal",
@@ -329,6 +359,7 @@ gtk_action_init (GtkAction *action)
   action->private_data->short_label = NULL;
   action->private_data->tooltip = NULL;
   action->private_data->stock_id = NULL;
+  action->private_data->icon_name = NULL;
   action->private_data->visible_horizontal = TRUE;
   action->private_data->visible_vertical   = TRUE;
   action->private_data->visible_overflown  = TRUE;
@@ -356,12 +387,37 @@ gtk_action_init (GtkAction *action)
   action->private_data->proxies = NULL;
 }
 
+static void
+gtk_action_buildable_init (GtkBuildableIface *iface)
+{
+  iface->set_name = gtk_action_buildable_set_name;
+  iface->get_name = gtk_action_buildable_get_name;
+}
+
+static void
+gtk_action_buildable_set_name (GtkBuildable *buildable,
+                              const gchar  *name)
+{
+  GtkAction *action = GTK_ACTION (buildable);
+
+  action->private_data->name = g_intern_string (name);
+}
+
+static const gchar *
+gtk_action_buildable_get_name (GtkBuildable *buildable)
+{
+  GtkAction *action = GTK_ACTION (buildable);
+
+  return action->private_data->name;
+}
+
 /**
  * gtk_action_new:
  * @name: A unique name for the action
- * @label: the label displayed in menu items and on buttons
- * @tooltip: a tooltip for the action
- * @stock_id: the stock icon to display in widgets representing the action
+ * @label: the label displayed in menu items and on buttons, or %NULL
+ * @tooltip: a tooltip for the action, or %NULL
+ * @stock_id: the stock icon to display in widgets representing the
+ *   action, or %NULL
  *
  * Creates a new #GtkAction object. To add the action to a
  * #GtkActionGroup and set the accelerator for the action,
@@ -379,16 +435,14 @@ gtk_action_new (const gchar *name,
                const gchar *tooltip,
                const gchar *stock_id)
 {
-  GtkAction *action;
-
-  action = g_object_new (GTK_TYPE_ACTION,
-                        "name", name,
-                        "label", label,
-                        "tooltip", tooltip,
-                        "stock_id", stock_id,
-                        NULL);
-
-  return action;
+  g_return_val_if_fail (name != NULL, NULL);
+
+  return g_object_new (GTK_TYPE_ACTION,
+                       "name", name,
+                      "label", label,
+                      "tooltip", tooltip,
+                      "stock-id", stock_id,
+                      NULL);
 }
 
 static void
@@ -397,17 +451,17 @@ gtk_action_finalize (GObject *object)
   GtkAction *action;
   action = GTK_ACTION (object);
 
-  g_free (action->private_data->name);
   g_free (action->private_data->label);
   g_free (action->private_data->short_label);
   g_free (action->private_data->tooltip);
   g_free (action->private_data->stock_id);
+  g_free (action->private_data->icon_name);
 
   g_closure_unref (action->private_data->accel_closure);
   if (action->private_data->accel_group)
     g_object_unref (action->private_data->accel_group);
 
-  G_OBJECT_CLASS (parent_class)->finalize (object);  
+  G_OBJECT_CLASS (gtk_action_parent_class)->finalize (object);  
 }
 
 static void
@@ -417,99 +471,49 @@ gtk_action_set_property (GObject         *object,
                         GParamSpec      *pspec)
 {
   GtkAction *action;
-  gchar *tmp;
   
   action = GTK_ACTION (object);
 
   switch (prop_id)
     {
     case PROP_NAME:
-      tmp = action->private_data->name;
-      action->private_data->name = g_value_dup_string (value);
-      g_free (tmp);
+      action->private_data->name = g_intern_string (g_value_get_string (value));
       break;
     case PROP_LABEL:
-      tmp = action->private_data->label;
-      action->private_data->label = g_value_dup_string (value);
-      g_free (tmp);
-      action->private_data->label_set = (action->private_data->label != NULL);
-      /* if label is unset, then use the label from the stock item */
-      if (!action->private_data->label_set && action->private_data->stock_id)
-       {
-         GtkStockItem stock_item;
-
-         if (gtk_stock_lookup (action->private_data->stock_id, &stock_item))
-           action->private_data->label = g_strdup (stock_item.label);
-       }
-      /* if short_label is unset, set short_label=label */
-      if (!action->private_data->short_label_set)
-       {
-         tmp = action->private_data->short_label;
-         action->private_data->short_label = g_strdup (action->private_data->label);
-         g_free (tmp);
-         g_object_notify (object, "short-label");
-       }
+      gtk_action_set_label (action, g_value_get_string (value));
       break;
     case PROP_SHORT_LABEL:
-      tmp = action->private_data->short_label;
-      action->private_data->short_label = g_value_dup_string (value);
-      g_free (tmp);
-      action->private_data->short_label_set = (action->private_data->short_label != NULL);
-      /* if short_label is unset, then use the value of label */
-      if (!action->private_data->short_label_set)
-       {
-         action->private_data->short_label = g_strdup (action->private_data->label);
-       }
+      gtk_action_set_short_label (action, g_value_get_string (value));
       break;
     case PROP_TOOLTIP:
-      tmp = action->private_data->tooltip;
-      action->private_data->tooltip = g_value_dup_string (value);
-      g_free (tmp);
+      gtk_action_set_tooltip (action, g_value_get_string (value));
       break;
     case PROP_STOCK_ID:
-      tmp = action->private_data->stock_id;
-      action->private_data->stock_id = g_value_dup_string (value);
-      g_free (tmp);
-      /* update label and short_label if appropriate */
-      if (!action->private_data->label_set)
-       {
-         GtkStockItem stock_item;
-
-         g_free (action->private_data->label);
-         if (gtk_stock_lookup (action->private_data->stock_id, &stock_item))
-           action->private_data->label = g_strdup (stock_item.label);
-         else
-           action->private_data->label = NULL;
-         g_object_notify (object, "label");
-       }
-      if (!action->private_data->short_label_set)
-       {
-         tmp = action->private_data->short_label;
-         action->private_data->short_label = g_strdup (action->private_data->label);
-         g_free (tmp);
-         g_object_notify (object, "short-label");
-       }
+      gtk_action_set_stock_id (action, g_value_get_string (value));
+      break;
+    case PROP_ICON_NAME:
+      gtk_action_set_icon_name (action, g_value_get_string (value));
       break;
     case PROP_VISIBLE_HORIZONTAL:
-      action->private_data->visible_horizontal = g_value_get_boolean (value);
+      gtk_action_set_visible_horizontal (action, g_value_get_boolean (value));
       break;
     case PROP_VISIBLE_VERTICAL:
-      action->private_data->visible_vertical = g_value_get_boolean (value);
+      gtk_action_set_visible_vertical (action, g_value_get_boolean (value));
       break;
     case PROP_VISIBLE_OVERFLOWN:
       action->private_data->visible_overflown = g_value_get_boolean (value);
       break;
     case PROP_IS_IMPORTANT:
-      action->private_data->is_important = g_value_get_boolean (value);
+      gtk_action_set_is_important (action, g_value_get_boolean (value));
       break;
     case PROP_HIDE_IF_EMPTY:
       action->private_data->hide_if_empty = g_value_get_boolean (value);
       break;
     case PROP_SENSITIVE:
-      action->private_data->sensitive = g_value_get_boolean (value);
+      gtk_action_set_sensitive (action, g_value_get_boolean (value));
       break;
     case PROP_VISIBLE:
-      action->private_data->visible = g_value_get_boolean (value);
+      gtk_action_set_visible (action, g_value_get_boolean (value));
       break;
     case PROP_ACTION_GROUP:
       gtk_action_set_action_group (action, g_value_get_object (value));
@@ -533,7 +537,7 @@ gtk_action_get_property (GObject    *object,
   switch (prop_id)
     {
     case PROP_NAME:
-      g_value_set_string (value, action->private_data->name);
+      g_value_set_static_string (value, action->private_data->name);
       break;
     case PROP_LABEL:
       g_value_set_string (value, action->private_data->label);
@@ -547,6 +551,9 @@ gtk_action_get_property (GObject    *object,
     case PROP_STOCK_ID:
       g_value_set_string (value, action->private_data->stock_id);
       break;
+    case PROP_ICON_NAME:
+      g_value_set_string (value, action->private_data->icon_name);
+      break;
     case PROP_VISIBLE_HORIZONTAL:
       g_value_set_boolean (value, action->private_data->visible_horizontal);
       break;
@@ -598,40 +605,15 @@ create_tool_item (GtkAction *action)
 }
 
 static void
-remove_proxy (GtkWidget *proxy, 
-             GtkAction *action)
+remove_proxy (GtkAction *action,
+             GtkWidget *proxy)
 {
   if (GTK_IS_MENU_ITEM (proxy))
     gtk_action_disconnect_accelerator (action);
-
+  
   action->private_data->proxies = g_slist_remove (action->private_data->proxies, proxy);
 }
 
-static void
-gtk_action_sync_sensitivity (GtkAction  *action, 
-                            GParamSpec *pspec,
-                            GtkWidget  *proxy)
-{
-  gtk_widget_set_sensitive (proxy, gtk_action_is_sensitive (action));
-}
-
-static void
-gtk_action_sync_property (GtkAction  *action, 
-                         GParamSpec *pspec,
-                         GtkWidget  *proxy)
-{
-  const gchar *property;
-  GValue value = { 0, };
-
-  property = g_param_spec_get_name (pspec);
-
-  g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
-  g_object_get_property (G_OBJECT (action), property, &value);
-
-  g_object_set_property (G_OBJECT (proxy), property, &value);
-  g_value_unset (&value);
-}
-
 /**
  * _gtk_action_sync_menu_visible:
  * @action: a #GtkAction, or %NULL to determine the action from @proxy
@@ -659,9 +641,9 @@ _gtk_action_sync_menu_visible (GtkAction *action,
 
   g_return_if_fail (GTK_IS_MENU_ITEM (proxy));
   g_return_if_fail (action == NULL || GTK_IS_ACTION (action));
-  
+
   if (action == NULL)
-    action = g_object_get_data (G_OBJECT (proxy), "gtk-action");
+    action = g_object_get_qdata (G_OBJECT (proxy), quark_gtk_action_proxy);
 
   visible = gtk_action_is_visible (action);
   hide_if_empty = action->private_data->hide_if_empty;
@@ -674,101 +656,6 @@ _gtk_action_sync_menu_visible (GtkAction *action,
 
 gboolean _gtk_menu_is_empty (GtkWidget *menu);
 
-static void
-gtk_action_sync_visible (GtkAction  *action, 
-                        GParamSpec *pspec,
-                        GtkWidget  *proxy)
-{
-  if (GTK_IS_MENU_ITEM (proxy))
-    {
-      GtkWidget *menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (proxy));
-
-      _gtk_action_sync_menu_visible (action, proxy, _gtk_menu_is_empty (menu));
-    }
-  else
-    {
-      if (gtk_action_is_visible (action))
-       gtk_widget_show (proxy);
-      else
-       gtk_widget_hide (proxy);
-    }
-}
-
-static void
-gtk_action_sync_label (GtkAction  *action, 
-                      GParamSpec *pspec, 
-                      GtkWidget  *proxy)
-{
-  GtkWidget *label = NULL;
-
-  g_return_if_fail (GTK_IS_MENU_ITEM (proxy));
-  label = GTK_BIN (proxy)->child;
-
-  if (GTK_IS_LABEL (label))
-    gtk_label_set_label (GTK_LABEL (label), action->private_data->label);
-}
-
-static void
-gtk_action_sync_short_label (GtkAction  *action, 
-                            GParamSpec *pspec,
-                            GtkWidget  *proxy)
-{
-  GValue value = { 0, };
-
-  g_value_init (&value, G_TYPE_STRING);
-  g_object_get_property (G_OBJECT (action), "short-label", &value);
-
-  g_object_set_property (G_OBJECT (proxy), "label", &value);
-  g_value_unset (&value);
-}
-
-static void
-gtk_action_sync_stock_id (GtkAction  *action, 
-                         GParamSpec *pspec,
-                         GtkWidget  *proxy)
-{
-  GtkWidget *image = NULL;
-
-  if (GTK_IS_IMAGE_MENU_ITEM (proxy))
-    {
-      image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (proxy));
-
-      if (GTK_IS_IMAGE (image))
-       gtk_image_set_from_stock (GTK_IMAGE (image),
-                                 action->private_data->stock_id, GTK_ICON_SIZE_MENU);
-    }
-}
-
-static void
-gtk_action_sync_button_stock_id (GtkAction  *action, 
-                                GParamSpec *pspec,
-                                GtkWidget  *proxy)
-{
-  g_object_set (G_OBJECT (proxy),
-                "label",
-                action->private_data->stock_id,
-                NULL);
-}
-
-static void
-gtk_action_sync_tooltip (GtkAction  *action, 
-                        GParamSpec *pspec, 
-                        GtkWidget  *proxy)
-{
-  g_return_if_fail (GTK_IS_TOOL_ITEM (proxy));
-
-  if (GTK_IS_TOOLBAR (gtk_widget_get_parent (proxy)))
-    {
-      GtkToolbar *toolbar = GTK_TOOLBAR (gtk_widget_get_parent (proxy));
-      
-      gtk_tool_item_set_tooltip (GTK_TOOL_ITEM (proxy), 
-                                toolbar->tooltips,
-                                action->private_data->tooltip,
-                                NULL);
-    }
-}
-
-
 static gboolean
 gtk_action_create_menu_proxy (GtkToolItem *tool_item, 
                              GtkAction   *action)
@@ -797,20 +684,14 @@ connect_proxy (GtkAction     *action,
               GtkWidget     *proxy)
 {
   g_object_ref (action);
-  g_object_set_data_full (G_OBJECT (proxy), I_("gtk-action"), action,
-                         g_object_unref);
+  g_object_set_qdata_full (G_OBJECT (proxy), quark_gtk_action_proxy, action,
+                          g_object_unref);
 
   /* add this widget to the list of proxies */
   action->private_data->proxies = g_slist_prepend (action->private_data->proxies, proxy);
-  g_signal_connect (proxy, "destroy",
-                   G_CALLBACK (remove_proxy), action);
-
-  g_signal_connect_object (action, "notify::sensitive",
-                          G_CALLBACK (gtk_action_sync_sensitivity), proxy, 0);
+  g_object_weak_ref (G_OBJECT (proxy), (GWeakNotify)remove_proxy, action);
+  
   gtk_widget_set_sensitive (proxy, gtk_action_is_sensitive (action));
-
-  g_signal_connect_object (action, "notify::visible",
-                          G_CALLBACK (gtk_action_sync_visible), proxy, 0);
   if (gtk_action_is_visible (action))
     gtk_widget_show (proxy);
   else
@@ -840,7 +721,7 @@ connect_proxy (GtkAction     *action,
 
       if (!label)
        label = g_object_new (GTK_TYPE_ACCEL_LABEL,
-                             "use_underline", TRUE,
+                             "use-underline", TRUE,
                              "xalign", 0.0,
                              "visible", TRUE,
                              "parent", proxy,
@@ -848,12 +729,10 @@ connect_proxy (GtkAction     *action,
       
       if (GTK_IS_ACCEL_LABEL (label) && action->private_data->accel_quark)
        g_object_set (label,
-                     "accel_closure", action->private_data->accel_closure,
+                     "accel-closure", action->private_data->accel_closure,
                      NULL);
 
       gtk_label_set_label (GTK_LABEL (label), action->private_data->label);
-      g_signal_connect_object (action, "notify::label",
-                              G_CALLBACK (gtk_action_sync_label), proxy, 0);
 
       if (GTK_IS_IMAGE_MENU_ITEM (proxy))
        {
@@ -867,19 +746,21 @@ connect_proxy (GtkAction     *action,
            }
          if (!image)
            {
-             image = gtk_image_new_from_stock (NULL,
-                                               GTK_ICON_SIZE_MENU);
+             image = gtk_image_new ();
              gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (proxy),
                                             image);
              gtk_widget_show (image);
            }
-         gtk_image_set_from_stock (GTK_IMAGE (image),
-                                   action->private_data->stock_id, GTK_ICON_SIZE_MENU);
-         g_signal_connect_object (action, "notify::stock-id",
-                                  G_CALLBACK (gtk_action_sync_stock_id),
-                                  proxy, 0);
+         
+         if (action->private_data->stock_id &&
+             gtk_icon_factory_lookup_default (action->private_data->stock_id))
+           gtk_image_set_from_stock (GTK_IMAGE (image),
+                                     action->private_data->stock_id, GTK_ICON_SIZE_MENU);
+         else if (action->private_data->icon_name)
+           gtk_image_set_from_icon_name (GTK_IMAGE (image),
+                                         action->private_data->icon_name, GTK_ICON_SIZE_MENU);
        }
-
+      
       if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (proxy)) == NULL)
        g_signal_connect_object (proxy, "activate",
                                 G_CALLBACK (gtk_action_activate), action,
@@ -888,58 +769,39 @@ connect_proxy (GtkAction     *action,
     }
   else if (GTK_IS_TOOL_ITEM (proxy))
     {
-      GParamSpec *pspec;
-
-      /* toolbar item specific synchronisers ... */
-
-      g_object_set (proxy,
-                   "visible_horizontal", action->private_data->visible_horizontal,
-                   "visible_vertical",   action->private_data->visible_vertical,
-                   "is_important", action->private_data->is_important,
-                   NULL);
-
-      pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (action),
-                                            "tooltip");
-      gtk_action_sync_tooltip (action, pspec, proxy);
-
-      g_signal_connect_object (action, "notify::visible-horizontal",
-                              G_CALLBACK (gtk_action_sync_property), 
-                              proxy, 0);
-      g_signal_connect_object (action, "notify::visible-vertical",
-                              G_CALLBACK (gtk_action_sync_property), 
-                              proxy, 0);
-      g_signal_connect_object (action, "notify::is-important",
-                              G_CALLBACK (gtk_action_sync_property), 
-                              proxy, 0);
-      g_signal_connect_object (action, "notify::tooltip",
-                              G_CALLBACK (gtk_action_sync_tooltip), 
-                              proxy, 0);
-
-      g_signal_connect_object (proxy, "create_menu_proxy",
-                              G_CALLBACK (gtk_action_create_menu_proxy),
-                              action, 0);
-
-      gtk_tool_item_rebuild_menu (GTK_TOOL_ITEM (proxy));
-
       /* toolbar button specific synchronisers ... */
       if (GTK_IS_TOOL_BUTTON (proxy))
        {
          g_object_set (proxy,
+                       "visible-horizontal", action->private_data->visible_horizontal,
+                       "visible-vertical", action->private_data->visible_vertical,
+                       "is-important", action->private_data->is_important,
                        "label", action->private_data->short_label,
-                       "use_underline", TRUE,
-                       "stock_id", action->private_data->stock_id,
+                       "use-underline", TRUE,
+                       "stock-id", action->private_data->stock_id,
+                       "icon-name", action->private_data->icon_name,
                        NULL);
 
-         g_signal_connect_object (action, "notify::short-label",
-                                  G_CALLBACK (gtk_action_sync_short_label),
-                                  proxy, 0);      
-         g_signal_connect_object (action, "notify::stock-id",
-                                  G_CALLBACK (gtk_action_sync_property), 
-                                  proxy, 0);
          g_signal_connect_object (proxy, "clicked",
                                   G_CALLBACK (gtk_action_activate), action,
                                   G_CONNECT_SWAPPED);
-       }
+        }
+      else 
+        {
+           g_object_set (proxy,
+                        "visible-horizontal", action->private_data->visible_horizontal,
+                        "visible-vertical", action->private_data->visible_vertical,
+                        "is-important", action->private_data->is_important,
+                        NULL);
+       }
+
+      gtk_action_sync_tooltip (action, proxy);
+
+      g_signal_connect_object (proxy, "create_menu_proxy",
+                              G_CALLBACK (gtk_action_create_menu_proxy),
+                              action, 0);
+
+      gtk_tool_item_rebuild_menu (GTK_TOOL_ITEM (proxy));
     }
   else if (GTK_IS_BUTTON (proxy))
     {
@@ -950,24 +812,19 @@ connect_proxy (GtkAction     *action,
          g_object_set (proxy,
                        "label", action->private_data->stock_id,
                        NULL);
-         g_signal_connect_object (action, "notify::stock-id",
-                                  G_CALLBACK (gtk_action_sync_button_stock_id),
-                                  proxy, 0);
        }
-      else if (GTK_BIN (proxy)->child == NULL || 
-              GTK_IS_LABEL (GTK_BIN (proxy)->child))
+      else 
        {
-         /* synchronise the label */
-         g_object_set (proxy,
-                       "label", action->private_data->short_label,
-                       "use_underline", TRUE,
-                       NULL);
-         g_signal_connect_object (action, "notify::short-label",
-                                  G_CALLBACK (gtk_action_sync_short_label),
-                                  proxy, 0);
-         
+         if (GTK_BIN (proxy)->child == NULL || 
+             GTK_IS_LABEL (GTK_BIN (proxy)->child))
+           {
+             /* synchronise the label */
+             g_object_set (proxy,
+                           "label", action->private_data->short_label,
+                           "use-underline", TRUE,
+                           NULL);
+           }
        }
-      
       /* we leave the button alone if there is a custom child */
       g_signal_connect_object (proxy, "clicked",
                               G_CALLBACK (gtk_action_activate), action,
@@ -982,43 +839,17 @@ static void
 disconnect_proxy (GtkAction *action, 
                  GtkWidget *proxy)
 {
-  g_object_set_data (G_OBJECT (proxy), I_("gtk-action"), NULL);
+  g_object_set_qdata (G_OBJECT (proxy), quark_gtk_action_proxy, NULL);
 
-  /* remove proxy from list of proxies */
-  g_signal_handlers_disconnect_by_func (proxy,
-                                       G_CALLBACK (remove_proxy),
-                                       action);
-  remove_proxy (proxy, action);
+  g_object_weak_unref (G_OBJECT (proxy), (GWeakNotify)remove_proxy, action);
+  remove_proxy (action, proxy);
 
   /* disconnect the activate handler */
   g_signal_handlers_disconnect_by_func (proxy,
                                        G_CALLBACK (gtk_action_activate),
                                        action);
 
-  /* disconnect handlers for notify::* signals */
-  g_signal_handlers_disconnect_by_func (action,
-                                       G_CALLBACK (gtk_action_sync_sensitivity),
-                                       proxy);
-  g_signal_handlers_disconnect_by_func (action,
-                                       G_CALLBACK (gtk_action_sync_visible),
-                                       proxy);
-  g_signal_handlers_disconnect_by_func (action,
-                                       G_CALLBACK (gtk_action_sync_property),
-                                       proxy);
-
-  g_signal_handlers_disconnect_by_func (action,
-                               G_CALLBACK (gtk_action_sync_stock_id), proxy);
-
-  /* menu item specific synchronisers ... */
-  g_signal_handlers_disconnect_by_func (action,
-                                       G_CALLBACK (gtk_action_sync_label),
-                                       proxy);
-  
   /* toolbar button specific synchronisers ... */
-  g_signal_handlers_disconnect_by_func (action,
-                                       G_CALLBACK (gtk_action_sync_short_label),
-                                       proxy);
-
   g_signal_handlers_disconnect_by_func (proxy,
                                        G_CALLBACK (gtk_action_create_menu_proxy),
                                        action);
@@ -1087,6 +918,8 @@ gtk_action_create_icon (GtkAction *action, GtkIconSize icon_size)
 
   if (action->private_data->stock_id)
     return gtk_image_new_from_stock (action->private_data->stock_id, icon_size);
+  else if (action->private_data->icon_name)
+    return gtk_image_new_from_icon_name (action->private_data->icon_name, icon_size);
   else
     return NULL;
 }
@@ -1163,7 +996,7 @@ gtk_action_connect_proxy (GtkAction *action,
   g_return_if_fail (GTK_IS_ACTION (action));
   g_return_if_fail (GTK_IS_WIDGET (proxy));
 
-  prev_action = g_object_get_data (G_OBJECT (proxy), "gtk-action");
+  prev_action = g_object_get_qdata (G_OBJECT (proxy), quark_gtk_action_proxy);
 
   if (prev_action)
     (* GTK_ACTION_GET_CLASS (action)->disconnect_proxy) (prev_action, proxy);  
@@ -1188,7 +1021,7 @@ gtk_action_disconnect_proxy (GtkAction *action,
   g_return_if_fail (GTK_IS_ACTION (action));
   g_return_if_fail (GTK_IS_WIDGET (proxy));
 
-  g_return_if_fail (g_object_get_data (G_OBJECT (proxy), "gtk-action") == action);
+  g_return_if_fail (g_object_get_qdata (G_OBJECT (proxy), quark_gtk_action_proxy) == action);
 
   (* GTK_ACTION_GET_CLASS (action)->disconnect_proxy) (action, proxy);  
 }
@@ -1198,9 +1031,10 @@ gtk_action_disconnect_proxy (GtkAction *action,
  * @action: the action object
  * 
  * Returns the proxy widgets for an action.
+ * See also gtk_widget_get_action().
  * 
- * Return value: a #GSList of proxy widgets. The list is owned by the action and
- * must not be modified.
+ * Return value: a #GSList of proxy widgets. The list is owned by GTK+
+ * and must not be modified.
  *
  * Since: 2.4
  **/
@@ -1213,6 +1047,27 @@ gtk_action_get_proxies (GtkAction *action)
 }
 
 
+/**
+ * gtk_widget_get_action:
+ * @widget: a #GtkWidget
+ *
+ * Returns the #GtkAction that @widget is a proxy for. 
+ * See also gtk_action_get_proxies().
+ *
+ * Returns: the action that a widget is a proxy for, or
+ *  %NULL, if it is not attached to an action.
+ *
+ * Since: 2.10
+ */
+GtkAction*
+gtk_widget_get_action (GtkWidget *widget)
+{
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+  
+  return g_object_get_qdata (G_OBJECT (widget), quark_gtk_action_proxy);
+}
+
+
 /**
  * gtk_action_get_name:
  * @action: the action object
@@ -1275,6 +1130,22 @@ gtk_action_get_sensitive (GtkAction *action)
   return action->private_data->sensitive;
 }
 
+void
+_gtk_action_sync_sensitive (GtkAction *action)
+{
+  GSList *p;
+  GtkWidget *proxy;
+  gboolean sensitive;
+
+  sensitive = gtk_action_is_sensitive (action);
+
+  for (p = action->private_data->proxies; p; p = p->next)
+    {
+      proxy = (GtkWidget *)p->data;
+      gtk_widget_set_sensitive (proxy, sensitive);
+    }      
+}
+
 /**
  * gtk_action_set_sensitive:
  * @action: the action object
@@ -1299,6 +1170,8 @@ gtk_action_set_sensitive (GtkAction *action,
     {
       action->private_data->sensitive = sensitive;
 
+      _gtk_action_sync_sensitive (action);
+
       g_object_notify (G_OBJECT (action), "sensitive");
     }
 }
@@ -1346,6 +1219,36 @@ gtk_action_get_visible (GtkAction *action)
   return action->private_data->visible;
 }
 
+void
+_gtk_action_sync_visible (GtkAction *action)
+{
+  GSList *p;
+  GtkWidget *proxy;
+  GtkWidget *menu;
+  gboolean visible;
+
+  visible = gtk_action_is_visible (action);
+    
+  for (p = action->private_data->proxies; p; p = p->next)
+    {
+      proxy = (GtkWidget *)p->data;
+
+      if (GTK_IS_MENU_ITEM (proxy))
+       {
+         menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (proxy));
+         
+         _gtk_action_sync_menu_visible (action, proxy, _gtk_menu_is_empty (menu));
+       }
+      else
+       {
+         if (visible)
+           gtk_widget_show (proxy);
+         else
+           gtk_widget_hide (proxy);
+       }
+    } 
+}
+
 /**
  * gtk_action_set_visible:
  * @action: the action object
@@ -1370,10 +1273,305 @@ gtk_action_set_visible (GtkAction *action,
     {
       action->private_data->visible = visible;
 
+      _gtk_action_sync_visible (action);
+
       g_object_notify (G_OBJECT (action), "visible");
     }
 }
 
+static void 
+gtk_action_set_is_important (GtkAction *action,
+                            gboolean   is_important)
+{
+  GSList *p;
+  GtkWidget *proxy;
+
+  is_important = is_important != FALSE;
+  
+  if (action->private_data->is_important != is_important)
+    {
+      action->private_data->is_important = is_important;
+
+      for (p = action->private_data->proxies; p; p = p->next)
+       {
+         proxy = (GtkWidget *)p->data;
+
+         if (GTK_IS_TOOL_ITEM (proxy))
+           gtk_tool_item_set_is_important (GTK_TOOL_ITEM (proxy),
+                                           is_important);
+       }
+      
+      g_object_notify (G_OBJECT (action), "is-important");
+    }  
+}
+
+static void 
+gtk_action_set_label (GtkAction          *action,
+                     const gchar *label)
+{
+  GSList *p;
+  GtkWidget *proxy, *child;
+  gchar *tmp;
+  
+  tmp = action->private_data->label;
+  action->private_data->label = g_strdup (label);
+  g_free (tmp);
+  action->private_data->label_set = (action->private_data->label != NULL);
+  /* if label is unset, then use the label from the stock item */
+  if (!action->private_data->label_set && action->private_data->stock_id)
+    {
+      GtkStockItem stock_item;
+      
+      if (gtk_stock_lookup (action->private_data->stock_id, &stock_item))
+       action->private_data->label = g_strdup (stock_item.label);
+    }
+  
+  for (p = action->private_data->proxies; p; p = p->next)
+    {
+      proxy = (GtkWidget *)p->data;
+      
+      if (GTK_IS_MENU_ITEM (proxy))
+       {
+         child = GTK_BIN (proxy)->child;
+         
+         if (GTK_IS_LABEL (child))
+           gtk_label_set_label (GTK_LABEL (child), 
+                                action->private_data->label);
+       }
+    }
+  
+  g_object_notify (G_OBJECT (action), "label");
+  
+  /* if short_label is unset, set short_label=label */
+  if (!action->private_data->short_label_set)
+    {
+      gtk_action_set_short_label (action, action->private_data->label);
+      action->private_data->short_label_set = FALSE;
+    }
+}
+
+static void 
+gtk_action_set_short_label (GtkAction  *action,
+                           const gchar *label)
+{
+  GSList *p;
+  GtkWidget *proxy, *child;
+  gchar *tmp;
+
+  tmp = action->private_data->short_label;
+  action->private_data->short_label = g_strdup (label);
+  g_free (tmp);
+  action->private_data->short_label_set = (action->private_data->short_label != NULL);
+  /* if short_label is unset, then use the value of label */
+  if (!action->private_data->short_label_set)
+    action->private_data->short_label = g_strdup (action->private_data->label);
+
+  for (p = action->private_data->proxies; p; p = p->next)
+    {
+      proxy = (GtkWidget *)p->data;
+
+      if (GTK_IS_TOOL_BUTTON (proxy))
+       gtk_tool_button_set_label (GTK_TOOL_BUTTON (proxy), 
+                                  action->private_data->short_label);
+      else if (GTK_IS_BUTTON (proxy) &&
+              !gtk_button_get_use_stock (GTK_BUTTON (proxy)))
+       {
+         child = GTK_BIN (proxy)->child;
+         
+         if (child == NULL || GTK_IS_LABEL (child))
+           gtk_button_set_label (GTK_BUTTON (proxy), 
+                                 action->private_data->short_label);
+       }
+    }
+
+  g_object_notify (G_OBJECT (action), "short-label");
+}
+
+static void 
+gtk_action_set_visible_horizontal (GtkAction *action,
+                                  gboolean   visible_horizontal)
+{
+  GSList *p;
+  GtkWidget *proxy;
+
+  visible_horizontal = visible_horizontal != FALSE;
+  
+  if (action->private_data->visible_horizontal != visible_horizontal)
+    {
+      action->private_data->visible_horizontal = visible_horizontal;
+
+      for (p = action->private_data->proxies; p; p = p->next)
+       {
+         proxy = (GtkWidget *)p->data;
+
+         if (GTK_IS_TOOL_ITEM (proxy))
+           gtk_tool_item_set_visible_horizontal (GTK_TOOL_ITEM (proxy),
+                                                 visible_horizontal);
+       }
+      
+      g_object_notify (G_OBJECT (action), "visible-horizontal");
+    }  
+}
+
+static void 
+gtk_action_set_visible_vertical (GtkAction *action,
+                                gboolean   visible_vertical)
+{
+  GSList *p;
+  GtkWidget *proxy;
+
+  visible_vertical = visible_vertical != FALSE;
+  
+  if (action->private_data->visible_vertical != visible_vertical)
+    {
+      action->private_data->visible_vertical = visible_vertical;
+
+      for (p = action->private_data->proxies; p; p = p->next)
+       {
+         proxy = (GtkWidget *)p->data;
+
+         if (GTK_IS_TOOL_ITEM (proxy))
+           gtk_tool_item_set_visible_vertical (GTK_TOOL_ITEM (proxy),
+                                               visible_vertical);
+       }
+      
+      g_object_notify (G_OBJECT (action), "visible-vertical");
+    }  
+}
+
+static void 
+gtk_action_sync_tooltip (GtkAction *action,
+                        GtkWidget *proxy)
+{
+  gtk_tool_item_set_tooltip_text (GTK_TOOL_ITEM (proxy),
+                                 action->private_data->tooltip);
+}
+
+static void 
+gtk_action_set_tooltip (GtkAction   *action,
+                       const gchar *tooltip)
+{
+  GSList *p;
+  GtkWidget *proxy;
+  gchar *tmp;
+
+  tmp = action->private_data->tooltip;
+  action->private_data->tooltip = g_strdup (tooltip);
+  g_free (tmp);
+
+  for (p = action->private_data->proxies; p; p = p->next)
+    {
+      proxy = (GtkWidget *)p->data;
+
+      if (GTK_IS_TOOL_ITEM (proxy))
+        gtk_action_sync_tooltip (action, proxy);
+    }
+
+  g_object_notify (G_OBJECT (action), "tooltip");
+}
+
+static void 
+gtk_action_set_stock_id (GtkAction   *action,
+                        const gchar *stock_id)
+{
+  GSList *p;
+  GtkWidget *proxy, *image;
+  gchar *tmp;
+  
+  tmp = action->private_data->stock_id;
+  action->private_data->stock_id = g_strdup (stock_id);
+  g_free (tmp);
+
+  for (p = action->private_data->proxies; p; p = p->next)
+    {
+      proxy = (GtkWidget *)p->data;
+      
+      if (GTK_IS_IMAGE_MENU_ITEM (proxy))
+       {
+         image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (proxy));
+         
+         if (GTK_IS_IMAGE (image))
+           gtk_image_set_from_stock (GTK_IMAGE (image),
+                                     action->private_data->stock_id, GTK_ICON_SIZE_MENU);
+       } 
+      else if (GTK_IS_TOOL_BUTTON (proxy))
+       {
+         gtk_tool_button_set_stock_id (GTK_TOOL_BUTTON (proxy),
+                                       action->private_data->stock_id);
+       }
+      else if (GTK_IS_BUTTON (proxy) &&
+              gtk_button_get_use_stock (GTK_BUTTON (proxy)))
+       {
+         gtk_button_set_label (GTK_BUTTON (proxy),
+                               action->private_data->stock_id);
+       }
+    }
+
+  g_object_notify (G_OBJECT (action), "stock-id");
+  
+  /* update label and short_label if appropriate */
+  if (!action->private_data->label_set)
+    {
+      GtkStockItem stock_item;
+      
+      if (action->private_data->stock_id &&
+         gtk_stock_lookup (action->private_data->stock_id, &stock_item))
+       gtk_action_set_label (action, stock_item.label);
+      else 
+       gtk_action_set_label (action, NULL);
+      
+      action->private_data->label_set = FALSE;
+    }
+}
+
+static void 
+gtk_action_set_icon_name (GtkAction   *action,
+                         const gchar *icon_name)
+{
+  GSList *p;
+  GtkWidget *proxy, *image;
+  gchar *tmp;
+  
+  tmp = action->private_data->icon_name;
+  action->private_data->icon_name = g_strdup (icon_name);
+  g_free (tmp);
+
+  for (p = action->private_data->proxies; p; p = p->next)
+    {
+      proxy = (GtkWidget *)p->data;
+      
+      if (GTK_IS_IMAGE_MENU_ITEM (proxy))
+       {
+         image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (proxy));
+         
+         if (GTK_IS_IMAGE (image) &&
+             (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_EMPTY ||
+              gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_ICON_NAME))
+           gtk_image_set_from_icon_name (GTK_IMAGE (image),
+                                         action->private_data->icon_name, GTK_ICON_SIZE_MENU);
+       } 
+      else if (GTK_IS_TOOL_BUTTON (proxy))
+       {
+         gtk_tool_button_set_icon_name (GTK_TOOL_BUTTON (proxy),
+                                        action->private_data->icon_name);
+       }
+      else if (GTK_IS_BUTTON (proxy) &&
+              !gtk_button_get_use_stock (GTK_BUTTON (proxy)))
+       {
+         image = gtk_button_get_image (GTK_BUTTON (proxy));
+         
+         if (GTK_IS_IMAGE (image) &&
+             (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_EMPTY ||
+              gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_ICON_NAME))
+           gtk_image_set_from_icon_name (GTK_IMAGE (image),
+                                         action->private_data->icon_name, GTK_ICON_SIZE_MENU);
+       }
+    }
+  
+  g_object_notify (G_OBJECT (action), "icon-name");
+}
+
+
 /**
  * gtk_action_block_activate_from:
  * @action: the action object
@@ -1600,5 +1798,28 @@ gtk_action_disconnect_accelerator (GtkAction *action)
                                action->private_data->accel_closure);
 }
 
+/**
+ * gtk_action_create_menu:
+ * @action: a #GtkAction
+ *
+ * If @action provides a #GtkMenu widget as a submenu for the menu
+ * item or the toolbar item it creates, this function returns an
+ * instance of that menu.
+ *
+ * Return value: the menu item provided by the action, or %NULL.
+ *
+ * Since: 2.12
+ */
+GtkWidget *
+gtk_action_create_menu (GtkAction *action)
+{
+  g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
+
+  if (GTK_ACTION_GET_CLASS (action)->create_menu)
+    return GTK_ACTION_GET_CLASS (action)->create_menu (action);
+
+  return NULL;
+}
+
 #define __GTK_ACTION_C__
 #include "gtkaliasdef.c"