2 * This file is a part of hildon
4 * Copyright (C) 2008 Nokia Corporation, all rights reserved.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; version 2.1 of
9 * the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24 * SECTION:hildon-window-stack
25 * @short_description: Object representing a stack of windows in the Hildon framework
26 * @see_also: #HildonStackableWindow
28 * The #HildonWindowStack is an object used to represent a stack of
29 * windows in the Hildon framework.
31 * Stacks contain all #HildonStackableWindow<!-- -->s that are being
32 * shown. The user can only interact with the topmost window from each
33 * stack (as it covers all the others), but all of them are mapped and
34 * visible from the Gtk point of view.
36 * Each window can only be in one stack at a time. All stacked windows
37 * are visible and all visible windows are stacked.
39 * Each application has a default stack, and windows are automatically
40 * added to it when they are shown with gtk_widget_show().
42 * Additional stacks can be created at any time using
43 * hildon_window_stack_new(). To add a window to a specific stack, use
44 * hildon_window_stack_push_1() (remember that, for the default stack,
45 * gtk_widget_show() can be used instead).
47 * To remove a window from a stack use hildon_window_stack_pop_1(), or
48 * simply gtk_widget_hide().
50 * For more complex layout changes, applications can push and/or pop
51 * several windows at the same time in a single step. See
52 * hildon_window_stack_push(), hildon_window_stack_pop() and
53 * hildon_window_stack_pop_and_push() for more details.
56 #include "hildon-window-stack.h"
57 #include "hildon-window-stack-private.h"
58 #include "hildon-stackable-window-private.h"
60 struct _HildonWindowStackPrivate
63 GtkWindowGroup *group;
66 #define HILDON_WINDOW_STACK_GET_PRIVATE(obj) \
67 (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
68 HILDON_TYPE_WINDOW_STACK, HildonWindowStackPrivate))
70 G_DEFINE_TYPE (HildonWindowStack, hildon_window_stack, G_TYPE_OBJECT);
73 * hildon_window_stack_get_default:
75 * Returns the default window stack. This stack always exists and
76 * doesn't need to be created by the application.
78 * Return value: the default #HildonWindowStack
81 hildon_window_stack_get_default (void)
83 static HildonWindowStack *stack = NULL;
84 if (G_UNLIKELY (stack == NULL)) {
85 stack = g_object_new (HILDON_TYPE_WINDOW_STACK, NULL);
86 stack->priv->group = gtk_window_get_group (NULL);
92 * hildon_window_stack_new:
94 * Creates a new #HildonWindowStack. The stack is initially empty.
96 * Return value: a new #HildonWindowStack
99 hildon_window_stack_new (void)
101 HildonWindowStack *stack = g_object_new (HILDON_TYPE_WINDOW_STACK, NULL);
102 stack->priv->group = gtk_window_group_new ();
107 * hildon_window_stack_size:
108 * @stack: A #HildonWindowStack
110 * Returns the number of windows in @stack
112 * Return value: Number of windows in @stack
115 hildon_window_stack_size (HildonWindowStack *stack)
117 g_return_val_if_fail (HILDON_IS_WINDOW_STACK (stack), 0);
119 return g_list_length (stack->priv->list);
122 /* Remove a window from its stack, no matter its position */
124 hildon_window_stack_remove (HildonStackableWindow *win)
126 HildonWindowStack *stack = hildon_stackable_window_get_stack (win);
128 /* If the window is stacked */
130 hildon_stackable_window_set_stack (win, NULL, -1);
131 stack->priv->list = g_list_remove (stack->priv->list, win);
132 gtk_window_set_transient_for (GTK_WINDOW (win), NULL);
137 * hildon_window_stack_peek:
138 * @stack: A %HildonWindowStack
140 * Returns the window on top of @stack. The stack is never modified.
142 * Return value: the window on top of the stack, or %NULL if the stack
146 hildon_window_stack_peek (HildonWindowStack *stack)
148 GtkWidget *win = NULL;
150 g_return_val_if_fail (HILDON_IS_WINDOW_STACK (stack), NULL);
152 if (stack->priv->list != NULL) {
153 win = GTK_WIDGET (stack->priv->list->data);
160 _hildon_window_stack_do_push (HildonWindowStack *stack,
161 HildonStackableWindow *win)
163 HildonWindowStack *current_stack;
165 g_return_val_if_fail (HILDON_IS_WINDOW_STACK (stack), FALSE);
166 g_return_val_if_fail (HILDON_IS_STACKABLE_WINDOW (win), FALSE);
168 current_stack = hildon_stackable_window_get_stack (win);
170 if (current_stack == NULL) {
171 GtkWidget *parent = hildon_window_stack_peek (stack);
173 /* Push the window */
174 hildon_stackable_window_set_stack (win, stack, g_list_length (stack->priv->list));
175 stack->priv->list = g_list_prepend (stack->priv->list, win);
177 /* Make the window part of the same group as its parent */
179 gtk_window_set_transient_for (GTK_WINDOW (win), GTK_WINDOW (parent));
181 gtk_window_group_add_window (stack->priv->group, GTK_WINDOW (win));
186 g_warning ("Trying to push a window that is already on a stack");
192 _hildon_window_stack_do_pop (HildonWindowStack *stack)
194 GtkWidget *win = hildon_window_stack_peek (stack);
197 hildon_window_stack_remove (HILDON_STACKABLE_WINDOW (win));
203 * hildon_window_stack_push_1:
204 * @stack: A %HildonWindowStack
205 * @win: A %HildonStackableWindow
207 * Adds @win to the top of @stack, and shows it. The window must not
208 * be already stacked.
211 hildon_window_stack_push_1 (HildonWindowStack *stack,
212 HildonStackableWindow *win)
214 if (_hildon_window_stack_do_push (stack, win))
215 gtk_widget_show (GTK_WIDGET (win));
219 * hildon_window_stack_pop_1:
220 * @stack: A %HildonWindowStack
222 * Removes the window on top of @stack, and hides it. If the stack is
223 * empty nothing happens.
225 * Return value: the window on top of the stack, or %NULL if the stack
229 hildon_window_stack_pop_1 (HildonWindowStack *stack)
231 GtkWidget *win = _hildon_window_stack_do_pop (stack);
233 gtk_widget_hide (win);
238 * hildon_window_stack_push_list:
239 * @stack: A %HildonWindowStack
240 * @list: A list of %HildonStackableWindow<!-- -->s to push
242 * Pushes all windows in @list to the top of @stack, and shows
243 * them. Everything is done in a single transition, so the user will
244 * only see the last window in @list during this operation. None of
245 * the windows must be already stacked.
248 hildon_window_stack_push_list (HildonWindowStack *stack,
251 HildonStackableWindow *win;
253 GList *pushed = NULL;
255 g_return_if_fail (HILDON_IS_WINDOW_STACK (stack));
257 /* Stack all windows */
258 for (l = list; l != NULL; l = g_list_next (l)) {
259 win = HILDON_STACKABLE_WINDOW (l->data);
261 _hildon_window_stack_do_push (stack, win);
262 pushed = g_list_prepend (pushed, win);
264 g_warning ("Trying to stack a non-stackable window!");
268 /* Show windows in reverse order (topmost first) */
269 g_list_foreach (pushed, (GFunc) gtk_widget_show, NULL);
271 g_list_free (pushed);
275 * hildon_window_stack_push:
276 * @stack: A %HildonWindowStack
277 * @win1: The first window to push
278 * @Varargs: A %NULL-terminated list of additional #HildonStackableWindow<!-- -->s to push.
280 * Pushes all windows to the top of @stack, and shows them. Everything
281 * is done in a single transition, so the user will only see the last
282 * window. None of the windows must be already stacked.
285 hildon_window_stack_push (HildonWindowStack *stack,
286 HildonStackableWindow *win1,
289 HildonStackableWindow *win;
293 va_start (args, win1);
294 win = va_arg (args, HildonStackableWindow *);
296 while (win != NULL) {
297 list = g_list_prepend (list, win);
298 win = va_arg (args, HildonStackableWindow *);
303 hildon_window_stack_push_list (stack, list);
308 * hildon_window_stack_pop:
309 * @stack: A %HildonWindowStack
310 * @nwindows: Number of windows to pop
311 * @popped_windows: if non-%NULL, the list of popped windows is stored here
313 * Pops @nwindows windows from @stack, and hides them. Everything is
314 * done in a single transition, so the user will not see any of the
315 * windows being popped in this operation.
317 * If @popped_windows is not %NULL, the list of popped windows is
318 * stored there (ordered bottom-up). That list must be freed by the
322 hildon_window_stack_pop (HildonWindowStack *stack,
324 GList **popped_windows)
327 GList *popped = NULL;
329 g_return_if_fail (HILDON_IS_WINDOW_STACK (stack));
330 g_return_if_fail (nwindows > 0);
331 g_return_if_fail (g_list_length (stack->priv->list) >= nwindows);
334 for (i = 0; i < nwindows; i++) {
335 GtkWidget *win = _hildon_window_stack_do_pop (stack);
336 popped = g_list_prepend (popped, win);
339 /* Hide windows in reverse order (topmost last) */
340 g_list_foreach (popped, (GFunc) gtk_widget_hide, NULL);
342 if (popped_windows) {
343 *popped_windows = popped;
345 g_list_free (popped);
350 * hildon_window_stack_pop_and_push_list:
351 * @stack: A %HildonWindowStack
352 * @nwindows: Number of windows to pop.
353 * @popped_windows: if non-%NULL, the list of popped windows is stored here
354 * @list: A list of %HildonStackableWindow<!-- -->s to push
356 * Pops @nwindows windows from @stack (and hides them), then pushes
357 * all windows in @list (and shows them). Everything is done in a
358 * single transition, so the user will only see the last window from
359 * @list. None of the pushed windows must be already stacked.
361 * If @popped_windows is not %NULL, the list of popped windows is
362 * stored there (ordered bottom-up). That list must be freed by the
366 hildon_window_stack_pop_and_push_list (HildonWindowStack *stack,
368 GList **popped_windows,
373 GList *popped = NULL;
374 GList *pushed = NULL;
376 g_return_if_fail (HILDON_IS_WINDOW_STACK (stack));
377 g_return_if_fail (nwindows > 0);
378 g_return_if_fail (g_list_length (stack->priv->list) >= nwindows);
381 for (i = 0; i < nwindows; i++) {
382 GtkWidget *win = _hildon_window_stack_do_pop (stack);
383 popped = g_list_prepend (popped, win);
387 for (l = list; l != NULL; l = g_list_next (l)) {
388 HildonStackableWindow *win = HILDON_STACKABLE_WINDOW (l->data);
390 _hildon_window_stack_do_push (stack, win);
391 pushed = g_list_prepend (pushed, win);
393 g_warning ("Trying to stack a non-stackable window!");
397 /* Show windows in reverse order (topmost first) */
398 g_list_foreach (pushed, (GFunc) gtk_widget_show, NULL);
400 /* Hide windows in reverse order (topmost last) */
401 g_list_foreach (popped, (GFunc) gtk_widget_hide, NULL);
403 g_list_free (pushed);
404 if (popped_windows) {
405 *popped_windows = popped;
407 g_list_free (popped);
412 * hildon_window_stack_pop_and_push:
413 * @stack: A %HildonWindowStack
414 * @nwindows: Number of windows to pop.
415 * @popped_windows: if non-%NULL, the list of popped windows is stored here
416 * @win1: The first window to push
417 * @Varargs: A %NULL-terminated list of additional #HildonStackableWindow<!-- -->s to push.
419 * Pops @nwindows windows from @stack (and hides them), then pushes
420 * all passed windows (and shows them). Everything is done in a single
421 * transition, so the user will only see the last pushed window. None
422 * of the pushed windows must be already stacked.
424 * If @popped_windows is not %NULL, the list of popped windows is
425 * stored there (ordered bottom-up). That list must be freed by the
429 hildon_window_stack_pop_and_push (HildonWindowStack *stack,
431 GList **popped_windows,
432 HildonStackableWindow *win1,
435 HildonStackableWindow *win;
439 va_start (args, win1);
440 win = va_arg (args, HildonStackableWindow *);
442 while (win != NULL) {
443 list = g_list_prepend (list, win);
444 win = va_arg (args, HildonStackableWindow *);
449 hildon_window_stack_pop_and_push_list (stack, nwindows, popped_windows, list);
454 hildon_window_stack_finalize (GObject *object)
456 HildonWindowStack *stack = HILDON_WINDOW_STACK (object);
458 if (stack->priv->list)
459 hildon_window_stack_pop (stack, hildon_window_stack_size (stack), NULL);
461 if (stack->priv->group)
462 g_object_unref (stack->priv->group);
464 G_OBJECT_CLASS (hildon_window_stack_parent_class)->finalize (object);
468 hildon_window_stack_class_init (HildonWindowStackClass *klass)
470 GObjectClass *gobject_class = (GObjectClass *)klass;
472 gobject_class->finalize = hildon_window_stack_finalize;
474 g_type_class_add_private (klass, sizeof (HildonWindowStackPrivate));
478 hildon_window_stack_init (HildonWindowStack *self)
480 HildonWindowStackPrivate *priv;
482 priv = self->priv = HILDON_WINDOW_STACK_GET_PRIVATE (self);