2 * This file is a part of hildon
4 * Copyright (C) 2005, 2006, 2007 Nokia Corporation, all rights reserved.
6 * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@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 can be used to display a short, timed notification
30 * or information to the user. It can communicate that a
31 * task has been finished or the application state has changed.
32 * Banners should be used only to display non-critical pieces of
41 #include "hildon-banner.h"
42 #include <gtk/gtkhbox.h>
43 #include <gtk/gtkimage.h>
44 #include <gtk/gtkicontheme.h>
47 #include <X11/Xatom.h>
48 #include "hildon-defines.h"
49 #include "hildon-banner-private.h"
51 /* position relative to the screen */
53 #define HILDON_BANNER_WINDOW_X 0
55 #define HILDON_BANNER_WINDOW_Y 73
57 #define HILDON_BANNER_WINDOW_FULLSCREEN_Y 20
61 #define HILDON_BANNER_PROGRESS_WIDTH 104
63 #define HILDON_BANNER_LABEL_MAX_TIMED 375
65 #define HILDON_BANNER_LABEL_MAX_PROGRESS 375 /*265*/
69 #define HILDON_BANNER_DEFAULT_TIMEOUT 3000
73 #define HILDON_BANNER_DEFAULT_ICON "qgn_note_infoprint"
75 #define HILDON_BANNER_DEFAULT_PROGRESS_ANIMATION "qgn_indi_pball_a"
85 static GtkWidget* global_timed_banner = NULL;
88 get_current_app_window (void);
91 check_fullscreen_state (Window window);
94 hildon_banner_timed_quark (void);
97 hildon_banner_bind_label_style (HildonBanner *self,
101 hildon_banner_timeout (gpointer data);
104 hildon_banner_clear_timeout (HildonBanner *self);
107 hildon_banner_ensure_timeout (HildonBanner *self);
110 hildon_banner_set_property (GObject *object,
116 hildon_banner_get_property (GObject *object,
122 hildon_banner_destroy (GtkObject *object);
125 hildon_banner_real_get_instance (GObject *window,
129 hildon_banner_constructor (GType type,
130 guint n_construct_params,
131 GObjectConstructParam *construct_params);
134 hildon_banner_finalize (GObject *object);
137 hildon_banner_button_press_event (GtkWidget* widget,
138 GdkEventButton* event);
141 hildon_banner_map_event (GtkWidget *widget,
144 hildon_banner_reset_wrap_state (HildonBanner *banner);
147 force_to_wrap_truncated (HildonBanner *banner);
150 hildon_banner_check_position (GtkWidget *widget);
153 hildon_banner_realize (GtkWidget *widget);
156 hildon_banner_class_init (HildonBannerClass *klass);
159 hildon_banner_init (HildonBanner *self);
162 hildon_banner_ensure_child (HildonBanner *self,
163 GtkWidget *user_widget,
166 const gchar *first_property,
170 hildon_banner_get_instance_for_widget (GtkWidget *widget,
173 G_DEFINE_TYPE (HildonBanner, hildon_banner, GTK_TYPE_WINDOW)
175 /* copy/paste from old infoprint implementation: Use matchbox
176 properties to find the topmost application window */
178 get_current_app_window (void)
185 Atom atom_current_app_window = gdk_x11_get_xatom_by_name ("_MB_CURRENT_APP_WINDOW");
187 Window win_result = None;
188 guchar *data_return = NULL;
190 status = XGetWindowProperty (GDK_DISPLAY(), GDK_ROOT_WINDOW (),
191 atom_current_app_window, 0L, 16L,
192 0, XA_WINDOW, &realType, &format,
196 if (status == Success && realType == XA_WINDOW && format == 32 && n == 1 && data_return != NULL)
198 win_result = ((Window*) data_return)[0];
207 /* Checks if a window is in fullscreen state or not. This
208 information is needed when banners are positioned on screen.
209 copy/paste from old infoprint implementation. */
211 check_fullscreen_state (Window window)
215 int format, status, i;
216 guchar *data_return = NULL;
219 Atom atom_window_state = gdk_x11_get_xatom_by_name ("_NET_WM_STATE");
220 Atom atom_fullscreen = gdk_x11_get_xatom_by_name ("_NET_WM_STATE_FULLSCREEN");
225 /* in some cases XGetWindowProperty seems to generate BadWindow,
226 so at the moment this function does not always work perfectly */
227 gdk_error_trap_push ();
228 status = XGetWindowProperty (GDK_DISPLAY (), window,
229 atom_window_state, 0L, 1000000L,
230 0, XA_ATOM, &realType, &format,
231 &n, &extra, &data_return);
235 if (gdk_error_trap_pop ())
238 if (status == Success && realType == XA_ATOM && format == 32 && n > 0)
240 for (i=0; i < n; i++)
241 if (((Atom*)data_return)[i] && ((Atom*)data_return)[i] == atom_fullscreen)
243 if (data_return) XFree (data_return);
255 hildon_banner_timed_quark (void)
257 static GQuark quark = 0;
259 if (G_UNLIKELY(quark == 0))
260 quark = g_quark_from_static_string ("hildon-banner-timed");
265 /* Set the label name to make the correct rc-style attached into it */
267 hildon_banner_bind_label_style (HildonBanner *self,
270 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (self);
273 GtkWidget *label = priv->label;
275 /* Too bad that we cannot really reset the widget name */
276 gtk_widget_set_name (label, name ? name : g_type_name (GTK_WIDGET_TYPE (label)));
279 /* In timeout function we automatically destroy timed banners */
281 simulate_close (GtkWidget* widget)
283 gboolean result = FALSE;
285 /* If the banner is currently visible (it normally should),
286 we simulate clicking the close button of the window.
287 This allows applications to reuse the banner by prevent
289 if (GTK_WIDGET_DRAWABLE (widget))
291 GdkEvent *event = gdk_event_new (GDK_DELETE);
292 event->any.window = g_object_ref (widget->window);
293 event->any.send_event = FALSE;
294 result = gtk_widget_event (widget, event);
295 gdk_event_free (event);
302 hildon_banner_timeout (gpointer data)
305 gboolean continue_timeout = FALSE;
307 GDK_THREADS_ENTER ();
309 g_assert (HILDON_IS_BANNER (data));
311 widget = GTK_WIDGET (data);
312 g_object_ref (widget);
314 continue_timeout = simulate_close (widget);
316 if (! continue_timeout) {
317 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (data);
318 priv->timeout_id = 0;
319 gtk_widget_destroy (widget);
322 g_object_unref (widget);
324 GDK_THREADS_LEAVE ();
326 return continue_timeout;
330 hildon_banner_clear_timeout (HildonBanner *self)
332 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (self);
335 if (priv->timeout_id != 0) {
336 g_source_remove (priv->timeout_id);
337 priv->timeout_id = 0;
345 hildon_banner_ensure_timeout (HildonBanner *self)
347 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (self);
350 if (priv->timeout_id == 0 && priv->is_timed && priv->timeout > 0)
351 priv->timeout_id = g_timeout_add (priv->timeout,
352 hildon_banner_timeout, self);
356 hildon_banner_set_property (GObject *object,
362 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (object);
368 priv->timeout = g_value_get_uint (value);
372 priv->is_timed = g_value_get_boolean (value);
375 case PROP_PARENT_WINDOW:
376 window = g_value_get_object (value);
378 g_object_remove_weak_pointer(G_OBJECT (priv->parent), (gpointer) &priv->parent);
381 gtk_window_set_transient_for (GTK_WINDOW (object), (GtkWindow *) window);
382 priv->parent = (GtkWindow *) window;
385 gtk_window_set_destroy_with_parent (GTK_WINDOW (object), TRUE);
386 g_object_add_weak_pointer(G_OBJECT (window), (gpointer) &priv->parent);
392 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
398 hildon_banner_get_property (GObject *object,
403 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (object);
409 g_value_set_uint (value, priv->timeout);
413 g_value_set_boolean (value, priv->is_timed);
416 case PROP_PARENT_WINDOW:
417 g_value_set_object (value, gtk_window_get_transient_for (GTK_WINDOW (object)));
421 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
427 hildon_banner_destroy (GtkObject *object)
429 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (object);
433 GObject *parent_window = (GObject *) priv->parent;
435 g_assert (HILDON_IS_BANNER (object));
436 self = HILDON_BANNER (object);
438 /* Drop possible global pointer. That can hold reference to us */
439 if ((gpointer) object == (gpointer) global_timed_banner) {
440 global_timed_banner = NULL;
441 g_object_unref (object);
444 /* Remove the data from parent window for timed banners. Those hold reference */
445 if (priv->is_timed && parent_window != NULL) {
446 g_object_set_qdata (parent_window, hildon_banner_timed_quark (), NULL);
449 (void) hildon_banner_clear_timeout (self);
451 if (GTK_OBJECT_CLASS (hildon_banner_parent_class)->destroy)
452 GTK_OBJECT_CLASS (hildon_banner_parent_class)->destroy (object);
455 /* Search a previous banner instance */
457 hildon_banner_real_get_instance (GObject *window,
461 /* If we have a parent window, the previous instance is stored there */
463 return g_object_get_qdata(window, hildon_banner_timed_quark ());
466 /* System notification instance is stored into global pointer */
467 return (GObject *) global_timed_banner;
470 /* Non-timed banners are normal (non-singleton) objects */
474 /* By overriding constructor we force timed banners to be
475 singletons for each window */
477 hildon_banner_constructor (GType type,
478 guint n_construct_params,
479 GObjectConstructParam *construct_params)
481 GObject *banner, *window = NULL;
482 gboolean timed = FALSE;
485 /* Search banner type information from parameters in order
486 to locate the possible previous banner instance. */
487 for (i = 0; i < n_construct_params; i++)
489 if (strcmp(construct_params[i].pspec->name, "parent-window") == 0)
490 window = g_value_get_object (construct_params[i].value);
491 else if (strcmp(construct_params[i].pspec->name, "is-timed") == 0)
492 timed = g_value_get_boolean (construct_params[i].value);
495 /* Try to get a previous instance if such exists */
496 banner = hildon_banner_real_get_instance (window, timed);
499 /* We have to create a new banner */
500 banner = G_OBJECT_CLASS (hildon_banner_parent_class)->constructor (type, n_construct_params, construct_params);
502 /* Store the newly created singleton instance either into parent
503 window data or into global variables. */
506 g_object_set_qdata_full (G_OBJECT (window), hildon_banner_timed_quark (),
507 g_object_ref (banner), g_object_unref);
509 g_assert (global_timed_banner == NULL);
510 global_timed_banner = g_object_ref (banner);
515 /* FIXME: This is a hack! We have to manually freeze
516 notifications. This is normally done by g_object_init, but we
517 are not going to call that. g_object_newv will otherwise give
518 a critical like this:
520 GLIB CRITICAL ** GLib-GObject - g_object_notify_queue_thaw:
521 assertion `nqueue->freeze_count > 0' failed */
523 g_object_freeze_notify (banner);
524 hildon_banner_reset_wrap_state (HILDON_BANNER (banner));
527 /* We restart possible timeouts for each new timed banner request */
528 if (timed && hildon_banner_clear_timeout (HILDON_BANNER (banner)))
529 hildon_banner_ensure_timeout (HILDON_BANNER(banner));
535 hildon_banner_finalize (GObject *object)
537 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (object);
540 g_object_remove_weak_pointer(G_OBJECT (priv->parent), (gpointer) &priv->parent);
543 G_OBJECT_CLASS (hildon_banner_parent_class)->finalize (object);
547 hildon_banner_button_press_event (GtkWidget* widget,
548 GdkEventButton* event)
550 gboolean result = simulate_close (widget);
553 /* signal emission not stopped - basically behave like
554 * gtk_main_do_event() for a delete event */
555 gtk_widget_destroy (widget);
561 /* We start the timer for timed notifications after the window appears on screen */
563 hildon_banner_map_event (GtkWidget *widget,
566 gboolean result = FALSE;
568 if (GTK_WIDGET_CLASS (hildon_banner_parent_class)->map_event)
569 result = GTK_WIDGET_CLASS (hildon_banner_parent_class)->map_event (widget, event);
571 hildon_banner_ensure_timeout (HILDON_BANNER(widget));
576 #if defined(MAEMO_GTK)
578 static GdkAtom atom_temporaries = GDK_NONE;
580 /* Do nothing for _GTK_DELETE_TEMPORARIES */
582 hildon_banner_client_event (GtkWidget *widget,
583 GdkEventClient *event)
585 gboolean handled = FALSE;
587 if (atom_temporaries == GDK_NONE)
588 atom_temporaries = gdk_atom_intern_static_string ("_GTK_DELETE_TEMPORARIES");
590 if (event->message_type == atom_temporaries)
600 hildon_banner_reset_wrap_state (HildonBanner *banner)
603 HildonBannerPrivate *priv;
605 priv = HILDON_BANNER_GET_PRIVATE (banner);
608 layout = gtk_label_get_layout (GTK_LABEL (priv->label));
610 pango_layout_set_width (layout, -1);
611 priv->has_been_wrapped = FALSE;
612 priv->has_been_truncated = FALSE;
614 gtk_widget_set_size_request (priv->label, -1, -1);
615 gtk_widget_set_size_request (GTK_WIDGET (banner), -1, -1);
618 /* force to wrap truncated label by setting explicit size request
619 * see N#27000 and G#329646 */
621 force_to_wrap_truncated (HildonBanner *banner)
625 int width_text, width_max;
628 PangoRectangle logical;
629 GtkRequisition requisition;
630 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (banner);
632 g_return_if_fail (priv);
634 label = GTK_LABEL (priv->label);
636 layout = gtk_label_get_layout (label);
638 pango_layout_get_extents (layout, NULL, &logical);
639 width_text = PANGO_PIXELS (logical.width);
641 width_max = priv->is_timed ? HILDON_BANNER_LABEL_MAX_TIMED
642 : HILDON_BANNER_LABEL_MAX_PROGRESS;
644 /* If the width of the label is going to exceed the maximum allowed
645 * width, enforce the maximum allowed width now.
647 if (priv->has_been_wrapped
648 || width_text >= width_max) {
649 /* Force wrapping by setting the maximum size */
652 priv->has_been_wrapped = TRUE;
655 /* Make the label update its layout; and update our layout pointer
656 * because the layout will be cleared and refreshed.
658 gtk_widget_set_size_request (GTK_WIDGET (label), width, height);
659 gtk_widget_size_request (GTK_WIDGET (label), &requisition);
661 layout = gtk_label_get_layout (label);
663 /* If the layout has now been wrapped and exceeds 3 lines, we truncate
664 * the rest of the label according to spec.
666 if (priv->has_been_truncated
667 || (pango_layout_is_wrapped (layout)
668 && pango_layout_get_line_count (layout) > 3)) {
671 pango_layout_get_extents (layout, NULL, &logical);
672 lines = pango_layout_get_line_count (layout);
674 /* This calculation assumes that the same font is used
675 * throughout the banner -- this is usually the case on maemo
677 * FIXME: Pango >= 1.20 has pango_layout_set_height().
679 height = (PANGO_PIXELS (logical.height) * 3) / lines + 1;
680 priv->has_been_truncated = TRUE;
683 /* Set the new width/height if applicable */
684 gtk_widget_set_size_request (GTK_WIDGET (label), width, height);
689 hildon_banner_check_position (GtkWidget *widget)
694 gtk_widget_set_size_request (widget, gdk_screen_width (), -1);
696 force_to_wrap_truncated (HILDON_BANNER(widget)); /* see N#27000 and G#329646 */
698 gtk_widget_size_request (widget, &req);
705 x = HILDON_BANNER_WINDOW_X;
707 y = check_fullscreen_state (get_current_app_window ()) ?
708 HILDON_BANNER_WINDOW_FULLSCREEN_Y : HILDON_BANNER_WINDOW_Y;
710 gtk_window_move (GTK_WINDOW (widget), x, y);
714 hildon_banner_realize (GtkWidget *widget)
718 const gchar *notification_type = "_HILDON_NOTIFICATION_TYPE_BANNER";
719 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (widget);
722 /* We let the parent to init widget->window before we need it */
723 if (GTK_WIDGET_CLASS (hildon_banner_parent_class)->realize)
724 GTK_WIDGET_CLASS (hildon_banner_parent_class)->realize (widget);
726 /* We use special hint to turn the banner into information notification. */
727 gdk_window_set_type_hint (widget->window, GDK_WINDOW_TYPE_HINT_NOTIFICATION);
728 gtk_window_set_transient_for (GTK_WINDOW (widget), (GtkWindow *) priv->parent);
730 hildon_banner_check_position (widget);
732 /* Set the _HILDON_NOTIFICATION_TYPE property so Matchbox places the window correctly */
733 display = gdk_drawable_get_display (widget->window);
734 atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_NOTIFICATION_TYPE");
735 XChangeProperty (GDK_WINDOW_XDISPLAY (widget->window), GDK_WINDOW_XID (widget->window),
736 atom, XA_STRING, 8, PropModeReplace, (guchar *) notification_type,
737 strlen (notification_type));
741 hildon_banner_class_init (HildonBannerClass *klass)
743 GObjectClass *object_class;
744 GtkWidgetClass *widget_class;
746 object_class = G_OBJECT_CLASS (klass);
747 widget_class = GTK_WIDGET_CLASS (klass);
749 /* Append private structure to class. This is more elegant than
750 on g_new based approach */
751 g_type_class_add_private (klass, sizeof (HildonBannerPrivate));
753 /* Override virtual methods */
754 object_class->constructor = hildon_banner_constructor;
755 object_class->finalize = hildon_banner_finalize;
756 object_class->set_property = hildon_banner_set_property;
757 object_class->get_property = hildon_banner_get_property;
758 GTK_OBJECT_CLASS (klass)->destroy = hildon_banner_destroy;
759 widget_class->map_event = hildon_banner_map_event;
760 widget_class->realize = hildon_banner_realize;
761 widget_class->button_press_event = hildon_banner_button_press_event;
762 #if defined(MAEMO_GTK)
763 widget_class->client_event = hildon_banner_client_event;
766 /* Install properties.
767 We need construct properties for singleton purposes */
770 * HildonBanner:parent-window:
772 * The window for which the banner will be singleton.
775 g_object_class_install_property (object_class, PROP_PARENT_WINDOW,
776 g_param_spec_object ("parent-window",
778 "The window for which the banner will be singleton",
779 GTK_TYPE_WINDOW, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
782 * HildonBanner:is-timed:
784 * Whether the banner is timed and goes away automatically.
787 g_object_class_install_property (object_class, PROP_IS_TIMED,
788 g_param_spec_boolean ("is-timed",
790 "Whether or not the notification goes away automatically "
791 "after the specified time has passed",
792 FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
795 * HildonBanner:timeout:
797 * The time before making the banner banner go away. This needs
798 * to be adjusted before the banner is mapped to the screen.
801 g_object_class_install_property (object_class, PROP_TIMEOUT,
802 g_param_spec_uint ("timeout",
804 "The time before making the banner banner go away",
807 HILDON_BANNER_DEFAULT_TIMEOUT,
808 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
812 hildon_banner_init (HildonBanner *self)
814 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (self);
819 /* Initialize the common layout inside banner */
820 priv->layout = gtk_hbox_new (FALSE, HILDON_MARGIN_DEFAULT);
822 priv->label = g_object_new (GTK_TYPE_LABEL, NULL);
823 gtk_label_set_line_wrap (GTK_LABEL (priv->label), TRUE);
824 gtk_label_set_line_wrap_mode (GTK_LABEL (priv->label), PANGO_WRAP_WORD_CHAR);
826 gtk_container_set_border_width (GTK_CONTAINER (priv->layout), HILDON_MARGIN_DEFAULT);
827 gtk_container_add (GTK_CONTAINER (self), priv->layout);
828 gtk_box_pack_start (GTK_BOX (priv->layout), priv->label, TRUE, TRUE, 0);
830 gtk_window_set_accept_focus (GTK_WINDOW (self), FALSE);
832 #if defined(MAEMO_GTK)
833 gtk_window_set_is_temporary (GTK_WINDOW (self), TRUE);
836 hildon_banner_reset_wrap_state (self);
838 gtk_widget_add_events (GTK_WIDGET (self), GDK_BUTTON_PRESS_MASK);
841 /* Makes sure that icon/progress item contains the desired type
842 of item. If possible, tries to avoid creating a new widget but
843 reuses the existing one */
845 hildon_banner_ensure_child (HildonBanner *self,
846 GtkWidget *user_widget,
849 const gchar *first_property,
854 HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (self);
858 widget = priv->main_item;
859 va_start (args, first_property);
861 /* Reuse existing widget if possible */
862 if (! user_widget && G_TYPE_CHECK_INSTANCE_TYPE (widget, type))
864 g_object_set_valist (G_OBJECT (widget), first_property, args);
868 /* We have to abandon old content widget */
870 gtk_container_remove (GTK_CONTAINER (priv->layout), widget);
872 /* Use user provided widget or create a new one */
873 priv->main_item = widget = user_widget ?
874 user_widget : GTK_WIDGET (g_object_new_valist(type, first_property, args));
875 gtk_box_pack_start (GTK_BOX (priv->layout), widget, TRUE, TRUE, 0);
878 /* We make sure that the widget exists in desired position. Different
879 banners place this child widget to different places */
880 gtk_box_reorder_child (GTK_BOX (priv->layout), widget, pos);
884 /* Creates a new banner instance or uses an existing one */
886 hildon_banner_get_instance_for_widget (GtkWidget *widget,
891 window = widget ? gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW) : NULL;
892 return g_object_new (HILDON_TYPE_BANNER, "parent-window", window, "is-timed", timed, NULL);
896 * hildon_banner_show_information:
897 * @widget: the #GtkWidget that is the owner of the banner
898 * @icon_name: the name of icon to use. Can be %NULL for default icon
899 * @text: Text to display
901 * This function creates and displays an information banner that
902 * automatically goes away after certain time period. For each window
903 * in your application there can only be one timed banner, so if you
904 * spawn a new banner before the earlier one has timed out, the
905 * previous one will be replaced.
907 * Returns: The newly created banner
911 hildon_banner_show_information (GtkWidget *widget,
912 const gchar *icon_name,
915 HildonBanner *banner;
917 g_return_val_if_fail (icon_name == NULL || icon_name[0] != 0, NULL);
918 g_return_val_if_fail (text != NULL, NULL);
921 banner = hildon_banner_get_instance_for_widget (widget, TRUE);
923 hildon_banner_set_text (banner, text);
924 hildon_banner_bind_label_style (banner, NULL);
926 /* Show the banner, since caller cannot do that */
927 gtk_widget_show_all (GTK_WIDGET (banner));
929 return (GtkWidget *) banner;
933 * hildon_banner_show_informationf:
934 * @widget: the #GtkWidget that is the owner of the banner
935 * @icon_name: the name of icon to use. Can be %NULL for default icon
936 * @format: a printf-like format string
937 * @Varargs: arguments for the format string
939 * A helper function for #hildon_banner_show_information with
942 * Returns: the newly created banner
945 hildon_banner_show_informationf (GtkWidget *widget,
946 const gchar *icon_name,
950 g_return_val_if_fail (format != NULL, NULL);
956 va_start (args, format);
957 message = g_strdup_vprintf (format, args);
960 banner = hildon_banner_show_information (widget, icon_name, message);
968 * hildon_banner_show_information_with_markup:
969 * @widget: the #GtkWidget that wants to display banner
970 * @icon_name: the name of icon to use. Can be %NULL for default icon.
971 * @markup: a markup string to display (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
973 * This function creates and displays an information banner that
974 * automatically goes away after certain time period. For each window
975 * in your application there can only be one timed banner, so if you
976 * spawn a new banner before the earlier one has timed out, the
977 * previous one will be replaced.
979 * Returns: the newly created banner
983 hildon_banner_show_information_with_markup (GtkWidget *widget,
984 const gchar *icon_name,
987 HildonBanner *banner;
989 g_return_val_if_fail (icon_name == NULL || icon_name[0] != 0, NULL);
990 g_return_val_if_fail (markup != NULL, NULL);
993 banner = hildon_banner_get_instance_for_widget (widget, TRUE);
995 hildon_banner_set_markup (banner, markup);
996 hildon_banner_bind_label_style (banner, NULL);
998 /* Show the banner, since caller cannot do that */
999 gtk_widget_show_all (GTK_WIDGET (banner));
1001 return (GtkWidget *) banner;
1005 * hildon_banner_show_animation:
1006 * @widget: the #GtkWidget that wants to display banner
1007 * @animation_name: The progress animation to use. You usually can just
1008 * pass %NULL for the default animation.
1009 * @text: the text to display.
1011 * Shows an animated progress notification. It's recommended not to try
1012 * to show more than one progress notification at a time, since
1013 * they will appear on top of each other. You can use progress
1014 * notifications with timed banners. In this case the banners are
1015 * located so that you can somehow see both.
1017 * Please note that banners are destroyed automatically once the
1018 * window they are attached to is closed. The pointer that you
1019 * receive with this function do not contain additional references,
1020 * so it can become invalid without warning (this is true for
1021 * all toplevel windows in gtk). To make sure that the banner do not disapear
1022 * automatically, you can separately ref the return value (this
1023 * doesn't prevent the banner from disappearing, but the object it just
1024 * not finalized). In this case you have to call both #gtk_widget_destroy
1025 * followed by #g_object_unref (in this order).
1027 * Returns: a #HildonBanner widget. You must call #gtk_widget_destroy
1028 * once you are done with the banner.
1032 hildon_banner_show_animation (GtkWidget *widget,
1033 const gchar *animation_name,
1036 HildonBanner *banner;
1037 GtkIconTheme *theme;
1039 GtkWidget *image_widget;
1040 const gchar *filename;
1042 g_return_val_if_fail (animation_name == NULL || animation_name[0] != 0, NULL);
1043 g_return_val_if_fail (text != NULL, NULL);
1045 /* Find out which animation to use */
1046 theme = gtk_icon_theme_get_default ();
1047 info = gtk_icon_theme_lookup_icon (theme, animation_name ? /* FIXME: consider using: gtk_icon_theme_load_icon() */
1048 animation_name : HILDON_BANNER_DEFAULT_PROGRESS_ANIMATION,
1049 HILDON_ICON_SIZE_NOTE, 0);
1051 /* Try to load animation. One could try to optimize this
1052 to avoid loading the default animation during each call */
1054 filename = gtk_icon_info_get_filename (info);
1055 image_widget = gtk_image_new_from_file (filename);
1056 gtk_icon_info_free (info);
1058 g_warning ("Icon theme lookup for icon failed!");
1059 image_widget = NULL;
1062 /* Prepare banner */
1063 banner = hildon_banner_get_instance_for_widget (widget, FALSE);
1064 hildon_banner_ensure_child (banner, image_widget, 0,
1065 GTK_TYPE_IMAGE, "yalign", 0.0, NULL);
1067 hildon_banner_set_text (banner, text);
1068 hildon_banner_bind_label_style (banner, NULL);
1071 gtk_widget_show_all (GTK_WIDGET (banner));
1073 return (GtkWidget *) banner;
1077 * hildon_banner_show_progress:
1078 * @widget: the #GtkWidget that wants to display banner
1079 * @bar: Progressbar to use. You usually can just pass %NULL, unless
1080 * you want somehow customized progress bar.
1081 * @text: text to display.
1083 * Shows progress notification. See #hildon_banner_show_animation
1084 * for more information.
1086 * Returns: a #HildonBanner widget. You must call #gtk_widget_destroy
1087 * once you are done with the banner.
1091 hildon_banner_show_progress (GtkWidget *widget,
1092 GtkProgressBar *bar,
1095 HildonBanner *banner;
1096 HildonBannerPrivate *priv;
1098 g_return_val_if_fail (bar == NULL || GTK_IS_PROGRESS_BAR (bar), NULL);
1099 g_return_val_if_fail (text != NULL, NULL);
1102 /* Prepare banner */
1103 banner = hildon_banner_get_instance_for_widget (widget, FALSE);
1104 priv = HILDON_BANNER_GET_PRIVATE (banner);
1106 hildon_banner_ensure_child (banner, (GtkWidget *) bar, -1, GTK_TYPE_PROGRESS_BAR, NULL);
1108 gtk_widget_set_size_request (priv->main_item,
1109 HILDON_BANNER_PROGRESS_WIDTH, -1);
1111 hildon_banner_set_text (banner, text);
1112 hildon_banner_bind_label_style (banner, NULL);
1114 /* Show the banner */
1115 gtk_widget_show_all (GTK_WIDGET (banner));
1117 return GTK_WIDGET (banner);
1121 * hildon_banner_set_text:
1122 * @self: a #HildonBanner widget
1123 * @text: a new text to display in banner
1125 * Sets the text that is displayed in the banner.
1129 hildon_banner_set_text (HildonBanner *self,
1133 HildonBannerPrivate *priv;
1134 const gchar *existing_text;
1136 g_return_if_fail (HILDON_IS_BANNER (self));
1138 priv = HILDON_BANNER_GET_PRIVATE (self);
1141 label = GTK_LABEL (priv->label);
1142 existing_text = gtk_label_get_text (label);
1144 if (existing_text != NULL &&
1146 strcmp (existing_text, text) != 0) {
1147 gtk_label_set_text (label, text);
1148 hildon_banner_reset_wrap_state (self);
1151 hildon_banner_check_position (GTK_WIDGET (self));
1155 * hildon_banner_set_markup:
1156 * @self: a #HildonBanner widget
1157 * @markup: a new text with Pango markup to display in the banner
1159 * Sets the text with markup that is displayed in the banner.
1163 hildon_banner_set_markup (HildonBanner *self,
1164 const gchar *markup)
1167 HildonBannerPrivate *priv;
1169 g_return_if_fail (HILDON_IS_BANNER (self));
1171 priv = HILDON_BANNER_GET_PRIVATE (self);
1174 label = GTK_LABEL (priv->label);
1175 gtk_label_set_markup (label, markup);
1177 hildon_banner_reset_wrap_state (self);
1179 hildon_banner_check_position (GTK_WIDGET(self));
1183 * hildon_banner_set_fraction:
1184 * @self: a #HildonBanner widget
1185 * @fraction: #gdouble
1187 * The fraction is the completion of progressbar,
1188 * the scale is from 0.0 to 1.0.
1189 * Sets the amount of fraction the progressbar has.
1193 hildon_banner_set_fraction (HildonBanner *self,
1196 HildonBannerPrivate *priv;
1198 g_return_if_fail (HILDON_IS_BANNER (self));
1199 priv = HILDON_BANNER_GET_PRIVATE (self);
1202 g_return_if_fail (GTK_IS_PROGRESS_BAR (priv->main_item));
1203 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->main_item), fraction);
1207 * hildon_banner_set_timeout:
1208 * @self: a #HildonBanner widget
1209 * @timeout: timeout to set in miliseconds.
1211 * Sets the timeout on the banner. After the given amount of miliseconds
1212 * has elapsed the banner will go away. Note that settings this only makes
1213 * sense on the banners that are timed and that have not been yet displayed
1218 hildon_banner_set_timeout (HildonBanner *self,
1221 HildonBannerPrivate *priv;
1223 g_return_if_fail (HILDON_IS_BANNER (self));
1224 priv = HILDON_BANNER_GET_PRIVATE (self);
1227 priv->timeout = timeout;
1231 * hildon_banner_set_icon:
1232 * @self: a #HildonBanner widget
1233 * @icon_name: the name of icon to use. Can be %NULL for default icon
1235 * Sets the icon to be used in the banner.
1239 hildon_banner_set_icon (HildonBanner *self,
1240 const gchar *icon_name)
1242 HildonBannerPrivate *priv;
1244 g_return_if_fail (HILDON_IS_BANNER (self));
1245 priv = HILDON_BANNER_GET_PRIVATE (self);
1248 hildon_banner_ensure_child (self, NULL, 0, GTK_TYPE_IMAGE,
1249 "pixel-size", HILDON_ICON_PIXEL_SIZE_NOTE,
1250 "icon-name", icon_name ? icon_name : HILDON_BANNER_DEFAULT_ICON,
1256 * hildon_banner_set_icon_from_file:
1257 * @self: a #HildonBanner widget
1258 * @icon_file: the filename of icon to use. Can be %NULL for default icon
1260 * Sets the icon from its filename to be used in the banner.
1264 hildon_banner_set_icon_from_file (HildonBanner *self,
1265 const gchar *icon_file)
1267 HildonBannerPrivate *priv;
1269 g_return_if_fail (HILDON_IS_BANNER (self));
1270 priv = HILDON_BANNER_GET_PRIVATE (self);
1273 if (icon_file != NULL) {
1274 hildon_banner_ensure_child (self, NULL, 0, GTK_TYPE_IMAGE,
1275 "pixel-size", HILDON_ICON_PIXEL_SIZE_NOTE,
1280 hildon_banner_ensure_child (self, NULL, 0, GTK_TYPE_IMAGE,
1281 "pixel-size", HILDON_ICON_PIXEL_SIZE_NOTE,
1282 "icon-name", HILDON_BANNER_DEFAULT_ICON,