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-defines.h"
88 #include "hildon-gtk.h"
90 /* position relative to the screen */
92 #define HILDON_BANNER_WINDOW_X 0
94 #define HILDON_BANNER_WINDOW_Y HILDON_WINDOW_TITLEBAR_HEIGHT
98 #define HILDON_BANNER_LABEL_MAX_TIMED \
99 (gdk_screen_width() - ((HILDON_MARGIN_TRIPLE) * 2))
101 #define HILDON_BANNER_LABEL_MAX_PROGRESS 375 /*265*/
103 /* default timeout */
105 #define HILDON_BANNER_DEFAULT_TIMEOUT 3000
109 #define HILDON_BANNER_DEFAULT_PROGRESS_ANIMATION "indicator_update"
111 /* animation related stuff */
113 #define HILDON_BANNER_ANIMATION_FRAMERATE ((float)1000/150)
115 #define HILDON_BANNER_ANIMATION_TMPL "indicator_update%d"
117 #define HILDON_BANNER_ANIMATION_NFRAMES 8
127 static GtkWidget* global_timed_banner = NULL;
130 hildon_banner_timed_quark (void);
133 hildon_banner_bind_style (HildonBanner *self,
137 hildon_banner_timeout (gpointer data);
140 hildon_banner_clear_timeout (HildonBanner *self);
143 hildon_banner_ensure_timeout (HildonBanner *self);
146 hildon_banner_set_property (GObject *object,
152 hildon_banner_get_property (GObject *object,
158 hildon_banner_destroy (GtkObject *object);
161 hildon_banner_real_get_instance (GObject *window,
165 hildon_banner_constructor (GType type,
166 guint n_construct_params,
167 GObjectConstructParam *construct_params);
170 hildon_banner_finalize (GObject *object);
173 hildon_banner_button_press_event (GtkWidget* widget,
174 GdkEventButton* event);
177 hildon_banner_map_event (GtkWidget *widget,
180 hildon_banner_reset_wrap_state (HildonBanner *banner);
183 force_to_wrap_truncated (HildonBanner *banner);
186 hildon_banner_check_position (GtkWidget *widget);
189 hildon_banner_realize (GtkWidget *widget);
192 hildon_banner_class_init (HildonBannerClass *klass);
195 hildon_banner_init (HildonBanner *self);
198 hildon_banner_ensure_child (HildonBanner *self,
199 GtkWidget *user_widget,
202 const gchar *first_property,
206 hildon_banner_get_instance_for_widget (GtkWidget *widget,
210 hildon_banner_set_override_flag (HildonBanner *banner);
213 hildon_banner_real_show_information (GtkWidget *widget,
215 gboolean override_dnd);
217 G_DEFINE_TYPE (HildonBanner, hildon_banner, GTK_TYPE_WINDOW)
219 typedef struct _HildonBannerPrivate HildonBannerPrivate;
221 #define HILDON_BANNER_GET_PRIVATE(obj) \
222 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
223 HILDON_TYPE_BANNER, HildonBannerPrivate));
225 struct _HildonBannerPrivate
227 GtkWidget *main_item;
228 GtkWidget *alignment;
235 guint has_been_wrapped : 1;
236 guint has_been_truncated : 1;
237 guint require_override_dnd : 1;
238 guint overrides_dnd : 1;
242 hildon_banner_timed_quark (void)
244 static GQuark quark = 0;
246 if (G_UNLIKELY(quark == 0))
247 quark = g_quark_from_static_string ("hildon-banner-timed");
252 /* Set the widget and label name to make the correct rc-style attached into them */
254 hildon_banner_bind_style (HildonBanner *self,
255 const gchar *name_sufix)
257 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (self);
262 name = g_strconcat ("HildonBannerLabel-", name_sufix, NULL);
263 gtk_widget_set_name (priv->label, name);
266 name = g_strconcat ("HildonBanner-", name_sufix, NULL);
267 gtk_widget_set_name (GTK_WIDGET (self), name);
271 /* In timeout function we automatically destroy timed banners */
273 simulate_close (GtkWidget* widget)
275 gboolean result = FALSE;
277 /* If the banner is currently visible (it normally should),
278 we simulate clicking the close button of the window.
279 This allows applications to reuse the banner by prevent
281 if (GTK_WIDGET_DRAWABLE (widget))
283 GdkEvent *event = gdk_event_new (GDK_DELETE);
284 event->any.window = g_object_ref (widget->window);
285 event->any.send_event = FALSE;
286 result = gtk_widget_event (widget, event);
287 gdk_event_free (event);
294 hildon_banner_timeout (gpointer data)
297 gboolean continue_timeout = FALSE;
299 GDK_THREADS_ENTER ();
301 g_assert (HILDON_IS_BANNER (data));
303 widget = GTK_WIDGET (data);
304 g_object_ref (widget);
306 continue_timeout = simulate_close (widget);
308 if (! continue_timeout) {
309 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (data);
310 priv->timeout_id = 0;
311 gtk_widget_destroy (widget);
314 g_object_unref (widget);
316 GDK_THREADS_LEAVE ();
318 return continue_timeout;
322 hildon_banner_clear_timeout (HildonBanner *self)
324 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (self);
327 if (priv->timeout_id != 0) {
328 g_source_remove (priv->timeout_id);
329 priv->timeout_id = 0;
337 hildon_banner_ensure_timeout (HildonBanner *self)
339 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (self);
342 if (priv->timeout_id == 0 && priv->is_timed && priv->timeout > 0)
343 priv->timeout_id = g_timeout_add (priv->timeout,
344 hildon_banner_timeout, self);
348 hildon_banner_set_property (GObject *object,
354 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (object);
360 priv->timeout = g_value_get_uint (value);
364 priv->is_timed = g_value_get_boolean (value);
367 case PROP_PARENT_WINDOW:
368 window = g_value_get_object (value);
370 g_object_remove_weak_pointer(G_OBJECT (priv->parent), (gpointer) &priv->parent);
373 gtk_window_set_transient_for (GTK_WINDOW (object), (GtkWindow *) window);
374 priv->parent = (GtkWindow *) window;
377 gtk_window_set_destroy_with_parent (GTK_WINDOW (object), TRUE);
378 g_object_add_weak_pointer(G_OBJECT (window), (gpointer) &priv->parent);
384 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
390 hildon_banner_get_property (GObject *object,
395 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (object);
401 g_value_set_uint (value, priv->timeout);
405 g_value_set_boolean (value, priv->is_timed);
408 case PROP_PARENT_WINDOW:
409 g_value_set_object (value, gtk_window_get_transient_for (GTK_WINDOW (object)));
413 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
419 hildon_banner_destroy (GtkObject *object)
421 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (object);
425 GObject *parent_window = (GObject *) priv->parent;
427 g_assert (HILDON_IS_BANNER (object));
428 self = HILDON_BANNER (object);
430 /* Drop possible global pointer. That can hold reference to us */
431 if ((gpointer) object == (gpointer) global_timed_banner) {
432 global_timed_banner = NULL;
433 g_object_unref (object);
436 /* Remove the data from parent window for timed banners. Those hold reference */
437 if (priv->is_timed && parent_window != NULL) {
438 g_object_set_qdata (parent_window, hildon_banner_timed_quark (), NULL);
441 if (!priv->is_timed && priv->parent) {
442 hildon_gtk_window_set_progress_indicator (priv->parent, 0);
445 (void) hildon_banner_clear_timeout (self);
447 if (GTK_OBJECT_CLASS (hildon_banner_parent_class)->destroy)
448 GTK_OBJECT_CLASS (hildon_banner_parent_class)->destroy (object);
451 /* Search a previous banner instance */
453 hildon_banner_real_get_instance (GObject *window,
457 /* If we have a parent window, the previous instance is stored there */
459 return g_object_get_qdata(window, hildon_banner_timed_quark ());
462 /* System notification instance is stored into global pointer */
463 return (GObject *) global_timed_banner;
466 /* Non-timed banners are normal (non-singleton) objects */
470 /* By overriding constructor we force timed banners to be
471 singletons for each window */
473 hildon_banner_constructor (GType type,
474 guint n_construct_params,
475 GObjectConstructParam *construct_params)
477 GObject *banner, *window = NULL;
478 gboolean timed = FALSE;
481 /* Search banner type information from parameters in order
482 to locate the possible previous banner instance. */
483 for (i = 0; i < n_construct_params; i++)
485 if (strcmp(construct_params[i].pspec->name, "parent-window") == 0)
486 window = g_value_get_object (construct_params[i].value);
487 else if (strcmp(construct_params[i].pspec->name, "is-timed") == 0)
488 timed = g_value_get_boolean (construct_params[i].value);
491 /* Try to get a previous instance if such exists */
492 banner = hildon_banner_real_get_instance (window, timed);
495 /* We have to create a new banner */
496 banner = G_OBJECT_CLASS (hildon_banner_parent_class)->constructor (type, n_construct_params, construct_params);
498 /* Store the newly created singleton instance either into parent
499 window data or into global variables. */
502 g_object_set_qdata_full (G_OBJECT (window), hildon_banner_timed_quark (),
503 g_object_ref (banner), g_object_unref);
505 g_assert (global_timed_banner == NULL);
506 global_timed_banner = g_object_ref (banner);
511 /* FIXME: This is a hack! We have to manually freeze
512 notifications. This is normally done by g_object_init, but we
513 are not going to call that. g_object_newv will otherwise give
514 a critical like this:
516 GLIB CRITICAL ** GLib-GObject - g_object_notify_queue_thaw:
517 assertion `nqueue->freeze_count > 0' failed */
519 g_object_freeze_notify (banner);
520 hildon_banner_reset_wrap_state (HILDON_BANNER (banner));
523 /* We restart possible timeouts for each new timed banner request */
524 if (timed && hildon_banner_clear_timeout (HILDON_BANNER (banner)))
525 hildon_banner_ensure_timeout (HILDON_BANNER(banner));
531 hildon_banner_finalize (GObject *object)
533 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (object);
536 g_object_remove_weak_pointer(G_OBJECT (priv->parent), (gpointer) &priv->parent);
539 G_OBJECT_CLASS (hildon_banner_parent_class)->finalize (object);
543 hildon_banner_button_press_event (GtkWidget* widget,
544 GdkEventButton* event)
546 gboolean result = simulate_close (widget);
549 /* signal emission not stopped - basically behave like
550 * gtk_main_do_event() for a delete event, but just hide the
551 * banner instead of destroying it, as it is already meant to
552 * be destroyed by hildon_banner_timeout() (if it's timed) or
553 * the application (if it's not). */
554 gtk_widget_hide (widget);
560 #if defined(MAEMO_GTK)
562 hildon_banner_map (GtkWidget *widget)
564 if (GTK_WIDGET_CLASS (hildon_banner_parent_class)->map) {
565 /* Make the banner temporary _before_ mapping it, to avoid closing
566 * other temporary windows */
567 gtk_window_set_is_temporary (GTK_WINDOW (widget), TRUE);
569 GTK_WIDGET_CLASS (hildon_banner_parent_class)->map (widget);
571 /* Make the banner non-temporary _after_ mapping it, to avoid
572 * being closed by other non-temporary windows */
573 gtk_window_set_is_temporary (GTK_WINDOW (widget), FALSE);
575 hildon_banner_check_position (widget);
580 /* We start the timer for timed notifications after the window appears on screen */
582 hildon_banner_map_event (GtkWidget *widget,
585 gboolean result = FALSE;
587 if (GTK_WIDGET_CLASS (hildon_banner_parent_class)->map_event)
588 result = GTK_WIDGET_CLASS (hildon_banner_parent_class)->map_event (widget, event);
590 hildon_banner_ensure_timeout (HILDON_BANNER(widget));
596 hildon_banner_reset_wrap_state (HildonBanner *banner)
599 HildonBannerPrivate *priv;
601 priv = HILDON_BANNER_GET_PRIVATE (banner);
604 layout = gtk_label_get_layout (GTK_LABEL (priv->label));
606 pango_layout_set_width (layout, -1);
607 priv->has_been_wrapped = FALSE;
608 priv->has_been_truncated = FALSE;
610 gtk_widget_set_size_request (priv->label, -1, -1);
611 gtk_widget_set_size_request (GTK_WIDGET (banner), -1, -1);
614 /* force to wrap truncated label by setting explicit size request
615 * see N#27000 and G#329646 */
617 force_to_wrap_truncated (HildonBanner *banner)
621 int width_text, width_max;
624 PangoRectangle logical;
625 GtkRequisition requisition;
626 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (banner);
628 g_return_if_fail (priv);
630 label = GTK_LABEL (priv->label);
632 layout = gtk_label_get_layout (label);
634 pango_layout_get_extents (layout, NULL, &logical);
635 width_text = PANGO_PIXELS (logical.width);
637 width_max = priv->is_timed ? HILDON_BANNER_LABEL_MAX_TIMED
638 : HILDON_BANNER_LABEL_MAX_PROGRESS;
640 /* If the width of the label is going to exceed the maximum allowed
641 * width, enforce the maximum allowed width now.
643 if (priv->has_been_wrapped
644 || width_text >= width_max
645 || pango_layout_is_wrapped (layout)) {
646 /* Force wrapping by setting the maximum size */
649 priv->has_been_wrapped = TRUE;
652 /* Make the label update its layout; and update our layout pointer
653 * because the layout will be cleared and refreshed.
655 gtk_widget_set_size_request (GTK_WIDGET (label), width, height);
656 gtk_widget_size_request (GTK_WIDGET (label), &requisition);
658 layout = gtk_label_get_layout (label);
660 /* If the layout has now been wrapped and exceeds 3 lines, we truncate
661 * the rest of the label according to spec.
663 if (priv->has_been_truncated
664 || (pango_layout_is_wrapped (layout)
665 && pango_layout_get_line_count (layout) > 3)) {
668 pango_layout_get_extents (layout, NULL, &logical);
669 lines = pango_layout_get_line_count (layout);
671 /* This calculation assumes that the same font is used
672 * throughout the banner -- this is usually the case on maemo
674 * FIXME: Pango >= 1.20 has pango_layout_set_height().
676 height = (PANGO_PIXELS (logical.height) * 3) / lines + 1;
677 priv->has_been_truncated = TRUE;
680 /* Set the new width/height if applicable */
681 gtk_widget_set_size_request (GTK_WIDGET (label), width, height);
686 hildon_banner_check_position (GtkWidget *widget)
691 gtk_widget_set_size_request (widget, gdk_screen_width (), -1);
693 force_to_wrap_truncated (HILDON_BANNER(widget)); /* see N#27000 and G#329646 */
695 gtk_widget_size_request (widget, &req);
702 x = HILDON_BANNER_WINDOW_X;
704 y = HILDON_BANNER_WINDOW_Y;
706 gtk_window_move (GTK_WINDOW (widget), x, y);
710 screen_size_changed (GdkScreen *screen,
714 gtk_window_reshow_with_initial_size (banner);
718 hildon_banner_realize (GtkWidget *widget)
723 guint32 portrait = 1;
724 const gchar *notification_type = "_HILDON_NOTIFICATION_TYPE_BANNER";
725 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (widget);
728 /* We let the parent to init widget->window before we need it */
729 if (GTK_WIDGET_CLASS (hildon_banner_parent_class)->realize)
730 GTK_WIDGET_CLASS (hildon_banner_parent_class)->realize (widget);
732 /* We use special hint to turn the banner into information notification. */
733 gdk_window_set_type_hint (widget->window, GDK_WINDOW_TYPE_HINT_NOTIFICATION);
734 gtk_window_set_transient_for (GTK_WINDOW (widget), (GtkWindow *) priv->parent);
736 hildon_banner_check_position (widget);
738 gdkwin = widget->window;
740 /* Set the _HILDON_NOTIFICATION_TYPE property so Matchbox places the window correctly */
741 atom = gdk_atom_intern ("_HILDON_NOTIFICATION_TYPE", FALSE);
742 gdk_property_change (gdkwin, atom, gdk_x11_xatom_to_atom (XA_STRING), 8, GDK_PROP_MODE_REPLACE,
743 (gpointer) notification_type, strlen (notification_type));
745 /* HildonBanner supports portrait mode */
746 atom = gdk_atom_intern ("_HILDON_PORTRAIT_MODE_SUPPORT", FALSE);
747 gdk_property_change (gdkwin, atom, gdk_x11_xatom_to_atom (XA_CARDINAL), 32,
748 GDK_PROP_MODE_REPLACE, (gpointer) &portrait, 1);
750 /* Manage override flag */
751 if ((priv->require_override_dnd)&&(!priv->overrides_dnd)) {
752 hildon_banner_set_override_flag (HILDON_BANNER (widget));
753 priv->overrides_dnd = TRUE;
756 screen = gtk_widget_get_screen (widget);
757 g_signal_connect (screen, "size-changed", G_CALLBACK (screen_size_changed), widget);
761 hildon_banner_unrealize (GtkWidget *widget)
763 GdkScreen *screen = gtk_widget_get_screen (widget);
764 g_signal_handlers_disconnect_by_func (screen, G_CALLBACK (screen_size_changed), widget);
766 GTK_WIDGET_CLASS (hildon_banner_parent_class)->unrealize (widget);
770 hildon_banner_class_init (HildonBannerClass *klass)
772 GObjectClass *object_class;
773 GtkWidgetClass *widget_class;
775 object_class = G_OBJECT_CLASS (klass);
776 widget_class = GTK_WIDGET_CLASS (klass);
778 /* Append private structure to class. This is more elegant than
779 on g_new based approach */
780 g_type_class_add_private (klass, sizeof (HildonBannerPrivate));
782 /* Override virtual methods */
783 object_class->constructor = hildon_banner_constructor;
784 object_class->finalize = hildon_banner_finalize;
785 object_class->set_property = hildon_banner_set_property;
786 object_class->get_property = hildon_banner_get_property;
787 GTK_OBJECT_CLASS (klass)->destroy = hildon_banner_destroy;
788 widget_class->map_event = hildon_banner_map_event;
789 widget_class->realize = hildon_banner_realize;
790 widget_class->unrealize = hildon_banner_unrealize;
791 widget_class->button_press_event = hildon_banner_button_press_event;
792 #if defined(MAEMO_GTK)
793 widget_class->map = hildon_banner_map;
796 /* Install properties.
797 We need construct properties for singleton purposes */
800 * HildonBanner:parent-window:
802 * The window for which the banner will be singleton.
805 g_object_class_install_property (object_class, PROP_PARENT_WINDOW,
806 g_param_spec_object ("parent-window",
808 "The window for which the banner will be singleton",
809 GTK_TYPE_WINDOW, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
812 * HildonBanner:is-timed:
814 * Whether the banner is timed and goes away automatically.
817 g_object_class_install_property (object_class, PROP_IS_TIMED,
818 g_param_spec_boolean ("is-timed",
820 "Whether or not the notification goes away automatically "
821 "after the specified time has passed",
822 FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
825 * HildonBanner:timeout:
827 * The time before destroying the banner. This needs
828 * to be adjusted before the banner is mapped to the screen.
831 g_object_class_install_property (object_class, PROP_TIMEOUT,
832 g_param_spec_uint ("timeout",
834 "The time before making the banner banner go away",
837 HILDON_BANNER_DEFAULT_TIMEOUT,
838 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
842 hildon_banner_init (HildonBanner *self)
844 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (self);
848 priv->overrides_dnd = FALSE;
849 priv->require_override_dnd = FALSE;
851 /* Initialize the common layout inside banner */
852 priv->alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
853 priv->layout = gtk_hbox_new (FALSE, HILDON_MARGIN_DEFAULT);
855 priv->label = g_object_new (GTK_TYPE_LABEL, NULL);
856 gtk_label_set_line_wrap (GTK_LABEL (priv->label), TRUE);
857 gtk_label_set_line_wrap_mode (GTK_LABEL (priv->label), PANGO_WRAP_WORD_CHAR);
859 gtk_container_set_border_width (GTK_CONTAINER (priv->layout), HILDON_MARGIN_DEFAULT);
860 gtk_container_add (GTK_CONTAINER (self), priv->alignment);
861 gtk_container_add (GTK_CONTAINER (priv->alignment), priv->layout);
862 gtk_box_pack_start (GTK_BOX (priv->layout), priv->label, FALSE, FALSE, 0);
864 gtk_window_set_accept_focus (GTK_WINDOW (self), FALSE);
866 hildon_banner_reset_wrap_state (self);
868 gtk_widget_add_events (GTK_WIDGET (self), GDK_BUTTON_PRESS_MASK);
871 /* Makes sure that icon/progress item contains the desired type
872 of item. If possible, tries to avoid creating a new widget but
873 reuses the existing one */
875 hildon_banner_ensure_child (HildonBanner *self,
876 GtkWidget *user_widget,
879 const gchar *first_property,
884 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (self);
888 widget = priv->main_item;
889 va_start (args, first_property);
891 /* Reuse existing widget if possible */
892 if (! user_widget && G_TYPE_CHECK_INSTANCE_TYPE (widget, type))
894 g_object_set_valist (G_OBJECT (widget), first_property, args);
898 /* We have to abandon old content widget */
900 gtk_container_remove (GTK_CONTAINER (priv->layout), widget);
902 /* Use user provided widget or create a new one */
903 priv->main_item = widget = user_widget ?
904 user_widget : GTK_WIDGET (g_object_new_valist(type, first_property, args));
905 gtk_box_pack_start (GTK_BOX (priv->layout), widget, FALSE, FALSE, 0);
908 /* We make sure that the widget exists in desired position. Different
909 banners place this child widget to different places */
910 gtk_box_reorder_child (GTK_BOX (priv->layout), widget, pos);
914 /* Creates a new banner instance or uses an existing one */
916 hildon_banner_get_instance_for_widget (GtkWidget *widget,
921 window = widget ? gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW) : NULL;
922 return g_object_new (HILDON_TYPE_BANNER, "parent-window", window, "is-timed", timed, NULL);
926 hildon_banner_create_animation (void)
929 GdkPixbufSimpleAnim *anim;
932 GError *error = NULL;
936 anim = gdk_pixbuf_simple_anim_new (HILDON_ICON_PIXEL_SIZE_STYLUS,
937 HILDON_ICON_PIXEL_SIZE_STYLUS,
938 HILDON_BANNER_ANIMATION_FRAMERATE);
939 gdk_pixbuf_simple_anim_set_loop (anim, TRUE);
940 theme = gtk_icon_theme_get_default ();
942 for (i = 1; i <= HILDON_BANNER_ANIMATION_NFRAMES; i++) {
943 icon_name = g_strdup_printf (HILDON_BANNER_ANIMATION_TMPL, i);
944 frame = gtk_icon_theme_load_icon (theme, icon_name, HILDON_ICON_PIXEL_SIZE_STYLUS,
948 g_warning ("Icon theme lookup for icon `%s' failed: %s",
949 icon_name, error->message);
950 g_error_free (error);
953 gdk_pixbuf_simple_anim_add_frame (anim, frame);
956 g_object_unref (frame);
960 image = gtk_image_new_from_animation (GDK_PIXBUF_ANIMATION (anim));
961 g_object_unref (anim);
967 * hildon_banner_show_information:
968 * @widget: the #GtkWidget that is the owner of the banner
969 * @icon_name: since Hildon 2.2 this parameter is not used anymore and
970 * any value that you pass will be ignored
971 * @text: Text to display
973 * This function creates and displays an information banner that is
974 * automatically destroyed after a certain time period (see
975 * hildon_banner_set_timeout()). For each window in your application
976 * there can only be one timed banner, so if you spawn a new banner
977 * before the earlier one has timed out, the previous one will be
980 * Returns: The newly created banner
984 hildon_banner_show_information (GtkWidget *widget,
985 const gchar *icon_name,
988 return hildon_banner_real_show_information (widget, text, FALSE);
992 * hildon_banner_show_information_override_dnd:
993 * @widget: the #GtkWidget that is the owner of the banner
994 * @text: Text to display
996 * Equivalent to hildon_banner_show_information(), but overriding the
997 * "do not disturb" flag.
999 * Returns: The newly created banner
1005 hildon_banner_show_information_override_dnd (GtkWidget *widget,
1008 return hildon_banner_real_show_information (widget, text, TRUE);
1012 hildon_banner_set_override_flag (HildonBanner *banner)
1016 gdk_property_change (GTK_WIDGET (banner)->window,
1017 gdk_atom_intern_static_string ("_HILDON_DO_NOT_DISTURB_OVERRIDE"),
1018 gdk_x11_xatom_to_atom (XA_INTEGER),
1020 GDK_PROP_MODE_REPLACE,
1021 (const guchar*) &state,
1027 hildon_banner_real_show_information (GtkWidget *widget,
1029 gboolean override_dnd)
1031 HildonBanner *banner;
1032 HildonBannerPrivate *priv = NULL;
1034 g_return_val_if_fail (text != NULL, NULL);
1036 /* Prepare banner */
1037 banner = hildon_banner_get_instance_for_widget (widget, TRUE);
1038 priv = HILDON_BANNER_GET_PRIVATE (banner);
1040 hildon_banner_set_text (banner, text);
1041 hildon_banner_bind_style (banner, "information");
1044 /* so on the realize it will set the property */
1045 priv->require_override_dnd = TRUE;
1048 /* Show the banner, since caller cannot do that */
1049 gtk_widget_show_all (GTK_WIDGET (banner));
1051 return GTK_WIDGET (banner);
1055 * hildon_banner_show_informationf:
1056 * @widget: the #GtkWidget that is the owner of the banner
1057 * @icon_name: since Hildon 2.2 this parameter is not used anymore and
1058 * any value that you pass will be ignored
1059 * @format: a printf-like format string
1060 * @Varargs: arguments for the format string
1062 * A helper function for hildon_banner_show_information() with
1063 * string formatting.
1065 * Returns: the newly created banner
1068 hildon_banner_show_informationf (GtkWidget *widget,
1069 const gchar *icon_name,
1070 const gchar *format,
1073 g_return_val_if_fail (format != NULL, NULL);
1079 va_start (args, format);
1080 message = g_strdup_vprintf (format, args);
1083 banner = hildon_banner_show_information (widget, icon_name, message);
1091 * hildon_banner_show_information_with_markup:
1092 * @widget: the #GtkWidget that wants to display banner
1093 * @icon_name: since Hildon 2.2 this parameter is not used anymore and
1094 * any value that you pass will be ignored
1095 * @markup: a markup string to display (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
1097 * This function creates and displays an information banner that is
1098 * automatically destroyed after certain time period (see
1099 * hildon_banner_set_timeout()). For each window in your application
1100 * there can only be one timed banner, so if you spawn a new banner
1101 * before the earlier one has timed out, the previous one will be
1104 * Returns: the newly created banner
1108 hildon_banner_show_information_with_markup (GtkWidget *widget,
1109 const gchar *icon_name,
1110 const gchar *markup)
1112 HildonBanner *banner;
1114 g_return_val_if_fail (icon_name == NULL || icon_name[0] != 0, NULL);
1115 g_return_val_if_fail (markup != NULL, NULL);
1117 /* Prepare banner */
1118 banner = hildon_banner_get_instance_for_widget (widget, TRUE);
1120 hildon_banner_set_markup (banner, markup);
1121 hildon_banner_bind_style (banner, "information");
1123 /* Show the banner, since caller cannot do that */
1124 gtk_widget_show_all (GTK_WIDGET (banner));
1126 return (GtkWidget *) banner;
1130 * hildon_banner_show_animation:
1131 * @widget: the #GtkWidget that wants to display banner
1132 * @animation_name: since Hildon 2.2 this parameter is not used
1133 * anymore and any value that you pass will be
1135 * @text: the text to display.
1137 * Shows an animated progress notification. It's recommended not to try
1138 * to show more than one progress notification at a time, since
1139 * they will appear on top of each other. You can use progress
1140 * notifications with timed banners. In this case the banners are
1141 * located so that you can somehow see both.
1143 * Unlike information banners (created with
1144 * hildon_banner_show_information()), animation banners are not
1145 * destroyed automatically using a timeout. You have to destroy them
1148 * Please note also that these banners are destroyed automatically if the
1149 * window they are attached to is closed. The pointer that you receive
1150 * with this function does not contain additional references, so it
1151 * can become invalid without warning (this is true for all toplevel
1152 * windows in gtk). To make sure that the banner does not disappear
1153 * automatically, you can separately ref the return value (this
1154 * doesn't prevent the banner from disappearing, just the object from
1155 * being finalized). In this case you have to call
1156 * gtk_widget_destroy() followed by g_object_unref().
1158 * Returns: a #HildonBanner widget. You must call gtk_widget_destroy()
1159 * once you are done with the banner.
1161 * Deprecated: Hildon 2.2: use
1162 * hildon_gtk_window_set_progress_indicator() instead.
1165 hildon_banner_show_animation (GtkWidget *widget,
1166 const gchar *animation_name,
1169 HildonBanner *banner;
1170 GtkWidget *image_widget;
1172 g_return_val_if_fail (text != NULL, NULL);
1174 image_widget = hildon_banner_create_animation ();
1176 /* Prepare banner */
1177 banner = hildon_banner_get_instance_for_widget (widget, FALSE);
1178 hildon_banner_ensure_child (banner, image_widget, 0,
1179 GTK_TYPE_IMAGE, "yalign", 0.0, NULL);
1181 hildon_banner_set_text (banner, text);
1182 hildon_banner_bind_style (banner, "animation");
1185 gtk_widget_show_all (GTK_WIDGET (banner));
1187 return (GtkWidget *) banner;
1191 * hildon_banner_show_progress:
1192 * @widget: the #GtkWidget that wants to display banner
1193 * @bar: since Hildon 2.2 this parameter is not used anymore and
1194 * any value that you pass will be ignored
1195 * @text: text to display.
1197 * Shows progress notification. See hildon_banner_show_animation()
1198 * for more information.
1200 * Returns: a #HildonBanner widget. You must call #gtk_widget_destroy
1201 * once you are done with the banner.
1203 * Deprecated: Hildon 2.2: use hildon_gtk_window_set_progress_indicator() instead.
1206 hildon_banner_show_progress (GtkWidget *widget,
1207 GtkProgressBar *bar,
1210 HildonBanner *banner;
1211 HildonBannerPrivate *priv;
1213 g_return_val_if_fail (text != NULL, NULL);
1215 /* Prepare banner */
1216 banner = hildon_banner_get_instance_for_widget (widget, FALSE);
1217 priv = HILDON_BANNER_GET_PRIVATE (banner);
1220 hildon_banner_set_text (banner, text);
1221 hildon_banner_bind_style (banner, "progress");
1224 hildon_gtk_window_set_progress_indicator (priv->parent, 1);
1226 /* Show the banner */
1227 gtk_widget_show_all (GTK_WIDGET (banner));
1229 return GTK_WIDGET (banner);
1233 * hildon_banner_set_text:
1234 * @self: a #HildonBanner widget
1235 * @text: a new text to display in banner
1237 * Sets the text that is displayed in the banner.
1241 hildon_banner_set_text (HildonBanner *self,
1245 HildonBannerPrivate *priv;
1246 const gchar *existing_text;
1248 g_return_if_fail (HILDON_IS_BANNER (self));
1250 priv = HILDON_BANNER_GET_PRIVATE (self);
1253 label = GTK_LABEL (priv->label);
1254 existing_text = gtk_label_get_text (label);
1256 if (existing_text != NULL &&
1258 strcmp (existing_text, text) != 0) {
1259 gtk_label_set_text (label, text);
1260 hildon_banner_reset_wrap_state (self);
1263 hildon_banner_check_position (GTK_WIDGET (self));
1267 * hildon_banner_set_markup:
1268 * @self: a #HildonBanner widget
1269 * @markup: a new text with Pango markup to display in the banner
1271 * Sets the text with markup that is displayed in the banner.
1275 hildon_banner_set_markup (HildonBanner *self,
1276 const gchar *markup)
1279 HildonBannerPrivate *priv;
1281 g_return_if_fail (HILDON_IS_BANNER (self));
1283 priv = HILDON_BANNER_GET_PRIVATE (self);
1286 label = GTK_LABEL (priv->label);
1287 gtk_label_set_markup (label, markup);
1289 hildon_banner_reset_wrap_state (self);
1291 hildon_banner_check_position (GTK_WIDGET(self));
1295 * hildon_banner_set_fraction:
1296 * @self: a #HildonBanner widget
1297 * @fraction: #gdouble
1299 * The fraction is the completion of progressbar,
1300 * the scale is from 0.0 to 1.0.
1301 * Sets the amount of fraction the progressbar has.
1303 * Note that this method only has effect if @self was created with
1304 * hildon_banner_show_progress()
1306 * Deprecated: This function does nothing. As of Hildon 2.2, hildon
1307 * banners don't have progress bars.
1310 hildon_banner_set_fraction (HildonBanner *self,
1316 * hildon_banner_set_timeout:
1317 * @self: a #HildonBanner widget
1318 * @timeout: timeout to set in miliseconds.
1320 * Sets the timeout on the banner. After the given amount of miliseconds
1321 * has elapsed the banner will be destroyed. Setting this only makes
1322 * sense on banners that are timed and that have not been yet displayed
1325 * Note that this method only has effect if @self is an information
1326 * banner (created using hildon_banner_show_information() and
1330 hildon_banner_set_timeout (HildonBanner *self,
1333 HildonBannerPrivate *priv;
1335 g_return_if_fail (HILDON_IS_BANNER (self));
1336 priv = HILDON_BANNER_GET_PRIVATE (self);
1339 priv->timeout = timeout;
1343 * hildon_banner_set_icon:
1344 * @self: a #HildonBanner widget
1345 * @icon_name: the name of icon to use. Can be %NULL for default icon
1347 * Sets the icon to be used in the banner.
1349 * Deprecated: This function does nothing. As of hildon 2.2, hildon
1350 * banners don't allow changing their icons.
1353 hildon_banner_set_icon (HildonBanner *self,
1354 const gchar *icon_name)
1359 * hildon_banner_set_icon_from_file:
1360 * @self: a #HildonBanner widget
1361 * @icon_file: the filename of icon to use. Can be %NULL for default icon
1363 * Sets the icon from its filename to be used in the banner.
1365 * Deprecated: This function does nothing. As of hildon 2.2, hildon
1366 * banners don't allow changing their icons.
1369 hildon_banner_set_icon_from_file (HildonBanner *self,
1370 const gchar *icon_file)