* src/hildon-*.c * src/hildon-*.h: Ensure a consistent include order, include <gtk...
[hildon] / src / hildon-program.c
index 9cc94f0..6f50388 100644 (file)
@@ -47,8 +47,8 @@
  * <example>
  * <programlisting>
  * HildonProgram *program;
- * HildonWindow *first_window;
- * HildonWindow *second_window;
+ * HildonWindow *window1;
+ * HildonWindow *window2;
  * GtkToolbar *common_toolbar, *window_specific_toolbar;
  * GtkMenu *menu;
  * <!-- -->
@@ -68,7 +68,7 @@
  * hildon_program_set_common_menu (program, menu);
  * <!-- -->
  * hildon_program_set_common_toolbar (program, common_toolbar);
- * hildon_window_add_toolbar (first_window, window_specific_toolbar);
+ * hildon_window_add_toolbar (window1, window_specific_toolbar);
  * <!-- -->
  * hildon_program_set_can_hibernate (program, TRUE);
  * </programlisting>
 #include                                        <config.h>
 #endif
 
+#include                                        <X11/Xatom.h>
+
 #include                                        "hildon-program.h"
 #include                                        "hildon-program-private.h"
 #include                                        "hildon-window-private.h"
-#include                                        <X11/Xatom.h>
+#include                                        "hildon-stackable-window-private.h"
 
 static void
 hildon_program_init                             (HildonProgram *self);
@@ -148,6 +150,8 @@ hildon_program_init                             (HildonProgram *self)
     priv->window_group = GDK_WINDOW_XID (gdk_display_get_default_group (gdk_display_get_default()));
     priv->common_toolbar = NULL;
     priv->name = NULL;
+    priv->windows = NULL;
+    priv->window_stack = NULL;
 }
 
 static void
@@ -259,6 +263,125 @@ hildon_program_get_property                     (GObject *object,
     }
 }
 
+/**
+ * hildon_program_pop_window_stack:
+ * @self: A #HildonProgram
+ *
+ * The #HildonProgram object maintains a list of stackable
+ * windows. Each time a #HildonStackableWindow is shown, it is
+ * automatically added to the top of the stack. Windows are removed
+ * from the stack when they are destroyed.
+ *
+ * This function removes the #HildonStackableWindow from the top of
+ * the stack and returns it. The window is automatically hidden, but
+ * not destroyed. If that window was visible and there are more
+ * windows left in the stack, the next one will be shown
+ * automatically.
+ *
+ * If the stack is empty, %NULL is returned.
+ *
+ * Returns: A #HildonStackableWindow, or %NULL.
+ */
+HildonStackableWindow *
+hildon_program_pop_window_stack                 (HildonProgram *self)
+{
+    HildonStackableWindow *top;
+
+    top = hildon_program_peek_window_stack (self);
+
+    if (top)
+    {
+        HildonStackableWindow *next;
+
+        /* Remove the window from the stack and get the next one */
+        _hildon_program_remove_from_stack (self, top);
+        next = hildon_program_peek_window_stack (self);
+
+        /* Hide the window just removed and show the next one if necessary */
+        if (GTK_WIDGET_VISIBLE (GTK_WIDGET (top)) && next != NULL);
+            gtk_widget_show (GTK_WIDGET (next));
+
+        gtk_widget_hide (GTK_WIDGET (top));
+    }
+
+    return top;
+}
+
+/**
+ * hildon_program_peek_window_stack:
+ * @self: A #HildonProgram
+ *
+ * The #HildonProgram object maintains a list of stackable
+ * windows. Each time a #HildonStackableWindow is shown, it is
+ * automatically added to the top of the stack. Windows are removed
+ * from the stack when they are destroyed.
+ *
+ * This function returns the #HildonStackableWindow from the top of
+ * the stack or %NULL if the stack is empty. The stack is never modified.
+ *
+ * Returns: A #HildonStackableWindow, or %NULL.
+ */
+HildonStackableWindow *
+hildon_program_peek_window_stack                (HildonProgram *self)
+{
+    HildonStackableWindow *top = NULL;
+    HildonProgramPrivate *priv;
+
+    g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
+
+    priv = HILDON_PROGRAM_GET_PRIVATE (self);
+    g_assert (priv);
+
+    if (priv->window_stack != NULL)
+        top = HILDON_STACKABLE_WINDOW (priv->window_stack->data);
+
+    return top;
+}
+
+void G_GNUC_INTERNAL
+_hildon_program_add_to_stack                    (HildonProgram         *self,
+                                                 HildonStackableWindow *win)
+{
+    HildonProgramPrivate *priv;
+
+    g_return_if_fail (HILDON_IS_PROGRAM (self));
+    g_return_if_fail (HILDON_IS_STACKABLE_WINDOW (win));
+
+    priv = HILDON_PROGRAM_GET_PRIVATE (self);
+    g_assert (priv);
+
+    if (g_slist_find (priv->window_stack, win) == NULL)
+    {
+        priv->window_stack = g_slist_prepend (priv->window_stack, win);
+    }
+    else
+    {
+        g_critical ("%s: window already in the stack!", __FUNCTION__);
+    }
+
+}
+
+gboolean G_GNUC_INTERNAL
+_hildon_program_remove_from_stack               (HildonProgram         *self,
+                                                 HildonStackableWindow *win)
+{
+    GSList *pos;
+    HildonProgramPrivate *priv;
+
+    g_return_val_if_fail (HILDON_IS_PROGRAM (self), FALSE);
+    g_return_val_if_fail (HILDON_IS_STACKABLE_WINDOW (win), FALSE);
+
+    priv = HILDON_PROGRAM_GET_PRIVATE (self);
+    g_assert (priv);
+
+    pos = g_slist_find (priv->window_stack, win);
+
+    if (pos != NULL)
+        priv->window_stack = g_slist_delete_link (priv->window_stack, pos);
+
+    return (pos != NULL);
+}
+
 /* Utilities */
 static gint 
 hildon_program_window_list_compare              (gconstpointer window_a, 
@@ -684,3 +807,80 @@ hildon_program_get_is_topmost                   (HildonProgram *self)
 
     return priv->is_topmost;
 }
+
+/**
+ * hildon_program_go_to_root_window:
+ * @self: A #HildonProgram
+ *
+ * Will close all windows in the #HildonProgram but the first one (the
+ * root window) by sending them a delete event. If any of the windows
+ * refuses to close (by handling it) no further events will be
+ * sent. All windows in the program must be #HildonStackableWindow for
+ * this to work.
+ */
+void
+hildon_program_go_to_root_window                (HildonProgram *self)
+{
+    HildonProgramPrivate *priv;
+    GSList *windows, *iter;
+    gboolean windows_left;
+
+    g_return_if_fail (HILDON_IS_PROGRAM (self));
+    priv = HILDON_PROGRAM_GET_PRIVATE (self);
+    g_assert (priv);
+
+    /* List of stacked windows (starting from the topmost one) */
+    windows = g_slist_copy (priv->window_stack);
+    iter = windows;
+
+    /* Destroy all the windows but the last one (which is the root
+     * window, as the list is reversed) */
+    windows_left = (iter != NULL && iter->next != NULL);
+    while (windows_left)
+    {
+        if (HILDON_IS_STACKABLE_WINDOW (iter->data))
+        {
+            GdkEvent *event;
+            HildonStackableWindow *win;
+
+            /* Mark the window as "going home" */
+            win = HILDON_STACKABLE_WINDOW (iter->data);
+            hildon_stackable_window_set_going_home (win, TRUE);
+
+            /* Set win pointer to NULL if the window is destroyed */
+            g_object_add_weak_pointer (G_OBJECT (win), (gpointer) &win);
+
+            /* Send a delete event */
+            event = gdk_event_new (GDK_DELETE);
+            event->any.window = g_object_ref (GTK_WIDGET (win)->window);
+            gtk_main_do_event (event);
+            gdk_event_free (event);
+
+            /* Continue sending delete events if the window has been destroyed */
+            if (win == NULL)
+            {
+                iter = iter->next;
+                windows_left = (iter != NULL && iter->next != NULL);
+            }
+            else
+            {
+                g_object_remove_weak_pointer (G_OBJECT (win), (gpointer) &win);
+                hildon_stackable_window_set_going_home (win, FALSE);
+                windows_left = FALSE;
+            }
+        }
+        else
+        {
+            g_critical ("Window list contains a non-stackable window");
+            windows_left = FALSE;
+        }
+    }
+
+    /* Show the last window that hasn't been destroyed */
+    if (iter != NULL && GTK_IS_WIDGET (iter->data))
+    {
+        gtk_widget_show (GTK_WIDGET (iter->data));
+    }
+
+    g_slist_free (windows);
+}