2 * This file is part of hildon-libs
4 * Copyright (C) 2005 Nokia Corporation.
6 * Contact: Luc Pionchon <luc.pionchon@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; either 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
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 #define HILDON_BANNER_WINDOW_X 30
36 #define HILDON_BANNER_WINDOW_Y 73
37 #define HILDON_BANNER_WINDOW_FULLSCREEN_Y 20
38 #define HILDON_BANNER_PROGRESS_WIDTH 104
39 #define HILDON_BANNER_LABEL_MAX_TIMED 375
40 #define HILDON_BANNER_LABEL_MAX_PROGRESS 265
41 #define HILDON_BANNER_TIMEOUT 3000
43 #define HILDON_BANNER_DEFAULT_ICON "qgn_note_infoprint"
44 #define HILDON_BANNER_DEFAULT_PROGRESS_ANIMATION "qgn_indi_pball_a"
47 PROP_PARENT_WINDOW = 1,
51 struct _HildonBannerPrivate
53 GtkWidget *main_item, *label, *layout;
58 static GtkWidget *global_timed_banner = NULL;
60 G_DEFINE_TYPE(HildonBanner, hildon_banner, GTK_TYPE_WINDOW)
62 /* copy/paste from old infoprint implementation: Use matchbox
63 properties to find the topmost application window */
64 static Window get_current_app_window(void)
71 Atom atom_current_app_window = gdk_x11_get_xatom_by_name ("_MB_CURRENT_APP_WINDOW");
73 Window win_result = None;
74 guchar *data_return = NULL;
76 status = XGetWindowProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(),
77 atom_current_app_window, 0L, 16L,
78 0, XA_WINDOW, &realType, &format,
82 if ( status == Success && realType == XA_WINDOW
83 && format == 32 && n == 1 && data_return != NULL )
85 win_result = ((Window*) data_return)[0];
94 /* Checks if a window is in fullscreen state or not. This
95 information is needed when banners are positioned on screen.
96 copy/paste from old infoprint implementation. */
97 static gboolean check_fullscreen_state( Window window )
101 int format, status, i;
102 guchar *data_return = NULL;
105 Atom atom_window_state = gdk_x11_get_xatom_by_name ("_NET_WM_STATE");
106 Atom atom_fullscreen = gdk_x11_get_xatom_by_name ("_NET_WM_STATE_FULLSCREEN");
108 if ( window == None )
111 /* in some cases XGetWindowProperty seems to generate BadWindow,
112 so at the moment this function does not always work perfectly */
113 gdk_error_trap_push();
114 status = XGetWindowProperty(GDK_DISPLAY(), window,
115 atom_window_state, 0L, 1000000L,
116 0, XA_ATOM, &realType, &format,
117 &n, &extra, &data_return);
119 if (gdk_error_trap_pop())
122 if (status == Success && realType == XA_ATOM && format == 32 && n > 0)
125 if ( ((Atom*)data_return)[i] &&
126 ((Atom*)data_return)[i] == atom_fullscreen)
128 if (data_return) XFree(data_return);
139 static GQuark hildon_banner_timed_quark(void)
141 static GQuark quark = 0;
143 if (G_UNLIKELY(quark == 0))
144 quark = g_quark_from_static_string("hildon-banner-timed");
149 /* Set the label name to make the correct rc-style attached into it */
150 static void hildon_banner_bind_label_style(HildonBanner *self,
153 GtkWidget *label = self->priv->label;
155 /* Too bad that we cannot really reset the widget name */
156 gtk_widget_set_name(label, name ? name : g_type_name(GTK_WIDGET_TYPE(label)));
159 /* In timeout function we automatically destroy timed banners */
160 static gboolean hildon_banner_timeout(gpointer data)
164 gboolean continue_timeout = FALSE;
166 GDK_THREADS_ENTER ();
168 g_assert(HILDON_IS_BANNER(data));
170 widget = GTK_WIDGET(data);
171 g_object_ref(widget);
173 /* If the banner is currently visible (it normally should),
174 we simulate clicking the close button of the window.
175 This allows applications to reuse the banner by prevent
177 if (GTK_WIDGET_DRAWABLE(widget))
179 event = gdk_event_new (GDK_DELETE);
180 event->any.window = g_object_ref(widget->window);
181 event->any.send_event = FALSE;
182 continue_timeout = gtk_widget_event (widget, event);
183 gdk_event_free(event);
186 if (!continue_timeout)
187 gtk_widget_destroy (widget);
189 g_object_unref(widget);
191 GDK_THREADS_LEAVE ();
193 return continue_timeout;
196 static gboolean hildon_banner_clear_timeout(HildonBanner *self)
198 g_assert(HILDON_IS_BANNER(self));
200 if (self->priv->timeout_id != 0) {
201 g_source_remove(self->priv->timeout_id);
202 self->priv->timeout_id = 0;
209 static void hildon_banner_ensure_timeout(HildonBanner *self)
211 g_assert(HILDON_IS_BANNER(self));
213 if (self->priv->timeout_id == 0 && self->priv->is_timed)
214 self->priv->timeout_id = g_timeout_add(HILDON_BANNER_TIMEOUT,
215 hildon_banner_timeout, self);
218 static void hildon_banner_set_property(GObject *object,
225 HildonBannerPrivate *priv = HILDON_BANNER(object)->priv;
229 priv->is_timed = g_value_get_boolean(value);
231 /* Timed and progress notifications have different
232 pixel size values for text */
233 geom.max_width = priv->is_timed ?
234 HILDON_BANNER_LABEL_MAX_TIMED : HILDON_BANNER_LABEL_MAX_PROGRESS;
236 geom.max_height = -1;
237 gtk_window_set_geometry_hints(GTK_WINDOW(object),
238 priv->label, &geom, GDK_HINT_MAX_SIZE);
240 case PROP_PARENT_WINDOW:
241 window = g_value_get_object(value);
243 gtk_window_set_transient_for(GTK_WINDOW(object), (GtkWindow *) window);
246 gtk_window_set_destroy_with_parent(GTK_WINDOW(object), TRUE);
250 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
255 static void hildon_banner_get_property(GObject *object,
256 guint prop_id, GValue *value, GParamSpec *pspec)
258 HildonBanner *self = HILDON_BANNER(object);
263 g_value_set_boolean(value, self->priv->is_timed);
265 case PROP_PARENT_WINDOW:
266 g_value_set_object(value, gtk_window_get_transient_for(GTK_WINDOW(object)));
269 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
274 static void hildon_banner_destroy(GtkObject *object)
277 GObject *parent_window;
279 g_assert(HILDON_IS_BANNER(object));
280 self = HILDON_BANNER(object);
282 /* Drop possible global pointer. That can hold reference to us */
283 if ((gpointer) object == (gpointer) global_timed_banner) {
284 global_timed_banner = NULL;
285 g_object_unref(object);
288 /* Remove the data from parent window for timed banners. Those hold reference */
289 if (self->priv->is_timed &&
290 (parent_window = (GObject *) gtk_window_get_transient_for(
291 GTK_WINDOW(object))) != NULL)
292 g_object_set_qdata(parent_window, hildon_banner_timed_quark(), NULL);
294 (void) hildon_banner_clear_timeout(self);
296 if (GTK_OBJECT_CLASS(hildon_banner_parent_class)->destroy)
297 GTK_OBJECT_CLASS(hildon_banner_parent_class)->destroy(object);
300 /* Search a previous banner instance */
301 static GObject *hildon_banner_real_get_instance(GObject *window, gboolean timed)
303 g_assert(window == NULL || GTK_IS_WINDOW(window));
306 /* If we have a parent window, the previous instance is stored there */
308 return g_object_get_qdata(window, hildon_banner_timed_quark());
310 /* System notification instance is strored into global pointer */
311 return (GObject *) global_timed_banner;
314 /* Non-timed banners are normal (non-singleton) objects */
318 /* By overriding constructor we force timed banners to be
319 singletons for each window */
320 static GObject* hildon_banner_constructor (GType type,
321 guint n_construct_params, GObjectConstructParam *construct_params)
323 GObject *banner, *window = NULL;
324 gboolean timed = FALSE;
327 /* Search banner type information from parameters in order
328 to locate the possible previous banner instance. */
329 for (i = 0; i < n_construct_params; i++)
331 if (strcmp(construct_params[i].pspec->name, "parent-window") == 0)
332 window = g_value_get_object(construct_params[i].value);
333 else if (strcmp(construct_params[i].pspec->name, "is-timed") == 0)
334 timed = g_value_get_boolean(construct_params[i].value);
337 /* Try to get a previous instance if such exists */
338 banner = hildon_banner_real_get_instance(window, timed);
341 /* We have to create a new banner */
342 banner = G_OBJECT_CLASS(hildon_banner_parent_class)->constructor(
343 type, n_construct_params, construct_params);
345 /* Store the newly created singleton instance either into parent
346 window data or into global variables. */
349 g_object_set_qdata_full(G_OBJECT(window), hildon_banner_timed_quark(),
350 g_object_ref(banner), g_object_unref);
352 g_assert(global_timed_banner == NULL);
353 global_timed_banner = g_object_ref(banner);
358 /* FIXME: This is a hack! We have to manually freeze
359 notifications. This is normally done by g_object_init, but we
360 are not going to call that. g_object_newv will otherwise give
361 a critical like this:
363 GLIB CRITICAL ** GLib-GObject - g_object_notify_queue_thaw:
364 assertion `nqueue->freeze_count > 0' failed */
366 g_object_freeze_notify(banner);
369 /* We restart possible timeouts for each new timed banner request */
370 if (timed && hildon_banner_clear_timeout(HILDON_BANNER(banner)))
371 hildon_banner_ensure_timeout(HILDON_BANNER(banner));
376 /* We start the timer for timed notifications after the window appears on screen */
377 static gboolean hildon_banner_map_event(GtkWidget *widget, GdkEventAny *event)
379 gboolean result = FALSE;
381 if (GTK_WIDGET_CLASS(hildon_banner_parent_class)->map_event)
382 result = GTK_WIDGET_CLASS(hildon_banner_parent_class)->map_event(widget, event);
384 hildon_banner_ensure_timeout(HILDON_BANNER(widget));
389 static void hildon_banner_check_position(GtkWidget *widget)
394 gtk_widget_size_request(widget, &req);
400 x = gdk_screen_width() - HILDON_BANNER_WINDOW_X - req.width;
401 y = check_fullscreen_state(get_current_app_window()) ?
402 HILDON_BANNER_WINDOW_FULLSCREEN_Y : HILDON_BANNER_WINDOW_Y;
404 gtk_window_move(GTK_WINDOW(widget), x, y);
407 static void hildon_banner_realize(GtkWidget *widget)
409 /* We let the parent to init widget->window before we need it */
410 if (GTK_WIDGET_CLASS(hildon_banner_parent_class)->realize)
411 GTK_WIDGET_CLASS(hildon_banner_parent_class)->realize(widget);
413 /* We use special hint to turn the banner into information notification. */
414 gdk_window_set_type_hint(widget->window, GDK_WINDOW_TYPE_HINT_MESSAGE);
416 hildon_banner_check_position(widget);
419 static void hildon_banner_class_init(HildonBannerClass *klass)
421 GObjectClass *object_class;
422 GtkWidgetClass *widget_class;
424 object_class = G_OBJECT_CLASS(klass);
425 widget_class = GTK_WIDGET_CLASS(klass);
427 /* Append private structure to class. This is more elegant than
428 on g_new based approach */
429 g_type_class_add_private(klass, sizeof(HildonBannerPrivate));
431 /* Override virtual methods */
432 object_class->constructor = hildon_banner_constructor;
433 object_class->set_property = hildon_banner_set_property;
434 object_class->get_property = hildon_banner_get_property;
435 GTK_OBJECT_CLASS(klass)->destroy = hildon_banner_destroy;
436 widget_class->map_event = hildon_banner_map_event;
437 widget_class->realize = hildon_banner_realize;
439 /* Install properties.
440 We need construct properties for singleton purposes */
441 g_object_class_install_property(object_class, PROP_PARENT_WINDOW,
442 g_param_spec_object("parent-window",
444 "The window for which the banner will be singleton",
445 GTK_TYPE_WINDOW, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
447 g_object_class_install_property(object_class, PROP_IS_TIMED,
448 g_param_spec_boolean("is-timed",
450 "Whether or not the notification goes away automatically "
451 "after the specified time has passed",
452 FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
455 static void hildon_banner_init(HildonBanner *self)
457 HildonBannerPrivate *priv;
459 /* Make private data available through cached pointer */
460 self->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
462 HildonBannerPrivate);
464 /* Initialize the common layout inside banner */
465 self->priv->layout = gtk_hbox_new(FALSE, HILDON_MARGIN_DEFAULT);
466 priv->label = g_object_new(GTK_TYPE_LABEL, NULL);
467 gtk_label_set_line_wrap(GTK_LABEL(priv->label), TRUE);
468 gtk_container_set_border_width(GTK_CONTAINER(self->priv->layout), HILDON_MARGIN_DEFAULT);
469 gtk_container_add(GTK_CONTAINER(self), self->priv->layout);
470 gtk_box_pack_start(GTK_BOX(self->priv->layout), priv->label, TRUE, TRUE, 0);
471 gtk_window_set_accept_focus(GTK_WINDOW(self), FALSE);
474 /* Makes sure that icon/progress item contains the desired type
475 of item. If possible, tries to avoid creating a new widget but
476 reuses the existing one */
477 static void hildon_banner_ensure_child(HildonBanner *self,
478 GtkWidget *user_widget,
481 const gchar *first_property, ...)
486 g_assert(HILDON_IS_BANNER(self));
487 g_assert(user_widget == NULL || GTK_IS_WIDGET(user_widget));
489 widget = self->priv->main_item;
490 va_start(args, first_property);
492 /* Reuse existing widget if possible */
493 if (!user_widget && G_TYPE_CHECK_INSTANCE_TYPE(widget, type))
495 g_object_set_valist(G_OBJECT(widget), first_property, args);
499 /* We have to abandon old content widget */
501 gtk_container_remove(GTK_CONTAINER(self->priv->layout), widget);
503 /* Use user provided widget or create a new one */
504 self->priv->main_item = widget = user_widget ?
505 user_widget : GTK_WIDGET(g_object_new_valist(type, first_property, args));
506 gtk_box_pack_start(GTK_BOX(self->priv->layout), widget, FALSE, TRUE, 0);
509 /* We make sure that the widget exists in desired position. Different
510 banners place this child widget to different places */
511 gtk_box_reorder_child(GTK_BOX(self->priv->layout), widget, pos);
515 /* Creates a new banner instance or uses an existing one */
516 static HildonBanner *hildon_banner_get_instance_for_widget(GtkWidget *widget, gboolean timed)
520 g_return_val_if_fail(widget == NULL || GTK_IS_WIDGET(widget), NULL);
521 window = widget ? gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW) : NULL;
522 return g_object_new(HILDON_TYPE_BANNER, "parent-window", window, "is-timed", timed, NULL);
529 /* Public functions **************************************************************/
532 * hildon_banner_show_information:
533 * @widget: the #GtkWidget that wants to display banner
534 * @icon_name: the name of icon to use. Can be %NULL for default icon.
535 * @text: Text to display
537 * This function creates and displays an information banner that
538 * automatically goes away after certain time period. For each window
539 * in your application there can only be one timed banner, so if you
540 * spawn a new banner before the earlier one has timed out, the
541 * previous one will be replaced.
545 void hildon_banner_show_information(GtkWidget *widget,
546 const gchar *icon_name, const gchar *text)
548 HildonBanner *banner;
550 g_return_if_fail(widget == NULL || GTK_IS_WIDGET(widget));
551 g_return_if_fail(icon_name == NULL || icon_name[0] != 0);
552 g_return_if_fail(text != NULL);
555 banner = hildon_banner_get_instance_for_widget(widget, TRUE);
556 hildon_banner_ensure_child(banner, NULL, 0, GTK_TYPE_IMAGE,
557 "pixel-size", HILDON_ICON_PIXEL_SIZE_NOTE,
558 "icon-name", icon_name ? icon_name : HILDON_BANNER_DEFAULT_ICON,
560 hildon_banner_set_text(banner, text);
561 hildon_banner_bind_label_style(banner, NULL);
563 /* Show the banner, since caller cannot do that */
564 gtk_widget_show_all(GTK_WIDGET(banner));
568 * hildon_banner_show_information_with_markup:
569 * @widget: the #GtkWidget that wants to display banner
570 * @icon_name: the name of icon to use. Can be %NULL for default icon.
571 * @markup: a markup string to display (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
573 * This function creates and displays an information banner that
574 * automatically goes away after certain time period. For each window
575 * in your application there can only be one timed banner, so if you
576 * spawn a new banner before the earlier one has timed out, the
577 * previous one will be replaced.
581 void hildon_banner_show_information_with_markup(GtkWidget *widget,
582 const gchar *icon_name, const gchar *markup)
584 HildonBanner *banner;
586 g_return_if_fail(widget == NULL || GTK_IS_WIDGET(widget));
587 g_return_if_fail(icon_name == NULL || icon_name[0] != 0);
588 g_return_if_fail(markup != NULL);
591 banner = hildon_banner_get_instance_for_widget(widget, TRUE);
593 hildon_banner_ensure_child(banner, NULL, 0, GTK_TYPE_IMAGE,
594 "pixel-size", HILDON_ICON_PIXEL_SIZE_NOTE,
595 "icon-name", icon_name ? icon_name : HILDON_BANNER_DEFAULT_ICON,
597 hildon_banner_set_markup(banner, markup);
598 hildon_banner_bind_label_style(banner, NULL);
600 /* Show the banner, since caller cannot do that */
601 gtk_widget_show_all(GTK_WIDGET(banner));
605 * hildon_banner_show_animation:
606 * @widget: the #GtkWidget that wants to display banner
607 * @animation_name: The progress animation to use. You usually can just
608 * pass %NULL for the default animation.
609 * @text: the text to display.
611 * Shows an animated progress notification. It's recommended not to try
612 * to show more than one progress notification at a time, since
613 * they will appear on top of each other. You can use progress
614 * notifications with timed banners. In this case the banners are
615 * located so that you can somehow see both.
617 * Please note that banners are destroyed automatically once the
618 * window they are attached to is closed. The pointer that you
619 * receive with this function do not contain additional references,
620 * so it can become invalid without warning (this is true for
621 * all toplevel windows in gtk). To make sure that the banner do not disapear
622 * automatically, you can separately ref the return value (this
623 * doesn't prevent the banner from disappearing, but the object it just
624 * not finalized). In this case you have to call both #gtk_widget_destroy
625 * followed by #g_object_unref (in this order).
627 * Returns: a #HildonBanner widget. You must call #gtk_widget_destroy
628 * once you are ready with the banner.
632 GtkWidget *hildon_banner_show_animation(GtkWidget *widget,
633 const gchar *animation_name, const gchar *text)
635 HildonBanner *banner;
638 GtkWidget *image_widget;
639 const gchar *filename;
641 g_return_val_if_fail(widget == NULL || GTK_IS_WIDGET(widget), NULL);
642 g_return_val_if_fail(animation_name == NULL || animation_name[0] != 0, NULL);
643 g_return_val_if_fail(text != NULL, NULL);
645 /* Find out which animation to use */
646 theme = gtk_icon_theme_get_default();
647 info = gtk_icon_theme_lookup_icon(theme, animation_name ?
648 animation_name : HILDON_BANNER_DEFAULT_PROGRESS_ANIMATION,
649 HILDON_ICON_SIZE_NOTE, 0);
651 /* Try to load animation. One could try to optimize this
652 to avoid loading the default animation during each call */
654 filename = gtk_icon_info_get_filename(info);
655 image_widget = gtk_image_new_from_file(filename);
656 gtk_icon_info_free(info);
658 g_warning("icon theme lookup for icon failed!");
663 banner = hildon_banner_get_instance_for_widget(widget, FALSE);
664 hildon_banner_ensure_child(banner, image_widget, 0,
665 GTK_TYPE_IMAGE, NULL);
666 hildon_banner_set_text(banner, text);
667 hildon_banner_bind_label_style(banner, NULL);
670 gtk_widget_show_all(GTK_WIDGET(banner));
672 return GTK_WIDGET(banner);
676 * hildon_banner_show_progress:
677 * @widget: the #GtkWidget that wants to display banner
678 * @bar: Progressbar to use. You usually can just pass %NULL, unless
679 * you want somehow customized progress bar.
680 * @text: text to display.
682 * Shows progress notification. See #hildon_banner_show_animation
683 * for more information.
685 * Returns: a #HildonBanner widget. You must call #gtk_widget_destroy
686 * once you are ready with the banner.
690 GtkWidget *hildon_banner_show_progress(GtkWidget *widget,
691 GtkProgressBar *bar, const gchar *text)
693 HildonBanner *banner;
695 g_return_val_if_fail(widget == NULL || GTK_IS_WIDGET(widget), NULL);
696 g_return_val_if_fail(bar == NULL || GTK_IS_PROGRESS_BAR(bar), NULL);
697 g_return_val_if_fail(text != NULL, NULL);
700 banner = hildon_banner_get_instance_for_widget(widget, FALSE);
701 hildon_banner_ensure_child(banner, (GtkWidget *) bar, -1, GTK_TYPE_PROGRESS_BAR, NULL);
702 gtk_widget_set_size_request(banner->priv->main_item,
703 HILDON_BANNER_PROGRESS_WIDTH, -1);
704 hildon_banner_set_text(banner, text);
705 hildon_banner_bind_label_style(banner, NULL);
707 /* Show the banner */
708 gtk_widget_show_all(GTK_WIDGET(banner));
710 return GTK_WIDGET(banner);
714 * hildon_banner_set_text:
715 * @self: a #HildonBanner widget
716 * @text: a new text to display in banner
718 * Sets the text that is displayed in the banner.
722 void hildon_banner_set_text(HildonBanner *self, const gchar *text)
727 g_return_if_fail(HILDON_IS_BANNER(self));
729 label = GTK_LABEL(self->priv->label);
730 gtk_label_set_text(label, text);
732 /* A re-used window may be too large, shrink to the requisition size */
733 gtk_widget_size_request(GTK_WIDGET(self), &req);
736 gtk_window_resize(GTK_WINDOW(self), req.width, req.height);
739 hildon_banner_check_position(GTK_WIDGET(self));
743 * hildon_banner_set_markup:
744 * @self: a #HildonBanner widget
745 * @markup: a new text with Pango markup to display in the banner
747 * Sets the text with markup that is displayed in the banner.
751 void hildon_banner_set_markup(HildonBanner *self, const gchar *markup)
756 g_return_if_fail(HILDON_IS_BANNER(self));
758 label = GTK_LABEL(self->priv->label);
759 gtk_label_set_markup(label, markup);
761 /* A re-used window may be too large, shrink to the requisition size */
762 gtk_widget_size_request(GTK_WIDGET(self), &req);
765 gtk_window_resize(GTK_WINDOW(self), req.width, req.height);
768 hildon_banner_check_position(GTK_WIDGET(self));
772 * hildon_banner_set_fraction:
773 * @self: a #HildonBanner widget
774 * @fraction: #gdouble
776 * The fraction is the completion of progressbar,
777 * the scale is from 0.0 to 1.0.
778 * Sets the amount of fraction the progressbar has.
782 void hildon_banner_set_fraction(HildonBanner *self, gdouble fraction)
784 g_return_if_fail(HILDON_IS_BANNER(self));
785 g_return_if_fail(GTK_IS_PROGRESS_BAR(self->priv->main_item));
786 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(self->priv->main_item), fraction);
794 * Deprecated: really, do NOT use.
796 void _hildon_gtk_label_set_text_n_lines(GtkLabel *label, const gchar *text, gint max_lines)
798 /* Forces the wrapping of text into several lines and ellipsizes the rest.
799 Similar to combination of gtk_label_set_wrap and pango ellipzation.
800 We cannot just use those directly, since ellipzation always wins wrapping.
802 This means that we have to:
803 * First wrap the text
804 * Insert forced linebreaks into text
805 * Truncate the result
807 NOTE! This will not work with pango markup!
809 FIXME: luc: DO NOT TRUNCATE the text. Use as many lines as needed.
810 Lenth of the text is under applications' responsibility.
811 Widget does not have to enforce this.
814 PangoLayoutLine *line;
816 GString *wrapped_text;
820 g_return_if_fail(GTK_IS_LABEL(label));
821 g_return_if_fail(max_lines >= 1);
823 /* Setup the label to contain the new data */
824 gtk_label_set_text(label, text);
825 gtk_label_set_line_wrap(label, TRUE);
826 gtk_label_set_ellipsize(label, PANGO_ELLIPSIZE_NONE);
828 /* We really want to recalculate the size, not use some old values */
829 gtk_widget_size_request(GTK_WIDGET(label), &req);
830 layout = gtk_label_get_layout(label);
831 lines = pango_layout_get_line_count(layout);
833 /* Now collect the wrapped text. */
834 wrapped_text = g_string_new(NULL);
836 for (i = 0; i < lines; i++)
838 /* Append the next line into wrapping buffer, but
839 avoid adding extra whitespaces at the end, since those
840 can cause other lines to be ellipsized as well. */
841 line = pango_layout_get_line(layout, i);
842 line_data = g_strndup(pango_layout_get_text(layout) + line->start_index,
844 g_strchomp(line_data);
845 g_string_append(wrapped_text, line_data);
847 /* Append forced linebreaks, until we have the desired
848 amount of lines. After that we put the rest to the
849 last line to make ellipzation to happen */
852 if (i < max_lines - 1)
853 g_string_append_c(wrapped_text, '\n');
855 g_string_append_c(wrapped_text, ' ');
861 /* Now update the label to use wrapped text. Use builtin
862 ellipzation as well. */
863 gtk_widget_set_size_request(GTK_WIDGET(label), req.width, -1);
864 gtk_label_set_text(label, wrapped_text->str);
865 gtk_label_set_ellipsize(label, PANGO_ELLIPSIZE_END);
866 gtk_label_set_line_wrap(label, FALSE);
868 g_string_free(wrapped_text, TRUE);