From c5e04ca04066ae2d92d3999626ef91d5d0606cab Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Thu, 12 Nov 2009 21:27:40 -0500 Subject: EWebView popup menu enhancements. Bumps the GtkHtml dependency to 3.29.2 for gtk_html_unselect_all(). --- widgets/misc/e-popup-action.c | 344 ++++++++++++++++++++++++++++++------------ 1 file changed, 244 insertions(+), 100 deletions(-) (limited to 'widgets/misc/e-popup-action.c') 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)); -- cgit v1.2.3