[notification-daemon] Add a notification box class that updates in place



commit fe52631b4c0cdfd1ae19f1c1be10f01b381b245f
Author: William Jon McCann <jmccann redhat com>
Date:   Fri Oct 29 17:34:11 2010 -0400

    Add a notification box class that updates in place
    
    https://bugzilla.gnome.org/show_bug.cgi?id=633457

 src/Makefile.am           |    2 +
 src/nd-notification-box.c |  403 +++++++++++++++++++++++++++++++++++++++++++++
 src/nd-notification-box.h |   58 +++++++
 src/nd-queue.c            |  314 ++---------------------------------
 4 files changed, 477 insertions(+), 300 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index ad3cb8a..384129b 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,6 +3,8 @@ libexec_PROGRAMS = notification-daemon
 notification_daemon_SOURCES = \
 	nd-notification.c \
 	nd-notification.h \
+	nd-notification-box.c \
+	nd-notification-box.h \
 	nd-bubble.c \
 	nd-bubble.h \
 	nd-stack.c \
diff --git a/src/nd-notification-box.c b/src/nd-notification-box.c
new file mode 100644
index 0000000..3261ad6
--- /dev/null
+++ b/src/nd-notification-box.c
@@ -0,0 +1,403 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <strings.h>
+#include <glib.h>
+
+#include "nd-notification.h"
+#include "nd-notification-box.h"
+
+#define ND_NOTIFICATION_BOX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ND_TYPE_NOTIFICATION_BOX, NdNotificationBoxPrivate))
+
+#define IMAGE_SIZE    48
+#define BODY_X_OFFSET (IMAGE_SIZE + 8)
+#define WIDTH         400
+
+struct NdNotificationBoxPrivate
+{
+        NdNotification *notification;
+
+        GtkWidget      *icon;
+        GtkWidget      *close_button;
+        GtkWidget      *summary_label;
+        GtkWidget      *body_label;
+
+        GtkWidget      *main_hbox;
+        GtkWidget      *iconbox;
+        GtkWidget      *content_hbox;
+        GtkWidget      *actions_box;
+        GtkWidget      *last_sep;
+};
+
+static void     nd_notification_box_class_init  (NdNotificationBoxClass *klass);
+static void     nd_notification_box_init        (NdNotificationBox      *notification_box);
+static void     nd_notification_box_finalize    (GObject                *object);
+
+G_DEFINE_TYPE (NdNotificationBox, nd_notification_box, GTK_TYPE_EVENT_BOX)
+
+NdNotification *
+nd_notification_box_get_notification (NdNotificationBox *notification_box)
+{
+        g_return_val_if_fail (ND_IS_NOTIFICATION_BOX (notification_box), NULL);
+
+        return notification_box->priv->notification;
+}
+
+static gboolean
+nd_notification_box_button_release_event (GtkWidget      *widget,
+                                          GdkEventButton *event)
+{
+        NdNotificationBox *notification_box = ND_NOTIFICATION_BOX (widget);
+
+        nd_notification_action_invoked (notification_box->priv->notification, "default");
+
+        return FALSE;
+}
+
+static void
+nd_notification_box_class_init (NdNotificationBoxClass *klass)
+{
+        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
+        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+        object_class->finalize = nd_notification_box_finalize;
+        widget_class->button_release_event = nd_notification_box_button_release_event;
+
+        g_type_class_add_private (klass, sizeof (NdNotificationBoxPrivate));
+}
+
+static void
+on_close_button_clicked (GtkButton         *button,
+                         NdNotificationBox *notification_box)
+{
+        nd_notification_close (notification_box->priv->notification, ND_NOTIFICATION_CLOSED_USER);
+}
+
+static void
+on_action_clicked (GtkButton         *button,
+                   GdkEventButton    *event,
+                   NdNotificationBox *notification_box)
+{
+        const char *key = g_object_get_data (G_OBJECT (button), "_action_key");
+
+        nd_notification_action_invoked (notification_box->priv->notification,
+                                        key);
+}
+
+static GtkWidget *
+create_notification_action (NdNotificationBox *box,
+                            NdNotification    *notification,
+                            const char        *text,
+                            const char        *key)
+{
+        GtkWidget *label;
+        GtkWidget *button;
+        GtkWidget *hbox;
+        GdkPixbuf *pixbuf;
+        char      *buf;
+
+        button = gtk_button_new ();
+        gtk_widget_show (button);
+        gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+        gtk_container_set_border_width (GTK_CONTAINER (button), 0);
+
+        hbox = gtk_hbox_new (FALSE, 6);
+        gtk_widget_show (hbox);
+        gtk_container_add (GTK_CONTAINER (button), hbox);
+
+        /* Try to be smart and find a suitable icon. */
+        buf = g_strdup_printf ("stock_%s", key);
+        pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (box))),
+                                           buf,
+                                           16,
+                                           GTK_ICON_LOOKUP_USE_BUILTIN,
+                                           NULL);
+        g_free (buf);
+
+        if (pixbuf != NULL) {
+                GtkWidget *image = gtk_image_new_from_pixbuf (pixbuf);
+                gtk_widget_show (image);
+                gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+                gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.5);
+        }
+
+        label = gtk_label_new (NULL);
+        gtk_widget_show (label);
+        gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+        buf = g_strdup_printf ("<small>%s</small>", text);
+        gtk_label_set_markup (GTK_LABEL (label), buf);
+        g_free (buf);
+
+        g_object_set_data_full (G_OBJECT (button),
+                                "_action_key", g_strdup (key), g_free);
+        g_signal_connect (G_OBJECT (button),
+                          "button-release-event",
+                          G_CALLBACK (on_action_clicked),
+                          box);
+        return button;
+}
+
+static void
+remove_item (GtkWidget *item,
+             gpointer   data)
+{
+        gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (item)),
+                              item);
+}
+
+static void
+update_notification_box (NdNotificationBox *notification_box)
+{
+        gboolean       have_icon;
+        gboolean       have_body;
+        gboolean       have_actions;
+        GdkPixbuf     *pixbuf;
+        char         **actions;
+        int            i;
+        char          *str;
+        char          *quoted;
+        GtkRequisition req;
+        int            summary_width;
+
+        /* Add content */
+
+        have_icon = FALSE;
+        have_body = FALSE;
+        have_actions = FALSE;
+
+        /* image */
+        pixbuf = nd_notification_load_image (notification_box->priv->notification, IMAGE_SIZE);
+        if (pixbuf != NULL) {
+                gtk_image_set_from_pixbuf (GTK_IMAGE (notification_box->priv->icon), pixbuf);
+
+                g_object_unref (G_OBJECT (pixbuf));
+                have_icon = TRUE;
+        }
+
+        /* summary */
+        quoted = g_markup_escape_text (nd_notification_get_summary (notification_box->priv->notification), -1);
+        str = g_strdup_printf ("<b><big>%s</big></b>", quoted);
+        g_free (quoted);
+
+        gtk_label_set_markup (GTK_LABEL (notification_box->priv->summary_label), str);
+        g_free (str);
+
+        gtk_widget_size_request (notification_box->priv->close_button, &req);
+        /* -1: main_vbox border width
+           -10: vbox border width
+           -6: spacing for hbox */
+        summary_width = WIDTH - (1*2) - (10*2) - BODY_X_OFFSET - req.width - (6*2);
+
+        gtk_widget_set_size_request (notification_box->priv->summary_label,
+                                     summary_width,
+                                     -1);
+
+        /* body */
+        gtk_label_set_markup (GTK_LABEL (notification_box->priv->body_label), nd_notification_get_body (notification_box->priv->notification));
+
+        if (str != NULL && *str != '\0') {
+                gtk_widget_set_size_request (notification_box->priv->body_label,
+                                             summary_width,
+                                             -1);
+                have_body = TRUE;
+        }
+
+        /* actions */
+        gtk_container_foreach (GTK_CONTAINER (notification_box->priv->actions_box), remove_item, NULL);
+        actions = nd_notification_get_actions (notification_box->priv->notification);
+        for (i = 0; actions[i] != NULL; i += 2) {
+                char *l = actions[i + 1];
+
+                if (l == NULL) {
+                        g_warning ("Label not found for action %s. "
+                                   "The protocol specifies that a label must "
+                                   "follow an action in the actions array",
+                                   actions[i]);
+
+                        break;
+                }
+
+                if (strcasecmp (actions[i], "default") != 0) {
+                        GtkWidget *button;
+
+                        button = create_notification_action (notification_box,
+                                                             notification_box->priv->notification,
+                                                             l,
+                                                             actions[i]);
+                        gtk_box_pack_start (GTK_BOX (notification_box->priv->actions_box), button, FALSE, FALSE, 0);
+
+                        have_actions = TRUE;
+                }
+        }
+
+        if (have_icon || have_body || have_actions) {
+                gtk_widget_show (notification_box->priv->content_hbox);
+        } else {
+                gtk_widget_hide (notification_box->priv->content_hbox);
+        }
+}
+
+static void
+nd_notification_box_init (NdNotificationBox *notification_box)
+{
+        GtkWidget     *box;
+        GtkWidget     *iconbox;
+        GtkWidget     *image;
+        GtkWidget     *vbox;
+        GtkWidget     *alignment;
+        AtkObject     *atkobj;
+        GtkRcStyle    *rcstyle;
+
+        notification_box->priv = ND_NOTIFICATION_BOX_GET_PRIVATE (notification_box);
+        box = gtk_hbox_new (FALSE, 6);
+        gtk_container_add (GTK_CONTAINER (notification_box), box);
+        gtk_widget_show (box);
+
+        /* First row (icon, vbox, close) */
+        iconbox = gtk_alignment_new (0.5, 0, 0, 0);
+        gtk_widget_show (iconbox);
+        gtk_alignment_set_padding (GTK_ALIGNMENT (iconbox),
+                                   5, 0, 0, 0);
+        gtk_box_pack_start (GTK_BOX (box),
+                            iconbox,
+                            FALSE, FALSE, 0);
+        gtk_widget_set_size_request (iconbox, BODY_X_OFFSET, -1);
+
+        notification_box->priv->icon = gtk_image_new ();
+        gtk_widget_show (notification_box->priv->icon);
+        gtk_container_add (GTK_CONTAINER (iconbox), notification_box->priv->icon);
+
+        vbox = gtk_vbox_new (FALSE, 6);
+        gtk_widget_show (vbox);
+        gtk_box_pack_start (GTK_BOX (box), vbox, TRUE, TRUE, 0);
+        gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
+
+        /* Add the close button */
+        alignment = gtk_alignment_new (0.5, 0, 0, 0);
+        gtk_widget_show (alignment);
+        gtk_box_pack_start (GTK_BOX (box), alignment, FALSE, FALSE, 0);
+
+        notification_box->priv->close_button = gtk_button_new ();
+        gtk_widget_show (notification_box->priv->close_button);
+        gtk_container_add (GTK_CONTAINER (alignment), notification_box->priv->close_button);
+        gtk_button_set_relief (GTK_BUTTON (notification_box->priv->close_button), GTK_RELIEF_NONE);
+        gtk_container_set_border_width (GTK_CONTAINER (notification_box->priv->close_button), 0);
+        g_signal_connect (G_OBJECT (notification_box->priv->close_button),
+                          "clicked",
+                          G_CALLBACK (on_close_button_clicked),
+                          notification_box);
+
+        rcstyle = gtk_rc_style_new ();
+        rcstyle->xthickness = rcstyle->ythickness = 0;
+        gtk_widget_modify_style (notification_box->priv->close_button, rcstyle);
+        g_object_unref (rcstyle);
+
+        atkobj = gtk_widget_get_accessible (notification_box->priv->close_button);
+        atk_action_set_description (ATK_ACTION (atkobj), 0,
+                                    "Closes the notification.");
+        atk_object_set_name (atkobj, "");
+        atk_object_set_description (atkobj, "Closes the notification.");
+
+        image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
+        gtk_widget_show (image);
+        gtk_container_add (GTK_CONTAINER (notification_box->priv->close_button), image);
+
+        /* center vbox */
+        notification_box->priv->summary_label = gtk_label_new (NULL);
+        gtk_widget_show (notification_box->priv->summary_label);
+        gtk_box_pack_start (GTK_BOX (vbox), notification_box->priv->summary_label, TRUE, TRUE, 0);
+        gtk_misc_set_alignment (GTK_MISC (notification_box->priv->summary_label), 0, 0);
+        gtk_label_set_line_wrap (GTK_LABEL (notification_box->priv->summary_label), TRUE);
+
+        atkobj = gtk_widget_get_accessible (notification_box->priv->summary_label);
+        atk_object_set_description (atkobj, "Notification summary text.");
+
+        notification_box->priv->content_hbox = gtk_hbox_new (FALSE, 6);
+        gtk_widget_show (notification_box->priv->content_hbox);
+        gtk_box_pack_start (GTK_BOX (vbox), notification_box->priv->content_hbox, FALSE, FALSE, 0);
+
+        vbox = gtk_vbox_new (FALSE, 6);
+
+        gtk_widget_show (vbox);
+        gtk_box_pack_start (GTK_BOX (notification_box->priv->content_hbox), vbox, TRUE, TRUE, 0);
+
+        notification_box->priv->body_label = gtk_label_new (NULL);
+        gtk_widget_show (notification_box->priv->body_label);
+        gtk_box_pack_start (GTK_BOX (vbox), notification_box->priv->body_label, TRUE, TRUE, 0);
+        gtk_misc_set_alignment (GTK_MISC (notification_box->priv->body_label), 0, 0);
+        gtk_label_set_line_wrap (GTK_LABEL (notification_box->priv->body_label), TRUE);
+
+        atkobj = gtk_widget_get_accessible (notification_box->priv->body_label);
+        atk_object_set_description (atkobj, "Notification body text.");
+
+        alignment = gtk_alignment_new (1, 0.5, 0, 0);
+        gtk_widget_show (alignment);
+        gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, TRUE, 0);
+
+        notification_box->priv->actions_box = gtk_hbox_new (FALSE, 6);
+        gtk_widget_show (notification_box->priv->actions_box);
+        gtk_container_add (GTK_CONTAINER (alignment), notification_box->priv->actions_box);
+
+}
+
+static void
+on_notification_changed (NdNotification    *notification,
+                         NdNotificationBox *notification_box)
+{
+        update_notification_box (notification_box);
+}
+
+static void
+nd_notification_box_finalize (GObject *object)
+{
+        NdNotificationBox *notification_box;
+
+        g_return_if_fail (object != NULL);
+        g_return_if_fail (ND_IS_NOTIFICATION_BOX (object));
+
+        notification_box = ND_NOTIFICATION_BOX (object);
+
+        g_return_if_fail (notification_box->priv != NULL);
+
+        g_signal_handlers_disconnect_by_func (notification_box->priv->notification, G_CALLBACK (on_notification_changed), notification_box);
+
+        g_object_unref (notification_box->priv->notification);
+
+        G_OBJECT_CLASS (nd_notification_box_parent_class)->finalize (object);
+}
+
+NdNotificationBox *
+nd_notification_box_new_for_notification (NdNotification *notification)
+{
+        NdNotificationBox *notification_box;
+
+        notification_box = g_object_new (ND_TYPE_NOTIFICATION_BOX,
+                                         "visible-window", FALSE,
+                                         NULL);
+        notification_box->priv->notification = g_object_ref (notification);
+        g_signal_connect (notification, "changed", G_CALLBACK (on_notification_changed), notification_box);
+        update_notification_box (notification_box);
+
+        return notification_box;
+}
diff --git a/src/nd-notification-box.h b/src/nd-notification-box.h
new file mode 100644
index 0000000..2e59973
--- /dev/null
+++ b/src/nd-notification-box.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifndef __ND_NOTIFICATION_BOX_H
+#define __ND_NOTIFICATION_BOX_H
+
+#include <gtk/gtk.h>
+#include "nd-notification.h"
+
+G_BEGIN_DECLS
+
+#define ND_TYPE_NOTIFICATION_BOX         (nd_notification_box_get_type ())
+#define ND_NOTIFICATION_BOX(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), ND_TYPE_NOTIFICATION_BOX, NdNotificationBox))
+#define ND_NOTIFICATION_BOX_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), ND_TYPE_NOTIFICATION_BOX, NdNotificationBoxClass))
+#define ND_IS_NOTIFICATION_BOX(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), ND_TYPE_NOTIFICATION_BOX))
+#define ND_IS_NOTIFICATION_BOX_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), ND_TYPE_NOTIFICATION_BOX))
+#define ND_NOTIFICATION_BOX_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), ND_TYPE_NOTIFICATION_BOX, NdNotificationBoxClass))
+
+typedef struct NdNotificationBoxPrivate NdNotificationBoxPrivate;
+
+typedef struct
+{
+        GtkEventBox               parent;
+        NdNotificationBoxPrivate *priv;
+} NdNotificationBox;
+
+typedef struct
+{
+        GtkEventBoxClass   parent_class;
+} NdNotificationBoxClass;
+
+GType               nd_notification_box_get_type             (void);
+
+NdNotificationBox * nd_notification_box_new_for_notification (NdNotification    *notification);
+
+NdNotification *    nd_notification_box_get_notification     (NdNotificationBox *notification_box);
+
+G_END_DECLS
+
+#endif /* __ND_NOTIFICATION_BOX_H */
diff --git a/src/nd-queue.c b/src/nd-queue.c
index a3a0164..20eac19 100644
--- a/src/nd-queue.c
+++ b/src/nd-queue.c
@@ -32,12 +32,11 @@
 #include "nd-queue.h"
 
 #include "nd-notification.h"
+#include "nd-notification-box.h"
 #include "nd-stack.h"
 
 #define ND_QUEUE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ND_TYPE_QUEUE, NdQueuePrivate))
 
-#define IMAGE_SIZE    48
-#define BODY_X_OFFSET (IMAGE_SIZE + 8)
 #define WIDTH         400
 
 typedef struct
@@ -70,13 +69,13 @@ enum {
 
 static guint signals [LAST_SIGNAL] = { 0, };
 
-static void     nd_queue_class_init  (NdQueueClass *klass);
-static void     nd_queue_init        (NdQueue      *queue);
-static void     nd_queue_finalize    (GObject         *object);
-static void     queue_update         (NdQueue *queue);
-static void     on_notification_close (NdNotification *notification,
-                                       int             reason,
-                                       NdQueue        *queue);
+static void     nd_queue_class_init     (NdQueueClass   *klass);
+static void     nd_queue_init           (NdQueue        *queue);
+static void     nd_queue_finalize       (GObject        *object);
+static void     queue_update            (NdQueue        *queue);
+static void     on_notification_close   (NdNotification *notification,
+                                         int             reason,
+                                         NdQueue        *queue);
 
 static gpointer queue_object = NULL;
 
@@ -660,291 +659,6 @@ collate_notifications (NdNotification *a,
 }
 
 static void
-on_close_button_clicked (GtkButton      *button,
-                         NdNotification *notification)
-{
-        nd_notification_close (notification, ND_NOTIFICATION_CLOSED_USER);
-}
-
-static void
-on_action_clicked (GtkButton      *button,
-                   GdkEventButton *event,
-                   NdNotification *notification)
-{
-        const char *key = g_object_get_data (G_OBJECT (button), "_action_key");
-
-        nd_notification_action_invoked (notification,
-                                        key);
-}
-
-static GtkWidget *
-create_notification_action (NdQueue        *queue,
-                            NdNotification *notification,
-                            const char     *text,
-                            const char     *key)
-{
-        GtkWidget *label;
-        GtkWidget *button;
-        GtkWidget *hbox;
-        GdkPixbuf *pixbuf;
-        char      *buf;
-
-        button = gtk_button_new ();
-        gtk_widget_show (button);
-        gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
-        gtk_container_set_border_width (GTK_CONTAINER (button), 0);
-
-        hbox = gtk_hbox_new (FALSE, 6);
-        gtk_widget_show (hbox);
-        gtk_container_add (GTK_CONTAINER (button), hbox);
-
-        /* Try to be smart and find a suitable icon. */
-        buf = g_strdup_printf ("stock_%s", key);
-        pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (queue->priv->dock))),
-                                           buf,
-                                           16,
-                                           GTK_ICON_LOOKUP_USE_BUILTIN,
-                                           NULL);
-        g_free (buf);
-
-        if (pixbuf != NULL) {
-                GtkWidget *image = gtk_image_new_from_pixbuf (pixbuf);
-                gtk_widget_show (image);
-                gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
-                gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.5);
-        }
-
-        label = gtk_label_new (NULL);
-        gtk_widget_show (label);
-        gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
-        gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
-        buf = g_strdup_printf ("<small>%s</small>", text);
-        gtk_label_set_markup (GTK_LABEL (label), buf);
-        g_free (buf);
-
-        g_object_set_data_full (G_OBJECT (button),
-                                "_action_key", g_strdup (key), g_free);
-        g_signal_connect (G_OBJECT (button),
-                          "button-release-event",
-                          G_CALLBACK (on_action_clicked),
-                          notification);
-        return button;
-}
-
-static gboolean
-on_button_release (GtkWidget      *widget,
-                   GdkEventButton *event,
-                   NdNotification *notification)
-{
-        g_debug ("CLICK");
-        nd_notification_action_invoked (notification, "default");
-
-        return FALSE;
-}
-
-static GtkWidget *
-create_notification_box (NdQueue        *queue,
-                         NdNotification *n)
-{
-        GtkWidget     *event_box;
-        GtkWidget     *box;
-        GtkWidget     *iconbox;
-        GtkWidget     *icon;
-        GtkWidget     *image;
-        GtkWidget     *content_hbox;
-        GtkWidget     *actions_box;
-        GtkWidget     *vbox;
-        GtkWidget     *summary_label;
-        GtkWidget     *body_label;
-        GtkWidget     *alignment;
-        GtkWidget     *close_button;
-        AtkObject     *atkobj;
-        GtkRcStyle    *rcstyle;
-        char          *str;
-        char          *quoted;
-        GtkRequisition req;
-        int            summary_width;
-        gboolean       have_icon;
-        gboolean       have_body;
-        gboolean       have_actions;
-        GdkPixbuf     *pixbuf;
-        char         **actions;
-        int            i;
-
-        event_box = gtk_event_box_new ();
-        gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box),
-                                          FALSE);
-        g_signal_connect (event_box, "button-release-event", G_CALLBACK (on_button_release), n);
-
-        box = gtk_hbox_new (FALSE, 6);
-        gtk_container_add (GTK_CONTAINER (event_box), box);
-        gtk_widget_show (box);
-
-        /* First row (icon, vbox, close) */
-        iconbox = gtk_alignment_new (0.5, 0, 0, 0);
-        gtk_widget_show (iconbox);
-        gtk_alignment_set_padding (GTK_ALIGNMENT (iconbox),
-                                   5, 0, 0, 0);
-        gtk_box_pack_start (GTK_BOX (box),
-                            iconbox,
-                            FALSE, FALSE, 0);
-        gtk_widget_set_size_request (iconbox, BODY_X_OFFSET, -1);
-
-        icon = gtk_image_new ();
-        gtk_widget_show (icon);
-        gtk_container_add (GTK_CONTAINER (iconbox), icon);
-
-        vbox = gtk_vbox_new (FALSE, 6);
-        gtk_widget_show (vbox);
-        gtk_box_pack_start (GTK_BOX (box), vbox, TRUE, TRUE, 0);
-        gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
-
-        /* Add the close button */
-        alignment = gtk_alignment_new (0.5, 0, 0, 0);
-        gtk_widget_show (alignment);
-        gtk_box_pack_start (GTK_BOX (box), alignment, FALSE, FALSE, 0);
-
-        close_button = gtk_button_new ();
-        gtk_widget_show (close_button);
-        gtk_container_add (GTK_CONTAINER (alignment), close_button);
-        gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
-        gtk_container_set_border_width (GTK_CONTAINER (close_button), 0);
-        g_signal_connect (G_OBJECT (close_button),
-                          "clicked",
-                          G_CALLBACK (on_close_button_clicked),
-                          n);
-
-        rcstyle = gtk_rc_style_new ();
-        rcstyle->xthickness = rcstyle->ythickness = 0;
-        gtk_widget_modify_style (close_button, rcstyle);
-        g_object_unref (rcstyle);
-
-        atkobj = gtk_widget_get_accessible (close_button);
-        atk_action_set_description (ATK_ACTION (atkobj), 0,
-                                    "Closes the notification.");
-        atk_object_set_name (atkobj, "");
-        atk_object_set_description (atkobj, "Closes the notification.");
-
-        image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
-        gtk_widget_show (image);
-        gtk_container_add (GTK_CONTAINER (close_button), image);
-
-        /* center vbox */
-        summary_label = gtk_label_new (NULL);
-        gtk_widget_show (summary_label);
-        gtk_box_pack_start (GTK_BOX (vbox), summary_label, TRUE, TRUE, 0);
-        gtk_misc_set_alignment (GTK_MISC (summary_label), 0, 0);
-        gtk_label_set_line_wrap (GTK_LABEL (summary_label), TRUE);
-
-        atkobj = gtk_widget_get_accessible (summary_label);
-        atk_object_set_description (atkobj, "Notification summary text.");
-
-        content_hbox = gtk_hbox_new (FALSE, 6);
-        gtk_widget_show (content_hbox);
-        gtk_box_pack_start (GTK_BOX (vbox), content_hbox, FALSE, FALSE, 0);
-
-        vbox = gtk_vbox_new (FALSE, 6);
-
-        gtk_widget_show (vbox);
-        gtk_box_pack_start (GTK_BOX (content_hbox), vbox, TRUE, TRUE, 0);
-
-        body_label = gtk_label_new (NULL);
-        gtk_widget_show (body_label);
-        gtk_box_pack_start (GTK_BOX (vbox), body_label, TRUE, TRUE, 0);
-        gtk_misc_set_alignment (GTK_MISC (body_label), 0, 0);
-        gtk_label_set_line_wrap (GTK_LABEL (body_label), TRUE);
-
-        atkobj = gtk_widget_get_accessible (body_label);
-        atk_object_set_description (atkobj, "Notification body text.");
-
-        alignment = gtk_alignment_new (1, 0.5, 0, 0);
-        gtk_widget_show (alignment);
-        gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, TRUE, 0);
-
-        actions_box = gtk_hbox_new (FALSE, 6);
-        gtk_widget_show (actions_box);
-        gtk_container_add (GTK_CONTAINER (alignment), actions_box);
-
-        /* Add content */
-
-        have_icon = FALSE;
-        have_body = FALSE;
-        have_actions = FALSE;
-
-        /* image */
-        pixbuf = nd_notification_load_image (n, IMAGE_SIZE);
-        if (pixbuf != NULL) {
-                gtk_image_set_from_pixbuf (GTK_IMAGE (icon), pixbuf);
-
-                g_object_unref (G_OBJECT (pixbuf));
-                have_icon = TRUE;
-        }
-
-        /* summary */
-        quoted = g_markup_escape_text (nd_notification_get_summary (n), -1);
-        str = g_strdup_printf ("<b><big>%s</big></b>", quoted);
-        g_free (quoted);
-
-        gtk_label_set_markup (GTK_LABEL (summary_label), str);
-        g_free (str);
-
-        gtk_widget_size_request (close_button, &req);
-        /* -1: main_vbox border width
-           -10: vbox border width
-           -6: spacing for hbox */
-        summary_width = WIDTH - (1*2) - (10*2) - BODY_X_OFFSET - req.width - (6*2);
-
-        gtk_widget_set_size_request (summary_label,
-                                     summary_width,
-                                     -1);
-
-        /* body */
-        gtk_label_set_markup (GTK_LABEL (body_label), nd_notification_get_body (n));
-
-        if (str != NULL && *str != '\0') {
-                gtk_widget_set_size_request (body_label,
-                                             summary_width,
-                                             -1);
-                have_body = TRUE;
-        }
-
-        /* actions */
-        actions = nd_notification_get_actions (n);
-        for (i = 0; actions[i] != NULL; i += 2) {
-                char *l = actions[i + 1];
-
-                if (l == NULL) {
-                        g_warning ("Label not found for action %s. "
-                                   "The protocol specifies that a label must "
-                                   "follow an action in the actions array",
-                                   actions[i]);
-
-                        break;
-                }
-
-                if (strcasecmp (actions[i], "default") != 0) {
-                        GtkWidget *button;
-
-                        button = create_notification_action (queue,
-                                                             n,
-                                                             l,
-                                                             actions[i]);
-                        gtk_box_pack_start (GTK_BOX (actions_box), button, FALSE, FALSE, 0);
-
-                        have_actions = TRUE;
-                }
-        }
-
-        if (have_icon || have_body || have_actions) {
-                gtk_widget_show (content_hbox);
-        } else {
-                gtk_widget_hide (content_hbox);
-        }
-
-        return event_box;
-}
-
-static void
 update_dock (NdQueue *queue)
 {
         GtkWidget   *child;
@@ -974,13 +688,13 @@ update_dock (NdQueue *queue)
         list = g_list_sort (list, (GCompareFunc)collate_notifications);
 
         for (l = list; l != NULL; l = l->next) {
-                NdNotification *n = l->data;
-                GtkWidget      *hbox;
-                GtkWidget      *sep;
+                NdNotification    *n = l->data;
+                NdNotificationBox *box;
+                GtkWidget         *sep;
 
-                hbox = create_notification_box (queue, n);
-                gtk_widget_show (hbox);
-                gtk_box_pack_start (GTK_BOX (child), hbox, FALSE, FALSE, 0);
+                box = nd_notification_box_new_for_notification (n);
+                gtk_widget_show (GTK_WIDGET (box));
+                gtk_box_pack_start (GTK_BOX (child), GTK_WIDGET (box), FALSE, FALSE, 0);
 
                 sep = gtk_hseparator_new ();
                 gtk_widget_show (sep);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]