[notification-daemon] Add a new theme called Slider



commit bd6d59af670ee5f479df228b16d5e1db112976aa
Author: William Jon McCann <jmccann redhat com>
Date:   Sat Jan 16 12:46:50 2010 -0500

    Add a new theme called Slider

 configure.ac                  |   25 +-
 src/themes/Makefile.am        |    3 +-
 src/themes/slider/Makefile.am |   13 +
 src/themes/slider/theme.c     |  917 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 953 insertions(+), 5 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 633e94b..3bdf127 100644
--- a/configure.ac
+++ b/configure.ac
@@ -69,12 +69,27 @@ AC_EXEEXT
 AM_PROG_LIBTOOL
 IT_PROG_INTLTOOL([0.35.0])
 
+REQ_GTK_VERSION=2.18.0
+
+dnl ---------------------------------------------------------------------------
+dnl Requirements for the themes
+dnl ---------------------------------------------------------------------------
+
+PKG_CHECK_MODULES(THEME,
+  gtk+-2.0 >= $REQ_GTK_VERSION
+)
+AC_SUBST(THEME_CFLAGS)
+AC_SUBST(THEME_LIBS)
+
+dnl ---------------------------------------------------------------------------
+dnl Requirements for the daemon
+dnl ---------------------------------------------------------------------------
+
 GETTEXT_PACKAGE=notification-daemon
 AC_SUBST(GETTEXT_PACKAGE)
 AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE", [Gettext package])
 AM_GLIB_GNU_GETTEXT
 
-REQ_GTK_VERSION=2.18.0
 REQ_GLIB_VERSION=$REQ_GTK_VERSION
 REQ_DBUS_VERSION=0.36
 REQ_LIBCANBERRA_GTK_VERSION=0.4
@@ -91,6 +106,10 @@ PKG_CHECK_MODULES(NOTIFICATION_DAEMON, $pkg_modules)
 AC_SUBST(NOTIFICATION_DAEMON_CFLAGS)
 AC_SUBST(NOTIFICATION_DAEMON_LIBS)
 
+dnl ---------------------------------------------------------------------------
+dnl Requirements for the setup tool
+dnl ---------------------------------------------------------------------------
+
 PKG_CHECK_MODULES(NOTIFICATION_CAPPLET, glib-2.0 >= $REQ_GLIB_VERSION gtk+-2.0 >= $REQ_GTK_VERSION libglade-2.0 gconf-2.0 libnotify dbus-1 dbus-glib-1)
 AC_SUBST(NOTIFICATION_CAPPLET_CFLAGS)
 AC_SUBST(NOTIFICATION_CAPPLET_LIBS)
@@ -203,9 +222,6 @@ fi
 
 AC_SUBST(CFLAGS)
 
-dnl ################################################################
-dnl # Output the Makefiles
-dnl ################################################################
 AC_CONFIG_FILES([
 Makefile
 data/Makefile
@@ -216,6 +232,7 @@ src/daemon/Makefile
 src/capplet/Makefile
 src/themes/Makefile
 src/themes/bubble/Makefile
+src/themes/slider/Makefile
 src/themes/standard/Makefile
 ])
 
diff --git a/src/themes/Makefile.am b/src/themes/Makefile.am
index 6699d81..18a53b4 100644
--- a/src/themes/Makefile.am
+++ b/src/themes/Makefile.am
@@ -1,2 +1,3 @@
-SUBDIRS = standard
+SUBDIRS = slider standard
+
 DIST_SUBDIRS = $(SUBDIRS) bubble
diff --git a/src/themes/slider/Makefile.am b/src/themes/slider/Makefile.am
new file mode 100644
index 0000000..58913bb
--- /dev/null
+++ b/src/themes/slider/Makefile.am
@@ -0,0 +1,13 @@
+NULL =
+
+enginedir = $(libdir)/notification-daemon-1.0/engines
+engine_LTLIBRARIES = libslider.la
+
+AM_CPPFLAGS = $(THEME_CFLAGS)
+
+libslider_la_SOURCES = theme.c
+
+libslider_la_LDFLAGS = -module -avoid-version
+libslider_la_LIBADD =	\
+	$(THEME_LIBS)	\
+	$(NULL)
diff --git a/src/themes/slider/theme.c b/src/themes/slider/theme.c
new file mode 100644
index 0000000..88b4e07
--- /dev/null
+++ b/src/themes/slider/theme.c
@@ -0,0 +1,917 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2006-2007 Christian Hammond <chipx86 chipx86 com>
+ * Copyright (C) 2009 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 <gtk/gtk.h>
+
+typedef void (*ActionInvokedCb) (GtkWindow *nw, const char *key);
+typedef void (*UrlClickedCb)    (GtkWindow *nw, const char *url);
+
+typedef struct
+{
+        GtkWidget *win;
+        GtkWidget *main_hbox;
+        GtkWidget *iconbox;
+        GtkWidget *icon;
+        GtkWidget *content_hbox;
+        GtkWidget *summary_label;
+        GtkWidget *close_button;
+        GtkWidget *body_label;
+        GtkWidget *actions_box;
+        GtkWidget *last_sep;
+        GtkWidget *pie_countdown;
+
+        gboolean has_arrow;
+        gboolean composited;
+
+        int width;
+        int height;
+
+        guchar urgency;
+        glong timeout;
+        glong remaining;
+
+        UrlClickedCb url_clicked;
+} WindowData;
+
+enum {
+        URGENCY_LOW,
+        URGENCY_NORMAL,
+        URGENCY_CRITICAL
+};
+
+#define WIDTH         400
+#define DEFAULT_X0    0
+#define DEFAULT_Y0    0
+#define DEFAULT_RADIUS 16
+#define IMAGE_SIZE    32
+#define PIE_RADIUS    12
+#define PIE_WIDTH     (2 * PIE_RADIUS)
+#define PIE_HEIGHT    (2 * PIE_RADIUS)
+#define BODY_X_OFFSET (IMAGE_SIZE + 8)
+#define BACKGROUND_ALPHA    0.90
+
+#if GTK_CHECK_VERSION(2, 10, 0)
+# define USE_COMPOSITE
+#endif
+
+static void
+draw_round_rect (cairo_t* cr,
+                 gdouble  aspect,
+                 gdouble  x,
+                 gdouble  y,
+                 gdouble  corner_radius,
+                 gdouble  width,
+                 gdouble  height)
+{
+        gdouble radius = corner_radius / aspect;
+
+        cairo_move_to (cr, x + radius, y);
+
+        // top-right, left of the corner
+        cairo_line_to (cr,
+                       x + width - radius,
+                       y);
+
+        // top-right, below the corner
+        cairo_arc (cr,
+                   x + width - radius,
+                   y + radius,
+                   radius,
+                   -90.0f * G_PI / 180.0f,
+                   0.0f * G_PI / 180.0f);
+
+        // bottom-right, above the corner
+        cairo_line_to (cr,
+                       x + width,
+                       y + height - radius);
+
+        // bottom-right, left of the corner
+        cairo_arc (cr,
+                   x + width - radius,
+                   y + height - radius,
+                   radius,
+                   0.0f * G_PI / 180.0f,
+                   90.0f * G_PI / 180.0f);
+
+        // bottom-left, right of the corner
+        cairo_line_to (cr,
+                       x + radius,
+                       y + height);
+
+        // bottom-left, above the corner
+        cairo_arc (cr,
+                   x + radius,
+                   y + height - radius,
+                   radius,
+                   90.0f * G_PI / 180.0f,
+                   180.0f * G_PI / 180.0f);
+
+        // top-left, below the corner
+        cairo_line_to (cr,
+                       x,
+                       y + radius);
+
+        // top-left, right of the corner
+        cairo_arc (cr,
+                   x + radius,
+                   y + radius,
+                   radius,
+                   180.0f * G_PI / 180.0f,
+                   270.0f * G_PI / 180.0f);
+}
+
+static void
+fill_background (GtkWidget  *widget,
+                 WindowData *windata,
+                 cairo_t    *cr)
+{
+        GdkColor  color;
+        double    r, g, b;
+
+        draw_round_rect (cr,
+                         1.0f,
+                         DEFAULT_X0 + 1,
+                         DEFAULT_Y0 + 1,
+                         DEFAULT_RADIUS,
+                         widget->allocation.width - 2,
+                         widget->allocation.height - 2);
+
+        color = widget->style->bg [GTK_STATE_NORMAL];
+        r = (float)color.red / 65535.0;
+        g = (float)color.green / 65535.0;
+        b = (float)color.blue / 65535.0;
+        cairo_set_source_rgba (cr, r, g, b, BACKGROUND_ALPHA);
+        cairo_fill_preserve (cr);
+
+        /* Should we show urgency somehow?  Probably doesn't
+         * have any meaningful value to the user... */
+
+        color = widget->style->text_aa [GTK_STATE_NORMAL];
+        r = (float) color.red / 65535.0;
+        g = (float) color.green / 65535.0;
+        b = (float) color.blue / 65535.0;
+        cairo_set_source_rgba (cr, r, g, b, BACKGROUND_ALPHA / 2);
+        cairo_set_line_width (cr, 1);
+        cairo_stroke (cr);
+}
+
+static void
+update_shape (WindowData *windata)
+{
+        GdkBitmap *mask;
+        cairo_t   *cr;
+
+        if (windata->composited) {
+                gtk_widget_shape_combine_mask (windata->win, NULL, 0, 0);
+                return;
+        }
+
+        mask = (GdkBitmap *) gdk_pixmap_new (NULL, windata->width, windata->height, 1);
+        if (mask == NULL) {
+                return;
+        }
+
+        cr = gdk_cairo_create (mask);
+        if (cairo_status (cr) == CAIRO_STATUS_SUCCESS) {
+                cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
+                cairo_paint (cr);
+
+                cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+                cairo_set_source_rgb (cr, 1.0f, 1.0f, 1.0f);
+                draw_round_rect (cr,
+                                 1.0f,
+                                 DEFAULT_X0,
+                                 DEFAULT_Y0,
+                                 DEFAULT_RADIUS,
+                                 windata->width,
+                                 windata->height);
+                cairo_fill (cr);
+
+                gtk_widget_shape_combine_mask (windata->win, mask, 0, 0);
+        }
+        cairo_destroy (cr);
+
+        g_object_unref (mask);
+}
+
+static gboolean
+paint_window (GtkWidget     *widget,
+              GdkEventExpose *event,
+              WindowData     *windata)
+{
+        cairo_t         *context;
+        cairo_surface_t *surface;
+        cairo_t         *cr;
+
+        if (windata->width == 0) {
+                windata->width = windata->win->allocation.width;
+                windata->height = windata->win->allocation.height;
+        }
+
+        context = gdk_cairo_create (widget->window);
+
+        cairo_set_operator (context, CAIRO_OPERATOR_SOURCE);
+        surface = cairo_surface_create_similar (cairo_get_target (context),
+                                                CAIRO_CONTENT_COLOR_ALPHA,
+                                                widget->allocation.width,
+                                                widget->allocation.height);
+        cr = cairo_create (surface);
+
+        fill_background (widget, windata, cr);
+
+        cairo_destroy (cr);
+        cairo_set_source_surface (context, surface, 0, 0);
+        cairo_paint (context);
+        cairo_surface_destroy (surface);
+        cairo_destroy (context);
+
+        update_shape (windata);
+
+        return FALSE;
+}
+
+static void
+destroy_windata(WindowData *windata)
+{
+        g_free (windata);
+}
+
+static void
+update_content_hbox_visibility (WindowData *windata)
+{
+        /*
+         * This is all a hack, but until we have a libview-style ContentBox,
+         * it'll just have to do.
+         */
+        if (GTK_WIDGET_VISIBLE (windata->icon)
+            || GTK_WIDGET_VISIBLE (windata->body_label)
+            || GTK_WIDGET_VISIBLE (windata->actions_box)) {
+                gtk_widget_show (windata->content_hbox);
+        } else {
+                gtk_widget_hide (windata->content_hbox);
+        }
+}
+
+static gboolean
+on_configure_event (GtkWidget         *nw,
+                    GdkEventConfigure *event,
+                    WindowData        *windata)
+{
+        windata->width = event->width;
+        windata->height = event->height;
+
+        gtk_widget_queue_draw (nw);
+
+        return FALSE;
+}
+
+static void
+color_reverse (const GdkColor *a,
+               GdkColor       *b)
+{
+        gdouble red;
+        gdouble green;
+        gdouble blue;
+        gdouble h;
+        gdouble s;
+        gdouble v;
+
+        red = (gdouble) a->red / 65535.0;
+        green = (gdouble) a->green / 65535.0;
+        blue = (gdouble) a->blue / 65535.0;
+
+        gtk_rgb_to_hsv (red, green, blue, &h, &s, &v);
+
+        /* pivot brightness around the center */
+        v = 0.5 + (0.5 - v);
+        if (v > 1.0)
+                v = 1.0;
+        else if (v < 0.0)
+                v = 0.0;
+
+        /* reduce saturation by 50% */
+        s *= 0.5;
+
+        gtk_hsv_to_rgb (h, s, v, &red, &green, &blue);
+
+        b->red = red * 65535.0;
+        b->green = green * 65535.0;
+        b->blue = blue * 65535.0;
+}
+
+static void
+override_style (GtkWidget *widget,
+                GtkStyle  *previous_style)
+{
+        GtkStateType state;
+        GtkStyle    *style;
+        GdkColor     fg;
+        GdkColor     bg;
+
+        style = gtk_style_copy (widget->style);
+
+        if (previous_style == NULL
+            || (previous_style != NULL
+                && (previous_style->bg[GTK_STATE_NORMAL].red != style->bg[GTK_STATE_NORMAL].red
+                    || previous_style->bg[GTK_STATE_NORMAL].green != style->bg[GTK_STATE_NORMAL].green
+                    || previous_style->bg[GTK_STATE_NORMAL].blue != style->bg[GTK_STATE_NORMAL].blue))) {
+
+                state = (GtkStateType) 0;
+                while (state < (GtkStateType) G_N_ELEMENTS (widget->style->bg))  {
+                        color_reverse (&style->bg[state], &bg);
+                        gtk_widget_modify_bg (widget, state, &bg);
+                        state++;
+                }
+
+        }
+
+        if (previous_style == NULL
+            || (previous_style != NULL
+                && (previous_style->fg[GTK_STATE_NORMAL].red != style->fg[GTK_STATE_NORMAL].red
+                    || previous_style->fg[GTK_STATE_NORMAL].green != style->fg[GTK_STATE_NORMAL].green
+                    || previous_style->fg[GTK_STATE_NORMAL].blue != style->fg[GTK_STATE_NORMAL].blue))) {
+
+                state = (GtkStateType) 0;
+                while (state < (GtkStateType) G_N_ELEMENTS (widget->style->fg)) {
+                        color_reverse (&style->fg[state], &fg);
+                        gtk_widget_modify_fg (widget, state, &fg);
+                        state++;
+                }
+        }
+
+        g_object_unref (style);
+}
+
+static void
+on_style_set (GtkWidget  *widget,
+              GtkStyle   *previous_style,
+              WindowData *windata)
+{
+        g_signal_handlers_block_by_func (G_OBJECT(widget), on_style_set, windata);
+        override_style (widget, previous_style);
+        gtk_widget_queue_draw (widget);
+
+        g_signal_handlers_unblock_by_func (G_OBJECT(widget), on_style_set, windata);
+}
+
+static void
+on_composited_changed (GtkWidget  *window,
+                       WindowData *windata)
+{
+        windata->composited = gdk_screen_is_composited (gtk_widget_get_screen (window));
+        update_shape (windata);
+}
+
+GtkWindow *
+create_notification (UrlClickedCb url_clicked)
+{
+        GtkWidget   *win;
+        GtkWidget   *drawbox;
+        GtkWidget   *main_vbox;
+        GtkWidget   *vbox;
+        GtkWidget   *close_button;
+        GtkWidget   *image;
+        GtkWidget   *alignment;
+        AtkObject   *atkobj;
+        GtkRcStyle  *rcstyle;
+        WindowData  *windata;
+#ifdef USE_COMPOSITE
+        GdkColormap *colormap;
+        GdkScreen   *screen;
+#endif
+
+        windata = g_new0 (WindowData, 1);
+        windata->urgency = URGENCY_NORMAL;
+        windata->url_clicked = url_clicked;
+
+        win = gtk_window_new (GTK_WINDOW_POPUP);
+        g_signal_connect (G_OBJECT (win),
+                          "style-set",
+                          G_CALLBACK (on_style_set),
+                          windata);
+        windata->win = win;
+
+        windata->composited = FALSE;
+#ifdef USE_COMPOSITE
+        screen = gtk_window_get_screen (GTK_WINDOW (win));
+        colormap = gdk_screen_get_rgba_colormap (screen);
+        if (colormap != NULL) {
+                gtk_widget_set_colormap (win, colormap);
+                if (gdk_screen_is_composited (screen)) {
+                        windata->composited = TRUE;
+                }
+        }
+        g_signal_connect (win,
+                          "composited-changed",
+                          G_CALLBACK (on_composited_changed),
+                          windata);
+#endif
+
+        gtk_window_set_title (GTK_WINDOW (win), "Notification");
+        gtk_window_set_type_hint (GTK_WINDOW (win),
+                                  GDK_WINDOW_TYPE_HINT_NOTIFICATION);
+        gtk_widget_add_events (win, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
+        gtk_widget_realize (win);
+
+        g_object_set_data_full (G_OBJECT (win),
+                                "windata", windata,
+                                (GDestroyNotify)destroy_windata);
+        atk_object_set_role (gtk_widget_get_accessible (win), ATK_ROLE_ALERT);
+
+        g_signal_connect (G_OBJECT (win),
+                          "configure-event",
+                          G_CALLBACK (on_configure_event),
+                          windata);
+
+        /*
+         * For some reason, there are occasionally graphics glitches when
+         * repainting the window. Despite filling the window with a background
+         * color, parts of the other windows on the screen or the shadows around
+         * notifications will appear on the notification. Somehow, adding this
+         * eventbox makes that problem just go away. Whatever works for now.
+         */
+        drawbox = gtk_event_box_new ();
+        gtk_widget_show (drawbox);
+        gtk_container_add (GTK_CONTAINER (win), drawbox);
+
+        main_vbox = gtk_vbox_new (FALSE, 0);
+        g_signal_connect (G_OBJECT (main_vbox),
+                          "style-set",
+                          G_CALLBACK (on_style_set),
+                          windata);
+        gtk_widget_show (main_vbox);
+        gtk_container_add (GTK_CONTAINER (drawbox), main_vbox);
+        gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
+        g_signal_connect (G_OBJECT (main_vbox),
+                          "expose-event",
+                          G_CALLBACK (paint_window),
+                          windata);
+
+        windata->main_hbox = gtk_hbox_new (FALSE, 0);
+        gtk_widget_show (windata->main_hbox);
+        gtk_box_pack_start (GTK_BOX (main_vbox),
+                            windata->main_hbox,
+                            FALSE, FALSE, 0);
+
+        /* First row (icon, vbox, close) */
+        windata->iconbox = gtk_hbox_new (FALSE, 0);
+        gtk_widget_show (windata->iconbox);
+        gtk_box_pack_start (GTK_BOX (windata->main_hbox),
+                            windata->iconbox,
+                            FALSE, FALSE, 0);
+        gtk_widget_set_size_request (windata->iconbox, BODY_X_OFFSET, -1);
+
+        windata->icon = gtk_image_new ();
+        gtk_box_pack_start (GTK_BOX (windata->iconbox),
+                            windata->icon,
+                            TRUE, TRUE, 0);
+        gtk_misc_set_alignment (GTK_MISC (windata->icon), 0.5, 0);
+
+        vbox = gtk_vbox_new (FALSE, 6);
+        gtk_widget_show (vbox);
+        gtk_box_pack_start (GTK_BOX (windata->main_hbox), 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 (windata->main_hbox), alignment, FALSE, FALSE, 0);
+
+        close_button = gtk_button_new ();
+        g_signal_connect (G_OBJECT (close_button),
+                          "style-set",
+                          G_CALLBACK (on_style_set),
+                          windata);
+        windata->close_button = close_button;
+        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_swapped (G_OBJECT (close_button),
+                                  "clicked",
+                                  G_CALLBACK (gtk_widget_destroy),
+                                  win);
+
+        rcstyle = gtk_rc_style_new ();
+        rcstyle->xthickness = rcstyle->ythickness = 0;
+        gtk_widget_modify_style (close_button, rcstyle);
+        gtk_rc_style_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 */
+        windata->summary_label = gtk_label_new (NULL);
+        g_signal_connect (G_OBJECT (windata->summary_label),
+                          "style-set",
+                          G_CALLBACK (on_style_set),
+                          windata);
+        gtk_widget_show (windata->summary_label);
+        gtk_box_pack_start (GTK_BOX (vbox), windata->summary_label, TRUE, TRUE, 0);
+        gtk_misc_set_alignment (GTK_MISC (windata->summary_label), 0, 0);
+        gtk_label_set_line_wrap (GTK_LABEL (windata->summary_label), TRUE);
+
+        atkobj = gtk_widget_get_accessible (windata->summary_label);
+        atk_object_set_description (atkobj, "Notification summary text.");
+
+        windata->content_hbox = gtk_hbox_new (FALSE, 6);
+        gtk_box_pack_start (GTK_BOX (vbox), windata->content_hbox, FALSE, FALSE, 0);
+
+
+        vbox = gtk_vbox_new (FALSE, 6);
+        gtk_widget_show (vbox);
+        gtk_box_pack_start (GTK_BOX (windata->content_hbox), vbox, TRUE, TRUE, 0);
+
+        windata->body_label = gtk_label_new (NULL);
+        g_signal_connect (G_OBJECT (windata->body_label),
+                          "style-set",
+                          G_CALLBACK (on_style_set),
+                          windata);
+        gtk_box_pack_start (GTK_BOX (vbox), windata->body_label, TRUE, TRUE, 0);
+        gtk_misc_set_alignment (GTK_MISC (windata->body_label), 0, 0);
+        gtk_label_set_line_wrap (GTK_LABEL (windata->body_label), TRUE);
+        g_signal_connect_swapped (G_OBJECT (windata->body_label),
+                                  "activate-link",
+                                  G_CALLBACK (windata->url_clicked),
+                                  win);
+
+        atkobj = gtk_widget_get_accessible (windata->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);
+
+        windata->actions_box = gtk_hbox_new (FALSE, 6);
+        gtk_container_add (GTK_CONTAINER (alignment), windata->actions_box);
+
+        return GTK_WINDOW (win);
+}
+
+void
+set_notification_hints (GtkWindow  *nw,
+                        GHashTable *hints)
+{
+        WindowData *windata = g_object_get_data (G_OBJECT(nw), "windata");
+        GValue     *value;
+
+        g_assert (windata != NULL);
+
+        value = (GValue *)g_hash_table_lookup (hints, "urgency");
+
+        if (value != NULL && G_VALUE_HOLDS_UCHAR (value)) {
+                windata->urgency = g_value_get_uchar (value);
+
+                if (windata->urgency == URGENCY_CRITICAL) {
+                        gtk_window_set_title (GTK_WINDOW (nw), "Critical Notification");
+                } else {
+                        gtk_window_set_title (GTK_WINDOW (nw), "Notification");
+                }
+        }
+}
+
+void
+set_notification_timeout (GtkWindow *nw,
+                          glong      timeout)
+{
+        WindowData *windata = g_object_get_data (G_OBJECT (nw), "windata");
+
+        g_assert (windata != NULL);
+
+        windata->timeout = timeout;
+}
+
+void
+notification_tick (GtkWindow *nw,
+                   glong      remaining)
+{
+        WindowData *windata = g_object_get_data(G_OBJECT (nw), "windata");
+
+        windata->remaining = remaining;
+
+        if (windata->pie_countdown != NULL) {
+                gtk_widget_queue_draw_area (windata->pie_countdown, 0, 0,
+                                            PIE_WIDTH, PIE_HEIGHT);
+        }
+}
+
+void
+set_notification_text (GtkWindow  *nw,
+                       const char *summary,
+                       const char *body)
+{
+        char *str, *quoted;
+        GtkRequisition req;
+        WindowData *windata = g_object_get_data (G_OBJECT (nw), "windata");
+
+        g_assert (windata != NULL);
+
+        quoted = g_markup_escape_text (summary, -1);
+        str = g_strdup_printf ("<b><big>%s</big></b>", quoted);
+        g_free (quoted);
+
+        gtk_label_set_markup (GTK_LABEL (windata->summary_label), str);
+        g_free (str);
+
+        gtk_label_set_markup (GTK_LABEL (windata->body_label), body);
+
+        if (body == NULL || *body == '\0') {
+                gtk_widget_hide (windata->body_label);
+        } else {
+                gtk_widget_show (windata->body_label);
+        }
+
+        update_content_hbox_visibility (windata);
+
+        if (body != NULL && *body != '\0') {
+                gtk_widget_size_request (windata->iconbox, &req);
+                gtk_widget_set_size_request (windata->body_label,
+                                             /* -1: border width for
+                                                -6: spacing for hbox */
+                                             WIDTH - (1*2) - (10*2) - req.width - 6,
+                                             -1);
+        }
+
+        gtk_widget_size_request (windata->close_button, &req);
+        gtk_widget_set_size_request (windata->summary_label,
+                                     /* -1: main_vbox border width
+                                        -10: vbox border width
+                                        -6: spacing for hbox */
+                                     WIDTH - (1*2) - (10*2) - BODY_X_OFFSET - req.width - (6*2),
+                                     -1);
+}
+
+void
+set_notification_icon (GtkWindow *nw,
+                       GdkPixbuf *pixbuf)
+{
+        WindowData *windata = g_object_get_data (G_OBJECT (nw), "windata");
+
+        g_assert (windata != NULL);
+
+        gtk_image_set_from_pixbuf (GTK_IMAGE (windata->icon), pixbuf);
+
+        if (pixbuf != NULL) {
+                int pixbuf_width = gdk_pixbuf_get_width (pixbuf);
+
+                gtk_widget_show (windata->icon);
+                gtk_widget_set_size_request (windata->iconbox,
+                                             MAX (BODY_X_OFFSET, pixbuf_width), -1);
+        } else {
+                gtk_widget_hide (windata->icon);
+                gtk_widget_set_size_request (windata->iconbox, BODY_X_OFFSET, -1);
+        }
+
+        update_content_hbox_visibility (windata);
+}
+
+void
+set_notification_arrow (GtkWidget *nw,
+                        gboolean   visible,
+                        int        x,
+                        int        y)
+{
+        WindowData *windata = g_object_get_data (G_OBJECT (nw), "windata");
+
+        g_assert (windata != NULL);
+}
+
+static gboolean
+on_countdown_expose (GtkWidget      *pie,
+                     GdkEventExpose *event,
+                     WindowData     *windata)
+{
+        GtkStyle        *style;
+        cairo_t         *context;
+        cairo_surface_t *surface;
+        cairo_t         *cr;
+        GdkColor         color;
+        double           r, g, b;
+
+        style = gtk_widget_get_style (windata->win);
+        context = gdk_cairo_create (GDK_DRAWABLE (windata->pie_countdown->window));
+        cairo_set_operator (context, CAIRO_OPERATOR_SOURCE);
+        surface = cairo_surface_create_similar (cairo_get_target (context),
+                                                CAIRO_CONTENT_COLOR_ALPHA,
+                                                pie->allocation.width,
+                                                pie->allocation.height);
+        cr = cairo_create (surface);
+
+        cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+        color = windata->win->style->bg [GTK_STATE_NORMAL];
+        r = (float)color.red / 65535.0;
+        g = (float)color.green / 65535.0;
+        b = (float)color.blue / 65535.0;
+        cairo_set_source_rgba (cr, r, g, b, BACKGROUND_ALPHA);
+        cairo_paint (cr);
+
+        if (windata->timeout > 0) {
+                gdouble pct = (gdouble) windata->remaining / (gdouble) windata->timeout;
+
+                gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]);
+
+                cairo_move_to (cr, PIE_RADIUS, PIE_RADIUS);
+                cairo_arc_negative (cr, PIE_RADIUS, PIE_RADIUS, PIE_RADIUS,
+                                    -G_PI_2, -(pct * G_PI * 2) - G_PI_2);
+                cairo_line_to (cr, PIE_RADIUS, PIE_RADIUS);
+                cairo_fill (cr);
+        }
+
+        cairo_destroy (cr);
+        cairo_set_source_surface (context, surface, 0, 0);
+        cairo_paint (context);
+        cairo_surface_destroy (surface);
+        cairo_destroy (context);
+
+        return TRUE;
+}
+
+static void
+on_action_clicked (GtkWidget      *w,
+                   GdkEventButton *event,
+                   ActionInvokedCb action_cb)
+{
+        GtkWindow *nw   = g_object_get_data (G_OBJECT (w), "_nw");
+        const char *key = g_object_get_data (G_OBJECT (w), "_action_key");
+
+        action_cb (nw, key);
+}
+
+void
+add_notification_action (GtkWindow      *nw,
+                         const char     *text,
+                         const char     *key,
+                         ActionInvokedCb cb)
+{
+        WindowData *windata = g_object_get_data (G_OBJECT (nw), "windata");
+        GtkWidget *label;
+        GtkWidget *button;
+        GtkWidget *hbox;
+        GdkPixbuf *pixbuf;
+        char *buf;
+
+        g_assert (windata != NULL);
+
+        if (!GTK_WIDGET_VISIBLE (windata->actions_box)) {
+                GtkWidget *alignment;
+
+                gtk_widget_show (windata->actions_box);
+                update_content_hbox_visibility (windata);
+
+                alignment = gtk_alignment_new (1, 0.5, 0, 0);
+                gtk_widget_show (alignment);
+                gtk_box_pack_end (GTK_BOX (windata->actions_box),
+                                  alignment,
+                                  FALSE, TRUE, 0);
+
+                windata->pie_countdown = gtk_drawing_area_new ();
+                g_signal_connect (G_OBJECT (windata->pie_countdown),
+                                  "style-set",
+                                  G_CALLBACK (on_style_set),
+                                  windata);
+
+                gtk_widget_show (windata->pie_countdown);
+                gtk_container_add (GTK_CONTAINER (alignment), windata->pie_countdown);
+                gtk_widget_set_size_request (windata->pie_countdown,
+                                             PIE_WIDTH, PIE_HEIGHT);
+                g_signal_connect (G_OBJECT (windata->pie_countdown),
+                                  "expose_event",
+                                  G_CALLBACK (on_countdown_expose),
+                                  windata);
+        }
+
+        button = gtk_button_new ();
+        g_signal_connect (G_OBJECT (button),
+                          "style-set",
+                          G_CALLBACK (on_style_set),
+                          windata);
+        gtk_widget_show (button);
+        gtk_box_pack_start (GTK_BOX (windata->actions_box), button, FALSE, FALSE, 0);
+        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 (gdk_drawable_get_screen (GTK_WIDGET (nw)->window)),
+                                           buf,
+                                           16,
+                                           GTK_ICON_LOOKUP_USE_BUILTIN,
+                                           NULL);
+        g_free(buf);
+
+        if (pixbuf != NULL) {
+                GtkWidget *image = gtk_image_new_from_pixbuf (pixbuf);
+                g_signal_connect (G_OBJECT (image),
+                                  "style-set",
+                                  G_CALLBACK (on_style_set),
+                                  windata);
+                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);
+        g_signal_connect (G_OBJECT (label),
+                          "style-set",
+                          G_CALLBACK (on_style_set),
+                          windata);
+        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 (G_OBJECT (button), "_nw", nw);
+        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), cb);
+}
+
+void
+clear_notification_actions (GtkWindow *nw)
+{
+        WindowData *windata = g_object_get_data (G_OBJECT (nw), "windata");
+
+        windata->pie_countdown = NULL;
+
+        gtk_widget_hide (windata->actions_box);
+        gtk_container_foreach (GTK_CONTAINER (windata->actions_box),
+                               (GtkCallback)gtk_object_destroy,
+                               NULL);
+}
+
+void
+move_notification (GtkWidget *nw,
+                   int        x,
+                   int        y)
+{
+        WindowData *windata = g_object_get_data (G_OBJECT (nw), "windata");
+
+        g_assert (windata != NULL);
+
+        gtk_window_move (GTK_WINDOW (nw), x, y);
+}
+
+void
+get_theme_info (char **theme_name,
+                char **theme_ver,
+                char **author,
+                char **homepage)
+{
+        *theme_name = g_strdup ("Slider");
+        *theme_ver  = g_strdup_printf ("%d.%d.%d",
+                                       NOTIFICATION_DAEMON_MAJOR_VERSION,
+                                       NOTIFICATION_DAEMON_MINOR_VERSION,
+                                       NOTIFICATION_DAEMON_MICRO_VERSION);
+        *author = g_strdup ("William Jon McCann");
+        *homepage = g_strdup ("http://www.gnome.org/";);
+}
+
+gboolean
+get_always_stack (GtkWidget *nw)
+{
+        return TRUE;
+}
+
+gboolean
+theme_check_init (unsigned int major_ver,
+                  unsigned int minor_ver,
+                  unsigned int micro_ver)
+{
+        return major_ver == 0
+                && (minor_ver > 3
+                    || (minor_ver == 3 && micro_ver >= 2));
+}



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