]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkaction.c
Fix the GtkBuildable implementation to allow setting column types.
[~andy/gtk] / gtk / gtkaction.c
index 50bc3c4f0f39903476f9b351b289e7e4727a6e3a..99bfcb96d60ee249a1ebf004ed6cd4c8c8dcde5e 100644 (file)
 #include <config.h>
 
 #include "gtkaction.h"
+#include "gtkactiongroup.h"
 #include "gtkaccellabel.h"
 #include "gtkbutton.h"
+#include "gtkiconfactory.h"
 #include "gtkimage.h"
 #include "gtkimagemenuitem.h"
 #include "gtkintl.h"
 #include "gtkmarshalers.h"
 #include "gtkmenuitem.h"
 #include "gtkstock.h"
+#include "gtktearoffmenuitem.h"
 #include "gtktoolbutton.h"
 #include "gtktoolbar.h"
+#include "gtkprivate.h"
+#include "gtkbuildable.h"
+#include "gtkalias.h"
 
 
 #define GTK_ACTION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ACTION, GtkActionPrivate))
 
 struct _GtkActionPrivate 
 {
-  gchar *name;
+  const gchar *name; /* interned */
   gchar *label;
   gchar *short_label;
   gchar *tooltip;
-  gchar *stock_id; /* icon */
-
-  guint sensitive       : 1;
-  guint visible         : 1;
-  guint label_set       : 1; /* these two used so we can set label */
-  guint short_label_set : 1; /* based on stock id */
-  guint is_important    : 1;
+  gchar *stock_id; /* stock icon */
+  gchar *icon_name; /* themed icon */
+
+  guint sensitive          : 1;
+  guint visible            : 1;
+  guint label_set          : 1; /* these two used so we can set label */
+  guint short_label_set    : 1; /* based on stock id */
+  guint visible_horizontal : 1;
+  guint visible_vertical   : 1;
+  guint is_important       : 1;
+  guint hide_if_empty      : 1;
+  guint visible_overflown  : 1;
 
   /* accelerator */
   guint          accel_count;
@@ -66,14 +77,14 @@ struct _GtkActionPrivate
   GClosure      *accel_closure;
   GQuark         accel_quark;
 
+  GtkActionGroup *action_group;
+
   /* list of proxy widgets */
   GSList *proxies;
 };
 
 enum 
 {
-  CONNECT_PROXY,
-  DISCONNECT_PROXY,
   ACTIVATE,
   LAST_SIGNAL
 };
@@ -86,44 +97,32 @@ enum
   PROP_SHORT_LABEL,
   PROP_TOOLTIP,
   PROP_STOCK_ID,
+  PROP_ICON_NAME,
+  PROP_VISIBLE_HORIZONTAL,
+  PROP_VISIBLE_VERTICAL,
+  PROP_VISIBLE_OVERFLOWN,
   PROP_IS_IMPORTANT,
+  PROP_HIDE_IF_EMPTY,
   PROP_SENSITIVE,
   PROP_VISIBLE,
+  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,
-                                    "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,
@@ -134,13 +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,
+                                        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,
@@ -148,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 };
 
 
@@ -158,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;
@@ -170,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;
 
@@ -179,61 +199,135 @@ gtk_action_class_init (GtkActionClass *klass)
   g_object_class_install_property (gobject_class,
                                   PROP_NAME,
                                   g_param_spec_string ("name",
-                                                       _("Name"),
-                                                       _("A unique name for the action."),
+                                                       P_("Name"),
+                                                       P_("A unique name for the action."),
                                                        NULL,
-                                                       G_PARAM_READWRITE |
+                                                       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",
-                                                       _("Label"),
-                                                       _("The label used for menu items and buttons that activate this action."),
+                                                       P_("Label"),
+                                                       P_("The label used for menu items and buttons "
+                                                          "that activate this action."),
                                                        NULL,
-                                                       G_PARAM_READWRITE));
+                                                       GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_SHORT_LABEL,
-                                  g_param_spec_string ("short_label",
-                                                       _("Short label"),
-                                                       _("A shorter label that may be used on toolbar buttons."),
+                                  g_param_spec_string ("short-label",
+                                                       P_("Short label"),
+                                                       P_("A shorter label that may be used on toolbar buttons."),
                                                        NULL,
-                                                       G_PARAM_READWRITE));
+                                                       GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_TOOLTIP,
                                   g_param_spec_string ("tooltip",
-                                                       _("Tooltip"),
-                                                       _("A tooltip for this action."),
+                                                       P_("Tooltip"),
+                                                       P_("A tooltip for this action."),
                                                        NULL,
-                                                       G_PARAM_READWRITE));
+                                                       GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_STOCK_ID,
-                                  g_param_spec_string ("stock_id",
-                                                       _("Stock Icon"),
-                                                       _("The stock icon displayed in widgets representing this action."),
+                                  g_param_spec_string ("stock-id",
+                                                       P_("Stock Icon"),
+                                                       P_("The stock icon displayed in widgets representing "
+                                                          "this action."),
                                                        NULL,
-                                                       G_PARAM_READWRITE));
+                                                       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",
+                                                        P_("Visible when horizontal"),
+                                                        P_("Whether the toolbar item is visible when the toolbar "
+                                                           "is in a horizontal orientation."),
+                                                        TRUE,
+                                                        GTK_PARAM_READWRITE));
+  /**
+   * GtkAction:visible-overflown:
+   *
+   * When %TRUE, toolitem proxies for this action are represented in the 
+   * toolbar overflow menu.
+   *
+   * Since: 2.6
+   */
+  g_object_class_install_property (gobject_class,
+                                  PROP_VISIBLE_OVERFLOWN,
+                                  g_param_spec_boolean ("visible-overflown",
+                                                        P_("Visible when overflown"),
+                                                        P_("When TRUE, toolitem proxies for this action "
+                                                           "are represented in the toolbar overflow menu."),
+                                                        TRUE,
+                                                        GTK_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class,
+                                  PROP_VISIBLE_VERTICAL,
+                                  g_param_spec_boolean ("visible-vertical",
+                                                        P_("Visible when vertical"),
+                                                        P_("Whether the toolbar item is visible when the toolbar "
+                                                           "is in a vertical orientation."),
+                                                        TRUE,
+                                                        GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_IS_IMPORTANT,
-                                  g_param_spec_boolean ("is_important",
-                                                        _("Is important"),
-                                                        _("Whether the action is considered important. When TRUE, toolitem proxies for this action show text in GTK_TOOLBAR_BOTH_HORIZ mode"),
+                                  g_param_spec_boolean ("is-important",
+                                                        P_("Is important"),
+                                                        P_("Whether the action is considered important. "
+                                                           "When TRUE, toolitem proxies for this action "
+                                                           "show text in GTK_TOOLBAR_BOTH_HORIZ mode."),
                                                         FALSE,
-                                                        G_PARAM_READWRITE));
+                                                        GTK_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class,
+                                  PROP_HIDE_IF_EMPTY,
+                                  g_param_spec_boolean ("hide-if-empty",
+                                                        P_("Hide if empty"),
+                                                        P_("When TRUE, empty menu proxies for this action are hidden."),
+                                                        TRUE,
+                                                        GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_SENSITIVE,
                                   g_param_spec_boolean ("sensitive",
-                                                        _("Sensitive"),
-                                                        _("Whether the action is enabled."),
+                                                        P_("Sensitive"),
+                                                        P_("Whether the action is enabled."),
                                                         TRUE,
-                                                        G_PARAM_READWRITE));
+                                                        GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
                                   PROP_VISIBLE,
                                   g_param_spec_boolean ("visible",
-                                                        _("Visible"),
-                                                        _("Whether the action is visible."),
+                                                        P_("Visible"),
+                                                        P_("Whether the action is visible."),
                                                         TRUE,
-                                                        G_PARAM_READWRITE));
-
+                                                        GTK_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class,
+                                  PROP_ACTION_GROUP,
+                                  g_param_spec_object ("action-group",
+                                                        P_("Action Group"),
+                                                        P_("The GtkActionGroup this GtkAction is associated with, or NULL (for internal use)."),
+                                                        GTK_TYPE_ACTION_GROUP,
+                                                        GTK_PARAM_READWRITE));
 
   /**
    * GtkAction::activate:
@@ -244,54 +338,13 @@ gtk_action_class_init (GtkActionClass *klass)
    * Since: 2.4
    */
   action_signals[ACTIVATE] =
-    g_signal_new ("activate",
+    g_signal_new (I_("activate"),
                  G_OBJECT_CLASS_TYPE (klass),
                  G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE,
                  G_STRUCT_OFFSET (GtkActionClass, activate),  NULL, NULL,
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);
 
-  /**
-   * GtkAction::connect-proxy:
-   * @action: the action
-   * @proxy: the proxy
-   *
-   * The connect_proxy signal is emitted after connecting a proxy to 
-   * an action. Note that the proxy may have been connected to a different
-   * action before.
-   *
-   * This is intended for simple customizations for which a custom action
-   * class would be too clumsy, e.g. showing tooltips for menuitems in the
-   * statusbar.
-   *
-   * Since: 2.4
-   */
-  action_signals[CONNECT_PROXY] =
-    g_signal_new ("connect_proxy",
-                 G_OBJECT_CLASS_TYPE (klass),
-                 0, 0, NULL, NULL,
-                 _gtk_marshal_VOID__OBJECT,
-                 G_TYPE_NONE, 1, 
-                 GTK_TYPE_WIDGET);
-
-  /**
-   * GtkAction::disconnect-proxy:
-   * @action: the action
-   * @proxy: the proxy
-   *
-   * The disconnect_proxy signal is emitted after disconnecting a proxy 
-   * from an action. 
-   *
-   * Since: 2.4
-   */
-  action_signals[DISCONNECT_PROXY] =
-    g_signal_new ("disconnect_proxy",
-                 G_OBJECT_CLASS_TYPE (klass),
-                 0, 0, NULL, NULL,
-                 _gtk_marshal_VOID__OBJECT,
-                 G_TYPE_NONE, 1, 
-                 GTK_TYPE_WIDGET);
-
   g_type_class_add_private (gobject_class, sizeof (GtkActionPrivate));
 }
 
@@ -306,7 +359,12 @@ 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;
   action->private_data->is_important = FALSE;
+  action->private_data->hide_if_empty = TRUE;
 
   action->private_data->sensitive = TRUE;
   action->private_data->visible = TRUE;
@@ -315,6 +373,8 @@ gtk_action_init (GtkAction *action)
   action->private_data->short_label_set = FALSE;
 
   action->private_data->accel_count = 0;
+  action->private_data->accel_group = NULL;
+  action->private_data->accel_quark = 0;
   action->private_data->accel_closure = 
     g_closure_new_object (sizeof (GClosure), G_OBJECT (action));
   g_closure_set_marshal (action->private_data->accel_closure, 
@@ -322,28 +382,86 @@ gtk_action_init (GtkAction *action)
   g_closure_ref (action->private_data->accel_closure);
   g_closure_sink (action->private_data->accel_closure);
 
-  action->private_data->accel_quark = 0;
-  action->private_data->accel_count = 0;
-  action->private_data->accel_group = NULL;
+  action->private_data->action_group = NULL;
 
   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, 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,
+ * call gtk_action_group_add_action_with_accel().
+ * See <xref linkend="XML-UI"/> for information on allowed action
+ * names.
+ *
+ * Return value: a new #GtkAction
+ *
+ * Since: 2.4
+ */
+GtkAction *
+gtk_action_new (const gchar *name,
+               const gchar *label,
+               const gchar *tooltip,
+               const gchar *stock_id)
+{
+  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
 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 (gtk_action_parent_class)->finalize (object);  
 }
 
 static void
@@ -353,87 +471,52 @@ 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:
+      gtk_action_set_visible_horizontal (action, g_value_get_boolean (value));
+      break;
+    case PROP_VISIBLE_VERTICAL:
+      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));
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -454,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);
@@ -468,15 +551,33 @@ 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;
+    case PROP_VISIBLE_VERTICAL:
+      g_value_set_boolean (value, action->private_data->visible_vertical);
+      break;
+    case PROP_VISIBLE_OVERFLOWN:
+      g_value_set_boolean (value, action->private_data->visible_overflown);
+      break;
     case PROP_IS_IMPORTANT:
       g_value_set_boolean (value, action->private_data->is_important);
       break;
+    case PROP_HIDE_IF_EMPTY:
+      g_value_set_boolean (value, action->private_data->hide_if_empty);
+      break;
     case PROP_SENSITIVE:
       g_value_set_boolean (value, action->private_data->sensitive);
       break;
     case PROP_VISIBLE:
       g_value_set_boolean (value, action->private_data->visible);
       break;
+    case PROP_ACTION_GROUP:
+      g_value_set_object (value, action->private_data->action_group);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -504,107 +605,76 @@ 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_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);
-}
-
-static void
-gtk_action_sync_label (GtkAction  *action, 
-                      GParamSpec *pspec, 
-                      GtkWidget  *proxy)
+/**
+ * _gtk_action_sync_menu_visible:
+ * @action: a #GtkAction, or %NULL to determine the action from @proxy
+ * @proxy: a proxy menu item
+ * @empty: whether the submenu attached to @proxy is empty
+ * 
+ * Updates the visibility of @proxy from the visibility of @action
+ * according to the following rules:
+ * <itemizedlist>
+ * <listitem><para>if @action is invisible, @proxy is too
+ * </para></listitem>
+ * <listitem><para>if @empty is %TRUE, hide @proxy unless the "hide-if-empty" 
+ *   property of @action indicates otherwise
+ * </para></listitem>
+ * </itemizedlist>
+ * 
+ * This function is used in the implementation of #GtkUIManager.
+ **/
+void
+_gtk_action_sync_menu_visible (GtkAction *action,
+                              GtkWidget *proxy,
+                              gboolean   empty)
 {
-  GtkWidget *label = NULL;
+  gboolean visible, hide_if_empty;
 
   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);
-}
+  g_return_if_fail (action == NULL || GTK_IS_ACTION (action));
 
-static void
-gtk_action_sync_short_label (GtkAction  *action, 
-                            GParamSpec *pspec,
-                            GtkWidget  *proxy)
-{
-  GValue value = { 0, };
+  if (action == NULL)
+    action = g_object_get_qdata (G_OBJECT (proxy), quark_gtk_action_proxy);
 
-  g_value_init (&value, G_TYPE_STRING);
-  g_object_get_property (G_OBJECT (action), "short_label", &value);
+  visible = gtk_action_is_visible (action);
+  hide_if_empty = action->private_data->hide_if_empty;
 
-  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_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);
-    }
+  if (visible && !(empty && hide_if_empty))
+    gtk_widget_show (proxy);
+  else
+    gtk_widget_hide (proxy);
 }
 
+gboolean _gtk_menu_is_empty (GtkWidget *menu);
 
 static gboolean
 gtk_action_create_menu_proxy (GtkToolItem *tool_item, 
                              GtkAction   *action)
 {
-  GtkWidget *menu_item = gtk_action_create_menu_item (action);
-
-  g_object_ref (menu_item);
-  gtk_object_sink (GTK_OBJECT (menu_item));
+  GtkWidget *menu_item;
   
-  gtk_tool_item_set_proxy_menu_item (tool_item, "gtk-action-menu-item", menu_item);
-  g_object_unref (menu_item);
+  if (action->private_data->visible_overflown)
+    {
+      menu_item = gtk_action_create_menu_item (action);
+
+      g_object_ref_sink (menu_item);
+      
+      gtk_tool_item_set_proxy_menu_item (tool_item, 
+                                        "gtk-action-menu-item", menu_item);
+      g_object_unref (menu_item);
+    }
+  else
+    gtk_tool_item_set_proxy_menu_item (tool_item, 
+                                      "gtk-action-menu-item", NULL);
 
   return TRUE;
 }
@@ -614,21 +684,15 @@ connect_proxy (GtkAction     *action,
               GtkWidget     *proxy)
 {
   g_object_ref (action);
-  g_object_set_data_full (G_OBJECT (proxy), "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_property), proxy, 0);
-  gtk_widget_set_sensitive (proxy, action->private_data->sensitive);
-
-  g_signal_connect_object (action, "notify::visible",
-                          G_CALLBACK (gtk_action_sync_property), proxy, 0);
-  if (action->private_data->visible)
+  g_object_weak_ref (G_OBJECT (proxy), (GWeakNotify)remove_proxy, action);
+  
+  gtk_widget_set_sensitive (proxy, gtk_action_is_sensitive (action));
+  if (gtk_action_is_visible (action))
     gtk_widget_show (proxy);
   else
     gtk_widget_hide (proxy);
@@ -657,20 +721,18 @@ 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,
                              NULL);
       
       if (GTK_IS_ACCEL_LABEL (label) && action->private_data->accel_quark)
-       g_object_set (G_OBJECT (label),
-                     "accel_closure", action->private_data->accel_closure,
+       g_object_set (label,
+                     "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))
        {
@@ -684,127 +746,145 @@ 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);
        }
-
-      g_signal_connect_object (proxy, "activate",
-                              G_CALLBACK (gtk_action_activate), action,
-                              G_CONNECT_SWAPPED);
+      
+      if (gtk_menu_item_get_submenu (GTK_MENU_ITEM (proxy)) == NULL)
+       g_signal_connect_object (proxy, "activate",
+                                G_CALLBACK (gtk_action_activate), action,
+                                G_CONNECT_SWAPPED);
 
     }
-  else if (GTK_IS_TOOL_BUTTON (proxy))
+  else if (GTK_IS_TOOL_ITEM (proxy))
     {
       /* toolbar button specific synchronisers ... */
-
-      g_object_set (G_OBJECT (proxy),
-                   "label", action->private_data->short_label,
-                   "use_underline", TRUE,
-                   "stock_id", action->private_data->stock_id,
-                   "is_important", action->private_data->is_important,
-                   NULL);
-      /* FIXME: we should set the tooltip here, but the current api
-       * doesn't allow it before the item is added to a toolbar. 
-       */
-      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 (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);
+      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,
+                       "icon-name", action->private_data->icon_name,
+                       NULL);
+
+         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);
 
-      g_signal_connect_object (proxy, "clicked",
-                              G_CALLBACK (gtk_action_activate), action,
-                              G_CONNECT_SWAPPED);
+      gtk_tool_item_rebuild_menu (GTK_TOOL_ITEM (proxy));
     }
   else if (GTK_IS_BUTTON (proxy))
     {
       /* button specific synchronisers ... */
-
-      /* synchronise the label */
-      g_object_set (G_OBJECT (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_button_get_use_stock (GTK_BUTTON (proxy)))
+       {
+         /* synchronise stock-id */
+         g_object_set (proxy,
+                       "label", action->private_data->stock_id,
+                       NULL);
+       }
+      else 
+       {
+         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,
                               G_CONNECT_SWAPPED);
     }
 
-  g_signal_emit (action, action_signals[CONNECT_PROXY], 0, proxy);
+  if (action->private_data->action_group)
+    _gtk_action_group_emit_connect_proxy (action->private_data->action_group, action, proxy);
 }
 
 static void
 disconnect_proxy (GtkAction *action, 
                  GtkWidget *proxy)
 {
-  g_object_set_data (G_OBJECT (proxy), "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 */
+  /* toolbar button specific synchronisers ... */
   g_signal_handlers_disconnect_by_func (proxy,
-                                       G_CALLBACK (gtk_action_sync_property),
+                                       G_CALLBACK (gtk_action_create_menu_proxy),
                                        action);
 
-  g_signal_handlers_disconnect_by_func (action,
-                               G_CALLBACK (gtk_action_sync_stock_id), proxy);
+  if (action->private_data->action_group)
+    _gtk_action_group_emit_disconnect_proxy (action->private_data->action_group, action, 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);
+void
+_gtk_action_emit_activate (GtkAction *action)
+{
+  GtkActionGroup *group = action->private_data->action_group;
 
-  g_signal_handlers_disconnect_by_func (proxy,
-                                       G_CALLBACK (gtk_action_create_menu_proxy),
-                                       action);
+  if (group != NULL) 
+    {
+      g_object_ref (group);
+      _gtk_action_group_emit_pre_activate (group, action);
+    }
 
-  g_signal_emit (action, action_signals[DISCONNECT_PROXY], 0, proxy);
+    g_signal_emit (action, action_signals[ACTIVATE], 0);
+
+  if (group != NULL) 
+    {
+      _gtk_action_group_emit_post_activate (group, action);
+      g_object_unref (group);
+    }
 }
 
 /**
  * gtk_action_activate:
  * @action: the action object
  *
- * Emits the "activate" signal on the specified action. 
- * This gets called by the proxy widgets when they get activated.
+ * Emits the "activate" signal on the specified action, if it isn't 
+ * insensitive. This gets called by the proxy widgets when they get 
+ * activated.
  *
  * It can also be used to manually activate an action.
  *
@@ -813,7 +893,10 @@ disconnect_proxy (GtkAction *action,
 void
 gtk_action_activate (GtkAction *action)
 {
-  g_signal_emit (action, action_signals[ACTIVATE], 0);
+  g_return_if_fail (GTK_IS_ACTION (action));
+  
+  if (gtk_action_is_sensitive (action))
+    _gtk_action_emit_activate (action);
 }
 
 /**
@@ -835,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;
 }
@@ -911,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);  
@@ -936,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);  
 }
@@ -946,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
  **/
@@ -961,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
@@ -972,7 +1079,7 @@ gtk_action_get_proxies (GtkAction *action)
  *
  * Since: 2.4
  **/
-const gchar *
+G_CONST_RETURN gchar *
 gtk_action_get_name (GtkAction *action)
 {
   g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
@@ -980,6 +1087,491 @@ gtk_action_get_name (GtkAction *action)
   return action->private_data->name;
 }
 
+/**
+ * gtk_action_is_sensitive:
+ * @action: the action object
+ * 
+ * Returns whether the action is effectively sensitive.
+ *
+ * Return value: %TRUE if the action and its associated action group 
+ * are both sensitive.
+ *
+ * Since: 2.4
+ **/
+gboolean
+gtk_action_is_sensitive (GtkAction *action)
+{
+  GtkActionPrivate *priv;
+  g_return_val_if_fail (GTK_IS_ACTION (action), FALSE);
+
+  priv = action->private_data;
+  return priv->sensitive &&
+    (priv->action_group == NULL ||
+     gtk_action_group_get_sensitive (priv->action_group));
+}
+
+/**
+ * gtk_action_get_sensitive:
+ * @action: the action object
+ * 
+ * Returns whether the action itself is sensitive. Note that this doesn't 
+ * necessarily mean effective sensitivity. See gtk_action_is_sensitive() 
+ * for that.
+ *
+ * Return value: %TRUE if the action itself is sensitive.
+ *
+ * Since: 2.4
+ **/
+gboolean
+gtk_action_get_sensitive (GtkAction *action)
+{
+  g_return_val_if_fail (GTK_IS_ACTION (action), FALSE);
+
+  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
+ * @sensitive: %TRUE to make the action sensitive
+ * 
+ * Sets the ::sensitive property of the action to @sensitive. Note that 
+ * this doesn't necessarily mean effective sensitivity. See 
+ * gtk_action_is_sensitive() 
+ * for that.
+ *
+ * Since: 2.6
+ **/
+void
+gtk_action_set_sensitive (GtkAction *action,
+                         gboolean   sensitive)
+{
+  g_return_if_fail (GTK_IS_ACTION (action));
+
+  sensitive = sensitive != FALSE;
+  
+  if (action->private_data->sensitive != sensitive)
+    {
+      action->private_data->sensitive = sensitive;
+
+      _gtk_action_sync_sensitive (action);
+
+      g_object_notify (G_OBJECT (action), "sensitive");
+    }
+}
+
+/**
+ * gtk_action_is_visible:
+ * @action: the action object
+ * 
+ * Returns whether the action is effectively visible.
+ *
+ * Return value: %TRUE if the action and its associated action group 
+ * are both visible.
+ *
+ * Since: 2.4
+ **/
+gboolean
+gtk_action_is_visible (GtkAction *action)
+{
+  GtkActionPrivate *priv;
+  g_return_val_if_fail (GTK_IS_ACTION (action), FALSE);
+
+  priv = action->private_data;
+  return priv->visible &&
+    (priv->action_group == NULL ||
+     gtk_action_group_get_visible (priv->action_group));
+}
+
+/**
+ * gtk_action_get_visible:
+ * @action: the action object
+ * 
+ * Returns whether the action itself is visible. Note that this doesn't 
+ * necessarily mean effective visibility. See gtk_action_is_sensitive() 
+ * for that.
+ *
+ * Return value: %TRUE if the action itself is visible.
+ *
+ * Since: 2.4
+ **/
+gboolean
+gtk_action_get_visible (GtkAction *action)
+{
+  g_return_val_if_fail (GTK_IS_ACTION (action), FALSE);
+
+  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
+ * @visible: %TRUE to make the action visible
+ * 
+ * Sets the ::visible property of the action to @visible. Note that 
+ * this doesn't necessarily mean effective visibility. See 
+ * gtk_action_is_visible() 
+ * for that.
+ *
+ * Since: 2.6
+ **/
+void
+gtk_action_set_visible (GtkAction *action,
+                       gboolean   visible)
+{
+  g_return_if_fail (GTK_IS_ACTION (action));
+
+  visible = visible != FALSE;
+  
+  if (action->private_data->visible != visible)
+    {
+      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
@@ -1034,11 +1626,27 @@ closure_accel_activate (GClosure     *closure,
                         gpointer      invocation_hint,
                         gpointer      marshal_data)
 {
-  if (GTK_ACTION (closure->data)->private_data->sensitive)
-    g_signal_emit (closure->data, action_signals[ACTIVATE], 0);
+  if (gtk_action_is_sensitive (GTK_ACTION (closure->data)))
+    {
+      _gtk_action_emit_activate (GTK_ACTION (closure->data));
+      
+      /* we handled the accelerator */
+      g_value_set_boolean (return_value, TRUE);
+    }
+}
+
+static void
+gtk_action_set_action_group (GtkAction     *action,
+                            GtkActionGroup *action_group)
+{
+  g_return_if_fail (GTK_IS_ACTION (action));
+
+  if (action->private_data->action_group == NULL)
+    g_return_if_fail (GTK_IS_ACTION_GROUP (action_group));
+  else
+    g_return_if_fail (action_group == NULL);
 
-  /* we handled the accelerator */
-  g_value_set_boolean (return_value, TRUE);
+  action->private_data->action_group = action_group;
 }
 
 /**
@@ -1061,6 +1669,49 @@ gtk_action_set_accel_path (GtkAction   *action,
   action->private_data->accel_quark = g_quark_from_string (accel_path);
 }
 
+/**
+ * gtk_action_get_accel_path:
+ * @action: the action object
+ *
+ * Returns the accel path for this action.  
+ *
+ * Since: 2.6
+ *
+ * Returns: the accel path for this action, or %NULL
+ *   if none is set. The returned string is owned by GTK+ 
+ *   and must not be freed or modified.
+ */
+G_CONST_RETURN gchar *
+gtk_action_get_accel_path (GtkAction *action)
+{
+  g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
+
+  if (action->private_data->accel_quark)
+    return g_quark_to_string (action->private_data->accel_quark);
+  else
+    return NULL;
+}
+
+/**
+ * gtk_action_get_accel_closure:
+ * @action: the action object
+ *
+ * Returns the accel closure for this action.
+ *
+ * Since: 2.8
+ *
+ * Returns: the accel closure for this action. The returned closure is
+ *          owned by GTK+ and must not be unreffed or modified.
+ */
+GClosure *
+gtk_action_get_accel_closure (GtkAction *action)
+{
+  g_return_val_if_fail (GTK_IS_ACTION (action), NULL);
+
+  return action->private_data->accel_closure;
+}
+
+
 /**
  * gtk_action_set_accel_group:
  * @action: the action object
@@ -1146,3 +1797,29 @@ gtk_action_disconnect_accelerator (GtkAction *action)
     gtk_accel_group_disconnect (action->private_data->accel_group,
                                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"