Do not set any flag for empty legacy menus
[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
662     GList *menu_children = gtk_container_get_children (GTK_CONTAINER (menu));
663     if (!priv->common_menu
664         && menu && menu_children != NULL) {
665         hildon_program_set_common_menu_flag (self, TRUE);
666     } else if (priv->common_menu &&
667                (!menu || menu_children == NULL))
668     {
669         hildon_program_set_common_menu_flag (self, FALSE);
670     }
671     g_list_free (menu_children);
672
673     priv->common_menu = menu;
674
675     if (priv->common_menu)
676     {
677         g_object_ref (menu);
678         gtk_object_sink (GTK_OBJECT (menu));
679         gtk_widget_show_all (GTK_WIDGET (menu));
680     }
681 }
682
683 /**
684  * hildon_program_get_common_menu:
685  * @self: The #HildonProgram from which to retrieve the common menu
686  *
687  * Returns the #GtkMenu that was set as common menu for this
688  * #HildonProgram.
689  *
690  * Return value: the #GtkMenu or %NULL of no common menu was set.
691  **/
692 GtkMenu*
693 hildon_program_get_common_menu                  (HildonProgram *self)
694 {
695     HildonProgramPrivate *priv;
696
697     g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
698
699     priv = HILDON_PROGRAM_GET_PRIVATE (self);
700     g_assert (priv);
701
702     return priv->common_menu;
703 }
704
705 static void
706 hildon_program_on_common_app_menu_changed       (HildonAppMenu *menu,
707                                                  HildonProgram *program)
708 {
709     hildon_program_set_common_menu_flag (program,
710                                          hildon_app_menu_has_visible_children (menu));
711 }
712
713 /**
714  * hildon_program_set_common_app_menu:
715  * @self: The #HildonProgram in which the common menu should be used
716  * @menu: A #HildonAppMenu to use as common menu for the program
717  *
718  * Sets a #HildonAppMenu that will appear in all
719  * #HildonWindow<!-- -->s registered with the #HildonProgram. Only
720  * one common #HildonAppMenu can be set, further calls will detach the
721  * previous common #HildonAppMenu. A #HildonWindow can use its own
722  * #HildonAppMenu with hildon_window_set_app_menu()
723  *
724  * This method does not support #GtkMenu<!-- -->s. See
725  * hildon_program_set_common_menu() for that.
726  *
727  * Since: 2.2
728  **/
729 void
730 hildon_program_set_common_app_menu              (HildonProgram *self,
731                                                  HildonAppMenu *menu)
732 {
733     HildonProgramPrivate *priv;
734     HildonAppMenu *old_menu;
735
736     g_return_if_fail (HILDON_IS_PROGRAM (self));
737     g_return_if_fail (menu == NULL || HILDON_IS_APP_MENU (menu));
738
739     priv = HILDON_PROGRAM_GET_PRIVATE (self);
740     g_assert (priv);
741
742     old_menu = priv->common_app_menu;
743
744     /* Only set the menu flag if there was no common menu and
745        we are setting one. If we are unsetting the current common menu,
746        remove the commmon menu flag. Otherwise, nothing to do. */
747     if (!priv->common_app_menu
748         && menu && hildon_app_menu_has_visible_children (menu)) {
749         hildon_program_set_common_menu_flag (self, TRUE);
750     } else if (priv->common_app_menu &&
751                (!menu || !hildon_app_menu_has_visible_children (menu))) {
752         hildon_program_set_common_menu_flag (self, FALSE);
753     }
754
755     /* Set new menu */
756     priv->common_app_menu = menu;
757     if (menu) {
758         g_signal_connect (menu, "changed",
759                           G_CALLBACK (hildon_program_on_common_app_menu_changed), self);
760         g_object_ref_sink (menu);
761     }
762
763     /* Hide and unref old menu */
764     if (old_menu) {
765         hildon_app_menu_set_parent_window (old_menu, NULL);
766         g_signal_handlers_disconnect_by_func (old_menu,
767                                               hildon_program_on_common_app_menu_changed,
768                                               self);
769         g_object_unref (old_menu);
770     }
771 }
772
773 /**
774  * hildon_program_get_common_app_menu:
775  * @self: The #HildonProgram from which to retrieve the common app menu
776  *
777  * Returns the #HildonAppMenu that was set as common menu for this
778  * #HildonProgram.
779  *
780  * Return value: the #HildonAppMenu or %NULL of no common app menu was
781  * set.
782  *
783  * Since: 2.2
784  **/
785 HildonAppMenu*
786 hildon_program_get_common_app_menu              (HildonProgram *self)
787 {
788     HildonProgramPrivate *priv;
789
790     g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
791
792     priv = HILDON_PROGRAM_GET_PRIVATE (self);
793     g_assert (priv);
794
795     return priv->common_app_menu;
796 }
797
798 /**
799  * hildon_program_set_common_toolbar:
800  * @self: The #HildonProgram in which the common toolbar should be used
801  * @toolbar: A #GtkToolbar to use as common toolbar for the program
802  *
803  * Sets a #GtkToolbar that will appear in all the #HildonWindow registered
804  * to the #HildonProgram. Only one common #GtkToolbar can be set, further
805  * call will detach the previous common #GtkToolbar. A #HildonWindow
806  * can use its own #GtkToolbar with hildon_window_add_toolbar(). Both
807  * #HildonProgram and #HildonWindow specific toolbars will be shown
808  **/
809 void
810 hildon_program_set_common_toolbar               (HildonProgram *self, 
811                                                  GtkToolbar *toolbar)
812 {
813     HildonProgramPrivate *priv;
814
815     g_return_if_fail (HILDON_IS_PROGRAM (self));
816
817     priv = HILDON_PROGRAM_GET_PRIVATE (self);
818     g_assert (priv);
819
820     if (priv->common_toolbar)
821     {
822         if (priv->common_toolbar->parent)
823         {
824             gtk_container_remove (GTK_CONTAINER (priv->common_toolbar->parent), 
825                                   priv->common_toolbar);
826         }
827         
828         g_object_unref (priv->common_toolbar);
829     }
830
831     priv->common_toolbar = GTK_WIDGET (toolbar);
832
833     if (priv->common_toolbar)
834     {
835         g_object_ref (priv->common_toolbar);
836         gtk_object_sink (GTK_OBJECT (priv->common_toolbar) );
837     }
838
839     /* if the program is the topmost we have to update the common
840        toolbar right now for the topmost window */
841     if (priv->is_topmost)
842       {
843         g_slist_foreach (priv->windows, 
844                          (GFunc) hildon_program_common_toolbar_topmost_window, NULL);
845       }
846 }
847
848 /**
849  * hildon_program_get_common_toolbar:
850  * @self: The #HildonProgram from which to retrieve the common toolbar
851  *
852  * Returns the #GtkToolbar that was set as common toolbar for this
853  * #HildonProgram.
854  *
855  * Return value: the #GtkToolbar or %NULL of no common toolbar was
856  * set.
857  **/
858 GtkToolbar*
859 hildon_program_get_common_toolbar               (HildonProgram *self)
860 {
861     HildonProgramPrivate *priv;
862
863     g_return_val_if_fail (HILDON_IS_PROGRAM (self), NULL);
864
865     priv = HILDON_PROGRAM_GET_PRIVATE (self);
866     g_assert (priv);
867
868     return priv->common_toolbar ? GTK_TOOLBAR (priv->common_toolbar) : NULL;
869 }
870
871 /**
872  * hildon_program_get_is_topmost:
873  * @self: A #HildonWindow
874  *
875  * Returns whether one of the program's windows or dialogs is
876  * currently activated by the window manager.
877  *
878  * Return value: %TRUE if a window or dialog is topmost, %FALSE
879  * otherwise.
880  **/
881 gboolean
882 hildon_program_get_is_topmost                   (HildonProgram *self)
883 {
884     HildonProgramPrivate *priv;
885
886     g_return_val_if_fail (HILDON_IS_PROGRAM (self), FALSE);
887     
888     priv = HILDON_PROGRAM_GET_PRIVATE (self);
889     g_assert (priv);
890
891     return priv->is_topmost;
892 }
893
894 /**
895  * hildon_program_go_to_root_window:
896  * @self: A #HildonProgram
897  *
898  * Goes to the root window of the stack.
899  *
900  * Deprecated: See #HildonWindowStack
901  *
902  * Since: 2.2
903  */
904 void
905 hildon_program_go_to_root_window                (HildonProgram *self)
906 {
907     HildonWindowStack *stack = hildon_window_stack_get_default ();
908     gint n = hildon_window_stack_size (stack);
909     g_warning ("%s: this function is deprecated. Use hildon_window_stack_pop() instead.", __FUNCTION__);
910     if (n > 1) {
911         hildon_window_stack_pop (stack, n-1, NULL);
912     }
913 }