2 * This file is a part of hildon
4 * Copyright (C) 2006 Nokia Corporation, all rights reserved.
6 * Contact: Rodrigo Novo <rodrigo.novo@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-program
27 * @short_description: Application abstraction in the Hildon framework.
28 * @see_also: #HildonWindow, #HildonStackableWindow
30 * #HildonProgram is an object used to represent an application running
31 * in the Hildon framework.
33 * Applications can have one or more #HildonWindow<!-- -->s. These
34 * can be registered in the #HildonProgram with hildon_program_add_window(),
35 * and can be unregistered similarly with hildon_program_remove_window().
37 * #HildonProgram provides the programmer with commodities such
38 * as applying a common toolbar and menu to all registered
39 * #HildonWindow<!-- -->s. This is done with hildon_program_set_common_menu(),
40 * hildon_program_set_common_app_menu() and hildon_program_set_common_toolbar().
42 * #HildonProgram is also used to apply program-wide properties that
43 * are specific to the Hildon framework. For instance
44 * hildon_program_set_can_hibernate() sets whether or not an application
45 * can be set to hibernate by the Hildon task navigator, in situations of
50 * HildonProgram *program;
51 * HildonWindow *window1;
52 * HildonWindow *window2;
53 * GtkToolbar *common_toolbar, *window_specific_toolbar;
54 * HildonAppMenu *menu;
56 * program = HILDON_PROGRAM (hildon_program_get_instance ());
58 * window1 = HILDON_WINDOW (hildon_window_new ());
59 * window2 = HILDON_WINDOW (hildon_window_new ());
61 * common_toolbar = create_common_toolbar ();
62 * window_specific_toolbar = create_window_specific_toolbar ();
64 * menu = create_menu ();
66 * hildon_program_add_window (program, window1);
67 * hildon_program_add_window (program, window2);
69 * hildon_program_set_common_app_menu (program, menu);
71 * hildon_program_set_common_toolbar (program, common_toolbar);
72 * hildon_window_add_toolbar (window1, window_specific_toolbar);
74 * hildon_program_set_can_hibernate (program, TRUE);
79 #undef HILDON_DISABLE_DEPRECATED
85 #include <X11/Xatom.h>
87 #include "hildon-program.h"
88 #include "hildon-program-private.h"
89 #include "hildon-window-private.h"
90 #include "hildon-window-stack.h"
91 #include "hildon-app-menu-private.h"
94 hildon_program_init (HildonProgram *self);
97 hildon_program_finalize (GObject *self);
100 hildon_program_class_init (HildonProgramClass *self);
103 hildon_program_get_property (GObject *object,
108 hildon_program_set_property (GObject *object,
121 hildon_program_get_type (void)
123 static GType program_type = 0;
127 static const GTypeInfo program_info =
129 sizeof (HildonProgramClass),
130 NULL, /* base_init */
131 NULL, /* base_finalize */
132 (GClassInitFunc) hildon_program_class_init,
133 NULL, /* class_finalize */
134 NULL, /* class_data */
135 sizeof (HildonProgram),
137 (GInstanceInitFunc) hildon_program_init,
139 program_type = g_type_register_static(G_TYPE_OBJECT,
140 "HildonProgram", &program_info, 0);
146 hildon_program_init (HildonProgram *self)
148 HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (self);
151 priv->killable = FALSE;
152 priv->window_count = 0;
153 priv->is_topmost = FALSE;
154 priv->window_group = GDK_WINDOW_XID (gdk_display_get_default_group (gdk_display_get_default()));
155 priv->common_menu = NULL;
156 priv->common_app_menu = NULL;
157 priv->common_toolbar = NULL;
158 priv->windows = NULL;
162 hildon_program_finalize (GObject *self)
164 HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (HILDON_PROGRAM (self));
167 if (priv->common_toolbar)
169 g_object_unref (priv->common_toolbar);
170 priv->common_toolbar = NULL;
173 if (priv->common_menu)
175 g_object_unref (priv->common_menu);
176 priv->common_menu = NULL;
181 hildon_program_class_init (HildonProgramClass *self)
183 GObjectClass *object_class = G_OBJECT_CLASS (self);
185 g_type_class_add_private (self, sizeof (HildonProgramPrivate));
187 /* Set up object virtual functions */
188 object_class->finalize = hildon_program_finalize;
189 object_class->set_property = hildon_program_set_property;
190 object_class->get_property = hildon_program_get_property;
192 /* Install properties */
195 * HildonProgram:is-topmost:
197 * Whether one of the program's window or dialog currently
198 * is activated by window manager.
200 g_object_class_install_property (object_class, PROP_IS_TOPMOST,
201 g_param_spec_boolean ("is-topmost",
203 "Whether one of the program's window or dialog currently "
204 "is activated by window manager",
209 * HildonProgram:can-hibernate:
211 * Whether the program should be set to hibernate by the Task
212 * Navigator in low memory situation.
214 g_object_class_install_property (object_class, PROP_KILLABLE,
215 g_param_spec_boolean ("can-hibernate",
217 "Whether the program should be set to hibernate by the Task "
218 "Navigator in low memory situation",
225 hildon_program_set_property (GObject *object,
230 switch (property_id) {
233 hildon_program_set_can_hibernate (HILDON_PROGRAM (object), g_value_get_boolean (value));
237 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
244 hildon_program_get_property (GObject *object,
249 HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (object);
255 g_value_set_boolean (value, priv->killable);
258 case PROP_IS_TOPMOST:
259 g_value_set_boolean (value, priv->is_topmost);
263 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
269 * hildon_program_pop_window_stack:
270 * @self: A #HildonProgram
272 * Pops a window from the stack.
274 * Deprecated: Use hildon_window_stack_pop() instead
276 * Returns: A #HildonStackableWindow, or %NULL
280 HildonStackableWindow *
281 hildon_program_pop_window_stack (HildonProgram *self)
283 HildonWindowStack *stack = hildon_window_stack_get_default ();
284 GtkWidget *win = hildon_window_stack_pop_1 (stack);
285 g_warning ("%s: this function is deprecated. Use hildon_window_stack_pop() instead", __FUNCTION__);
286 return win ? HILDON_STACKABLE_WINDOW (win) : NULL;
290 * hildon_program_peek_window_stack:
291 * @self: A #HildonProgram
293 * Deprecated: Use hildon_window_stack_peek() instead
295 * Returns: A #HildonStackableWindow, or %NULL
299 HildonStackableWindow *
300 hildon_program_peek_window_stack (HildonProgram *self)
302 HildonWindowStack *stack = hildon_window_stack_get_default ();
303 GtkWidget *win = hildon_window_stack_peek (stack);
304 g_warning ("%s: this function is deprecated. Use hildon_window_stack_peek() instead", __FUNCTION__);
305 return win ? HILDON_STACKABLE_WINDOW (win) : NULL;
310 hildon_program_window_list_compare (gconstpointer window_a,
311 gconstpointer window_b)
313 g_return_val_if_fail (HILDON_IS_WINDOW(window_a) &&
314 HILDON_IS_WINDOW(window_b), 1);
316 return window_a != window_b;
320 * foreach function, checks if a window is topmost and acts consequently
323 hildon_program_window_list_is_is_topmost (gpointer data,
326 if (data && HILDON_IS_WINDOW (data))
328 HildonWindow *window = HILDON_WINDOW (data);
329 Window window_id = * (Window*)window_id_;
331 hildon_window_update_topmost (window, window_id);
336 * Check the _MB_CURRENT_APP_WINDOW on the root window, and update
337 * the top_most status accordingly
340 hildon_program_update_top_most (HildonProgram *program)
343 Window active_window;
344 HildonProgramPrivate *priv;
346 priv = HILDON_PROGRAM_GET_PRIVATE (program);
349 active_window = hildon_window_get_active_window();
357 gdk_error_trap_push ();
358 wm_hints = XGetWMHints (GDK_DISPLAY (), active_window);
359 xerror = gdk_error_trap_pop ();
360 if (xerror && xerror != BadWindow)
369 is_topmost = (wm_hints->window_group == priv->window_group);
374 /* Send notification if is_topmost has changed */
375 if (!priv->is_topmost != !is_topmost)
377 priv->is_topmost = is_topmost;
378 g_object_notify (G_OBJECT (program), "is-topmost");
381 /* Check each window if it was is_topmost */
382 g_slist_foreach (priv->windows,
383 (GFunc)hildon_program_window_list_is_is_topmost, &active_window);
387 * We keep track of the _MB_CURRENT_APP_WINDOW property on the root window,
388 * to detect when a window belonging to this program was is_topmost. This
389 * is based on the window group WM hint.
391 static GdkFilterReturn
392 hildon_program_root_window_event_filter (GdkXEvent *xevent,
396 XAnyEvent *eventti = xevent;
397 HildonProgram *program = HILDON_PROGRAM (data);
398 Atom active_app_atom =
399 XInternAtom (GDK_DISPLAY (), "_MB_CURRENT_APP_WINDOW", False);
401 if (eventti->type == PropertyNotify)
403 XPropertyEvent *pevent = xevent;
405 if (pevent->atom == active_app_atom)
407 hildon_program_update_top_most (program);
411 return GDK_FILTER_CONTINUE;
415 * Checks if the window is the topmost window of the program and in
416 * that case forces the window to take the common toolbar.
419 hildon_program_common_toolbar_topmost_window (gpointer window,
422 if (HILDON_IS_WINDOW (window) && hildon_window_get_is_topmost (HILDON_WINDOW (window)))
423 hildon_window_take_common_toolbar (HILDON_WINDOW (window));
427 * hildon_program_get_instance:
429 * Returns the #HildonProgram for the current process. The object is
430 * created on the first call. Note that you're not supposed to unref
431 * the returned object since it's not reffed in the first place.
433 * Return value: the #HildonProgram.
436 hildon_program_get_instance (void)
438 static HildonProgram *program = NULL;
442 program = g_object_new (HILDON_TYPE_PROGRAM, NULL);
449 * hildon_program_add_window:
450 * @self: The #HildonProgram to which the window should be registered
451 * @window: A #HildonWindow to be added
453 * Registers a #HildonWindow as belonging to a given #HildonProgram. This
454 * allows to apply program-wide settings as all the registered windows,
455 * such as hildon_program_set_common_menu(), hildon_program_set_common_app_menu()
456 * and hildon_program_set_common_toolbar().
459 hildon_program_add_window (HildonProgram *self,
460 HildonWindow *window)
462 HildonProgramPrivate *priv;
464 g_return_if_fail (HILDON_IS_PROGRAM (self));
465 g_return_if_fail (HILDON_IS_WINDOW (window));
467 priv = HILDON_PROGRAM_GET_PRIVATE (self);
470 if (g_slist_find_custom (priv->windows, window,
471 hildon_program_window_list_compare) )
473 /* We already have that window */
477 if (!priv->window_count)
479 hildon_program_update_top_most (self);
481 /* Now that we have a window we should start keeping track of
483 gdk_window_set_events (gdk_get_default_root_window (),
484 gdk_window_get_events (gdk_get_default_root_window ()) | GDK_PROPERTY_CHANGE_MASK);
486 gdk_window_add_filter (gdk_get_default_root_window (),
487 hildon_program_root_window_event_filter, self );
490 hildon_window_set_can_hibernate_property (window, &priv->killable);
492 hildon_window_set_program (window, G_OBJECT (self));
494 priv->windows = g_slist_append (priv->windows, window);
495 priv->window_count ++;
499 * hildon_program_remove_window:
500 * @self: The #HildonProgram to which the window should be unregistered
501 * @window: The #HildonWindow to unregister
503 * Used to unregister a window from the program. Subsequent calls to
504 * hildon_program_set_common_menu(), hildon_program_set_common_app_menu()
505 * and hildon_program_set_common_toolbar() will not affect the window.
508 hildon_program_remove_window (HildonProgram *self,
509 HildonWindow *window)
511 HildonProgramPrivate *priv;
513 g_return_if_fail (HILDON_IS_PROGRAM (self));
514 g_return_if_fail (HILDON_IS_WINDOW (window));
516 priv = HILDON_PROGRAM_GET_PRIVATE (self);
519 g_return_if_fail (g_slist_find (priv->windows, window));
521 hildon_window_unset_program (window);
523 priv->windows = g_slist_remove (priv->windows, window);
525 priv->window_count --;
527 if (! priv->window_count)
528 gdk_window_remove_filter (gdk_get_default_root_window(),
529 hildon_program_root_window_event_filter,
534 * hildon_program_set_can_hibernate:
535 * @self: The #HildonProgram which can hibernate or not
536 * @can_hibernate: whether or not the #HildonProgram can hibernate
538 * Used to set whether or not the Hildon task navigator should
539 * be able to set the program to hibernation in case of low memory
542 hildon_program_set_can_hibernate (HildonProgram *self,
543 gboolean can_hibernate)
545 HildonProgramPrivate *priv;
547 g_return_if_fail (HILDON_IS_PROGRAM (self));
549 priv = HILDON_PROGRAM_GET_PRIVATE (self);
552 if (priv->killable != can_hibernate)
554 g_slist_foreach (priv->windows,
555 (GFunc) hildon_window_set_can_hibernate_property, &can_hibernate);
558 priv->killable = can_hibernate;
562 * hildon_program_get_can_hibernate:
563 * @self: The #HildonProgram which can hibernate or not
565 * Returns whether the #HildonProgram is set to be support hibernation
566 * from the Hildon task navigator
568 * Return value: %TRUE if the program can hibernate, %FALSE otherwise.
571 hildon_program_get_can_hibernate (HildonProgram *self)
573 HildonProgramPrivate *priv;
575 g_return_val_if_fail (HILDON_IS_PROGRAM (self), FALSE);
577 priv = HILDON_PROGRAM_GET_PRIVATE (self);
580 return priv->killable;
584 * hildon_program_set_common_menu:
585 * @self: The #HildonProgram in which the common menu should be used
586 * @menu: A #GtkMenu to use as common menu for the program
588 * Sets a #GtkMenu that will appear in all #HildonWindow<!-- -->s
589 * registered with the #HildonProgram. Only one common #GtkMenu can be
590 * set, further calls will detach the previous common #GtkMenu. A
591 * #HildonWindow can use its own #GtkMenu with
592 * hildon_window_set_menu()
594 * This method does not support #HildonAppMenu<!-- -->s. See
595 * hildon_program_set_common_app_menu() for that.
600 hildon_program_set_common_menu (HildonProgram *self,
603 HildonProgramPrivate *priv;
605 g_return_if_fail (HILDON_IS_PROGRAM (self));
607 priv = HILDON_PROGRAM_GET_PRIVATE (self);
610 if (priv->common_menu)
612 if (GTK_WIDGET_VISIBLE (priv->common_menu))
614 gtk_menu_popdown (priv->common_menu);
615 gtk_menu_shell_deactivate (GTK_MENU_SHELL (priv->common_menu));
618 if (gtk_menu_get_attach_widget (priv->common_menu))
620 gtk_menu_detach (priv->common_menu);
624 g_object_unref (priv->common_menu);
628 priv->common_menu = menu;
630 if (priv->common_menu)
633 gtk_object_sink (GTK_OBJECT (menu));
634 gtk_widget_show_all (GTK_WIDGET (menu));
639 * hildon_program_get_common_menu:
640 * @self: The #HildonProgram from which to retrieve the common menu
642 * Returns the #GtkMenu that was set as common menu for this
645 * Return value: the #GtkMenu or %NULL of no common menu was set.
648 hildon_program_get_common_menu (HildonProgram *self)
650 HildonProgramPrivate *priv;
652 g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
654 priv = HILDON_PROGRAM_GET_PRIVATE (self);
657 return priv->common_menu;
661 * hildon_program_set_common_app_menu:
662 * @self: The #HildonProgram in which the common menu should be used
663 * @menu: A #HildonAppMenu to use as common menu for the program
665 * Sets a #HildonAppMenu that will appear in all
666 * #HildonWindow<!-- -->s registered with the #HildonProgram. Only
667 * one common #HildonAppMenu can be set, further calls will detach the
668 * previous common #HildonAppMenu. A #HildonWindow can use its own
669 * #HildonAppMenu with hildon_window_set_app_menu()
671 * This method does not support #GtkMenu<!-- -->s. See
672 * hildon_program_set_common_menu() for that.
677 hildon_program_set_common_app_menu (HildonProgram *self,
680 HildonProgramPrivate *priv;
681 HildonAppMenu *old_menu;
683 g_return_if_fail (HILDON_IS_PROGRAM (self));
684 g_return_if_fail (menu == NULL || HILDON_IS_APP_MENU (menu));
686 priv = HILDON_PROGRAM_GET_PRIVATE (self);
689 old_menu = priv->common_app_menu;
692 priv->common_app_menu = menu;
694 g_object_ref_sink (menu);
696 /* Hide and unref old menu */
698 hildon_app_menu_set_parent_window (old_menu, NULL);
699 g_object_unref (old_menu);
704 * hildon_program_get_common_app_menu:
705 * @self: The #HildonProgram from which to retrieve the common app menu
707 * Returns the #HildonAppMenu that was set as common menu for this
710 * Return value: the #HildonAppMenu or %NULL of no common app menu was
716 hildon_program_get_common_app_menu (HildonProgram *self)
718 HildonProgramPrivate *priv;
720 g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
722 priv = HILDON_PROGRAM_GET_PRIVATE (self);
725 return priv->common_app_menu;
729 * hildon_program_set_common_toolbar:
730 * @self: The #HildonProgram in which the common toolbar should be used
731 * @toolbar: A #GtkToolbar to use as common toolbar for the program
733 * Sets a #GtkToolbar that will appear in all the #HildonWindow registered
734 * to the #HildonProgram. Only one common #GtkToolbar can be set, further
735 * call will detach the previous common #GtkToolbar. A #HildonWindow
736 * can use its own #GtkToolbar with hildon_window_add_toolbar(). Both
737 * #HildonProgram and #HildonWindow specific toolbars will be shown
740 hildon_program_set_common_toolbar (HildonProgram *self,
743 HildonProgramPrivate *priv;
745 g_return_if_fail (HILDON_IS_PROGRAM (self));
747 priv = HILDON_PROGRAM_GET_PRIVATE (self);
750 if (priv->common_toolbar)
752 if (priv->common_toolbar->parent)
754 gtk_container_remove (GTK_CONTAINER (priv->common_toolbar->parent),
755 priv->common_toolbar);
758 g_object_unref (priv->common_toolbar);
761 priv->common_toolbar = GTK_WIDGET (toolbar);
763 if (priv->common_toolbar)
765 g_object_ref (priv->common_toolbar);
766 gtk_object_sink (GTK_OBJECT (priv->common_toolbar) );
769 /* if the program is the topmost we have to update the common
770 toolbar right now for the topmost window */
771 if (priv->is_topmost)
773 g_slist_foreach (priv->windows,
774 (GFunc) hildon_program_common_toolbar_topmost_window, NULL);
779 * hildon_program_get_common_toolbar:
780 * @self: The #HildonProgram from which to retrieve the common toolbar
782 * Returns the #GtkToolbar that was set as common toolbar for this
785 * Return value: the #GtkToolbar or %NULL of no common toolbar was
789 hildon_program_get_common_toolbar (HildonProgram *self)
791 HildonProgramPrivate *priv;
793 g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
795 priv = HILDON_PROGRAM_GET_PRIVATE (self);
798 return priv->common_toolbar ? GTK_TOOLBAR (priv->common_toolbar) : NULL;
802 * hildon_program_get_is_topmost:
803 * @self: A #HildonWindow
805 * Returns whether one of the program's windows or dialogs is
806 * currently activated by the window manager.
808 * Return value: %TRUE if a window or dialog is topmost, %FALSE
812 hildon_program_get_is_topmost (HildonProgram *self)
814 HildonProgramPrivate *priv;
816 g_return_val_if_fail (HILDON_IS_PROGRAM (self), FALSE);
818 priv = HILDON_PROGRAM_GET_PRIVATE (self);
821 return priv->is_topmost;
825 * hildon_program_go_to_root_window:
826 * @self: A #HildonProgram
828 * Goes to the root window of the stack.
830 * Deprecated: See #HildonWindowStack
835 hildon_program_go_to_root_window (HildonProgram *self)
837 HildonWindowStack *stack = hildon_window_stack_get_default ();
838 gint n = hildon_window_stack_size (stack);
839 g_warning ("%s: this function is deprecated. Use hildon_window_stack_pop() instead.", __FUNCTION__);
841 hildon_window_stack_pop (stack, n-1, NULL);