[gnome-contacts] Make notification a pure GtkBin and move the content packing to the vala code



commit 570ceb747969b4b94d13a299b655a927aca20ffe
Author: Alexander Larsson <alexl redhat com>
Date:   Tue Dec 20 16:20:18 2011 +0100

    Make notification a pure GtkBin and move the content packing to the vala code

 data/gnome-contacts.css |    3 +-
 src/contacts-app.vala   |   25 +-
 src/gtk-notification.c  |  865 ++++++++++++++++++++++++++---------------------
 src/gtk-notification.h  |   19 +-
 vapi/custom.vapi        |    6 +-
 5 files changed, 508 insertions(+), 410 deletions(-)
---
diff --git a/data/gnome-contacts.css b/data/gnome-contacts.css
index e82ffd1..1945371 100644
--- a/data/gnome-contacts.css
+++ b/data/gnome-contacts.css
@@ -113,11 +113,12 @@ ContactsViewWidget {
     color: #f57900;
 }
 
-.contacts-notification {
+.notification {
     border-style: solid;
     border-color: #949486;
     border-width: 0 1 1 1;
     border-radius: 0 0 5 5;
+    padding: 8;
     background-color: #d8d8d8;
     background-image: -gtk-gradient (linear,
 				     left top, left bottom,
diff --git a/src/contacts-app.vala b/src/contacts-app.vala
index f03fa12..b848734 100644
--- a/src/contacts-app.vala
+++ b/src/contacts-app.vala
@@ -136,21 +136,28 @@ public class Contacts.App : Gtk.Application {
     contacts_pane = new ContactPane (contacts_store);
     contacts_pane.set_hexpand (true);
     contacts_pane.will_delete.connect ( (c) => {
+      var notification = new Gtk.Notification ();
+
+      var g = new Grid ();
+      g.set_column_spacing (8);
+      notification.add (g);
+
+
       string msg = _("Contact deleted: \"%s\"").printf (c.display_name);
-      var notification = new Gtk.Notification (msg, Stock.UNDO);
-      notification.show ();
-      ulong id;
-      id = notification.destroy.connect ( () => {
-	contacts_store.aggregator.remove_individual (c.individual);
+      var b = new Button.from_stock (Stock.UNDO);
+      g.add (new Label (msg));
+      g.add (b);
+
+      notification.show_all ();
+      var id = notification.timed_out.connect ( () => {
+	  contacts_store.aggregator.remove_individual (c.individual);
       });
-      notification.actioned.connect ( () => {
-	notification.disconnect (id);
-	notification.destroy ();
+      b.clicked.connect ( () => {
+	notification.dismiss ();
 	c.show ();
 	list_pane.select_contact (c);
 	contacts_pane.show_contact (c);
       });
-
       overlay.add_overlay (notification);
     });
     grid.attach (contacts_pane, 1, 0, 1, 2);
diff --git a/src/gtk-notification.c b/src/gtk-notification.c
index abe1a80..72e53c3 100644
--- a/src/gtk-notification.c
+++ b/src/gtk-notification.c
@@ -1,4 +1,4 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /*
  * gtk-notification.c
  * Copyright (C) Erick PÃrez Castellanos 2011 <erick red gmail com>
@@ -26,540 +26,625 @@
  * @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.
+ * the user, allowing them to close the notification or wait for it
+ * to time out.
  *
- * #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.
+ * #GtkNotification provides one signal (#GtkNotification::timed-out), for when the notification
+ * times out.
  *
  */
 
 #define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
 #define SHADOW_OFFSET_X 2
 #define SHADOW_OFFSET_Y 3
-#define INNER_BORDER 4
 
 enum {
-	PROP_0,
-	PROP_MESSAGE,
-	PROP_BUTTON_LABEL,
-	PROP_TIMEOUT
+  PROP_0,
+  PROP_TIMEOUT
 };
 
 struct _GtkNotificationPrivate {
-	GtkWidget *message;
-	GtkWidget *action_button;
-	GtkWidget *close_button;
-
-	gchar *message_label;
-	gchar *button_label;
-	guint timeout;
+  GtkWidget *close_button;
 
-	guint timeout_source_id;
+  guint timeout;
+  guint timeout_source_id;
 };
 
 enum {
-	ACTIONED,
-	LAST_SIGNAL
+  TIMED_OUT,
+  LAST_SIGNAL
 };
 
 static guint notification_signals[LAST_SIGNAL] = { 0 };
 
 static gboolean gtk_notification_draw                           (GtkWidget       *widget,
-																 cairo_t         *cr);
+                                                                 cairo_t         *cr);
 static void     gtk_notification_get_preferred_width            (GtkWidget       *widget,
-																 gint            *minimum_size,
-																 gint            *natural_size);
+                                                                 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);
+                                                                 gint             width,
+                                                                 gint            *minimum_height,
+                                                                 gint            *natural_height);
 static void     gtk_notification_get_preferred_height           (GtkWidget       *widget,
-																 gint            *minimum_size,
-																 gint            *natural_size);
+                                                                 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);
+                                                                 gint             height,
+                                                                 gint            *minimum_width,
+                                                                 gint            *natural_width);
 static void     gtk_notification_size_allocate                  (GtkWidget       *widget,
-																 GtkAllocation   *allocation);
+                                                                 GtkAllocation   *allocation);
 static void     gtk_notification_update_message                 (GtkNotification *notification,
-																 const gchar     *new_message);
+                                                                 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);
+                                                                 const gchar     *new_button_label);
+static gboolean gtk_notification_timeout_cb                     (gpointer         user_data);
 
 /* signals handlers */
 static void     gtk_notification_close_button_clicked_cb        (GtkWidget       *widget,
-																 gpointer         user_data);
+                                                                 gpointer         user_data);
 static void     gtk_notification_action_button_clicked_cb       (GtkWidget       *widget,
-																 gpointer         user_data);
+                                                                 gpointer         user_data);
+
 
-G_DEFINE_TYPE(GtkNotification, gtk_notification, GTK_TYPE_GRID);
+G_DEFINE_TYPE(GtkNotification, gtk_notification, GTK_TYPE_BIN);
 
 static void
-gtk_notification_init(GtkNotification *notification)
+gtk_notification_init (GtkNotification *notification)
 {
-	GtkWidget *close_button_image;
-
-	gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (notification)),
-								 "contacts-notification");
-
-	//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);
-	close_button_image = gtk_image_new_from_icon_name ("window-close-symbolic", GTK_ICON_SIZE_BUTTON);
-	gtk_button_set_image (GTK_BUTTON (notification->priv->close_button), close_button_image);
-
-	gtk_container_add (GTK_CONTAINER (notification), notification->priv->message);
-	gtk_container_add (GTK_CONTAINER (notification), notification->priv->action_button);
-	gtk_container_add (GTK_CONTAINER (notification), notification->priv->close_button);
-
-	gtk_widget_pop_composite_child ();
-
-	notification->priv->timeout_source_id = 0;
+  GtkWidget *close_button_image;
+  GtkStyleContext *context;
+  GtkNotificationPrivate *priv;
+
+  context = gtk_widget_get_style_context (GTK_WIDGET (notification));
+  gtk_style_context_add_class (context, "notification");
+
+
+  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 ();
+
+  priv = notification->priv =
+    G_TYPE_INSTANCE_GET_PRIVATE (notification,
+                                 GTK_TYPE_NOTIFICATION,
+                                 GtkNotificationPrivate);
+
+  priv->close_button = gtk_button_new ();
+  gtk_widget_set_parent (priv->close_button, GTK_WIDGET (notification));
+  gtk_widget_show (priv->close_button);
+  g_object_set (priv->close_button,
+                "relief", GTK_RELIEF_NONE,
+                "focus-on-click", FALSE,
+                NULL);
+  g_signal_connect (priv->close_button,
+                    "clicked",
+                    G_CALLBACK (gtk_notification_close_button_clicked_cb),
+                    notification);
+  close_button_image = gtk_image_new_from_icon_name ("window-close-symbolic", GTK_ICON_SIZE_BUTTON);
+  gtk_button_set_image (GTK_BUTTON (notification->priv->close_button), close_button_image);
+
+  gtk_widget_pop_composite_child ();
+
+  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);
+  GtkNotification *notification;
 
-	if (notification->priv->message_label)
-		g_free (notification->priv->message_label);
+  g_return_if_fail (GTK_IS_NOTIFICATION (object));
 
-	if (notification->priv->button_label)
-		g_free (notification->priv->button_label);
+  notification = GTK_NOTIFICATION (object);
 
-	if (notification->priv->timeout_source_id != 0)
-		g_source_remove(notification->priv->timeout_source_id);
+  if (notification->priv->timeout_source_id != 0)
+    g_source_remove (notification->priv->timeout_source_id);
 
-	G_OBJECT_CLASS (gtk_notification_parent_class)->finalize(object);
+  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)
 {
-	GtkNotification *notification = GTK_NOTIFICATION (object);
-
-	g_return_if_fail (GTK_IS_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;
-	}
+  GtkNotification *notification = GTK_NOTIFICATION (object);
+
+  g_return_if_fail (GTK_IS_NOTIFICATION (object));
+
+  switch (prop_id) {
+  case PROP_TIMEOUT:
+    gtk_notification_set_timeout (notification,
+                                  g_value_get_uint (value));
+    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;
-	}
+  g_return_if_fail (GTK_IS_NOTIFICATION (object));
+  GtkNotification *notification = GTK_NOTIFICATION (object);
+
+  switch (prop_id) {
+  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_forall (GtkContainer *container,
+                         gboolean      include_internals,
+                         GtkCallback   callback,
+                         gpointer      callback_data)
+{
+  GtkBin *bin = GTK_BIN (container);
+  GtkNotification *notification = GTK_NOTIFICATION (container);
+  GtkNotificationPrivate *priv = notification->priv;
+  GtkWidget *child;
+
+  child = gtk_bin_get_child (bin);
+  if (child)
+    (* callback) (child, callback_data);
+
+  if (include_internals)
+    (* callback) (priv->close_button, callback_data);
 }
 
 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));
+  GObjectClass* object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
+  GtkContainerClass *container_class = GTK_CONTAINER_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;
+
+  container_class->forall = gtk_notification_forall;
+  gtk_container_class_handle_border_width (container_class);
+
+
+  /**
+   * 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, 10,
+                                                     GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+  notification_signals[TIMED_OUT] = g_signal_new ("timed-out",
+                                                  G_OBJECT_CLASS_TYPE (klass),
+                                                  G_SIGNAL_RUN_LAST,
+                                                  G_STRUCT_OFFSET (GtkNotificationClass, timed_out),
+                                                  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, int left_border, int right_border,
-				 int bottom_border, double inner_alpha)
+                 int bottom_border, double inner_alpha)
 {
-	cairo_pattern_t *pattern;
-	cairo_matrix_t matrix;
-	double x0, x1, x2, x3;
-	double y0, y1, y2, y3;
+  cairo_pattern_t *pattern;
+  cairo_matrix_t matrix;
+  double x0, x1, x2, x3;
+  double y0, y1, y2, y3;
+
+  cairo_save (cr);
 
-	cairo_save (cr);
+  x0 = rect.x;
+  x1 = rect.x + left_border;
+  x2 = rect.x + rect.width - right_border;
+  x3 = rect.x + rect.width;
 
-	x0 = rect.x;
-	x1 = rect.x + left_border;
-	x2 = rect.x + rect.width - right_border;
-	x3 = rect.x + rect.width;
+  y0 = rect.y;
+  y2 = rect.y + rect.height - bottom_border;
+  y3 = rect.y + rect.height;
 
-	y0 = rect.y;
-	y2 = rect.y + rect.height - bottom_border;
-	y3 = rect.y + rect.height;
+  /* Bottom border */
 
-	/* Bottom border */
+  pattern = cairo_pattern_create_linear(0, y2, 0, y3);
 
-	pattern = cairo_pattern_create_linear(0, y2, 0, y3);
+  cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0, 0, 0, inner_alpha);
+  cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0, 0, 0, 0.0);
 
-	cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0, 0, 0, inner_alpha);
-	cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0, 0, 0, 0.0);
+  cairo_set_source(cr, pattern);
+  cairo_pattern_destroy(pattern);
 
-	cairo_set_source(cr, pattern);
-	cairo_pattern_destroy(pattern);
+  cairo_rectangle(cr, x1, y2, x2 - x1, y3 - y2);
+  cairo_fill(cr);
 
-	cairo_rectangle(cr, x1, y2, x2 - x1, y3 - y2);
-	cairo_fill(cr);
+  /* Left border */
 
-	/* Left border */
+  pattern = cairo_pattern_create_linear(x0, 0, x1, 0);
 
-	pattern = cairo_pattern_create_linear(x0, 0, x1, 0);
+  cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0, 0, 0, 0.0);
+  cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0, 0, 0, inner_alpha);
 
-	cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0, 0, 0, 0.0);
-	cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0, 0, 0, inner_alpha);
+  cairo_set_source(cr, pattern);
+  cairo_pattern_destroy(pattern);
 
-	cairo_set_source(cr, pattern);
-	cairo_pattern_destroy(pattern);
+  cairo_rectangle(cr, x0, y0, x1 - x0, y2 - y0);
+  cairo_fill(cr);
 
-	cairo_rectangle(cr, x0, y0, x1 - x0, y2 - y0);
-	cairo_fill(cr);
+  /* Right border */
 
-	/* Right border */
+  pattern = cairo_pattern_create_linear(x2, 0, x3, 0);
 
-	pattern = cairo_pattern_create_linear(x2, 0, x3, 0);
+  cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0, 0, 0, inner_alpha);
+  cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0, 0, 0, 0.0);
 
-	cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0, 0, 0, inner_alpha);
-	cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0, 0, 0, 0.0);
+  cairo_set_source(cr, pattern);
+  cairo_pattern_destroy(pattern);
 
-	cairo_set_source(cr, pattern);
-	cairo_pattern_destroy(pattern);
+  cairo_rectangle(cr, x2, y0, x3 - x2, y2 - y0);
+  cairo_fill(cr);
 
-	cairo_rectangle(cr, x2, y0, x3 - x2, y2 - y0);
-	cairo_fill(cr);
+  /* SW corner */
 
-	/* SW corner */
+  pattern = cairo_pattern_create_radial(0, 0, 0, 0.0, 0, 1.0);
+  cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0, 0, 0, inner_alpha);
+  cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0, 0, 0, 0.0);
 
-	pattern = cairo_pattern_create_radial(0, 0, 0, 0.0, 0, 1.0);
-	cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0, 0, 0, inner_alpha);
-	cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0, 0, 0, 0.0);
+  cairo_matrix_init_scale (&matrix, 1.0 / left_border, 1.0 / bottom_border);
+  cairo_matrix_translate (&matrix, - x1, -y2);
+  cairo_pattern_set_matrix (pattern, &matrix);
 
-	cairo_matrix_init_scale (&matrix, 1.0 / left_border, 1.0 / bottom_border);
-	cairo_matrix_translate (&matrix, - x1, -y2);
-	cairo_pattern_set_matrix (pattern, &matrix);
+  cairo_set_source(cr, pattern);
+  cairo_pattern_destroy(pattern);
 
-	cairo_set_source(cr, pattern);
-	cairo_pattern_destroy(pattern);
+  cairo_rectangle(cr, x0, y2, x1 - x0, y3 - y2);
+  cairo_fill(cr);
 
-	cairo_rectangle(cr, x0, y2, x1 - x0, y3 - y2);
-	cairo_fill(cr);
+  /* SE corner */
 
-	/* SE corner */
+  pattern = cairo_pattern_create_radial(0, 0, 0, 0, 0, 1.0);
+  cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0.0, 0, 0, inner_alpha);
+  cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0.0, 0, 0, 0.0);
 
-	pattern = cairo_pattern_create_radial(0, 0, 0, 0, 0, 1.0);
-	cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0.0, 0, 0, inner_alpha);
-	cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0.0, 0, 0, 0.0);
+  cairo_matrix_init_scale (&matrix, 1.0 / left_border, 1.0 / bottom_border);
+  cairo_matrix_translate (&matrix, - x2, -y2);
+  cairo_pattern_set_matrix (pattern, &matrix);
 
-	cairo_matrix_init_scale (&matrix, 1.0 / left_border, 1.0 / bottom_border);
-	cairo_matrix_translate (&matrix, - x2, -y2);
-	cairo_pattern_set_matrix (pattern, &matrix);
+  cairo_set_source(cr, pattern);
+  cairo_pattern_destroy(pattern);
+
+  cairo_rectangle(cr, x2, y2, x3 - x2, y3 - y2);
+  cairo_fill(cr);
+
+  cairo_restore (cr);
+}
+
+static void
+get_padding_and_border (GtkNotification *notification,
+                        GtkBorder *border)
+{
+  GtkStyleContext *context;
+  GtkStateFlags state;
+  GtkBorder tmp;
 
-	cairo_set_source(cr, pattern);
-	cairo_pattern_destroy(pattern);
+  context = gtk_widget_get_style_context (GTK_WIDGET (notification));
+  state = gtk_widget_get_state_flags (GTK_WIDGET (notification));
 
-	cairo_rectangle(cr, x2, y2, x3 - x2, y3 - y2);
-	cairo_fill(cr);
+  gtk_style_context_get_padding (context, state, border);
 
-	cairo_restore (cr);
+  gtk_style_context_get_border (context, state, &tmp);
+  border->top += tmp.top;
+  border->right += tmp.right;
+  border->bottom += tmp.bottom;
+  border->left += tmp.left;
 }
 
 static gboolean
 gtk_notification_draw (GtkWidget *widget, cairo_t *cr)
 {
-	GtkStyleContext *context;
-	GdkRectangle rect;
-	int border_radius;
-	GtkStateFlags state;
-	int inner_radius;
-
-	gtk_widget_get_allocation (widget, &rect);
-
-	context = gtk_widget_get_style_context(widget);
-	state = gtk_style_context_get_state (context);
-
-	inner_radius = 5;
-	draw_shadow_box (cr, rect, SHADOW_OFFSET_X + inner_radius, SHADOW_OFFSET_X + inner_radius,
-					 SHADOW_OFFSET_Y + inner_radius, 0.8);
-
-	gtk_style_context_save (context);
-	gtk_render_background (context,  cr,
-						   SHADOW_OFFSET_X, 0,
-						   gtk_widget_get_allocated_width (widget) - 2 *SHADOW_OFFSET_X,
-						   gtk_widget_get_allocated_height (widget) - SHADOW_OFFSET_Y);
-	gtk_render_frame (context,cr,
-					  SHADOW_OFFSET_X, 0,
-					  gtk_widget_get_allocated_width (widget) - 2 *SHADOW_OFFSET_X,
-					  gtk_widget_get_allocated_height (widget) - SHADOW_OFFSET_Y);
-
-	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;
+  GtkNotification *notification = GTK_NOTIFICATION (widget);
+  GtkStyleContext *context;
+  GdkRectangle rect;
+  int border_radius;
+  GtkStateFlags state;
+  int inner_radius;
+
+  gtk_widget_get_allocation (widget, &rect);
+
+  context = gtk_widget_get_style_context(widget);
+  state = gtk_style_context_get_state (context);
+
+  inner_radius = 5;
+  draw_shadow_box (cr, rect, SHADOW_OFFSET_X + inner_radius, SHADOW_OFFSET_X + inner_radius,
+                   SHADOW_OFFSET_Y + inner_radius, 0.8);
+
+  gtk_style_context_save (context);
+  gtk_render_background (context,  cr,
+                         SHADOW_OFFSET_X, 0,
+                         gtk_widget_get_allocated_width (widget) - 2 *SHADOW_OFFSET_X,
+                         gtk_widget_get_allocated_height (widget) - SHADOW_OFFSET_Y);
+  gtk_render_frame (context,cr,
+                    SHADOW_OFFSET_X, 0,
+                    gtk_widget_get_allocated_width (widget) - 2 *SHADOW_OFFSET_X,
+                    gtk_widget_get_allocated_height (widget) - SHADOW_OFFSET_Y);
+
+  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 */
+  if (notification->priv->timeout_source_id == 0)
+    notification->priv->timeout_source_id = g_timeout_add (notification->priv->timeout * 1000,
+                                                           gtk_notification_timeout_cb,
+                                                           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_X * 2 + 2 * INNER_BORDER;
-	*natural_size = parent_natural_size + SHADOW_OFFSET_X * 2 + 2 * INNER_BORDER;
+  GtkNotification *notification = GTK_NOTIFICATION (widget);
+  GtkNotificationPrivate *priv = notification->priv;
+  GtkBin *bin = GTK_BIN (widget);
+  gint child_min, child_nat;
+  GtkWidget *child;
+  GtkBorder padding;
+  gint minimum, natural;
+
+  get_padding_and_border (notification, &padding);
+
+  minimum = 0;
+  natural = 0;
+
+  child = gtk_bin_get_child (bin);
+  if (child && gtk_widget_get_visible (child))
+    {
+      gtk_widget_get_preferred_width (child,
+                                      &child_min, &child_nat);
+      minimum += child_min;
+      natural += child_nat;
+    }
+
+  gtk_widget_get_preferred_width (priv->close_button,
+                                  &child_min, &child_nat);
+  minimum += child_min;
+  natural += child_nat;
+
+
+  minimum += padding.left + padding.right + 2 * SHADOW_OFFSET_X;
+  natural += padding.left + padding.right + 2 * SHADOW_OFFSET_X;
+
+ if (minimum_size)
+    *minimum_size = minimum;
+
+  if (natural_size)
+    *natural_size = natural;
 }
 
 static void
-gtk_notification_get_preferred_height_for_width (GtkWidget *widget,
-												 gint width,
-												 gint *minimum_height,
-												 gint *natural_height)
+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_height_for_width (widget,
-										width,
-										&parent_minimum_size,
-										&parent_natural_size);
-
-	*minimum_height = parent_minimum_size + SHADOW_OFFSET_Y + 2 * INNER_BORDER;
-	*natural_height = parent_natural_size + SHADOW_OFFSET_Y + 2 * INNER_BORDER;
+  GtkNotification *notification = GTK_NOTIFICATION (widget);
+  GtkNotificationPrivate *priv = notification->priv;
+  GtkBin *bin = GTK_BIN (widget);
+  gint child_min, child_nat, child_height;
+  GtkWidget *child;
+  GtkBorder padding;
+  gint minimum, natural;
+
+  get_padding_and_border (notification, &padding);
+
+  minimum = 0;
+  natural = 0;
+
+  child_height = height - SHADOW_OFFSET_Y - padding.top - padding.bottom;
+
+  child = gtk_bin_get_child (bin);
+  if (child && gtk_widget_get_visible (child))
+    {
+      gtk_widget_get_preferred_width_for_height (child, child_height,
+                                                 &child_min, &child_nat);
+      minimum += child_min;
+      natural += child_nat;
+    }
+
+  gtk_widget_get_preferred_width_for_height (priv->close_button, child_height,
+                                             &child_min, &child_nat);
+  minimum += child_min;
+  natural += child_nat;
+
+  minimum += padding.left + padding.right + 2 * SHADOW_OFFSET_X;
+  natural += padding.left + padding.right + 2 * SHADOW_OFFSET_X;
+
+ if (minimum_width)
+    *minimum_width = minimum;
+
+  if (natural_width)
+    *natural_width = natural;
 }
 
 static void
-gtk_notification_get_preferred_height (GtkWidget *widget, gint *minimum_size, gint *natural_size)
+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 (widget,
-																		   &parent_minimum_size,
-																		   &parent_natural_size);
-
-	*minimum_size = parent_minimum_size + SHADOW_OFFSET_Y + 2 * INNER_BORDER;
-	*natural_size = parent_natural_size + SHADOW_OFFSET_Y + 2 * INNER_BORDER;
+  GtkNotification *notification = GTK_NOTIFICATION (widget);
+  GtkNotificationPrivate *priv = notification->priv;
+  GtkBin *bin = GTK_BIN (widget);
+  gint child_min, child_nat, child_width, button_width;
+  GtkWidget *child;
+  GtkBorder padding;
+  gint minimum, natural;
+
+  get_padding_and_border (notification, &padding);
+
+  gtk_widget_get_preferred_height (priv->close_button,
+                                   &minimum, &natural);
+  gtk_widget_get_preferred_width (priv->close_button,
+                                  NULL, &button_width);
+
+  child = gtk_bin_get_child (bin);
+  if (child && gtk_widget_get_visible (child))
+    {
+      child_width = width - 2 * SHADOW_OFFSET_X - padding.left - padding.top - button_width;
+
+      gtk_widget_get_preferred_height_for_width (child, child_width,
+                                                 &child_min, &child_nat);
+      minimum = MAX (minimum, child_min);
+      natural = MAX (natural, child_nat);
+    }
+
+  minimum += padding.top + padding.top + SHADOW_OFFSET_Y;
+  natural += padding.top + padding.top + SHADOW_OFFSET_Y;
+
+ if (minimum_height)
+    *minimum_height = minimum;
+
+  if (natural_height)
+    *natural_height = natural;
 }
 
 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_X + 2 * INNER_BORDER;
-	*natural_width = parent_natural_size + 2 * SHADOW_OFFSET_X + 2 * INNER_BORDER;
+gtk_notification_get_preferred_height (GtkWidget *widget, gint *minimum_height, gint *natural_height)
+{
+  GtkNotification *notification = GTK_NOTIFICATION (widget);
+  GtkNotificationPrivate *priv = notification->priv;
+  GtkBin *bin = GTK_BIN (widget);
+  gint child_min, child_nat;
+  GtkWidget *child;
+  GtkBorder padding;
+  gint minimum, natural;
+
+  get_padding_and_border (notification, &padding);
+
+  gtk_widget_get_preferred_height (priv->close_button,
+                                   &minimum, &natural);
+
+  child = gtk_bin_get_child (bin);
+  if (child && gtk_widget_get_visible (child))
+    {
+      gtk_widget_get_preferred_height (child,
+                                       &child_min, &child_nat);
+      minimum = MAX (minimum, child_min);
+      natural = MAX (natural, child_nat);
+    }
+
+  minimum += padding.top + padding.top + SHADOW_OFFSET_Y;
+  natural += padding.top + padding.top + SHADOW_OFFSET_Y;
+
+ if (minimum_height)
+    *minimum_height = minimum;
+
+  if (natural_height)
+    *natural_height = natural;
 }
 
 static void
-gtk_notification_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
+gtk_notification_size_allocate (GtkWidget *widget,
+                                GtkAllocation *allocation)
 {
-	GtkAllocation parent_allocation;
+  GtkNotification *notification = GTK_NOTIFICATION (widget);
+  GtkNotificationPrivate *priv = notification->priv;
+  GtkBin *bin = GTK_BIN (widget);
+  GtkAllocation child_allocation;
+  GtkBorder padding;
+  GtkWidget *child;
+  int button_width;
 
-	parent_allocation.x = allocation->x + SHADOW_OFFSET_X + INNER_BORDER;
-	parent_allocation.y = allocation->y + INNER_BORDER;
-	parent_allocation.width = allocation->width - 2 * SHADOW_OFFSET_X - 2 * INNER_BORDER;
-	parent_allocation.height = allocation->height - SHADOW_OFFSET_Y - 2 *INNER_BORDER;
+  gtk_widget_set_allocation (widget, allocation);
 
-	GTK_WIDGET_CLASS (gtk_notification_parent_class)->
-		size_allocate (widget, &parent_allocation);
+  get_padding_and_border (notification, &padding);
 
-	gtk_widget_set_allocation (widget, allocation);
+  child_allocation.x = allocation->x + SHADOW_OFFSET_X + padding.left;
+  child_allocation.y = allocation->y + padding.top;
+  child_allocation.height = MAX (1, allocation->height - SHADOW_OFFSET_Y - padding.top - padding.bottom);
+
+
+  gtk_widget_get_preferred_width_for_height (priv->close_button, child_allocation.height,
+                                             NULL, &button_width);
+
+  child_allocation.width = MAX (1, allocation->width - 2 * SHADOW_OFFSET_X - padding.left - padding.right - button_width);
+
+  child = gtk_bin_get_child (bin);
+  if (child && gtk_widget_get_visible (child))
+    gtk_widget_size_allocate (child, &child_allocation);
+
+  child_allocation.x += child_allocation.width;
+  child_allocation.width = button_width;
+
+  gtk_widget_size_allocate (priv->close_button, &child_allocation);
 }
 
-static void
-gtk_notification_update_message (GtkNotification *notification, const gchar *new_message)
+static gboolean
+gtk_notification_timeout_cb (gpointer user_data)
 {
-	g_free (notification->priv->message_label);
-	notification->priv->message_label = g_strdup (new_message);
-	g_object_notify (G_OBJECT (notification), "message");
+  GtkNotification *notification = GTK_NOTIFICATION (user_data);
+
+  g_signal_emit (notification, notification_signals[TIMED_OUT], 0);
+  gtk_notification_dismiss (notification);
 
-	gtk_label_set_text (GTK_LABEL (notification->priv->message),
-						notification->priv->message_label);
+  return FALSE;
 }
 
-static void
-gtk_notification_update_button (GtkNotification *notification, const gchar *new_button_label)
+void
+gtk_notification_set_timeout (GtkNotification *notification,
+                              guint            timeout_msec)
 {
-	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);
+  notification->priv->timeout = timeout_msec;
+  g_object_notify (G_OBJECT (notification), "timeout");
 }
 
-static gboolean
-gtk_notification_auto_destroy (gpointer user_data)
+void
+gtk_notification_dismiss (GtkNotification *notification)
 {
-	GtkWidget *notification = GTK_WIDGET(user_data);
-	gtk_widget_destroy (notification);
-	return FALSE;
+  gtk_widget_destroy (GTK_WIDGET (notification));
 }
 
 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;
+  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));
+  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);
+  g_signal_emit_by_name (user_data, "actioned", NULL);
 }
 
 GtkWidget *
-gtk_notification_new (gchar *message, gchar *action)
+gtk_notification_new (void)
 {
-	return g_object_new (GTK_TYPE_NOTIFICATION,
-						 "message", message,
-						 "button-label", action,
-						 "orientation", GTK_ORIENTATION_HORIZONTAL,
-						 "column-spacing", 8,
-						 NULL);
+  return g_object_new (GTK_TYPE_NOTIFICATION, NULL);
 }
diff --git a/src/gtk-notification.h b/src/gtk-notification.h
index 5f6519c..9cff5e4 100644
--- a/src/gtk-notification.h
+++ b/src/gtk-notification.h
@@ -1,4 +1,4 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /*
  * gtk-notification.c
  * Copyright (C) Erick PÃrez Castellanos 2011 <erick red gmail com>
@@ -36,22 +36,25 @@ typedef struct _GtkNotificationClass GtkNotificationClass;
 typedef struct _GtkNotification GtkNotification;
 
 struct _GtkNotificationClass {
-	GtkGridClass parent_class;
+  GtkBinClass parent_class;
 
-	/* Signals */
-	void (*actioned) (GtkNotification *self);
+  /* Signals */
+  void (*timed_out) (GtkNotification *self);
 };
 
 struct _GtkNotification {
-	GtkGrid parent_instance;
+  GtkBin parent_instance;
 
-	/*< private > */
-	GtkNotificationPrivate *priv;
+  /*< private > */
+  GtkNotificationPrivate *priv;
 };
 
 GType gtk_notification_get_type (void) G_GNUC_CONST;
 
-GtkWidget * gtk_notification_new (gchar * message, gchar * action);
+GtkWidget *gtk_notification_new         (void);
+void       gtk_notification_set_timeout (GtkNotification *notification,
+                                         guint            timeout_msec);
+void       gtk_notification_dismiss     (GtkNotification *notification);
 
 G_END_DECLS
 
diff --git a/vapi/custom.vapi b/vapi/custom.vapi
index b124296..70b4854 100644
--- a/vapi/custom.vapi
+++ b/vapi/custom.vapi
@@ -41,6 +41,8 @@ namespace Contacts {
 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 ();
+		public Notification ();
+		public void set_timeout (uint timeout_msec);
+		public void dismiss ();
+		public virtual signal void timed_out ();
 	}}



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