1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
4
* Based on gtk-notification from gnome-contacts:
5
* http://git.gnome.org/browse/gnome-contacts/tree/src/gtk-notification.c?id=3.3.91
7
* Copyright (C) Erick Pérez Castellanos 2011 <erick.red@gmail.com>
8
* Copyright (C) 2012 Red Hat, Inc.
10
* This program is free software: you can redistribute it and/or modify it
11
* under the terms of the GNU Lesser General Public License as published
12
* by the Free Software Foundation, either version 3 of the License, or
13
* (at your option) any later version.
15
* This program is distributed in the hope that it will be useful, but
16
* WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
* See the GNU Lesser General Public License for more details.
20
* You should have received a copy of the GNU Lesser General Public License
21
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
24
#include "gd-notification.h"
27
* SECTION:gdnotification
28
* @short_description: Report notification messages to the user
30
* @see_also: #GtkStatusbar, #GtkMessageDialog, #GtkInfoBar
32
* #GdNotification is a widget made for showing notifications to
33
* the user, allowing them to close the notification or wait for it
36
* #GdNotification provides one signal (#GdNotification::dismissed), for when the notification
37
* times out or is closed.
41
#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
42
#define SHADOW_OFFSET_X 2
43
#define SHADOW_OFFSET_Y 3
44
#define ANIMATION_TIME 200 /* msec */
45
#define ANIMATION_STEP 40 /* msec */
50
PROP_SHOW_CLOSE_BUTTON
53
struct _GdNotificationPrivate {
54
GtkWidget *close_button;
55
gboolean show_close_button;
57
GdkWindow *bin_window;
59
int animate_y; /* from 0 to allocation.height */
60
gboolean waiting_for_viewable;
63
gboolean sent_dismissed;
64
guint animate_timeout;
67
guint timeout_source_id;
75
static guint notification_signals[LAST_SIGNAL] = { 0 };
77
static gboolean gd_notification_draw (GtkWidget *widget,
79
static void gd_notification_get_preferred_width (GtkWidget *widget,
82
static void gd_notification_get_preferred_height_for_width (GtkWidget *widget,
85
gint *natural_height);
86
static void gd_notification_get_preferred_height (GtkWidget *widget,
89
static void gd_notification_get_preferred_width_for_height (GtkWidget *widget,
93
static void gd_notification_size_allocate (GtkWidget *widget,
94
GtkAllocation *allocation);
95
static gboolean gd_notification_timeout_cb (gpointer user_data);
96
static void gd_notification_show (GtkWidget *widget);
97
static void gd_notification_add (GtkContainer *container,
100
/* signals handlers */
101
static void gd_notification_close_button_clicked_cb (GtkWidget *widget,
104
G_DEFINE_TYPE(GdNotification, gd_notification, GTK_TYPE_BIN);
107
gd_notification_init (GdNotification *notification)
109
GtkWidget *close_button_image;
110
GtkStyleContext *context;
111
GdNotificationPrivate *priv;
113
context = gtk_widget_get_style_context (GTK_WIDGET (notification));
114
gtk_style_context_add_class (context, "documents-notification");
116
gtk_widget_set_halign (GTK_WIDGET (notification), GTK_ALIGN_CENTER);
117
gtk_widget_set_valign (GTK_WIDGET (notification), GTK_ALIGN_START);
119
gtk_widget_set_has_window (GTK_WIDGET (notification), TRUE);
121
gtk_widget_push_composite_child ();
123
priv = notification->priv =
124
G_TYPE_INSTANCE_GET_PRIVATE (notification,
125
GD_TYPE_NOTIFICATION,
126
GdNotificationPrivate);
129
priv->close_button = gtk_button_new ();
130
gtk_widget_set_parent (priv->close_button, GTK_WIDGET (notification));
131
gtk_widget_show (priv->close_button);
132
g_object_set (priv->close_button,
133
"relief", GTK_RELIEF_NONE,
134
"focus-on-click", FALSE,
136
g_signal_connect (priv->close_button,
138
G_CALLBACK (gd_notification_close_button_clicked_cb),
140
close_button_image = gtk_image_new_from_icon_name ("window-close-symbolic", GTK_ICON_SIZE_BUTTON);
141
gtk_button_set_image (GTK_BUTTON (notification->priv->close_button), close_button_image);
143
gtk_widget_pop_composite_child ();
145
priv->timeout_source_id = 0;
149
gd_notification_finalize (GObject *object)
151
GdNotification *notification;
152
GdNotificationPrivate *priv;
154
g_return_if_fail (GTK_IS_NOTIFICATION (object));
156
notification = GD_NOTIFICATION (object);
157
priv = notification->priv;
159
if (priv->animate_timeout != 0)
160
g_source_remove (priv->animate_timeout);
162
if (priv->timeout_source_id != 0)
163
g_source_remove (priv->timeout_source_id);
165
G_OBJECT_CLASS (gd_notification_parent_class)->finalize (object);
169
gd_notification_destroy (GtkWidget *widget)
171
GdNotification *notification = GD_NOTIFICATION (widget);
172
GdNotificationPrivate *priv = notification->priv;
174
if (!priv->sent_dismissed)
176
g_signal_emit (notification, notification_signals[DISMISSED], 0);
177
priv->sent_dismissed = TRUE;
180
if (priv->close_button)
182
gtk_widget_unparent (priv->close_button);
183
priv->close_button = NULL;
186
GTK_WIDGET_CLASS (gd_notification_parent_class)->destroy (widget);
190
gd_notification_realize (GtkWidget *widget)
192
GdNotification *notification = GD_NOTIFICATION (widget);
193
GdNotificationPrivate *priv = notification->priv;
194
GtkBin *bin = GTK_BIN (widget);
195
GtkAllocation allocation;
198
GdkWindowAttr attributes;
199
gint attributes_mask;
201
gtk_widget_set_realized (widget, TRUE);
203
gtk_widget_get_allocation (widget, &allocation);
205
attributes.x = allocation.x;
206
attributes.y = allocation.y;
207
attributes.width = allocation.width;
208
attributes.height = allocation.height;
209
attributes.window_type = GDK_WINDOW_CHILD;
210
attributes.wclass = GDK_INPUT_OUTPUT;
211
attributes.visual = gtk_widget_get_visual (widget);
213
attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK;
215
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
217
window = gdk_window_new (gtk_widget_get_parent_window (widget),
218
&attributes, attributes_mask);
219
gtk_widget_set_window (widget, window);
220
gdk_window_set_user_data (window, notification);
223
attributes.y = attributes.height + priv->animate_y;
224
attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_VISIBILITY_NOTIFY_MASK;
226
priv->bin_window = gdk_window_new (window, &attributes, attributes_mask);
227
gdk_window_set_user_data (priv->bin_window, notification);
229
child = gtk_bin_get_child (bin);
231
gtk_widget_set_parent_window (child, priv->bin_window);
232
gtk_widget_set_parent_window (priv->close_button, priv->bin_window);
234
gdk_window_show (priv->bin_window);
238
gd_notification_unrealize (GtkWidget *widget)
240
GdNotification *notification = GD_NOTIFICATION (widget);
241
GdNotificationPrivate *priv = notification->priv;
243
gdk_window_set_user_data (priv->bin_window, NULL);
244
gdk_window_destroy (priv->bin_window);
245
priv->bin_window = NULL;
247
GTK_WIDGET_CLASS (gd_notification_parent_class)->unrealize (widget);
251
animation_target (GdNotification *notification)
253
GdNotificationPrivate *priv = notification->priv;
254
GtkAllocation allocation;
256
if (priv->revealed) {
257
gtk_widget_get_allocation (GTK_WIDGET (notification), &allocation);
258
return allocation.height;
265
animation_timeout_cb (gpointer user_data)
267
GdNotification *notification = GD_NOTIFICATION (user_data);
268
GdNotificationPrivate *priv = notification->priv;
269
GtkAllocation allocation;
272
target = animation_target (notification);
274
if (priv->animate_y != target) {
275
gtk_widget_get_allocation (GTK_WIDGET (notification), &allocation);
277
delta = allocation.height * ANIMATION_STEP / ANIMATION_TIME;
280
priv->animate_y += delta;
282
priv->animate_y -= delta;
284
priv->animate_y = CLAMP (priv->animate_y, 0, allocation.height);
286
if (priv->bin_window != NULL)
287
gdk_window_move (priv->bin_window,
289
-allocation.height + priv->animate_y);
293
if (priv->dismissed && priv->animate_y == 0)
294
gtk_widget_destroy (GTK_WIDGET (notification));
296
priv->animate_timeout = 0;
301
start_animation (GdNotification *notification)
303
GdNotificationPrivate *priv = notification->priv;
306
if (priv->animate_timeout != 0)
307
return; /* Already running */
309
target = animation_target (notification);
310
if (priv->animate_y != target)
311
notification->priv->animate_timeout =
312
gdk_threads_add_timeout (ANIMATION_STEP,
313
animation_timeout_cb,
318
gd_notification_show (GtkWidget *widget)
320
GdNotification *notification = GD_NOTIFICATION (widget);
321
GdNotificationPrivate *priv = notification->priv;
323
GTK_WIDGET_CLASS (gd_notification_parent_class)->show (widget);
324
priv->revealed = TRUE;
325
priv->waiting_for_viewable = TRUE;
329
gd_notification_hide (GtkWidget *widget)
331
GdNotification *notification = GD_NOTIFICATION (widget);
332
GdNotificationPrivate *priv = notification->priv;
334
GTK_WIDGET_CLASS (gd_notification_parent_class)->hide (widget);
335
priv->revealed = FALSE;
336
priv->waiting_for_viewable = FALSE;
340
gd_notification_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
342
GdNotification *notification = GD_NOTIFICATION (object);
344
g_return_if_fail (GTK_IS_NOTIFICATION (object));
348
gd_notification_set_timeout (notification,
349
g_value_get_int (value));
351
case PROP_SHOW_CLOSE_BUTTON:
352
gd_notification_set_show_close_button (notification,
353
g_value_get_boolean (value));
356
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
362
gd_notification_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
364
g_return_if_fail (GTK_IS_NOTIFICATION (object));
365
GdNotification *notification = GD_NOTIFICATION (object);
369
g_value_set_int (value, notification->priv->timeout);
371
case PROP_SHOW_CLOSE_BUTTON:
372
g_value_set_boolean (value,
373
notification->priv->show_close_button);
376
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
382
gd_notification_forall (GtkContainer *container,
383
gboolean include_internals,
384
GtkCallback callback,
385
gpointer callback_data)
387
GtkBin *bin = GTK_BIN (container);
388
GdNotification *notification = GD_NOTIFICATION (container);
389
GdNotificationPrivate *priv = notification->priv;
392
child = gtk_bin_get_child (bin);
394
(* callback) (child, callback_data);
396
if (include_internals)
397
(* callback) (priv->close_button, callback_data);
401
gd_notification_visibility_notify_event (GtkWidget *widget,
402
GdkEventVisibility *event)
404
GdNotification *notification = GD_NOTIFICATION (widget);
405
GdNotificationPrivate *priv = notification->priv;
407
if (!gtk_widget_get_visible (widget))
410
if (priv->waiting_for_viewable)
412
start_animation (notification);
413
priv->waiting_for_viewable = FALSE;
416
if (notification->priv->timeout_source_id == 0 &&
417
notification->priv->timeout != -1)
418
notification->priv->timeout_source_id =
419
gdk_threads_add_timeout (notification->priv->timeout * 1000,
420
gd_notification_timeout_cb,
427
gd_notification_class_init (GdNotificationClass *klass)
429
GObjectClass* object_class = G_OBJECT_CLASS (klass);
430
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
431
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
433
object_class->finalize = gd_notification_finalize;
434
object_class->set_property = gd_notification_set_property;
435
object_class->get_property = gd_notification_get_property;
437
widget_class->show = gd_notification_show;
438
widget_class->hide = gd_notification_hide;
439
widget_class->destroy = gd_notification_destroy;
440
widget_class->get_preferred_width = gd_notification_get_preferred_width;
441
widget_class->get_preferred_height_for_width = gd_notification_get_preferred_height_for_width;
442
widget_class->get_preferred_height = gd_notification_get_preferred_height;
443
widget_class->get_preferred_width_for_height = gd_notification_get_preferred_width_for_height;
444
widget_class->size_allocate = gd_notification_size_allocate;
445
widget_class->draw = gd_notification_draw;
446
widget_class->realize = gd_notification_realize;
447
widget_class->unrealize = gd_notification_unrealize;
448
widget_class->visibility_notify_event = gd_notification_visibility_notify_event;
450
container_class->add = gd_notification_add;
451
container_class->forall = gd_notification_forall;
452
gtk_container_class_handle_border_width (container_class);
456
* GdNotification:timeout:
458
* The time it takes to hide the widget, in seconds.
462
g_object_class_install_property (object_class,
464
g_param_spec_int("timeout", "timeout",
465
"The time it takes to hide the widget, in seconds",
467
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
468
g_object_class_install_property (object_class,
469
PROP_SHOW_CLOSE_BUTTON,
470
g_param_spec_boolean("show-close-button", "show-close-button",
471
"Whether to show a stock close button that dismisses the notification",
473
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
475
notification_signals[DISMISSED] = g_signal_new ("dismissed",
476
G_OBJECT_CLASS_TYPE (klass),
478
G_STRUCT_OFFSET (GdNotificationClass, dismissed),
481
g_cclosure_marshal_VOID__VOID,
485
g_type_class_add_private (object_class, sizeof (GdNotificationPrivate));
489
draw_shadow_box (cairo_t *cr, GdkRectangle rect, int left_border, int right_border,
490
int bottom_border, double inner_alpha)
492
cairo_pattern_t *pattern;
493
cairo_matrix_t matrix;
494
double x0, x1, x2, x3;
500
x1 = rect.x + left_border;
501
x2 = rect.x + rect.width - right_border;
502
x3 = rect.x + rect.width;
505
y2 = rect.y + rect.height - bottom_border;
506
y3 = rect.y + rect.height;
510
pattern = cairo_pattern_create_linear(0, y2, 0, y3);
512
cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0, 0, 0, inner_alpha);
513
cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0, 0, 0, 0.0);
515
cairo_set_source(cr, pattern);
516
cairo_pattern_destroy(pattern);
518
cairo_rectangle(cr, x1, y2, x2 - x1, y3 - y2);
523
pattern = cairo_pattern_create_linear(x0, 0, x1, 0);
525
cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0, 0, 0, 0.0);
526
cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0, 0, 0, inner_alpha);
528
cairo_set_source(cr, pattern);
529
cairo_pattern_destroy(pattern);
531
cairo_rectangle(cr, x0, y0, x1 - x0, y2 - y0);
536
pattern = cairo_pattern_create_linear(x2, 0, x3, 0);
538
cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0, 0, 0, inner_alpha);
539
cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0, 0, 0, 0.0);
541
cairo_set_source(cr, pattern);
542
cairo_pattern_destroy(pattern);
544
cairo_rectangle(cr, x2, y0, x3 - x2, y2 - y0);
549
pattern = cairo_pattern_create_radial(0, 0, 0, 0.0, 0, 1.0);
550
cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0, 0, 0, inner_alpha);
551
cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0, 0, 0, 0.0);
553
cairo_matrix_init_scale (&matrix, 1.0 / left_border, 1.0 / bottom_border);
554
cairo_matrix_translate (&matrix, - x1, -y2);
555
cairo_pattern_set_matrix (pattern, &matrix);
557
cairo_set_source(cr, pattern);
558
cairo_pattern_destroy(pattern);
560
cairo_rectangle(cr, x0, y2, x1 - x0, y3 - y2);
565
pattern = cairo_pattern_create_radial(0, 0, 0, 0, 0, 1.0);
566
cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0.0, 0, 0, inner_alpha);
567
cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0.0, 0, 0, 0.0);
569
cairo_matrix_init_scale (&matrix, 1.0 / left_border, 1.0 / bottom_border);
570
cairo_matrix_translate (&matrix, - x2, -y2);
571
cairo_pattern_set_matrix (pattern, &matrix);
573
cairo_set_source(cr, pattern);
574
cairo_pattern_destroy(pattern);
576
cairo_rectangle(cr, x2, y2, x3 - x2, y3 - y2);
583
get_padding_and_border (GdNotification *notification,
586
GtkStyleContext *context;
590
context = gtk_widget_get_style_context (GTK_WIDGET (notification));
591
state = gtk_widget_get_state_flags (GTK_WIDGET (notification));
593
gtk_style_context_get_padding (context, state, border);
595
gtk_style_context_get_border (context, state, &tmp);
596
border->top += tmp.top;
597
border->right += tmp.right;
598
border->bottom += tmp.bottom;
599
border->left += tmp.left;
603
gd_notification_draw (GtkWidget *widget, cairo_t *cr)
605
GdNotification *notification = GD_NOTIFICATION (widget);
606
GdNotificationPrivate *priv = notification->priv;
607
GtkStyleContext *context;
611
if (gtk_cairo_should_draw_window (cr, priv->bin_window))
613
gtk_widget_get_allocation (widget, &rect);
615
context = gtk_widget_get_style_context(widget);
618
draw_shadow_box (cr, rect, SHADOW_OFFSET_X + inner_radius, SHADOW_OFFSET_X + inner_radius,
619
SHADOW_OFFSET_Y + inner_radius, 0.8);
621
gtk_style_context_save (context);
622
gtk_render_background (context, cr,
624
gtk_widget_get_allocated_width (widget) - 2 *SHADOW_OFFSET_X,
625
gtk_widget_get_allocated_height (widget) - SHADOW_OFFSET_Y);
626
gtk_render_frame (context,cr,
628
gtk_widget_get_allocated_width (widget) - 2 *SHADOW_OFFSET_X,
629
gtk_widget_get_allocated_height (widget) - SHADOW_OFFSET_Y);
631
gtk_style_context_restore (context);
633
if (GTK_WIDGET_CLASS (gd_notification_parent_class)->draw)
634
GTK_WIDGET_CLASS (gd_notification_parent_class)->draw(widget, cr);
641
gd_notification_add (GtkContainer *container,
644
GtkBin *bin = GTK_BIN (container);
645
GdNotification *notification = GD_NOTIFICATION (bin);
646
GdNotificationPrivate *priv = notification->priv;
648
g_return_if_fail (gtk_bin_get_child (bin) == NULL);
650
gtk_widget_set_parent_window (child, priv->bin_window);
652
GTK_CONTAINER_CLASS (gd_notification_parent_class)->add (container, child);
657
gd_notification_get_preferred_width (GtkWidget *widget, gint *minimum_size, gint *natural_size)
659
GdNotification *notification = GD_NOTIFICATION (widget);
660
GdNotificationPrivate *priv = notification->priv;
661
GtkBin *bin = GTK_BIN (widget);
662
gint child_min, child_nat;
665
gint minimum, natural;
667
get_padding_and_border (notification, &padding);
672
child = gtk_bin_get_child (bin);
673
if (child && gtk_widget_get_visible (child))
675
gtk_widget_get_preferred_width (child,
676
&child_min, &child_nat);
677
minimum += child_min;
678
natural += child_nat;
681
if (priv->show_close_button)
683
gtk_widget_get_preferred_width (priv->close_button,
684
&child_min, &child_nat);
685
minimum += child_min;
686
natural += child_nat;
689
minimum += padding.left + padding.right + 2 * SHADOW_OFFSET_X;
690
natural += padding.left + padding.right + 2 * SHADOW_OFFSET_X;
693
*minimum_size = minimum;
696
*natural_size = natural;
700
gd_notification_get_preferred_width_for_height (GtkWidget *widget,
705
GdNotification *notification = GD_NOTIFICATION (widget);
706
GdNotificationPrivate *priv = notification->priv;
707
GtkBin *bin = GTK_BIN (widget);
708
gint child_min, child_nat, child_height;
711
gint minimum, natural;
713
get_padding_and_border (notification, &padding);
718
child_height = height - SHADOW_OFFSET_Y - padding.top - padding.bottom;
720
child = gtk_bin_get_child (bin);
721
if (child && gtk_widget_get_visible (child))
723
gtk_widget_get_preferred_width_for_height (child, child_height,
724
&child_min, &child_nat);
725
minimum += child_min;
726
natural += child_nat;
729
if (priv->show_close_button)
731
gtk_widget_get_preferred_width_for_height (priv->close_button, child_height,
732
&child_min, &child_nat);
733
minimum += child_min;
734
natural += child_nat;
737
minimum += padding.left + padding.right + 2 * SHADOW_OFFSET_X;
738
natural += padding.left + padding.right + 2 * SHADOW_OFFSET_X;
741
*minimum_width = minimum;
744
*natural_width = natural;
748
gd_notification_get_preferred_height_for_width (GtkWidget *widget,
750
gint *minimum_height,
751
gint *natural_height)
753
GdNotification *notification = GD_NOTIFICATION (widget);
754
GdNotificationPrivate *priv = notification->priv;
755
GtkBin *bin = GTK_BIN (widget);
756
gint child_min, child_nat, child_width, button_width = 0;
759
gint minimum = 0, natural = 0;
761
get_padding_and_border (notification, &padding);
763
if (priv->show_close_button)
765
gtk_widget_get_preferred_height (priv->close_button,
767
gtk_widget_get_preferred_width (priv->close_button,
768
NULL, &button_width);
771
child = gtk_bin_get_child (bin);
772
if (child && gtk_widget_get_visible (child))
774
child_width = width - button_width -
775
2 * SHADOW_OFFSET_X - padding.left - padding.right;
777
gtk_widget_get_preferred_height_for_width (child, child_width,
778
&child_min, &child_nat);
779
minimum = MAX (minimum, child_min);
780
natural = MAX (natural, child_nat);
783
minimum += padding.top + padding.bottom + SHADOW_OFFSET_Y;
784
natural += padding.top + padding.bottom + SHADOW_OFFSET_Y;
787
*minimum_height = minimum;
790
*natural_height = natural;
794
gd_notification_get_preferred_height (GtkWidget *widget,
795
gint *minimum_height,
796
gint *natural_height)
800
gd_notification_get_preferred_width (widget, &width, NULL);
801
gd_notification_get_preferred_height_for_width (widget, width,
802
minimum_height, natural_height);
806
gd_notification_size_allocate (GtkWidget *widget,
807
GtkAllocation *allocation)
809
GdNotification *notification = GD_NOTIFICATION (widget);
810
GdNotificationPrivate *priv = notification->priv;
811
GtkBin *bin = GTK_BIN (widget);
812
GtkAllocation child_allocation;
814
GtkRequisition button_req;
817
gtk_widget_set_allocation (widget, allocation);
819
/* If somehow the notification changes while not hidden
820
and we're not animating, immediately follow the resize */
821
if (priv->animate_y > 0 &&
822
!priv->animate_timeout)
823
priv->animate_y = allocation->height;
825
get_padding_and_border (notification, &padding);
827
if (gtk_widget_get_realized (widget))
829
gdk_window_move_resize (gtk_widget_get_window (widget),
834
gdk_window_move_resize (priv->bin_window,
836
-allocation->height + priv->animate_y,
841
child_allocation.x = SHADOW_OFFSET_X + padding.left;
842
child_allocation.y = padding.top;
844
if (priv->show_close_button)
845
gtk_widget_get_preferred_size (priv->close_button, &button_req, NULL);
847
button_req.width = button_req.height = 0;
849
child_allocation.height = MAX (1, allocation->height - SHADOW_OFFSET_Y - padding.top - padding.bottom);
850
child_allocation.width = MAX (1, (allocation->width - button_req.width -
851
2 * SHADOW_OFFSET_X - padding.left - padding.right));
853
child = gtk_bin_get_child (bin);
854
if (child && gtk_widget_get_visible (child))
855
gtk_widget_size_allocate (child, &child_allocation);
857
if (priv->show_close_button)
859
child_allocation.x += child_allocation.width;
860
child_allocation.width = button_req.width;
861
child_allocation.y += (child_allocation.height - button_req.height) / 2;
862
child_allocation.height = button_req.height;
864
gtk_widget_size_allocate (priv->close_button, &child_allocation);
869
gd_notification_timeout_cb (gpointer user_data)
871
GdNotification *notification = GD_NOTIFICATION (user_data);
873
gd_notification_dismiss (notification);
879
gd_notification_set_timeout (GdNotification *notification,
882
GdNotificationPrivate *priv = notification->priv;
884
priv->timeout = timeout_sec;
885
g_object_notify (G_OBJECT (notification), "timeout");
889
gd_notification_set_show_close_button (GdNotification *notification,
890
gboolean show_close_button)
892
GdNotificationPrivate *priv = notification->priv;
894
priv->show_close_button = show_close_button;
896
gtk_widget_set_visible (priv->close_button, show_close_button);
897
gtk_widget_queue_resize (GTK_WIDGET (notification));
901
gd_notification_dismiss (GdNotification *notification)
903
GdNotificationPrivate *priv = notification->priv;
905
if (notification->priv->timeout_source_id)
907
g_source_remove (notification->priv->timeout_source_id);
908
notification->priv->timeout_source_id = 0;
911
priv->dismissed = TRUE;
912
priv->revealed = FALSE;
913
start_animation (notification);
917
gd_notification_close_button_clicked_cb (GtkWidget *widget, gpointer user_data)
919
GdNotification *notification = GD_NOTIFICATION(user_data);
921
gd_notification_dismiss (notification);
925
gd_notification_new (void)
927
return g_object_new (GD_TYPE_NOTIFICATION, NULL);