aboutsummaryrefslogtreecommitdiffstats
path: root/widgets/misc/e-popup-action.c
diff options
context:
space:
mode:
Diffstat (limited to 'widgets/misc/e-popup-action.c')
-rw-r--r--widgets/misc/e-popup-action.c344
1 files changed, 244 insertions, 100 deletions
diff --git a/widgets/misc/e-popup-action.c b/widgets/misc/e-popup-action.c
index e856a1fc24..5f060a45cd 100644
--- a/widgets/misc/e-popup-action.c
+++ b/widgets/misc/e-popup-action.c
@@ -30,23 +30,110 @@
enum {
PROP_0,
- PROP_SOURCE
+ PROP_RELATED_ACTION,
+ PROP_USE_ACTION_APPEARANCE
};
struct _EPopupActionPrivate {
- GtkAction *source;
+ GtkAction *related_action;
+ gboolean use_action_appearance;
+ gulong activate_handler_id;
+ gulong notify_handler_id;
};
static gpointer parent_class;
static void
-popup_action_set_source (EPopupAction *popup_action,
- GtkAction *source)
+popup_action_notify_cb (GtkAction *action,
+ GParamSpec *pspec,
+ GtkActivatable *activatable)
{
- g_return_if_fail (popup_action->priv->source == NULL);
- g_return_if_fail (GTK_IS_ACTION (source));
+ GtkActivatableIface *iface;
- popup_action->priv->source = g_object_ref (source);
+ iface = GTK_ACTIVATABLE_GET_IFACE (activatable);
+ g_return_if_fail (iface->update != NULL);
+
+ iface->update (activatable, action, pspec->name);
+}
+
+static GtkAction *
+popup_action_get_related_action (EPopupAction *popup_action)
+{
+ return popup_action->priv->related_action;
+}
+
+static void
+popup_action_set_related_action (EPopupAction *popup_action,
+ GtkAction *related_action)
+{
+ GtkActivatable *activatable;
+
+ /* Do not call gtk_activatable_do_set_related_action() because
+ * it assumes the activatable object is a widget and tries to add
+ * it to the related actions's proxy list. Instead we'll just do
+ * the relevant steps manually. */
+
+ activatable = GTK_ACTIVATABLE (popup_action);
+
+ if (related_action == popup_action->priv->related_action)
+ return;
+
+ if (related_action != NULL)
+ g_object_ref (related_action);
+
+ if (popup_action->priv->related_action != NULL) {
+ g_signal_handler_disconnect (
+ popup_action,
+ popup_action->priv->activate_handler_id);
+ g_signal_handler_disconnect (
+ popup_action->priv->related_action,
+ popup_action->priv->notify_handler_id);
+ popup_action->priv->activate_handler_id = 0;
+ popup_action->priv->notify_handler_id = 0;
+ g_object_unref (popup_action->priv->related_action);
+ }
+
+ popup_action->priv->related_action = related_action;
+
+ if (related_action != NULL) {
+ popup_action->priv->activate_handler_id =
+ g_signal_connect_swapped (
+ popup_action, "activate",
+ G_CALLBACK (gtk_action_activate),
+ related_action);
+ popup_action->priv->notify_handler_id =
+ g_signal_connect (
+ related_action, "notify",
+ G_CALLBACK (popup_action_notify_cb),
+ popup_action);
+ gtk_activatable_sync_action_properties (
+ activatable, related_action);
+ } else
+ gtk_action_set_visible (GTK_ACTION (popup_action), FALSE);
+
+ g_object_notify (G_OBJECT (popup_action), "related-action");
+}
+
+static gboolean
+popup_action_get_use_action_appearance (EPopupAction *popup_action)
+{
+ return popup_action->priv->use_action_appearance;
+}
+
+static void
+popup_action_set_use_action_appearance (EPopupAction *popup_action,
+ gboolean use_action_appearance)
+{
+ GtkActivatable *activatable;
+ GtkAction *related_action;
+
+ popup_action->priv->use_action_appearance = use_action_appearance;
+
+ g_object_notify (G_OBJECT (popup_action), "use-action-appearance");
+
+ activatable = GTK_ACTIVATABLE (popup_action);
+ related_action = popup_action_get_related_action (popup_action);
+ gtk_activatable_sync_action_properties (activatable, related_action);
}
static void
@@ -56,11 +143,17 @@ popup_action_set_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
- case PROP_SOURCE:
- popup_action_set_source (
+ case PROP_RELATED_ACTION:
+ popup_action_set_related_action (
E_POPUP_ACTION (object),
g_value_get_object (value));
return;
+
+ case PROP_USE_ACTION_APPEARANCE:
+ popup_action_set_use_action_appearance (
+ E_POPUP_ACTION (object),
+ g_value_get_boolean (value));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -73,9 +166,17 @@ popup_action_get_property (GObject *object,
GParamSpec *pspec)
{
switch (property_id) {
- case PROP_SOURCE:
+ case PROP_RELATED_ACTION:
g_value_set_object (
- value, e_popup_action_get_source (
+ value,
+ popup_action_get_related_action (
+ E_POPUP_ACTION (object)));
+ return;
+
+ case PROP_USE_ACTION_APPEARANCE:
+ g_value_set_boolean (
+ value,
+ popup_action_get_use_action_appearance (
E_POPUP_ACTION (object)));
return;
}
@@ -90,9 +191,15 @@ popup_action_dispose (GObject *object)
priv = E_POPUP_ACTION_GET_PRIVATE (object);
- if (priv->source != NULL) {
- g_object_unref (priv->source);
- priv->source = NULL;
+ if (priv->related_action != NULL) {
+ g_signal_handler_disconnect (
+ object,
+ priv->activate_handler_id);
+ g_signal_handler_disconnect (
+ priv->related_action,
+ priv->notify_handler_id);
+ g_object_unref (priv->related_action);
+ priv->related_action = NULL;
}
/* Chain up to parent's dispose() method. */
@@ -100,56 +207,97 @@ popup_action_dispose (GObject *object)
}
static void
-popup_action_constructed (GObject *object)
+popup_action_update (GtkActivatable *activatable,
+ GtkAction *action,
+ const gchar *property_name)
{
- EPopupActionPrivate *priv;
- GObject *source;
- gchar *icon_name;
- gchar *label;
- gchar *stock_id;
- gchar *tooltip;
+ GObjectClass *class;
+ GParamSpec *pspec;
+ GValue *value;
- priv = E_POPUP_ACTION_GET_PRIVATE (object);
+ /* Ignore "action-group" changes" */
+ if (strcmp (property_name, "action-group") == 0)
+ return;
- source = G_OBJECT (priv->source);
+ /* Ignore "visible" changes. */
+ if (strcmp (property_name, "visible") == 0)
+ return;
- g_object_get (
- object, "icon-name", &icon_name, "label", &label,
- "stock-id", &stock_id, "tooltip", &tooltip, NULL);
+ value = g_slice_new0 (GValue);
+ class = G_OBJECT_GET_CLASS (action);
+ pspec = g_object_class_find_property (class, property_name);
+ g_value_init (value, pspec->value_type);
- if (label == NULL)
- e_binding_new (source, "label", object, "label");
+ g_object_get_property (G_OBJECT (action), property_name, value);
- if (tooltip == NULL)
- e_binding_new (source, "tooltip", object, "tooltip");
+ if (strcmp (property_name, "sensitive") == 0)
+ property_name = "visible";
+ else if (!gtk_activatable_get_use_action_appearance (activatable))
+ goto exit;
- if (icon_name == NULL && stock_id == NULL) {
- g_free (icon_name);
- g_free (stock_id);
+ g_object_set_property (G_OBJECT (activatable), property_name, value);
- g_object_get (
- source, "icon-name", &icon_name,
- "stock-id", &stock_id, NULL);
+exit:
+ g_value_unset (value);
+ g_slice_free (GValue, value);
+}
- if (icon_name == NULL) {
- e_binding_new (
- source, "icon-name", object, "icon-name");
- e_binding_new (
- source, "stock-id", object, "stock-id");
- } else {
- e_binding_new (
- source, "stock-id", object, "stock-id");
- e_binding_new (
- source, "icon-name", object, "icon-name");
- }
- }
+static void
+popup_action_sync_action_properties (GtkActivatable *activatable,
+ GtkAction *action)
+{
+ if (action == NULL)
+ return;
+
+ /* XXX GTK+ 2.18 is still missing accessor functions for
+ * "hide-if-empty" and "visible-overflown" properties.
+ * These are rarely used so we'll skip them for now. */
+
+ /* A popup action is never shown as insensitive. */
+ gtk_action_set_sensitive (GTK_ACTION (activatable), TRUE);
+
+ gtk_action_set_visible (
+ GTK_ACTION (activatable),
+ gtk_action_get_sensitive (action));
+
+ gtk_action_set_visible_horizontal (
+ GTK_ACTION (activatable),
+ gtk_action_get_visible_horizontal (action));
+
+ gtk_action_set_visible_vertical (
+ GTK_ACTION (activatable),
+ gtk_action_get_visible_vertical (action));
+
+ gtk_action_set_is_important (
+ GTK_ACTION (activatable),
+ gtk_action_get_is_important (action));
- e_binding_new (source, "sensitive", object, "visible");
+ if (!gtk_activatable_get_use_action_appearance (activatable))
+ return;
- g_free (icon_name);
- g_free (label);
- g_free (stock_id);
- g_free (tooltip);
+ gtk_action_set_label (
+ GTK_ACTION (activatable),
+ gtk_action_get_label (action));
+
+ gtk_action_set_short_label (
+ GTK_ACTION (activatable),
+ gtk_action_get_short_label (action));
+
+ gtk_action_set_tooltip (
+ GTK_ACTION (activatable),
+ gtk_action_get_tooltip (action));
+
+ gtk_action_set_stock_id (
+ GTK_ACTION (activatable),
+ gtk_action_get_stock_id (action));
+
+ gtk_action_set_gicon (
+ GTK_ACTION (activatable),
+ gtk_action_get_gicon (action));
+
+ gtk_action_set_icon_name (
+ GTK_ACTION (activatable),
+ gtk_action_get_icon_name (action));
}
static void
@@ -165,22 +313,32 @@ popup_action_class_init (EPopupActionClass *class)
object_class->get_property = popup_action_get_property;
object_class->dispose = popup_action_dispose;
- g_object_class_install_property (
+ g_object_class_override_property (
+ object_class,
+ PROP_RELATED_ACTION,
+ "related-action");
+
+ g_object_class_override_property (
object_class,
- PROP_SOURCE,
- g_param_spec_object (
- "source",
- _("Source Action"),
- _("The source action to proxy"),
- GTK_TYPE_ACTION,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT_ONLY));
+ PROP_USE_ACTION_APPEARANCE,
+ "use-action-appearance");
+}
+
+static void
+popup_action_iface_init (GtkActivatableIface *iface)
+{
+ iface->update = popup_action_update;
+ iface->sync_action_properties = popup_action_sync_action_properties;
}
static void
popup_action_init (EPopupAction *popup_action)
{
popup_action->priv = E_POPUP_ACTION_GET_PRIVATE (popup_action);
+ popup_action->priv->use_action_appearance = TRUE;
+
+ /* Remain invisible until we have a related action. */
+ gtk_action_set_visible (GTK_ACTION (popup_action), FALSE);
}
GType
@@ -202,43 +360,28 @@ e_popup_action_get_type (void)
NULL /* value_table */
};
+ static const GInterfaceInfo iface_info = {
+ (GInterfaceInitFunc) popup_action_iface_init,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL /* interface_data */
+ };
+
type = g_type_register_static (
GTK_TYPE_ACTION, "EPopupAction", &type_info, 0);
+
+ g_type_add_interface_static (
+ type, GTK_TYPE_ACTIVATABLE, &iface_info);
}
return type;
}
EPopupAction *
-e_popup_action_new (const gchar *name,
- const gchar *label,
- GtkAction *source)
+e_popup_action_new (const gchar *name)
{
- EPopupAction *popup_action;
-
g_return_val_if_fail (name != NULL, NULL);
- g_return_val_if_fail (GTK_IS_ACTION (source), NULL);
- popup_action = g_object_new (
- E_TYPE_POPUP_ACTION, "name", name,
- "label", label, "source", source, NULL);
-
- /* XXX This is a hack to work around the fact that GtkAction's
- * "label" and "tooltip" properties are not constructor
- * properties, even though they're supplied upfront.
- *
- * See: http://bugzilla.gnome.org/show_bug.cgi?id=568334 */
- popup_action_constructed (G_OBJECT (popup_action));
-
- return popup_action;
-}
-
-GtkAction *
-e_popup_action_get_source (EPopupAction *popup_action)
-{
- g_return_val_if_fail (E_IS_POPUP_ACTION (popup_action), NULL);
-
- return popup_action->priv->source;
+ return g_object_new (E_TYPE_POPUP_ACTION, "name", name, NULL);
}
void
@@ -252,30 +395,31 @@ e_action_group_add_popup_actions (GtkActionGroup *action_group,
for (ii = 0; ii < n_entries; ii++) {
EPopupAction *popup_action;
- GtkAction *source;
+ GtkAction *related_action;
const gchar *label;
label = gtk_action_group_translate_string (
action_group, entries[ii].label);
- source = gtk_action_group_get_action (
- action_group, entries[ii].source);
+ related_action = gtk_action_group_get_action (
+ action_group, entries[ii].related);
- if (source == NULL) {
+ if (related_action == NULL) {
g_warning (
- "Source action '%s' not found in "
- "action group '%s'", entries[ii].source,
+ "Related action '%s' not found in "
+ "action group '%s'", entries[ii].related,
gtk_action_group_get_name (action_group));
continue;
}
- popup_action = e_popup_action_new (
- entries[ii].name, label, source);
+ popup_action = e_popup_action_new (entries[ii].name);
+
+ gtk_activatable_set_related_action (
+ GTK_ACTIVATABLE (popup_action), related_action);
- g_signal_connect_swapped (
- popup_action, "activate",
- G_CALLBACK (gtk_action_activate),
- popup_action->priv->source);
+ if (label != NULL && *label != '\0')
+ gtk_action_set_label (
+ GTK_ACTION (popup_action), label);
gtk_action_group_add_action (
action_group, GTK_ACTION (popup_action));