summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErick Pérez Castellanos <erick.red@gmail.com>2011-12-19 15:30:07 +0100
committerAlexander Larsson <alexl@redhat.com>2011-12-19 15:30:07 +0100
commit5b4091ab73512094edc3fced192982f5e309bb37 (patch)
treed81adb062e6a6928aef9eb8eab834b4987766579
parent24da24bc5ab31227fc81c9e63b3ee305ea83a127 (diff)
downloadgnome-contacts-5b4091ab73512094edc3fced192982f5e309bb37.tar.gz
Initial version of GtkNotification
-rw-r--r--src/Makefile.am2
-rw-r--r--src/gtk-notification.c530
-rw-r--r--src/gtk-notification.h58
-rw-r--r--vapi/custom.vapi8
4 files changed, 598 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 09feabc..0e81a3c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -38,6 +38,7 @@ vala_sources = \
$(NULL)
gnome_contacts_SOURCES = \
+ gtk-notification.c \
contacts-esd-setup.c \
$(vala_sources) \
$(NULL)
@@ -47,5 +48,6 @@ gnome_contacts_LDADD = $(CONTACTS_LIBS) -lm
CLEANFILES = $(vala_sources:.vala=.c) *.vapi *.stamp
EXTRA_DIST = \
+ gtk-notification.h \
contacts-esd-setup.h \
$(NULL)
diff --git a/src/gtk-notification.c b/src/gtk-notification.c
new file mode 100644
index 0000000..4b3eeea
--- /dev/null
+++ b/src/gtk-notification.c
@@ -0,0 +1,530 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtk-notification.c
+ * Copyright (C) Erick Pérez Castellanos 2011 <erick.red@gmail.com>
+ *
+ gtk-notification.c is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gtk-notification.c 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.";
+ */
+
+#include "gtk-notification.h"
+
+/**
+ * SECTION:gtknotification
+ * @short_description: Report notification messages to the user
+ * @include: gtk/gtk.h
+ * @see_also: #GtkStatusbar, #GtkMessageDialog, #GtkInfoBar
+ *
+ * #GtkNotification is a widget made for showing notifications to
+ * the user, allowing them to execute 1 action over the notification,
+ * or closing it.
+ *
+ * #GtkNotification provides one signal (#GtkNotification::actioned), for when the action button is activated.
+ * Here the user will receive the signal, and then it's up to the user to destroy the widget,
+ * or hide it.
+ * The close button destroy the notification, so you can safely connect to the
+ * #GtkWidget::destroy signal in order to know when the notification has been closed.
+ *
+ * #GtkNotification, the main difference here with some other widgets, is the timeout
+ * inside GtkNotification widget. It mean, when the no action is taken over a period of time,
+ * The widget will destroy itself.
+ *
+ */
+
+#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
+#define SHADOW_OFFSET 10
+#define SHADOW_RADIUS 5
+
+#define GTK_STYLE_PROVIDER_PRIORITY_FORCE G_MAXUINT
+#define DEFAULT_CSS \
+ ".rounded-box {\n" \
+ " border-radius: 0 0 5 5;\n" \
+ "}\n"
+
+enum {
+ PROP_0,
+ PROP_MESSAGE,
+ PROP_BUTTON_LABEL,
+ PROP_TIMEOUT
+};
+
+struct _GtkNotificationPrivate {
+ GtkWidget *message;
+ GtkWidget *action_button;
+ GtkWidget *close_button;
+
+ gchar * message_label;
+ gchar * button_label;
+ guint timeout;
+
+ guint timeout_source_id;
+};
+
+enum {
+ ACTIONED,
+ LAST_SIGNAL
+};
+
+static guint notification_signals[LAST_SIGNAL] = { 0 };
+
+static void draw_shadow_box(cairo_t *cr, GdkRectangle rect, double radius, double transparency);
+static gboolean gtk_notification_draw(GtkWidget *widget, cairo_t *cr);
+static void gtk_notification_get_preferred_width(GtkWidget *widget, gint *minimum_size, gint *natural_size);
+static void gtk_notification_get_preferred_height_for_width(GtkWidget *widget,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height);
+static void gtk_notification_get_preferred_height(GtkWidget *widget, gint *minimum_size, gint *natural_size);
+static void gtk_notification_get_preferred_width_for_height(GtkWidget *widget,
+ gint height,
+ gint *minimum_width,
+ gint *natural_width);
+static void gtk_notification_size_allocate(GtkWidget *widget, GtkAllocation *allocation);
+static void gtk_notification_update_message(GtkNotification * notification, const gchar * new_message);
+static void gtk_notification_update_button(GtkNotification * notification, const gchar * new_button_label);
+static gboolean gtk_notification_auto_destroy(gpointer user_data);
+
+/* signals handlers */
+static void gtk_notification_close_button_clicked_cb(GtkWidget * widget, gpointer user_data);
+static void gtk_notification_action_button_clicked_cb(GtkWidget * widget, gpointer user_data);
+
+G_DEFINE_TYPE(GtkNotification, gtk_notification, GTK_TYPE_BOX);
+
+static void gtk_notification_init(GtkNotification *notification) {
+ g_object_set(GTK_BOX(notification), "orientation", GTK_ORIENTATION_HORIZONTAL, "homogeneous", FALSE, "spacing", 2, NULL);
+
+ //setting fixed CSS to accomplish the border-radius seen in the mockups
+ GtkStyleProvider *provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
+ gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), provider, GTK_STYLE_PROVIDER_PRIORITY_FORCE);
+ gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(provider), DEFAULT_CSS, -1, NULL);
+
+ gtk_style_context_add_class(gtk_widget_get_style_context(GTK_WIDGET(notification)), "rounded-box");
+
+ //FIXME position should be set by properties
+ gtk_widget_set_halign(GTK_WIDGET(notification), GTK_ALIGN_CENTER);
+ gtk_widget_set_valign(GTK_WIDGET(notification), GTK_ALIGN_START);
+
+ gtk_widget_push_composite_child();
+
+ notification->priv = G_TYPE_INSTANCE_GET_PRIVATE (notification,
+ GTK_TYPE_NOTIFICATION,
+ GtkNotificationPrivate);
+
+ notification->priv->message = gtk_label_new(notification->priv->message_label);
+ gtk_widget_show(notification->priv->message);
+ notification->priv->action_button = gtk_button_new_with_label(notification->priv->button_label);
+ gtk_widget_show(notification->priv->action_button);
+ g_signal_connect(notification->priv->action_button,
+ "clicked",
+ G_CALLBACK(gtk_notification_action_button_clicked_cb),
+ notification);
+
+ notification->priv->close_button = gtk_button_new();
+ gtk_widget_show(notification->priv->close_button);
+ g_object_set(notification->priv->close_button, "relief", GTK_RELIEF_NONE, "focus-on-click", FALSE, NULL);
+ g_signal_connect(notification->priv->close_button,
+ "clicked",
+ G_CALLBACK(gtk_notification_close_button_clicked_cb),
+ notification);
+ GtkWidget * close_button_image = gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_BUTTON);
+ gtk_button_set_image(GTK_BUTTON(notification->priv->close_button), close_button_image);
+
+ gtk_box_pack_start(GTK_BOX(notification), notification->priv->message, FALSE, FALSE, SHADOW_OFFSET);
+ gtk_box_pack_end(GTK_BOX(notification), notification->priv->close_button, FALSE, TRUE, 0);
+ gtk_box_pack_end(GTK_BOX(notification), notification->priv->action_button, FALSE, TRUE, 0);
+
+ gtk_widget_pop_composite_child();
+
+ notification->priv->timeout_source_id = 0;
+}
+
+static void gtk_notification_finalize(GObject *object) {
+ g_return_if_fail(GTK_IS_NOTIFICATION (object));
+ GtkNotification * notification = GTK_NOTIFICATION(object);
+ if (notification->priv->message_label) {
+ g_free(notification->priv->message_label);
+ }
+ if (notification->priv->button_label) {
+ g_free(notification->priv->button_label);
+ }
+ if (notification->priv->timeout_source_id != 0) {
+ g_source_remove(notification->priv->timeout_source_id);
+ }
+
+ G_OBJECT_CLASS (gtk_notification_parent_class)->finalize(object);
+}
+
+static void gtk_notification_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) {
+ g_return_if_fail(GTK_IS_NOTIFICATION (object));
+ GtkNotification * notification = GTK_NOTIFICATION(object);
+
+ switch (prop_id) {
+ case PROP_MESSAGE:
+ gtk_notification_update_message(notification, g_value_get_string(value));
+ break;
+ case PROP_BUTTON_LABEL:
+ gtk_notification_update_button(notification, g_value_get_string(value));
+ break;
+ case PROP_TIMEOUT:
+ notification->priv->timeout = g_value_get_uint(value);
+ g_object_notify(object, "timeout");
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void gtk_notification_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) {
+ g_return_if_fail(GTK_IS_NOTIFICATION (object));
+ GtkNotification * notification = GTK_NOTIFICATION(object);
+
+ switch (prop_id) {
+ case PROP_MESSAGE:
+ g_value_set_string(value, notification->priv->message_label);
+ break;
+ case PROP_BUTTON_LABEL:
+ g_value_set_string(value, notification->priv->button_label);
+ break;
+ case PROP_TIMEOUT:
+ g_value_set_uint(value, notification->priv->timeout);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+ break;
+ }
+}
+
+static void gtk_notification_class_init(GtkNotificationClass *klass) {
+ GObjectClass* object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
+
+ object_class->finalize = gtk_notification_finalize;
+ object_class->set_property = gtk_notification_set_property;
+ object_class->get_property = gtk_notification_get_property;
+
+ widget_class->get_preferred_width = gtk_notification_get_preferred_width;
+ widget_class->get_preferred_height_for_width = gtk_notification_get_preferred_height_for_width;
+ widget_class->get_preferred_height = gtk_notification_get_preferred_height;
+ widget_class->get_preferred_width_for_height = gtk_notification_get_preferred_width_for_height;
+ widget_class->size_allocate = gtk_notification_size_allocate;
+
+ widget_class->draw = gtk_notification_draw;
+
+ //FIXME these properties need tranlsations
+ /**
+ * GtkNotification:message:
+ *
+ * Message shown in the notification.
+ *
+ * Since: 0.1
+ */
+ g_object_class_install_property(object_class,
+ PROP_MESSAGE,
+ g_param_spec_string("message", "message", "Message shown on the notification", "",
+ GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ /**
+ * GtkNotification:button-label:
+ *
+ * Action button label, could be one of #GtkStockItem.
+ *
+ * Since: 0.1
+ */
+ g_object_class_install_property(object_class,
+ PROP_BUTTON_LABEL,
+ g_param_spec_string("button-label",
+ "button-label",
+ "Label of the action button, if is a stock gtk indetifier, the button will get and icon too",
+ "",
+ GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ /**
+ * GtkNotification:timeout:
+ *
+ * The time it takes to hide the widget, in seconds.
+ *
+ * Since: 0.1
+ */
+ g_object_class_install_property(object_class,
+ PROP_TIMEOUT,
+ g_param_spec_uint("timeout", "timeout", "The time it takes to hide the widget, in seconds", 0, G_MAXUINT, 5,
+ GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ notification_signals[ACTIONED] = g_signal_new("actioned",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkNotificationClass, actioned),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ g_type_class_add_private(object_class, sizeof(GtkNotificationPrivate));
+}
+
+static void draw_shadow_box(cairo_t *cr, GdkRectangle rect, double radius, double transparency) {
+ cairo_pattern_t *pattern;
+ double x0, x1, x2, x3;
+ double y0, y1, y2, y3;
+
+ x0 = rect.x;
+ x1 = rect.x + radius;
+ x2 = rect.x + rect.width - radius;
+ x3 = rect.x + rect.width;
+
+ y0 = rect.y;
+ y1 = rect.y + radius;
+ y2 = rect.y + rect.height - radius;
+ y3 = rect.y + rect.height;
+
+ /* Fill non-border part */
+ cairo_set_source_rgba(cr, 0, 0, 0, transparency);
+ cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1);
+ cairo_fill(cr);
+
+ /* Upper border */
+
+ pattern = cairo_pattern_create_linear(0, y0, 0, y1);
+
+ cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0.0, 0, 0, 0.0);
+ cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0.0, 0, 0, transparency);
+
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+
+ cairo_rectangle(cr, x1, y0, x2 - x1, y1 - y0);
+ cairo_fill(cr);
+
+ /* Bottom border */
+
+ pattern = cairo_pattern_create_linear(0, y2, 0, y3);
+
+ cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0.0, 0, 0, transparency);
+ cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0.0, 0, 0, 0.0);
+
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+
+ cairo_rectangle(cr, x1, y2, x2 - x1, y3 - y2);
+ cairo_fill(cr);
+
+ /* Left border */
+
+ pattern = cairo_pattern_create_linear(x0, 0, x1, 0);
+
+ cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0.0, 0, 0, 0.0);
+ cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0.0, 0, 0, transparency);
+
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+
+ cairo_rectangle(cr, x0, y1, x1 - x0, y2 - y1);
+ cairo_fill(cr);
+
+ /* Right border */
+
+ pattern = cairo_pattern_create_linear(x2, 0, x3, 0);
+
+ cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0.0, 0, 0, transparency);
+ cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0.0, 0, 0, 0.0);
+
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+
+ cairo_rectangle(cr, x2, y1, x3 - x2, y2 - y1);
+ cairo_fill(cr);
+
+ /* NW corner */
+
+ pattern = cairo_pattern_create_radial(x1, y1, 0, x1, y1, radius);
+
+ cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0.0, 0, 0, transparency);
+ cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0.0, 0, 0, 0.0);
+
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+
+ cairo_rectangle(cr, x0, y0, x1 - x0, y1 - y0);
+ cairo_fill(cr);
+
+ /* NE corner */
+
+ pattern = cairo_pattern_create_radial(x2, y1, 0, x2, y1, radius);
+
+ cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0.0, 0, 0, transparency);
+ cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0.0, 0, 0, 0.0);
+
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+
+ cairo_rectangle(cr, x2, y0, x3 - x2, y1 - y0);
+ cairo_fill(cr);
+
+ /* SW corner */
+
+ pattern = cairo_pattern_create_radial(x1, y2, 0, x1, y2, radius);
+
+ cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0.0, 0, 0, transparency);
+ cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0.0, 0, 0, 0.0);
+
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+
+ cairo_rectangle(cr, x0, y2, x1 - x0, y3 - y2);
+ cairo_fill(cr);
+
+ /* SE corner */
+
+ pattern = cairo_pattern_create_radial(x2, y2, 0, x2, y2, radius);
+
+ cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0.0, 0, 0, transparency);
+ cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0.0, 0, 0, 0.0);
+
+ cairo_set_source(cr, pattern);
+ cairo_pattern_destroy(pattern);
+
+ cairo_rectangle(cr, x2, y2, x3 - x2, y3 - y2);
+ cairo_fill(cr);
+}
+
+static gboolean gtk_notification_draw(GtkWidget *widget, cairo_t *cr) {
+ GdkRectangle rect;
+ gtk_widget_get_allocation(widget, &rect);
+ rect.x += SHADOW_OFFSET;
+ rect.y += SHADOW_OFFSET;
+ rect.width -= SHADOW_OFFSET;
+ rect.height -= SHADOW_OFFSET;
+
+ draw_shadow_box(cr, rect, SHADOW_RADIUS, 0.4);
+
+ GtkStyleContext * context = gtk_widget_get_style_context(widget);
+ gtk_style_context_save(context);
+ //FIXME I don't see the frame drawing at all
+ gtk_render_background(context,
+ cr,
+ 0,
+ 0,
+ gtk_widget_get_allocated_width(widget) - SHADOW_OFFSET,
+ gtk_widget_get_allocated_height(widget) - SHADOW_OFFSET);
+
+ gtk_style_context_restore(context);
+
+ if (GTK_WIDGET_CLASS(gtk_notification_parent_class)->draw)
+ GTK_WIDGET_CLASS(gtk_notification_parent_class)->draw(widget, cr);
+
+ /* starting timeout when drawing the first time */
+ GtkNotification * notification = GTK_NOTIFICATION(widget);
+ if (notification->priv->timeout_source_id == 0) {
+ notification->priv->timeout_source_id = g_timeout_add(notification->priv->timeout * 1000,
+ gtk_notification_auto_destroy,
+ widget);
+ }
+ return FALSE;
+}
+
+static void gtk_notification_get_preferred_width(GtkWidget *widget, gint *minimum_size, gint *natural_size) {
+ gint parent_minimum_size, parent_natural_size;
+ GTK_WIDGET_CLASS(gtk_notification_parent_class)->get_preferred_width(widget, &parent_minimum_size, &parent_natural_size);
+
+ *minimum_size = parent_minimum_size + SHADOW_OFFSET + (SHADOW_OFFSET / 2);
+ *natural_size = parent_natural_size + SHADOW_OFFSET + (SHADOW_OFFSET / 2);
+}
+
+static void gtk_notification_get_preferred_height_for_width(GtkWidget *widget,
+ gint width,
+ gint *minimum_height,
+ gint *natural_height) {
+ gint parent_minimum_size, parent_natural_size;
+ GTK_WIDGET_CLASS(gtk_notification_parent_class)->get_preferred_height_for_width(widget,
+ width,
+ &parent_minimum_size,
+ &parent_natural_size);
+
+ *minimum_height = parent_minimum_size + 2 * SHADOW_OFFSET;
+ *natural_height = parent_natural_size + 2 * SHADOW_OFFSET;
+}
+
+static void gtk_notification_get_preferred_height(GtkWidget *widget, gint *minimum_size, gint *natural_size) {
+ gint parent_minimum_size, parent_natural_size;
+ GTK_WIDGET_CLASS(gtk_notification_parent_class)->get_preferred_height(widget, &parent_minimum_size, &parent_natural_size);
+
+ *minimum_size = parent_minimum_size + 2 * SHADOW_OFFSET;
+ *natural_size = parent_natural_size + 2 * SHADOW_OFFSET;
+}
+
+static void gtk_notification_get_preferred_width_for_height(GtkWidget *widget,
+ gint height,
+ gint *minimum_width,
+ gint *natural_width) {
+ gint parent_minimum_size, parent_natural_size;
+ GTK_WIDGET_CLASS(gtk_notification_parent_class)->get_preferred_width_for_height(widget,
+ height,
+ &parent_minimum_size,
+ &parent_natural_size);
+
+ *minimum_width = parent_minimum_size + 2 * SHADOW_OFFSET;
+ *natural_width = parent_natural_size + 2 * SHADOW_OFFSET;
+}
+
+static void gtk_notification_size_allocate(GtkWidget *widget, GtkAllocation *allocation) {
+ GtkAllocation parent_allocation;
+ parent_allocation.x = allocation->x + (SHADOW_OFFSET / 2);
+ parent_allocation.y = allocation->y + (SHADOW_OFFSET / 2);
+ parent_allocation.width = allocation->width - 2 * SHADOW_OFFSET;
+ parent_allocation.height = allocation->height - 2 * SHADOW_OFFSET;
+
+ GTK_WIDGET_CLASS(gtk_notification_parent_class)->size_allocate(widget, &parent_allocation);
+
+ gtk_widget_set_allocation(widget, allocation);
+}
+
+static void gtk_notification_update_message(GtkNotification * notification, const gchar * new_message) {
+ g_free(notification->priv->message_label);
+ notification->priv->message_label = g_strdup(new_message);
+ g_object_notify(G_OBJECT(notification), "message");
+
+ gtk_label_set_text(GTK_LABEL(notification->priv->message), notification->priv->message_label);
+}
+
+static void gtk_notification_update_button(GtkNotification * notification, const gchar * new_button_label) {
+ g_free(notification->priv->button_label);
+ notification->priv->button_label = g_strdup(new_button_label);
+ g_object_notify(G_OBJECT(notification), "button-label");
+
+ gtk_button_set_label(GTK_BUTTON(notification->priv->action_button), notification->priv->button_label);
+ gtk_button_set_use_stock(GTK_BUTTON(notification->priv->action_button), TRUE);
+}
+
+static gboolean gtk_notification_auto_destroy(gpointer user_data) {
+ GtkWidget * notification = GTK_WIDGET(user_data);
+ gtk_widget_destroy(notification);
+ return FALSE;
+}
+
+static void gtk_notification_close_button_clicked_cb(GtkWidget * widget, gpointer user_data) {
+ GtkNotification * notification = GTK_NOTIFICATION(user_data);
+ g_source_remove(notification->priv->timeout_source_id);
+ notification->priv->timeout_source_id = 0;
+
+ gtk_widget_destroy(GTK_WIDGET(notification));
+}
+
+static void gtk_notification_action_button_clicked_cb(GtkWidget * widget, gpointer user_data) {
+ g_signal_emit_by_name(user_data, "actioned", NULL);
+}
+
+GtkWidget * gtk_notification_new(gchar * message, gchar * action) {
+ return g_object_new(GTK_TYPE_NOTIFICATION, "message", message, "button-label", action, NULL);
+}
diff --git a/src/gtk-notification.h b/src/gtk-notification.h
new file mode 100644
index 0000000..f9f9ce4
--- /dev/null
+++ b/src/gtk-notification.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+ * gtk-notification.c
+ * Copyright (C) Erick Pérez Castellanos 2011 <erick.red@gmail.com>
+ *
+ gtk-notification.c is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gtk-notification.c 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.";
+ */
+
+#ifndef _GTK_NOTIFICATION_H_
+#define _GTK_NOTIFICATION_H_
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_NOTIFICATION (gtk_notification_get_type ())
+#define GTK_NOTIFICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_NOTIFICATION, GtkNotification))
+#define GTK_NOTIFICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_NOTIFICATION, GtkNotificationClass))
+#define GTK_IS_NOTIFICATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_NOTIFICATION))
+#define GTK_IS_NOTIFICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_NOTIFICATION))
+#define GTK_NOTIFICATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_NOTIFICATION, GtkNotificationClass))
+
+typedef struct _GtkNotificationPrivate GtkNotificationPrivate;
+typedef struct _GtkNotificationClass GtkNotificationClass;
+typedef struct _GtkNotification GtkNotification;
+
+struct _GtkNotificationClass {
+ GtkBoxClass parent_class;
+
+ /* Signals */
+ void (*actioned) (GtkNotification *self);
+};
+
+struct _GtkNotification {
+ GtkBox parent_instance;
+
+ /*< private > */
+ GtkNotificationPrivate *priv;
+};
+
+GType gtk_notification_get_type (void) G_GNUC_CONST;
+
+GtkWidget * gtk_notification_new (gchar * message, gchar * action);
+
+G_END_DECLS
+
+#endif /* _GTK_NOTIFICATION_H_ */
diff --git a/vapi/custom.vapi b/vapi/custom.vapi
index 0ec822c..b124296 100644
--- a/vapi/custom.vapi
+++ b/vapi/custom.vapi
@@ -36,3 +36,11 @@ namespace Contacts {
[CCode (cname = "eds_personal_google_group_name")]
public static unowned string? eds_personal_google_group_name ();
}
+
+[CCode (cprefix = "Gtk", lower_case_cprefix = "gtk_", cheader_filename = "gtk-notification.h")]
+namespace Gtk {
+ public class Notification : Gtk.Box {
+ [CCode (has_construct_function = false, type = "GtkWidget*")]
+ public Notification (string msg, string action);
+ public virtual signal void actioned ();
+ }}