Add HildonAppMenu::changed signal
[hildon] / hildon / hildon-program.c
1 /*
2  * This file is a part of hildon
3  *
4  * Copyright (C) 2006 Nokia Corporation, all rights reserved.
5  *
6  * Contact: Rodrigo Novo <rodrigo.novo@nokia.com>
7  *
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.
12  *
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.
17  *
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
21  * 02110-1301 USA
22  *
23  */
24
25 /**
26  * SECTION:hildon-program
27  * @short_description: Application abstraction in the Hildon framework.
28  * @see_also: #HildonWindow, #HildonStackableWindow
29  *
30  * #HildonProgram is an object used to represent an application running
31  * in the Hildon framework.
32  *
33  * Applications can have one or more #HildonWindow<!-- -->s. These
34  * can be registered in the #HildonProgram with hildon_program_add_window(),
35  * and can be unregistered similarly with hildon_program_remove_window().
36  *
37  * #HildonProgram provides the programmer with commodities such
38  * as applying a common toolbar and menu to all registered
39  * #HildonWindow<!-- -->s. This is done with hildon_program_set_common_menu(),
40  * hildon_program_set_common_app_menu() and hildon_program_set_common_toolbar().
41  *
42  * #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
46  * low memory.
47  *
48  * <example>
49  * <programlisting>
50  * HildonProgram *program;
51  * HildonWindow *window1;
52  * HildonWindow *window2;
53  * GtkToolbar *common_toolbar, *window_specific_toolbar;
54  * HildonAppMenu *menu;
55  * <!-- -->
56  * program = HILDON_PROGRAM (hildon_program_get_instance ());
57  * <!-- -->
58  * window1 = HILDON_WINDOW (hildon_window_new ());
59  * window2 = HILDON_WINDOW (hildon_window_new ());
60  * <!-- -->
61  * common_toolbar = create_common_toolbar ();
62  * window_specific_toolbar = create_window_specific_toolbar ();
63  * <!-- -->
64  * menu = create_menu ();
65  * <!-- -->
66  * hildon_program_add_window (program, window1);
67  * hildon_program_add_window (program, window2);
68  * <!-- -->
69  * hildon_program_set_common_app_menu (program, menu);
70  * <!-- -->
71  * hildon_program_set_common_toolbar (program, common_toolbar);
72  * hildon_window_add_toolbar (window1, window_specific_toolbar);
73  * <!-- -->
74  * hildon_program_set_can_hibernate (program, TRUE);
75  * </programlisting>
76  * </example>
77  */
78
79 #undef                                          HILDON_DISABLE_DEPRECATED
80
81 #ifdef                                          HAVE_CONFIG_H
82 #include                                        <config.h>
83 #endif
84
85 #include                                        <X11/Xatom.h>
86
87 #include                                        "hildon-program.h"
88 #include                                        "hildon-program-private.h"
89 #include                                        "hildon-window-private.h"
90 #include                                        "hildon-window-stack.h"
91 #include                                        "hildon-app-menu-private.h"
92
93 static void
94 hildon_program_init                             (HildonProgram *self);
95
96 static void
97 hildon_program_finalize                         (GObject *self);
98
99 static void
100 hildon_program_class_init                       (HildonProgramClass *self);
101
102 static void
103 hildon_program_get_property                     (GObject *object, 
104                                                  guint property_id,
105                                                  GValue *value, 
106                                                  GParamSpec *pspec);
107 static void
108 hildon_program_set_property                     (GObject *object, 
109                                                  guint property_id,
110                                                  const GValue *value, 
111                                                  GParamSpec *pspec);
112
113 enum
114 {
115     PROP_0,
116     PROP_IS_TOPMOST,
117     PROP_KILLABLE
118 };
119
120 GType G_GNUC_CONST
121 hildon_program_get_type                         (void)
122 {
123     static GType program_type = 0;
124
125     if (! program_type)
126     {
127         static const GTypeInfo program_info =
128         {
129             sizeof (HildonProgramClass),
130             NULL,       /* base_init */
131             NULL,       /* base_finalize */
132             (GClassInitFunc) hildon_program_class_init,
133             NULL,       /* class_finalize */
134             NULL,       /* class_data */
135             sizeof (HildonProgram),
136             0,  /* n_preallocs */
137             (GInstanceInitFunc) hildon_program_init,
138         };
139         program_type = g_type_register_static(G_TYPE_OBJECT,
140                 "HildonProgram", &program_info, 0);
141     }
142     return program_type;
143 }
144
145 static void
146 hildon_program_init                             (HildonProgram *self)
147 {
148     HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (self);
149     g_assert (priv);
150     
151     priv->killable = FALSE;
152     priv->window_count = 0;
153     priv->is_topmost = FALSE;
154     priv->window_group = GDK_WINDOW_XID (gdk_display_get_default_group (gdk_display_get_default()));
155     priv->common_menu = NULL;
156     priv->common_app_menu = NULL;
157     priv->common_toolbar = NULL;
158     priv->windows = NULL;
159 }
160
161 static void
162 hildon_program_finalize                         (GObject *self)
163 {
164     HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (HILDON_PROGRAM (self));
165     g_assert (priv);
166     
167     if (priv->common_toolbar)
168     {
169         g_object_unref (priv->common_toolbar);
170         priv->common_toolbar = NULL;
171     }
172
173     if (priv->common_menu)
174     {
175         g_object_unref (priv->common_menu);
176         priv->common_menu = NULL;
177     }
178 }
179
180 static void
181 hildon_program_class_init                       (HildonProgramClass *self)
182 {
183     GObjectClass *object_class = G_OBJECT_CLASS (self);
184
185     g_type_class_add_private (self, sizeof (HildonProgramPrivate));
186
187     /* Set up object virtual functions */
188     object_class->finalize      = hildon_program_finalize;
189     object_class->set_property  = hildon_program_set_property;
190     object_class->get_property  = hildon_program_get_property;
191
192     /* Install properties */
193
194     /**
195      * HildonProgram:is-topmost:
196      *
197      * Whether one of the program's window or dialog currently
198      * is activated by window manager. 
199      */
200     g_object_class_install_property (object_class, PROP_IS_TOPMOST,
201                 g_param_spec_boolean ("is-topmost",
202                 "Is top-most",
203                 "Whether one of the program's window or dialog currently "
204                 "is activated by window manager",
205                 FALSE,
206                 G_PARAM_READABLE)); 
207
208     /**
209      * HildonProgram:can-hibernate:
210      *
211      * Whether the program should be set to hibernate by the Task
212      * Navigator in low memory situation.
213      */
214     g_object_class_install_property (object_class, PROP_KILLABLE,
215                 g_param_spec_boolean ("can-hibernate",
216                 "Can hibernate",
217                 "Whether the program should be set to hibernate by the Task "
218                 "Navigator in low memory situation",
219                 FALSE,
220                 G_PARAM_READWRITE)); 
221     return;
222 }
223
224 static void
225 hildon_program_set_property                     (GObject *object, 
226                                                  guint property_id,
227                                                  const GValue *value, 
228                                                  GParamSpec *pspec)
229 {
230     switch (property_id) {
231
232         case PROP_KILLABLE:
233             hildon_program_set_can_hibernate (HILDON_PROGRAM (object), g_value_get_boolean (value));
234             break;
235             
236         default:
237             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
238             break;
239     }
240
241 }
242
243 static void
244 hildon_program_get_property                     (GObject *object, 
245                                                  guint property_id,
246                                                  GValue *value, 
247                                                  GParamSpec *pspec)
248 {
249     HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (object);
250     g_assert (priv);
251
252     switch (property_id)
253     {
254         case PROP_KILLABLE:
255             g_value_set_boolean (value, priv->killable);
256             break;
257
258         case PROP_IS_TOPMOST:
259             g_value_set_boolean (value, priv->is_topmost);
260             break;
261
262         default:
263             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
264             break;
265     }
266 }
267
268 /**
269  * hildon_program_pop_window_stack:
270  * @self: A #HildonProgram
271  *
272  * Pops a window from the stack.
273  *
274  * Deprecated: Use hildon_window_stack_pop() instead
275  *
276  * Returns: A #HildonStackableWindow, or %NULL
277  *
278  * Since: 2.2
279  */
280 HildonStackableWindow *
281 hildon_program_pop_window_stack                 (HildonProgram *self)
282 {
283     HildonWindowStack *stack = hildon_window_stack_get_default ();
284     GtkWidget *win = hildon_window_stack_pop_1 (stack);
285     g_warning ("%s: this function is deprecated. Use hildon_window_stack_pop() instead", __FUNCTION__);
286     return win ? HILDON_STACKABLE_WINDOW (win) : NULL;
287 }
288
289 /**
290  * hildon_program_peek_window_stack:
291  * @self: A #HildonProgram
292  *
293  * Deprecated: Use hildon_window_stack_peek() instead
294  *
295  * Returns: A #HildonStackableWindow, or %NULL
296  *
297  * Since: 2.2
298  */
299 HildonStackableWindow *
300 hildon_program_peek_window_stack                (HildonProgram *self)
301 {
302     HildonWindowStack *stack = hildon_window_stack_get_default ();
303     GtkWidget *win = hildon_window_stack_peek (stack);
304     g_warning ("%s: this function is deprecated. Use hildon_window_stack_peek() instead", __FUNCTION__);
305     return win ? HILDON_STACKABLE_WINDOW (win) : NULL;
306 }
307
308 /* Utilities */
309 static gint 
310 hildon_program_window_list_compare              (gconstpointer window_a, 
311                                                  gconstpointer window_b)
312 {
313     g_return_val_if_fail (HILDON_IS_WINDOW(window_a) && 
314                           HILDON_IS_WINDOW(window_b), 1);
315
316     return window_a != window_b;
317 }
318
319 /*
320  * foreach function, checks if a window is topmost and acts consequently
321  */
322 static void
323 hildon_program_window_list_is_is_topmost        (gpointer data, 
324                                                  gpointer window_id_)
325 {
326     if (data && HILDON_IS_WINDOW (data))
327     {
328         HildonWindow *window = HILDON_WINDOW (data);
329         Window window_id = * (Window*)window_id_;
330
331         hildon_window_update_topmost (window, window_id);
332     }
333 }
334
335 /*
336  * Check the _MB_CURRENT_APP_WINDOW on the root window, and update
337  * the top_most status accordingly
338  */
339 static void
340 hildon_program_update_top_most                  (HildonProgram *program)
341 {
342     gboolean is_topmost;
343     Window active_window;
344     HildonProgramPrivate *priv;
345
346     priv = HILDON_PROGRAM_GET_PRIVATE (program);
347     g_assert (priv);
348     
349     active_window = hildon_window_get_active_window();
350     is_topmost = FALSE;
351
352     if (active_window)
353     {
354       gint xerror;
355       XWMHints *wm_hints;
356       
357       gdk_error_trap_push ();
358       wm_hints = XGetWMHints (GDK_DISPLAY (), active_window);
359       xerror = gdk_error_trap_pop ();
360       if (xerror && xerror != BadWindow)
361       {
362         if (wm_hints)
363           XFree (wm_hints);
364         return;
365       }
366
367       if (wm_hints)
368       {
369         is_topmost = (wm_hints->window_group == priv->window_group);
370         XFree (wm_hints);
371       }
372     }
373
374     /* Send notification if is_topmost has changed */
375     if (!priv->is_topmost != !is_topmost)
376     {
377       priv->is_topmost = is_topmost;
378       g_object_notify (G_OBJECT (program), "is-topmost");
379     }
380
381     /* Check each window if it was is_topmost */
382     g_slist_foreach (priv->windows, 
383             (GFunc)hildon_program_window_list_is_is_topmost, &active_window);
384 }
385
386 /*
387  * We keep track of the _MB_CURRENT_APP_WINDOW property on the root window,
388  * to detect when a window belonging to this program was is_topmost. This
389  * is based on the window group WM hint.
390  */
391 static GdkFilterReturn
392 hildon_program_root_window_event_filter         (GdkXEvent *xevent,
393                                                  GdkEvent *event,
394                                                  gpointer data)
395 {
396     XAnyEvent *eventti = xevent;
397     HildonProgram *program = HILDON_PROGRAM (data);
398     Atom active_app_atom =
399             XInternAtom (GDK_DISPLAY (), "_MB_CURRENT_APP_WINDOW", False);
400
401     if (eventti->type == PropertyNotify)
402     {
403         XPropertyEvent *pevent = xevent;
404
405         if (pevent->atom == active_app_atom)
406         {
407             hildon_program_update_top_most (program);
408         }
409     }
410
411     return GDK_FILTER_CONTINUE;
412 }
413
414 static void
415 hildon_program_window_set_common_menu_flag (HildonWindow *window,
416                                             gboolean common_menu)
417 {
418     if (HILDON_IS_WINDOW (window))
419     {
420         gboolean has_menu = hildon_window_get_app_menu (window) ||
421             hildon_window_get_main_menu (window);
422
423         if (!has_menu) {
424             hildon_window_set_menu_flag (window, common_menu);
425         }
426     }
427 }
428
429 static void
430 hildon_program_set_common_menu_flag (HildonProgram *self,
431                                      gboolean common_menu)
432 {
433     HildonProgramPrivate *priv = HILDON_PROGRAM_GET_PRIVATE (self);
434
435     g_slist_foreach (priv->windows,
436                      (GFunc) hildon_program_window_set_common_menu_flag,
437                      GINT_TO_POINTER (common_menu));
438 }
439
440 /* 
441  * Checks if the window is the topmost window of the program and in
442  * that case forces the window to take the common toolbar.
443  */
444 static void
445 hildon_program_common_toolbar_topmost_window    (gpointer window, 
446                                                  gpointer data)
447 {
448     if (HILDON_IS_WINDOW (window) && hildon_window_get_is_topmost (HILDON_WINDOW (window)))
449         hildon_window_take_common_toolbar (HILDON_WINDOW (window));
450 }
451
452 /**
453  * hildon_program_get_instance:
454  *
455  * Returns the #HildonProgram for the current process. The object is
456  * created on the first call. Note that you're not supposed to unref
457  * the returned object since it's not reffed in the first place.
458  *
459  * Return value: the #HildonProgram.
460  **/
461 HildonProgram*
462 hildon_program_get_instance                     (void)
463 {
464     static HildonProgram *program = NULL;
465
466     if (! program)
467     {
468         program = g_object_new (HILDON_TYPE_PROGRAM, NULL);
469     }
470
471     return program;
472 }
473
474 /**
475  * hildon_program_add_window:
476  * @self: The #HildonProgram to which the window should be registered
477  * @window: A #HildonWindow to be added
478  *
479  * Registers a #HildonWindow as belonging to a given #HildonProgram. This
480  * allows to apply program-wide settings as all the registered windows,
481  * such as hildon_program_set_common_menu(), hildon_program_set_common_app_menu()
482  * and hildon_program_set_common_toolbar().
483  **/
484 void
485 hildon_program_add_window                       (HildonProgram *self, 
486                                                  HildonWindow *window)
487 {
488     HildonProgramPrivate *priv;
489     
490     g_return_if_fail (HILDON_IS_PROGRAM (self));
491     g_return_if_fail (HILDON_IS_WINDOW (window));
492     
493     priv = HILDON_PROGRAM_GET_PRIVATE (self);
494     g_assert (priv);
495
496     if (g_slist_find_custom (priv->windows, window,
497            hildon_program_window_list_compare) )
498     {
499         /* We already have that window */
500         return;
501     }
502
503     if (!priv->window_count)
504     {
505         hildon_program_update_top_most (self);
506         
507         /* Now that we have a window we should start keeping track of
508          * the root window */
509         gdk_window_set_events (gdk_get_default_root_window (),
510                 gdk_window_get_events (gdk_get_default_root_window ()) | GDK_PROPERTY_CHANGE_MASK);
511
512         gdk_window_add_filter (gdk_get_default_root_window (),
513                 hildon_program_root_window_event_filter, self );
514     }
515     
516     hildon_window_set_can_hibernate_property (window, &priv->killable);
517
518     hildon_window_set_program (window, G_OBJECT (self));
519
520     if (priv->common_menu || priv->common_app_menu)
521         hildon_program_window_set_common_menu_flag (window, TRUE);
522
523     priv->windows = g_slist_append (priv->windows, window);
524     priv->window_count ++;
525 }
526
527 /**
528  * hildon_program_remove_window:
529  * @self: The #HildonProgram to which the window should be unregistered
530  * @window: The #HildonWindow to unregister
531  *
532  * Used to unregister a window from the program. Subsequent calls to
533  * hildon_program_set_common_menu(), hildon_program_set_common_app_menu()
534  * and hildon_program_set_common_toolbar() will not affect the window.
535  **/
536 void
537 hildon_program_remove_window                    (HildonProgram *self, 
538                                                  HildonWindow *window)
539 {
540     HildonProgramPrivate *priv;
541     
542     g_return_if_fail (HILDON_IS_PROGRAM (self));
543     g_return_if_fail (HILDON_IS_WINDOW (window));
544     
545     priv = HILDON_PROGRAM_GET_PRIVATE (self);
546     g_assert (priv);
547     
548     g_return_if_fail (g_slist_find (priv->windows, window));
549
550     hildon_window_unset_program (window);
551
552     priv->windows = g_slist_remove (priv->windows, window);
553
554     priv->window_count --;
555
556     if (! priv->window_count)
557         gdk_window_remove_filter (gdk_get_default_root_window(),
558                 hildon_program_root_window_event_filter,
559                 self);
560
561     if (priv->common_menu || priv->common_app_menu)
562         hildon_program_window_set_common_menu_flag (window, FALSE);
563 }
564
565 /**
566  * hildon_program_set_can_hibernate:
567  * @self: The #HildonProgram which can hibernate or not
568  * @can_hibernate: whether or not the #HildonProgram can hibernate
569  *
570  * Used to set whether or not the Hildon task navigator should
571  * be able to set the program to hibernation in case of low memory
572  **/
573 void
574 hildon_program_set_can_hibernate                (HildonProgram *self, 
575                                                  gboolean can_hibernate)
576 {
577     HildonProgramPrivate *priv;
578     
579     g_return_if_fail (HILDON_IS_PROGRAM (self));
580     
581     priv = HILDON_PROGRAM_GET_PRIVATE (self);
582     g_assert (priv);
583
584     if (priv->killable != can_hibernate)
585     {
586         g_slist_foreach (priv->windows, 
587                 (GFunc) hildon_window_set_can_hibernate_property, &can_hibernate);
588     }
589
590     priv->killable = can_hibernate;
591 }
592
593 /**
594  * hildon_program_get_can_hibernate:
595  * @self: The #HildonProgram which can hibernate or not
596  *
597  * Returns whether the #HildonProgram is set to be support hibernation
598  * from the Hildon task navigator
599  *
600  * Return value: %TRUE if the program can hibernate, %FALSE otherwise.
601  **/
602 gboolean
603 hildon_program_get_can_hibernate                (HildonProgram *self)
604 {
605     HildonProgramPrivate *priv;
606     
607     g_return_val_if_fail (HILDON_IS_PROGRAM (self), FALSE);
608    
609     priv = HILDON_PROGRAM_GET_PRIVATE (self);
610     g_assert (priv);
611
612     return priv->killable;
613 }
614
615 /**
616  * hildon_program_set_common_menu:
617  * @self: The #HildonProgram in which the common menu should be used
618  * @menu: A #GtkMenu to use as common menu for the program
619  *
620  * Sets a #GtkMenu that will appear in all #HildonWindow<!-- -->s
621  * registered with the #HildonProgram. Only one common #GtkMenu can be
622  * set, further calls will detach the previous common #GtkMenu. A
623  * #HildonWindow can use its own #GtkMenu with
624  * hildon_window_set_menu()
625  *
626  * This method does not support #HildonAppMenu<!-- -->s. See
627  * hildon_program_set_common_app_menu() for that.
628  **/
629 void
630 hildon_program_set_common_menu                  (HildonProgram *self, 
631                                                  GtkMenu *menu)
632 {
633     HildonProgramPrivate *priv;
634
635     g_return_if_fail (HILDON_IS_PROGRAM (self));
636
637     priv = HILDON_PROGRAM_GET_PRIVATE (self);
638     g_assert (priv);
639
640     if (priv->common_menu)
641     {
642         if (GTK_WIDGET_VISIBLE (priv->common_menu))
643         {
644             gtk_menu_popdown (priv->common_menu);
645             gtk_menu_shell_deactivate (GTK_MENU_SHELL (priv->common_menu));
646         }
647
648         if (gtk_menu_get_attach_widget (priv->common_menu))
649         {
650             gtk_menu_detach (priv->common_menu);
651         }
652         else
653         {
654             g_object_unref (priv->common_menu);
655         }
656     }
657
658     /* Only set the menu flag if there was no common menu and
659        we are setting one. If we are unsetting the current common menu,
660        remove the commmon menu flag. Otherwise, nothing to do. */
661     if (!priv->common_menu && menu) {
662         hildon_program_set_common_menu_flag (self, TRUE);
663     } else if (priv->common_menu && !menu) {
664         hildon_program_set_common_menu_flag (self, FALSE);
665     }
666
667     priv->common_menu = menu;
668
669     if (priv->common_menu)
670     {
671         g_object_ref (menu);
672         gtk_object_sink (GTK_OBJECT (menu));
673         gtk_widget_show_all (GTK_WIDGET (menu));
674     }
675 }
676
677 /**
678  * hildon_program_get_common_menu:
679  * @self: The #HildonProgram from which to retrieve the common menu
680  *
681  * Returns the #GtkMenu that was set as common menu for this
682  * #HildonProgram.
683  *
684  * Return value: the #GtkMenu or %NULL of no common menu was set.
685  **/
686 GtkMenu*
687 hildon_program_get_common_menu                  (HildonProgram *self)
688 {
689     HildonProgramPrivate *priv;
690
691     g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
692
693     priv = HILDON_PROGRAM_GET_PRIVATE (self);
694     g_assert (priv);
695
696     return priv->common_menu;
697 }
698
699 /**
700  * hildon_program_set_common_app_menu:
701  * @self: The #HildonProgram in which the common menu should be used
702  * @menu: A #HildonAppMenu to use as common menu for the program
703  *
704  * Sets a #HildonAppMenu that will appear in all
705  * #HildonWindow<!-- -->s registered with the #HildonProgram. Only
706  * one common #HildonAppMenu can be set, further calls will detach the
707  * previous common #HildonAppMenu. A #HildonWindow can use its own
708  * #HildonAppMenu with hildon_window_set_app_menu()
709  *
710  * This method does not support #GtkMenu<!-- -->s. See
711  * hildon_program_set_common_menu() for that.
712  *
713  * Since: 2.2
714  **/
715 void
716 hildon_program_set_common_app_menu              (HildonProgram *self,
717                                                  HildonAppMenu *menu)
718 {
719     HildonProgramPrivate *priv;
720     HildonAppMenu *old_menu;
721
722     g_return_if_fail (HILDON_IS_PROGRAM (self));
723     g_return_if_fail (menu == NULL || HILDON_IS_APP_MENU (menu));
724
725     priv = HILDON_PROGRAM_GET_PRIVATE (self);
726     g_assert (priv);
727
728     old_menu = priv->common_app_menu;
729
730     /* Only set the menu flag if there was no common menu and
731        we are setting one. If we are unsetting the current common menu,
732        remove the commmon menu flag. Otherwise, nothing to do. */
733     if (!priv->common_app_menu && menu) {
734         hildon_program_set_common_menu_flag (self, TRUE);
735     } else if (priv->common_app_menu && !menu) {
736         hildon_program_set_common_menu_flag (self, FALSE);
737     }
738
739     /* Set new menu */
740     priv->common_app_menu = menu;
741     if (menu)
742         g_object_ref_sink (menu);
743
744     /* Hide and unref old menu */
745     if (old_menu) {
746         hildon_app_menu_set_parent_window (old_menu, NULL);
747         g_object_unref (old_menu);
748     }
749 }
750
751 /**
752  * hildon_program_get_common_app_menu:
753  * @self: The #HildonProgram from which to retrieve the common app menu
754  *
755  * Returns the #HildonAppMenu that was set as common menu for this
756  * #HildonProgram.
757  *
758  * Return value: the #HildonAppMenu or %NULL of no common app menu was
759  * set.
760  *
761  * Since: 2.2
762  **/
763 HildonAppMenu*
764 hildon_program_get_common_app_menu              (HildonProgram *self)
765 {
766     HildonProgramPrivate *priv;
767
768     g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
769
770     priv = HILDON_PROGRAM_GET_PRIVATE (self);
771     g_assert (priv);
772
773     return priv->common_app_menu;
774 }
775
776 /**
777  * hildon_program_set_common_toolbar:
778  * @self: The #HildonProgram in which the common toolbar should be used
779  * @toolbar: A #GtkToolbar to use as common toolbar for the program
780  *
781  * Sets a #GtkToolbar that will appear in all the #HildonWindow registered
782  * to the #HildonProgram. Only one common #GtkToolbar can be set, further
783  * call will detach the previous common #GtkToolbar. A #HildonWindow
784  * can use its own #GtkToolbar with hildon_window_add_toolbar(). Both
785  * #HildonProgram and #HildonWindow specific toolbars will be shown
786  **/
787 void
788 hildon_program_set_common_toolbar               (HildonProgram *self, 
789                                                  GtkToolbar *toolbar)
790 {
791     HildonProgramPrivate *priv;
792
793     g_return_if_fail (HILDON_IS_PROGRAM (self));
794
795     priv = HILDON_PROGRAM_GET_PRIVATE (self);
796     g_assert (priv);
797
798     if (priv->common_toolbar)
799     {
800         if (priv->common_toolbar->parent)
801         {
802             gtk_container_remove (GTK_CONTAINER (priv->common_toolbar->parent), 
803                                   priv->common_toolbar);
804         }
805         
806         g_object_unref (priv->common_toolbar);
807     }
808
809     priv->common_toolbar = GTK_WIDGET (toolbar);
810
811     if (priv->common_toolbar)
812     {
813         g_object_ref (priv->common_toolbar);
814         gtk_object_sink (GTK_OBJECT (priv->common_toolbar) );
815     }
816
817     /* if the program is the topmost we have to update the common
818        toolbar right now for the topmost window */
819     if (priv->is_topmost)
820       {
821         g_slist_foreach (priv->windows, 
822                          (GFunc) hildon_program_common_toolbar_topmost_window, NULL);
823       }
824 }
825
826 /**
827  * hildon_program_get_common_toolbar:
828  * @self: The #HildonProgram from which to retrieve the common toolbar
829  *
830  * Returns the #GtkToolbar that was set as common toolbar for this
831  * #HildonProgram.
832  *
833  * Return value: the #GtkToolbar or %NULL of no common toolbar was
834  * set.
835  **/
836 GtkToolbar*
837 hildon_program_get_common_toolbar               (HildonProgram *self)
838 {
839     HildonProgramPrivate *priv;
840
841     g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
842
843     priv = HILDON_PROGRAM_GET_PRIVATE (self);
844     g_assert (priv);
845
846     return priv->common_toolbar ? GTK_TOOLBAR (priv->common_toolbar) : NULL;
847 }
848
849 /**
850  * hildon_program_get_is_topmost:
851  * @self: A #HildonWindow
852  *
853  * Returns whether one of the program's windows or dialogs is
854  * currently activated by the window manager.
855  *
856  * Return value: %TRUE if a window or dialog is topmost, %FALSE
857  * otherwise.
858  **/
859 gboolean
860 hildon_program_get_is_topmost                   (HildonProgram *self)
861 {
862     HildonProgramPrivate *priv;
863
864     g_return_val_if_fail (HILDON_IS_PROGRAM (self), FALSE);
865     
866     priv = HILDON_PROGRAM_GET_PRIVATE (self);
867     g_assert (priv);
868
869     return priv->is_topmost;
870 }
871
872 /**
873  * hildon_program_go_to_root_window:
874  * @self: A #HildonProgram
875  *
876  * Goes to the root window of the stack.
877  *
878  * Deprecated: See #HildonWindowStack
879  *
880  * Since: 2.2
881  */
882 void
883 hildon_program_go_to_root_window                (HildonProgram *self)
884 {
885     HildonWindowStack *stack = hildon_window_stack_get_default ();
886     gint n = hildon_window_stack_size (stack);
887     g_warning ("%s: this function is deprecated. Use hildon_window_stack_pop() instead.", __FUNCTION__);
888     if (n > 1) {
889         hildon_window_stack_pop (stack, n-1, NULL);
890     }
891 }