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
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 used to control a hildon program.
29 * HildonProgram is not a widget itself nor a container. HildonProgram can
30 * contain one or more @HildonWindow.
37 #include "hildon-program.h"
38 #include "hildon-program-private.h"
39 #include "hildon-window-private.h"
40 #include <X11/Xatom.h>
43 hildon_program_init (HildonProgram *self);
46 hildon_program_finalize (GObject *self);
49 hildon_program_class_init (HildonProgramClass *self);
52 hildon_program_get_property (GObject *object,
57 hildon_program_set_property (GObject *object,
70 hildon_program_get_type (void)
72 static GType program_type = 0;
76 static const GTypeInfo program_info =
78 sizeof (HildonProgramClass),
80 NULL, /* base_finalize */
81 (GClassInitFunc) hildon_program_class_init,
82 NULL, /* class_finalize */
83 NULL, /* class_data */
84 sizeof (HildonProgram),
86 (GInstanceInitFunc) hildon_program_init,
88 program_type = g_type_register_static(G_TYPE_OBJECT,
89 "HildonProgram", &program_info, 0);
95 hildon_program_init (HildonProgram *self)
97 HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (self);
100 priv->killable = FALSE;
101 priv->window_count = 0;
102 priv->is_topmost = FALSE;
103 priv->window_group = GDK_WINDOW_XID (gdk_display_get_default_group (gdk_display_get_default()));
104 priv->common_toolbar = NULL;
109 hildon_program_finalize (GObject *self)
111 HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (HILDON_PROGRAM (self));
114 if (priv->common_toolbar)
116 g_object_unref (priv->common_toolbar);
117 priv->common_toolbar = NULL;
120 if (priv->common_menu)
122 g_object_unref (priv->common_menu);
123 priv->common_menu = NULL;
130 hildon_program_class_init (HildonProgramClass *self)
132 GObjectClass *object_class = G_OBJECT_CLASS (self);
134 g_type_class_add_private (self, sizeof (HildonProgramPrivate));
136 /* Set up object virtual functions */
137 object_class->finalize = hildon_program_finalize;
138 object_class->set_property = hildon_program_set_property;
139 object_class->get_property = hildon_program_get_property;
141 /* Install properties */
144 * HildonProgram:is-topmost:
146 * Whether one of the program's window or dialog currently
147 * is activated by window manager.
149 g_object_class_install_property (object_class, PROP_IS_TOPMOST,
150 g_param_spec_boolean ("is-topmost",
152 "Whether one of the program's window or dialog currently "
153 "is activated by window manager",
158 * HildonProgram:can-hibernate:
160 * Whether the program should be set to hibernate by the Task
161 * Navigator in low memory situation.
163 g_object_class_install_property (object_class, PROP_KILLABLE,
164 g_param_spec_boolean ("can-hibernate",
166 "Whether the program should be set to hibernate by the Task "
167 "Navigator in low memory situation",
174 hildon_program_set_property (GObject *object,
179 switch (property_id) {
182 hildon_program_set_can_hibernate (HILDON_PROGRAM (object), g_value_get_boolean (value));
186 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
193 hildon_program_get_property (GObject *object,
198 HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (object);
204 g_value_set_boolean (value, priv->killable);
207 case PROP_IS_TOPMOST:
208 g_value_set_boolean (value, priv->is_topmost);
212 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
219 hildon_program_window_list_compare (gconstpointer window_a,
220 gconstpointer window_b)
222 g_return_val_if_fail (HILDON_IS_WINDOW(window_a) &&
223 HILDON_IS_WINDOW(window_b), 1);
225 return window_a != window_b;
229 * foreach function, checks if a window is topmost and acts consequently
232 hildon_program_window_list_is_is_topmost (gpointer data,
235 if (data && HILDON_IS_WINDOW (data))
237 HildonWindow *window = HILDON_WINDOW (data);
238 Window window_id = * (Window*)window_id_;
240 hildon_window_update_topmost (window, window_id);
245 * Check the _MB_CURRENT_APP_WINDOW on the root window, and update
246 * the top_most status accordingly
249 hildon_program_update_top_most (HildonProgram *program)
252 Window active_window;
253 HildonProgramPrivate *priv;
255 priv = HILDON_PROGRAM_GET_PRIVATE (program);
258 active_window = hildon_window_get_active_window();
262 wm_hints = XGetWMHints (GDK_DISPLAY (), active_window);
267 if (wm_hints->window_group == priv->window_group)
269 if (!priv->is_topmost)
271 priv->is_topmost = TRUE;
272 g_object_notify (G_OBJECT (program), "is-topmost");
275 else if (priv->is_topmost)
277 priv->is_topmost = FALSE;
278 g_object_notify (G_OBJECT (program), "is-topmost");
284 /* Check each window if it was is_topmost */
285 g_slist_foreach (priv->windows,
286 (GFunc)hildon_program_window_list_is_is_topmost, &active_window);
290 * We keep track of the _MB_CURRENT_APP_WINDOW property on the root window,
291 * to detect when a window belonging to this program was is_topmost. This
292 * is based on the window group WM hint.
294 static GdkFilterReturn
295 hildon_program_root_window_event_filter (GdkXEvent *xevent,
299 XAnyEvent *eventti = xevent;
300 HildonProgram *program = HILDON_PROGRAM (data);
301 Atom active_app_atom =
302 XInternAtom (GDK_DISPLAY (), "_MB_CURRENT_APP_WINDOW", False);
304 if (eventti->type == PropertyNotify)
306 XPropertyEvent *pevent = xevent;
308 if (pevent->atom == active_app_atom)
310 hildon_program_update_top_most (program);
314 return GDK_FILTER_CONTINUE;
318 * Checks if the window is the topmost window of the program and in
319 * that case forces the window to take the common toolbar.
322 hildon_program_common_toolbar_topmost_window (gpointer window,
325 if (HILDON_IS_WINDOW (window) && hildon_window_get_is_topmost (HILDON_WINDOW (window)))
326 hildon_window_take_common_toolbar (HILDON_WINDOW (window));
330 * hildon_program_get_instance:
332 * Return value: Returns the #HildonProgram for the current process.
333 * The object is created on the first call.
336 hildon_program_get_instance (void)
338 static HildonProgram *program = NULL;
342 program = g_object_new (HILDON_TYPE_PROGRAM, NULL);
349 * hildon_program_add_window:
350 * @self: The @HildonProgram to which the window should be registered
351 * @window: A @HildonWindow to be added
353 * Registers a @HildonWindow as belonging to a given @HildonProgram. This
354 * allows to apply program-wide settings as all the registered windows,
355 * such as hildon_program_set_common_menu() and
356 * hildon_pogram_set_common_toolbar()
359 hildon_program_add_window (HildonProgram *self,
360 HildonWindow *window)
362 HildonProgramPrivate *priv;
364 g_return_if_fail (HILDON_IS_PROGRAM (self));
366 priv = HILDON_PROGRAM_GET_PRIVATE (self);
369 if (g_slist_find_custom (priv->windows, window,
370 hildon_program_window_list_compare) )
372 /* We already have that window */
376 if (!priv->window_count)
378 hildon_program_update_top_most (self);
380 /* Now that we have a window we should start keeping track of
382 gdk_window_set_events (gdk_get_default_root_window (),
383 gdk_window_get_events (gdk_get_default_root_window ()) | GDK_PROPERTY_CHANGE_MASK);
385 gdk_window_add_filter (gdk_get_default_root_window (),
386 hildon_program_root_window_event_filter, self );
389 hildon_window_set_can_hibernate_property (window, &priv->killable);
391 hildon_window_set_program (window, G_OBJECT (self));
393 priv->windows = g_slist_append (priv->windows, window);
394 priv->window_count ++;
398 * hildon_program_remove_window:
399 * @self: The #HildonProgram to which the window should be unregistered
400 * @window: The @HildonWindow to unregister
402 * Used to unregister a window from the program. Subsequent calls to
403 * hildon_program_set_common_menu() and hildon_pogram_set_common_toolbar()
404 * will not affect the window
407 hildon_program_remove_window (HildonProgram *self,
408 HildonWindow *window)
410 HildonProgramPrivate *priv;
412 g_return_if_fail (HILDON_IS_PROGRAM (self));
414 priv = HILDON_PROGRAM_GET_PRIVATE (self);
417 hildon_window_unset_program (window);
419 priv->windows = g_slist_remove (priv->windows, window);
421 priv->window_count --;
423 if (! priv->window_count)
424 gdk_window_remove_filter (gdk_get_default_root_window(),
425 hildon_program_root_window_event_filter,
430 * hildon_program_set_can_hibernate:
431 * @self: The #HildonProgram which can hibernate or not
432 * @can_hibernate: whether or not the #HildonProgram can hibernate
434 * Used to set whether or not the Hildon task navigator should
435 * be able to set the program to hibernation in case of low memory
438 hildon_program_set_can_hibernate (HildonProgram *self,
439 gboolean can_hibernate)
441 HildonProgramPrivate *priv;
443 g_return_if_fail (HILDON_IS_PROGRAM (self));
445 priv = HILDON_PROGRAM_GET_PRIVATE (self);
448 if (priv->killable != can_hibernate)
450 g_slist_foreach (priv->windows,
451 (GFunc) hildon_window_set_can_hibernate_property, &can_hibernate);
454 priv->killable = can_hibernate;
458 * hildon_program_get_can_hibernate:
459 * @self: The #HildonProgram which can hibernate or not
461 * Return value: Whether or not this #HildonProgram is set to be
462 * support hibernation from the Hildon task navigator
465 hildon_program_get_can_hibernate (HildonProgram *self)
467 HildonProgramPrivate *priv;
469 g_return_val_if_fail (HILDON_IS_PROGRAM (self), FALSE);
471 priv = HILDON_PROGRAM_GET_PRIVATE (self);
474 return priv->killable;
478 * hildon_program_set_common_menu:
479 * @self: The #HildonProgram in which the common menu should be used
480 * @menu: A GtkMenu to use as common menu for the program
482 * Sets a GtkMenu that will appear in all the @HildonWindow registered
483 * to the #HildonProgram. Only one common GtkMenu can be set, further
484 * call will detach the previous common GtkMenu. A @HildonWindow
485 * can use it's own GtkMenu with @hildon_window_set_menu
488 hildon_program_set_common_menu (HildonProgram *self,
491 HildonProgramPrivate *priv;
493 g_return_if_fail (HILDON_IS_PROGRAM (self));
495 priv = HILDON_PROGRAM_GET_PRIVATE (self);
498 if (priv->common_menu)
500 if (GTK_WIDGET_VISIBLE (priv->common_menu))
502 gtk_menu_popdown (GTK_MENU (priv->common_menu));
503 gtk_menu_shell_deactivate (GTK_MENU_SHELL (priv->common_menu));
506 if (gtk_menu_get_attach_widget (GTK_MENU (priv->common_menu)))
508 gtk_menu_detach (GTK_MENU (priv->common_menu));
512 g_object_unref (priv->common_menu);
516 priv->common_menu = GTK_WIDGET (menu);
518 if (priv->common_menu)
521 gtk_object_sink (GTK_OBJECT (menu));
522 gtk_widget_show_all (GTK_WIDGET (menu));
527 * hildon_program_get_common_menu:
528 * @self: The #HildonProgram from which to retrieve the common menu
530 * Return value: the GtkMenu that was set as common menu for this
531 * #HildonProgram, or NULL of no common menu was set.
534 hildon_program_get_common_menu (HildonProgram *self)
536 HildonProgramPrivate *priv;
538 g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
540 priv = HILDON_PROGRAM_GET_PRIVATE (self);
543 return GTK_MENU (priv->common_menu);
547 * hildon_program_set_common_toolbar:
548 * @self: The #HildonProgram in which the common toolbar should be used
549 * @toolbar: A GtkToolbar to use as common toolbar for the program
551 * Sets a GtkToolbar that will appear in all the @HildonWindow registered
552 * to the #HildonProgram. Only one common GtkToolbar can be set, further
553 * call will detach the previous common GtkToolbar. A @HildonWindow
554 * can use its own GtkToolbar with @hildon_window_set_toolbar. Both
555 * #HildonProgram and @HildonWindow specific toolbars will be shown
558 hildon_program_set_common_toolbar (HildonProgram *self,
561 HildonProgramPrivate *priv;
563 g_return_if_fail (HILDON_IS_PROGRAM (self));
565 priv = HILDON_PROGRAM_GET_PRIVATE (self);
568 if (priv->common_toolbar)
570 if (priv->common_toolbar->parent)
572 gtk_container_remove (GTK_CONTAINER (priv->common_toolbar->parent),
573 priv->common_toolbar);
576 g_object_unref (priv->common_toolbar);
579 priv->common_toolbar = GTK_WIDGET (toolbar);
581 if (priv->common_toolbar)
583 g_object_ref (priv->common_toolbar);
584 gtk_object_sink (GTK_OBJECT (priv->common_toolbar) );
587 /* if the program is the topmost we have to update the common
588 toolbar right now for the topmost window */
589 if (priv->is_topmost)
591 g_slist_foreach (priv->windows,
592 (GFunc) hildon_program_common_toolbar_topmost_window, NULL);
597 * hildon_program_get_common_toolbar:
598 * @self: The #HildonProgram from which to retrieve the common toolbar
600 * Return value: the GtkToolbar that was set as common toolbar for this
601 * #HildonProgram, or NULL of no common menu was set.
604 hildon_program_get_common_toolbar (HildonProgram *self)
606 HildonProgramPrivate *priv;
608 g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
610 priv = HILDON_PROGRAM_GET_PRIVATE (self);
613 return priv->common_toolbar ? GTK_TOOLBAR (priv->common_toolbar) : NULL;
617 * hildon_program_get_is_topmost:
618 * @self: A #HildonWindow
620 * Return value: Whether or not one of the program's window or dialog is
621 * currenltly activated by the window manager.
624 hildon_program_get_is_topmost (HildonProgram *self)
626 HildonProgramPrivate *priv;
628 g_return_val_if_fail (HILDON_IS_PROGRAM (self), FALSE);
630 priv = HILDON_PROGRAM_GET_PRIVATE (self);
633 return priv->is_topmost;