* examples/hildon-stackable-window-example.c * src/hildon-stackable-window.c * src...
[hildon] / src / hildon-stackable-window.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2008 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Karl Lattimer <karl.lattimer@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: Widget representing a stackable, top-level window in the Hildon framework.
28  *
29  * The #HildonStackableWindow is a GTK+ widget which represents a
30  * top-level window in the Hildon framework. It is derived from
31  * #HildonWindow. Applications that use stackable windows are organized
32  * in a hierarchical way so users can go from any window back to the
33  * application's root window.
34  */
35
36 #include                                        <X11/X.h>
37 #include                                        <X11/Xatom.h>
38 #include                                        "hildon-stackable-window.h"
39 #include                                        "hildon-program.h"
40 #include                                        "hildon-window-private.h"
41 #include                                        "hildon-program-private.h"
42
43 typedef struct                                  _HildonStackableWindowPrivate HildonStackableWindowPrivate;
44
45 struct                                          _HildonStackableWindowPrivate
46 {
47     gboolean going_home;
48 };
49
50 #define                                         HILDON_STACKABLE_WINDOW_GET_PRIVATE(obj) \
51                                                 (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
52                                                 HILDON_TYPE_STACKABLE_WINDOW, HildonStackableWindowPrivate))
53
54 G_DEFINE_TYPE (HildonStackableWindow, hildon_stackable_window, HILDON_TYPE_WINDOW);
55
56 static void
57 hildon_stackable_window_set_going_home          (HildonStackableWindow *self,
58                                                  gboolean going_home)
59 {
60     HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
61     priv->going_home = going_home;
62 }
63
64 static gboolean
65 hildon_stackable_window_get_going_home          (HildonStackableWindow *self)
66 {
67     HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
68     return priv->going_home;
69 }
70
71 static GSList*
72 get_window_list                                 (GtkWidget *widget)
73 {
74     HildonWindowPrivate *wpriv;
75     HildonProgramPrivate *ppriv;
76     GSList *retval = NULL;
77     g_return_val_if_fail (widget != NULL, NULL);
78
79     wpriv = HILDON_WINDOW_GET_PRIVATE (widget);
80     g_assert (wpriv != NULL);
81
82     if (wpriv->program)
83     {
84         ppriv = HILDON_PROGRAM_GET_PRIVATE (wpriv->program);
85         g_assert (ppriv != NULL);
86         retval = ppriv->windows;
87     }
88
89     return retval;
90 }
91
92 static GtkWidget*
93 get_last_window                                 (GtkWidget *widget)
94 {
95     GtkWidget *retval = NULL;
96     GSList *windows = get_window_list (widget);
97     GSList *last = NULL;
98
99     g_return_val_if_fail (windows != NULL, NULL);
100
101     /* Go to the end of the window list */
102     while (windows->next != NULL)
103     {
104         last = windows;
105         windows = windows->next;
106     }
107
108     if ((windows->data == widget) && (last != NULL))
109     {
110         retval = GTK_WIDGET (last->data);
111     }
112
113     return retval;
114 }
115
116 static void
117 hildon_stackable_window_map                     (GtkWidget *widget)
118 {
119     GtkWidget *lastwin;
120
121     if (GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->map)
122         GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->map (widget);
123
124     lastwin = get_last_window (widget);
125
126     if (HILDON_IS_STACKABLE_WINDOW (lastwin) && GTK_WIDGET_VISIBLE (lastwin))
127         gtk_widget_hide (lastwin);
128 }
129
130 static void
131 hildon_stackable_window_unmap                   (GtkWidget *widget)
132 {
133     GtkWidget *lastwin;
134
135     if (GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->unmap)
136         GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->unmap (widget);
137
138     lastwin = get_last_window (widget);
139
140     if (HILDON_IS_STACKABLE_WINDOW (lastwin) && !GTK_WIDGET_VISIBLE (lastwin) &&
141         !hildon_stackable_window_get_going_home (HILDON_STACKABLE_WINDOW (widget)))
142     {
143         gtk_widget_show (lastwin);
144     }
145 }
146
147 static void
148 hildon_stackable_window_unset_program           (HildonWindow *hwin)
149 {
150     GSList *windows = get_window_list (GTK_WIDGET (hwin));
151     gint l = g_slist_length (windows);
152     GtkWidget *nextwin = GTK_WIDGET (g_slist_nth_data (windows, l - 2));
153
154     if (HILDON_WINDOW_CLASS (hildon_stackable_window_parent_class)->unset_program)
155         HILDON_WINDOW_CLASS (hildon_stackable_window_parent_class)->unset_program (hwin);
156
157     if (HILDON_IS_STACKABLE_WINDOW (nextwin) && !GTK_WIDGET_VISIBLE (nextwin) &&
158         !hildon_stackable_window_get_going_home (HILDON_STACKABLE_WINDOW (nextwin)))
159     {
160         gtk_widget_show (nextwin);
161     }
162 }
163
164 static void
165 hildon_stackable_window_realize                 (GtkWidget *widget)
166 {
167     GdkDisplay *display;
168     Atom atom;
169
170     GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->realize (widget);
171
172     /* Set the window type to "_HILDON_WM_WINDOW_TYPE_STACKABLE", to allow the WM to manage
173        it properly.  */
174     display = gdk_drawable_get_display (widget->window);
175     atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_WM_WINDOW_TYPE_STACKABLE");
176     XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (widget->window),
177                      gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE"),
178                      XA_ATOM, 32, PropModeAppend,
179                      (guchar *)&atom, 1);
180 }
181
182 static void
183 hildon_stackable_window_class_init              (HildonStackableWindowClass *klass)
184 {
185     GtkWidgetClass    *widget_class = GTK_WIDGET_CLASS (klass);
186     HildonWindowClass *window_class = HILDON_WINDOW_CLASS (klass);
187
188     widget_class->map               = hildon_stackable_window_map;
189     widget_class->unmap             = hildon_stackable_window_unmap;
190     widget_class->realize           = hildon_stackable_window_realize;
191
192     window_class->unset_program     = hildon_stackable_window_unset_program;
193
194     g_type_class_add_private (klass, sizeof (HildonStackableWindowPrivate));
195 }
196
197 static void
198 hildon_stackable_window_init                    (HildonStackableWindow *self)
199 {
200     hildon_stackable_window_set_going_home (self, FALSE);
201 }
202
203 /**
204  * hildon_stackable_window_new:
205  *
206  * Creates a new #HildonStackableWindow.
207  *
208  * Return value: A #HildonStackableWindow
209  **/
210 GtkWidget*
211 hildon_stackable_window_new                     (void)
212 {
213     HildonStackableWindow *newwindow = g_object_new (HILDON_TYPE_STACKABLE_WINDOW, NULL);
214
215     return GTK_WIDGET (newwindow);
216 }
217
218 /**
219  * hildon_stackable_window_go_to_root_window:
220  * @self: A #HildonStackableWindow
221  *
222  * Will pop out all the stackable windows in the @HildonProgram but the
223  * first one, which can be considered as the "home" window.
224  */
225 void
226 hildon_stackable_window_go_to_root_window       (HildonStackableWindow *self)
227 {
228     g_return_if_fail (HILDON_IS_STACKABLE_WINDOW (self));
229
230     GSList *windows       = get_window_list (GTK_WIDGET (self));
231     GSList *tmp           = NULL;
232     HildonWindow *rootwin = HILDON_WINDOW (g_slist_nth_data (windows, 0));
233
234     g_return_if_fail (rootwin != NULL);
235
236     tmp = g_slist_nth (windows, 1);
237     while (tmp != NULL)
238     {
239         if (HILDON_IS_STACKABLE_WINDOW (tmp->data))
240         {
241             HildonStackableWindow *win = HILDON_STACKABLE_WINDOW (tmp->data);
242             hildon_stackable_window_set_going_home (win, TRUE);
243             gtk_widget_destroy (GTK_WIDGET (win));
244         }
245
246         tmp = g_slist_nth (windows, 1);
247     }
248
249     if (!GTK_WIDGET_VISIBLE (rootwin))
250         gtk_widget_show (GTK_WIDGET (rootwin));
251 }