diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/gtk-notification.c | 530 | ||||
-rw-r--r-- | src/gtk-notification.h | 58 |
3 files changed, 590 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_ */ |