Add HildonAppMenu::changed signal
[hildon] / hildon / hildon-stackable-window.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2008, 2009 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Rodrigo Novo <rodrigo.novo@nokia.com>
7  *
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.
12  *
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.
17  *
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
21  * 02110-1301 USA
22  *
23  */
24
25 /**
26  * SECTION:hildon-stackable-window
27  * @short_description: Stackable top-level window in the Hildon framework.
28  * @see_also: #HildonWindowStack, #HildonProgram, #HildonWindow
29  *
30  * #HildonStackableWindow is a top-level window that can be stacked on
31  * top of others. It is derived from #HildonWindow. Applications that
32  * use stackable windows are organized in a hierarchical way so users
33  * can go from any window back to the previous one or directly to the
34  * stack's root window.
35  *
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 the user will see the
39  * whole stack as if it was a single window.
40  *
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.
44  *
45  * Alternatively, you can remove a window from the top of the stack
46  * without destroying it by using gtk_widget_hide(). The window will
47  * be hidden and the previous one will appear automatically.
48  *
49  * It is important to note that all #HildonStackableWindow<!-- -->s on
50  * a stack are always mapped and visible (from the Gtk point of view)
51  * and all visible #HildonStackableWindow<!-- -->s are always on a
52  * stack.
53  *
54  * To see how to manage multiple stacks per application and for other
55  * advanced details on stack handling, see #HildonWindowStack
56  *
57  * <example>
58  * <title>Basic HildonStackableWindow example</title>
59  * <programlisting>
60  * static void
61  * show_new_window (void)
62  * {
63  *     GtkWidget *win;
64  * <!-- -->
65  *     win = hildon_stackable_window_new ();
66  * <!-- -->
67  *     // ... configure new window
68  * <!-- -->
69  *     gtk_widget_show (win);
70  * }
71  * <!-- -->
72  * int
73  * main (int argc, char **argv)
74  * {
75  *     GtkWidget *win;
76  *     GtkWidget *button;
77  * <!-- -->
78  *     gtk_init (&amp;argc, &amp;args);
79  * <!-- -->
80  *     win = hildon_stackable_window_new ();
81  *     gtk_window_set_title (GTK_WINDOW (win), "Main window);
82  * <!-- -->
83  *     // ... add some widgets to the window
84  * <!-- -->
85  *     g_signal_connect (button, "clicked", G_CALLBACK (show_new_window), NULL);
86  *     g_signal_connect (win, "destroy", G_CALLBACK (gtk_main_quit), NULL);
87  * <!-- -->
88  *     gtk_widget_show_all (win);
89  *     gtk_main ();
90  * <!-- -->
91  *     return 0;
92  * }
93  * </programlisting>
94  * </example>
95  */
96
97 #undef HILDON_DISABLE_DEPRECATED
98
99 #include                                        <X11/X.h>
100 #include                                        <X11/Xatom.h>
101 #include                                        <gdk/gdkx.h>
102
103 #include                                        "hildon-stackable-window.h"
104 #include                                        "hildon-stackable-window-private.h"
105 #include                                        "hildon-window-stack.h"
106 #include                                        "hildon-window-stack-private.h"
107
108 G_DEFINE_TYPE (HildonStackableWindow, hildon_stackable_window, HILDON_TYPE_WINDOW);
109
110 void G_GNUC_INTERNAL
111 hildon_stackable_window_set_stack               (HildonStackableWindow *self,
112                                                  HildonWindowStack     *stack,
113                                                  gint                   position)
114 {
115     HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
116
117     if (stack)
118         g_object_ref (stack);
119
120     if (priv->stack)
121         g_object_unref (priv->stack);
122
123     priv->stack = stack;
124     priv->stack_position = position;
125 }
126
127 /**
128  * hildon_stackable_window_get_stack:
129  * @self: a #HildonStackableWindow
130  *
131  * Returns the stack where window @self is on, or %NULL if the window
132  * is not stacked.
133  *
134  * Return value: a #HildonWindowStack, or %NULL
135  *
136  * Since: 2.2
137  **/
138 HildonWindowStack *
139 hildon_stackable_window_get_stack               (HildonStackableWindow *self)
140 {
141     HildonStackableWindowPrivate *priv;
142
143     g_return_val_if_fail (HILDON_IS_STACKABLE_WINDOW (self), NULL);
144
145     priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
146
147     return priv->stack;
148 }
149
150 /**
151  * hildon_stackable_window_set_main_menu:
152  * @self: a #HildonStackableWindow
153  * @menu: a #HildonAppMenu to be used for this window
154  *
155  * Sets the menu to be used for this window.
156  *
157  * Deprecated: Hildon 2.2: use hildon_window_set_app_menu()
158  **/
159 void
160 hildon_stackable_window_set_main_menu           (HildonStackableWindow *self,
161                                                  HildonAppMenu *menu)
162 {
163     hildon_window_set_app_menu (HILDON_WINDOW (self), menu);
164 }
165
166 static void
167 hildon_stackable_window_map                     (GtkWidget *widget)
168 {
169     GdkDisplay *display;
170     Atom atom;
171     unsigned long val;
172     HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (widget);
173
174     val = priv->stack_position;
175
176     /* Set additional property "_HILDON_STACKABLE_WINDOW", to allow the WM to manage
177        it as a stackable window. */
178     display = gdk_drawable_get_display (widget->window);
179     atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_STACKABLE_WINDOW");
180     XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (widget->window), atom,
181                      XA_INTEGER, 32, PropModeReplace,
182                      (unsigned char *) &val, 1);
183
184     GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->map (widget);
185 }
186
187 static void
188 hildon_stackable_window_show                    (GtkWidget *widget)
189 {
190     HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (widget);
191
192     /* Stack the window if not already stacked */
193     if (priv->stack == NULL) {
194         HildonWindowStack *stack = hildon_window_stack_get_default ();
195         _hildon_window_stack_do_push (stack, HILDON_STACKABLE_WINDOW (widget));
196     }
197
198     GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->show (widget);
199 }
200
201 static void
202 hildon_stackable_window_hide                    (GtkWidget *widget)
203 {
204     HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (widget);
205
206     if (priv->stack) {
207         hildon_window_stack_remove (HILDON_STACKABLE_WINDOW (widget));
208     }
209
210     GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->hide (widget);
211 }
212
213 static gboolean
214 hildon_stackable_window_delete_event            (GtkWidget   *widget,
215                                                  GdkEventAny *event)
216 {
217     HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (widget);
218     gboolean retvalue = FALSE;
219
220     if (priv->stack && hildon_window_stack_peek (priv->stack) != widget) {
221         /* Ignore the delete event if this window is not the topmost one */
222         retvalue = TRUE;
223     } else if (GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->delete_event) {
224         retvalue = GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->delete_event (widget, event);
225     }
226
227     return retvalue;
228 }
229
230 static void
231 hildon_stackable_window_class_init              (HildonStackableWindowClass *klass)
232 {
233     GtkWidgetClass    *widget_class = GTK_WIDGET_CLASS (klass);
234
235     widget_class->map               = hildon_stackable_window_map;
236     widget_class->show              = hildon_stackable_window_show;
237     widget_class->hide              = hildon_stackable_window_hide;
238     widget_class->delete_event      = hildon_stackable_window_delete_event;
239
240     g_type_class_add_private (klass, sizeof (HildonStackableWindowPrivate));
241 }
242
243 static void
244 hildon_stackable_window_init                    (HildonStackableWindow *self)
245 {
246     HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
247
248     priv->stack = NULL;
249     priv->stack_position = -1;
250 }
251
252 /**
253  * hildon_stackable_window_new:
254  *
255  * Creates a new #HildonStackableWindow.
256  *
257  * Return value: A #HildonStackableWindow
258  *
259  * Since: 2.2
260  **/
261 GtkWidget*
262 hildon_stackable_window_new                     (void)
263 {
264     HildonStackableWindow *newwindow = g_object_new (HILDON_TYPE_STACKABLE_WINDOW, NULL);
265
266     return GTK_WIDGET (newwindow);
267 }