X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Fhildon-program.c;h=6f503884bfe171cb0095fe04692426e30c161c08;hb=2cd50329538b9d88797e16e11383264ae84ee340;hp=9cc94f03db608965edad61dec87ac431f5a3e296;hpb=c7a5a9bb6db85fadf3a7a9ddedc3632ca36040ec;p=hildon diff --git a/src/hildon-program.c b/src/hildon-program.c index 9cc94f0..6f50388 100644 --- a/src/hildon-program.c +++ b/src/hildon-program.c @@ -47,8 +47,8 @@ * * * 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); * @@ -79,10 +79,12 @@ #include #endif +#include + #include "hildon-program.h" #include "hildon-program-private.h" #include "hildon-window-private.h" -#include +#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); +}