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 * @file hildon-program.c
28 * This file implements the HildonProgram object
36 #include "hildon-program.h"
37 #include "hildon-program-private.h"
38 #include "hildon-window-private.h"
39 #include <X11/Xatom.h>
42 hildon_program_init (HildonProgram *self);
45 hildon_program_finalize (GObject *self);
48 hildon_program_class_init (HildonProgramClass *self);
51 hildon_program_get_property (GObject *object,
56 hildon_program_set_property (GObject *object,
69 hildon_program_get_type (void)
71 static GType program_type = 0;
75 static const GTypeInfo program_info =
77 sizeof (HildonProgramClass),
79 NULL, /* base_finalize */
80 (GClassInitFunc) hildon_program_class_init,
81 NULL, /* class_finalize */
82 NULL, /* class_data */
83 sizeof (HildonProgram),
85 (GInstanceInitFunc) hildon_program_init,
87 program_type = g_type_register_static(G_TYPE_OBJECT,
88 "HildonProgram", &program_info, 0);
94 hildon_program_init (HildonProgram *self)
96 HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (self);
99 priv->killable = FALSE;
100 priv->window_count = 0;
101 priv->is_topmost = FALSE;
102 priv->window_group = GDK_WINDOW_XID (gdk_display_get_default_group (gdk_display_get_default()));
103 priv->common_toolbar = NULL;
108 hildon_program_finalize (GObject *self)
110 HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (HILDON_PROGRAM (self));
113 if (priv->common_toolbar)
115 g_object_unref (priv->common_toolbar);
116 priv->common_toolbar = NULL;
119 if (priv->common_menu)
121 g_object_unref (priv->common_menu);
122 priv->common_menu = NULL;
129 hildon_program_class_init (HildonProgramClass *self)
131 GObjectClass *object_class = G_OBJECT_CLASS (self);
133 g_type_class_add_private (self, sizeof (HildonProgramPrivate));
135 /* Set up object virtual functions */
136 object_class->finalize = hildon_program_finalize;
137 object_class->set_property = hildon_program_set_property;
138 object_class->get_property = hildon_program_get_property;
140 /* Install properties */
141 g_object_class_install_property (object_class, PROP_IS_TOPMOST,
142 g_param_spec_boolean ("is-topmost",
144 "Whether one of the program's window or dialog currently "
145 "is activated by window manager",
149 g_object_class_install_property (object_class, PROP_KILLABLE,
150 g_param_spec_boolean ("can-hibernate",
152 "Whether the program should be set to hibernate by the Task "
153 "Navigator in low memory situation",
160 hildon_program_set_property (GObject *object,
165 switch (property_id) {
168 hildon_program_set_can_hibernate (HILDON_PROGRAM (object), g_value_get_boolean (value));
172 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
179 hildon_program_get_property (GObject *object,
184 HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (object);
190 g_value_set_boolean (value, priv->killable);
193 case PROP_IS_TOPMOST:
194 g_value_set_boolean (value, priv->is_topmost);
198 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
205 hildon_program_window_list_compare (gconstpointer window_a,
206 gconstpointer window_b)
208 g_return_val_if_fail (HILDON_IS_WINDOW(window_a) &&
209 HILDON_IS_WINDOW(window_b), 1);
211 return window_a != window_b;
215 * foreach function, checks if a window is topmost and acts consequently
218 hildon_program_window_list_is_is_topmost (gpointer data,
221 if (data && HILDON_IS_WINDOW (data))
223 HildonWindow *window = HILDON_WINDOW (data);
224 Window window_id = * (Window*)window_id_;
226 hildon_window_update_topmost (window, window_id);
231 * Check the _MB_CURRENT_APP_WINDOW on the root window, and update
232 * the top_most status accordingly
235 hildon_program_update_top_most (HildonProgram *program)
238 Window active_window;
239 HildonProgramPrivate *priv;
241 priv = HILDON_PROGRAM_GET_PRIVATE (program);
244 active_window = hildon_window_get_active_window();
248 wm_hints = XGetWMHints (GDK_DISPLAY (), active_window);
253 if (wm_hints->window_group == priv->window_group)
255 if (!priv->is_topmost)
257 priv->is_topmost = TRUE;
258 g_object_notify (G_OBJECT (program), "is-topmost");
261 else if (priv->is_topmost)
263 priv->is_topmost = FALSE;
264 g_object_notify (G_OBJECT (program), "is-topmost");
270 /* Check each window if it was is_topmost */
271 g_slist_foreach (priv->windows,
272 (GFunc)hildon_program_window_list_is_is_topmost, &active_window);
276 * We keep track of the _MB_CURRENT_APP_WINDOW property on the root window,
277 * to detect when a window belonging to this program was is_topmost. This
278 * is based on the window group WM hint.
280 static GdkFilterReturn
281 hildon_program_root_window_event_filter (GdkXEvent *xevent,
285 XAnyEvent *eventti = xevent;
286 HildonProgram *program = HILDON_PROGRAM (data);
287 Atom active_app_atom =
288 XInternAtom (GDK_DISPLAY (), "_MB_CURRENT_APP_WINDOW", False);
290 if (eventti->type == PropertyNotify)
292 XPropertyEvent *pevent = xevent;
294 if (pevent->atom == active_app_atom)
296 hildon_program_update_top_most (program);
300 return GDK_FILTER_CONTINUE;
304 * Checks if the window is the topmost window of the program and in
305 * that case forces the window to take the common toolbar.
308 hildon_program_common_toolbar_topmost_window (gpointer window,
311 if (HILDON_IS_WINDOW (window) && hildon_window_get_is_topmost (HILDON_WINDOW (window)))
312 hildon_window_take_common_toolbar (HILDON_WINDOW (window));
316 * hildon_program_get_instance:
318 * Return value: Returns the #HildonProgram for the current process.
319 * The object is created on the first call.
322 hildon_program_get_instance (void)
324 static HildonProgram *program = NULL;
328 program = g_object_new (HILDON_TYPE_PROGRAM, NULL);
335 * hildon_program_add_window:
336 * @program: The @HildonProgram to which the window should be registered
337 * @window: A @HildonWindow to be added
339 * Registers a @HildonWindow as belonging to a given @HildonProgram. This
340 * allows to apply program-wide settings as all the registered windows,
341 * such as hildon_program_set_common_menu() and
342 * hildon_pogram_set_common_toolbar()
345 hildon_program_add_window (HildonProgram *self,
346 HildonWindow *window)
348 HildonProgramPrivate *priv;
350 g_return_if_fail (HILDON_IS_PROGRAM (self));
352 priv = HILDON_PROGRAM_GET_PRIVATE (self);
355 if (g_slist_find_custom (priv->windows, window,
356 hildon_program_window_list_compare) )
358 /* We already have that window */
362 if (!priv->window_count)
364 hildon_program_update_top_most (self);
366 /* Now that we have a window we should start keeping track of
368 gdk_window_set_events (gdk_get_default_root_window (),
369 gdk_window_get_events (gdk_get_default_root_window ()) | GDK_PROPERTY_CHANGE_MASK);
371 gdk_window_add_filter (gdk_get_default_root_window (),
372 hildon_program_root_window_event_filter, self );
375 hildon_window_set_can_hibernate_property (window, &priv->killable);
377 hildon_window_set_program (window, G_OBJECT (self));
379 priv->windows = g_slist_append (priv->windows, window);
380 priv->window_count ++;
384 * hildon_program_remove_window:
385 * @self: The #HildonProgram to which the window should be unregistered
386 * @window: The @HildonWindow to unregister
388 * Used to unregister a window from the program. Subsequent calls to
389 * hildon_program_set_common_menu() and hildon_pogram_set_common_toolbar()
390 * will not affect the window
393 hildon_program_remove_window (HildonProgram *self,
394 HildonWindow *window)
396 HildonProgramPrivate *priv;
398 g_return_if_fail (HILDON_IS_PROGRAM (self));
400 priv = HILDON_PROGRAM_GET_PRIVATE (self);
403 hildon_window_unset_program (window);
405 priv->windows = g_slist_remove (priv->windows, window);
407 priv->window_count --;
409 if (! priv->window_count)
410 gdk_window_remove_filter (gdk_get_default_root_window(),
411 hildon_program_root_window_event_filter,
416 * hildon_program_set_can_hibernate:
417 * @self: The #HildonProgram which can hibernate or not
418 * @can_hibernate: whether or not the #HildonProgram can hibernate
420 * Used to set whether or not the Hildon task navigator should
421 * be able to set the program to hibernation in case of low memory
424 hildon_program_set_can_hibernate (HildonProgram *self,
427 HildonProgramPrivate *priv;
429 g_return_if_fail (HILDON_IS_PROGRAM (self));
431 priv = HILDON_PROGRAM_GET_PRIVATE (self);
434 if (priv->killable != killable)
436 g_slist_foreach (priv->windows,
437 (GFunc)hildon_window_set_can_hibernate_property, &killable);
440 priv->killable = killable;
444 * hildon_program_get_can_hibernate:
445 * @self: The #HildonProgram which can hibernate or not
447 * Return value: Whether or not this #HildonProgram is set to be
448 * support hibernation from the Hildon task navigator
451 hildon_program_get_can_hibernate (HildonProgram *self)
453 HildonProgramPrivate *priv;
455 g_return_val_if_fail (HILDON_IS_PROGRAM (self), FALSE);
457 priv = HILDON_PROGRAM_GET_PRIVATE (self);
460 return priv->killable;
464 * hildon_program_set_common_menu:
465 * @self: The #HildonProgram in which the common menu should be used
466 * @menu: A GtkMenu to use as common menu for the program
468 * Sets a GtkMenu that will appear in all the @HildonWindow registered
469 * to the #HildonProgram. Only one common GtkMenu can be set, further
470 * call will detach the previous common GtkMenu. A @HildonWindow
471 * can use it's own GtkMenu with @hildon_window_set_menu
474 hildon_program_set_common_menu (HildonProgram *self,
477 HildonProgramPrivate *priv;
479 g_return_if_fail (HILDON_IS_PROGRAM (self));
481 priv = HILDON_PROGRAM_GET_PRIVATE (self);
484 if (priv->common_menu)
486 if (GTK_WIDGET_VISIBLE (priv->common_menu))
488 gtk_menu_popdown (GTK_MENU (priv->common_menu));
489 gtk_menu_shell_deactivate (GTK_MENU_SHELL (priv->common_menu));
492 if (gtk_menu_get_attach_widget (GTK_MENU (priv->common_menu)))
494 gtk_menu_detach (GTK_MENU (priv->common_menu));
498 g_object_unref (priv->common_menu);
502 priv->common_menu = GTK_WIDGET (menu);
504 if (priv->common_menu)
507 gtk_object_sink (GTK_OBJECT (menu));
508 gtk_widget_show_all (GTK_WIDGET (menu));
513 * hildon_program_get_common_menu:
514 * @self: The #HildonProgram from which to retrieve the common menu
516 * Return value: the GtkMenu that was set as common menu for this
517 * #HildonProgram, or NULL of no common menu was set.
520 hildon_program_get_common_menu (HildonProgram *self)
522 HildonProgramPrivate *priv;
524 g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
526 priv = HILDON_PROGRAM_GET_PRIVATE (self);
529 return GTK_MENU (priv->common_menu);
533 * hildon_program_set_common_toolbar:
534 * @self: The #HildonProgram in which the common toolbar should be used
535 * @toolbar: A GtkToolbar to use as common toolbar for the program
537 * Sets a GtkToolbar that will appear in all the @HildonWindow registered
538 * to the #HildonProgram. Only one common GtkToolbar can be set, further
539 * call will detach the previous common GtkToolbar. A @HildonWindow
540 * can use its own GtkToolbar with @hildon_window_set_toolbar. Both
541 * #HildonProgram and @HildonWindow specific toolbars will be shown
544 hildon_program_set_common_toolbar (HildonProgram *self,
547 HildonProgramPrivate *priv;
549 g_return_if_fail (HILDON_IS_PROGRAM (self));
551 priv = HILDON_PROGRAM_GET_PRIVATE (self);
554 if (priv->common_toolbar)
556 if (priv->common_toolbar->parent)
558 gtk_container_remove (GTK_CONTAINER (priv->common_toolbar->parent),
559 priv->common_toolbar);
562 g_object_unref (priv->common_toolbar);
565 priv->common_toolbar = GTK_WIDGET (toolbar);
567 if (priv->common_toolbar)
569 g_object_ref (priv->common_toolbar);
570 gtk_object_sink (GTK_OBJECT (priv->common_toolbar) );
573 /* if the program is the topmost we have to update the common
574 toolbar right now for the topmost window */
575 if (priv->is_topmost)
577 g_slist_foreach (priv->windows,
578 (GFunc) hildon_program_common_toolbar_topmost_window, NULL);
583 * hildon_program_get_common_toolbar:
584 * @self: The #HildonProgram from which to retrieve the common toolbar
586 * Return value: the GtkToolbar that was set as common toolbar for this
587 * #HildonProgram, or NULL of no common menu was set.
590 hildon_program_get_common_toolbar (HildonProgram *self)
592 HildonProgramPrivate *priv;
594 g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
596 priv = HILDON_PROGRAM_GET_PRIVATE (self);
599 return priv->common_toolbar ? GTK_TOOLBAR (priv->common_toolbar) : NULL;
603 * hildon_program_get_is_topmost:
604 * @self: A #HildonWindow
606 * Return value: Whether or not one of the program's window or dialog is
607 * currenltly activated by the window manager.
610 hildon_program_get_is_topmost (HildonProgram *self)
612 HildonProgramPrivate *priv;
614 g_return_val_if_fail (HILDON_IS_PROGRAM (self), FALSE);
616 priv = HILDON_PROGRAM_GET_PRIVATE (self);
619 return priv->is_topmost;