2 * This file is a part of hildon
4 * Copyright (C) 2008 Nokia Corporation, all rights reserved.
6 * Contact: Karl Lattimer <karl.lattimer@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.
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.
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"
43 typedef struct _HildonStackableWindowPrivate HildonStackableWindowPrivate;
45 struct _HildonStackableWindowPrivate
50 #define HILDON_STACKABLE_WINDOW_GET_PRIVATE(obj) \
51 (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
52 HILDON_TYPE_STACKABLE_WINDOW, HildonStackableWindowPrivate))
54 G_DEFINE_TYPE (HildonStackableWindow, hildon_stackable_window, HILDON_TYPE_WINDOW);
57 hildon_stackable_window_set_going_home (HildonStackableWindow *self,
60 HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
61 priv->going_home = going_home;
65 hildon_stackable_window_get_going_home (HildonStackableWindow *self)
67 HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
68 return priv->going_home;
72 get_window_list (GtkWidget *widget)
74 HildonWindowPrivate *wpriv;
75 HildonProgramPrivate *ppriv;
76 GSList *retval = NULL;
77 g_return_val_if_fail (widget != NULL, NULL);
79 wpriv = HILDON_WINDOW_GET_PRIVATE (widget);
80 g_assert (wpriv != NULL);
84 ppriv = HILDON_PROGRAM_GET_PRIVATE (wpriv->program);
85 g_assert (ppriv != NULL);
86 retval = ppriv->windows;
93 get_last_window (GtkWidget *widget)
95 GtkWidget *retval = NULL;
96 GSList *windows = get_window_list (widget);
99 g_return_val_if_fail (windows != NULL, NULL);
101 /* Go to the end of the window list */
102 while (windows->next != NULL)
105 windows = windows->next;
108 if ((windows->data == widget) && (last != NULL))
110 retval = GTK_WIDGET (last->data);
117 hildon_stackable_window_map (GtkWidget *widget)
121 if (GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->map)
122 GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->map (widget);
124 lastwin = get_last_window (widget);
126 if (HILDON_IS_STACKABLE_WINDOW (lastwin) && GTK_WIDGET_VISIBLE (lastwin))
127 gtk_widget_hide (lastwin);
131 hildon_stackable_window_unmap (GtkWidget *widget)
135 if (GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->unmap)
136 GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->unmap (widget);
138 lastwin = get_last_window (widget);
140 if (HILDON_IS_STACKABLE_WINDOW (lastwin) && !GTK_WIDGET_VISIBLE (lastwin) &&
141 !hildon_stackable_window_get_going_home (HILDON_STACKABLE_WINDOW (widget)))
143 gtk_widget_show (lastwin);
148 hildon_stackable_window_unset_program (HildonWindow *hwin)
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));
154 if (HILDON_WINDOW_CLASS (hildon_stackable_window_parent_class)->unset_program)
155 HILDON_WINDOW_CLASS (hildon_stackable_window_parent_class)->unset_program (hwin);
157 if (HILDON_IS_STACKABLE_WINDOW (nextwin) && !GTK_WIDGET_VISIBLE (nextwin) &&
158 !hildon_stackable_window_get_going_home (HILDON_STACKABLE_WINDOW (hwin)))
160 gtk_widget_show (nextwin);
165 hildon_stackable_window_realize (GtkWidget *widget)
170 GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->realize (widget);
172 /* Set the window type to "_HILDON_WM_WINDOW_TYPE_STACKABLE", to allow the WM to manage
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,
183 hildon_stackable_window_delete_event (GtkWidget *widget,
186 GSList *list = get_window_list (widget);
187 list = g_slist_find (list, widget);
189 /* Ignore the delete event if this is not the topmost window */
190 if (list != NULL && list->next != NULL)
192 else if (GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->delete_event)
193 return GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->delete_event (widget, event);
199 hildon_stackable_window_class_init (HildonStackableWindowClass *klass)
201 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
202 HildonWindowClass *window_class = HILDON_WINDOW_CLASS (klass);
204 widget_class->map = hildon_stackable_window_map;
205 widget_class->unmap = hildon_stackable_window_unmap;
206 widget_class->realize = hildon_stackable_window_realize;
207 widget_class->delete_event = hildon_stackable_window_delete_event;
209 window_class->unset_program = hildon_stackable_window_unset_program;
211 g_type_class_add_private (klass, sizeof (HildonStackableWindowPrivate));
215 hildon_stackable_window_init (HildonStackableWindow *self)
217 hildon_stackable_window_set_going_home (self, FALSE);
221 * hildon_stackable_window_new:
223 * Creates a new #HildonStackableWindow.
225 * Return value: A #HildonStackableWindow
228 hildon_stackable_window_new (void)
230 HildonStackableWindow *newwindow = g_object_new (HILDON_TYPE_STACKABLE_WINDOW, NULL);
232 return GTK_WIDGET (newwindow);
236 * hildon_stackable_window_go_to_root_window:
237 * @self: A #HildonStackableWindow
239 * Will close all the stackable windows in the @HildonProgram but the
240 * first one (the root window) by sending them a delete event. If any
241 * of the windows refuses to close (by handling it) no further events
245 hildon_stackable_window_go_to_root_window (HildonStackableWindow *self)
247 GSList *windows, *iter;
248 gboolean windows_left;
250 g_return_if_fail (HILDON_IS_STACKABLE_WINDOW (self));
252 /* List of windows in reverse order (starting from the topmost one) */
253 windows = g_slist_reverse (g_slist_copy (get_window_list (GTK_WIDGET (self))));
256 /* Destroy all the windows but the last one (which is the root
257 * window, as the list is reversed) */
258 windows_left = (iter != NULL && iter->next != NULL);
261 if (HILDON_IS_STACKABLE_WINDOW (iter->data))
264 HildonStackableWindow *win;
266 /* Mark the window as "going home" */
267 win = HILDON_STACKABLE_WINDOW (iter->data);
268 hildon_stackable_window_set_going_home (win, TRUE);
270 /* Set win pointer to NULL if the window is destroyed */
271 g_object_add_weak_pointer (G_OBJECT (win), (gpointer) &win);
273 /* Send a delete event */
274 event = gdk_event_new (GDK_DELETE);
275 event->any.window = g_object_ref (GTK_WIDGET (win)->window);
276 gtk_main_do_event (event);
277 gdk_event_free (event);
279 /* Continue sending delete events if the window has been destroyed */
283 windows_left = (iter != NULL && iter->next != NULL);
287 g_object_remove_weak_pointer (G_OBJECT (win), (gpointer) &win);
288 hildon_stackable_window_set_going_home (win, FALSE);
289 windows_left = FALSE;
294 g_warning ("Window list contains a non-stackable window");
295 windows_left = FALSE;
299 /* Show the last window that hasn't been destroyed */
300 if (iter != NULL && GTK_IS_WIDGET (iter->data))
302 gtk_widget_show (GTK_WIDGET (iter->data));
305 g_slist_free (windows);