*/
/**
- * SECTION:hildon-banner
- * @short_description: A widget used to display timed notifications.
+ * SECTION:hildon-banner
+ * @short_description: A widget used to display timed notifications.
*
* #HildonBanner is a small, pop-up window that can be used to display
* a short, timed notification or information to the user. It can
* hildon_gtk_window_set_progress_indicator() for the preferred way of
* showing progress notifications in Hildon 2.2.
*
- * Information banners dissapear automatically after a certain
+ * Information banners are automatically destroyed after a certain
* period. This is stored in the #HildonBanner:timeout property (in
* miliseconds), and can be changed using hildon_banner_set_timeout().
*
* Note that #HildonBanner<!-- -->s should only be used to display
* non-critical pieces of information.
+ *
+ * <example>
+ * <title>Using the HildonBanner widget</title>
+ * <programlisting>
+ * void show_info_banner (GtkWidget *parent)
+ * {
+ * GtkWidget *banner;
+ * <!-- -->
+ * banner = hildon_banner_show_information (widget, NULL, "Information banner");
+ * hildon_banner_set_timeout (HILDON_BANNER (banner), 9000);
+ * <!-- -->
+ * return;
+ * }
+ * </programlisting>
+ * </example>
*/
#ifdef HAVE_CONFIG_H
#undef HILDON_DISABLE_DEPRECATED
#include "hildon-banner.h"
-#include "hildon-banner-private.h"
+#include "hildon-private.h"
#include "hildon-defines.h"
#include "hildon-gtk.h"
-/* position relative to the screen */
-
-#define HILDON_BANNER_WINDOW_X 0
-
-#define HILDON_BANNER_WINDOW_Y HILDON_WINDOW_TITLEBAR_HEIGHT
-
/* max widths */
-#define HILDON_BANNER_PROGRESS_WIDTH 104
-
#define HILDON_BANNER_LABEL_MAX_TIMED \
(gdk_screen_width() - ((HILDON_MARGIN_TRIPLE) * 2))
hildon_banner_timed_quark (void);
static void
-hildon_banner_bind_style (HildonBanner *self,
- const gchar *name);
+hildon_banner_bind_style (HildonBanner *self);
static gboolean
hildon_banner_timeout (gpointer data);
static gboolean
hildon_banner_map_event (GtkWidget *widget,
GdkEventAny *event);
-static void
-hildon_banner_reset_wrap_state (HildonBanner *banner);
static void
force_to_wrap_truncated (HildonBanner *banner);
static void
-hildon_banner_check_position (GtkWidget *widget);
-
-static void
hildon_banner_realize (GtkWidget *widget);
static void
const gchar *text,
gboolean override_dnd);
-
G_DEFINE_TYPE (HildonBanner, hildon_banner, GTK_TYPE_WINDOW)
+typedef struct _HildonBannerPrivate HildonBannerPrivate;
+
+#define HILDON_BANNER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
+ HILDON_TYPE_BANNER, HildonBannerPrivate));
+
+struct _HildonBannerPrivate
+{
+ GtkWidget *main_item;
+ GtkWidget *alignment;
+ GtkWidget *label;
+ GtkWidget *layout;
+ GtkWindow *parent;
+ const gchar *name_suffix;
+ guint timeout;
+ guint timeout_id;
+ guint is_timed : 1;
+ guint require_override_dnd : 1;
+ guint overrides_dnd : 1;
+};
+
static GQuark
hildon_banner_timed_quark (void)
{
/* Set the widget and label name to make the correct rc-style attached into them */
static void
-hildon_banner_bind_style (HildonBanner *self,
- const gchar *name_sufix)
+hildon_banner_bind_style (HildonBanner *self)
{
HildonBannerPrivate *priv = HILDON_BANNER_GET_PRIVATE (self);
+ GdkScreen *screen = gtk_widget_get_screen (GTK_WIDGET (self));
+ gboolean portrait = gdk_screen_get_width (screen) < gdk_screen_get_height (screen);
+ const gchar *portrait_suffix = portrait ? "-portrait" : NULL;
gchar *name;
g_assert (priv);
- name = g_strconcat ("HildonBannerLabel-", name_sufix, NULL);
+ name = g_strconcat ("HildonBannerLabel-", priv->name_suffix, NULL);
gtk_widget_set_name (priv->label, name);
g_free (name);
- name = g_strconcat ("HildonBanner-", name_sufix, NULL);
+ name = g_strconcat ("HildonBanner-", priv->name_suffix, portrait_suffix, NULL);
gtk_widget_set_name (GTK_WIDGET (self), name);
g_free (name);
}
return result;
}
+static void
+hildon_banner_size_request (GtkWidget *self,
+ GtkRequisition *req)
+{
+ GTK_WIDGET_CLASS (hildon_banner_parent_class)->size_request (self, req);
+ req->width = gdk_screen_get_width (gtk_widget_get_screen (self));
+}
+
static gboolean
hildon_banner_timeout (gpointer data)
{
GtkWidget *widget;
gboolean continue_timeout = FALSE;
- GDK_THREADS_ENTER ();
-
g_assert (HILDON_IS_BANNER (data));
widget = GTK_WIDGET (data);
g_object_unref (widget);
- GDK_THREADS_LEAVE ();
-
return continue_timeout;
}
g_assert (priv);
if (priv->timeout_id == 0 && priv->is_timed && priv->timeout > 0)
- priv->timeout_id = g_timeout_add (priv->timeout,
+ priv->timeout_id = gdk_threads_add_timeout (priv->timeout,
hildon_banner_timeout, self);
}
assertion `nqueue->freeze_count > 0' failed */
g_object_freeze_notify (banner);
- hildon_banner_reset_wrap_state (HILDON_BANNER (banner));
}
/* We restart possible timeouts for each new timed banner request */
* being closed by other non-temporary windows */
gtk_window_set_is_temporary (GTK_WINDOW (widget), FALSE);
- hildon_banner_check_position (widget);
+ gtk_window_move (GTK_WINDOW (widget), 0, HILDON_WINDOW_TITLEBAR_HEIGHT);
}
}
#endif
}
static void
-hildon_banner_reset_wrap_state (HildonBanner *banner)
+banner_do_set_text (HildonBanner *banner,
+ const gchar *text,
+ gboolean is_markup)
{
- PangoLayout *layout;
HildonBannerPrivate *priv;
+ GtkRequisition req;
priv = HILDON_BANNER_GET_PRIVATE (banner);
- g_assert (priv);
-
- layout = gtk_label_get_layout (GTK_LABEL (priv->label));
-
- pango_layout_set_width (layout, -1);
- priv->has_been_wrapped = FALSE;
- priv->has_been_truncated = FALSE;
+ if (is_markup) {
+ gtk_label_set_markup (GTK_LABEL (priv->label), text);
+ } else {
+ gtk_label_set_text (GTK_LABEL (priv->label), text);
+ }
gtk_widget_set_size_request (priv->label, -1, -1);
- gtk_widget_set_size_request (GTK_WIDGET (banner), -1, -1);
+ gtk_widget_size_request (priv->label, &req);
+
+ force_to_wrap_truncated (banner);
}
/* force to wrap truncated label by setting explicit size request
{
GtkLabel *label;
PangoLayout *layout;
- int width_text, width_max;
+ int width_max;
int width = -1;
int height = -1;
PangoRectangle logical;
layout = gtk_label_get_layout (label);
pango_layout_get_extents (layout, NULL, &logical);
- width_text = PANGO_PIXELS (logical.width);
+ width = PANGO_PIXELS (logical.width);
width_max = priv->is_timed ? HILDON_BANNER_LABEL_MAX_TIMED
: HILDON_BANNER_LABEL_MAX_PROGRESS;
/* If the width of the label is going to exceed the maximum allowed
* width, enforce the maximum allowed width now.
*/
- if (priv->has_been_wrapped
- || width_text >= width_max
- || pango_layout_is_wrapped (layout)) {
- /* Force wrapping by setting the maximum size */
+ if (width >= width_max || pango_layout_is_wrapped (layout)) {
width = width_max;
-
- priv->has_been_wrapped = TRUE;
}
/* Make the label update its layout; and update our layout pointer
/* If the layout has now been wrapped and exceeds 3 lines, we truncate
* the rest of the label according to spec.
*/
- if (priv->has_been_truncated
- || (pango_layout_is_wrapped (layout)
- && pango_layout_get_line_count (layout) > 3)) {
+ if (pango_layout_is_wrapped (layout) && pango_layout_get_line_count (layout) > 3) {
int lines;
pango_layout_get_extents (layout, NULL, &logical);
* FIXME: Pango >= 1.20 has pango_layout_set_height().
*/
height = (PANGO_PIXELS (logical.height) * 3) / lines + 1;
- priv->has_been_truncated = TRUE;
}
/* Set the new width/height if applicable */
gtk_widget_set_size_request (GTK_WIDGET (label), width, height);
}
-
static void
-hildon_banner_check_position (GtkWidget *widget)
-{
- gint x, y;
- GtkRequisition req;
-
- gtk_widget_set_size_request (widget, gdk_screen_width (), -1);
-
- force_to_wrap_truncated (HILDON_BANNER(widget)); /* see N#27000 and G#329646 */
+screen_size_changed (GdkScreen *screen,
+ GtkWindow *banner)
- gtk_widget_size_request (widget, &req);
-
- if (req.width == 0)
- {
- return;
- }
-
- x = HILDON_BANNER_WINDOW_X;
-
- y = HILDON_BANNER_WINDOW_Y;
-
- gtk_window_move (GTK_WINDOW (widget), x, y);
+{
+ hildon_banner_bind_style (HILDON_BANNER (banner));
+ gtk_window_reshow_with_initial_size (banner);
+ force_to_wrap_truncated (HILDON_BANNER (banner));
}
static void
hildon_banner_realize (GtkWidget *widget)
{
GdkWindow *gdkwin;
+ GdkScreen *screen;
GdkAtom atom;
guint32 portrait = 1;
const gchar *notification_type = "_HILDON_NOTIFICATION_TYPE_BANNER";
gdk_window_set_type_hint (widget->window, GDK_WINDOW_TYPE_HINT_NOTIFICATION);
gtk_window_set_transient_for (GTK_WINDOW (widget), (GtkWindow *) priv->parent);
- hildon_banner_check_position (widget);
-
gdkwin = widget->window;
/* Set the _HILDON_NOTIFICATION_TYPE property so Matchbox places the window correctly */
hildon_banner_set_override_flag (HILDON_BANNER (widget));
priv->overrides_dnd = TRUE;
}
+
+ screen = gtk_widget_get_screen (widget);
+ g_signal_connect (screen, "size-changed", G_CALLBACK (screen_size_changed), widget);
+}
+
+static void
+hildon_banner_unrealize (GtkWidget *widget)
+{
+ GdkScreen *screen = gtk_widget_get_screen (widget);
+ g_signal_handlers_disconnect_by_func (screen, G_CALLBACK (screen_size_changed), widget);
+
+ GTK_WIDGET_CLASS (hildon_banner_parent_class)->unrealize (widget);
}
static void
object_class->set_property = hildon_banner_set_property;
object_class->get_property = hildon_banner_get_property;
GTK_OBJECT_CLASS (klass)->destroy = hildon_banner_destroy;
+ widget_class->size_request = hildon_banner_size_request;
widget_class->map_event = hildon_banner_map_event;
widget_class->realize = hildon_banner_realize;
+ widget_class->unrealize = hildon_banner_unrealize;
widget_class->button_press_event = hildon_banner_button_press_event;
#if defined(MAEMO_GTK)
widget_class->map = hildon_banner_map;
/**
* HildonBanner:timeout:
*
- * The time before making the banner banner go away. This needs
+ * The time before destroying the banner. This needs
* to be adjusted before the banner is mapped to the screen.
*
*/
priv->parent = NULL;
priv->overrides_dnd = FALSE;
priv->require_override_dnd = FALSE;
+ priv->name_suffix = NULL;
/* Initialize the common layout inside banner */
+ priv->alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
priv->layout = gtk_hbox_new (FALSE, HILDON_MARGIN_DEFAULT);
priv->label = g_object_new (GTK_TYPE_LABEL, NULL);
gtk_label_set_line_wrap (GTK_LABEL (priv->label), TRUE);
gtk_label_set_line_wrap_mode (GTK_LABEL (priv->label), PANGO_WRAP_WORD_CHAR);
+ gtk_label_set_justify (GTK_LABEL (priv->label), GTK_JUSTIFY_CENTER);
gtk_container_set_border_width (GTK_CONTAINER (priv->layout), HILDON_MARGIN_DEFAULT);
- gtk_container_add (GTK_CONTAINER (self), priv->layout);
- gtk_box_pack_start (GTK_BOX (priv->layout), priv->label, TRUE, TRUE, 0);
+ gtk_container_add (GTK_CONTAINER (self), priv->alignment);
+ gtk_container_add (GTK_CONTAINER (priv->alignment), priv->layout);
+ gtk_box_pack_start (GTK_BOX (priv->layout), priv->label, FALSE, FALSE, 0);
gtk_window_set_accept_focus (GTK_WINDOW (self), FALSE);
- hildon_banner_reset_wrap_state (self);
-
gtk_widget_add_events (GTK_WIDGET (self), GDK_BUTTON_PRESS_MASK);
}
/* Use user provided widget or create a new one */
priv->main_item = widget = user_widget ?
user_widget : GTK_WIDGET (g_object_new_valist(type, first_property, args));
- gtk_box_pack_start (GTK_BOX (priv->layout), widget, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (priv->layout), widget, FALSE, FALSE, 0);
}
/* We make sure that the widget exists in desired position. Different
return g_object_new (HILDON_TYPE_BANNER, "parent-window", window, "is-timed", timed, NULL);
}
-static GtkWidget *
-hildon_banner_create_animation (void)
-{
- GtkWidget *image;
- GdkPixbufSimpleAnim *anim;
- GdkPixbuf *frame;
- GtkIconTheme *theme;
- GError *error = NULL;
- gchar *icon_name;
- gint i;
-
- anim = gdk_pixbuf_simple_anim_new (HILDON_ICON_PIXEL_SIZE_STYLUS,
- HILDON_ICON_PIXEL_SIZE_STYLUS,
- HILDON_BANNER_ANIMATION_FRAMERATE);
- gdk_pixbuf_simple_anim_set_loop (anim, TRUE);
- theme = gtk_icon_theme_get_default ();
-
- for (i = 1; i <= HILDON_BANNER_ANIMATION_NFRAMES; i++) {
- icon_name = g_strdup_printf (HILDON_BANNER_ANIMATION_TMPL, i);
- frame = gtk_icon_theme_load_icon (theme, icon_name, HILDON_ICON_PIXEL_SIZE_STYLUS,
- 0, &error);
-
- if (error) {
- g_warning ("Icon theme lookup for icon `%s' failed: %s",
- icon_name, error->message);
- g_error_free (error);
- error = NULL;
- } else {
- gdk_pixbuf_simple_anim_add_frame (anim, frame);
- }
-
- g_object_unref (frame);
- g_free (icon_name);
- }
-
- image = gtk_image_new_from_animation (GDK_PIXBUF_ANIMATION (anim));
- g_object_unref (anim);
-
- return image;
-}
-
/**
* hildon_banner_show_information:
* @widget: the #GtkWidget that is the owner of the banner
* any value that you pass will be ignored
* @text: Text to display
*
- * This function creates and displays an information banner that
- * automatically goes away after certain time period. For each window
- * in your application there can only be one timed banner, so if you
- * spawn a new banner before the earlier one has timed out, the
- * previous one will be replaced.
+ * This function creates and displays an information banner that is
+ * automatically destroyed after a certain time period (see
+ * hildon_banner_set_timeout()). For each window in your application
+ * there can only be one timed banner, so if you spawn a new banner
+ * before the earlier one has timed out, the previous one will be
+ * replaced.
*
* Returns: The newly created banner
*
* @widget: the #GtkWidget that is the owner of the banner
* @text: Text to display
*
- * Equivalent to hildon_banner_show_information() but it overrides the do not
- * disturb flag, in the special cases that could be needed. It is required
- * because this method calls internally gtk_widget_show before returns the banner,
- * but the do not disturb flag is checked on the mapping of the widget
- *
+ * Equivalent to hildon_banner_show_information(), but overriding the
+ * "do not disturb" flag.
*
* Returns: The newly created banner
*
1);
}
+static void
+reshow_banner (HildonBanner *banner)
+{
+ if (GTK_WIDGET_VISIBLE (banner)) {
+ gint width = gdk_screen_get_width (gtk_widget_get_screen (GTK_WIDGET (banner)));
+ gtk_window_resize (GTK_WINDOW (banner), width, 1);
+ }
+ force_to_wrap_truncated (banner);
+ gtk_widget_show_all (GTK_WIDGET (banner));
+}
static GtkWidget*
hildon_banner_real_show_information (GtkWidget *widget,
banner = hildon_banner_get_instance_for_widget (widget, TRUE);
priv = HILDON_BANNER_GET_PRIVATE (banner);
- hildon_banner_set_text (banner, text);
- hildon_banner_bind_style (banner, "information");
+ priv->name_suffix = "information";
+ banner_do_set_text (banner, text, FALSE);
+ hildon_banner_bind_style (banner);
if (override_dnd) {
/* so on the realize it will set the property */
}
/* Show the banner, since caller cannot do that */
- gtk_widget_show_all (GTK_WIDGET (banner));
+ reshow_banner (banner);
return GTK_WIDGET (banner);
}
* @format: a printf-like format string
* @Varargs: arguments for the format string
*
- * A helper function for #hildon_banner_show_information with
+ * A helper function for hildon_banner_show_information() with
* string formatting.
*
* Returns: the newly created banner
* any value that you pass will be ignored
* @markup: a markup string to display (see <link linkend="PangoMarkupFormat">Pango markup format</link>)
*
- * This function creates and displays an information banner that
- * automatically goes away after certain time period. For each window
- * in your application there can only be one timed banner, so if you
- * spawn a new banner before the earlier one has timed out, the
- * previous one will be replaced.
+ * This function creates and displays an information banner that is
+ * automatically destroyed after certain time period (see
+ * hildon_banner_set_timeout()). For each window in your application
+ * there can only be one timed banner, so if you spawn a new banner
+ * before the earlier one has timed out, the previous one will be
+ * replaced.
*
* Returns: the newly created banner
*
const gchar *markup)
{
HildonBanner *banner;
+ HildonBannerPrivate *priv;
g_return_val_if_fail (icon_name == NULL || icon_name[0] != 0, NULL);
g_return_val_if_fail (markup != NULL, NULL);
/* Prepare banner */
banner = hildon_banner_get_instance_for_widget (widget, TRUE);
+ priv = HILDON_BANNER_GET_PRIVATE (banner);
- hildon_banner_set_markup (banner, markup);
- hildon_banner_bind_style (banner, "information");
+ priv->name_suffix = "information";
+ banner_do_set_text (banner, markup, TRUE);
+ hildon_banner_bind_style (banner);
/* Show the banner, since caller cannot do that */
- gtk_widget_show_all (GTK_WIDGET (banner));
+ reshow_banner (banner);
return (GtkWidget *) banner;
}
* notifications with timed banners. In this case the banners are
* located so that you can somehow see both.
*
- * Please note that banners are destroyed automatically once the
+ * Unlike information banners (created with
+ * hildon_banner_show_information()), animation banners are not
+ * destroyed automatically using a timeout. You have to destroy them
+ * yourself.
+ *
+ * Please note also that these banners are destroyed automatically if the
* window they are attached to is closed. The pointer that you receive
* with this function does not contain additional references, so it
* can become invalid without warning (this is true for all toplevel
* windows in gtk). To make sure that the banner does not disappear
* automatically, you can separately ref the return value (this
* doesn't prevent the banner from disappearing, just the object from
- * being finalized). In this case you have to call both
- * gtk_widget_destroy() followed by g_object_unref() (in this order).
+ * being finalized). In this case you have to call
+ * gtk_widget_destroy() followed by g_object_unref().
*
* Returns: a #HildonBanner widget. You must call gtk_widget_destroy()
* once you are done with the banner.
{
HildonBanner *banner;
GtkWidget *image_widget;
+ HildonBannerPrivate *priv;
g_return_val_if_fail (text != NULL, NULL);
- image_widget = hildon_banner_create_animation ();
+ image_widget = hildon_private_create_animation (
+ HILDON_BANNER_ANIMATION_FRAMERATE,
+ HILDON_BANNER_ANIMATION_TMPL,
+ HILDON_BANNER_ANIMATION_NFRAMES);
/* Prepare banner */
banner = hildon_banner_get_instance_for_widget (widget, FALSE);
hildon_banner_ensure_child (banner, image_widget, 0,
GTK_TYPE_IMAGE, "yalign", 0.0, NULL);
- hildon_banner_set_text (banner, text);
- hildon_banner_bind_style (banner, "animation");
+ priv = HILDON_BANNER_GET_PRIVATE (banner);
+ priv->name_suffix = "animation";
+ banner_do_set_text (banner, text, FALSE);
+ hildon_banner_bind_style (banner);
/* And show it */
- gtk_widget_show_all (GTK_WIDGET (banner));
+ reshow_banner (banner);
return (GtkWidget *) banner;
}
* any value that you pass will be ignored
* @text: text to display.
*
- * Shows progress notification. See #hildon_banner_show_animation
+ * Shows progress notification. See hildon_banner_show_animation()
* for more information.
*
* Returns: a #HildonBanner widget. You must call #gtk_widget_destroy
priv = HILDON_BANNER_GET_PRIVATE (banner);
g_assert (priv);
- hildon_banner_set_text (banner, text);
- hildon_banner_bind_style (banner, "progress");
+ priv->name_suffix = "progress";
+ banner_do_set_text (banner, text, FALSE);
+ hildon_banner_bind_style (banner);
if (priv->parent)
hildon_gtk_window_set_progress_indicator (priv->parent, 1);
/* Show the banner */
- gtk_widget_show_all (GTK_WIDGET (banner));
+ reshow_banner (banner);
return GTK_WIDGET (banner);
}
hildon_banner_set_text (HildonBanner *self,
const gchar *text)
{
- GtkLabel *label;
- HildonBannerPrivate *priv;
- const gchar *existing_text;
-
g_return_if_fail (HILDON_IS_BANNER (self));
- priv = HILDON_BANNER_GET_PRIVATE (self);
- g_assert (priv);
-
- label = GTK_LABEL (priv->label);
- existing_text = gtk_label_get_text (label);
+ banner_do_set_text (self, text, FALSE);
- if (existing_text != NULL &&
- text != NULL &&
- strcmp (existing_text, text) != 0) {
- gtk_label_set_text (label, text);
- hildon_banner_reset_wrap_state (self);
- }
-
- hildon_banner_check_position (GTK_WIDGET (self));
+ if (GTK_WIDGET_VISIBLE (self))
+ reshow_banner (self);
}
/**
hildon_banner_set_markup (HildonBanner *self,
const gchar *markup)
{
- GtkLabel *label;
- HildonBannerPrivate *priv;
-
g_return_if_fail (HILDON_IS_BANNER (self));
- priv = HILDON_BANNER_GET_PRIVATE (self);
- g_assert (priv);
-
- label = GTK_LABEL (priv->label);
- gtk_label_set_markup (label, markup);
-
- hildon_banner_reset_wrap_state (self);
+ banner_do_set_text (self, markup, TRUE);
- hildon_banner_check_position (GTK_WIDGET(self));
+ if (GTK_WIDGET_VISIBLE (self))
+ reshow_banner (self);
}
/**
* @timeout: timeout to set in miliseconds.
*
* Sets the timeout on the banner. After the given amount of miliseconds
- * has elapsed the banner will go away. Note that settings this only makes
- * sense on the banners that are timed and that have not been yet displayed
+ * has elapsed the banner will be destroyed. Setting this only makes
+ * sense on banners that are timed and that have not been yet displayed
* on the screen.
*
* Note that this method only has effect if @self is an information