* examples/hildon-stackable-window-example.c (new_window): * src/Makefile.am (noinst_...
[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-stackable-window-private.h"
40 #include                                        "hildon-program.h"
41 #include                                        "hildon-window-private.h"
42 #include                                        "hildon-program-private.h"
43
44 G_DEFINE_TYPE (HildonStackableWindow, hildon_stackable_window, HILDON_TYPE_WINDOW);
45
46 void G_GNUC_INTERNAL
47 hildon_stackable_window_set_going_home          (HildonStackableWindow *self,
48                                                  gboolean going_home)
49 {
50     HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
51     priv->going_home = going_home;
52 }
53
54 gboolean G_GNUC_INTERNAL
55 hildon_stackable_window_get_going_home          (HildonStackableWindow *self)
56 {
57     HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
58     return priv->going_home;
59 }
60
61 static GSList*
62 get_window_list                                 (GtkWidget *widget)
63 {
64     HildonWindowPrivate *wpriv;
65     HildonProgramPrivate *ppriv;
66     GSList *retval = NULL;
67     g_return_val_if_fail (widget != NULL, NULL);
68
69     wpriv = HILDON_WINDOW_GET_PRIVATE (widget);
70     g_assert (wpriv != NULL);
71
72     if (wpriv->program)
73     {
74         ppriv = HILDON_PROGRAM_GET_PRIVATE (wpriv->program);
75         g_assert (ppriv != NULL);
76         retval = ppriv->windows;
77     }
78
79     return retval;
80 }
81
82 static GtkWidget*
83 get_last_window                                 (GtkWidget *widget)
84 {
85     GtkWidget *retval = NULL;
86     GSList *windows = get_window_list (widget);
87     GSList *last = NULL;
88
89     g_return_val_if_fail (windows != NULL, NULL);
90
91     /* Go to the end of the window list */
92     while (windows->next != NULL)
93     {
94         last = windows;
95         windows = windows->next;
96     }
97
98     if ((windows->data == widget) && (last != NULL))
99     {
100         retval = GTK_WIDGET (last->data);
101     }
102
103     return retval;
104 }
105
106 static void
107 hildon_stackable_window_map                     (GtkWidget *widget)
108 {
109     GtkWidget *lastwin;
110
111     if (GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->map)
112         GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->map (widget);
113
114     lastwin = get_last_window (widget);
115
116     if (HILDON_IS_STACKABLE_WINDOW (lastwin) && GTK_WIDGET_VISIBLE (lastwin))
117         gtk_widget_hide (lastwin);
118 }
119
120 static void
121 hildon_stackable_window_unmap                   (GtkWidget *widget)
122 {
123     GtkWidget *lastwin;
124
125     if (GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->unmap)
126         GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->unmap (widget);
127
128     lastwin = get_last_window (widget);
129
130     if (HILDON_IS_STACKABLE_WINDOW (lastwin) && !GTK_WIDGET_VISIBLE (lastwin) &&
131         !hildon_stackable_window_get_going_home (HILDON_STACKABLE_WINDOW (widget)))
132     {
133         gtk_widget_show (lastwin);
134     }
135 }
136
137 static void
138 hildon_stackable_window_unset_program           (HildonWindow *hwin)
139 {
140     GSList *windows = get_window_list (GTK_WIDGET (hwin));
141     gint l = g_slist_length (windows);
142     GtkWidget *nextwin = GTK_WIDGET (g_slist_nth_data (windows, l - 2));
143
144     if (HILDON_WINDOW_CLASS (hildon_stackable_window_parent_class)->unset_program)
145         HILDON_WINDOW_CLASS (hildon_stackable_window_parent_class)->unset_program (hwin);
146
147     if (HILDON_IS_STACKABLE_WINDOW (nextwin) && !GTK_WIDGET_VISIBLE (nextwin) &&
148         !hildon_stackable_window_get_going_home (HILDON_STACKABLE_WINDOW (hwin)))
149     {
150         gtk_widget_show (nextwin);
151     }
152 }
153
154 static void
155 hildon_stackable_window_realize                 (GtkWidget *widget)
156 {
157     GdkDisplay *display;
158     Atom atom;
159
160     GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->realize (widget);
161
162     /* Set the window type to "_HILDON_WM_WINDOW_TYPE_STACKABLE", to allow the WM to manage
163        it properly.  */
164     display = gdk_drawable_get_display (widget->window);
165     atom = gdk_x11_get_xatom_by_name_for_display (display, "_HILDON_WM_WINDOW_TYPE_STACKABLE");
166     XChangeProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (widget->window),
167                      gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_WINDOW_TYPE"),
168                      XA_ATOM, 32, PropModeAppend,
169                      (guchar *)&atom, 1);
170 }
171
172 static gboolean
173 hildon_stackable_window_delete_event            (GtkWidget *widget,
174                                                  GdkEventAny *event)
175 {
176     GSList *list = get_window_list (widget);
177     list = g_slist_find (list, widget);
178
179     /* Ignore the delete event if this is not the topmost window */
180     if (list != NULL && list->next != NULL)
181         return TRUE;
182     else if (GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->delete_event)
183         return GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->delete_event (widget, event);
184     else
185         return FALSE;
186 }
187
188 static void
189 hildon_stackable_window_class_init              (HildonStackableWindowClass *klass)
190 {
191     GtkWidgetClass    *widget_class = GTK_WIDGET_CLASS (klass);
192     HildonWindowClass *window_class = HILDON_WINDOW_CLASS (klass);
193
194     widget_class->map               = hildon_stackable_window_map;
195     widget_class->unmap             = hildon_stackable_window_unmap;
196     widget_class->realize           = hildon_stackable_window_realize;
197     widget_class->delete_event      = hildon_stackable_window_delete_event;
198
199     window_class->unset_program     = hildon_stackable_window_unset_program;
200
201     g_type_class_add_private (klass, sizeof (HildonStackableWindowPrivate));
202 }
203
204 static void
205 hildon_stackable_window_init                    (HildonStackableWindow *self)
206 {
207     hildon_stackable_window_set_going_home (self, FALSE);
208 }
209
210 /**
211  * hildon_stackable_window_new:
212  *
213  * Creates a new #HildonStackableWindow.
214  *
215  * Return value: A #HildonStackableWindow
216  **/
217 GtkWidget*
218 hildon_stackable_window_new                     (void)
219 {
220     HildonStackableWindow *newwindow = g_object_new (HILDON_TYPE_STACKABLE_WINDOW, NULL);
221
222     return GTK_WIDGET (newwindow);
223 }