More checks for the case where the overshoot is bigger than the size of the widget.
[hildon] / src / hildon-stackable-window.c
index 03830b4..5fe4642 100644 (file)
  * #HildonWindow. Applications that use stackable windows are organized
  * in a hierarchical way so users can go from any window back to the
  * application's root window.
+ *
+ * To add a window to the stack, use hildon_program_add_window(). Once
+ * you show the new window, the previous one will be automatically
+ * hidden. When the new window is destroyed, the previous one will
+ * appear again.
+ *
+ * <example>
+ * <programlisting>
+ * void
+ * show_first_window (void)
+ * {
+ *     HildonProgram *program;
+ *     GtkWidget *win1;
+ * <!-- -->
+ *     program = hildon_program_get_instance ();
+ *     win1 = hildon_stackable_window_new ();
+ * <!-- -->
+ *     // ... configure first window
+ * <!-- -->
+ *     hildon_program_add_window (program, HILDON_WINDOW (win1));
+ *     gtk_widget_show (win1);
+ * }
+ * <!-- -->
+ * void
+ * show_second_window (void)
+ * {
+ *     HildonProgram *program;
+ *     GtkWidget *win2;
+ * <!-- -->
+ *     program = hildon_program_get_instance ();
+ *     win2 = hildon_stackable_window_new ();
+ * <!-- -->
+ *     // ... configure second window
+ * <!-- -->
+ *     hildon_program_add_window (program, HILDON_WINDOW (win2));
+ *     gtk_widget_show (win2);
+ * }
+ * </programlisting>
+ * </example>
  */
 
 #include                                        <X11/X.h>
 #include                                        <X11/Xatom.h>
 #include                                        "hildon-stackable-window.h"
+#include                                        "hildon-stackable-window-private.h"
 #include                                        "hildon-program.h"
 #include                                        "hildon-window-private.h"
 #include                                        "hildon-program-private.h"
 
-typedef struct                                  _HildonStackableWindowPrivate HildonStackableWindowPrivate;
-
-struct                                          _HildonStackableWindowPrivate
-{
-    gboolean going_home;
-};
-
-#define                                         HILDON_STACKABLE_WINDOW_GET_PRIVATE(obj) \
-                                                (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
-                                                HILDON_TYPE_STACKABLE_WINDOW, HildonStackableWindowPrivate))
-
 G_DEFINE_TYPE (HildonStackableWindow, hildon_stackable_window, HILDON_TYPE_WINDOW);
 
-static void
+void G_GNUC_INTERNAL
 hildon_stackable_window_set_going_home          (HildonStackableWindow *self,
                                                  gboolean going_home)
 {
@@ -61,7 +90,7 @@ hildon_stackable_window_set_going_home          (HildonStackableWindow *self,
     priv->going_home = going_home;
 }
 
-static gboolean
+gboolean G_GNUC_INTERNAL
 hildon_stackable_window_get_going_home          (HildonStackableWindow *self)
 {
     HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (self);
@@ -90,24 +119,28 @@ get_window_list                                 (GtkWidget *widget)
 }
 
 static GtkWidget*
-get_last_window                                 (GtkWidget *widget)
+get_previous_window_if_last                     (GtkWidget *widget)
 {
     GtkWidget *retval = NULL;
-    GSList *windows = get_window_list (widget);
-    GSList *last = NULL;
+    GSList *iter = get_window_list (widget);
+    GSList *previous = NULL;
 
-    g_return_val_if_fail (windows != NULL, NULL);
+    /* Return NULL if the window hasn't been added to the HildonProgram */
+    if (iter == NULL)
+    {
+        return NULL;
+    }
 
     /* Go to the end of the window list */
-    while (windows->next != NULL)
+    while (iter->next != NULL)
     {
-        last = windows;
-        windows = windows->next;
+        previous = iter;
+        iter = iter->next;
     }
 
-    if ((windows->data == widget) && (last != NULL))
+    if ((iter->data == widget) && (previous != NULL))
     {
-        retval = GTK_WIDGET (last->data);
+        retval = GTK_WIDGET (previous->data);
     }
 
     return retval;
@@ -116,48 +149,42 @@ get_last_window                                 (GtkWidget *widget)
 static void
 hildon_stackable_window_map                     (GtkWidget *widget)
 {
-    GtkWidget *lastwin;
+    GtkWidget *previous = get_previous_window_if_last (widget);
 
     if (GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->map)
         GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->map (widget);
 
-    lastwin = get_last_window (widget);
-
-    if (HILDON_IS_STACKABLE_WINDOW (lastwin) && GTK_WIDGET_VISIBLE (lastwin))
-        gtk_widget_hide (lastwin);
+    if (HILDON_IS_STACKABLE_WINDOW (previous) && GTK_WIDGET_VISIBLE (previous))
+        gtk_widget_hide (previous);
 }
 
 static void
 hildon_stackable_window_unmap                   (GtkWidget *widget)
 {
-    GtkWidget *lastwin;
+    GtkWidget *previous = get_previous_window_if_last (widget);
 
     if (GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->unmap)
         GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->unmap (widget);
 
-    lastwin = get_last_window (widget);
-
-    if (HILDON_IS_STACKABLE_WINDOW (lastwin) && !GTK_WIDGET_VISIBLE (lastwin) &&
+    if (HILDON_IS_STACKABLE_WINDOW (previous) && !GTK_WIDGET_VISIBLE (previous) &&
         !hildon_stackable_window_get_going_home (HILDON_STACKABLE_WINDOW (widget)))
     {
-        gtk_widget_show (lastwin);
+        gtk_widget_show (previous);
     }
 }
 
 static void
 hildon_stackable_window_unset_program           (HildonWindow *hwin)
 {
-    GSList *windows = get_window_list (GTK_WIDGET (hwin));
-    gint l = g_slist_length (windows);
-    GtkWidget *nextwin = GTK_WIDGET (g_slist_nth_data (windows, l - 2));
+    GtkWidget *previous = get_previous_window_if_last (GTK_WIDGET (hwin));
 
     if (HILDON_WINDOW_CLASS (hildon_stackable_window_parent_class)->unset_program)
         HILDON_WINDOW_CLASS (hildon_stackable_window_parent_class)->unset_program (hwin);
 
-    if (HILDON_IS_STACKABLE_WINDOW (nextwin) && !GTK_WIDGET_VISIBLE (nextwin) &&
-        !hildon_stackable_window_get_going_home (HILDON_STACKABLE_WINDOW (nextwin)))
+    if (HILDON_IS_STACKABLE_WINDOW (previous) && !GTK_WIDGET_VISIBLE (previous) &&
+        !hildon_stackable_window_get_going_home (HILDON_STACKABLE_WINDOW (hwin)))
     {
-        gtk_widget_show (nextwin);
+        gtk_widget_show (previous);
     }
 }
 
@@ -179,6 +206,22 @@ hildon_stackable_window_realize                 (GtkWidget *widget)
                     (guchar *)&atom, 1);
 }
 
+static gboolean
+hildon_stackable_window_delete_event            (GtkWidget *widget,
+                                                 GdkEventAny *event)
+{
+    GSList *list = get_window_list (widget);
+    list = g_slist_find (list, widget);
+
+    /* Ignore the delete event if this is not the topmost window */
+    if (list != NULL && list->next != NULL)
+        return TRUE;
+    else if (GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->delete_event)
+        return GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->delete_event (widget, event);
+    else
+        return FALSE;
+}
+
 static void
 hildon_stackable_window_class_init              (HildonStackableWindowClass *klass)
 {
@@ -188,6 +231,7 @@ hildon_stackable_window_class_init              (HildonStackableWindowClass *kla
     widget_class->map               = hildon_stackable_window_map;
     widget_class->unmap             = hildon_stackable_window_unmap;
     widget_class->realize           = hildon_stackable_window_realize;
+    widget_class->delete_event      = hildon_stackable_window_delete_event;
 
     window_class->unset_program     = hildon_stackable_window_unset_program;
 
@@ -214,38 +258,3 @@ hildon_stackable_window_new                     (void)
 
     return GTK_WIDGET (newwindow);
 }
-
-/**
- * hildon_stackable_window_go_to_root_window:
- * @self: A #HildonStackableWindow
- *
- * Will pop out all the stackable windows in the @HildonProgram but the
- * first one, which can be considered as the "home" window.
- */
-void
-hildon_stackable_window_go_to_root_window       (HildonStackableWindow *self)
-{
-    g_return_if_fail (HILDON_IS_STACKABLE_WINDOW (self));
-
-    GSList *windows       = get_window_list (GTK_WIDGET (self));
-    GSList *tmp           = NULL;
-    HildonWindow *rootwin = HILDON_WINDOW (g_slist_nth_data (windows, 0));
-
-    g_return_if_fail (rootwin != NULL);
-
-    tmp = g_slist_nth (windows, 1);
-    while (tmp != NULL)
-    {
-        if (HILDON_IS_STACKABLE_WINDOW (tmp->data))
-        {
-            HildonStackableWindow *win = HILDON_STACKABLE_WINDOW (tmp->data);
-            hildon_stackable_window_set_going_home (win, TRUE);
-            gtk_widget_destroy (GTK_WIDGET (win));
-        }
-
-        tmp = g_slist_nth (windows, 1);
-    }
-
-    if (!GTK_WIDGET_VISIBLE (rootwin))
-        gtk_widget_show (GTK_WIDGET (rootwin));
-}