+2008-08-08 Alberto Garcia <agarcia@igalia.com>
+
+ * src/hildon-program-private.h
+ * src/hildon-program.c
+ * src/hildon-program.h
+ (_hildon_program_remove_from_stack, _hildon_program_add_to_stack)
+ (hildon_program_peek_window_stack)
+ (hildon_program_pop_window_stack)
+ (hildon_program_go_to_root_window): HildonProgram now has a
+ separate list for stackable windows. Functions are provided to
+ manage that list with a stack-like API.
+
+ * src/hildon-stackable-window.c: Stackable window management is
+ now much simpler with the new HildonProgram API. Windows no
+ longer need to be manually added to the program, they're
+ automatically pushed to the top of the stack when shown.
+
+ * examples/hildon-stackable-window-example.c: Updated example to
+ reflect the API changes.
+
2008-08-07 Claudio Saavedra <csaavedra@igalia.com>
* src/hildon-touch-selector.c: Comment out unimplemented
static void
add_window (GtkWidget* w);
-static void
-detach_window (GtkWidget* w)
-{
- HildonProgram *program = hildon_program_get_instance ();
- hildon_program_remove_window (program, HILDON_WINDOW (w));
-}
-
static GtkWidget*
new_window (gboolean ismain)
{
if (!ismain)
{
GtkWidget *detach, *back;
- detach = GTK_WIDGET (gtk_button_new_with_label ("Detach"));
+ detach = GTK_WIDGET (gtk_button_new_with_label ("Destroy"));
gtk_box_pack_end (GTK_BOX (hbbox), detach, FALSE, FALSE, 0);
g_signal_connect_swapped (G_OBJECT (detach), "clicked",
- G_CALLBACK (detach_window),
+ G_CALLBACK (gtk_widget_destroy),
HILDON_STACKABLE_WINDOW (window));
back = GTK_WIDGET (gtk_button_new_with_label ("Back to root"));
add_window (GtkWidget *w)
{
GtkWidget *window = new_window (FALSE);
- HildonProgram *program = hildon_program_get_instance ();
-
- hildon_program_add_window (program, HILDON_WINDOW (window));
-
gtk_widget_show_all (window);
return;
main (int argc,
char **args)
{
- HildonProgram *program;
GtkWidget *window;
gtk_init (&argc, &args);
g_set_application_name ("stack");
- program = hildon_program_get_instance ();
window = new_window (TRUE);
- hildon_program_add_window (program, HILDON_WINDOW (window));
g_signal_connect (G_OBJECT (window), "delete_event",
G_CALLBACK (gtk_main_quit), NULL);
#include <glib-object.h>
#include "hildon-window.h"
+#include "hildon-stackable-window.h"
G_BEGIN_DECLS
GtkWidget *common_menu;
GtkWidget *common_toolbar;
GSList *windows;
+ GSList *window_stack;
Window window_group;
gchar *name;
};
+void G_GNUC_INTERNAL
+_hildon_program_add_to_stack (HildonProgram *self,
+ HildonStackableWindow *win);
+
+gboolean G_GNUC_INTERNAL
+_hildon_program_remove_from_stack (HildonProgram *self,
+ HildonStackableWindow *win);
+
G_END_DECLS
#endif /* __HILDON_PROGRAM_PRIVATE_H__ */
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
}
}
+/**
+ * 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,
priv = HILDON_PROGRAM_GET_PRIVATE (self);
g_assert (priv);
- /* List of windows in reverse order (starting from the topmost one) */
- windows = g_slist_reverse (g_slist_copy (priv->windows));
+ /* 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
}
else
{
- g_warning ("Window list contains a non-stackable window");
+ g_critical ("Window list contains a non-stackable window");
windows_left = FALSE;
}
}
#include <glib-object.h>
#include "hildon-window.h"
+#include "hildon-stackable-window.h"
G_BEGIN_DECLS
gboolean
hildon_program_get_is_topmost (HildonProgram *self);
+HildonStackableWindow *
+hildon_program_pop_window_stack (HildonProgram *self);
+
+HildonStackableWindow *
+hildon_program_peek_window_stack (HildonProgram *self);
+
void
hildon_program_go_to_root_window (HildonProgram *self);
* 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.
+ * To add a window to the stack, just use gtk_widget_show(). The
+ * previous one will be automatically hidden. When the new window is
+ * destroyed, the previous one will appear again.
*
* <example>
* <programlisting>
* <!-- -->
* // ... configure first window
* <!-- -->
- * hildon_program_add_window (program, HILDON_WINDOW (win1));
* gtk_widget_show (win1);
* }
* <!-- -->
* <!-- -->
* // ... configure second window
* <!-- -->
- * hildon_program_add_window (program, HILDON_WINDOW (win2));
* gtk_widget_show (win2);
* }
* </programlisting>
return priv->going_home;
}
-static GSList*
-get_window_list (GtkWidget *widget)
-{
- HildonWindowPrivate *wpriv;
- HildonProgramPrivate *ppriv;
- GSList *retval = NULL;
- g_return_val_if_fail (widget != NULL, NULL);
-
- wpriv = HILDON_WINDOW_GET_PRIVATE (widget);
- g_assert (wpriv != NULL);
-
- if (wpriv->program)
- {
- ppriv = HILDON_PROGRAM_GET_PRIVATE (wpriv->program);
- g_assert (ppriv != NULL);
- retval = ppriv->windows;
- }
-
- return retval;
-}
-
-static GtkWidget*
-get_previous_window_if_last (GtkWidget *widget)
-{
- GtkWidget *retval = NULL;
- GSList *iter = get_window_list (widget);
- GSList *previous = 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 (iter->next != NULL)
- {
- previous = iter;
- iter = iter->next;
- }
-
- if ((iter->data == widget) && (previous != NULL))
- {
- retval = GTK_WIDGET (previous->data);
- }
-
- return retval;
-}
-
-static void
-hildon_stackable_window_map (GtkWidget *widget)
-{
- 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);
-
- if (HILDON_IS_STACKABLE_WINDOW (previous) && GTK_WIDGET_VISIBLE (previous))
- gtk_widget_hide (previous);
-}
-
-static void
-hildon_stackable_window_unmap (GtkWidget *widget)
-{
- 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);
-
- if (HILDON_IS_STACKABLE_WINDOW (previous) && !GTK_WIDGET_VISIBLE (previous) &&
- !hildon_stackable_window_get_going_home (HILDON_STACKABLE_WINDOW (widget)))
- {
- gtk_widget_show (previous);
- }
-}
-
-static void
-hildon_stackable_window_unset_program (HildonWindow *hwin)
-{
- 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 (previous) && !GTK_WIDGET_VISIBLE (previous) &&
- !hildon_stackable_window_get_going_home (HILDON_STACKABLE_WINDOW (hwin)))
- {
- gtk_widget_show (previous);
- }
-}
-
void
hildon_stackable_window_set_main_menu (HildonStackableWindow *self,
HildonAppMenu *menu)
(guchar *)&atom, 1);
}
-static gboolean
-hildon_stackable_window_delete_event (GtkWidget *widget,
- GdkEventAny *event)
+static void
+hildon_stackable_window_show (GtkWidget *widget)
{
- GSList *list = get_window_list (widget);
- list = g_slist_find (list, widget);
+ HildonProgram *program = hildon_program_get_instance ();
+ HildonStackableWindow *current_win = HILDON_STACKABLE_WINDOW (widget);
+ HildonStackableWindow *previous_win = hildon_program_peek_window_stack (program);
- /* 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;
+ if (previous_win != current_win)
+ _hildon_program_add_to_stack (program, current_win);
+
+ GTK_WIDGET_CLASS (hildon_stackable_window_parent_class)->show (widget);
+
+ if (previous_win != NULL && previous_win != current_win)
+ gtk_widget_hide (GTK_WIDGET (previous_win));
+}
+
+static void
+hildon_stackable_window_destroy (GtkObject *obj)
+{
+ HildonProgram *program = hildon_program_get_instance ();
+ HildonStackableWindow *topmost = hildon_program_peek_window_stack (program);
+
+ if (_hildon_program_remove_from_stack (program, HILDON_STACKABLE_WINDOW (obj)))
+ {
+ if (topmost != NULL && GTK_OBJECT (topmost) == obj)
+ {
+ HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (obj);
+ topmost = hildon_program_peek_window_stack (program);
+ if (topmost != NULL && !priv->going_home)
+ gtk_widget_show (GTK_WIDGET (topmost));
+ }
+ }
+
+ GTK_OBJECT_CLASS (hildon_stackable_window_parent_class)->destroy (obj);
}
static void
{
HildonStackableWindowPrivate *priv = HILDON_STACKABLE_WINDOW_GET_PRIVATE (object);
- if (priv->app_menu) {
+ if (priv->app_menu)
gtk_widget_destroy (GTK_WIDGET (priv->app_menu));
- }
}
static void
hildon_stackable_window_class_init (HildonStackableWindowClass *klass)
{
GObjectClass *obj_class = G_OBJECT_CLASS (klass);
+ GtkObjectClass *gtk_obj_class = GTK_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
HildonWindowClass *window_class = HILDON_WINDOW_CLASS (klass);
obj_class->finalize = hildon_stackable_window_finalize;
- widget_class->map = hildon_stackable_window_map;
- widget_class->unmap = hildon_stackable_window_unmap;
+ gtk_obj_class->destroy = hildon_stackable_window_destroy;
+
widget_class->realize = hildon_stackable_window_realize;
- widget_class->delete_event = hildon_stackable_window_delete_event;
+ widget_class->show = hildon_stackable_window_show;
- window_class->unset_program = hildon_stackable_window_unset_program;
window_class->toggle_menu = hildon_stackable_window_toggle_menu;
g_type_class_add_private (klass, sizeof (HildonStackableWindowPrivate));