2 * This file is part of hildon-libs
4 * Copyright (C) 2005, 2006 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
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
25 #include <gtk/gtkhbox.h>
26 #include <gtk/gtkimage.h>
27 #include <gtk/gtkicontheme.h>
30 #include <X11/Xatom.h>
32 #include "hildon-defines.h"
33 #include "hildon-banner.h"
35 /* position relative to the screen */
36 #define HILDON_BANNER_WINDOW_X 30
37 #define HILDON_BANNER_WINDOW_Y 73
38 #define HILDON_BANNER_WINDOW_FULLSCREEN_Y 20
41 #define HILDON_BANNER_PROGRESS_WIDTH 104
42 #define HILDON_BANNER_LABEL_MAX_TIMED 375
43 #define HILDON_BANNER_LABEL_MAX_PROGRESS 375 /*265*/
46 #define HILDON_BANNER_TIMEOUT 3000
49 #define HILDON_BANNER_DEFAULT_ICON "qgn_note_infoprint"
50 #define HILDON_BANNER_DEFAULT_PROGRESS_ANIMATION "qgn_indi_pball_a"
53 PROP_PARENT_WINDOW = 1,
57 struct _HildonBannerPrivate
66 static GtkWidget *global_timed_banner = NULL;
68 G_DEFINE_TYPE(HildonBanner, hildon_banner, GTK_TYPE_WINDOW)
70 /* copy/paste from old infoprint implementation: Use matchbox
71 properties to find the topmost application window */
72 static Window get_current_app_window(void)
79 Atom atom_current_app_window = gdk_x11_get_xatom_by_name ("_MB_CURRENT_APP_WINDOW");
81 Window win_result = None;
82 guchar *data_return = NULL;
84 status = XGetWindowProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
85 atom_current_app_window, 0L, 16L,
86 0, XA_WINDOW, &realType, &format,
90 if ( status == Success && realType == XA_WINDOW
91 && format == 32 && n == 1 && data_return != NULL )
93 win_result = ((Window*) data_return)[0];
102 /* Checks if a window is in fullscreen state or not. This
103 information is needed when banners are positioned on screen.
104 copy/paste from old infoprint implementation. */
105 static gboolean check_fullscreen_state( Window window )
109 int format, status, i;
110 guchar *data_return = NULL;
113 Atom atom_window_state = gdk_x11_get_xatom_by_name ("_NET_WM_STATE");
114 Atom atom_fullscreen = gdk_x11_get_xatom_by_name ("_NET_WM_STATE_FULLSCREEN");
116 if ( window == None )
119 /* in some cases XGetWindowProperty seems to generate BadWindow,
120 so at the moment this function does not always work perfectly */
121 gdk_error_trap_push();
122 status = XGetWindowProperty(GDK_DISPLAY(), window,
123 atom_window_state, 0L, 1000000L,
124 0, XA_ATOM, &realType, &format,
125 &n, &extra, &data_return);
127 if (gdk_error_trap_pop())
130 if (status == Success && realType == XA_ATOM && format == 32 && n > 0)
133 if ( ((Atom*)data_return)[i] &&
134 ((Atom*)data_return)[i] == atom_fullscreen)
136 if (data_return) XFree(data_return);
147 static GQuark hildon_banner_timed_quark(void)
149 static GQuark quark = 0;
151 if (G_UNLIKELY(quark == 0))
152 quark = g_quark_from_static_string("hildon-banner-timed");
157 /* Set the label name to make the correct rc-style attached into it */
158 static void hildon_banner_bind_label_style(HildonBanner *self,
161 GtkWidget *label = self->priv->label;
163 /* Too bad that we cannot really reset the widget name */
164 gtk_widget_set_name(label, name ? name : g_type_name(GTK_WIDGET_TYPE(label)));
167 /* In timeout function we automatically destroy timed banners */
168 static gboolean hildon_banner_timeout(gpointer data)
172 gboolean continue_timeout = FALSE;
174 GDK_THREADS_ENTER ();
176 g_assert(HILDON_IS_BANNER(data));
178 widget = GTK_WIDGET(data);
179 g_object_ref(widget);
181 /* If the banner is currently visible (it normally should),
182 we simulate clicking the close button of the window.
183 This allows applications to reuse the banner by prevent
185 if (GTK_WIDGET_DRAWABLE(widget))
187 event = gdk_event_new (GDK_DELETE);
188 event->any.window = g_object_ref(widget->window);
189 event->any.send_event = FALSE;
190 continue_timeout = gtk_widget_event (widget, event);
191 gdk_event_free(event);
194 if (!continue_timeout)
195 gtk_widget_destroy (widget);
197 g_object_unref(widget);
199 GDK_THREADS_LEAVE ();
201 return continue_timeout;
204 static gboolean hildon_banner_clear_timeout(HildonBanner *self)
206 g_assert(HILDON_IS_BANNER(self));
208 if (self->priv->timeout_id != 0) {
209 g_source_remove(self->priv->timeout_id);
210 self->priv->timeout_id = 0;
217 static void hildon_banner_ensure_timeout(HildonBanner *self)
219 g_assert(HILDON_IS_BANNER(self));
221 if (self->priv->timeout_id == 0 && self->priv->is_timed)
222 self->priv->timeout_id = g_timeout_add(HILDON_BANNER_TIMEOUT,
223 hildon_banner_timeout, self);
226 static void hildon_banner_set_property(GObject *object,
233 HildonBannerPrivate *priv = HILDON_BANNER(object)->priv;
237 priv->is_timed = g_value_get_boolean(value);
239 /* Timed and progress notifications have different
240 pixel size values for text.
241 We force to use requisition size for timed banners
242 in order to avoid resize problems when reusing the
243 window (see bug #24339) */
244 geom.max_width = priv->is_timed ? -1
245 : HILDON_BANNER_LABEL_MAX_PROGRESS;
246 geom.max_height = -1;
247 gtk_window_set_geometry_hints(GTK_WINDOW(object),
248 priv->label, &geom, GDK_HINT_MAX_SIZE);
251 case PROP_PARENT_WINDOW:
252 window = g_value_get_object(value);
254 gtk_window_set_transient_for(GTK_WINDOW(object), (GtkWindow *) window);
257 gtk_window_set_destroy_with_parent(GTK_WINDOW(object), TRUE);
262 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
267 static void hildon_banner_get_property(GObject *object,
272 HildonBanner *self = HILDON_BANNER(object);
277 g_value_set_boolean(value, self->priv->is_timed);
280 case PROP_PARENT_WINDOW:
281 g_value_set_object(value, gtk_window_get_transient_for(GTK_WINDOW(object)));
285 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
290 static void hildon_banner_destroy(GtkObject *object)
293 GObject *parent_window;
295 g_assert(HILDON_IS_BANNER(object));
296 self = HILDON_BANNER(object);
298 /* Drop possible global pointer. That can hold reference to us */
299 if ((gpointer) object == (gpointer) global_timed_banner) {
300 global_timed_banner = NULL;
301 g_object_unref(object);
304 /* Remove the data from parent window for timed banners. Those hold reference */
305 if (self->priv->is_timed &&
306 (parent_window = (GObject *) gtk_window_get_transient_for(
307 GTK_WINDOW(object))) != NULL)
308 g_object_set_qdata(parent_window, hildon_banner_timed_quark(), NULL);
310 (void) hildon_banner_clear_timeout(self);
312 if (GTK_OBJECT_CLASS(hildon_banner_parent_class)->destroy)
313 GTK_OBJECT_CLASS(hildon_banner_parent_class)->destroy(object);
316 /* Search a previous banner instance */
317 static GObject *hildon_banner_real_get_instance(GObject *window, gboolean timed)
319 g_assert(window == NULL || GTK_IS_WINDOW(window));
322 /* If we have a parent window, the previous instance is stored there */
324 return g_object_get_qdata(window, hildon_banner_timed_quark());
326 /* System notification instance is stored into global pointer */
327 return (GObject *) global_timed_banner;
330 /* Non-timed banners are normal (non-singleton) objects */
334 /* By overriding constructor we force timed banners to be
335 singletons for each window */
336 static GObject* hildon_banner_constructor (GType type,
337 guint n_construct_params,
338 GObjectConstructParam *construct_params)
340 GObject *banner, *window = NULL;
341 gboolean timed = FALSE;
344 /* Search banner type information from parameters in order
345 to locate the possible previous banner instance. */
346 for (i = 0; i < n_construct_params; i++)
348 if (strcmp(construct_params[i].pspec->name, "parent-window") == 0)
349 window = g_value_get_object(construct_params[i].value);
350 else if (strcmp(construct_params[i].pspec->name, "is-timed") == 0)
351 timed = g_value_get_boolean(construct_params[i].value);
354 /* Try to get a previous instance if such exists */
355 banner = hildon_banner_real_get_instance(window, timed);
358 /* We have to create a new banner */
359 banner = G_OBJECT_CLASS(hildon_banner_parent_class)->constructor(
360 type, n_construct_params, construct_params);
362 /* Store the newly created singleton instance either into parent
363 window data or into global variables. */
366 g_object_set_qdata_full(G_OBJECT(window), hildon_banner_timed_quark(),
367 g_object_ref(banner), g_object_unref);
369 g_assert(global_timed_banner == NULL);
370 global_timed_banner = g_object_ref(banner);
375 /* FIXME: This is a hack! We have to manually freeze
376 notifications. This is normally done by g_object_init, but we
377 are not going to call that. g_object_newv will otherwise give
378 a critical like this:
380 GLIB CRITICAL ** GLib-GObject - g_object_notify_queue_thaw:
381 assertion `nqueue->freeze_count > 0' failed */
383 g_object_freeze_notify(banner);
386 /* We restart possible timeouts for each new timed banner request */
387 if (timed && hildon_banner_clear_timeout(HILDON_BANNER(banner)))
388 hildon_banner_ensure_timeout(HILDON_BANNER(banner));
393 /* We start the timer for timed notifications after the window appears on screen */
394 static gboolean hildon_banner_map_event(GtkWidget *widget, GdkEventAny *event)
396 gboolean result = FALSE;
398 if (GTK_WIDGET_CLASS(hildon_banner_parent_class)->map_event)
399 result = GTK_WIDGET_CLASS(hildon_banner_parent_class)->map_event(widget, event);
401 hildon_banner_ensure_timeout(HILDON_BANNER(widget));
407 /* force to wrap truncated label by setting explicit size request
408 * see N#27000 and G#329646 */
409 static void force_to_wrap_truncated(HildonBanner *banner){
412 int width_text, width_max;
415 label = GTK_LABEL(banner->priv->label);
417 layout = gtk_label_get_layout(label);
418 width_text = PANGO_PIXELS(pango_layout_get_width(layout));
419 /* = width to which the lines of the PangoLayout should be wrapped */
421 width_max = banner->priv->is_timed ? HILDON_BANNER_LABEL_MAX_TIMED
422 : HILDON_BANNER_LABEL_MAX_PROGRESS;
424 if(width_text >= width_max){
425 /* explicitly request maximum size to force wrapping */
426 PangoRectangle logical;
428 pango_layout_set_width (layout, width_max * PANGO_SCALE);
429 pango_layout_get_extents (layout, NULL, &logical);
431 width = PANGO_PIXELS (logical.width);
434 /* use fixed width when wrapping or natural one otherwise */
435 gtk_widget_set_size_request (GTK_WIDGET (label),
440 static void hildon_banner_check_position(GtkWidget *widget)
445 force_to_wrap_truncated(HILDON_BANNER(widget)); /* see N#27000 and G#329646 */
447 gtk_widget_size_request(widget, &req);
454 x = gdk_screen_width() - HILDON_BANNER_WINDOW_X - req.width;
455 y = check_fullscreen_state(get_current_app_window()) ?
456 HILDON_BANNER_WINDOW_FULLSCREEN_Y : HILDON_BANNER_WINDOW_Y;
458 gtk_window_move(GTK_WINDOW(widget), x, y);
461 static void hildon_banner_realize(GtkWidget *widget)
463 /* We let the parent to init widget->window before we need it */
464 if (GTK_WIDGET_CLASS(hildon_banner_parent_class)->realize)
465 GTK_WIDGET_CLASS(hildon_banner_parent_class)->realize(widget);
467 /* We use special hint to turn the banner into information notification. */
468 gdk_window_set_type_hint(widget->window, GDK_WINDOW_TYPE_HINT_MESSAGE);
470 hildon_banner_check_position(widget);
473 static void hildon_banner_class_init(HildonBannerClass *klass)
475 GObjectClass *object_class;
476 GtkWidgetClass *widget_class;
478 object_class = G_OBJECT_CLASS(klass);
479 widget_class = GTK_WIDGET_CLASS(klass);
481 /* Append private structure to class. This is more elegant than
482 on g_new based approach */
483 g_type_class_add_private(klass, sizeof(HildonBannerPrivate));
485 /* Override virtual methods */
486 object_class->constructor = hildon_banner_constructor;
487 object_class->set_property = hildon_banner_set_property;
488 object_class->get_property = hildon_banner_get_property;
489 GTK_OBJECT_CLASS(klass)->destroy = hildon_banner_destroy;
490 widget_class->map_event = hildon_banner_map_event;
491 widget_class->realize = hildon_banner_realize;
493 /* Install properties.
494 We need construct properties for singleton purposes */
495 g_object_class_install_property(object_class, PROP_PARENT_WINDOW,
496 g_param_spec_object("parent-window",
498 "The window for which the banner will be singleton",
499 GTK_TYPE_WINDOW, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
501 g_object_class_install_property(object_class, PROP_IS_TIMED,
502 g_param_spec_boolean("is-timed",
504 "Whether or not the notification goes away automatically "
505 "after the specified time has passed",
506 FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
509 static void hildon_banner_init(HildonBanner *self)
511 HildonBannerPrivate *priv;
513 /* Make private data available through cached pointer */
514 self->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
516 HildonBannerPrivate);
518 /* Initialize the common layout inside banner */
519 self->priv->layout = gtk_hbox_new(FALSE, HILDON_MARGIN_DEFAULT);
521 priv->label = g_object_new(GTK_TYPE_LABEL, NULL);
522 gtk_label_set_line_wrap(GTK_LABEL(priv->label), TRUE);
524 gtk_container_set_border_width(GTK_CONTAINER(self->priv->layout), HILDON_MARGIN_DEFAULT);
525 gtk_container_add(GTK_CONTAINER(self), self->priv->layout);
526 gtk_box_pack_start(GTK_BOX(self->priv->layout), priv->label, TRUE, TRUE, 0);
528 gtk_window_set_accept_focus(GTK_WINDOW(self), FALSE);
531 /* Makes sure that icon/progress item contains the desired type
532 of item. If possible, tries to avoid creating a new widget but
533 reuses the existing one */
534 static void hildon_banner_ensure_child(HildonBanner *self,
535 GtkWidget *user_widget,
538 const gchar *first_property, ...)
543 g_assert(HILDON_IS_BANNER(self));
544 g_assert(user_widget == NULL || GTK_IS_WIDGET(user_widget));
546 widget = self->priv->main_item;
547 va_start(args, first_property);
549 /* Reuse existing widget if possible */
550 if (!user_widget && G_TYPE_CHECK_INSTANCE_TYPE(widget, type))
552 g_object_set_valist(G_OBJECT(widget), first_property, args);
556 /* We have to abandon old content widget */
558 gtk_container_remove(GTK_CONTAINER(self->priv->layout), widget);
560 /* Use user provided widget or create a new one */
561 self->priv->main_item = widget = user_widget ?
562 user_widget : GTK_WIDGET(g_object_new_valist(type, first_property, args));
563 gtk_box_pack_start(GTK_BOX(self->priv->layout), widget, TRUE, TRUE, 0);
566 /* We make sure that the widget exists in desired position. Different
567 banners place this child widget to different places */
568 gtk_box_reorder_child(GTK_BOX(self->priv->layout), widget, pos);
572 /* Creates a new banner instance or uses an existing one */
573 static HildonBanner *hildon_banner_get_instance_for_widget(GtkWidget *widget, gboolean timed)
577 g_return_val_if_fail(widget == NULL || GTK_IS_WIDGET(widget), NULL);
578 window = widget ? gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW) : NULL;
579 return g_object_new(HILDON_TYPE_BANNER, "parent-window", window, "is-timed", timed, NULL);
586 /* Public functions **************************************************************/
589 * hildon_banner_show_information:
590 * @widget: the #GtkWidget that wants to display banner
591 * @icon_name: the name of icon to use. Can be %NULL for default icon.
592 * @text: Text to display
594 * This function creates and displays an information banner that
595 * automatically goes away after certain time period. For each window
596 * in your application there can only be one timed banner, so if you
597 * spawn a new banner before the earlier one has timed out, the
598 * previous one will be replaced.
602 void hildon_banner_show_information(GtkWidget *widget,
603 const gchar *icon_name,
606 HildonBanner *banner;
608 g_return_if_fail(widget == NULL || GTK_IS_WIDGET(widget));
609 g_return_if_fail(icon_name == NULL || icon_name[0] != 0);
610 g_return_if_fail(text != NULL);
613 banner = hildon_banner_get_instance_for_widget(widget, TRUE);
614 hildon_banner_ensure_child(banner, NULL, 0, GTK_TYPE_IMAGE,
615 "pixel-size", HILDON_ICON_PIXEL_SIZE_NOTE,
616 "icon-name", icon_name ? icon_name : HILDON_BANNER_DEFAULT_ICON,
619 hildon_banner_set_text(banner, text);
620 hildon_banner_bind_label_style(banner, NULL);
622 /* Show the banner, since caller cannot do that */
623 gtk_widget_show_all(GTK_WIDGET(banner));
627 * hildon_banner_show_information_with_markup:
628 * @widget: the #GtkWidget that wants to display banner
629 * @icon_name: the name of icon to use. Can be %NULL for default icon.
630 * @markup: a markup string to display (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
632 * This function creates and displays an information banner that
633 * automatically goes away after certain time period. For each window
634 * in your application there can only be one timed banner, so if you
635 * spawn a new banner before the earlier one has timed out, the
636 * previous one will be replaced.
640 void hildon_banner_show_information_with_markup(GtkWidget *widget,
641 const gchar *icon_name, const gchar *markup)
643 HildonBanner *banner;
645 g_return_if_fail(widget == NULL || GTK_IS_WIDGET(widget));
646 g_return_if_fail(icon_name == NULL || icon_name[0] != 0);
647 g_return_if_fail(markup != NULL);
650 banner = hildon_banner_get_instance_for_widget(widget, TRUE);
652 hildon_banner_ensure_child(banner, NULL, 0, GTK_TYPE_IMAGE,
653 "pixel-size", HILDON_ICON_PIXEL_SIZE_NOTE,
654 "icon-name", icon_name ? icon_name : HILDON_BANNER_DEFAULT_ICON,
657 hildon_banner_set_markup(banner, markup);
658 hildon_banner_bind_label_style(banner, NULL);
660 /* Show the banner, since caller cannot do that */
661 gtk_widget_show_all(GTK_WIDGET(banner));
665 * hildon_banner_show_animation:
666 * @widget: the #GtkWidget that wants to display banner
667 * @animation_name: The progress animation to use. You usually can just
668 * pass %NULL for the default animation.
669 * @text: the text to display.
671 * Shows an animated progress notification. It's recommended not to try
672 * to show more than one progress notification at a time, since
673 * they will appear on top of each other. You can use progress
674 * notifications with timed banners. In this case the banners are
675 * located so that you can somehow see both.
677 * Please note that banners are destroyed automatically once the
678 * window they are attached to is closed. The pointer that you
679 * receive with this function do not contain additional references,
680 * so it can become invalid without warning (this is true for
681 * all toplevel windows in gtk). To make sure that the banner do not disapear
682 * automatically, you can separately ref the return value (this
683 * doesn't prevent the banner from disappearing, but the object it just
684 * not finalized). In this case you have to call both #gtk_widget_destroy
685 * followed by #g_object_unref (in this order).
687 * Returns: a #HildonBanner widget. You must call #gtk_widget_destroy
688 * once you are ready with the banner.
692 GtkWidget *hildon_banner_show_animation(GtkWidget *widget,
693 const gchar *animation_name, const gchar *text)
695 HildonBanner *banner;
698 GtkWidget *image_widget;
699 const gchar *filename;
701 g_return_val_if_fail(widget == NULL || GTK_IS_WIDGET(widget), NULL);
702 g_return_val_if_fail(animation_name == NULL || animation_name[0] != 0, NULL);
703 g_return_val_if_fail(text != NULL, NULL);
705 /* Find out which animation to use */
706 theme = gtk_icon_theme_get_default();
707 info = gtk_icon_theme_lookup_icon(theme, animation_name ? /* TODO: consider using: gtk_icon_theme_load_icon() */
708 animation_name : HILDON_BANNER_DEFAULT_PROGRESS_ANIMATION,
709 HILDON_ICON_SIZE_NOTE, 0);
711 /* Try to load animation. One could try to optimize this
712 to avoid loading the default animation during each call */
714 filename = gtk_icon_info_get_filename(info);
715 image_widget = gtk_image_new_from_file(filename);
716 gtk_icon_info_free(info);
718 g_warning("icon theme lookup for icon failed!");
723 banner = hildon_banner_get_instance_for_widget(widget, FALSE);
724 hildon_banner_ensure_child(banner, image_widget, 0,
725 GTK_TYPE_IMAGE, "yalign", 0.0, NULL);
726 hildon_banner_set_text(banner, text);
727 hildon_banner_bind_label_style(banner, NULL);
730 gtk_widget_show_all(GTK_WIDGET(banner));
732 return GTK_WIDGET(banner);
736 * hildon_banner_show_progress:
737 * @widget: the #GtkWidget that wants to display banner
738 * @bar: Progressbar to use. You usually can just pass %NULL, unless
739 * you want somehow customized progress bar.
740 * @text: text to display.
742 * Shows progress notification. See #hildon_banner_show_animation
743 * for more information.
745 * Returns: a #HildonBanner widget. You must call #gtk_widget_destroy
746 * once you are ready with the banner.
750 GtkWidget *hildon_banner_show_progress(GtkWidget *widget,
751 GtkProgressBar *bar, const gchar *text)
753 HildonBanner *banner;
755 g_return_val_if_fail(widget == NULL || GTK_IS_WIDGET(widget), NULL);
756 g_return_val_if_fail(bar == NULL || GTK_IS_PROGRESS_BAR(bar), NULL);
757 g_return_val_if_fail(text != NULL, NULL);
760 banner = hildon_banner_get_instance_for_widget(widget, FALSE);
761 hildon_banner_ensure_child(banner, (GtkWidget *) bar, -1, GTK_TYPE_PROGRESS_BAR, NULL);
762 gtk_widget_set_size_request(banner->priv->main_item,
763 HILDON_BANNER_PROGRESS_WIDTH, -1);
764 hildon_banner_set_text(banner, text);
765 hildon_banner_bind_label_style(banner, NULL);
767 /* Show the banner */
768 gtk_widget_show_all(GTK_WIDGET(banner));
770 return GTK_WIDGET(banner);
774 * hildon_banner_set_text:
775 * @self: a #HildonBanner widget
776 * @text: a new text to display in banner
778 * Sets the text that is displayed in the banner.
782 void hildon_banner_set_text(HildonBanner *self, const gchar *text)
786 g_return_if_fail(HILDON_IS_BANNER(self));
788 label = GTK_LABEL(self->priv->label);
789 gtk_label_set_text(label, text);
791 hildon_banner_check_position(GTK_WIDGET(self));
795 * hildon_banner_set_markup:
796 * @self: a #HildonBanner widget
797 * @markup: a new text with Pango markup to display in the banner
799 * Sets the text with markup that is displayed in the banner.
803 void hildon_banner_set_markup(HildonBanner *self, const gchar *markup)
807 g_return_if_fail(HILDON_IS_BANNER(self));
809 label = GTK_LABEL(self->priv->label);
810 gtk_label_set_markup(label, markup);
812 hildon_banner_check_position(GTK_WIDGET(self));
816 * hildon_banner_set_fraction:
817 * @self: a #HildonBanner widget
818 * @fraction: #gdouble
820 * The fraction is the completion of progressbar,
821 * the scale is from 0.0 to 1.0.
822 * Sets the amount of fraction the progressbar has.
826 void hildon_banner_set_fraction(HildonBanner *self, gdouble fraction)
828 g_return_if_fail(HILDON_IS_BANNER(self));
829 g_return_if_fail(GTK_IS_PROGRESS_BAR(self->priv->main_item));
830 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(self->priv->main_item), fraction);
838 * Deprecated: really, do NOT use.
840 void _hildon_gtk_label_set_text_n_lines(GtkLabel *label, const gchar *text, gint max_lines)
842 /* Forces the wrapping of text into several lines and ellipsizes the rest.
843 Similar to combination of gtk_label_set_wrap and pango ellipzation.
844 We cannot just use those directly, since ellipzation always wins wrapping.
846 This means that we have to:
847 * First wrap the text
848 * Insert forced linebreaks into text
849 * Truncate the result
851 NOTE! This will not work with pango markup!
853 FIXME: luc: DO NOT TRUNCATE the text. Use as many lines as needed.
854 Lenth of the text is under applications' responsibility.
855 Widget does not have to enforce this.
858 PangoLayoutLine *line;
860 GString *wrapped_text;
864 g_return_if_fail(GTK_IS_LABEL(label));
865 g_return_if_fail(max_lines >= 1);
867 /* Setup the label to contain the new data */
868 gtk_label_set_text(label, text);
869 gtk_label_set_line_wrap(label, TRUE);
870 gtk_label_set_ellipsize(label, PANGO_ELLIPSIZE_NONE);
872 /* We really want to recalculate the size, not use some old values */
873 gtk_widget_size_request(GTK_WIDGET(label), &req);
874 layout = gtk_label_get_layout(label);
875 lines = pango_layout_get_line_count(layout);
877 /* Now collect the wrapped text. */
878 wrapped_text = g_string_new(NULL);
880 for (i = 0; i < lines; i++)
882 /* Append the next line into wrapping buffer, but
883 avoid adding extra whitespaces at the end, since those
884 can cause other lines to be ellipsized as well. */
885 line = pango_layout_get_line(layout, i);
886 line_data = g_strndup(pango_layout_get_text(layout) + line->start_index,
888 g_strchomp(line_data);
889 g_string_append(wrapped_text, line_data);
891 /* Append forced linebreaks, until we have the desired
892 amount of lines. After that we put the rest to the
893 last line to make ellipzation to happen */
896 if (i < max_lines - 1)
897 g_string_append_c(wrapped_text, '\n');
899 g_string_append_c(wrapped_text, ' ');
905 /* Now update the label to use wrapped text. Use builtin
906 ellipzation as well. */
907 gtk_widget_set_size_request(GTK_WIDGET(label), req.width, -1);
908 gtk_label_set_text(label, wrapped_text->str);
909 gtk_label_set_ellipsize(label, PANGO_ELLIPSIZE_END);
910 gtk_label_set_line_wrap(label, FALSE);
912 g_string_free(wrapped_text, TRUE);