2 * This file is part of hildon-lgpl
4 * Copyright (C) 2005 Nokia Corporation.
6 * Contact: Luc Pionchon <luc.pionchon@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; either 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 * @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 = 0;
117 /* priv->group_leader = NULL;*/
121 hildon_program_finalize (GObject *self)
123 HildonProgramPriv *priv = HILDON_PROGRAM_GET_PRIVATE (HILDON_PROGRAM (self));
125 if (priv->common_toolbar)
127 g_object_unref (priv->common_toolbar);
128 priv->common_toolbar = NULL;
131 if (priv->common_menu)
133 g_object_unref (priv->common_menu);
134 priv->common_menu = NULL;
142 hildon_program_class_init (HildonProgramClass *self)
144 GObjectClass *object_class = G_OBJECT_CLASS(self);
146 g_type_class_add_private (self, sizeof(HildonProgramPriv));
148 /* Set up object virtual functions */
149 object_class->finalize = hildon_program_finalize;
150 object_class->set_property = hildon_program_set_property;
151 object_class->get_property = hildon_program_get_property;
153 /* Install properties */
154 g_object_class_install_property (object_class, PROP_IS_TOPMOST,
155 g_param_spec_boolean ("is-topmost",
157 "Whether one of the program's window or dialog currently "
158 "is activated by window manager",
162 g_object_class_install_property (object_class, PROP_KILLABLE,
163 g_param_spec_boolean ("can-hibernate",
165 "Whether the program should be set to hibernate by the Task "
166 "Navigator in low memory situation",
174 hildon_program_set_property (GObject * object, guint property_id,
175 const GValue * value, GParamSpec * pspec)
177 switch (property_id){
179 hildon_program_set_can_hibernate (HILDON_PROGRAM (object),
180 g_value_get_boolean (value));
184 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
191 hildon_program_get_property (GObject * object, guint property_id,
192 GValue * value, GParamSpec * pspec)
194 HildonProgramPriv *priv = HILDON_PROGRAM_GET_PRIVATE (object);
199 g_value_set_boolean (value, priv->killable);
201 case PROP_IS_TOPMOST:
202 g_value_set_boolean (value, priv->is_topmost);
205 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
213 hildon_program_window_list_compare (gconstpointer window_a,
214 gconstpointer window_b)
216 g_return_val_if_fail (1, HILDON_IS_WINDOW(window_a) &&
217 HILDON_IS_WINDOW(window_b));
219 return GTK_WIDGET (window_a)->window != GTK_WIDGET(window_b)->window;
223 * foreach function, checks if a window is topmost and acts consequently
226 hildon_program_window_list_is_is_topmost (gpointer data, gpointer window_id_)
228 if (data && HILDON_IS_WINDOW (data))
230 HildonWindow *window = HILDON_WINDOW (data);
231 Window window_id = * (Window*)window_id_;
233 hildon_window_update_topmost (window, window_id);
238 * Check the _MB_CURRENT_APP_WINDOW on the root window, and update
239 * the top_most status accordingly
242 hildon_program_update_top_most (HildonProgram *program)
245 Window active_window;
246 HildonProgramPriv *priv;
248 priv = HILDON_PROGRAM_GET_PRIVATE (program);
250 active_window = hildon_window_get_active_window();
252 wm_hints = XGetWMHints (GDK_DISPLAY (), active_window);
257 if (wm_hints->window_group == priv->window_group)
259 if (!priv->is_topmost)
261 priv->is_topmost = TRUE;
262 g_object_notify (G_OBJECT (program), "is-topmost");
265 else if (priv->is_topmost)
267 priv->is_topmost = FALSE;
268 g_object_notify (G_OBJECT (program), "is-topmost");
274 /* Check each window if it was is_topmost */
275 g_slist_foreach (priv->windows,
276 (GFunc)hildon_program_window_list_is_is_topmost, &active_window);
283 * We keep track of the _MB_CURRENT_APP_WINDOW property on the root window,
284 * to detect when a window belonging to this program was is_topmost. This
285 * is based on the window group WM hint.
287 static GdkFilterReturn
288 hildon_program_root_window_event_filter (GdkXEvent *xevent,
292 XAnyEvent *eventti = xevent;
293 HildonProgram *program = HILDON_PROGRAM (data);
294 Atom active_app_atom =
295 XInternAtom (GDK_DISPLAY (), "_MB_CURRENT_APP_WINDOW", False);
297 if (eventti->type == PropertyNotify)
299 XPropertyEvent *pevent = xevent;
301 if (pevent->atom == active_app_atom)
303 hildon_program_update_top_most (program);
307 return GDK_FILTER_CONTINUE;
314 * hildon_program_get_instance:
316 * Return value: Returns the #HildonProgram for the current process.
317 * The object is created on the first call.
320 hildon_program_get_instance ()
322 static HildonProgram *program = NULL;
326 program = g_object_new (HILDON_TYPE_PROGRAM, NULL);
333 * hildon_program_add_window:
334 * @program: The @HildonProgram to which the window should be registered
335 * @window: A @HildonWindow to be added
337 * Registers a @HildonWindow as belonging to a given @HildonProgram. This
338 * allows to apply program-wide settings as all the registered windows,
339 * such as hildon_program_set_common_menu() and
340 * hildon_pogram_set_common_toolbar()
343 hildon_program_add_window (HildonProgram *self, HildonWindow *window)
345 HildonProgramPriv *priv;
347 g_return_if_fail (self && HILDON_IS_PROGRAM (self));
349 priv = HILDON_PROGRAM_GET_PRIVATE (self);
351 if (g_slist_find_custom (priv->windows, window,
352 hildon_program_window_list_compare) )
354 /* We already have that window */
358 if (!priv->window_count)
360 priv->window_group = GDK_WINDOW_XID (gdk_window_get_group (
361 GTK_WIDGET (window)->window));
363 hildon_program_update_top_most (self);
365 /* Now that we have a window we should start keeping track of
367 gdk_window_set_events (gdk_get_default_root_window (),
368 gdk_window_get_events (gdk_get_default_root_window ()) | GDK_PROPERTY_CHANGE_MASK);
369 gdk_window_add_filter (gdk_get_default_root_window (),
370 hildon_program_root_window_event_filter, self );
373 hildon_window_set_can_hibernate_property (window, &priv->killable);
375 hildon_window_set_program (window, G_OBJECT (self));
377 priv->windows = g_slist_append (priv->windows, window);
378 priv->window_count ++;
382 * hildon_program_remove_window:
383 * @self: The #HildonProgram to which the window should be unregistered
384 * @window: The @HildonWindow to unregister
386 * Used to unregister a window from the program. Subsequent calls to
387 * hildon_program_set_common_menu() and hildon_pogram_set_common_toolbar()
388 * will not affect the window
391 hildon_program_remove_window (HildonProgram *self, HildonWindow *window)
393 HildonProgramPriv *priv;
395 g_return_if_fail (self && HILDON_IS_PROGRAM (self));
397 priv = HILDON_PROGRAM_GET_PRIVATE (self);
399 hildon_window_unset_program (window);
401 priv->windows = g_slist_remove (priv->windows, window);
403 priv->window_count --;
405 if (!priv->window_count)
407 gdk_window_remove_filter (gdk_get_default_root_window(),
408 hildon_program_root_window_event_filter,
414 * hildon_program_set_can_hibernate:
415 * @self: The #HildonProgram which can hibernate or not
416 * @can_hibernate: whether or not the #HildonProgram can hibernate
418 * Used to set whether or not the Hildon task navigator should
419 * be able to set the program to hibernation in case of low memory
422 hildon_program_set_can_hibernate (HildonProgram *self, gboolean killable)
424 HildonProgramPriv *priv;
426 g_return_if_fail (self && HILDON_IS_PROGRAM (self));
428 priv = HILDON_PROGRAM_GET_PRIVATE (self);
430 if (priv->killable != killable)
432 g_slist_foreach (priv->windows,
433 (GFunc)hildon_window_set_can_hibernate_property, &killable);
436 priv->killable = killable;
441 * hildon_program_get_can_hibernate:
442 * @self: The #HildonProgram which can hibernate or not
444 * Return value: Whether or not this #HildonProgram is set to be
445 * support hibernation from the Hildon task navigator
448 hildon_program_get_can_hibernate (HildonProgram *self)
450 HildonProgramPriv *priv;
452 g_return_val_if_fail (self && HILDON_IS_PROGRAM (self), FALSE);
454 priv = HILDON_PROGRAM_GET_PRIVATE (self);
456 return priv->killable;
461 * hildon_program_set_common_menu:
462 * @self: The #HildonProgram in which the common menu should be used
463 * @menu: A GtkMenu to use as common menu for the program
465 * Sets a GtkMenu that will appear in all the @HildonWindow registered
466 * to the #HildonProgram. Only one common GtkMenu can be set, further
467 * call will detach the previous common GtkMenu. A @HildonWindow
468 * can use it's own GtkMenu with @hildon_window_set_menu
471 hildon_program_set_common_menu (HildonProgram *self, GtkMenu *menu)
473 HildonProgramPriv *priv;
475 g_return_if_fail (self && HILDON_IS_PROGRAM (self));
477 priv = HILDON_PROGRAM_GET_PRIVATE (self);
479 if (priv->common_menu)
481 if (GTK_WIDGET_VISIBLE (priv->common_menu))
483 gtk_menu_popdown (GTK_MENU(priv->common_menu));
484 gtk_menu_shell_deactivate (GTK_MENU_SHELL (priv->common_menu));
487 if (gtk_menu_get_attach_widget (GTK_MENU (priv->common_menu)))
489 gtk_menu_detach (GTK_MENU (priv->common_menu));
493 g_object_unref (priv->common_menu);
497 priv->common_menu = GTK_WIDGET (menu);
499 if (priv->common_menu)
502 gtk_object_sink (GTK_OBJECT (menu));
503 gtk_widget_show_all (GTK_WIDGET (menu));
508 * hildon_program_get_common_menu:
509 * @self: The #HildonProgram from which to retrieve the common menu
511 * Return value: the GtkMenu that was set as common menu for this
512 * #HildonProgram, or NULL of no common menu was set.
515 hildon_program_get_common_menu (HildonProgram *self)
517 HildonProgramPriv *priv;
519 g_return_val_if_fail (self && HILDON_IS_PROGRAM (self), NULL);
521 priv = HILDON_PROGRAM_GET_PRIVATE (self);
523 return GTK_MENU (priv->common_menu);
527 * hildon_program_set_common_toolbar:
528 * @self: The #HildonProgram in which the common toolbar should be used
529 * @toolbar: A GtkToolbar to use as common toolbar for the program
531 * Sets a GtkToolbar that will appear in all the @HildonWindow registered
532 * to the #HildonProgram. Only one common GtkToolbar can be set, further
533 * call will detach the previous common GtkToolbar. A @HildonWindow
534 * can use its own GtkToolbar with @hildon_window_set_toolbar. Both
535 * #HildonProgram and @HildonWindow specific toolbars will be shown
538 hildon_program_set_common_toolbar (HildonProgram *self, GtkToolbar *toolbar)
540 HildonProgramPriv *priv;
542 g_return_if_fail (self && HILDON_IS_PROGRAM (self));
544 priv = HILDON_PROGRAM_GET_PRIVATE (self);
546 if (priv->common_toolbar)
548 if (priv->common_toolbar->parent)
550 gtk_widget_unparent(priv->common_toolbar->parent);
553 g_object_unref (priv->common_toolbar);
556 priv->common_toolbar = GTK_WIDGET (toolbar);
558 if (priv->common_toolbar)
560 g_object_ref (priv->common_toolbar);
561 gtk_object_sink (GTK_OBJECT (priv->common_toolbar) );
566 * hildon_program_get_common_toolbar:
567 * @self: The #HildonProgram from which to retrieve the common toolbar
569 * Return value: the GtkToolbar that was set as common toolbar for this
570 * #HildonProgram, or NULL of no common menu was set.
573 hildon_program_get_common_toolbar (HildonProgram *self)
575 HildonProgramPriv *priv;
577 g_return_val_if_fail (self && HILDON_IS_PROGRAM (self), NULL);
579 priv = HILDON_PROGRAM_GET_PRIVATE (self);
581 return priv->common_toolbar ? GTK_TOOLBAR (priv->common_toolbar) : NULL;
585 * hildon_program_get_is_topmost:
586 * @self: A #HildonWindow
588 * Return value: Whether or not one of the program's window or dialog is
589 * currenltly activated by the window manager.
592 hildon_program_get_is_topmost (HildonProgram *self)
594 HildonProgramPriv *priv;
596 g_return_val_if_fail (self && HILDON_IS_PROGRAM (self), FALSE);
598 priv = HILDON_PROGRAM_GET_PRIVATE (self);
600 return priv->is_topmost;