2008-11-25 Alberto Garcia <agarcia@igalia.com>
+ * doc/hildon-docs.sgml
+ * doc/hildon.types
+ * src/Makefile.am
+ * src/hildon.h
+ * src/hildon-window-stack-private.h
+ * src/hildon-window-stack.h
+ * src/hildon-window-stack.c:
+ New HildonWindowStack object, that adds support for multiple
+ stacks of windows per process.
+
+ * src/hildon-stackable-window-private.h
+ * src/hildon-stackable-window.h
+ * src/hildon-stackable-window.c (hildon_stackable_window_set_stack)
+ (hildon_stackable_window_get_stack, hildon_stackable_window_map)
+ (hildon_stackable_window_show, hildon_stackable_window_hide)
+ (hildon_stackable_window_class_init)
+ (hildon_stackable_window_init):
+ Use HildonWindowStack for stack management.
+
+ * src/hildon-program.c (hildon_program_pop_window_stack)
+ (hildon_program_peek_window_stack)
+ (hildon_program_go_to_root_window):
+ Add a fallback implementation to the deprecated functions using
+ HildonWindowStack.
+
+ * examples/hildon-stackable-window-example.c:
+ Use the new HildonWindowStack API.
+
+2008-11-25 Alberto Garcia <agarcia@igalia.com>
+
* src/hildon-stackable-window-private.h
* src/hildon-stackable-window.c (hildon_stackable_window_show)
(hildon_stackable_window_hide, hildon_stackable_window_init):
<xi:include href="xml/hildon-helper.xml"/>
<xi:include href="xml/hildon-defines.xml"/>
<xi:include href="xml/hildon-bread-crumb.xml"/>
+ <xi:include href="xml/hildon-window-stack.xml"/>
</chapter>
<index>
#include <src/hildon-dialog.h>
#include <src/hildon-pannable-area.h>
#include <src/hildon-stackable-window.h>
+#include <src/hildon-window-stack.h>
#include <src/hildon-app-menu.h>
#include <src/hildon-entry.h>
#include <src/hildon-text-view.h>
hildon_dialog_get_type
hildon_pannable_area_get_type
hildon_stackable_window_get_type
+hildon_window_stack_get_type
hildon_app_menu_get_type
hildon_entry_get_type
hildon_text_view_get_type
*
* Copyright (C) 2008 Nokia Corporation, all rights reserved.
*
- * Author: Karl Lattimer <karl.lattimer@nokia.com>
- *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; version 2.1 of
*
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <glib.h>
-#include <gtk/gtk.h>
#include "hildon.h"
-#include <X11/X.h>
-#include <X11/Xlib.h>
-#include <X11/Xatom.h>
+static gint global_stack_count = 1;
+
+static void
+add_window (GtkWidget *button,
+ HildonStackableWindow *parent);
static void
-add_window (GtkWidget* w);
+push_windows (GtkWidget *button,
+ GtkSpinButton *spin);
+
+static void
+pop_windows (GtkWidget *button,
+ GtkSpinButton *spin);
static GtkWidget*
-new_window (gboolean ismain)
+new_window (HildonStackableWindow *parent)
{
- GtkWidget *window, *hbbox, *add;
- static int count = 0;
- gchar* title;
+ GtkWidget *window, *hbbox, *vbox, *label, *add, *new;
+ GtkWidget *spin1hbox, *spin1label1, *spin1, *spin1label2, *pushbtn, *align1;
+ GtkWidget *spin2hbox, *spin2label1, *spin2, *spin2label2, *popbtn, *align2;
+ gint stack_number, win_number;
+ gchar *text;
window = hildon_stackable_window_new ();
- if (count == 0)
- title = g_strdup ("main window");
- else
- title = g_strdup_printf ("win%d", count);
+ if (parent) {
+ stack_number = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (parent), "stack-number"));
+ win_number = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (parent), "win-number")) + 1;
+ } else {
+ stack_number = global_stack_count++;
+ win_number = 1;
+ }
+ g_object_set_data (G_OBJECT (window), "stack-number", GINT_TO_POINTER (stack_number));
+ g_object_set_data (G_OBJECT (window), "win-number", GINT_TO_POINTER (win_number));
- gtk_window_set_title (GTK_WINDOW (window), title);
- g_free (title);
+ /* Window title */
+ text = g_strdup_printf ("Stack number %d - window %d", stack_number, win_number);
+ gtk_window_set_title (GTK_WINDOW (window), text);
+ g_free (text);
- count++;
-
- gtk_container_set_border_width (GTK_CONTAINER (window), 6);
+ /* Main label */
+ text = g_strdup_printf ("Stack number %d\nWindow number %d", stack_number, win_number);
+ label = gtk_label_new (text);
+ g_free (text);
hbbox = gtk_hbutton_box_new ();
- gtk_container_add (GTK_CONTAINER (window), hbbox);
- add = gtk_button_new_with_label ("Add a window");
+ /* Button to push a window to the current stack */
+ add = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
+ gtk_button_set_label (GTK_BUTTON (add), "Add a window to this stack");
gtk_box_pack_start (GTK_BOX (hbbox), add, FALSE, FALSE, 0);
+ g_signal_connect (G_OBJECT (add), "clicked", G_CALLBACK (add_window), window);
+
+ /* Button to create a new stack */
+ new = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
+ gtk_button_set_label (GTK_BUTTON (new), "Add a window to a new stack");
+ gtk_box_pack_start (GTK_BOX (hbbox), new, FALSE, FALSE, 0);
+ g_signal_connect (G_OBJECT (new), "clicked", G_CALLBACK (add_window), NULL);
+
+ /* Spinbox and button to push many windows */
+ spin1hbox = gtk_hbox_new (FALSE, 0);
+ spin1label1 = gtk_label_new ("Push");
+ spin1 = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (2, 2, 5, 1, 1, 1)), 1, 0);
+ gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spin1), TRUE);
+ spin1label2 = gtk_label_new ("windows");
+ pushbtn = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
+ gtk_button_set_label (GTK_BUTTON (pushbtn), "Push windows");
+ gtk_box_pack_start (GTK_BOX (spin1hbox), spin1label1, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (spin1hbox), spin1, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (spin1hbox), spin1label2, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (spin1hbox), pushbtn, FALSE, FALSE, 10);
+ align1 = gtk_alignment_new (0.5, 0.5, 0, 0);
+ gtk_container_add (GTK_CONTAINER (align1), spin1hbox);
+ g_signal_connect (G_OBJECT (pushbtn), "clicked", G_CALLBACK (push_windows), spin1);
+
+ /* Spinbox and button to pop many windows */
+ spin2hbox = gtk_hbox_new (FALSE, 0);
+ spin2label1 = gtk_label_new ("Pop");
+ spin2 = gtk_spin_button_new (GTK_ADJUSTMENT (gtk_adjustment_new (2, 2, 5, 1, 1, 1)), 1, 0);
+ gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spin2), TRUE);
+ spin2label2 = gtk_label_new ("windows");
+ popbtn = hildon_gtk_button_new (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH);
+ gtk_button_set_label (GTK_BUTTON (popbtn), "Pop windows");
+ gtk_box_pack_start (GTK_BOX (spin2hbox), spin2label1, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (spin2hbox), spin2, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (spin2hbox), spin2label2, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (spin2hbox), popbtn, FALSE, FALSE, 10);
+ align2 = gtk_alignment_new (0.5, 0.5, 0, 0);
+ gtk_container_add (GTK_CONTAINER (align2), spin2hbox);
+ g_signal_connect (G_OBJECT (popbtn), "clicked", G_CALLBACK (pop_windows), spin2);
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), hbbox, FALSE, FALSE, 10);
+ gtk_box_pack_start (GTK_BOX (vbox), align1, FALSE, FALSE, 10);
+ gtk_box_pack_start (GTK_BOX (vbox), align2, FALSE, FALSE, 10);
- g_signal_connect (G_OBJECT (add), "clicked", G_CALLBACK (add_window), NULL);
+ gtk_container_set_border_width (GTK_CONTAINER (window), 6);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+ gtk_widget_show_all (vbox);
- if (!ismain)
- {
- GtkWidget *detach, *back;
- detach = GTK_WIDGET (gtk_button_new_with_label ("Destroy"));
- gtk_box_pack_end (GTK_BOX (hbbox), detach, FALSE, FALSE, 0);
+ return window;
+}
- g_signal_connect_swapped (G_OBJECT (detach), "clicked",
- G_CALLBACK (gtk_widget_destroy),
- HILDON_STACKABLE_WINDOW (window));
+static void
+add_window (GtkWidget *button,
+ HildonStackableWindow *parent)
+{
+ HildonWindowStack *stack = NULL;
+ GtkWidget *window;
+
+ if (parent) {
+ stack = hildon_stackable_window_get_stack (parent);
+ } else {
+ stack = hildon_window_stack_new ();
+ }
- back = GTK_WIDGET (gtk_button_new_with_label ("Back to root"));
- gtk_box_pack_end (GTK_BOX (hbbox), back, FALSE, FALSE, 0);
+ window = new_window (parent);
- g_signal_connect_swapped (G_OBJECT (back), "clicked",
- G_CALLBACK (hildon_program_go_to_root_window),
- hildon_program_get_instance ());
+ if (!stack) {
+ stack = hildon_window_stack_get_default ();
}
+ hildon_window_stack_push_1 (stack, HILDON_STACKABLE_WINDOW (window));
- return window;
+ return;
+}
+
+static void
+push_windows (GtkWidget *button,
+ GtkSpinButton *spin)
+{
+ GList *l = NULL;
+ HildonWindowStack *stack = NULL;
+ HildonStackableWindow *parent;
+ gint nwindows = gtk_spin_button_get_value_as_int (spin);
+
+ parent = HILDON_STACKABLE_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (spin)));
+ stack = hildon_stackable_window_get_stack (parent);
+
+ while (nwindows > 0) {
+ parent = HILDON_STACKABLE_WINDOW (new_window (parent));
+ l = g_list_append (l, parent);
+ nwindows--;
+ }
+ hildon_window_stack_push_list (stack, l);
+ g_list_free (l);
}
static void
-add_window (GtkWidget *w)
+pop_windows (GtkWidget *button,
+ GtkSpinButton *spin)
{
- GtkWidget *window = new_window (FALSE);
- gtk_widget_show_all (window);
+ HildonWindowStack *stack = NULL;
+ HildonStackableWindow *win;
+ gint nwindows = gtk_spin_button_get_value_as_int (spin);
- return;
+ win = HILDON_STACKABLE_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (spin)));
+ stack = hildon_stackable_window_get_stack (win);
+
+ hildon_window_stack_pop (stack, nwindows, NULL);
}
int
-main (int argc,
+main (int argc,
char **argv)
{
GtkWidget *window;
hildon_gtk_init (&argc, &argv);
- g_set_application_name ("stack");
+ g_set_application_name ("hildon-stackable-window-example");
- window = new_window (TRUE);
+ window = new_window (NULL);
- g_signal_connect (G_OBJECT (window), "delete_event",
+ g_signal_connect (G_OBJECT (window), "destroy",
G_CALLBACK (gtk_main_quit), NULL);
- gtk_widget_show_all (GTK_WIDGET (window));
+ gtk_widget_show (window);
gtk_main ();
hildon-caption.c \
hildon-window.c \
hildon-stackable-window.c \
+ hildon-window-stack.c \
hildon-program.c \
hildon-code-dialog.c \
hildon-enum-types.c \
hildon.h \
hildon-window.h \
hildon-stackable-window.h \
+ hildon-window-stack.h \
hildon-wizard-dialog.h \
hildon-calendar.h \
hildon-pannable-area.h \
hildon-weekday-picker-private.h \
hildon-window-private.h \
hildon-stackable-window-private.h \
+ hildon-window-stack-private.h \
hildon-wizard-dialog-private.h \
hildon-calendar-private.h \
hildon-app-menu-private.h \
#include "hildon-program.h"
#include "hildon-program-private.h"
#include "hildon-window-private.h"
+#include "hildon-window-stack.h"
static void
hildon_program_init (HildonProgram *self);
* hildon_program_pop_window_stack:
* @self: A #HildonProgram
*
- * Deprecated: See #HildonWindowStack
+ * Deprecated: Use hildon_window_stack_pop() instead
*
- * Returns: %NULL
+ * Returns: A #HildonStackableWindow, or %NULL
*/
HildonStackableWindow *
hildon_program_pop_window_stack (HildonProgram *self)
{
- return NULL;
+ HildonWindowStack *stack = hildon_window_stack_get_default ();
+ GtkWidget *win = hildon_window_stack_pop_1 (stack);
+ g_warning ("%s: this function is deprecated. Use hildon_window_stack_pop() instead", __FUNCTION__);
+ return win ? HILDON_STACKABLE_WINDOW (win) : NULL;
}
/**
* hildon_program_peek_window_stack:
* @self: A #HildonProgram
*
- * Deprecated: See #HildonWindowStack
+ * Deprecated: Use hildon_window_stack_peek() instead
*
- * Returns: %NULL
+ * Returns: A #HildonStackableWindow, or %NULL
*/
HildonStackableWindow *
hildon_program_peek_window_stack (HildonProgram *self)
{
- return NULL;
+ HildonWindowStack *stack = hildon_window_stack_get_default ();
+ GtkWidget *win = hildon_window_stack_peek (stack);
+ g_warning ("%s: this function is deprecated. Use hildon_window_stack_peek() instead", __FUNCTION__);
+ return win ? HILDON_STACKABLE_WINDOW (win) : NULL;
}
/* Utilities */
void
hildon_program_go_to_root_window (HildonProgram *self)
{
+ HildonWindowStack *stack = hildon_window_stack_get_default ();
+ gint n = hildon_window_stack_size (stack);
+ g_warning ("%s: this function is deprecated. Use hildon_window_stack_pop() instead.", __FUNCTION__);
+ if (n > 1) {
+ hildon_window_stack_pop (stack, n-1, NULL);
+ }
}
struct _HildonStackableWindowPrivate
{
HildonAppMenu *app_menu;
+ HildonWindowStack *stack;
+ gint stack_position;
};
#define HILDON_STACKABLE_WINDOW_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
HILDON_TYPE_STACKABLE_WINDOW, HildonStackableWindowPrivate))
+void G_GNUC_INTERNAL
+hildon_stackable_window_set_stack (HildonStackableWindow *self,
+ HildonWindowStack *stack,
+ gint position);
+
G_END_DECLS
#endif /* __HILDON_STACKABLE_WINDOW_PRIVATE_H__ */
/**
* SECTION:hildon-stackable-window
* @short_description: Widget representing a stackable, top-level window in the Hildon framework.
+ * @see_also: #HildonWindowStack
*
* The #HildonStackableWindow is a GTK+ widget which represents a
* top-level window in the Hildon framework. It is derived from
* in a hierarchical way so users can go from any window back to the
* application's root window.
*
+ * The user can only see and interact with the window on top of the
+ * stack. Although all other windows are mapped and visible, they are
+ * obscured by the topmost one so in practice they appear as if they
+ * were hidden.
+ *
* To add a window to the stack, just use gtk_widget_show(). The
- * previous one will be automatically hidden. When the new window is
- * destroyed, the previous one will appear again.
+ * previous one will be obscured by the new one. When the new window
+ * is destroyed, the previous one will appear again.
*
* Alternatively, you can remove a window from the top of the stack
- * without destroying it by using
- * hildon_program_pop_window_stack(). The window will be automatically
- * hidden and the previous one will appear.
+ * without destroying it by using hildon_window_stack_pop(). The
+ * window will be automatically hidden and the previous one will
+ * appear.
+ *
+ * For advanced details on stack handling, see #HildonWindowStack
*
* <example>
* <title>Basic HildonStackableWindow example</title>
* <!-- -->
* // ... configure new window
* <!-- -->
- * // This automatically hides the previous window
* gtk_widget_show (win);
* }
* <!-- -->
#include <X11/X.h>
#include <X11/Xatom.h>
+#include <gdk/gdkx.h>
#include "hildon-stackable-window.h"
#include "hildon-stackable-window-private.h"
#include "hildon-app-menu-private.h"
+#include "hildon-window-stack.h"
+#include "hildon-window-stack-private.h"
G_DEFINE_TYPE (HildonStackableWindow, hildon_stackable_window, HILDON_TYPE_WINDOW);
+void G_GNUC_INTERNAL
+hildon_stackable_window_set_stack (HildonStackableWindow *self,
+ HildonWindowStack *stack,
+ gint position)
+{
+ HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
+
+ if (stack)
+ g_object_ref (stack);
+
+ if (priv->stack)
+ g_object_unref (priv->stack);
+
+ priv->stack = stack;
+ priv->stack_position = position;
+}
+
+/**
+ * hildon_stackable_window_get_stack:
+ * @self: a #HildonStackableWindow
+ *
+ * Returns the stack where window @self is on, or %NULL if the window
+ * is not stacked.
+ *
+ * Return value: a #HildonWindowStack, or %NULL
+ **/
+HildonWindowStack *
+hildon_stackable_window_get_stack (HildonStackableWindow *self)
+{
+ HildonStackableWindowPrivate *priv;
+
+ g_return_val_if_fail (HILDON_IS_STACKABLE_WINDOW (self), NULL);
+
+ priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
+
+ return priv->stack;
+}
+
/**
* hildon_stackable_window_set_main_menu:
* @self: a #HildonStackableWindow
}
static void
-hildon_stackable_window_realize (GtkWidget *widget)
+hildon_stackable_window_map (GtkWidget *widget)
{
GdkDisplay *display;
Atom atom;
- unsigned long val = 1;
+ unsigned long val;
+ HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (widget);
- GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->realize (widget);
+ val = priv->stack_position;
/* Set additional property "_HILDON_STACKABLE_WINDOW", to allow the WM to manage
it as a stackable window. */
display = gdk_drawable_get_display (widget->window);
atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_STACKABLE_WINDOW");
XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (widget->window), atom,
- XA_ATOM, 32, PropModeReplace,
+ XA_INTEGER, 32, PropModeReplace,
(unsigned char *) &val, 1);
+
+ GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->map (widget);
}
static void
hildon_stackable_window_show (GtkWidget *widget)
{
- GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->show (widget);
+ HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (widget);
+
+ /* Stack the window if not already stacked */
+ if (priv->stack == NULL) {
+ HildonWindowStack *stack = hildon_window_stack_get_default ();
+ hildon_window_stack_push_1 (stack, HILDON_STACKABLE_WINDOW (widget));
+ } else {
+ GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->show (widget);
+ }
}
static void
hildon_stackable_window_hide (GtkWidget *widget)
{
+ HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (widget);
GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->hide (widget);
+
+ if (priv->stack) {
+ hildon_window_stack_remove (HILDON_STACKABLE_WINDOW (widget));
+ }
}
static void
obj_class->finalize = hildon_stackable_window_finalize;
- widget_class->realize = hildon_stackable_window_realize;
+ widget_class->map = hildon_stackable_window_map;
widget_class->show = hildon_stackable_window_show;
widget_class->hide = hildon_stackable_window_hide;
HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
priv->app_menu = NULL;
+ priv->stack = NULL;
+ priv->stack_position = -1;
}
/**
HILDON_TYPE_STACKABLE_WINDOW, \
HildonStackableWindowClass))
+typedef struct _HildonWindowStack HildonWindowStack;
+
typedef struct _HildonStackableWindow HildonStackableWindow;
typedef struct _HildonStackableWindowClass HildonStackableWindowClass;
hildon_stackable_window_set_main_menu (HildonStackableWindow *self,
HildonAppMenu *menu);
+HildonWindowStack *
+hildon_stackable_window_get_stack (HildonStackableWindow *self);
+
G_END_DECLS
#endif /* __HILDON_STACKABLE_WINDOW_H__ */
--- /dev/null
+/*
+ * This file is a part of hildon
+ *
+ * Copyright (C) 2008 Nokia Corporation, all rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __HILDON_WINDOW_STACK_PRIVATE_H__
+#define __HILDON_WINDOW_STACK_PRIVATE_H__
+
+G_BEGIN_DECLS
+
+void G_GNUC_INTERNAL
+hildon_window_stack_remove (HildonStackableWindow *win);
+
+G_END_DECLS
+
+#endif /* __HILDON_WINDOW_STACK_PRIVATE_H__ */
--- /dev/null
+/*
+ * This file is a part of hildon
+ *
+ * Copyright (C) 2008 Nokia Corporation, all rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+/**
+ * SECTION:hildon-window-stack
+ * @short_description: Object representing a stack of windows in the Hildon framework
+ * @see_also: #HildonStackableWindow
+ *
+ * The #HildonWindowStack is an object used to represent a stack of
+ * windows in the Hildon framework.
+ *
+ * Stacks contain all #HildonStackableWindow<!-- -->s that are being
+ * shown. The user can only interact with the topmost window from each
+ * stack (as it covers all the others), but all of them are mapped and
+ * visible from the Gtk point of view.
+ *
+ * Each window can only be in one stack at a time. All stacked windows
+ * are visible and all visible windows are stacked.
+ *
+ * Each application has a default stack, and windows are automatically
+ * added to it when they are shown with gtk_widget_show().
+ *
+ * Additional stacks can be created at any time using
+ * hildon_window_stack_new(). To add a window to a specific stack, use
+ * hildon_window_stack_push_1() (remember that, for the default stack,
+ * gtk_widget_show() can be used instead).
+ *
+ * To remove a window from a stack use hildon_window_stack_pop_1(), or
+ * simply gtk_widget_hide().
+ *
+ * For more complex layout changes, applications can push and/or pop
+ * several windows at the same time in a single step. See
+ * hildon_window_stack_push(), hildon_window_stack_pop() and
+ * hildon_window_stack_pop_and_push() for more details.
+ */
+
+#include "hildon-window-stack.h"
+#include "hildon-window-stack-private.h"
+#include "hildon-stackable-window-private.h"
+
+struct _HildonWindowStackPrivate
+{
+ GList *list;
+ GtkWindowGroup *group;
+};
+
+#define HILDON_WINDOW_STACK_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
+ HILDON_TYPE_WINDOW_STACK, HildonWindowStackPrivate))
+
+G_DEFINE_TYPE (HildonWindowStack, hildon_window_stack, G_TYPE_OBJECT);
+
+/**
+ * hildon_window_stack_get_default:
+ *
+ * Returns the default window stack. This stack always exists and
+ * doesn't need to be created by the application.
+ *
+ * Return value: the default #HildonWindowStack
+ **/
+HildonWindowStack *
+hildon_window_stack_get_default (void)
+{
+ static HildonWindowStack *stack = NULL;
+ if (G_UNLIKELY (stack == NULL)) {
+ stack = g_object_new (HILDON_TYPE_WINDOW_STACK, NULL);
+ stack->priv->group = gtk_window_get_group (NULL);
+ }
+ return stack;
+}
+
+/**
+ * hildon_window_stack_new:
+ *
+ * Creates a new #HildonWindowStack. The stack is initially empty.
+ *
+ * Return value: a new #HildonWindowStack
+ **/
+HildonWindowStack *
+hildon_window_stack_new (void)
+{
+ HildonWindowStack *stack = g_object_new (HILDON_TYPE_WINDOW_STACK, NULL);
+ stack->priv->group = gtk_window_group_new ();
+ return stack;
+}
+
+/**
+ * hildon_window_stack_size:
+ * @stack: A #HildonWindowStack
+ *
+ * Returns the number of windows in @stack
+ *
+ * Return value: Number of windows in @stack
+ **/
+gint
+hildon_window_stack_size (HildonWindowStack *stack)
+{
+ g_return_val_if_fail (HILDON_IS_WINDOW_STACK (stack), 0);
+
+ return g_list_length (stack->priv->list);
+}
+
+/* Remove a window from its stack, no matter its position */
+void G_GNUC_INTERNAL
+hildon_window_stack_remove (HildonStackableWindow *win)
+{
+ HildonWindowStack *stack = hildon_stackable_window_get_stack (win);
+
+ /* If the window is stacked */
+ if (stack) {
+ hildon_stackable_window_set_stack (win, NULL, -1);
+ stack->priv->list = g_list_remove (stack->priv->list, win);
+ gtk_window_set_transient_for (GTK_WINDOW (win), NULL);
+ }
+}
+
+/**
+ * hildon_window_stack_peek:
+ * @stack: A %HildonWindowStack
+ *
+ * Returns the window on top of @stack. The stack is never modified.
+ *
+ * Return value: the window on top of the stack, or %NULL if the stack
+ * is empty.
+ **/
+GtkWidget *
+hildon_window_stack_peek (HildonWindowStack *stack)
+{
+ GtkWidget *win = NULL;
+
+ g_return_val_if_fail (HILDON_IS_WINDOW_STACK (stack), NULL);
+
+ if (stack->priv->list != NULL) {
+ win = GTK_WIDGET (stack->priv->list->data);
+ }
+
+ return win;
+}
+
+static gboolean
+_hildon_window_stack_do_push (HildonWindowStack *stack,
+ HildonStackableWindow *win)
+{
+ HildonWindowStack *current_stack;
+
+ g_return_val_if_fail (HILDON_IS_WINDOW_STACK (stack), FALSE);
+ g_return_val_if_fail (HILDON_IS_STACKABLE_WINDOW (win), FALSE);
+
+ current_stack = hildon_stackable_window_get_stack (win);
+
+ if (current_stack == NULL) {
+ GtkWidget *parent = hildon_window_stack_peek (stack);
+
+ /* Push the window */
+ hildon_stackable_window_set_stack (win, stack, g_list_length (stack->priv->list));
+ stack->priv->list = g_list_prepend (stack->priv->list, win);
+
+ /* Make the window part of the same group as its parent */
+ if (parent) {
+ gtk_window_set_transient_for (GTK_WINDOW (win), GTK_WINDOW (parent));
+ } else {
+ gtk_window_group_add_window (stack->priv->group, GTK_WINDOW (win));
+ }
+
+ return TRUE;
+ } else {
+ g_warning ("Trying to push a window that is already on a stack");
+ return FALSE;
+ }
+}
+
+static GtkWidget *
+_hildon_window_stack_do_pop (HildonWindowStack *stack)
+{
+ GtkWidget *win = hildon_window_stack_peek (stack);
+
+ if (win)
+ hildon_window_stack_remove (HILDON_STACKABLE_WINDOW (win));
+
+ return win;
+}
+
+/**
+ * hildon_window_stack_push_1:
+ * @stack: A %HildonWindowStack
+ * @win: A %HildonStackableWindow
+ *
+ * Adds @win to the top of @stack, and shows it. The window must not
+ * be already stacked.
+ **/
+void
+hildon_window_stack_push_1 (HildonWindowStack *stack,
+ HildonStackableWindow *win)
+{
+ if (_hildon_window_stack_do_push (stack, win))
+ gtk_widget_show (GTK_WIDGET (win));
+}
+
+/**
+ * hildon_window_stack_pop_1:
+ * @stack: A %HildonWindowStack
+ *
+ * Removes the window on top of @stack, and hides it. If the stack is
+ * empty nothing happens.
+ *
+ * Return value: the window on top of the stack, or %NULL if the stack
+ * is empty.
+ **/
+GtkWidget *
+hildon_window_stack_pop_1 (HildonWindowStack *stack)
+{
+ GtkWidget *win = _hildon_window_stack_do_pop (stack);
+ if (win)
+ gtk_widget_hide (win);
+ return win;
+}
+
+/**
+ * hildon_window_stack_push_list:
+ * @stack: A %HildonWindowStack
+ * @list: A list of %HildonStackableWindow<!-- -->s to push
+ *
+ * Pushes all windows in @list to the top of @stack, and shows
+ * them. Everything is done in a single transition, so the user will
+ * only see the last window in @list during this operation. None of
+ * the windows must be already stacked.
+ **/
+void
+hildon_window_stack_push_list (HildonWindowStack *stack,
+ GList *list)
+{
+ HildonStackableWindow *win;
+ GList *l;
+ GList *pushed = NULL;
+
+ g_return_if_fail (HILDON_IS_WINDOW_STACK (stack));
+
+ /* Stack all windows */
+ for (l = list; l != NULL; l = g_list_next (l)) {
+ win = HILDON_STACKABLE_WINDOW (l->data);
+ if (win) {
+ _hildon_window_stack_do_push (stack, win);
+ pushed = g_list_prepend (pushed, win);
+ } else {
+ g_warning ("Trying to stack a non-stackable window!");
+ }
+ }
+
+ /* Show windows in reverse order (topmost first) */
+ g_list_foreach (pushed, (GFunc) gtk_widget_show, NULL);
+
+ g_list_free (pushed);
+}
+
+/**
+ * hildon_window_stack_push:
+ * @stack: A %HildonWindowStack
+ * @win1: The first window to push
+ * @Varargs: A %NULL-terminated list of additional #HildonStackableWindow<!-- -->s to push.
+ *
+ * Pushes all windows to the top of @stack, and shows them. Everything
+ * is done in a single transition, so the user will only see the last
+ * window. None of the windows must be already stacked.
+ **/
+void
+hildon_window_stack_push (HildonWindowStack *stack,
+ HildonStackableWindow *win1,
+ ...)
+{
+ HildonStackableWindow *win;
+ GList *list = NULL;
+ va_list args;
+
+ va_start (args, win1);
+ win = va_arg (args, HildonStackableWindow *);
+
+ while (win != NULL) {
+ list = g_list_prepend (list, win);
+ win = va_arg (args, HildonStackableWindow *);
+ }
+
+ va_end (args);
+
+ hildon_window_stack_push_list (stack, list);
+ g_list_free (list);
+}
+
+/**
+ * hildon_window_stack_pop:
+ * @stack: A %HildonWindowStack
+ * @nwindows: Number of windows to pop
+ * @popped_windows: if non-%NULL, the list of popped windows is stored here
+ *
+ * Pops @nwindows windows from @stack, and hides them. Everything is
+ * done in a single transition, so the user will not see any of the
+ * windows being popped in this operation.
+ *
+ * If @popped_windows is not %NULL, the list of popped windows is
+ * stored there (ordered bottom-up). That list must be freed by the
+ * user.
+ **/
+void
+hildon_window_stack_pop (HildonWindowStack *stack,
+ gint nwindows,
+ GList **popped_windows)
+{
+ gint i;
+ GList *popped = NULL;
+
+ g_return_if_fail (HILDON_IS_WINDOW_STACK (stack));
+ g_return_if_fail (nwindows > 0);
+ g_return_if_fail (g_list_length (stack->priv->list) >= nwindows);
+
+ /* Pop windows */
+ for (i = 0; i < nwindows; i++) {
+ GtkWidget *win = _hildon_window_stack_do_pop (stack);
+ popped = g_list_prepend (popped, win);
+ }
+
+ /* Hide windows in reverse order (topmost last) */
+ g_list_foreach (popped, (GFunc) gtk_widget_hide, NULL);
+
+ if (popped_windows) {
+ *popped_windows = popped;
+ } else {
+ g_list_free (popped);
+ }
+}
+
+/**
+ * hildon_window_stack_pop_and_push_list:
+ * @stack: A %HildonWindowStack
+ * @nwindows: Number of windows to pop.
+ * @popped_windows: if non-%NULL, the list of popped windows is stored here
+ * @list: A list of %HildonStackableWindow<!-- -->s to push
+ *
+ * Pops @nwindows windows from @stack (and hides them), then pushes
+ * all windows in @list (and shows them). Everything is done in a
+ * single transition, so the user will only see the last window from
+ * @list. None of the pushed windows must be already stacked.
+ *
+ * If @popped_windows is not %NULL, the list of popped windows is
+ * stored there (ordered bottom-up). That list must be freed by the
+ * user.
+ **/
+void
+hildon_window_stack_pop_and_push_list (HildonWindowStack *stack,
+ gint nwindows,
+ GList **popped_windows,
+ GList *list)
+{
+ gint i;
+ GList *l;
+ GList *popped = NULL;
+ GList *pushed = NULL;
+
+ g_return_if_fail (HILDON_IS_WINDOW_STACK (stack));
+ g_return_if_fail (nwindows > 0);
+ g_return_if_fail (g_list_length (stack->priv->list) >= nwindows);
+
+ /* Pop windows */
+ for (i = 0; i < nwindows; i++) {
+ GtkWidget *win = _hildon_window_stack_do_pop (stack);
+ popped = g_list_prepend (popped, win);
+ }
+
+ /* Push windows */
+ for (l = list; l != NULL; l = g_list_next (l)) {
+ HildonStackableWindow *win = HILDON_STACKABLE_WINDOW (l->data);
+ if (win) {
+ _hildon_window_stack_do_push (stack, win);
+ pushed = g_list_prepend (pushed, win);
+ } else {
+ g_warning ("Trying to stack a non-stackable window!");
+ }
+ }
+
+ /* Show windows in reverse order (topmost first) */
+ g_list_foreach (pushed, (GFunc) gtk_widget_show, NULL);
+
+ /* Hide windows in reverse order (topmost last) */
+ g_list_foreach (popped, (GFunc) gtk_widget_hide, NULL);
+
+ g_list_free (pushed);
+ if (popped_windows) {
+ *popped_windows = popped;
+ } else {
+ g_list_free (popped);
+ }
+}
+
+/**
+ * hildon_window_stack_pop_and_push:
+ * @stack: A %HildonWindowStack
+ * @nwindows: Number of windows to pop.
+ * @popped_windows: if non-%NULL, the list of popped windows is stored here
+ * @win1: The first window to push
+ * @Varargs: A %NULL-terminated list of additional #HildonStackableWindow<!-- -->s to push.
+ *
+ * Pops @nwindows windows from @stack (and hides them), then pushes
+ * all passed windows (and shows them). Everything is done in a single
+ * transition, so the user will only see the last pushed window. None
+ * of the pushed windows must be already stacked.
+ *
+ * If @popped_windows is not %NULL, the list of popped windows is
+ * stored there (ordered bottom-up). That list must be freed by the
+ * user.
+ **/
+void
+hildon_window_stack_pop_and_push (HildonWindowStack *stack,
+ gint nwindows,
+ GList **popped_windows,
+ HildonStackableWindow *win1,
+ ...)
+{
+ HildonStackableWindow *win;
+ GList *list = NULL;
+ va_list args;
+
+ va_start (args, win1);
+ win = va_arg (args, HildonStackableWindow *);
+
+ while (win != NULL) {
+ list = g_list_prepend (list, win);
+ win = va_arg (args, HildonStackableWindow *);
+ }
+
+ va_end (args);
+
+ hildon_window_stack_pop_and_push_list (stack, nwindows, popped_windows, list);
+ g_list_free (list);
+}
+
+static void
+hildon_window_stack_finalize (GObject *object)
+{
+ HildonWindowStack *stack = HILDON_WINDOW_STACK (object);
+
+ if (stack->priv->list)
+ hildon_window_stack_pop (stack, hildon_window_stack_size (stack), NULL);
+
+ if (stack->priv->group)
+ g_object_unref (stack->priv->group);
+
+ G_OBJECT_CLASS (hildon_window_stack_parent_class)->finalize (object);
+}
+
+static void
+hildon_window_stack_class_init (HildonWindowStackClass *klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *)klass;
+
+ gobject_class->finalize = hildon_window_stack_finalize;
+
+ g_type_class_add_private (klass, sizeof (HildonWindowStackPrivate));
+}
+
+static void
+hildon_window_stack_init (HildonWindowStack *self)
+{
+ HildonWindowStackPrivate *priv;
+
+ priv = self->priv = HILDON_WINDOW_STACK_GET_PRIVATE (self);
+
+ priv->list = NULL;
+ priv->group = NULL;
+}
--- /dev/null
+/*
+ * This file is a part of hildon
+ *
+ * Copyright (C) 2008 Nokia Corporation, all rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __HILDON_WINDOW_STACK_H__
+#define __HILDON_WINDOW_STACK_H__
+
+#include "hildon-stackable-window.h"
+
+G_BEGIN_DECLS
+
+#define HILDON_TYPE_WINDOW_STACK \
+ (hildon_window_stack_get_type())
+
+#define HILDON_WINDOW_STACK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ HILDON_TYPE_WINDOW_STACK, \
+ HildonWindowStack))
+
+#define HILDON_WINDOW_STACK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ HILDON_TYPE_WINDOW_STACK, \
+ HildonWindowStackClass))
+
+#define HILDON_IS_WINDOW_STACK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ HILDON_TYPE_WINDOW_STACK))
+
+#define HILDON_IS_WINDOW_STACK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ HILDON_TYPE_WINDOW_STACK))
+
+#define HILDON_WINDOW_STACK_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ HILDON_TYPE_WINDOW_STACK, \
+ HildonWindowStackClass))
+
+typedef struct _HildonWindowStackPrivate HildonWindowStackPrivate;
+
+typedef struct _HildonWindowStackClass HildonWindowStackClass;
+
+struct _HildonWindowStack
+{
+ GObject parent;
+
+ /* private */
+ HildonWindowStackPrivate *priv;
+};
+
+struct _HildonWindowStackClass
+{
+ GObjectClass parent_class;
+
+ /* Padding for future extension */
+ void (*_hildon_reserved1)(void);
+ void (*_hildon_reserved2)(void);
+ void (*_hildon_reserved3)(void);
+ void (*_hildon_reserved4)(void);
+};
+
+GType
+hildon_window_stack_get_type (void) G_GNUC_CONST;
+
+HildonWindowStack *
+hildon_window_stack_get_default (void);
+
+HildonWindowStack *
+hildon_window_stack_new (void);
+
+gint
+hildon_window_stack_size (HildonWindowStack *stack);
+
+GtkWidget *
+hildon_window_stack_peek (HildonWindowStack *stack);
+
+void
+hildon_window_stack_push (HildonWindowStack *stack,
+ HildonStackableWindow *win1,
+ ...);
+
+void
+hildon_window_stack_push_list (HildonWindowStack *stack,
+ GList *list);
+
+void
+hildon_window_stack_push_1 (HildonWindowStack *stack,
+ HildonStackableWindow *win);
+
+void
+hildon_window_stack_pop (HildonWindowStack *stack,
+ gint nwindows,
+ GList **popped_windows);
+
+GtkWidget *
+hildon_window_stack_pop_1 (HildonWindowStack *stack);
+
+void
+hildon_window_stack_pop_and_push (HildonWindowStack *stack,
+ gint nwindows,
+ GList **popped_windows,
+ HildonStackableWindow *win1,
+ ...);
+
+void
+hildon_window_stack_pop_and_push_list (HildonWindowStack *stack,
+ gint nwindows,
+ GList **popped_windows,
+ GList *list);
+
+G_END_DECLS
+
+#endif /* __HILDON_WINDOW_STACK_H__ */
#include "hildon-weekday-picker.h"
#include "hildon-window.h"
#include "hildon-stackable-window.h"
+#include "hildon-window-stack.h"
#include "hildon-wizard-dialog.h"
#include "hildon-calendar.h"
#include "hildon-bread-crumb-trail.h"