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