2 * This file is a part of hildon
4 * Copyright (C) 2005, 2006, 2007 Nokia Corporation, all rights reserved.
6 * Contact: Rodrigo Novo <rodrigo.novo@nokia.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; version 2.1 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
26 * SECTION:hildon-banner
27 * @short_description: A widget used to display timed notifications.
29 * #HildonBanner is a small, pop-up window that can be used to display
30 * a short, timed notification or information to the user. It can
31 * communicate that a task has been finished or that the application
34 * Hildon provides convenient funtions to create and show banners. To
35 * create and show information banners you can use
36 * hildon_banner_show_information(), hildon_banner_show_informationf()
37 * or hildon_banner_show_information_with_markup().
39 * If the application window has set the _HILDON_DO_NOT_DISTURB flag (using
40 * hildon_gtk_window_set_do_not_disturb() for example), the banner will not
41 * be shown. If you need to override this flag for important information,
42 * you can use the method hildon_banner_show_information_override_dnd().
43 * Please, take into account that this is only for important information.
46 * Two more kinds of banners are maintained for backward compatibility
47 * but are no longer recommended in Hildon 2.2. These are the animated
48 * banner (created with hildon_banner_show_animation()) and the
49 * progress banner (created with hildon_banner_show_progress()). See
50 * hildon_gtk_window_set_progress_indicator() for the preferred way of
51 * showing progress notifications in Hildon 2.2.
53 * Information banners are automatically destroyed after a certain
54 * period. This is stored in the #HildonBanner:timeout property (in
55 * miliseconds), and can be changed using hildon_banner_set_timeout().
57 * Note that #HildonBanner<!-- -->s should only be used to display
58 * non-critical pieces of information.
61 * <title>Using the HildonBanner widget</title>
63 * void show_info_banner (GtkWidget *parent)
67 * banner = hildon_banner_show_information (widget, NULL, "Information banner");
68 * hildon_banner_set_timeout (HILDON_BANNER (banner), 9000);
81 #include <X11/Xatom.h>
84 #undef HILDON_DISABLE_DEPRECATED
86 #include "hildon-banner.h"
87 #include "hildon-banner-private.h"
88 #include "hildon-defines.h"
89 #include "hildon-gtk.h"
91 /* position relative to the screen */
93 #define HILDON_BANNER_WINDOW_X 0
95 #define HILDON_BANNER_WINDOW_Y HILDON_WINDOW_TITLEBAR_HEIGHT
99 #define HILDON_BANNER_LABEL_MAX_TIMED \
100 (gdk_screen_width() - ((HILDON_MARGIN_TRIPLE) * 2))
102 #define HILDON_BANNER_LABEL_MAX_PROGRESS 375 /*265*/
104 /* default timeout */
106 #define HILDON_BANNER_DEFAULT_TIMEOUT 3000
110 #define HILDON_BANNER_DEFAULT_PROGRESS_ANIMATION "indicator_update"
112 /* animation related stuff */
114 #define HILDON_BANNER_ANIMATION_FRAMERATE ((float)1000/150)
116 #define HILDON_BANNER_ANIMATION_TMPL "indicator_update%d"
118 #define HILDON_BANNER_ANIMATION_NFRAMES 8
128 static GtkWidget* global_timed_banner = NULL;
131 hildon_banner_timed_quark (void);
134 hildon_banner_bind_style (HildonBanner *self,
138 hildon_banner_timeout (gpointer data);
141 hildon_banner_clear_timeout (HildonBanner *self);
144 hildon_banner_ensure_timeout (HildonBanner *self);
147 hildon_banner_set_property (GObject *object,
153 hildon_banner_get_property (GObject *object,
159 hildon_banner_destroy (GtkObject *object);
162 hildon_banner_real_get_instance (GObject *window,
166 hildon_banner_constructor (GType type,
167 guint n_construct_params,
168 GObjectConstructParam *construct_params);
171 hildon_banner_finalize (GObject *object);
174 hildon_banner_button_press_event (GtkWidget* widget,
175 GdkEventButton* event);
178 hildon_banner_map_event (GtkWidget *widget,
181 hildon_banner_reset_wrap_state (HildonBanner *banner);
184 force_to_wrap_truncated (HildonBanner *banner);
187 hildon_banner_check_position (GtkWidget *widget);
190 hildon_banner_realize (GtkWidget *widget);
193 hildon_banner_class_init (HildonBannerClass *klass);
196 hildon_banner_init (HildonBanner *self);
199 hildon_banner_ensure_child (HildonBanner *self,
200 GtkWidget *user_widget,
203 const gchar *first_property,
207 hildon_banner_get_instance_for_widget (GtkWidget *widget,
211 hildon_banner_set_override_flag (HildonBanner *banner);
214 hildon_banner_real_show_information (GtkWidget *widget,
216 gboolean override_dnd);
219 G_DEFINE_TYPE (HildonBanner, hildon_banner, GTK_TYPE_WINDOW)
222 hildon_banner_timed_quark (void)
224 static GQuark quark = 0;
226 if (G_UNLIKELY(quark == 0))
227 quark = g_quark_from_static_string ("hildon-banner-timed");
232 /* Set the widget and label name to make the correct rc-style attached into them */
234 hildon_banner_bind_style (HildonBanner *self,
235 const gchar *name_sufix)
237 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (self);
242 name = g_strconcat ("HildonBannerLabel-", name_sufix, NULL);
243 gtk_widget_set_name (priv->label, name);
246 name = g_strconcat ("HildonBanner-", name_sufix, NULL);
247 gtk_widget_set_name (GTK_WIDGET (self), name);
251 /* In timeout function we automatically destroy timed banners */
253 simulate_close (GtkWidget* widget)
255 gboolean result = FALSE;
257 /* If the banner is currently visible (it normally should),
258 we simulate clicking the close button of the window.
259 This allows applications to reuse the banner by prevent
261 if (GTK_WIDGET_DRAWABLE (widget))
263 GdkEvent *event = gdk_event_new (GDK_DELETE);
264 event->any.window = g_object_ref (widget->window);
265 event->any.send_event = FALSE;
266 result = gtk_widget_event (widget, event);
267 gdk_event_free (event);
274 hildon_banner_timeout (gpointer data)
277 gboolean continue_timeout = FALSE;
279 GDK_THREADS_ENTER ();
281 g_assert (HILDON_IS_BANNER (data));
283 widget = GTK_WIDGET (data);
284 g_object_ref (widget);
286 continue_timeout = simulate_close (widget);
288 if (! continue_timeout) {
289 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (data);
290 priv->timeout_id = 0;
291 gtk_widget_destroy (widget);
294 g_object_unref (widget);
296 GDK_THREADS_LEAVE ();
298 return continue_timeout;
302 hildon_banner_clear_timeout (HildonBanner *self)
304 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (self);
307 if (priv->timeout_id != 0) {
308 g_source_remove (priv->timeout_id);
309 priv->timeout_id = 0;
317 hildon_banner_ensure_timeout (HildonBanner *self)
319 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (self);
322 if (priv->timeout_id == 0 && priv->is_timed && priv->timeout > 0)
323 priv->timeout_id = g_timeout_add (priv->timeout,
324 hildon_banner_timeout, self);
328 hildon_banner_set_property (GObject *object,
334 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (object);
340 priv->timeout = g_value_get_uint (value);
344 priv->is_timed = g_value_get_boolean (value);
347 case PROP_PARENT_WINDOW:
348 window = g_value_get_object (value);
350 g_object_remove_weak_pointer(G_OBJECT (priv->parent), (gpointer) &priv->parent);
353 gtk_window_set_transient_for (GTK_WINDOW (object), (GtkWindow *) window);
354 priv->parent = (GtkWindow *) window;
357 gtk_window_set_destroy_with_parent (GTK_WINDOW (object), TRUE);
358 g_object_add_weak_pointer(G_OBJECT (window), (gpointer) &priv->parent);
364 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
370 hildon_banner_get_property (GObject *object,
375 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (object);
381 g_value_set_uint (value, priv->timeout);
385 g_value_set_boolean (value, priv->is_timed);
388 case PROP_PARENT_WINDOW:
389 g_value_set_object (value, gtk_window_get_transient_for (GTK_WINDOW (object)));
393 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
399 hildon_banner_destroy (GtkObject *object)
401 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (object);
405 GObject *parent_window = (GObject *) priv->parent;
407 g_assert (HILDON_IS_BANNER (object));
408 self = HILDON_BANNER (object);
410 /* Drop possible global pointer. That can hold reference to us */
411 if ((gpointer) object == (gpointer) global_timed_banner) {
412 global_timed_banner = NULL;
413 g_object_unref (object);
416 /* Remove the data from parent window for timed banners. Those hold reference */
417 if (priv->is_timed && parent_window != NULL) {
418 g_object_set_qdata (parent_window, hildon_banner_timed_quark (), NULL);
421 if (!priv->is_timed && priv->parent) {
422 hildon_gtk_window_set_progress_indicator (priv->parent, 0);
425 (void) hildon_banner_clear_timeout (self);
427 if (GTK_OBJECT_CLASS (hildon_banner_parent_class)->destroy)
428 GTK_OBJECT_CLASS (hildon_banner_parent_class)->destroy (object);
431 /* Search a previous banner instance */
433 hildon_banner_real_get_instance (GObject *window,
437 /* If we have a parent window, the previous instance is stored there */
439 return g_object_get_qdata(window, hildon_banner_timed_quark ());
442 /* System notification instance is stored into global pointer */
443 return (GObject *) global_timed_banner;
446 /* Non-timed banners are normal (non-singleton) objects */
450 /* By overriding constructor we force timed banners to be
451 singletons for each window */
453 hildon_banner_constructor (GType type,
454 guint n_construct_params,
455 GObjectConstructParam *construct_params)
457 GObject *banner, *window = NULL;
458 gboolean timed = FALSE;
461 /* Search banner type information from parameters in order
462 to locate the possible previous banner instance. */
463 for (i = 0; i < n_construct_params; i++)
465 if (strcmp(construct_params[i].pspec->name, "parent-window") == 0)
466 window = g_value_get_object (construct_params[i].value);
467 else if (strcmp(construct_params[i].pspec->name, "is-timed") == 0)
468 timed = g_value_get_boolean (construct_params[i].value);
471 /* Try to get a previous instance if such exists */
472 banner = hildon_banner_real_get_instance (window, timed);
475 /* We have to create a new banner */
476 banner = G_OBJECT_CLASS (hildon_banner_parent_class)->constructor (type, n_construct_params, construct_params);
478 /* Store the newly created singleton instance either into parent
479 window data or into global variables. */
482 g_object_set_qdata_full (G_OBJECT (window), hildon_banner_timed_quark (),
483 g_object_ref (banner), g_object_unref);
485 g_assert (global_timed_banner == NULL);
486 global_timed_banner = g_object_ref (banner);
491 /* FIXME: This is a hack! We have to manually freeze
492 notifications. This is normally done by g_object_init, but we
493 are not going to call that. g_object_newv will otherwise give
494 a critical like this:
496 GLIB CRITICAL ** GLib-GObject - g_object_notify_queue_thaw:
497 assertion `nqueue->freeze_count > 0' failed */
499 g_object_freeze_notify (banner);
500 hildon_banner_reset_wrap_state (HILDON_BANNER (banner));
503 /* We restart possible timeouts for each new timed banner request */
504 if (timed && hildon_banner_clear_timeout (HILDON_BANNER (banner)))
505 hildon_banner_ensure_timeout (HILDON_BANNER(banner));
511 hildon_banner_finalize (GObject *object)
513 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (object);
516 g_object_remove_weak_pointer(G_OBJECT (priv->parent), (gpointer) &priv->parent);
519 G_OBJECT_CLASS (hildon_banner_parent_class)->finalize (object);
523 hildon_banner_button_press_event (GtkWidget* widget,
524 GdkEventButton* event)
526 gboolean result = simulate_close (widget);
529 /* signal emission not stopped - basically behave like
530 * gtk_main_do_event() for a delete event, but just hide the
531 * banner instead of destroying it, as it is already meant to
532 * be destroyed by hildon_banner_timeout() (if it's timed) or
533 * the application (if it's not). */
534 gtk_widget_hide (widget);
540 #if defined(MAEMO_GTK)
542 hildon_banner_map (GtkWidget *widget)
544 if (GTK_WIDGET_CLASS (hildon_banner_parent_class)->map) {
545 /* Make the banner temporary _before_ mapping it, to avoid closing
546 * other temporary windows */
547 gtk_window_set_is_temporary (GTK_WINDOW (widget), TRUE);
549 GTK_WIDGET_CLASS (hildon_banner_parent_class)->map (widget);
551 /* Make the banner non-temporary _after_ mapping it, to avoid
552 * being closed by other non-temporary windows */
553 gtk_window_set_is_temporary (GTK_WINDOW (widget), FALSE);
555 hildon_banner_check_position (widget);
560 /* We start the timer for timed notifications after the window appears on screen */
562 hildon_banner_map_event (GtkWidget *widget,
565 gboolean result = FALSE;
567 if (GTK_WIDGET_CLASS (hildon_banner_parent_class)->map_event)
568 result = GTK_WIDGET_CLASS (hildon_banner_parent_class)->map_event (widget, event);
570 hildon_banner_ensure_timeout (HILDON_BANNER(widget));
576 hildon_banner_reset_wrap_state (HildonBanner *banner)
579 HildonBannerPrivate *priv;
581 priv = HILDON_BANNER_GET_PRIVATE (banner);
584 layout = gtk_label_get_layout (GTK_LABEL (priv->label));
586 pango_layout_set_width (layout, -1);
587 priv->has_been_wrapped = FALSE;
588 priv->has_been_truncated = FALSE;
590 gtk_widget_set_size_request (priv->label, -1, -1);
591 gtk_widget_set_size_request (GTK_WIDGET (banner), -1, -1);
594 /* force to wrap truncated label by setting explicit size request
595 * see N#27000 and G#329646 */
597 force_to_wrap_truncated (HildonBanner *banner)
601 int width_text, width_max;
604 PangoRectangle logical;
605 GtkRequisition requisition;
606 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (banner);
608 g_return_if_fail (priv);
610 label = GTK_LABEL (priv->label);
612 layout = gtk_label_get_layout (label);
614 pango_layout_get_extents (layout, NULL, &logical);
615 width_text = PANGO_PIXELS (logical.width);
617 width_max = priv->is_timed ? HILDON_BANNER_LABEL_MAX_TIMED
618 : HILDON_BANNER_LABEL_MAX_PROGRESS;
620 /* If the width of the label is going to exceed the maximum allowed
621 * width, enforce the maximum allowed width now.
623 if (priv->has_been_wrapped
624 || width_text >= width_max
625 || pango_layout_is_wrapped (layout)) {
626 /* Force wrapping by setting the maximum size */
629 priv->has_been_wrapped = TRUE;
632 /* Make the label update its layout; and update our layout pointer
633 * because the layout will be cleared and refreshed.
635 gtk_widget_set_size_request (GTK_WIDGET (label), width, height);
636 gtk_widget_size_request (GTK_WIDGET (label), &requisition);
638 layout = gtk_label_get_layout (label);
640 /* If the layout has now been wrapped and exceeds 3 lines, we truncate
641 * the rest of the label according to spec.
643 if (priv->has_been_truncated
644 || (pango_layout_is_wrapped (layout)
645 && pango_layout_get_line_count (layout) > 3)) {
648 pango_layout_get_extents (layout, NULL, &logical);
649 lines = pango_layout_get_line_count (layout);
651 /* This calculation assumes that the same font is used
652 * throughout the banner -- this is usually the case on maemo
654 * FIXME: Pango >= 1.20 has pango_layout_set_height().
656 height = (PANGO_PIXELS (logical.height) * 3) / lines + 1;
657 priv->has_been_truncated = TRUE;
660 /* Set the new width/height if applicable */
661 gtk_widget_set_size_request (GTK_WIDGET (label), width, height);
666 hildon_banner_check_position (GtkWidget *widget)
671 gtk_widget_set_size_request (widget, gdk_screen_width (), -1);
673 force_to_wrap_truncated (HILDON_BANNER(widget)); /* see N#27000 and G#329646 */
675 gtk_widget_size_request (widget, &req);
682 x = HILDON_BANNER_WINDOW_X;
684 y = HILDON_BANNER_WINDOW_Y;
686 gtk_window_move (GTK_WINDOW (widget), x, y);
690 screen_size_changed (GdkScreen *screen,
694 gtk_window_reshow_with_initial_size (banner);
698 hildon_banner_realize (GtkWidget *widget)
703 guint32 portrait = 1;
704 const gchar *notification_type = "_HILDON_NOTIFICATION_TYPE_BANNER";
705 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (widget);
708 /* We let the parent to init widget->window before we need it */
709 if (GTK_WIDGET_CLASS (hildon_banner_parent_class)->realize)
710 GTK_WIDGET_CLASS (hildon_banner_parent_class)->realize (widget);
712 /* We use special hint to turn the banner into information notification. */
713 gdk_window_set_type_hint (widget->window, GDK_WINDOW_TYPE_HINT_NOTIFICATION);
714 gtk_window_set_transient_for (GTK_WINDOW (widget), (GtkWindow *) priv->parent);
716 hildon_banner_check_position (widget);
718 gdkwin = widget->window;
720 /* Set the _HILDON_NOTIFICATION_TYPE property so Matchbox places the window correctly */
721 atom = gdk_atom_intern ("_HILDON_NOTIFICATION_TYPE", FALSE);
722 gdk_property_change (gdkwin, atom, gdk_x11_xatom_to_atom (XA_STRING), 8, GDK_PROP_MODE_REPLACE,
723 (gpointer) notification_type, strlen (notification_type));
725 /* HildonBanner supports portrait mode */
726 atom = gdk_atom_intern ("_HILDON_PORTRAIT_MODE_SUPPORT", FALSE);
727 gdk_property_change (gdkwin, atom, gdk_x11_xatom_to_atom (XA_CARDINAL), 32,
728 GDK_PROP_MODE_REPLACE, (gpointer) &portrait, 1);
730 /* Manage override flag */
731 if ((priv->require_override_dnd)&&(!priv->overrides_dnd)) {
732 hildon_banner_set_override_flag (HILDON_BANNER (widget));
733 priv->overrides_dnd = TRUE;
736 screen = gtk_widget_get_screen (widget);
737 g_signal_connect (screen, "size-changed", G_CALLBACK (screen_size_changed), widget);
741 hildon_banner_unrealize (GtkWidget *widget)
743 GdkScreen *screen = gtk_widget_get_screen (widget);
744 g_signal_handlers_disconnect_by_func (screen, G_CALLBACK (screen_size_changed), widget);
746 GTK_WIDGET_CLASS (hildon_banner_parent_class)->unrealize (widget);
750 hildon_banner_class_init (HildonBannerClass *klass)
752 GObjectClass *object_class;
753 GtkWidgetClass *widget_class;
755 object_class = G_OBJECT_CLASS (klass);
756 widget_class = GTK_WIDGET_CLASS (klass);
758 /* Append private structure to class. This is more elegant than
759 on g_new based approach */
760 g_type_class_add_private (klass, sizeof (HildonBannerPrivate));
762 /* Override virtual methods */
763 object_class->constructor = hildon_banner_constructor;
764 object_class->finalize = hildon_banner_finalize;
765 object_class->set_property = hildon_banner_set_property;
766 object_class->get_property = hildon_banner_get_property;
767 GTK_OBJECT_CLASS (klass)->destroy = hildon_banner_destroy;
768 widget_class->map_event = hildon_banner_map_event;
769 widget_class->realize = hildon_banner_realize;
770 widget_class->unrealize = hildon_banner_unrealize;
771 widget_class->button_press_event = hildon_banner_button_press_event;
772 #if defined(MAEMO_GTK)
773 widget_class->map = hildon_banner_map;
776 /* Install properties.
777 We need construct properties for singleton purposes */
780 * HildonBanner:parent-window:
782 * The window for which the banner will be singleton.
785 g_object_class_install_property (object_class, PROP_PARENT_WINDOW,
786 g_param_spec_object ("parent-window",
788 "The window for which the banner will be singleton",
789 GTK_TYPE_WINDOW, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
792 * HildonBanner:is-timed:
794 * Whether the banner is timed and goes away automatically.
797 g_object_class_install_property (object_class, PROP_IS_TIMED,
798 g_param_spec_boolean ("is-timed",
800 "Whether or not the notification goes away automatically "
801 "after the specified time has passed",
802 FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
805 * HildonBanner:timeout:
807 * The time before destroying the banner. This needs
808 * to be adjusted before the banner is mapped to the screen.
811 g_object_class_install_property (object_class, PROP_TIMEOUT,
812 g_param_spec_uint ("timeout",
814 "The time before making the banner banner go away",
817 HILDON_BANNER_DEFAULT_TIMEOUT,
818 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
822 hildon_banner_init (HildonBanner *self)
824 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (self);
828 priv->overrides_dnd = FALSE;
829 priv->require_override_dnd = FALSE;
831 /* Initialize the common layout inside banner */
832 priv->alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
833 priv->layout = gtk_hbox_new (FALSE, HILDON_MARGIN_DEFAULT);
835 priv->label = g_object_new (GTK_TYPE_LABEL, NULL);
836 gtk_label_set_line_wrap (GTK_LABEL (priv->label), TRUE);
837 gtk_label_set_line_wrap_mode (GTK_LABEL (priv->label), PANGO_WRAP_WORD_CHAR);
839 gtk_container_set_border_width (GTK_CONTAINER (priv->layout), HILDON_MARGIN_DEFAULT);
840 gtk_container_add (GTK_CONTAINER (self), priv->alignment);
841 gtk_container_add (GTK_CONTAINER (priv->alignment), priv->layout);
842 gtk_box_pack_start (GTK_BOX (priv->layout), priv->label, FALSE, FALSE, 0);
844 gtk_window_set_accept_focus (GTK_WINDOW (self), FALSE);
846 hildon_banner_reset_wrap_state (self);
848 gtk_widget_add_events (GTK_WIDGET (self), GDK_BUTTON_PRESS_MASK);
851 /* Makes sure that icon/progress item contains the desired type
852 of item. If possible, tries to avoid creating a new widget but
853 reuses the existing one */
855 hildon_banner_ensure_child (HildonBanner *self,
856 GtkWidget *user_widget,
859 const gchar *first_property,
864 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (self);
868 widget = priv->main_item;
869 va_start (args, first_property);
871 /* Reuse existing widget if possible */
872 if (! user_widget && G_TYPE_CHECK_INSTANCE_TYPE (widget, type))
874 g_object_set_valist (G_OBJECT (widget), first_property, args);
878 /* We have to abandon old content widget */
880 gtk_container_remove (GTK_CONTAINER (priv->layout), widget);
882 /* Use user provided widget or create a new one */
883 priv->main_item = widget = user_widget ?
884 user_widget : GTK_WIDGET (g_object_new_valist(type, first_property, args));
885 gtk_box_pack_start (GTK_BOX (priv->layout), widget, FALSE, FALSE, 0);
888 /* We make sure that the widget exists in desired position. Different
889 banners place this child widget to different places */
890 gtk_box_reorder_child (GTK_BOX (priv->layout), widget, pos);
894 /* Creates a new banner instance or uses an existing one */
896 hildon_banner_get_instance_for_widget (GtkWidget *widget,
901 window = widget ? gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW) : NULL;
902 return g_object_new (HILDON_TYPE_BANNER, "parent-window", window, "is-timed", timed, NULL);
906 hildon_banner_create_animation (void)
909 GdkPixbufSimpleAnim *anim;
912 GError *error = NULL;
916 anim = gdk_pixbuf_simple_anim_new (HILDON_ICON_PIXEL_SIZE_STYLUS,
917 HILDON_ICON_PIXEL_SIZE_STYLUS,
918 HILDON_BANNER_ANIMATION_FRAMERATE);
919 gdk_pixbuf_simple_anim_set_loop (anim, TRUE);
920 theme = gtk_icon_theme_get_default ();
922 for (i = 1; i <= HILDON_BANNER_ANIMATION_NFRAMES; i++) {
923 icon_name = g_strdup_printf (HILDON_BANNER_ANIMATION_TMPL, i);
924 frame = gtk_icon_theme_load_icon (theme, icon_name, HILDON_ICON_PIXEL_SIZE_STYLUS,
928 g_warning ("Icon theme lookup for icon `%s' failed: %s",
929 icon_name, error->message);
930 g_error_free (error);
933 gdk_pixbuf_simple_anim_add_frame (anim, frame);
936 g_object_unref (frame);
940 image = gtk_image_new_from_animation (GDK_PIXBUF_ANIMATION (anim));
941 g_object_unref (anim);
947 * hildon_banner_show_information:
948 * @widget: the #GtkWidget that is the owner of the banner
949 * @icon_name: since Hildon 2.2 this parameter is not used anymore and
950 * any value that you pass will be ignored
951 * @text: Text to display
953 * This function creates and displays an information banner that is
954 * automatically destroyed after a certain time period (see
955 * hildon_banner_set_timeout()). For each window in your application
956 * there can only be one timed banner, so if you spawn a new banner
957 * before the earlier one has timed out, the previous one will be
960 * Returns: The newly created banner
964 hildon_banner_show_information (GtkWidget *widget,
965 const gchar *icon_name,
968 return hildon_banner_real_show_information (widget, text, FALSE);
972 * hildon_banner_show_information_override_dnd:
973 * @widget: the #GtkWidget that is the owner of the banner
974 * @text: Text to display
976 * Equivalent to hildon_banner_show_information(), but overriding the
977 * "do not disturb" flag.
979 * Returns: The newly created banner
985 hildon_banner_show_information_override_dnd (GtkWidget *widget,
988 return hildon_banner_real_show_information (widget, text, TRUE);
992 hildon_banner_set_override_flag (HildonBanner *banner)
996 gdk_property_change (GTK_WIDGET (banner)->window,
997 gdk_atom_intern_static_string ("_HILDON_DO_NOT_DISTURB_OVERRIDE"),
998 gdk_x11_xatom_to_atom (XA_INTEGER),
1000 GDK_PROP_MODE_REPLACE,
1001 (const guchar*) &state,
1007 hildon_banner_real_show_information (GtkWidget *widget,
1009 gboolean override_dnd)
1011 HildonBanner *banner;
1012 HildonBannerPrivate *priv = NULL;
1014 g_return_val_if_fail (text != NULL, NULL);
1016 /* Prepare banner */
1017 banner = hildon_banner_get_instance_for_widget (widget, TRUE);
1018 priv = HILDON_BANNER_GET_PRIVATE (banner);
1020 hildon_banner_set_text (banner, text);
1021 hildon_banner_bind_style (banner, "information");
1024 /* so on the realize it will set the property */
1025 priv->require_override_dnd = TRUE;
1028 /* Show the banner, since caller cannot do that */
1029 gtk_widget_show_all (GTK_WIDGET (banner));
1031 return GTK_WIDGET (banner);
1035 * hildon_banner_show_informationf:
1036 * @widget: the #GtkWidget that is the owner of the banner
1037 * @icon_name: since Hildon 2.2 this parameter is not used anymore and
1038 * any value that you pass will be ignored
1039 * @format: a printf-like format string
1040 * @Varargs: arguments for the format string
1042 * A helper function for hildon_banner_show_information() with
1043 * string formatting.
1045 * Returns: the newly created banner
1048 hildon_banner_show_informationf (GtkWidget *widget,
1049 const gchar *icon_name,
1050 const gchar *format,
1053 g_return_val_if_fail (format != NULL, NULL);
1059 va_start (args, format);
1060 message = g_strdup_vprintf (format, args);
1063 banner = hildon_banner_show_information (widget, icon_name, message);
1071 * hildon_banner_show_information_with_markup:
1072 * @widget: the #GtkWidget that wants to display banner
1073 * @icon_name: since Hildon 2.2 this parameter is not used anymore and
1074 * any value that you pass will be ignored
1075 * @markup: a markup string to display (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1077 * This function creates and displays an information banner that is
1078 * automatically destroyed after certain time period (see
1079 * hildon_banner_set_timeout()). For each window in your application
1080 * there can only be one timed banner, so if you spawn a new banner
1081 * before the earlier one has timed out, the previous one will be
1084 * Returns: the newly created banner
1088 hildon_banner_show_information_with_markup (GtkWidget *widget,
1089 const gchar *icon_name,
1090 const gchar *markup)
1092 HildonBanner *banner;
1094 g_return_val_if_fail (icon_name == NULL || icon_name[0] != 0, NULL);
1095 g_return_val_if_fail (markup != NULL, NULL);
1097 /* Prepare banner */
1098 banner = hildon_banner_get_instance_for_widget (widget, TRUE);
1100 hildon_banner_set_markup (banner, markup);
1101 hildon_banner_bind_style (banner, "information");
1103 /* Show the banner, since caller cannot do that */
1104 gtk_widget_show_all (GTK_WIDGET (banner));
1106 return (GtkWidget *) banner;
1110 * hildon_banner_show_animation:
1111 * @widget: the #GtkWidget that wants to display banner
1112 * @animation_name: since Hildon 2.2 this parameter is not used
1113 * anymore and any value that you pass will be
1115 * @text: the text to display.
1117 * Shows an animated progress notification. It's recommended not to try
1118 * to show more than one progress notification at a time, since
1119 * they will appear on top of each other. You can use progress
1120 * notifications with timed banners. In this case the banners are
1121 * located so that you can somehow see both.
1123 * Unlike information banners (created with
1124 * hildon_banner_show_information()), animation banners are not
1125 * destroyed automatically using a timeout. You have to destroy them
1128 * Please note also that these banners are destroyed automatically if the
1129 * window they are attached to is closed. The pointer that you receive
1130 * with this function does not contain additional references, so it
1131 * can become invalid without warning (this is true for all toplevel
1132 * windows in gtk). To make sure that the banner does not disappear
1133 * automatically, you can separately ref the return value (this
1134 * doesn't prevent the banner from disappearing, just the object from
1135 * being finalized). In this case you have to call
1136 * gtk_widget_destroy() followed by g_object_unref().
1138 * Returns: a #HildonBanner widget. You must call gtk_widget_destroy()
1139 * once you are done with the banner.
1141 * Deprecated: Hildon 2.2: use
1142 * hildon_gtk_window_set_progress_indicator() instead.
1145 hildon_banner_show_animation (GtkWidget *widget,
1146 const gchar *animation_name,
1149 HildonBanner *banner;
1150 GtkWidget *image_widget;
1152 g_return_val_if_fail (text != NULL, NULL);
1154 image_widget = hildon_banner_create_animation ();
1156 /* Prepare banner */
1157 banner = hildon_banner_get_instance_for_widget (widget, FALSE);
1158 hildon_banner_ensure_child (banner, image_widget, 0,
1159 GTK_TYPE_IMAGE, "yalign", 0.0, NULL);
1161 hildon_banner_set_text (banner, text);
1162 hildon_banner_bind_style (banner, "animation");
1165 gtk_widget_show_all (GTK_WIDGET (banner));
1167 return (GtkWidget *) banner;
1171 * hildon_banner_show_progress:
1172 * @widget: the #GtkWidget that wants to display banner
1173 * @bar: since Hildon 2.2 this parameter is not used anymore and
1174 * any value that you pass will be ignored
1175 * @text: text to display.
1177 * Shows progress notification. See hildon_banner_show_animation()
1178 * for more information.
1180 * Returns: a #HildonBanner widget. You must call #gtk_widget_destroy
1181 * once you are done with the banner.
1183 * Deprecated: Hildon 2.2: use hildon_gtk_window_set_progress_indicator() instead.
1186 hildon_banner_show_progress (GtkWidget *widget,
1187 GtkProgressBar *bar,
1190 HildonBanner *banner;
1191 HildonBannerPrivate *priv;
1193 g_return_val_if_fail (text != NULL, NULL);
1195 /* Prepare banner */
1196 banner = hildon_banner_get_instance_for_widget (widget, FALSE);
1197 priv = HILDON_BANNER_GET_PRIVATE (banner);
1200 hildon_banner_set_text (banner, text);
1201 hildon_banner_bind_style (banner, "progress");
1204 hildon_gtk_window_set_progress_indicator (priv->parent, 1);
1206 /* Show the banner */
1207 gtk_widget_show_all (GTK_WIDGET (banner));
1209 return GTK_WIDGET (banner);
1213 * hildon_banner_set_text:
1214 * @self: a #HildonBanner widget
1215 * @text: a new text to display in banner
1217 * Sets the text that is displayed in the banner.
1221 hildon_banner_set_text (HildonBanner *self,
1225 HildonBannerPrivate *priv;
1226 const gchar *existing_text;
1228 g_return_if_fail (HILDON_IS_BANNER (self));
1230 priv = HILDON_BANNER_GET_PRIVATE (self);
1233 label = GTK_LABEL (priv->label);
1234 existing_text = gtk_label_get_text (label);
1236 if (existing_text != NULL &&
1238 strcmp (existing_text, text) != 0) {
1239 gtk_label_set_text (label, text);
1240 hildon_banner_reset_wrap_state (self);
1243 hildon_banner_check_position (GTK_WIDGET (self));
1247 * hildon_banner_set_markup:
1248 * @self: a #HildonBanner widget
1249 * @markup: a new text with Pango markup to display in the banner
1251 * Sets the text with markup that is displayed in the banner.
1255 hildon_banner_set_markup (HildonBanner *self,
1256 const gchar *markup)
1259 HildonBannerPrivate *priv;
1261 g_return_if_fail (HILDON_IS_BANNER (self));
1263 priv = HILDON_BANNER_GET_PRIVATE (self);
1266 label = GTK_LABEL (priv->label);
1267 gtk_label_set_markup (label, markup);
1269 hildon_banner_reset_wrap_state (self);
1271 hildon_banner_check_position (GTK_WIDGET(self));
1275 * hildon_banner_set_fraction:
1276 * @self: a #HildonBanner widget
1277 * @fraction: #gdouble
1279 * The fraction is the completion of progressbar,
1280 * the scale is from 0.0 to 1.0.
1281 * Sets the amount of fraction the progressbar has.
1283 * Note that this method only has effect if @self was created with
1284 * hildon_banner_show_progress()
1286 * Deprecated: This function does nothing. As of Hildon 2.2, hildon
1287 * banners don't have progress bars.
1290 hildon_banner_set_fraction (HildonBanner *self,
1296 * hildon_banner_set_timeout:
1297 * @self: a #HildonBanner widget
1298 * @timeout: timeout to set in miliseconds.
1300 * Sets the timeout on the banner. After the given amount of miliseconds
1301 * has elapsed the banner will be destroyed. Setting this only makes
1302 * sense on banners that are timed and that have not been yet displayed
1305 * Note that this method only has effect if @self is an information
1306 * banner (created using hildon_banner_show_information() and
1310 hildon_banner_set_timeout (HildonBanner *self,
1313 HildonBannerPrivate *priv;
1315 g_return_if_fail (HILDON_IS_BANNER (self));
1316 priv = HILDON_BANNER_GET_PRIVATE (self);
1319 priv->timeout = timeout;
1323 * hildon_banner_set_icon:
1324 * @self: a #HildonBanner widget
1325 * @icon_name: the name of icon to use. Can be %NULL for default icon
1327 * Sets the icon to be used in the banner.
1329 * Deprecated: This function does nothing. As of hildon 2.2, hildon
1330 * banners don't allow changing their icons.
1333 hildon_banner_set_icon (HildonBanner *self,
1334 const gchar *icon_name)
1339 * hildon_banner_set_icon_from_file:
1340 * @self: a #HildonBanner widget
1341 * @icon_file: the filename of icon to use. Can be %NULL for default icon
1343 * Sets the icon from its filename to be used in the banner.
1345 * Deprecated: This function does nothing. As of hildon 2.2, hildon
1346 * banners don't allow changing their icons.
1349 hildon_banner_set_icon_from_file (HildonBanner *self,
1350 const gchar *icon_file)