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.
28 * @see_also: #HildonWindow, #HildonStackableWindow
30 * The #HildonProgram is an object used to represent an application running
31 * in the Hildon framework.
33 * Such an application is thought to have one or more #HildonWindow. These
34 * shall be registered to the #HildonProgram with hildon_program_add_window(),
35 * and can be unregistered similarly with hildon_program_remove_window().
37 * The #HildonProgram provides the programmer with commodities such
38 * as applying a common toolbar and menu to all the #HildonWindow
39 * registered to it. This is done with hildon_program_set_common_menu()
40 * and hildon_program_set_common_toolbar().
42 * The #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;
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_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"
92 hildon_program_init (HildonProgram *self);
95 hildon_program_finalize (GObject *self);
98 hildon_program_class_init (HildonProgramClass *self);
101 hildon_program_get_property (GObject *object,
106 hildon_program_set_property (GObject *object,
119 hildon_program_get_type (void)
121 static GType program_type = 0;
125 static const GTypeInfo program_info =
127 sizeof (HildonProgramClass),
128 NULL, /* base_init */
129 NULL, /* base_finalize */
130 (GClassInitFunc) hildon_program_class_init,
131 NULL, /* class_finalize */
132 NULL, /* class_data */
133 sizeof (HildonProgram),
135 (GInstanceInitFunc) hildon_program_init,
137 program_type = g_type_register_static(G_TYPE_OBJECT,
138 "HildonProgram", &program_info, 0);
144 hildon_program_init (HildonProgram *self)
146 HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (self);
149 priv->killable = FALSE;
150 priv->window_count = 0;
151 priv->is_topmost = FALSE;
152 priv->window_group = GDK_WINDOW_XID (gdk_display_get_default_group (gdk_display_get_default()));
153 priv->common_toolbar = NULL;
154 priv->windows = NULL;
158 hildon_program_finalize (GObject *self)
160 HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (HILDON_PROGRAM (self));
163 if (priv->common_toolbar)
165 g_object_unref (priv->common_toolbar);
166 priv->common_toolbar = NULL;
169 if (priv->common_menu)
171 g_object_unref (priv->common_menu);
172 priv->common_menu = NULL;
177 hildon_program_class_init (HildonProgramClass *self)
179 GObjectClass *object_class = G_OBJECT_CLASS (self);
181 g_type_class_add_private (self, sizeof (HildonProgramPrivate));
183 /* Set up object virtual functions */
184 object_class->finalize = hildon_program_finalize;
185 object_class->set_property = hildon_program_set_property;
186 object_class->get_property = hildon_program_get_property;
188 /* Install properties */
191 * HildonProgram:is-topmost:
193 * Whether one of the program's window or dialog currently
194 * is activated by window manager.
196 g_object_class_install_property (object_class, PROP_IS_TOPMOST,
197 g_param_spec_boolean ("is-topmost",
199 "Whether one of the program's window or dialog currently "
200 "is activated by window manager",
205 * HildonProgram:can-hibernate:
207 * Whether the program should be set to hibernate by the Task
208 * Navigator in low memory situation.
210 g_object_class_install_property (object_class, PROP_KILLABLE,
211 g_param_spec_boolean ("can-hibernate",
213 "Whether the program should be set to hibernate by the Task "
214 "Navigator in low memory situation",
221 hildon_program_set_property (GObject *object,
226 switch (property_id) {
229 hildon_program_set_can_hibernate (HILDON_PROGRAM (object), g_value_get_boolean (value));
233 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
240 hildon_program_get_property (GObject *object,
245 HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (object);
251 g_value_set_boolean (value, priv->killable);
254 case PROP_IS_TOPMOST:
255 g_value_set_boolean (value, priv->is_topmost);
259 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
265 * hildon_program_pop_window_stack:
266 * @self: A #HildonProgram
268 * Deprecated: See #HildonWindowStack
272 HildonStackableWindow *
273 hildon_program_pop_window_stack (HildonProgram *self)
279 * hildon_program_peek_window_stack:
280 * @self: A #HildonProgram
282 * Deprecated: See #HildonWindowStack
286 HildonStackableWindow *
287 hildon_program_peek_window_stack (HildonProgram *self)
294 hildon_program_window_list_compare (gconstpointer window_a,
295 gconstpointer window_b)
297 g_return_val_if_fail (HILDON_IS_WINDOW(window_a) &&
298 HILDON_IS_WINDOW(window_b), 1);
300 return window_a != window_b;
304 * foreach function, checks if a window is topmost and acts consequently
307 hildon_program_window_list_is_is_topmost (gpointer data,
310 if (data && HILDON_IS_WINDOW (data))
312 HildonWindow *window = HILDON_WINDOW (data);
313 Window window_id = * (Window*)window_id_;
315 hildon_window_update_topmost (window, window_id);
320 * Check the _MB_CURRENT_APP_WINDOW on the root window, and update
321 * the top_most status accordingly
324 hildon_program_update_top_most (HildonProgram *program)
327 Window active_window;
328 HildonProgramPrivate *priv;
330 priv = HILDON_PROGRAM_GET_PRIVATE (program);
333 active_window = hildon_window_get_active_window();
339 gdk_error_trap_push ();
340 wm_hints = XGetWMHints (GDK_DISPLAY (), active_window);
341 xerror = gdk_error_trap_pop ();
348 if (wm_hints->window_group == priv->window_group)
350 if (!priv->is_topmost)
352 priv->is_topmost = TRUE;
353 g_object_notify (G_OBJECT (program), "is-topmost");
356 else if (priv->is_topmost)
358 priv->is_topmost = FALSE;
359 g_object_notify (G_OBJECT (program), "is-topmost");
365 /* Check each window if it was is_topmost */
366 g_slist_foreach (priv->windows,
367 (GFunc)hildon_program_window_list_is_is_topmost, &active_window);
371 * We keep track of the _MB_CURRENT_APP_WINDOW property on the root window,
372 * to detect when a window belonging to this program was is_topmost. This
373 * is based on the window group WM hint.
375 static GdkFilterReturn
376 hildon_program_root_window_event_filter (GdkXEvent *xevent,
380 XAnyEvent *eventti = xevent;
381 HildonProgram *program = HILDON_PROGRAM (data);
382 Atom active_app_atom =
383 XInternAtom (GDK_DISPLAY (), "_MB_CURRENT_APP_WINDOW", False);
385 if (eventti->type == PropertyNotify)
387 XPropertyEvent *pevent = xevent;
389 if (pevent->atom == active_app_atom)
391 hildon_program_update_top_most (program);
395 return GDK_FILTER_CONTINUE;
399 * Checks if the window is the topmost window of the program and in
400 * that case forces the window to take the common toolbar.
403 hildon_program_common_toolbar_topmost_window (gpointer window,
406 if (HILDON_IS_WINDOW (window) && hildon_window_get_is_topmost (HILDON_WINDOW (window)))
407 hildon_window_take_common_toolbar (HILDON_WINDOW (window));
411 * hildon_program_get_instance:
413 * Return value: Returns the #HildonProgram for the current process.
414 * The object is created on the first call. Note that you're not supposed
415 * to unref the returned object since it's not reffed in the first place.
418 hildon_program_get_instance (void)
420 static HildonProgram *program = NULL;
424 program = g_object_new (HILDON_TYPE_PROGRAM, NULL);
431 * hildon_program_add_window:
432 * @self: The #HildonProgram to which the window should be registered
433 * @window: A #HildonWindow to be added
435 * Registers a #HildonWindow as belonging to a given #HildonProgram. This
436 * allows to apply program-wide settings as all the registered windows,
437 * such as hildon_program_set_common_menu() and
438 * hildon_pogram_set_common_toolbar()
441 hildon_program_add_window (HildonProgram *self,
442 HildonWindow *window)
444 HildonProgramPrivate *priv;
446 g_return_if_fail (HILDON_IS_PROGRAM (self));
448 priv = HILDON_PROGRAM_GET_PRIVATE (self);
451 if (g_slist_find_custom (priv->windows, window,
452 hildon_program_window_list_compare) )
454 /* We already have that window */
458 if (!priv->window_count)
460 hildon_program_update_top_most (self);
462 /* Now that we have a window we should start keeping track of
464 gdk_window_set_events (gdk_get_default_root_window (),
465 gdk_window_get_events (gdk_get_default_root_window ()) | GDK_PROPERTY_CHANGE_MASK);
467 gdk_window_add_filter (gdk_get_default_root_window (),
468 hildon_program_root_window_event_filter, self );
471 hildon_window_set_can_hibernate_property (window, &priv->killable);
473 hildon_window_set_program (window, G_OBJECT (self));
475 priv->windows = g_slist_append (priv->windows, window);
476 priv->window_count ++;
480 * hildon_program_remove_window:
481 * @self: The #HildonProgram to which the window should be unregistered
482 * @window: The @HildonWindow to unregister
484 * Used to unregister a window from the program. Subsequent calls to
485 * hildon_program_set_common_menu() and hildon_pogram_set_common_toolbar()
486 * will not affect the window
489 hildon_program_remove_window (HildonProgram *self,
490 HildonWindow *window)
492 HildonProgramPrivate *priv;
494 g_return_if_fail (HILDON_IS_PROGRAM (self));
496 priv = HILDON_PROGRAM_GET_PRIVATE (self);
499 hildon_window_unset_program (window);
501 priv->windows = g_slist_remove (priv->windows, window);
503 priv->window_count --;
505 if (! priv->window_count)
506 gdk_window_remove_filter (gdk_get_default_root_window(),
507 hildon_program_root_window_event_filter,
512 * hildon_program_set_can_hibernate:
513 * @self: The #HildonProgram which can hibernate or not
514 * @can_hibernate: whether or not the #HildonProgram can hibernate
516 * Used to set whether or not the Hildon task navigator should
517 * be able to set the program to hibernation in case of low memory
520 hildon_program_set_can_hibernate (HildonProgram *self,
521 gboolean can_hibernate)
523 HildonProgramPrivate *priv;
525 g_return_if_fail (HILDON_IS_PROGRAM (self));
527 priv = HILDON_PROGRAM_GET_PRIVATE (self);
530 if (priv->killable != can_hibernate)
532 g_slist_foreach (priv->windows,
533 (GFunc) hildon_window_set_can_hibernate_property, &can_hibernate);
536 priv->killable = can_hibernate;
540 * hildon_program_get_can_hibernate:
541 * @self: The #HildonProgram which can hibernate or not
543 * Return value: Whether or not this #HildonProgram is set to be
544 * support hibernation from the Hildon task navigator
547 hildon_program_get_can_hibernate (HildonProgram *self)
549 HildonProgramPrivate *priv;
551 g_return_val_if_fail (HILDON_IS_PROGRAM (self), FALSE);
553 priv = HILDON_PROGRAM_GET_PRIVATE (self);
556 return priv->killable;
560 * hildon_program_set_common_menu:
561 * @self: The #HildonProgram in which the common menu should be used
562 * @menu: A GtkMenu to use as common menu for the program
564 * Sets a GtkMenu that will appear in all the #HildonWindow registered
565 * with the #HildonProgram. Only one common GtkMenu can be set, further
566 * calls will detach the previous common GtkMenu. A #HildonWindow
567 * can use it's own GtkMenu with hildon_window_set_menu()
569 * This method does not support #HildonAppMenu objects.
572 hildon_program_set_common_menu (HildonProgram *self,
575 HildonProgramPrivate *priv;
577 g_return_if_fail (HILDON_IS_PROGRAM (self));
579 priv = HILDON_PROGRAM_GET_PRIVATE (self);
582 if (priv->common_menu)
584 if (GTK_WIDGET_VISIBLE (priv->common_menu))
586 gtk_menu_popdown (GTK_MENU (priv->common_menu));
587 gtk_menu_shell_deactivate (GTK_MENU_SHELL (priv->common_menu));
590 if (gtk_menu_get_attach_widget (GTK_MENU (priv->common_menu)))
592 gtk_menu_detach (GTK_MENU (priv->common_menu));
596 g_object_unref (priv->common_menu);
600 priv->common_menu = GTK_WIDGET (menu);
602 if (priv->common_menu)
605 gtk_object_sink (GTK_OBJECT (menu));
606 gtk_widget_show_all (GTK_WIDGET (menu));
611 * hildon_program_get_common_menu:
612 * @self: The #HildonProgram from which to retrieve the common menu
614 * Return value: the GtkMenu that was set as common menu for this
615 * #HildonProgram, or %NULL of no common menu was set.
618 hildon_program_get_common_menu (HildonProgram *self)
620 HildonProgramPrivate *priv;
622 g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
624 priv = HILDON_PROGRAM_GET_PRIVATE (self);
627 return GTK_MENU (priv->common_menu);
631 * hildon_program_set_common_toolbar:
632 * @self: The #HildonProgram in which the common toolbar should be used
633 * @toolbar: A GtkToolbar to use as common toolbar for the program
635 * Sets a GtkToolbar that will appear in all the #HildonWindow registered
636 * to the #HildonProgram. Only one common GtkToolbar can be set, further
637 * call will detach the previous common GtkToolbar. A #HildonWindow
638 * can use its own GtkToolbar with hildon_window_add_toolbar(). Both
639 * #HildonProgram and #HildonWindow specific toolbars will be shown
642 hildon_program_set_common_toolbar (HildonProgram *self,
645 HildonProgramPrivate *priv;
647 g_return_if_fail (HILDON_IS_PROGRAM (self));
649 priv = HILDON_PROGRAM_GET_PRIVATE (self);
652 if (priv->common_toolbar)
654 if (priv->common_toolbar->parent)
656 gtk_container_remove (GTK_CONTAINER (priv->common_toolbar->parent),
657 priv->common_toolbar);
660 g_object_unref (priv->common_toolbar);
663 priv->common_toolbar = GTK_WIDGET (toolbar);
665 if (priv->common_toolbar)
667 g_object_ref (priv->common_toolbar);
668 gtk_object_sink (GTK_OBJECT (priv->common_toolbar) );
671 /* if the program is the topmost we have to update the common
672 toolbar right now for the topmost window */
673 if (priv->is_topmost)
675 g_slist_foreach (priv->windows,
676 (GFunc) hildon_program_common_toolbar_topmost_window, NULL);
681 * hildon_program_get_common_toolbar:
682 * @self: The #HildonProgram from which to retrieve the common toolbar
684 * Return value: the GtkToolbar that was set as common toolbar for this
685 * #HildonProgram, or %NULL of no common menu was set.
688 hildon_program_get_common_toolbar (HildonProgram *self)
690 HildonProgramPrivate *priv;
692 g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
694 priv = HILDON_PROGRAM_GET_PRIVATE (self);
697 return priv->common_toolbar ? GTK_TOOLBAR (priv->common_toolbar) : NULL;
701 * hildon_program_get_is_topmost:
702 * @self: A #HildonWindow
704 * Return value: Whether or not one of the program's window or dialog is
705 * currenltly activated by the window manager.
708 hildon_program_get_is_topmost (HildonProgram *self)
710 HildonProgramPrivate *priv;
712 g_return_val_if_fail (HILDON_IS_PROGRAM (self), FALSE);
714 priv = HILDON_PROGRAM_GET_PRIVATE (self);
717 return priv->is_topmost;
721 * hildon_program_go_to_root_window:
722 * @self: A #HildonProgram
724 * Deprecated: See #HildonWindowStack
727 hildon_program_go_to_root_window (HildonProgram *self)