From 51ebf20237270a785af0aa0e614db42275a05c62 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Fri, 15 Oct 2010 14:51:13 -0400 Subject: EAlert: Allow arbitrary actions to be added. You can now amend the predefined actions in an EAlert by calling e_alert_add_action(). Useful for adding actions from an existing GtkUIManager. Call e_alert_peek_actions() to obtain a combined list of predefined and custom actions. These will typically serve as "related" actions for GtkButtons (cf. gtk_activatable_set_related_action()). Also, both EShellWindow and EShellView now implement EAlertSink. Use EShellWindow for application-wide alerts, EShellView for view-specific alerts. --- widgets/misc/e-alert-bar.c | 112 ++++++++++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 43 deletions(-) (limited to 'widgets/misc') diff --git a/widgets/misc/e-alert-bar.c b/widgets/misc/e-alert-bar.c index b0509785f4..6e81bece1f 100644 --- a/widgets/misc/e-alert-bar.c +++ b/widgets/misc/e-alert-bar.c @@ -21,11 +21,14 @@ #include #include +#include "e-util/e-alert-action.h" + #define E_ALERT_BAR_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE \ ((obj), E_TYPE_ALERT_BAR, EAlertBarPrivate)) -#define ICON_SIZE GTK_ICON_SIZE_DIALOG +/* GTK_ICON_SIZE_DIALOG is a tad too big. */ +#define ICON_SIZE GTK_ICON_SIZE_DND struct _EAlertBarPrivate { GQueue alerts; @@ -46,8 +49,8 @@ alert_bar_show_alert (EAlertBar *alert_bar) GtkLabel *label; GtkInfoBar *info_bar; GtkWidget *action_area; - EAlertButton *buttons; EAlert *alert; + GList *actions; GList *children; GtkMessageType message_type; const gchar *stock_id; @@ -69,22 +72,27 @@ alert_bar_show_alert (EAlertBar *alert_bar) } /* Add new buttons. */ - buttons = e_alert_peek_buttons (alert); - if (buttons == NULL) { - gtk_info_bar_add_button ( - info_bar, _("_Dismiss"), GTK_RESPONSE_CLOSE); - } else while (buttons != NULL) { - const gchar *button_text; - - if (buttons->stock != NULL) - button_text = buttons->stock; - else - button_text = buttons->label; - - gtk_info_bar_add_button ( - info_bar, button_text, buttons->response); - - buttons = buttons->next; + actions = e_alert_peek_actions (alert); + while (actions != NULL) { + GtkWidget *button; + + /* These actions are already wired to trigger an + * EAlert::response signal when activated, which + * will in turn call gtk_info_bar_response(), so + * we can add buttons directly to the action + * area without knowning their response IDs. */ + + button = gtk_button_new (); + + gtk_activatable_set_related_action ( + GTK_ACTIVATABLE (button), + GTK_ACTION (actions->data)); + + gtk_box_pack_end ( + GTK_BOX (action_area), + button, FALSE, FALSE, 0); + + actions = g_list_next (actions); } response_id = e_alert_get_default_response (alert); @@ -109,51 +117,65 @@ alert_bar_show_alert (EAlertBar *alert_bar) } static void -alert_bar_dispose (GObject *object) +alert_bar_response_cb (EAlert *alert, + gint response_id, + EAlertBar *alert_bar) { - EAlertBarPrivate *priv; - - priv = E_ALERT_BAR_GET_PRIVATE (object); - - while (!g_queue_is_empty (&priv->alerts)) - g_object_unref (g_queue_pop_head (&priv->alerts)); + GQueue *queue; + EAlert *head; + GList *link; + gboolean was_head; + + queue = &alert_bar->priv->alerts; + head = g_queue_peek_head (queue); + was_head = (alert == head); + + g_signal_handlers_disconnect_by_func ( + alert, alert_bar_response_cb, alert_bar); + + /* XXX Would be easier if g_queue_remove() returned a boolean. */ + link = g_queue_find (queue, alert); + if (link != NULL) { + g_queue_delete_link (queue, link); + g_object_unref (alert); + } - /* Chain up to parent's dispose() method. */ - G_OBJECT_CLASS (e_alert_bar_parent_class)->dispose (object); + if (g_queue_is_empty (queue)) + gtk_widget_hide (GTK_WIDGET (alert_bar)); + else if (was_head) { + GtkInfoBar *info_bar = GTK_INFO_BAR (alert_bar); + gtk_info_bar_response (info_bar, response_id); + alert_bar_show_alert (alert_bar); + } } static void -alert_bar_response (GtkInfoBar *info_bar, - gint response_id) +alert_bar_dispose (GObject *object) { - EAlertBar *alert_bar; - EAlert *alert; + EAlertBarPrivate *priv; - alert_bar = E_ALERT_BAR (info_bar); + priv = E_ALERT_BAR_GET_PRIVATE (object); - alert = g_queue_pop_head (&alert_bar->priv->alerts); - e_alert_response (alert, response_id); - g_object_unref (alert); + while (!g_queue_is_empty (&priv->alerts)) { + EAlert *alert = g_queue_pop_head (&priv->alerts); + g_signal_handlers_disconnect_by_func ( + alert, alert_bar_response_cb, object); + g_object_unref (alert); + } - if (!g_queue_is_empty (&alert_bar->priv->alerts)) - alert_bar_show_alert (alert_bar); - else - gtk_widget_hide (GTK_WIDGET (alert_bar)); + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (e_alert_bar_parent_class)->dispose (object); } static void e_alert_bar_class_init (EAlertBarClass *class) { GObjectClass *object_class; - GtkInfoBarClass *info_bar_class; g_type_class_add_private (class, sizeof (EAlertBarPrivate)); object_class = G_OBJECT_CLASS (class); object_class->dispose = alert_bar_dispose; - - info_bar_class = GTK_INFO_BAR_CLASS (class); - info_bar_class->response = alert_bar_response; } static void @@ -230,6 +252,10 @@ e_alert_bar_add_alert (EAlertBar *alert_bar, g_return_if_fail (E_IS_ALERT_BAR (alert_bar)); g_return_if_fail (E_IS_ALERT (alert)); + g_signal_connect ( + alert, "response", + G_CALLBACK (alert_bar_response_cb), alert_bar); + g_queue_push_head (&alert_bar->priv->alerts, g_object_ref (alert)); alert_bar_show_alert (alert_bar); -- cgit v1.2.3