1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
4
* Copyright (C) Erick Pérez Castellanos 2011 <erick.red@gmail.com>
6
gtk-notification.c is free software: you can redistribute it and/or modify it
7
* under the terms of the GNU Lesser General Public License as published
8
* by the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* gtk-notification.c is distributed in the hope that it will be useful, but
12
* WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
* See the GNU Lesser General Public License for more details.
16
* You should have received a copy of the GNU Lesser General Public License
17
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
20
#include "gtk-notification.h"
23
* SECTION:gtknotification
24
* @short_description: Report notification messages to the user
26
* @see_also: #GtkStatusbar, #GtkMessageDialog, #GtkInfoBar
28
* #GtkNotification is a widget made for showing notifications to
29
* the user, allowing them to close the notification or wait for it
32
* #GtkNotification provides one signal (#GtkNotification::dismissed), for when the notification
33
* times out or is closed.
37
#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
38
#define SHADOW_OFFSET_X 2
39
#define SHADOW_OFFSET_Y 3
40
#define ANIMATION_TIME 200 /* msec */
41
#define ANIMATION_STEP 40 /* msec */
48
struct _GtkNotificationPrivate {
49
GtkWidget *close_button;
51
GdkWindow *bin_window;
53
int animate_y; /* from 0 to allocation.height */
54
gboolean waiting_for_viewable;
57
gboolean sent_dismissed;
58
guint animate_timeout;
61
guint timeout_source_id;
69
static guint notification_signals[LAST_SIGNAL] = { 0 };
71
static gboolean gtk_notification_draw (GtkWidget *widget,
73
static void gtk_notification_get_preferred_width (GtkWidget *widget,
76
static void gtk_notification_get_preferred_height_for_width (GtkWidget *widget,
79
gint *natural_height);
80
static void gtk_notification_get_preferred_height (GtkWidget *widget,
83
static void gtk_notification_get_preferred_width_for_height (GtkWidget *widget,
87
static void gtk_notification_size_allocate (GtkWidget *widget,
88
GtkAllocation *allocation);
89
static gboolean gtk_notification_timeout_cb (gpointer user_data);
90
static void gtk_notification_style_updated (GtkWidget *widget);
91
static void gtk_notification_show (GtkWidget *widget);
92
static void gtk_notification_add (GtkContainer *container,
95
/* signals handlers */
96
static void gtk_notification_close_button_clicked_cb (GtkWidget *widget,
98
static void gtk_notification_action_button_clicked_cb (GtkWidget *widget,
102
G_DEFINE_TYPE(GtkNotification, gtk_notification, GTK_TYPE_BIN);
105
gtk_notification_init (GtkNotification *notification)
107
GtkWidget *close_button_image;
108
GtkStyleContext *context;
109
GtkNotificationPrivate *priv;
111
context = gtk_widget_get_style_context (GTK_WIDGET (notification));
112
gtk_style_context_add_class (context, "contacts-notification");
115
gtk_widget_set_halign (GTK_WIDGET (notification), GTK_ALIGN_CENTER);
116
gtk_widget_set_valign (GTK_WIDGET (notification), GTK_ALIGN_START);
118
gtk_widget_set_has_window (GTK_WIDGET (notification), TRUE);
120
gtk_widget_push_composite_child ();
122
priv = notification->priv =
123
G_TYPE_INSTANCE_GET_PRIVATE (notification,
124
GTK_TYPE_NOTIFICATION,
125
GtkNotificationPrivate);
128
priv->close_button = gtk_button_new ();
129
gtk_widget_set_parent (priv->close_button, GTK_WIDGET (notification));
130
gtk_widget_show (priv->close_button);
131
g_object_set (priv->close_button,
132
"relief", GTK_RELIEF_NONE,
133
"focus-on-click", FALSE,
135
g_signal_connect (priv->close_button,
137
G_CALLBACK (gtk_notification_close_button_clicked_cb),
139
close_button_image = gtk_image_new_from_icon_name ("window-close-symbolic", GTK_ICON_SIZE_BUTTON);
140
gtk_button_set_image (GTK_BUTTON (notification->priv->close_button), close_button_image);
142
gtk_widget_pop_composite_child ();
144
priv->timeout_source_id = 0;
148
gtk_notification_finalize (GObject *object)
150
GtkNotification *notification;
151
GtkNotificationPrivate *priv;
153
g_return_if_fail (GTK_IS_NOTIFICATION (object));
155
notification = GTK_NOTIFICATION (object);
156
priv = notification->priv;
158
if (priv->animate_timeout != 0)
159
g_source_remove (priv->animate_timeout);
161
if (priv->timeout_source_id != 0)
162
g_source_remove (priv->timeout_source_id);
164
G_OBJECT_CLASS (gtk_notification_parent_class)->finalize (object);
168
gtk_notification_destroy (GtkWidget *widget)
170
GtkNotification *notification = GTK_NOTIFICATION (widget);
171
GtkNotificationPrivate *priv = notification->priv;
173
if (!priv->sent_dismissed)
175
g_signal_emit (notification, notification_signals[DISMISSED], 0);
176
priv->sent_dismissed = TRUE;
179
if (priv->close_button)
181
gtk_widget_unparent (priv->close_button);
182
priv->close_button = NULL;
185
GTK_WIDGET_CLASS (gtk_notification_parent_class)->destroy (widget);
189
gtk_notification_realize (GtkWidget *widget)
191
GtkNotification *notification = GTK_NOTIFICATION (widget);
192
GtkNotificationPrivate *priv = notification->priv;
193
GtkBin *bin = GTK_BIN (widget);
194
GtkAllocation allocation;
195
GtkAllocation view_allocation;
196
GtkStyleContext *context;
199
GdkWindowAttr attributes;
200
gint attributes_mask;
203
gtk_widget_set_realized (widget, TRUE);
205
gtk_widget_get_allocation (widget, &allocation);
207
attributes.x = allocation.x;
208
attributes.y = allocation.y;
209
attributes.width = allocation.width;
210
attributes.height = allocation.height;
211
attributes.window_type = GDK_WINDOW_CHILD;
212
attributes.wclass = GDK_INPUT_OUTPUT;
213
attributes.visual = gtk_widget_get_visual (widget);
215
attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK;
217
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
219
window = gdk_window_new (gtk_widget_get_parent_window (widget),
220
&attributes, attributes_mask);
221
gtk_widget_set_window (widget, window);
222
gdk_window_set_user_data (window, notification);
225
attributes.y = attributes.height + priv->animate_y;
226
attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_VISIBILITY_NOTIFY_MASK;
228
priv->bin_window = gdk_window_new (window, &attributes, attributes_mask);
229
gdk_window_set_user_data (priv->bin_window, notification);
231
child = gtk_bin_get_child (bin);
233
gtk_widget_set_parent_window (child, priv->bin_window);
234
gtk_widget_set_parent_window (priv->close_button, priv->bin_window);
236
context = gtk_widget_get_style_context (widget);
237
gtk_style_context_set_background (context, window);
238
gtk_style_context_set_background (context, priv->bin_window);
240
gdk_window_show (priv->bin_window);
244
gtk_notification_unrealize (GtkWidget *widget)
246
GtkNotification *notification = GTK_NOTIFICATION (widget);
247
GtkNotificationPrivate *priv = notification->priv;
249
gdk_window_set_user_data (priv->bin_window, NULL);
250
gdk_window_destroy (priv->bin_window);
251
priv->bin_window = NULL;
253
GTK_WIDGET_CLASS (gtk_notification_parent_class)->unrealize (widget);
257
animation_target (GtkNotification *notification)
259
GtkNotificationPrivate *priv = notification->priv;
260
GtkAllocation allocation;
262
if (priv->revealed) {
263
gtk_widget_get_allocation (GTK_WIDGET (notification), &allocation);
264
return allocation.height;
271
animation_timeout_cb (gpointer user_data)
273
GtkNotification *notification = GTK_NOTIFICATION (user_data);
274
GtkNotificationPrivate *priv = notification->priv;
275
GtkAllocation allocation;
278
target = animation_target (notification);
280
if (priv->animate_y != target) {
281
gtk_widget_get_allocation (GTK_WIDGET (notification), &allocation);
283
delta = allocation.height * ANIMATION_STEP / ANIMATION_TIME;
286
priv->animate_y += delta;
288
priv->animate_y -= delta;
290
priv->animate_y = CLAMP (priv->animate_y, 0, allocation.height);
292
if (priv->bin_window != NULL)
293
gdk_window_move (priv->bin_window,
295
-allocation.height + priv->animate_y);
299
if (priv->dismissed && priv->animate_y == 0)
300
gtk_widget_destroy (GTK_WIDGET (notification));
302
priv->animate_timeout = 0;
307
start_animation (GtkNotification *notification)
309
GtkNotificationPrivate *priv = notification->priv;
312
if (priv->animate_timeout != 0)
313
return; /* Already running */
315
target = animation_target (notification);
316
if (priv->animate_y != target)
317
notification->priv->animate_timeout =
318
gdk_threads_add_timeout (ANIMATION_STEP,
319
animation_timeout_cb,
324
gtk_notification_show (GtkWidget *widget)
326
GtkNotification *notification = GTK_NOTIFICATION (widget);
327
GtkNotificationPrivate *priv = notification->priv;
329
GTK_WIDGET_CLASS (gtk_notification_parent_class)->show (widget);
330
priv->revealed = TRUE;
331
priv->waiting_for_viewable = TRUE;
335
gtk_notification_hide (GtkWidget *widget)
337
GtkNotification *notification = GTK_NOTIFICATION (widget);
338
GtkNotificationPrivate *priv = notification->priv;
340
GTK_WIDGET_CLASS (gtk_notification_parent_class)->hide (widget);
341
priv->revealed = FALSE;
342
priv->waiting_for_viewable = FALSE;
346
gtk_notification_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
348
GtkNotification *notification = GTK_NOTIFICATION (object);
350
g_return_if_fail (GTK_IS_NOTIFICATION (object));
354
gtk_notification_set_timeout (notification,
355
g_value_get_uint (value));
358
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
364
gtk_notification_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
366
g_return_if_fail (GTK_IS_NOTIFICATION (object));
367
GtkNotification *notification = GTK_NOTIFICATION (object);
371
g_value_set_uint (value, notification->priv->timeout);
374
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
380
gtk_notification_forall (GtkContainer *container,
381
gboolean include_internals,
382
GtkCallback callback,
383
gpointer callback_data)
385
GtkBin *bin = GTK_BIN (container);
386
GtkNotification *notification = GTK_NOTIFICATION (container);
387
GtkNotificationPrivate *priv = notification->priv;
390
child = gtk_bin_get_child (bin);
392
(* callback) (child, callback_data);
394
if (include_internals)
395
(* callback) (priv->close_button, callback_data);
399
gtk_notification_visibility_notify_event (GtkWidget *widget,
400
GdkEventVisibility *event)
402
GtkNotification *notification = GTK_NOTIFICATION (widget);
403
GtkNotificationPrivate *priv = notification->priv;
405
if (priv->waiting_for_viewable)
407
start_animation (notification);
408
priv->waiting_for_viewable = FALSE;
411
if (notification->priv->timeout_source_id == 0)
412
notification->priv->timeout_source_id =
413
gdk_threads_add_timeout (notification->priv->timeout * 1000,
414
gtk_notification_timeout_cb,
421
gtk_notification_class_init (GtkNotificationClass *klass)
423
GObjectClass* object_class = G_OBJECT_CLASS (klass);
424
GtkWidgetClass* widget_class = GTK_WIDGET_CLASS(klass);
425
GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
427
object_class->finalize = gtk_notification_finalize;
428
object_class->set_property = gtk_notification_set_property;
429
object_class->get_property = gtk_notification_get_property;
431
widget_class->show = gtk_notification_show;
432
widget_class->destroy = gtk_notification_destroy;
433
widget_class->get_preferred_width = gtk_notification_get_preferred_width;
434
widget_class->get_preferred_height_for_width = gtk_notification_get_preferred_height_for_width;
435
widget_class->get_preferred_height = gtk_notification_get_preferred_height;
436
widget_class->get_preferred_width_for_height = gtk_notification_get_preferred_width_for_height;
437
widget_class->size_allocate = gtk_notification_size_allocate;
438
widget_class->draw = gtk_notification_draw;
439
widget_class->realize = gtk_notification_realize;
440
widget_class->unrealize = gtk_notification_unrealize;
441
widget_class->style_updated = gtk_notification_style_updated;
442
widget_class->visibility_notify_event = gtk_notification_visibility_notify_event;
444
container_class->add = gtk_notification_add;
445
container_class->forall = gtk_notification_forall;
446
gtk_container_class_handle_border_width (container_class);
450
* GtkNotification:timeout:
452
* The time it takes to hide the widget, in seconds.
456
g_object_class_install_property (object_class,
458
g_param_spec_uint("timeout", "timeout",
459
"The time it takes to hide the widget, in seconds",
461
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT));
463
notification_signals[DISMISSED] = g_signal_new ("dismissed",
464
G_OBJECT_CLASS_TYPE (klass),
466
G_STRUCT_OFFSET (GtkNotificationClass, dismissed),
469
g_cclosure_marshal_VOID__VOID,
473
g_type_class_add_private (object_class, sizeof (GtkNotificationPrivate));
477
draw_shadow_box (cairo_t *cr, GdkRectangle rect, int left_border, int right_border,
478
int bottom_border, double inner_alpha)
480
cairo_pattern_t *pattern;
481
cairo_matrix_t matrix;
482
double x0, x1, x2, x3;
488
x1 = rect.x + left_border;
489
x2 = rect.x + rect.width - right_border;
490
x3 = rect.x + rect.width;
493
y2 = rect.y + rect.height - bottom_border;
494
y3 = rect.y + rect.height;
498
pattern = cairo_pattern_create_linear(0, y2, 0, y3);
500
cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0, 0, 0, inner_alpha);
501
cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0, 0, 0, 0.0);
503
cairo_set_source(cr, pattern);
504
cairo_pattern_destroy(pattern);
506
cairo_rectangle(cr, x1, y2, x2 - x1, y3 - y2);
511
pattern = cairo_pattern_create_linear(x0, 0, x1, 0);
513
cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0, 0, 0, 0.0);
514
cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0, 0, 0, inner_alpha);
516
cairo_set_source(cr, pattern);
517
cairo_pattern_destroy(pattern);
519
cairo_rectangle(cr, x0, y0, x1 - x0, y2 - y0);
524
pattern = cairo_pattern_create_linear(x2, 0, x3, 0);
526
cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0, 0, 0, inner_alpha);
527
cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0, 0, 0, 0.0);
529
cairo_set_source(cr, pattern);
530
cairo_pattern_destroy(pattern);
532
cairo_rectangle(cr, x2, y0, x3 - x2, y2 - y0);
537
pattern = cairo_pattern_create_radial(0, 0, 0, 0.0, 0, 1.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_matrix_init_scale (&matrix, 1.0 / left_border, 1.0 / bottom_border);
542
cairo_matrix_translate (&matrix, - x1, -y2);
543
cairo_pattern_set_matrix (pattern, &matrix);
545
cairo_set_source(cr, pattern);
546
cairo_pattern_destroy(pattern);
548
cairo_rectangle(cr, x0, y2, x1 - x0, y3 - y2);
553
pattern = cairo_pattern_create_radial(0, 0, 0, 0, 0, 1.0);
554
cairo_pattern_add_color_stop_rgba(pattern, 0.0, 0.0, 0, 0, inner_alpha);
555
cairo_pattern_add_color_stop_rgba(pattern, 1.0, 0.0, 0, 0, 0.0);
557
cairo_matrix_init_scale (&matrix, 1.0 / left_border, 1.0 / bottom_border);
558
cairo_matrix_translate (&matrix, - x2, -y2);
559
cairo_pattern_set_matrix (pattern, &matrix);
561
cairo_set_source(cr, pattern);
562
cairo_pattern_destroy(pattern);
564
cairo_rectangle(cr, x2, y2, x3 - x2, y3 - y2);
571
get_padding_and_border (GtkNotification *notification,
574
GtkStyleContext *context;
578
context = gtk_widget_get_style_context (GTK_WIDGET (notification));
579
state = gtk_widget_get_state_flags (GTK_WIDGET (notification));
581
gtk_style_context_get_padding (context, state, border);
583
gtk_style_context_get_border (context, state, &tmp);
584
border->top += tmp.top;
585
border->right += tmp.right;
586
border->bottom += tmp.bottom;
587
border->left += tmp.left;
591
gtk_notification_draw (GtkWidget *widget, cairo_t *cr)
593
GtkNotification *notification = GTK_NOTIFICATION (widget);
594
GtkNotificationPrivate *priv = notification->priv;
595
GtkStyleContext *context;
599
if (gtk_cairo_should_draw_window (cr, priv->bin_window))
601
gtk_widget_get_allocation (widget, &rect);
603
context = gtk_widget_get_style_context(widget);
606
draw_shadow_box (cr, rect, SHADOW_OFFSET_X + inner_radius, SHADOW_OFFSET_X + inner_radius,
607
SHADOW_OFFSET_Y + inner_radius, 0.8);
609
gtk_style_context_save (context);
610
gtk_render_background (context, cr,
612
gtk_widget_get_allocated_width (widget) - 2 *SHADOW_OFFSET_X,
613
gtk_widget_get_allocated_height (widget) - SHADOW_OFFSET_Y);
614
gtk_render_frame (context,cr,
616
gtk_widget_get_allocated_width (widget) - 2 *SHADOW_OFFSET_X,
617
gtk_widget_get_allocated_height (widget) - SHADOW_OFFSET_Y);
619
gtk_style_context_restore (context);
621
if (GTK_WIDGET_CLASS (gtk_notification_parent_class)->draw)
622
GTK_WIDGET_CLASS (gtk_notification_parent_class)->draw(widget, cr);
629
gtk_notification_add (GtkContainer *container,
632
GtkBin *bin = GTK_BIN (container);
633
GtkNotification *notification = GTK_NOTIFICATION (bin);
634
GtkNotificationPrivate *priv = notification->priv;
636
g_return_if_fail (gtk_bin_get_child (bin) == NULL);
638
gtk_widget_set_parent_window (child, priv->bin_window);
640
GTK_CONTAINER_CLASS (gtk_notification_parent_class)->add (container, child);
645
gtk_notification_get_preferred_width (GtkWidget *widget, gint *minimum_size, gint *natural_size)
647
GtkNotification *notification = GTK_NOTIFICATION (widget);
648
GtkNotificationPrivate *priv = notification->priv;
649
GtkBin *bin = GTK_BIN (widget);
650
gint child_min, child_nat;
653
gint minimum, natural;
655
get_padding_and_border (notification, &padding);
660
child = gtk_bin_get_child (bin);
661
if (child && gtk_widget_get_visible (child))
663
gtk_widget_get_preferred_width (child,
664
&child_min, &child_nat);
665
minimum += child_min;
666
natural += child_nat;
669
gtk_widget_get_preferred_width (priv->close_button,
670
&child_min, &child_nat);
671
minimum += child_min;
672
natural += child_nat;
675
minimum += padding.left + padding.right + 2 * SHADOW_OFFSET_X;
676
natural += padding.left + padding.right + 2 * SHADOW_OFFSET_X;
679
*minimum_size = minimum;
682
*natural_size = natural;
686
gtk_notification_get_preferred_width_for_height (GtkWidget *widget,
691
GtkNotification *notification = GTK_NOTIFICATION (widget);
692
GtkNotificationPrivate *priv = notification->priv;
693
GtkBin *bin = GTK_BIN (widget);
694
gint child_min, child_nat, child_height;
697
gint minimum, natural;
699
get_padding_and_border (notification, &padding);
704
child_height = height - SHADOW_OFFSET_Y - padding.top - padding.bottom;
706
child = gtk_bin_get_child (bin);
707
if (child && gtk_widget_get_visible (child))
709
gtk_widget_get_preferred_width_for_height (child, child_height,
710
&child_min, &child_nat);
711
minimum += child_min;
712
natural += child_nat;
715
gtk_widget_get_preferred_width_for_height (priv->close_button, child_height,
716
&child_min, &child_nat);
717
minimum += child_min;
718
natural += child_nat;
720
minimum += padding.left + padding.right + 2 * SHADOW_OFFSET_X;
721
natural += padding.left + padding.right + 2 * SHADOW_OFFSET_X;
724
*minimum_width = minimum;
727
*natural_width = natural;
731
gtk_notification_get_preferred_height_for_width (GtkWidget *widget,
733
gint *minimum_height,
734
gint *natural_height)
736
GtkNotification *notification = GTK_NOTIFICATION (widget);
737
GtkNotificationPrivate *priv = notification->priv;
738
GtkBin *bin = GTK_BIN (widget);
739
gint child_min, child_nat, child_width, button_width;
742
gint minimum, natural;
744
get_padding_and_border (notification, &padding);
746
gtk_widget_get_preferred_height (priv->close_button,
748
gtk_widget_get_preferred_width (priv->close_button,
749
NULL, &button_width);
751
child = gtk_bin_get_child (bin);
752
if (child && gtk_widget_get_visible (child))
754
child_width = width - 2 * SHADOW_OFFSET_X - padding.left - padding.top - button_width;
756
gtk_widget_get_preferred_height_for_width (child, child_width,
757
&child_min, &child_nat);
758
minimum = MAX (minimum, child_min);
759
natural = MAX (natural, child_nat);
762
minimum += padding.top + padding.top + SHADOW_OFFSET_Y;
763
natural += padding.top + padding.top + SHADOW_OFFSET_Y;
766
*minimum_height = minimum;
769
*natural_height = natural;
773
gtk_notification_get_preferred_height (GtkWidget *widget, gint *minimum_height, gint *natural_height)
775
GtkNotification *notification = GTK_NOTIFICATION (widget);
776
GtkNotificationPrivate *priv = notification->priv;
777
GtkBin *bin = GTK_BIN (widget);
778
gint child_min, child_nat;
781
gint minimum, natural;
783
get_padding_and_border (notification, &padding);
785
gtk_widget_get_preferred_height (priv->close_button,
788
child = gtk_bin_get_child (bin);
789
if (child && gtk_widget_get_visible (child))
791
gtk_widget_get_preferred_height (child,
792
&child_min, &child_nat);
793
minimum = MAX (minimum, child_min);
794
natural = MAX (natural, child_nat);
797
minimum += padding.top + padding.top + SHADOW_OFFSET_Y;
798
natural += padding.top + padding.top + SHADOW_OFFSET_Y;
801
*minimum_height = minimum;
804
*natural_height = natural;
808
gtk_notification_size_allocate (GtkWidget *widget,
809
GtkAllocation *allocation)
811
GtkNotification *notification = GTK_NOTIFICATION (widget);
812
GtkNotificationPrivate *priv = notification->priv;
813
GtkBin *bin = GTK_BIN (widget);
814
GtkAllocation child_allocation;
819
gtk_widget_set_allocation (widget, allocation);
821
/* If somehow the notification changes while not hidden
822
and we're not animating, immediately follow the resize */
823
if (priv->animate_y > 0 &&
824
!priv->animate_timeout)
825
priv->animate_y = allocation->height;
827
get_padding_and_border (notification, &padding);
829
if (gtk_widget_get_realized (widget))
831
gdk_window_move_resize (gtk_widget_get_window (widget),
836
gdk_window_move_resize (priv->bin_window,
838
-allocation->height + priv->animate_y,
843
child_allocation.x = SHADOW_OFFSET_X + padding.left;
844
child_allocation.y = padding.top;
845
child_allocation.height = MAX (1, allocation->height - SHADOW_OFFSET_Y - padding.top - padding.bottom);
846
gtk_widget_get_preferred_width_for_height (priv->close_button, child_allocation.height,
847
NULL, &button_width);
849
child_allocation.width = MAX (1, allocation->width - 2 * SHADOW_OFFSET_X - padding.left - padding.right - button_width);
851
child = gtk_bin_get_child (bin);
852
if (child && gtk_widget_get_visible (child))
853
gtk_widget_size_allocate (child, &child_allocation);
855
child_allocation.x += child_allocation.width;
856
child_allocation.width = button_width;
858
gtk_widget_size_allocate (priv->close_button, &child_allocation);
862
gtk_notification_timeout_cb (gpointer user_data)
864
GtkNotification *notification = GTK_NOTIFICATION (user_data);
866
gtk_notification_dismiss (notification);
872
gtk_notification_style_updated (GtkWidget *widget)
874
GTK_WIDGET_CLASS (gtk_notification_parent_class)->style_updated (widget);
876
if (gtk_widget_get_realized (widget))
878
GtkStyleContext *context;
879
GtkNotification *notification = GTK_NOTIFICATION (widget);
880
GtkNotificationPrivate *priv = notification->priv;
882
context = gtk_widget_get_style_context (widget);
883
gtk_style_context_set_background (context, priv->bin_window);
884
gtk_style_context_set_background (context, gtk_widget_get_window (widget));
889
gtk_notification_set_timeout (GtkNotification *notification,
892
GtkNotificationPrivate *priv = notification->priv;
894
priv->timeout = timeout_msec;
895
g_object_notify (G_OBJECT (notification), "timeout");
899
gtk_notification_dismiss (GtkNotification *notification)
901
GtkNotificationPrivate *priv = notification->priv;
903
if (notification->priv->timeout_source_id)
905
g_source_remove (notification->priv->timeout_source_id);
906
notification->priv->timeout_source_id = 0;
909
priv->dismissed = TRUE;
910
priv->revealed = FALSE;
911
start_animation (notification);
915
gtk_notification_close_button_clicked_cb (GtkWidget *widget, gpointer user_data)
917
GtkNotification *notification = GTK_NOTIFICATION(user_data);
918
GtkNotificationPrivate *priv = notification->priv;
920
gtk_notification_dismiss (notification);
924
gtk_notification_new (void)
926
return g_object_new (GTK_TYPE_NOTIFICATION, NULL);