2 * This file is a part of hildon
4 * Copyright (C) 2006 Nokia Corporation, all rights reserved.
6 * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@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: An object that represents an application running in the Hildon framework.
29 * The HildonProgram is an object used to represent an application running
30 * in the Hildon framework.
32 * Such an application is thought to have one or more HildonWindow. These
33 * shall be registered to the HildonProgram with hildon_program_add_window,
34 * and can be unregistered similarly with hildon_program_remove_window.
36 * The HildonProgram provides the programmer with commodities such
37 * as applying a common toolbar and menu to all the HildonWindow
38 * registered to it. This is done with hildon_program_set_common_menu()
39 * and hildon_program_set_common_toolbar().
41 * The HildonProgram is also used to apply program-wide properties that
42 * are specific to the Hildon framework. For instance
43 * hildon_program_set_can_hibernate() sets whether or not an application
44 * can be set to hibernate by the Hildon task navigator, in situations of
49 * HildonProgram *program;
50 * HildonWindow *first_window;
51 * HildonWindow *second_window;
52 * GtkToolbar *common_toolbar, *window_specific_toolbar;
55 * program = HILDON_PROGRAM (hildon_program_get_instance ());
57 * window1 = HILDON_WINDOW (hildon_window_new ());
58 * window2 = HILDON_WINDOW (hildon_window_new ());
60 * common_toolbar = create_common_toolbar ();
61 * window_specific_toolbar = create_window_specific_toolbar ();
63 * menu = create_menu ();
65 * hildon_program_add (program, window1);
66 * hildon_program_add (program, window2);
68 * hildon_program_set_common_menu (program, menu);
70 * hildon_program_set_common_toolbar (program, common_toolbar);
71 * hildon_window_add_toolbar (first_window, window_specific_toolbar);
73 * hildon_program_set_can_hibernate (program, TRUE);
82 #include "hildon-program.h"
83 #include "hildon-program-private.h"
84 #include "hildon-window-private.h"
85 #include <X11/Xatom.h>
88 hildon_program_init (HildonProgram *self);
91 hildon_program_finalize (GObject *self);
94 hildon_program_class_init (HildonProgramClass *self);
97 hildon_program_get_property (GObject *object,
102 hildon_program_set_property (GObject *object,
115 hildon_program_get_type (void)
117 static GType program_type = 0;
121 static const GTypeInfo program_info =
123 sizeof (HildonProgramClass),
124 NULL, /* base_init */
125 NULL, /* base_finalize */
126 (GClassInitFunc) hildon_program_class_init,
127 NULL, /* class_finalize */
128 NULL, /* class_data */
129 sizeof (HildonProgram),
131 (GInstanceInitFunc) hildon_program_init,
133 program_type = g_type_register_static(G_TYPE_OBJECT,
134 "HildonProgram", &program_info, 0);
140 hildon_program_init (HildonProgram *self)
142 HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (self);
145 priv->killable = FALSE;
146 priv->window_count = 0;
147 priv->is_topmost = FALSE;
148 priv->window_group = GDK_WINDOW_XID (gdk_display_get_default_group (gdk_display_get_default()));
149 priv->common_toolbar = NULL;
154 hildon_program_finalize (GObject *self)
156 HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (HILDON_PROGRAM (self));
159 if (priv->common_toolbar)
161 g_object_unref (priv->common_toolbar);
162 priv->common_toolbar = NULL;
165 if (priv->common_menu)
167 g_object_unref (priv->common_menu);
168 priv->common_menu = NULL;
175 hildon_program_class_init (HildonProgramClass *self)
177 GObjectClass *object_class = G_OBJECT_CLASS (self);
179 g_type_class_add_private (self, sizeof (HildonProgramPrivate));
181 /* Set up object virtual functions */
182 object_class->finalize = hildon_program_finalize;
183 object_class->set_property = hildon_program_set_property;
184 object_class->get_property = hildon_program_get_property;
186 /* Install properties */
189 * HildonProgram:is-topmost:
191 * Whether one of the program's window or dialog currently
192 * is activated by window manager.
194 g_object_class_install_property (object_class, PROP_IS_TOPMOST,
195 g_param_spec_boolean ("is-topmost",
197 "Whether one of the program's window or dialog currently "
198 "is activated by window manager",
203 * HildonProgram:can-hibernate:
205 * Whether the program should be set to hibernate by the Task
206 * Navigator in low memory situation.
208 g_object_class_install_property (object_class, PROP_KILLABLE,
209 g_param_spec_boolean ("can-hibernate",
211 "Whether the program should be set to hibernate by the Task "
212 "Navigator in low memory situation",
219 hildon_program_set_property (GObject *object,
224 switch (property_id) {
227 hildon_program_set_can_hibernate (HILDON_PROGRAM (object), g_value_get_boolean (value));
231 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
238 hildon_program_get_property (GObject *object,
243 HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (object);
249 g_value_set_boolean (value, priv->killable);
252 case PROP_IS_TOPMOST:
253 g_value_set_boolean (value, priv->is_topmost);
257 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
264 hildon_program_window_list_compare (gconstpointer window_a,
265 gconstpointer window_b)
267 g_return_val_if_fail (HILDON_IS_WINDOW(window_a) &&
268 HILDON_IS_WINDOW(window_b), 1);
270 return window_a != window_b;
274 * foreach function, checks if a window is topmost and acts consequently
277 hildon_program_window_list_is_is_topmost (gpointer data,
280 if (data && HILDON_IS_WINDOW (data))
282 HildonWindow *window = HILDON_WINDOW (data);
283 Window window_id = * (Window*)window_id_;
285 hildon_window_update_topmost (window, window_id);
290 * Check the _MB_CURRENT_APP_WINDOW on the root window, and update
291 * the top_most status accordingly
294 hildon_program_update_top_most (HildonProgram *program)
297 Window active_window;
298 HildonProgramPrivate *priv;
300 priv = HILDON_PROGRAM_GET_PRIVATE (program);
303 active_window = hildon_window_get_active_window();
309 gdk_error_trap_push ();
310 wm_hints = XGetWMHints (GDK_DISPLAY (), active_window);
311 xerror = gdk_error_trap_pop ();
318 if (wm_hints->window_group == priv->window_group)
320 if (!priv->is_topmost)
322 priv->is_topmost = TRUE;
323 g_object_notify (G_OBJECT (program), "is-topmost");
326 else if (priv->is_topmost)
328 priv->is_topmost = FALSE;
329 g_object_notify (G_OBJECT (program), "is-topmost");
335 /* Check each window if it was is_topmost */
336 g_slist_foreach (priv->windows,
337 (GFunc)hildon_program_window_list_is_is_topmost, &active_window);
341 * We keep track of the _MB_CURRENT_APP_WINDOW property on the root window,
342 * to detect when a window belonging to this program was is_topmost. This
343 * is based on the window group WM hint.
345 static GdkFilterReturn
346 hildon_program_root_window_event_filter (GdkXEvent *xevent,
350 XAnyEvent *eventti = xevent;
351 HildonProgram *program = HILDON_PROGRAM (data);
352 Atom active_app_atom =
353 XInternAtom (GDK_DISPLAY (), "_MB_CURRENT_APP_WINDOW", False);
355 if (eventti->type == PropertyNotify)
357 XPropertyEvent *pevent = xevent;
359 if (pevent->atom == active_app_atom)
361 hildon_program_update_top_most (program);
365 return GDK_FILTER_CONTINUE;
369 * Checks if the window is the topmost window of the program and in
370 * that case forces the window to take the common toolbar.
373 hildon_program_common_toolbar_topmost_window (gpointer window,
376 if (HILDON_IS_WINDOW (window) && hildon_window_get_is_topmost (HILDON_WINDOW (window)))
377 hildon_window_take_common_toolbar (HILDON_WINDOW (window));
381 * hildon_program_get_instance:
383 * Return value: Returns the #HildonProgram for the current process.
384 * The object is created on the first call. Note that you're not supposed
385 * to unref the returned object since it's not reffed in the first place.
388 hildon_program_get_instance (void)
390 static HildonProgram *program = NULL;
394 program = g_object_new (HILDON_TYPE_PROGRAM, NULL);
401 * hildon_program_add_window:
402 * @self: The @HildonProgram to which the window should be registered
403 * @window: A @HildonWindow to be added
405 * Registers a @HildonWindow as belonging to a given @HildonProgram. This
406 * allows to apply program-wide settings as all the registered windows,
407 * such as hildon_program_set_common_menu() and
408 * hildon_pogram_set_common_toolbar()
411 hildon_program_add_window (HildonProgram *self,
412 HildonWindow *window)
414 HildonProgramPrivate *priv;
416 g_return_if_fail (HILDON_IS_PROGRAM (self));
418 priv = HILDON_PROGRAM_GET_PRIVATE (self);
421 if (g_slist_find_custom (priv->windows, window,
422 hildon_program_window_list_compare) )
424 /* We already have that window */
428 if (!priv->window_count)
430 hildon_program_update_top_most (self);
432 /* Now that we have a window we should start keeping track of
434 gdk_window_set_events (gdk_get_default_root_window (),
435 gdk_window_get_events (gdk_get_default_root_window ()) | GDK_PROPERTY_CHANGE_MASK);
437 gdk_window_add_filter (gdk_get_default_root_window (),
438 hildon_program_root_window_event_filter, self );
441 hildon_window_set_can_hibernate_property (window, &priv->killable);
443 hildon_window_set_program (window, G_OBJECT (self));
445 priv->windows = g_slist_append (priv->windows, window);
446 priv->window_count ++;
450 * hildon_program_remove_window:
451 * @self: The #HildonProgram to which the window should be unregistered
452 * @window: The @HildonWindow to unregister
454 * Used to unregister a window from the program. Subsequent calls to
455 * hildon_program_set_common_menu() and hildon_pogram_set_common_toolbar()
456 * will not affect the window
459 hildon_program_remove_window (HildonProgram *self,
460 HildonWindow *window)
462 HildonProgramPrivate *priv;
464 g_return_if_fail (HILDON_IS_PROGRAM (self));
466 priv = HILDON_PROGRAM_GET_PRIVATE (self);
469 hildon_window_unset_program (window);
471 priv->windows = g_slist_remove (priv->windows, window);
473 priv->window_count --;
475 if (! priv->window_count)
476 gdk_window_remove_filter (gdk_get_default_root_window(),
477 hildon_program_root_window_event_filter,
482 * hildon_program_set_can_hibernate:
483 * @self: The #HildonProgram which can hibernate or not
484 * @can_hibernate: whether or not the #HildonProgram can hibernate
486 * Used to set whether or not the Hildon task navigator should
487 * be able to set the program to hibernation in case of low memory
490 hildon_program_set_can_hibernate (HildonProgram *self,
491 gboolean can_hibernate)
493 HildonProgramPrivate *priv;
495 g_return_if_fail (HILDON_IS_PROGRAM (self));
497 priv = HILDON_PROGRAM_GET_PRIVATE (self);
500 if (priv->killable != can_hibernate)
502 g_slist_foreach (priv->windows,
503 (GFunc) hildon_window_set_can_hibernate_property, &can_hibernate);
506 priv->killable = can_hibernate;
510 * hildon_program_get_can_hibernate:
511 * @self: The #HildonProgram which can hibernate or not
513 * Return value: Whether or not this #HildonProgram is set to be
514 * support hibernation from the Hildon task navigator
517 hildon_program_get_can_hibernate (HildonProgram *self)
519 HildonProgramPrivate *priv;
521 g_return_val_if_fail (HILDON_IS_PROGRAM (self), FALSE);
523 priv = HILDON_PROGRAM_GET_PRIVATE (self);
526 return priv->killable;
530 * hildon_program_set_common_menu:
531 * @self: The #HildonProgram in which the common menu should be used
532 * @menu: A GtkMenu to use as common menu for the program
534 * Sets a GtkMenu that will appear in all the @HildonWindow registered
535 * to the #HildonProgram. Only one common GtkMenu can be set, further
536 * call will detach the previous common GtkMenu. A @HildonWindow
537 * can use it's own GtkMenu with @hildon_window_set_menu
540 hildon_program_set_common_menu (HildonProgram *self,
543 HildonProgramPrivate *priv;
545 g_return_if_fail (HILDON_IS_PROGRAM (self));
547 priv = HILDON_PROGRAM_GET_PRIVATE (self);
550 if (priv->common_menu)
552 if (GTK_WIDGET_VISIBLE (priv->common_menu))
554 gtk_menu_popdown (GTK_MENU (priv->common_menu));
555 gtk_menu_shell_deactivate (GTK_MENU_SHELL (priv->common_menu));
558 if (gtk_menu_get_attach_widget (GTK_MENU (priv->common_menu)))
560 gtk_menu_detach (GTK_MENU (priv->common_menu));
564 g_object_unref (priv->common_menu);
568 priv->common_menu = GTK_WIDGET (menu);
570 if (priv->common_menu)
573 gtk_object_sink (GTK_OBJECT (menu));
574 gtk_widget_show_all (GTK_WIDGET (menu));
579 * hildon_program_get_common_menu:
580 * @self: The #HildonProgram from which to retrieve the common menu
582 * Return value: the GtkMenu that was set as common menu for this
583 * #HildonProgram, or NULL of no common menu was set.
586 hildon_program_get_common_menu (HildonProgram *self)
588 HildonProgramPrivate *priv;
590 g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
592 priv = HILDON_PROGRAM_GET_PRIVATE (self);
595 return GTK_MENU (priv->common_menu);
599 * hildon_program_set_common_toolbar:
600 * @self: The #HildonProgram in which the common toolbar should be used
601 * @toolbar: A GtkToolbar to use as common toolbar for the program
603 * Sets a GtkToolbar that will appear in all the @HildonWindow registered
604 * to the #HildonProgram. Only one common GtkToolbar can be set, further
605 * call will detach the previous common GtkToolbar. A @HildonWindow
606 * can use its own GtkToolbar with @hildon_window_set_toolbar. Both
607 * #HildonProgram and @HildonWindow specific toolbars will be shown
610 hildon_program_set_common_toolbar (HildonProgram *self,
613 HildonProgramPrivate *priv;
615 g_return_if_fail (HILDON_IS_PROGRAM (self));
617 priv = HILDON_PROGRAM_GET_PRIVATE (self);
620 if (priv->common_toolbar)
622 if (priv->common_toolbar->parent)
624 gtk_container_remove (GTK_CONTAINER (priv->common_toolbar->parent),
625 priv->common_toolbar);
628 g_object_unref (priv->common_toolbar);
631 priv->common_toolbar = GTK_WIDGET (toolbar);
633 if (priv->common_toolbar)
635 g_object_ref (priv->common_toolbar);
636 gtk_object_sink (GTK_OBJECT (priv->common_toolbar) );
639 /* if the program is the topmost we have to update the common
640 toolbar right now for the topmost window */
641 if (priv->is_topmost)
643 g_slist_foreach (priv->windows,
644 (GFunc) hildon_program_common_toolbar_topmost_window, NULL);
649 * hildon_program_get_common_toolbar:
650 * @self: The #HildonProgram from which to retrieve the common toolbar
652 * Return value: the GtkToolbar that was set as common toolbar for this
653 * #HildonProgram, or NULL of no common menu was set.
656 hildon_program_get_common_toolbar (HildonProgram *self)
658 HildonProgramPrivate *priv;
660 g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
662 priv = HILDON_PROGRAM_GET_PRIVATE (self);
665 return priv->common_toolbar ? GTK_TOOLBAR (priv->common_toolbar) : NULL;
669 * hildon_program_get_is_topmost:
670 * @self: A #HildonWindow
672 * Return value: Whether or not one of the program's window or dialog is
673 * currenltly activated by the window manager.
676 hildon_program_get_is_topmost (HildonProgram *self)
678 HildonProgramPrivate *priv;
680 g_return_val_if_fail (HILDON_IS_PROGRAM (self), FALSE);
682 priv = HILDON_PROGRAM_GET_PRIVATE (self);
685 return priv->is_topmost;