2 * This file is part of hildon-libs
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 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 * @file hildon-program.c
28 * This file implements the HildonProgram object
32 #include "hildon-program.h"
33 #include "hildon-window-private.h"
36 #include <X11/Xatom.h>
39 #define HILDON_PROGRAM_GET_PRIVATE(obj) \
40 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), HILDON_TYPE_PROGRAM, HildonProgramPriv));
43 typedef struct _HildonProgramPriv HildonProgramPriv;
45 struct _HildonProgramPriv
49 GdkWindow *group_leader;
51 GtkWidget *common_menu;
52 GtkWidget *common_toolbar;
59 hildon_program_init (HildonProgram *self);
62 hildon_program_finalize (GObject *self);
65 hildon_program_class_init (HildonProgramClass *self);
68 hildon_program_get_property(GObject * object, guint property_id,
69 GValue * value, GParamSpec * pspec);
71 hildon_program_set_property (GObject * object, guint property_id,
72 const GValue * value, GParamSpec * pspec);
83 hildon_program_get_type (void)
85 static GType program_type = 0;
89 static const GTypeInfo program_info =
91 sizeof(HildonProgramClass),
93 NULL, /* base_finalize */
94 (GClassInitFunc) hildon_program_class_init,
95 NULL, /* class_finalize */
96 NULL, /* class_data */
97 sizeof(HildonProgram),
99 (GInstanceInitFunc) hildon_program_init,
101 program_type = g_type_register_static(G_TYPE_OBJECT,
102 "HildonProgram", &program_info, 0);
108 hildon_program_init (HildonProgram *self)
110 HildonProgramPriv *priv = HILDON_PROGRAM_GET_PRIVATE (self);
112 priv->killable = FALSE;
113 priv->window_count = 0;
114 priv->is_topmost = FALSE;
115 priv->window_group = GDK_WINDOW_XID (gdk_display_get_default_group
116 (gdk_display_get_default()));
117 priv->common_toolbar = NULL;
122 hildon_program_finalize (GObject *self)
124 HildonProgramPriv *priv = HILDON_PROGRAM_GET_PRIVATE (HILDON_PROGRAM (self));
126 if (priv->common_toolbar)
128 g_object_unref (priv->common_toolbar);
129 priv->common_toolbar = NULL;
132 if (priv->common_menu)
134 g_object_unref (priv->common_menu);
135 priv->common_menu = NULL;
143 hildon_program_class_init (HildonProgramClass *self)
145 GObjectClass *object_class = G_OBJECT_CLASS(self);
147 g_type_class_add_private (self, sizeof(HildonProgramPriv));
149 /* Set up object virtual functions */
150 object_class->finalize = hildon_program_finalize;
151 object_class->set_property = hildon_program_set_property;
152 object_class->get_property = hildon_program_get_property;
154 /* Install properties */
155 g_object_class_install_property (object_class, PROP_IS_TOPMOST,
156 g_param_spec_boolean ("is-topmost",
158 "Whether one of the program's window or dialog currently "
159 "is activated by window manager",
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",
175 hildon_program_set_property (GObject * object, guint property_id,
176 const GValue * value, GParamSpec * pspec)
178 switch (property_id){
180 hildon_program_set_can_hibernate (HILDON_PROGRAM (object),
181 g_value_get_boolean (value));
185 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
192 hildon_program_get_property (GObject * object, guint property_id,
193 GValue * value, GParamSpec * pspec)
195 HildonProgramPriv *priv = HILDON_PROGRAM_GET_PRIVATE (object);
200 g_value_set_boolean (value, priv->killable);
202 case PROP_IS_TOPMOST:
203 g_value_set_boolean (value, priv->is_topmost);
206 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
214 hildon_program_window_list_compare (gconstpointer window_a,
215 gconstpointer window_b)
217 g_return_val_if_fail (1, HILDON_IS_WINDOW(window_a) &&
218 HILDON_IS_WINDOW(window_b));
220 return window_a != window_b;
224 * foreach function, checks if a window is topmost and acts consequently
227 hildon_program_window_list_is_is_topmost (gpointer data, gpointer window_id_)
229 if (data && HILDON_IS_WINDOW (data))
231 HildonWindow *window = HILDON_WINDOW (data);
232 Window window_id = * (Window*)window_id_;
234 hildon_window_update_topmost (window, window_id);
239 * Check the _MB_CURRENT_APP_WINDOW on the root window, and update
240 * the top_most status accordingly
243 hildon_program_update_top_most (HildonProgram *program)
246 Window active_window;
247 HildonProgramPriv *priv;
249 priv = HILDON_PROGRAM_GET_PRIVATE (program);
251 active_window = hildon_window_get_active_window();
255 wm_hints = XGetWMHints (GDK_DISPLAY (), active_window);
260 if (wm_hints->window_group == priv->window_group)
262 if (!priv->is_topmost)
264 priv->is_topmost = TRUE;
265 g_object_notify (G_OBJECT (program), "is-topmost");
268 else if (priv->is_topmost)
270 priv->is_topmost = FALSE;
271 g_object_notify (G_OBJECT (program), "is-topmost");
277 /* Check each window if it was is_topmost */
278 g_slist_foreach (priv->windows,
279 (GFunc)hildon_program_window_list_is_is_topmost, &active_window);
286 * We keep track of the _MB_CURRENT_APP_WINDOW property on the root window,
287 * to detect when a window belonging to this program was is_topmost. This
288 * is based on the window group WM hint.
290 static GdkFilterReturn
291 hildon_program_root_window_event_filter (GdkXEvent *xevent,
295 XAnyEvent *eventti = xevent;
296 HildonProgram *program = HILDON_PROGRAM (data);
297 Atom active_app_atom =
298 XInternAtom (GDK_DISPLAY (), "_MB_CURRENT_APP_WINDOW", False);
300 if (eventti->type == PropertyNotify)
302 XPropertyEvent *pevent = xevent;
304 if (pevent->atom == active_app_atom)
306 hildon_program_update_top_most (program);
310 return GDK_FILTER_CONTINUE;
315 * hildon_program_common_toolbar_topmost_window:
316 * @window: A @HildonWindow to be informed about its new common toolbar
317 * @data: Not used, it is here just to respect the API
319 * Checks if the window is the topmost window of the program and in
320 * that case forces the window to take the common toolbar.
323 hildon_program_common_toolbar_topmost_window (gpointer window, gpointer data)
325 if (HILDON_IS_WINDOW (window) &&
326 hildon_window_get_is_topmost (HILDON_WINDOW (window)))
328 hildon_window_take_common_toolbar (HILDON_WINDOW (window));
335 * hildon_program_get_instance:
337 * Return value: Returns the #HildonProgram for the current process.
338 * The object is created on the first call.
341 hildon_program_get_instance ()
343 static HildonProgram *program = NULL;
347 program = g_object_new (HILDON_TYPE_PROGRAM, NULL);
354 * hildon_program_add_window:
355 * @program: The @HildonProgram to which the window should be registered
356 * @window: A @HildonWindow to be added
358 * Registers a @HildonWindow as belonging to a given @HildonProgram. This
359 * allows to apply program-wide settings as all the registered windows,
360 * such as hildon_program_set_common_menu() and
361 * hildon_pogram_set_common_toolbar()
364 hildon_program_add_window (HildonProgram *self, HildonWindow *window)
366 HildonProgramPriv *priv;
368 g_return_if_fail (self && HILDON_IS_PROGRAM (self));
370 priv = HILDON_PROGRAM_GET_PRIVATE (self);
372 if (g_slist_find_custom (priv->windows, window,
373 hildon_program_window_list_compare) )
375 /* We already have that window */
379 if (!priv->window_count)
381 hildon_program_update_top_most (self);
383 /* Now that we have a window we should start keeping track of
385 gdk_window_set_events (gdk_get_default_root_window (),
386 gdk_window_get_events (gdk_get_default_root_window ()) | GDK_PROPERTY_CHANGE_MASK);
387 gdk_window_add_filter (gdk_get_default_root_window (),
388 hildon_program_root_window_event_filter, self );
391 hildon_window_set_can_hibernate_property (window, &priv->killable);
393 hildon_window_set_program (window, G_OBJECT (self));
395 priv->windows = g_slist_append (priv->windows, window);
396 priv->window_count ++;
400 * hildon_program_remove_window:
401 * @self: The #HildonProgram to which the window should be unregistered
402 * @window: The @HildonWindow to unregister
404 * Used to unregister a window from the program. Subsequent calls to
405 * hildon_program_set_common_menu() and hildon_pogram_set_common_toolbar()
406 * will not affect the window
409 hildon_program_remove_window (HildonProgram *self, HildonWindow *window)
411 HildonProgramPriv *priv;
413 g_return_if_fail (self && HILDON_IS_PROGRAM (self));
415 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)
425 gdk_window_remove_filter (gdk_get_default_root_window(),
426 hildon_program_root_window_event_filter,
432 * hildon_program_set_can_hibernate:
433 * @self: The #HildonProgram which can hibernate or not
434 * @can_hibernate: whether or not the #HildonProgram can hibernate
436 * Used to set whether or not the Hildon task navigator should
437 * be able to set the program to hibernation in case of low memory
440 hildon_program_set_can_hibernate (HildonProgram *self, gboolean killable)
442 HildonProgramPriv *priv;
444 g_return_if_fail (self && HILDON_IS_PROGRAM (self));
446 priv = HILDON_PROGRAM_GET_PRIVATE (self);
448 if (priv->killable != killable)
450 g_slist_foreach (priv->windows,
451 (GFunc)hildon_window_set_can_hibernate_property, &killable);
454 priv->killable = killable;
459 * hildon_program_get_can_hibernate:
460 * @self: The #HildonProgram which can hibernate or not
462 * Return value: Whether or not this #HildonProgram is set to be
463 * support hibernation from the Hildon task navigator
466 hildon_program_get_can_hibernate (HildonProgram *self)
468 HildonProgramPriv *priv;
470 g_return_val_if_fail (self && HILDON_IS_PROGRAM (self), FALSE);
472 priv = HILDON_PROGRAM_GET_PRIVATE (self);
474 return priv->killable;
479 * hildon_program_set_common_menu:
480 * @self: The #HildonProgram in which the common menu should be used
481 * @menu: A GtkMenu to use as common menu for the program
483 * Sets a GtkMenu that will appear in all the @HildonWindow registered
484 * to the #HildonProgram. Only one common GtkMenu can be set, further
485 * call will detach the previous common GtkMenu. A @HildonWindow
486 * can use it's own GtkMenu with @hildon_window_set_menu
489 hildon_program_set_common_menu (HildonProgram *self, GtkMenu *menu)
491 HildonProgramPriv *priv;
493 g_return_if_fail (self && HILDON_IS_PROGRAM (self));
495 priv = HILDON_PROGRAM_GET_PRIVATE (self);
497 if (priv->common_menu)
499 if (GTK_WIDGET_VISIBLE (priv->common_menu))
501 gtk_menu_popdown (GTK_MENU(priv->common_menu));
502 gtk_menu_shell_deactivate (GTK_MENU_SHELL (priv->common_menu));
505 if (gtk_menu_get_attach_widget (GTK_MENU (priv->common_menu)))
507 gtk_menu_detach (GTK_MENU (priv->common_menu));
511 g_object_unref (priv->common_menu);
515 priv->common_menu = GTK_WIDGET (menu);
517 if (priv->common_menu)
520 gtk_object_sink (GTK_OBJECT (menu));
521 gtk_widget_show_all (GTK_WIDGET (menu));
526 * hildon_program_get_common_menu:
527 * @self: The #HildonProgram from which to retrieve the common menu
529 * Return value: the GtkMenu that was set as common menu for this
530 * #HildonProgram, or NULL of no common menu was set.
533 hildon_program_get_common_menu (HildonProgram *self)
535 HildonProgramPriv *priv;
537 g_return_val_if_fail (self && HILDON_IS_PROGRAM (self), NULL);
539 priv = HILDON_PROGRAM_GET_PRIVATE (self);
541 return GTK_MENU (priv->common_menu);
545 * hildon_program_set_common_toolbar:
546 * @self: The #HildonProgram in which the common toolbar should be used
547 * @toolbar: A GtkToolbar to use as common toolbar for the program
549 * Sets a GtkToolbar that will appear in all the @HildonWindow registered
550 * to the #HildonProgram. Only one common GtkToolbar can be set, further
551 * call will detach the previous common GtkToolbar. A @HildonWindow
552 * can use its own GtkToolbar with @hildon_window_set_toolbar. Both
553 * #HildonProgram and @HildonWindow specific toolbars will be shown
556 hildon_program_set_common_toolbar (HildonProgram *self, GtkToolbar *toolbar)
558 HildonProgramPriv *priv;
560 g_return_if_fail (self && HILDON_IS_PROGRAM (self));
562 priv = HILDON_PROGRAM_GET_PRIVATE (self);
564 if (priv->common_toolbar)
566 if (priv->common_toolbar->parent)
568 gtk_container_remove (GTK_CONTAINER (priv->common_toolbar->parent),
569 priv->common_toolbar);
572 g_object_unref (priv->common_toolbar);
575 priv->common_toolbar = GTK_WIDGET (toolbar);
577 if (priv->common_toolbar)
579 g_object_ref (priv->common_toolbar);
580 gtk_object_sink (GTK_OBJECT (priv->common_toolbar) );
583 /* if the program is the topmost we have to update the common
584 toolbar right now for the topmost window */
585 if (priv->is_topmost)
587 g_slist_foreach (priv->windows,
588 (GFunc) hildon_program_common_toolbar_topmost_window, NULL);
593 * hildon_program_get_common_toolbar:
594 * @self: The #HildonProgram from which to retrieve the common toolbar
596 * Return value: the GtkToolbar that was set as common toolbar for this
597 * #HildonProgram, or NULL of no common menu was set.
600 hildon_program_get_common_toolbar (HildonProgram *self)
602 HildonProgramPriv *priv;
604 g_return_val_if_fail (self && HILDON_IS_PROGRAM (self), NULL);
606 priv = HILDON_PROGRAM_GET_PRIVATE (self);
608 return priv->common_toolbar ? GTK_TOOLBAR (priv->common_toolbar) : NULL;
612 * hildon_program_get_is_topmost:
613 * @self: A #HildonWindow
615 * Return value: Whether or not one of the program's window or dialog is
616 * currenltly activated by the window manager.
619 hildon_program_get_is_topmost (HildonProgram *self)
621 HildonProgramPriv *priv;
623 g_return_val_if_fail (self && HILDON_IS_PROGRAM (self), FALSE);
625 priv = HILDON_PROGRAM_GET_PRIVATE (self);
627 return priv->is_topmost;