2 * This file is a part of hildon
4 * Copyright (C) 2008 Nokia Corporation, all rights reserved.
6 * Contact: Rodrigo Novo <rodrigo.novo@nokia.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; version 2.1 of
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
26 * SECTION:hildon-stackable-window
27 * @short_description: Widget representing a stackable, top-level window in the Hildon framework.
28 * @see_also: #HildonWindowStack
30 * The #HildonStackableWindow is a GTK+ widget which represents a
31 * top-level window in the Hildon framework. It is derived from
32 * #HildonWindow. Applications that use stackable windows are organized
33 * in a hierarchical way so users can go from any window back to the
34 * application's root window.
36 * The user can only see and interact with the window on top of the
37 * stack. Although all other windows are mapped and visible, they are
38 * obscured by the topmost one so in practice they appear as if they
41 * To add a window to the stack, just use gtk_widget_show(). The
42 * previous one will be obscured by the new one. When the new window
43 * is destroyed, the previous one will appear again.
45 * Alternatively, you can remove a window from the top of the stack
46 * without destroying it by using hildon_window_stack_pop(). The
47 * window will be automatically hidden and the previous one will
50 * For advanced details on stack handling, see #HildonWindowStack
53 * <title>Basic HildonStackableWindow example</title>
56 * show_new_window (void)
60 * win = hildon_stackable_window_new ();
62 * // ... configure new window
64 * gtk_widget_show (win);
68 * main (int argc, char **argv)
73 * gtk_init (&argc, &args);
75 * win = hildon_stackable_window_new ();
76 * gtk_window_set_title (GTK_WINDOW (win), "Main window);
78 * // ... add some widgets to the window
80 * g_signal_connect (button, "clicked", G_CALLBACK (show_new_window), NULL);
81 * g_signal_connect (win, "destroy", G_CALLBACK (gtk_main_quit), NULL);
83 * gtk_widget_show_all (win);
93 #include <X11/Xatom.h>
96 #include "hildon-stackable-window.h"
97 #include "hildon-stackable-window-private.h"
98 #include "hildon-app-menu-private.h"
99 #include "hildon-window-stack.h"
100 #include "hildon-window-stack-private.h"
101 #include "hildon-window-private.h"
102 #include "hildon-program.h"
104 G_DEFINE_TYPE (HildonStackableWindow, hildon_stackable_window, HILDON_TYPE_WINDOW);
107 hildon_stackable_window_set_stack (HildonStackableWindow *self,
108 HildonWindowStack *stack,
111 HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
114 g_object_ref (stack);
117 g_object_unref (priv->stack);
120 priv->stack_position = position;
124 * hildon_stackable_window_get_stack:
125 * @self: a #HildonStackableWindow
127 * Returns the stack where window @self is on, or %NULL if the window
130 * Return value: a #HildonWindowStack, or %NULL
135 hildon_stackable_window_get_stack (HildonStackableWindow *self)
137 HildonStackableWindowPrivate *priv;
139 g_return_val_if_fail (HILDON_IS_STACKABLE_WINDOW (self), NULL);
141 priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
147 * hildon_stackable_window_set_main_menu:
148 * @self: a #HildonStackableWindow
149 * @menu: a #HildonAppMenu to be used for this window
151 * Sets the menu to be used for this window. Pass %NULL to remove the
152 * current menu. Any reference to a previous menu will be dropped.
153 * #HildonStackableWindow takes ownership of the passed menu and
154 * you're not supposed to free it yourself anymore.
156 * Note that #HildonStackableWindow widgets use #HildonAppMenu rather
157 * than #GtkMenu, so you're not supposed to use
158 * hildon_window_set_main_menu() with a #HildonStackableWindow.
163 hildon_stackable_window_set_main_menu (HildonStackableWindow *self,
166 HildonStackableWindowPrivate *priv;
167 HildonAppMenu *old_menu;
169 g_return_if_fail (HILDON_IS_STACKABLE_WINDOW (self));
170 g_return_if_fail (!menu || HILDON_IS_APP_MENU (menu));
171 priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
173 old_menu = priv->app_menu;
176 priv->app_menu = menu;
178 g_object_ref_sink (menu);
182 g_object_unref (old_menu);
186 hildon_stackable_window_toggle_menu (HildonWindow *self,
190 HildonStackableWindowPrivate *priv;
191 HildonAppMenu *menu_to_use = NULL;
193 g_return_val_if_fail (HILDON_IS_STACKABLE_WINDOW (self), FALSE);
194 priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
195 g_assert (priv != NULL);
197 if (priv->app_menu) {
198 menu_to_use = priv->app_menu;
200 HildonProgram *program = HILDON_WINDOW_GET_PRIVATE (self)->program;
203 menu_to_use = hildon_program_get_common_app_menu (program);
205 if (self != hildon_app_menu_get_parent_window (HILDON_APP_MENU (menu_to_use)))
206 gtk_widget_hide (GTK_WIDGET (menu_to_use));
212 if (GTK_WIDGET_MAPPED (GTK_WIDGET (menu_to_use))) {
213 gtk_widget_hide (GTK_WIDGET (menu_to_use));
215 hildon_app_menu_popup (menu_to_use, GTK_WINDOW (self));
219 } else if (HILDON_WINDOW_CLASS (hildon_stackable_window_parent_class)->toggle_menu) {
220 return HILDON_WINDOW_CLASS (hildon_stackable_window_parent_class)->toggle_menu (self, button, time);
227 hildon_stackable_window_map (GtkWidget *widget)
232 HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (widget);
234 val = priv->stack_position;
236 /* Set additional property "_HILDON_STACKABLE_WINDOW", to allow the WM to manage
237 it as a stackable window. */
238 display = gdk_drawable_get_display (widget->window);
239 atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_STACKABLE_WINDOW");
240 XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (widget->window), atom,
241 XA_INTEGER, 32, PropModeReplace,
242 (unsigned char *) &val, 1);
244 GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->map (widget);
248 hildon_stackable_window_show (GtkWidget *widget)
250 HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (widget);
252 /* Stack the window if not already stacked */
253 if (priv->stack == NULL) {
254 HildonWindowStack *stack = hildon_window_stack_get_default ();
255 _hildon_window_stack_do_push (stack, HILDON_STACKABLE_WINDOW (widget));
258 GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->show (widget);
262 hildon_stackable_window_hide (GtkWidget *widget)
264 HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (widget);
267 hildon_window_stack_remove (HILDON_STACKABLE_WINDOW (widget));
270 GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->hide (widget);
274 hildon_stackable_window_delete_event (GtkWidget *widget,
277 HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (widget);
278 gboolean retvalue = FALSE;
280 if (priv->stack && hildon_window_stack_peek (priv->stack) != widget) {
281 /* Ignore the delete event if this window is not the topmost one */
283 } else if (GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->delete_event) {
284 retvalue = GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->delete_event (widget, event);
291 hildon_stackable_window_finalize (GObject *object)
293 HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (object);
295 if (priv->app_menu) {
296 hildon_app_menu_set_parent_window (priv->app_menu, NULL);
297 g_object_unref (GTK_WIDGET (priv->app_menu));
300 if (G_OBJECT_CLASS (hildon_stackable_window_parent_class)->finalize)
301 G_OBJECT_CLASS (hildon_stackable_window_parent_class)->finalize (object);
305 hildon_stackable_window_class_init (HildonStackableWindowClass *klass)
307 GObjectClass *obj_class = G_OBJECT_CLASS (klass);
308 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
309 HildonWindowClass *window_class = HILDON_WINDOW_CLASS (klass);
311 obj_class->finalize = hildon_stackable_window_finalize;
313 widget_class->map = hildon_stackable_window_map;
314 widget_class->show = hildon_stackable_window_show;
315 widget_class->hide = hildon_stackable_window_hide;
316 widget_class->delete_event = hildon_stackable_window_delete_event;
318 window_class->toggle_menu = hildon_stackable_window_toggle_menu;
320 g_type_class_add_private (klass, sizeof (HildonStackableWindowPrivate));
324 hildon_stackable_window_init (HildonStackableWindow *self)
326 HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
328 priv->app_menu = NULL;
330 priv->stack_position = -1;
334 * hildon_stackable_window_new:
336 * Creates a new #HildonStackableWindow.
338 * Return value: A #HildonStackableWindow
343 hildon_stackable_window_new (void)
345 HildonStackableWindow *newwindow = g_object_new (HILDON_TYPE_STACKABLE_WINDOW, NULL);
347 return GTK_WIDGET (newwindow);