Misc documentation updates
[hildon] / hildon / hildon-window.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-window
27  * @short_description: Widget representing a top-level window in the Hildon framework.
28  * @see_also: #HildonProgram, #HildonStackableWindow
29  *
30  * #HildonWindow is a GTK widget which represents a top-level
31  * window in the Hildon framework. It is derived from #GtkWindow
32  * and provides additional commodities specific to the Hildon
33  * framework.
34  *
35  * #HildonWindow<!-- -->s can have a menu attached, which is toggled
36  * with a hardware key or by tapping on the window frame. This menu
37  * can be either a #GtkMenu or a #HildonAppMenu (set with
38  * hildon_window_set_main_menu() and hildon_window_set_app_menu()
39  * respectively). Only one type of menu can be used at the same time.
40  * In Hildon 2.2, #HildonAppMenu is the recommended menu to use.
41  *
42  * Similarly, a #HildonWindow can have several toolbars
43  * attached. These can be added with hildon_window_add_toolbar(). In
44  * addition to those, a #HildonWindow can also have a
45  * #HildonEditToolbar. To add it to the window use
46  * hildon_window_set_edit_toolbar().
47  *
48  * <example>
49  * <title>Creating a HildonWindow</title>
50  * <programlisting>
51  * HildonWindow *window;
52  * GtkToolbar *toolbar;
53  * HildonAppMenu *menu;
54  * GdkPixbuf *icon_pixbuf;
55  * <!-- -->
56  * window = HILDON_WINDOW (hildon_window_new());
57  * <!-- -->
58  * toolbar = create_toolbar();
59  * <!-- -->
60  * menu = create_menu();
61  * <!-- -->
62  * icon_pixbuf = create_icon();
63  * <!-- -->
64  * hildon_window_set_app_menu (window, menu);
65  * <!-- -->
66  * hildon_window_add_toolbar (window, toolbar);
67  * <!-- -->
68  * // Can be used to set the window fullscreen
69  * gtk_window_fullscreen (GTK_WINDOW (window));
70  * <!-- -->
71  * // Used to trigger the blinking of the window's icon in the task navigator
72  * gtk_window_set_urgency_hint (GTK_WINDOW (window), TRUE);
73  * <!-- -->
74  * // Change the window's icon in the task navigator
75  * gtk_window_set_icon (GTK_WINDOW (window), icon_pixbuf);
76  * </programlisting>
77  * </example>
78  */
79
80 #undef                                          HILDON_DISABLE_DEPRECATED
81
82 #include                                        <memory.h>
83 #include                                        <string.h>
84 #include                                        <strings.h>
85 #include                                        <stdio.h>
86 #include                                        <libintl.h>
87 #include                                        <X11/X.h>
88 #include                                        <X11/Xatom.h>
89 #include                                        <gdk/gdkkeysyms.h>
90 #include                                        <gdk/gdkx.h>
91 #include                                        <gtk/gtkprivate.h>
92
93 #include                                        "hildon-window.h"
94 #include                                        "hildon-window-private.h"
95 #include                                        "hildon-app-menu-private.h"
96 #include                                        "hildon-find-toolbar.h"
97 #include                                        "hildon-defines.h"
98
99 #define                                         _(String) gettext(String)
100
101 #define                                         TOOLBAR_HEIGHT 70
102
103 #define                                         TOOLBAR_MIDDLE 0
104
105 /*FIXME*/
106 #define                                         CAN_HIBERNATE "CANKILL"
107
108 #define                                         CAN_HIBERNATE_LENGTH 7
109
110 #define                                         CAN_HIBERNATE_PROPERTY "_HILDON_ABLE_TO_HIBERNATE"
111
112 #define TITLE_SEPARATOR                         " - "
113
114 typedef void                                    (*HildonWindowSignal) (HildonWindow *, gint, gpointer);
115
116 static void
117 hildon_window_init                              (HildonWindow * self);
118
119 static void
120 hildon_window_class_init                        (HildonWindowClass * window_class);
121
122 static void
123 hildon_window_menu_popup_func                   (GtkMenu *menu, 
124                                                  gint *x, 
125                                                  gint *y,
126                                                  gboolean *push_in,
127                                                  GtkWidget *widget);
128 static void
129 hildon_window_menu_popup_func_full              (GtkMenu *menu, 
130                                                  gint *x, 
131                                                  gint *y,
132                                                  gboolean *push_in,
133                                                  GtkWidget *widget);
134 static gboolean
135 hildon_window_expose                            (GtkWidget *widget, 
136                                                  GdkEventExpose *event);
137 static void 
138 hildon_window_forall                            (GtkContainer *container,
139                                                  gboolean include_internals,
140                                                  GtkCallback callback,
141                                                  gpointer callback_data);
142 static void
143 hildon_window_show_all                          (GtkWidget *widget);
144
145 static void
146 hildon_window_size_allocate                     (GtkWidget * widget,
147                                                  GtkAllocation *allocation);
148 static void
149 hildon_window_size_request                      (GtkWidget * widget,
150                                                  GtkRequisition *requisition);
151 static void
152 hildon_window_finalize                          (GObject *obj_self);
153
154 static void
155 hildon_window_get_property                      (GObject *object,
156                                                  guint property_id,
157                                                  GValue *value, 
158                                                  GParamSpec *pspec);
159
160 static void
161 hildon_window_set_property                      (GObject      *object,
162                                                  guint         property_id,
163                                                  const GValue *value,
164                                                  GParamSpec   *pspec);
165
166 static void
167 hildon_window_update_markup                     (HildonWindow *window);
168
169 static void
170 hildon_window_destroy                           (GtkObject *obj);
171
172 static void
173 hildon_window_realize                           (GtkWidget *widget);
174
175 static void
176 hildon_window_unrealize                         (GtkWidget *widget);
177
178 static void
179 hildon_window_map                               (GtkWidget *widget);
180
181 static void
182 hildon_window_unmap                             (GtkWidget *widget);
183
184 static gboolean
185 hildon_window_key_press_event                   (GtkWidget *widget,
186                                                  GdkEventKey *event);
187
188 static gboolean
189 hildon_window_key_release_event                 (GtkWidget *widget, 
190                                                  GdkEventKey *event);
191 static gboolean
192 hildon_window_window_state_event                (GtkWidget *widget, 
193                                                  GdkEventWindowState *event);
194 static gboolean
195 hildon_window_focus_out_event                   (GtkWidget *widget, 
196                                                  GdkEventFocus *event);
197
198 static void
199 hildon_window_notify                            (GObject *gobject, 
200                                                  GParamSpec *param);
201
202 static void
203 hildon_window_is_topmost_notify                 (HildonWindow *window);
204
205 static gboolean
206 hildon_window_toggle_menu                       (HildonWindow * self,
207                                                  guint button,
208                                                  guint32 time);
209
210 static gboolean
211 hildon_window_toggle_menu_real                  (HildonWindow * self,
212                                                  guint button,
213                                                  guint32 time);
214
215 static gboolean
216 hildon_window_escape_timeout                    (gpointer data);
217
218 static GdkFilterReturn
219 hildon_window_event_filter                      (GdkXEvent *xevent, 
220                                                  GdkEvent *event, 
221                                                  gpointer data);
222
223 static GdkFilterReturn
224 hildon_window_root_window_event_filter          (GdkXEvent *xevent, 
225                                                  GdkEvent *event, 
226                                                  gpointer data );
227
228 static void
229 hildon_window_get_borders                       (HildonWindow *window);
230
231 static void
232 visible_toolbar                                 (gpointer data, 
233                                                  gpointer user_data);
234
235 static void
236 paint_toolbar                                   (GtkWidget *widget, 
237                                                  GtkBox *box, 
238                                                  GdkEventExpose * event, 
239                                                  gboolean fullscreen);
240
241 static void
242 paint_edit_toolbar                              (GtkWidget *widget,
243                                                  GtkWidget *toolbar,
244                                                  GdkEventExpose *event,
245                                                  gboolean fullscreen);
246
247 enum
248 {
249     PROP_0,
250     PROP_IS_TOPMOST,
251     PROP_MARKUP
252 };
253
254 enum
255 {
256     WIN_TYPE = 0,
257     WIN_TYPE_MESSAGE,
258     MAX_WIN_MESSAGES
259 };
260
261 G_DEFINE_TYPE (HildonWindow, hildon_window, GTK_TYPE_WINDOW);
262
263 static void 
264 hildon_window_class_init                        (HildonWindowClass * window_class)
265 {
266     /* Get convenience variables */
267     GtkWidgetClass *widget_class        = GTK_WIDGET_CLASS (window_class);
268     GObjectClass *object_class          = G_OBJECT_CLASS (window_class);
269     GtkContainerClass *container_class  = GTK_CONTAINER_CLASS (window_class);
270
271     object_class->get_property          = hildon_window_get_property;
272     object_class->set_property          = hildon_window_set_property;
273     object_class->notify                = hildon_window_notify;
274     widget_class->size_allocate         = hildon_window_size_allocate;
275     widget_class->size_request          = hildon_window_size_request;
276     widget_class->expose_event          = hildon_window_expose;
277     widget_class->show_all              = hildon_window_show_all;
278     widget_class->realize               = hildon_window_realize;
279     widget_class->unrealize             = hildon_window_unrealize;
280     widget_class->key_press_event       = hildon_window_key_press_event;
281     widget_class->key_release_event     = hildon_window_key_release_event;
282     widget_class->window_state_event    = hildon_window_window_state_event;
283     widget_class->focus_out_event       = hildon_window_focus_out_event;
284     widget_class->map                   = hildon_window_map;
285     widget_class->unmap                 = hildon_window_unmap;
286
287     /* now the object stuff */
288     object_class->finalize              = hildon_window_finalize;
289
290     /* To the container */
291     container_class->forall             = hildon_window_forall;
292
293     /* To this class */
294     window_class->toggle_menu           = hildon_window_toggle_menu_real;
295
296     /* gtkobject stuff*/
297     GTK_OBJECT_CLASS (window_class)->destroy = hildon_window_destroy; 
298
299     g_type_class_add_private (window_class,
300             sizeof (struct _HildonWindowPrivate));
301
302     /* Install properties */
303
304     g_object_class_install_property (object_class, PROP_IS_TOPMOST,
305             g_param_spec_boolean ("is-topmost",
306                 "Is top-most",
307                 "Whether the window is currently activated by the window "
308                 "manager",
309                 FALSE,
310                 G_PARAM_READABLE));
311
312     g_object_class_install_property (object_class, PROP_MARKUP,
313             g_param_spec_string ("markup",
314                 "Marked up text for the window title",
315                 "Marked up text for the window title",
316                 NULL,
317                 G_PARAM_READWRITE));
318
319     gtk_widget_class_install_style_property (widget_class,
320             g_param_spec_boxed ("borders",
321                 "Graphical borders",
322                 "Size of graphical window borders",
323                 GTK_TYPE_BORDER,
324                 G_PARAM_READABLE));
325
326     gtk_widget_class_install_style_property (widget_class,
327             g_param_spec_boxed ("toolbar-borders",
328                 "Graphical toolbar borders",
329                 "Size of graphical toolbar borders",
330                 GTK_TYPE_BORDER,
331                 G_PARAM_READABLE));
332
333     /* opera hack, install clip operation signal */
334     g_signal_new ("clipboard_operation",
335             G_OBJECT_CLASS_TYPE (object_class),
336             G_SIGNAL_RUN_FIRST,
337             G_STRUCT_OFFSET (HildonWindowClass, clipboard_operation),
338             NULL, NULL,
339             g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1,
340             G_TYPE_INT);
341 }
342
343 static void
344 hildon_window_init                              (HildonWindow *self)
345 {
346     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
347     g_assert (priv != NULL);
348
349     priv->vbox = gtk_vbox_new (TRUE, TOOLBAR_MIDDLE);
350     gtk_widget_set_parent (priv->vbox, GTK_WIDGET(self));
351     priv->menu = NULL;
352     priv->app_menu = NULL;
353     priv->edit_toolbar = NULL;
354     priv->visible_toolbars = 0;
355     priv->is_topmost = FALSE;
356     priv->borders = NULL;
357     priv->toolbar_borders = NULL;
358     priv->escape_timeout = 0;
359     priv->markup = NULL;
360
361     priv->fullscreen = FALSE;
362
363     priv->program = NULL;
364
365     /* We need to track the root window _MB_CURRENT_APP_WINDOW property */
366     gdk_window_set_events (gdk_get_default_root_window (),
367             gdk_window_get_events (gdk_get_default_root_window ()) | GDK_PROPERTY_CHANGE_MASK);
368
369     gdk_window_add_filter (gdk_get_default_root_window (), 
370             hildon_window_root_window_event_filter, self);
371 }
372
373 static void
374 hildon_window_finalize                          (GObject * obj_self)
375 {
376     HildonWindowPrivate *priv; 
377       
378     g_return_if_fail (HILDON_WINDOW (obj_self));
379
380     priv = HILDON_WINDOW_GET_PRIVATE (obj_self);
381     g_assert (priv != NULL);
382     
383     g_free (priv->markup);
384
385     if (priv->escape_timeout) {
386       g_source_remove (priv->escape_timeout);
387       priv->escape_timeout = 0;
388     }
389
390     if (priv->borders)
391         gtk_border_free (priv->borders);
392
393     if (priv->toolbar_borders)
394         gtk_border_free (priv->toolbar_borders);
395
396     if (G_OBJECT_CLASS (hildon_window_parent_class)->finalize)
397         G_OBJECT_CLASS (hildon_window_parent_class)->finalize (obj_self);
398
399 }
400
401 static void
402 hildon_window_realize                           (GtkWidget *widget)
403 {
404     Atom *old_atoms, *new_atoms;
405     Display *disp;
406     Window window;
407     gint atom_count;
408     Window active_window;
409     HildonWindowPrivate *priv;
410
411     GTK_WIDGET_CLASS (hildon_window_parent_class)->realize (widget);
412
413     priv = HILDON_WINDOW_GET_PRIVATE (widget);
414     g_assert (priv != NULL);
415
416     gtk_widget_realize (GTK_WIDGET (priv->vbox));
417
418     if (priv->edit_toolbar != NULL)
419         gtk_widget_realize (priv->edit_toolbar);
420
421     /* catch the custom button signal from mb to display the menu */
422     gdk_window_add_filter (widget->window, hildon_window_event_filter, widget);
423
424     window = GDK_WINDOW_XID (widget->window);
425     disp = GDK_WINDOW_XDISPLAY (widget->window);
426
427     /* Enable custom button that is used for menu */
428     XGetWMProtocols (disp, window, &old_atoms, &atom_count);
429     new_atoms = g_new (Atom, atom_count + 1);
430
431     memcpy (new_atoms, old_atoms, sizeof(Atom) * atom_count);
432
433     new_atoms[atom_count++] =
434         XInternAtom (disp, "_NET_WM_CONTEXT_CUSTOM", False);
435
436     XSetWMProtocols (disp, window, new_atoms, atom_count);
437
438     XFree(old_atoms);
439     g_free(new_atoms);
440
441     /* rely on GDK to set the window group to its default */
442     gdk_window_set_group (widget->window, NULL);
443
444     if (priv->program) {
445         gboolean can_hibernate = hildon_program_get_can_hibernate (priv->program);
446
447         hildon_window_set_can_hibernate_property (HILDON_WINDOW (widget),
448                 &can_hibernate);
449     }
450
451     if (priv->markup)
452         hildon_window_update_markup (HILDON_WINDOW (widget));
453
454     /* Update the topmost status */
455     active_window = hildon_window_get_active_window();
456     hildon_window_update_topmost (HILDON_WINDOW (widget), active_window);
457 }
458
459 static void
460 hildon_window_unrealize                         (GtkWidget *widget)
461 {
462     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
463     g_assert (priv != NULL);
464
465     gdk_window_remove_filter (widget->window, hildon_window_event_filter,
466             widget);
467
468     gtk_widget_unrealize (GTK_WIDGET (priv->vbox));
469
470     if (priv->edit_toolbar != NULL)
471         gtk_widget_unrealize (priv->edit_toolbar);
472
473     GTK_WIDGET_CLASS(hildon_window_parent_class)->unrealize(widget);
474 }
475
476 static void
477 hildon_window_map                             (GtkWidget *widget)
478 {
479   HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
480   g_assert (priv != NULL);
481
482   if (GTK_WIDGET_CLASS (hildon_window_parent_class)->map)
483     GTK_WIDGET_CLASS (hildon_window_parent_class)->map (widget);
484
485   if (priv->vbox != NULL && GTK_WIDGET_VISIBLE (priv->vbox))
486     gtk_widget_map (priv->vbox);
487
488   if (priv->edit_toolbar != NULL && GTK_WIDGET_VISIBLE (priv->edit_toolbar))
489     gtk_widget_map (priv->edit_toolbar);
490 }
491
492 static void
493 hildon_window_unmap                             (GtkWidget *widget)
494 {
495   HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
496   g_assert (priv != NULL);
497
498   gtk_widget_unmap (priv->vbox);
499
500   if (priv->edit_toolbar != NULL)
501     gtk_widget_unmap (priv->edit_toolbar);
502
503   if (GTK_WIDGET_CLASS (hildon_window_parent_class)->unmap)
504     GTK_WIDGET_CLASS (hildon_window_parent_class)->unmap (widget);
505 }
506
507 static void
508 hildon_window_get_property                      (GObject *object, 
509                                                  guint property_id,
510                                                  GValue *value, 
511                                                  GParamSpec * pspec)
512 {
513     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (object);
514     g_assert (priv != NULL);
515
516     switch (property_id) {
517
518         case PROP_IS_TOPMOST:
519             g_value_set_boolean (value, priv->is_topmost);
520             break;
521
522         case PROP_MARKUP:
523             g_value_set_string (value, priv->markup);
524             break;
525
526         default:
527             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
528             break;
529     }
530 }
531
532 static void
533 hildon_window_set_property                      (GObject      *object,
534                                                  guint         property_id,
535                                                  const GValue *value,
536                                                  GParamSpec   *pspec)
537 {
538     switch (property_id) {
539
540         case PROP_MARKUP:
541             hildon_window_set_markup (HILDON_WINDOW (object), g_value_get_string (value));
542             break;
543
544         default:
545             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
546             break;
547     }
548 }
549
550 /*
551  * Retrieve the graphical borders size used by the themes
552  */
553 static void
554 hildon_window_get_borders                       (HildonWindow *window)
555 {
556     GtkBorder zero = {0, 0, 0, 0};
557     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (window);
558     g_assert (priv);
559
560     GtkBorder *borders = NULL;
561     GtkBorder *toolbar_borders = NULL;
562
563     if (priv->borders)
564         gtk_border_free (priv->borders);
565     if (priv->toolbar_borders)
566         gtk_border_free (priv->toolbar_borders);
567
568     priv->borders = NULL;
569     priv->toolbar_borders = NULL;
570
571     gtk_widget_style_get (GTK_WIDGET (window), "borders",&borders,
572             "toolbar-borders", &toolbar_borders,
573             NULL);
574
575     // We're doing a copy here instead of reusing the pointer, 
576     // as we don't know where it comes from (has it been allocated using 
577     // malloc or slices... and we want to free it sanely. Blowing on 
578     // cold probbably.
579
580     if (borders) {
581         priv->borders = gtk_border_copy (borders);
582         gtk_border_free (borders);
583     } else
584         priv->borders = g_boxed_copy (GTK_TYPE_BORDER, &zero);
585
586     if (toolbar_borders) {
587         priv->toolbar_borders = gtk_border_copy (toolbar_borders);
588         gtk_border_free (toolbar_borders);
589     } else
590         priv->toolbar_borders = g_boxed_copy (GTK_TYPE_BORDER, &zero);
591 }
592
593 static gboolean
594 hildon_window_expose                            (GtkWidget *widget, 
595                                                  GdkEventExpose * event)
596 {
597     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
598     g_assert (priv);
599
600     GtkWidget *bx = priv->vbox;
601     GtkBox *box = GTK_BOX(bx);
602     GtkBorder *b = priv->borders;
603     GtkBorder *tb = priv->toolbar_borders;
604     gint tb_height = 0;
605
606     if (! priv->borders) {
607         hildon_window_get_borders (HILDON_WINDOW (widget));
608         b = priv->borders;
609         tb = priv->toolbar_borders;
610     }
611
612     tb_height = bx->allocation.height + tb->top + tb->bottom;
613
614     paint_toolbar (widget, box,
615             event, priv->fullscreen);
616
617     if (priv->edit_toolbar != NULL)
618     {
619         paint_edit_toolbar (widget, priv->edit_toolbar,
620                             event, priv->fullscreen);
621     }
622
623     if (! priv->fullscreen) {
624
625         /* Draw the left and right window border */
626         gint side_borders_height = widget->allocation.height - b->top;
627
628         if (priv->visible_toolbars)
629             side_borders_height -= tb_height;
630         else
631             side_borders_height -= b->bottom;
632
633         if (b->left > 0) 
634         {
635             gtk_paint_box (widget->style, widget->window,
636                     GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
637                     &event->area, widget, "left-border",
638                     widget->allocation.x, widget->allocation.y +
639                     b->top, b->left, side_borders_height);
640         } 
641
642         if (b->right > 0)
643         {
644             gtk_paint_box (widget->style, widget->window,
645                     GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
646                     &event->area, widget, "right-border",
647                     widget->allocation.x + widget->allocation.width -
648                     b->right, widget->allocation.y + b->top,
649                     b->right, side_borders_height);
650         }
651
652         /* If no toolbar, draw the bottom window border */
653         if (! priv->visible_toolbars && b->bottom > 0)
654         {
655             gtk_paint_box (widget->style, widget->window,
656                     GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
657                     &event->area, widget, "bottom-border",
658                     widget->allocation.x, widget->allocation.y +
659                     (widget->allocation.height - b->bottom),
660                     widget->allocation.width, b->bottom);
661         }
662
663         /* Draw the top border */
664         if (b->top > 0)
665         {
666             gtk_paint_box (widget->style, widget->window,
667                     GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
668                     &event->area, widget, "top-border",
669                     widget->allocation.x, widget->allocation.y,
670                     widget->allocation.width, b->top);
671         } 
672
673
674     }
675
676     /* don't draw the window stuff as it overwrites our borders with a blank
677      * rectangle. Instead start with the drawing of the GtkBin */
678     GTK_WIDGET_CLASS (g_type_class_peek_parent (hildon_window_parent_class))->expose_event (widget, event);
679
680     /* FIXME Not sure why this is commented out 
681      * GTK_WIDGET_CLASS (hildon_window_parent_class))->
682      *  expose_event (widget, event); 
683      */
684
685     return FALSE;
686 }
687
688 static void
689 hildon_window_size_request                      (GtkWidget *widget, 
690                                                  GtkRequisition *requisition)
691 {
692     GdkScreen *screen = gtk_widget_get_screen (widget);
693     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
694     GtkWidget *child;
695     GtkRequisition req;
696     g_assert (priv);
697
698     child = gtk_bin_get_child (GTK_BIN (widget));
699
700     if (child != NULL && GTK_WIDGET_VISIBLE (child))
701         gtk_widget_size_request (child, &req);
702
703     if (priv->vbox != NULL && GTK_WIDGET_VISIBLE (priv->vbox))
704         gtk_widget_size_request (priv->vbox, &req);
705
706     if (priv->edit_toolbar != NULL && GTK_WIDGET_VISIBLE (priv->edit_toolbar))
707         gtk_widget_size_request (priv->edit_toolbar, &req);
708
709     /* Request the full size of the screen */
710     requisition->width = gdk_screen_get_width (screen);
711     requisition->height = gdk_screen_get_height (screen);
712
713     if (! priv->fullscreen)
714         requisition->height -= HILDON_WINDOW_TITLEBAR_HEIGHT;
715 }
716
717 static void
718 hildon_window_size_allocate                     (GtkWidget *widget, 
719                                                  GtkAllocation *allocation)
720 {
721     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
722     g_assert (priv);
723
724     GtkAllocation box_alloc = { 0 };
725     GtkAllocation edittb_alloc = { 0 };
726     GtkAllocation alloc = *allocation;
727
728     GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
729     GtkBorder *tb;
730
731     if (!priv->borders)
732         hildon_window_get_borders (HILDON_WINDOW (widget));
733
734     tb = priv->toolbar_borders;
735
736     widget->allocation = *allocation;
737
738     /* Calculate allocation of edit toolbar */
739     if (priv->edit_toolbar != NULL && GTK_WIDGET_VISIBLE (priv->edit_toolbar))
740     {
741         GtkRequisition req;
742         gtk_widget_get_child_requisition (priv->edit_toolbar, &req);
743         edittb_alloc.width = alloc.width - tb->left - tb->right;
744         edittb_alloc.height = MIN (req.height, alloc.height);
745         edittb_alloc.x = alloc.x + tb->left;
746         edittb_alloc.y = alloc.y + tb->top;
747
748         if (edittb_alloc.height > 0)
749         {
750             alloc.y += tb->top + tb->bottom + edittb_alloc.height;
751             alloc.height -= tb->top + tb->bottom + edittb_alloc.height;
752             gtk_widget_size_allocate (priv->edit_toolbar, &edittb_alloc);
753         }
754     }
755
756     /* Calculate allocation of normal toolbars */
757     if (priv->vbox != NULL && GTK_WIDGET_VISIBLE (priv->vbox))
758     {
759         GtkRequisition req;
760         gtk_widget_get_child_requisition (priv->vbox, &req);
761         box_alloc.width = alloc.width - tb->left - tb->right;
762         box_alloc.height = MIN (req.height, alloc.height);
763         box_alloc.x = alloc.x + tb->left;
764         box_alloc.y = alloc.y + alloc.height - box_alloc.height - tb->bottom;
765
766         if (box_alloc.height > 0)
767         {
768             alloc.height -= tb->top + tb->bottom + box_alloc.height;
769             gtk_widget_size_allocate (priv->vbox, &box_alloc);
770         }
771     }
772
773     /* Calculate allocation of the child widget */
774     if (child != NULL && GTK_WIDGET_VISIBLE (child))
775     {
776         guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
777         alloc.x += border_width;
778         alloc.y += border_width;
779         alloc.width -= (border_width * 2);
780         alloc.height -= (border_width * 2);
781
782         if (! priv->fullscreen)
783         {
784             GtkBorder *b = priv->borders;
785             alloc.x += b->left;
786             alloc.width -= (b->left + b->right);
787
788             /* Use the top border if there's no edit toolbar */
789             if (edittb_alloc.height <= 0)
790             {
791                 alloc.y += b->top;
792                 alloc.height -= b->top;
793             }
794
795             /* Use the top border if there are no standard toolbars */
796             if (box_alloc.height <= 0)
797                 alloc.height -= b->bottom;
798         }
799
800         gtk_widget_size_allocate (child, &alloc);
801     }
802
803     if (priv->previous_vbox_y != box_alloc.y)
804     {
805         /* The size of the VBox has changed, we need to redraw part
806          * of the window borders */
807         gint draw_from_y = MIN (priv->previous_vbox_y, box_alloc.y) - tb->top;
808
809         gtk_widget_queue_draw_area (widget, 0, draw_from_y, 
810                 widget->allocation.width,
811                 widget->allocation.height - draw_from_y);
812
813         priv->previous_vbox_y = box_alloc.y;
814     }
815
816 }
817
818 static void
819 hildon_window_forall                            (GtkContainer *container, 
820                                                  gboolean include_internals,
821                                                  GtkCallback callback, 
822                                                  gpointer callback_data)
823 {
824     HildonWindow *self = HILDON_WINDOW (container);
825     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
826
827     g_return_if_fail (callback != NULL);
828     g_assert (priv);
829
830     GTK_CONTAINER_CLASS (hildon_window_parent_class)->forall (container, include_internals,
831             callback, callback_data);
832
833     if (include_internals && priv->vbox != NULL)
834         (* callback)(GTK_WIDGET (priv->vbox), callback_data);
835
836     if (include_internals && priv->edit_toolbar != NULL)
837         (* callback)(GTK_WIDGET (priv->edit_toolbar), callback_data);
838 }
839
840 static void
841 hildon_window_show_all                          (GtkWidget *widget)
842 {
843     HildonWindow *self = HILDON_WINDOW (widget);
844     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
845
846     g_assert (priv != NULL);
847
848     GTK_WIDGET_CLASS (hildon_window_parent_class)->show_all (widget);
849
850     gtk_widget_show_all (priv->vbox);
851
852     if (priv->edit_toolbar)
853         gtk_widget_show_all (priv->edit_toolbar);
854 }
855
856 static void
857 hildon_window_destroy                           (GtkObject *obj)
858 {
859     HildonWindow *self = HILDON_WINDOW (obj);
860     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (obj);
861     GList *menu_list = NULL;
862     GList *menu_node = NULL;
863
864     g_assert (priv != NULL);
865
866     if (priv->vbox != NULL)
867     {
868         if (priv->program)
869         {
870             GtkWidget * common_toolbar = 
871                 GTK_WIDGET (hildon_program_get_common_toolbar (priv->program));
872             if (common_toolbar && common_toolbar->parent == priv->vbox)
873             {
874                 gtk_container_remove (GTK_CONTAINER (priv->vbox),
875                         common_toolbar);
876             }
877         }
878
879         gtk_widget_unparent (priv->vbox);
880         priv->vbox = NULL;    
881
882     }
883
884     if (priv->edit_toolbar != NULL)
885     {
886         gtk_widget_unparent (priv->edit_toolbar);
887         priv->edit_toolbar = NULL;
888     }
889
890     if (priv->app_menu)
891     {
892         hildon_app_menu_set_parent_window (priv->app_menu, NULL);
893         g_object_unref (priv->app_menu);
894         priv->app_menu = NULL;
895     }
896
897     menu_list = g_list_copy (gtk_menu_get_for_attach_widget (GTK_WIDGET (obj)));
898     menu_node = menu_list;
899
900     while (menu_node)
901     {
902         if (GTK_IS_MENU (menu_node->data))
903         {
904             if (GTK_WIDGET_VISIBLE (GTK_WIDGET (menu_node->data)))
905             {
906                 gtk_menu_popdown (GTK_MENU (menu_node->data));
907                 gtk_menu_shell_deactivate (GTK_MENU_SHELL (menu_node->data));
908             }
909             gtk_menu_detach (GTK_MENU (menu_node->data));
910
911             /* Destroy it, but only if it's not a common menu */
912             if (priv->program && 
913                 hildon_program_get_common_menu (priv->program) != menu_node->data) {
914                     gtk_object_destroy (GTK_OBJECT (menu_node->data));
915                     g_object_unref (menu_node->data);
916             }
917         }
918         menu_node = menu_node->next;
919     }
920
921     g_list_free (menu_list);
922     menu_list = NULL;
923
924     if (priv->program)
925     {
926         hildon_program_remove_window (priv->program, self);
927     }
928
929     gdk_window_remove_filter (gdk_get_default_root_window(), 
930             hildon_window_root_window_event_filter,
931             obj);
932
933     gtk_widget_set_events (GTK_WIDGET(obj), 0);
934
935     GTK_OBJECT_CLASS (hildon_window_parent_class)->destroy (obj);
936 }
937
938 static void
939 hildon_window_notify                            (GObject *gobject, 
940                                                  GParamSpec *param)
941 {
942     HildonWindow *window = HILDON_WINDOW (gobject);
943
944     if (g_str_equal (param->name, "is-topmost"))
945     {
946         hildon_window_is_topmost_notify (window);
947     }
948
949     if (G_OBJECT_CLASS(hildon_window_parent_class)->notify)
950         G_OBJECT_CLASS(hildon_window_parent_class)->notify (gobject, param);
951 }
952
953
954 static void
955 visible_toolbar                                 (gpointer data, 
956                                                  gpointer user_data)
957 {
958     if (GTK_WIDGET_VISIBLE (((GtkBoxChild *)data)->widget))
959         (*((gint *)user_data))++;
960 }
961
962 static void
963 paint_toolbar                                   (GtkWidget *widget, 
964                                                  GtkBox *box, 
965                                                  GdkEventExpose * event, 
966                                                  gboolean fullscreen)
967 {
968     gint toolbar_num = 0; 
969     gint count;
970
971     /* collect info to help on painting the boxes */
972     g_list_foreach (box->children, visible_toolbar, 
973             (gpointer) &toolbar_num);
974
975     if(toolbar_num <= 0)
976         return;
977
978     /*top most toolbar painting*/
979     gtk_paint_box (widget->style, widget->window,
980             GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
981             &event->area, widget, "toolbar-primary",
982             widget->allocation.x,
983             GTK_WIDGET(box)->allocation.y,
984             widget->allocation.width,
985             TOOLBAR_HEIGHT);
986
987     /*multi toolbar painting*/
988     for (count = 0; count < toolbar_num - 1; count++)
989     {
990             gtk_paint_box (widget->style, widget->window,
991                            GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
992                            &event->area, widget, "toolbar-secondary",
993                            widget->allocation.x,
994                            GTK_WIDGET(box)->allocation.y +
995                            (1 + count) * (TOOLBAR_HEIGHT),
996                            widget->allocation.width,
997                            TOOLBAR_HEIGHT);
998     }
999 }
1000
1001 static void
1002 paint_edit_toolbar                              (GtkWidget *widget,
1003                                                  GtkWidget *toolbar,
1004                                                  GdkEventExpose *event,
1005                                                  gboolean fullscreen)
1006 {
1007     if (!GTK_WIDGET_VISIBLE (toolbar))
1008         return;
1009
1010     gtk_paint_box (widget->style, widget->window,
1011                    GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT,
1012                    &event->area, widget, "toolbar-edit-mode",
1013                    toolbar->allocation.x,
1014                    toolbar->allocation.y,
1015                    toolbar->allocation.width,
1016                    toolbar->allocation.height);
1017 }
1018
1019 /*
1020  * Checks the root window to know which is the topped window
1021  */
1022 Window
1023 hildon_window_get_active_window                 (void)
1024 {
1025     Atom realtype;
1026     gint xerror;
1027     int format;
1028     int status;
1029     Window ret;
1030     unsigned long n;
1031     unsigned long extra;
1032     union
1033     {
1034         Window *win;
1035         unsigned char *char_pointer;
1036     } win;
1037     Atom active_app_atom = 
1038         XInternAtom (GDK_DISPLAY (), "_MB_CURRENT_APP_WINDOW", False);
1039
1040     win.win = NULL;
1041
1042     gdk_error_trap_push ();
1043     status = XGetWindowProperty (GDK_DISPLAY(), GDK_ROOT_WINDOW(),
1044             active_app_atom, 0L, 16L,
1045             0, XA_WINDOW, &realtype, &format,
1046             &n, &extra, &win.char_pointer);
1047     xerror = gdk_error_trap_pop ();
1048     if (xerror || !(status == Success && realtype == XA_WINDOW && format == 32
1049                 && n == 1 && win.win != NULL))
1050     {
1051         if (win.win != NULL)
1052             XFree (win.char_pointer);
1053         return None;
1054     }
1055
1056     ret = win.win[0];
1057
1058     if (win.win != NULL)
1059         XFree(win.char_pointer);
1060
1061     return ret;
1062 }
1063
1064 static int
1065 xclient_message_type_check                      (XClientMessageEvent *cm, 
1066                                                  const gchar *name)
1067 {
1068     return cm->message_type == XInternAtom(GDK_DISPLAY(), name, FALSE);
1069 }
1070
1071 /*
1072  * Handle the window border custom button, which toggles the menu,
1073  * and the Hildon input method copy paste messages
1074  */
1075 static GdkFilterReturn
1076 hildon_window_event_filter                      (GdkXEvent *xevent, 
1077                                                  GdkEvent *event, 
1078                                                  gpointer data)
1079 {
1080     XAnyEvent *eventti = xevent;
1081
1082     if (eventti->type == ClientMessage)
1083     {
1084         XClientMessageEvent *cm = xevent;
1085
1086         if (xclient_message_type_check (cm, "_MB_GRAB_TRANSFER"))
1087         {
1088             hildon_window_toggle_menu (HILDON_WINDOW ( data ), cm->data.l[2], cm->data.l[0]);
1089             return GDK_FILTER_REMOVE;
1090         }
1091         /* opera hack clipboard client message */
1092         else if (xclient_message_type_check (cm, "_HILDON_IM_CLIPBOARD_COPY"))
1093         {
1094             g_signal_emit_by_name(G_OBJECT(data), "clipboard_operation",
1095                     HILDON_WINDOW_CO_COPY);
1096             return GDK_FILTER_REMOVE;
1097         }
1098         else if (xclient_message_type_check(cm, "_HILDON_IM_CLIPBOARD_CUT"))
1099         {
1100             g_signal_emit_by_name(G_OBJECT(data), "clipboard_operation",
1101                     HILDON_WINDOW_CO_CUT);
1102             return GDK_FILTER_REMOVE;
1103         }
1104         else if (xclient_message_type_check(cm, "_HILDON_IM_CLIPBOARD_PASTE"))
1105         {
1106             g_signal_emit_by_name(G_OBJECT(data), "clipboard_operation",
1107                     HILDON_WINDOW_CO_PASTE);
1108             return GDK_FILTER_REMOVE;
1109         }
1110     }
1111
1112     return GDK_FILTER_CONTINUE;
1113 }
1114
1115 /*
1116  * Here we keep track of changes in the _MB_CURRENT_APP_WINDOW,
1117  * to know when we acquire/lose topmost status
1118  */
1119 static GdkFilterReturn
1120 hildon_window_root_window_event_filter          (GdkXEvent *xevent, 
1121                                                  GdkEvent *event, 
1122                                                  gpointer data)
1123 {
1124     XAnyEvent *eventti = xevent;
1125     HildonWindow *hwindow = HILDON_WINDOW (data);
1126
1127     if (eventti->type == PropertyNotify)
1128     {
1129         XPropertyEvent *pevent = xevent;
1130         Atom active_app_atom = 
1131             XInternAtom (GDK_DISPLAY (), "_MB_CURRENT_APP_WINDOW", False);
1132
1133         if (pevent->atom == active_app_atom)
1134         {
1135             Window active_window = hildon_window_get_active_window();
1136
1137             hildon_window_update_topmost (hwindow, active_window);
1138         }
1139     }
1140
1141     return GDK_FILTER_CONTINUE;
1142 }
1143
1144 /*
1145  * Handle the menu hardware key here
1146  */
1147 static gboolean
1148 hildon_window_key_press_event                   (GtkWidget *widget, 
1149                                                  GdkEventKey *event)
1150 {
1151     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
1152
1153     g_return_val_if_fail (HILDON_IS_WINDOW (widget),FALSE);
1154     g_assert (priv);
1155
1156     switch (event->keyval)
1157     {
1158         case HILDON_HARDKEY_MENU:
1159             if (hildon_window_toggle_menu (HILDON_WINDOW (widget), 0, GDK_CURRENT_TIME))
1160                 return TRUE;
1161             break;
1162         case HILDON_HARDKEY_ESC:
1163             if (!priv->escape_timeout)
1164             {
1165                 priv->escape_timeout = g_timeout_add 
1166                     (HILDON_WINDOW_LONG_PRESS_TIME,
1167                      hildon_window_escape_timeout, widget);
1168             }
1169             break;
1170     }
1171
1172     return GTK_WIDGET_CLASS (hildon_window_parent_class)->key_press_event (widget, event);
1173 }
1174
1175 static gboolean
1176 hildon_window_key_release_event                 (GtkWidget *widget, 
1177                                                  GdkEventKey *event)
1178 {
1179     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
1180
1181     g_return_val_if_fail (HILDON_IS_WINDOW (widget), FALSE);
1182     g_assert (priv);
1183
1184     switch (event->keyval)
1185     {
1186         case HILDON_HARDKEY_ESC:
1187             if (priv->escape_timeout)
1188             {
1189                 g_source_remove (priv->escape_timeout);
1190                 priv->escape_timeout = 0;
1191             }
1192             break;
1193     }
1194
1195     return GTK_WIDGET_CLASS (hildon_window_parent_class)->key_release_event (widget, event);
1196
1197 }
1198
1199 /*
1200  * We keep track of the window state changes, because the drawing
1201  * (borders) differs whether we are in fullscreen mode or not
1202  */
1203 static gboolean
1204 hildon_window_window_state_event                (GtkWidget *widget, 
1205                                                  GdkEventWindowState *event)
1206 {
1207     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
1208     g_assert (priv != NULL);
1209
1210     if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
1211         priv->fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN;
1212
1213     if (GTK_WIDGET_CLASS (hildon_window_parent_class)->window_state_event)
1214     {
1215         return GTK_WIDGET_CLASS (hildon_window_parent_class)->window_state_event (
1216                 widget,
1217                 event);
1218     }
1219     else
1220     {
1221         return FALSE;
1222     }
1223 }
1224
1225 /*
1226  * If the window lost focus while the user started to press the ESC key, we
1227  * won't get the release event. We need to stop the timeout.
1228  */
1229 static gboolean
1230 hildon_window_focus_out_event                   (GtkWidget *widget, 
1231                                                  GdkEventFocus *event)
1232 {
1233   HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
1234
1235   if (priv->escape_timeout)
1236   {
1237       g_source_remove (priv->escape_timeout);
1238       priv->escape_timeout = 0;
1239   }
1240
1241   return GTK_WIDGET_CLASS (hildon_window_parent_class)->focus_out_event (widget, event);
1242 }
1243
1244 /*
1245  * The menu popuping needs a menu popup-function
1246  */
1247 static void
1248 hildon_window_menu_popup_func                   (GtkMenu *menu, 
1249                                                  gint *x, 
1250                                                  gint *y,
1251                                                  gboolean *push_in, 
1252                                                  GtkWidget *widget)
1253 {
1254     gint window_x = 0;
1255     gint window_y = 0;
1256     GdkWindow *window = GTK_WIDGET(widget)->window;
1257
1258     if (window)
1259     {
1260         gdk_window_get_origin (window, &window_x, &window_y);
1261     }
1262
1263     gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
1264             "vertical-offset", y, NULL);
1265
1266     if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1267     {
1268         *x = GTK_WIDGET (widget)->allocation.width + window_x - GTK_WIDGET (menu)->allocation.width - *x;
1269     }
1270     else
1271         *x += window_x;
1272
1273     *y += window_y;
1274
1275 }
1276
1277 static void
1278 hildon_window_menu_popup_func_full              (GtkMenu *menu, 
1279                                                  gint *x, 
1280                                                  gint *y,
1281                                                  gboolean *push_in, 
1282                                                  GtkWidget *widget)
1283 {
1284     gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
1285             "vertical-offset", y, NULL);
1286
1287     if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1288         *x = GTK_WIDGET (widget)->allocation.width - GTK_WIDGET (menu)->allocation.width - *x;
1289     else
1290         *x = MAX (0, *x);
1291
1292     *y = MAX (0, *y);
1293 }
1294
1295
1296 /*
1297  * Takes the common toolbar when we acquire the top-most status
1298  */
1299 static void
1300 hildon_window_is_topmost_notify                 (HildonWindow *window)
1301 {
1302     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (window);
1303
1304     g_assert (priv);
1305
1306     if (priv->is_topmost)
1307     {
1308         hildon_window_take_common_toolbar (window);
1309     }
1310 }
1311
1312 /*
1313  * Sets the program to which the window belongs. This should only be called
1314  * by hildon_program_add_window
1315  */
1316 void G_GNUC_INTERNAL
1317 hildon_window_set_program                       (HildonWindow *self, 
1318                                                  GObject *program)
1319 {
1320     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1321
1322     g_return_if_fail (HILDON_IS_WINDOW (self));
1323     g_assert (priv != NULL);
1324
1325     if (priv->program)
1326     {
1327         g_object_unref (priv->program);
1328     }
1329
1330     /* Now that we are bound to a program, we can rely on it to track the
1331      * root window */
1332     gdk_window_remove_filter (gdk_get_default_root_window(), 
1333             hildon_window_root_window_event_filter,
1334             self);
1335
1336     priv->program = HILDON_PROGRAM (program);
1337     g_object_ref (program);
1338 }
1339
1340 /*
1341  * Unsets the program to which the window belongs. This should only be called
1342  * by hildon_program_remove_window
1343  */
1344 void G_GNUC_INTERNAL
1345 hildon_window_unset_program                     (HildonWindow *self)
1346 {
1347     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1348
1349     g_return_if_fail(HILDON_IS_WINDOW (self));
1350     g_assert (priv != NULL);
1351
1352     if (priv->program)
1353     {
1354         g_object_unref (priv->program);
1355         priv->program = NULL;
1356
1357         /* We need to start tacking the root window again */
1358         gdk_window_set_events (gdk_get_default_root_window (),
1359                 gdk_window_get_events (gdk_get_default_root_window ())
1360                 | GDK_PROPERTY_CHANGE_MASK);
1361
1362         gdk_window_add_filter (gdk_get_default_root_window (),
1363                 hildon_window_root_window_event_filter, self );
1364     }
1365
1366     priv->program = NULL;
1367 }
1368
1369 /*
1370  * Sets whether or not the program to which this window belongs is
1371  * killable. This is used by the HildonProgram to signify to the
1372  * Task Navigator whether or not it can hibernate in memory-low situations
1373  **/    
1374 void G_GNUC_INTERNAL
1375 hildon_window_set_can_hibernate_property        (HildonWindow *self, 
1376                                                  gpointer _can_hibernate)
1377 {
1378     GdkAtom killable_atom;
1379     gboolean can_hibernate;
1380
1381     g_return_if_fail(self && HILDON_IS_WINDOW (self));
1382
1383     if (!GTK_WIDGET_REALIZED ((GTK_WIDGET (self))))
1384     {
1385         return;
1386     }
1387
1388     can_hibernate = * ((gboolean *)_can_hibernate);
1389
1390     killable_atom = gdk_atom_intern (CAN_HIBERNATE_PROPERTY, FALSE);
1391
1392     if (can_hibernate)
1393     {
1394         gdk_property_change (GTK_WIDGET (self)->window, killable_atom,
1395                 (GdkAtom)31/* XA_STRING */, 8,
1396                 GDK_PROP_MODE_REPLACE, (const guchar *)CAN_HIBERNATE,
1397                 CAN_HIBERNATE_LENGTH);
1398     }
1399     else
1400     {
1401         gdk_property_delete (GTK_WIDGET (self)->window, killable_atom);
1402     }
1403
1404 }
1405
1406 /*
1407  * If a common toolbar was set to the program, reparent it to
1408  * us
1409  */
1410 void G_GNUC_INTERNAL
1411 hildon_window_take_common_toolbar               (HildonWindow *self)
1412 {
1413     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1414
1415     g_return_if_fail(HILDON_IS_WINDOW (self));
1416     g_assert (priv);
1417
1418     if (priv->program)
1419     {
1420         GtkWidget *common_toolbar =  
1421             GTK_WIDGET (hildon_program_get_common_toolbar (priv->program));
1422
1423         if (common_toolbar && common_toolbar->parent != priv->vbox)
1424         {
1425             g_object_ref (common_toolbar);
1426             if (common_toolbar->parent)
1427             {
1428                 gtk_container_remove (GTK_CONTAINER (common_toolbar->parent),
1429                         common_toolbar);
1430             }
1431
1432             gtk_box_pack_end (GTK_BOX(priv->vbox), common_toolbar,
1433                     TRUE, TRUE, 0);
1434             g_object_unref (common_toolbar);
1435
1436             gtk_widget_set_size_request (common_toolbar, -1, TOOLBAR_HEIGHT);
1437
1438             gtk_widget_show  (priv->vbox);
1439
1440         }
1441     }
1442 }
1443
1444 /*
1445  * Compare the window that was last topped, and act consequently
1446  */
1447 void
1448 hildon_window_update_topmost                    (HildonWindow *self, 
1449                                                  Window window_id)
1450 {
1451     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1452
1453     GdkWindow *my_window;
1454
1455     g_return_if_fail (HILDON_IS_WINDOW (self));
1456     g_assert (priv);
1457
1458     my_window = GTK_WIDGET (self)->window;
1459
1460     if (my_window && window_id == GDK_WINDOW_XID (my_window))
1461     {
1462         if (! priv->is_topmost)
1463         {
1464             priv->is_topmost = TRUE;
1465             hildon_window_is_topmost_notify (self);
1466             g_object_notify (G_OBJECT (self), "is-topmost");
1467         }
1468     }
1469     else if (priv->is_topmost)
1470     {
1471         /* Should this go in the signal handler? */
1472         GtkWidget *focus = gtk_window_get_focus (GTK_WINDOW (self));
1473
1474         if (GTK_IS_ENTRY (focus))
1475             gtk_im_context_focus_out (GTK_ENTRY (focus)->im_context);
1476         if (GTK_IS_TEXT_VIEW (focus))
1477             gtk_im_context_focus_out (GTK_TEXT_VIEW (focus)->im_context);
1478
1479         priv->is_topmost = FALSE;
1480         hildon_window_is_topmost_notify (self);
1481         g_object_notify (G_OBJECT (self), "is-topmost");
1482     }
1483 }
1484
1485 static void
1486 detach_menu_func                                (GtkWidget *attach_widget, 
1487                                                  GtkMenu *menu)
1488 {
1489     /* FIXME Why is this even needed here? */
1490 }
1491
1492 static gboolean
1493 hildon_window_toggle_menu                       (HildonWindow *self,
1494                                                  guint button,
1495                                                  guint32 time)
1496 {
1497     g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
1498
1499     if (HILDON_WINDOW_GET_CLASS (self)->toggle_menu != NULL)
1500     {
1501         return HILDON_WINDOW_GET_CLASS (self)->toggle_menu (self, button, time);
1502     }
1503     else
1504     {
1505         return FALSE;
1506     }
1507 }
1508
1509
1510 static gboolean
1511 hildon_window_toggle_gtk_menu                   (HildonWindow *self,
1512                                                  GtkMenu      *menu,
1513                                                  guint         button,
1514                                                  guint32       time)
1515 {
1516     gboolean retvalue = FALSE;
1517
1518     g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
1519     g_return_val_if_fail (GTK_IS_MENU (menu), FALSE);
1520
1521     if (gtk_menu_get_attach_widget (menu) != GTK_WIDGET (self))
1522     {
1523         g_object_ref (menu);
1524         if (gtk_menu_get_attach_widget (menu))
1525         {
1526             gtk_menu_detach (menu);
1527         }
1528         gtk_menu_attach_to_widget (menu, GTK_WIDGET (self), &detach_menu_func);
1529         g_object_unref (menu);
1530     }
1531
1532     if (GTK_WIDGET_MAPPED (menu))
1533     {
1534         gtk_menu_popdown (menu);
1535         gtk_menu_shell_deactivate (GTK_MENU_SHELL (menu));
1536         retvalue = TRUE;
1537     }
1538     else
1539     {
1540         /* Check if the menu has items */
1541         GList *menu_children = gtk_container_get_children (GTK_CONTAINER (menu));
1542
1543         if (menu_children)
1544         {
1545             HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1546             g_list_free (menu_children);
1547
1548             /* Apply right theming */
1549             gtk_widget_set_name (GTK_WIDGET (menu), "menu_force_with_corners");
1550
1551             if (priv->fullscreen)
1552             {
1553                 gtk_menu_popup (menu, NULL, NULL,
1554                                 (GtkMenuPositionFunc)
1555                                 hildon_window_menu_popup_func_full,
1556                                 self, button, time);
1557             }
1558             else
1559             {
1560                 gtk_menu_popup (menu, NULL, NULL,
1561                                 (GtkMenuPositionFunc)
1562                                 hildon_window_menu_popup_func,
1563                                 self, button, time);
1564             }
1565             gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), TRUE);
1566             retvalue = TRUE;
1567         }
1568     }
1569
1570     return retvalue;
1571 }
1572
1573 static gboolean
1574 hildon_window_toggle_app_menu                   (HildonWindow  *self,
1575                                                  HildonAppMenu *menu)
1576 {
1577     g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
1578     g_return_val_if_fail (HILDON_IS_APP_MENU (menu), FALSE);
1579
1580     if (self != hildon_app_menu_get_parent_window (menu))
1581     {
1582         gtk_widget_hide (GTK_WIDGET (menu));
1583     }
1584
1585     if (GTK_WIDGET_MAPPED (menu))
1586     {
1587         gtk_widget_hide (GTK_WIDGET (menu));
1588     }
1589     else
1590     {
1591         hildon_app_menu_popup (menu, GTK_WINDOW (self));
1592     }
1593
1594     return TRUE;
1595 }
1596
1597 /*
1598  * Toggles the display of the HildonWindow menu.
1599  * Returns whether or not something was done (whether or not we had a menu
1600  * to toggle)
1601  */
1602 static gboolean
1603 hildon_window_toggle_menu_real                  (HildonWindow * self,
1604                                                  guint button,
1605                                                  guint32 time)
1606 {
1607     gboolean retvalue = FALSE;
1608     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1609
1610     g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
1611
1612     /* Select which menu to use, Window specific has highest priority,
1613      * then program specific */
1614     if (priv->menu)
1615     {
1616         retvalue = hildon_window_toggle_gtk_menu (self, priv->menu, button, time);
1617     }
1618     else if (priv->app_menu)
1619     {
1620         retvalue = hildon_window_toggle_app_menu (self, priv->app_menu);
1621     }
1622     else if (priv->program)
1623     {
1624         GtkMenu *gtkmenu = hildon_program_get_common_menu (priv->program);
1625         HildonAppMenu *appmenu = hildon_program_get_common_app_menu (priv->program);
1626
1627         if (gtkmenu)
1628         {
1629             retvalue = hildon_window_toggle_gtk_menu (self, gtkmenu, button, time);
1630         }
1631         else if (appmenu)
1632         {
1633             retvalue = hildon_window_toggle_app_menu (self, appmenu);
1634         }
1635     }
1636
1637     return retvalue;
1638 }
1639
1640 /*
1641  * If the ESC key was not released when the timeout expires,
1642  * close the window
1643  */
1644 static gboolean
1645 hildon_window_escape_timeout                    (gpointer data)
1646 {
1647     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (data);
1648     GdkEvent *event;
1649
1650     g_assert (priv);
1651
1652     GDK_THREADS_ENTER ();
1653
1654     /* Send fake event, simulation a situation that user
1655        pressed 'x' from the corner */
1656     event = gdk_event_new(GDK_DELETE);
1657     ((GdkEventAny *)event)->window = GDK_WINDOW (g_object_ref (GTK_WIDGET(data)->window));
1658     gtk_main_do_event(event);
1659
1660     /* That unrefs the window, so we're reffing it above */
1661     gdk_event_free(event);
1662
1663     priv->escape_timeout = 0;
1664
1665     GDK_THREADS_LEAVE ();
1666
1667     return FALSE;
1668 }
1669
1670 /**
1671  * hildon_window_new: 
1672  * 
1673  * Creates a new #HildonWindow.
1674  * 
1675  * Return value: A #HildonWindow.
1676  **/
1677 GtkWidget*
1678 hildon_window_new                               (void)
1679 {
1680     HildonWindow *newwindow = g_object_new (HILDON_TYPE_WINDOW, NULL);
1681
1682     return GTK_WIDGET (newwindow);
1683 }
1684
1685 /**
1686  * hildon_window_add_with_scrollbar:
1687  * @self: A #HildonWindow
1688  * @child: A #GtkWidget
1689  *
1690  * Adds @child to the #HildonWindow and creates a scrollbar for
1691  * it. Similar to adding first a #GtkScrolledWindow and then @child to
1692  * it.
1693  */
1694 void
1695 hildon_window_add_with_scrollbar                (HildonWindow *self,
1696                                                  GtkWidget *child)
1697 {
1698     GtkScrolledWindow *scrolledw;
1699
1700     g_return_if_fail (HILDON_IS_WINDOW (self));
1701     g_return_if_fail (GTK_IS_WIDGET (child));
1702     g_return_if_fail (child->parent == NULL);
1703
1704     scrolledw = GTK_SCROLLED_WINDOW (gtk_scrolled_window_new (NULL, NULL));
1705     gtk_scrolled_window_set_policy (scrolledw, GTK_POLICY_NEVER,
1706             GTK_POLICY_AUTOMATIC);
1707     gtk_scrolled_window_set_shadow_type (scrolledw, GTK_SHADOW_NONE);
1708
1709     if (GTK_IS_VIEWPORT (child))
1710         gtk_container_add (GTK_CONTAINER (scrolledw), child);
1711     else
1712     {
1713         if (GTK_IS_CONTAINER (child) )
1714             gtk_container_set_focus_vadjustment (GTK_CONTAINER(child),
1715                     gtk_scrolled_window_get_vadjustment (scrolledw) );
1716         gtk_scrolled_window_add_with_viewport (scrolledw, child);
1717     }
1718
1719     gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (scrolledw));
1720 }
1721
1722 static void
1723 calculate_visible_toolbars                      (gpointer data,
1724                                                  gpointer user_data)
1725 {
1726   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (((GtkBoxChild *)data)->widget)))
1727     (*((gint *)user_data)) ++;
1728 }
1729
1730 static void
1731 toolbar_visible_notify                          (GtkWidget *toolbar, GParamSpec *pspec,
1732                                                  HildonWindow *window)
1733 {
1734   HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (window);
1735
1736   g_assert (priv);
1737
1738   /* Recalculate from scratch the value just in case */
1739   priv->visible_toolbars = 0;
1740
1741   g_list_foreach (GTK_BOX (priv->vbox)->children, calculate_visible_toolbars, 
1742                   &priv->visible_toolbars);
1743
1744   if (priv->visible_toolbars == 0)
1745     gtk_widget_hide (priv->vbox);
1746   else
1747     gtk_widget_show (priv->vbox);
1748 }
1749
1750 /**
1751  * hildon_window_add_toolbar:
1752  * @self: A #HildonWindow
1753  * @toolbar: A #GtkToolbar to add to the #HildonWindow
1754  *
1755  * Adds a toolbar to the window. Note that the toolbar is not automatically
1756  * shown. You need to call gtk_widget_show_all() on it to make it visible.
1757  * It's also possible to hide the toolbar (without removing it) by calling
1758  * gtk_widget_hide()
1759  **/
1760 void 
1761 hildon_window_add_toolbar                       (HildonWindow *self, 
1762                                                  GtkToolbar *toolbar)
1763 {
1764     GtkBox *vbox;
1765     HildonWindowPrivate *priv;
1766
1767     g_return_if_fail (HILDON_IS_WINDOW (self));
1768     g_return_if_fail (toolbar && GTK_IS_TOOLBAR (toolbar));
1769
1770     priv = HILDON_WINDOW_GET_PRIVATE (self);
1771
1772     vbox = GTK_BOX (priv->vbox);
1773
1774     gtk_box_pack_start (vbox, GTK_WIDGET (toolbar), TRUE, TRUE, 0);
1775     gtk_box_reorder_child (vbox, GTK_WIDGET (toolbar), 0);
1776     gtk_widget_set_size_request (GTK_WIDGET (toolbar), -1, TOOLBAR_HEIGHT);
1777
1778     g_signal_connect (G_OBJECT (toolbar), "notify::visible",
1779                       G_CALLBACK (toolbar_visible_notify), self);
1780
1781     if (GTK_WIDGET_VISIBLE (toolbar))
1782       {
1783         priv->visible_toolbars++;
1784         gtk_widget_show (priv->vbox);
1785       }
1786
1787     gtk_widget_queue_resize (GTK_WIDGET (self));
1788 }
1789
1790 /**
1791  * hildon_window_remove_toolbar:
1792  * @self: A #HildonWindow
1793  * @toolbar: A #GtkToolbar to remove from the #HildonWindow
1794  *
1795  * Removes a toolbar from the window. Note that this decreases the refference
1796  * count on the widget. If you want to keep the toolbar alive call g_object_ref()
1797  * before calling this function.
1798  **/
1799 void
1800 hildon_window_remove_toolbar                    (HildonWindow *self, 
1801                                                  GtkToolbar *toolbar)
1802 {
1803     HildonWindowPrivate *priv;
1804
1805     g_return_if_fail (HILDON_IS_WINDOW (self));
1806     
1807     priv = HILDON_WINDOW_GET_PRIVATE (self);
1808
1809     if (GTK_WIDGET_VISIBLE (toolbar))
1810       {
1811         if (--(priv->visible_toolbars) == 0)
1812           gtk_widget_hide (priv->vbox);
1813       }
1814
1815     g_signal_handlers_disconnect_by_func (toolbar, toolbar_visible_notify, self);
1816
1817     gtk_container_remove (GTK_CONTAINER (priv->vbox), GTK_WIDGET (toolbar));
1818 }
1819
1820 /**
1821  * hildon_window_set_edit_toolbar:
1822  * @self: A #HildonWindow
1823  * @toolbar: A #HildonEditToolbar, or %NULL to remove the current one.
1824  *
1825  * Adds a #HildonEditToolbar to the window. Note that the toolbar is
1826  * not automatically shown. You need to call gtk_widget_show() on it
1827  * to make it visible. It's also possible to hide the toolbar (without
1828  * removing it) by calling gtk_widget_hide().
1829  *
1830  * A window can only have at most one edit toolbar at a time, so the
1831  * previous toolbar (if any) is replaced after calling this function.
1832  *
1833  * Since: 2.2
1834  **/
1835 void
1836 hildon_window_set_edit_toolbar                  (HildonWindow      *self,
1837                                                  HildonEditToolbar *toolbar)
1838 {
1839     HildonWindowPrivate *priv;
1840
1841     g_return_if_fail (HILDON_IS_WINDOW (self));
1842     g_return_if_fail (toolbar == NULL || HILDON_IS_EDIT_TOOLBAR (toolbar));
1843
1844     priv = HILDON_WINDOW_GET_PRIVATE (self);
1845
1846     if (priv->edit_toolbar != GTK_WIDGET (toolbar))
1847     {
1848         GtkWidget *old_toolbar = priv->edit_toolbar;
1849         priv->edit_toolbar = GTK_WIDGET (toolbar);
1850
1851         if (priv->edit_toolbar)
1852             gtk_widget_set_parent (priv->edit_toolbar, GTK_WIDGET (self));
1853
1854         if (old_toolbar)
1855             gtk_widget_unparent (old_toolbar);
1856     }
1857 }
1858
1859 /**
1860  * hildon_window_get_main_menu:
1861  * @self: a #HildonWindow
1862  *
1863  * Gets the #GtkMenu assigned to the #HildonWindow. Note that the
1864  * window is still the owner of the menu.
1865  *
1866  * Note that if you're using a #HildonAppMenu rather than a #GtkMenu
1867  * you should use hildon_window_get_app_menu() instead.
1868  *
1869  * Return value: The #GtkMenu assigned to this application view. 
1870  *
1871  * Since: 2.2
1872  **/
1873 GtkMenu*
1874 hildon_window_get_main_menu                     (HildonWindow * self)
1875 {
1876     HildonWindowPrivate *priv;
1877
1878     g_return_val_if_fail (HILDON_IS_WINDOW (self), NULL);
1879
1880     priv = HILDON_WINDOW_GET_PRIVATE (self);
1881
1882     return priv->menu;
1883 }
1884
1885 /**
1886  * hildon_window_get_menu:
1887  * @self: a #HildonWindow
1888  *
1889  * Gets the #GtkMenu assigned to @self
1890  *
1891  * Return value: a #GtkMenu
1892  *
1893  * Deprecated: In Hildon 2.2 this function has been renamed to
1894  * hildon_window_get_main_menu() for consistency
1895  **/
1896 GtkMenu*
1897 hildon_window_get_menu                          (HildonWindow * self)
1898 {
1899     return hildon_window_get_main_menu (self);
1900 }
1901
1902 /* Since we've been asking developers to call gtk_window_add_accel_group()
1903  * themselves, do not trigger criticals by trying it again.
1904  */
1905 static void
1906 hildon_window_add_accel_group (HildonWindow *self,
1907                                GtkAccelGroup *accel_group)
1908 {
1909     GSList *groups, *l;
1910
1911     groups = gtk_accel_groups_from_object (G_OBJECT (self));
1912     for (l = groups; l != NULL; l = l->next)
1913       if (l->data == (gpointer)accel_group)
1914         /* Maybe print a warning here? */
1915         return;
1916
1917     gtk_window_add_accel_group (GTK_WINDOW (self), accel_group);
1918 }
1919
1920 /**
1921  * hildon_window_set_main_menu:
1922  * @self: A #HildonWindow
1923  * @menu: The #GtkMenu to be used for this #HildonWindow
1924  *
1925  * Sets the menu to be used for this window. This menu overrides
1926  * a program-wide menu that may have been set with
1927  * hildon_program_set_common_menu(). Pass %NULL to remove the current
1928  * menu. #HildonWindow takes ownership of the passed menu and you're
1929  * not supposed to free it yourself anymore.
1930  *
1931  * Note that if you're using a #HildonAppMenu rather than a #GtkMenu
1932  * you should use hildon_window_set_app_menu() instead.
1933  **/
1934 void
1935 hildon_window_set_main_menu (HildonWindow* self,
1936                              GtkMenu     * menu)
1937 {
1938     HildonWindowPrivate *priv;
1939     GtkAccelGroup *accel_group;
1940
1941     g_return_if_fail (HILDON_IS_WINDOW (self));
1942
1943     priv = HILDON_WINDOW_GET_PRIVATE (self);
1944
1945     if (priv->menu != NULL)
1946     {
1947         accel_group = gtk_menu_get_accel_group (priv->menu);
1948         if (accel_group != NULL)
1949             gtk_window_remove_accel_group (GTK_WINDOW (self), accel_group);
1950
1951         gtk_menu_detach (priv->menu);
1952         g_object_unref (priv->menu);
1953     }
1954
1955     priv->menu = menu;
1956     if (priv->menu != NULL)
1957     {
1958         gtk_widget_set_name (GTK_WIDGET (priv->menu), "menu_force_with_corners");
1959         gtk_menu_attach_to_widget (priv->menu, GTK_WIDGET (self), &detach_menu_func);
1960         g_object_ref (priv->menu);
1961
1962         accel_group = gtk_menu_get_accel_group (priv->menu);
1963         if (accel_group != NULL)
1964             hildon_window_add_accel_group (self, accel_group);
1965     }
1966 }
1967
1968 /**
1969  * hildon_window_set_menu:
1970  * @self: A #HildonWindow
1971  * @menu: The #GtkMenu to be used for this #HildonWindow
1972  *
1973  * Sets the menu to be used for this window. This menu overrides
1974  * a program-wide menu that may have been set with
1975  * hildon_program_set_common_menu(). Pass %NULL to remove the current
1976  * menu. HildonWindow takes ownership of the passed menu and you're
1977  * not supposed to free it yourself anymore.
1978  *
1979  * Note: hildon_window_set_menu() calls gtk_widget_show_all() for the
1980  * #GtkMenu. To pass control about visibility to the application
1981  * developer, hildon_window_set_main_menu() was introduced, which
1982  * doesn't do this.
1983  *
1984  * Deprecated: Hildon 2.2: use hildon_window_set_main_menu()
1985  **/
1986 void
1987 hildon_window_set_menu                          (HildonWindow *self, 
1988                                                  GtkMenu *menu)
1989 {
1990     HildonWindowPrivate *priv;
1991
1992     g_return_if_fail (HILDON_IS_WINDOW (self));
1993
1994     hildon_window_set_main_menu (self, menu);
1995
1996     priv = HILDON_WINDOW_GET_PRIVATE (self);
1997
1998     if (priv->menu != NULL)
1999         gtk_widget_show_all (GTK_WIDGET (priv->menu));
2000 }
2001
2002 /**
2003  * hildon_window_get_is_topmost:
2004  * @self: A #HildonWindow
2005  *
2006  * Returns whether the #HildonWindow is currenty activated by the
2007  * window manager.
2008  *
2009  * Return value: %TRUE if @self is currently activated, %FALSE otherwise.
2010  **/
2011 gboolean
2012 hildon_window_get_is_topmost                    (HildonWindow *self)
2013 {
2014     HildonWindowPrivate *priv;
2015
2016     g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
2017
2018     priv = HILDON_WINDOW_GET_PRIVATE (self);
2019     return priv->is_topmost;
2020 }
2021
2022 /**
2023  * hildon_window_set_app_menu:
2024  * @self: a #HildonWindow
2025  * @menu: a #HildonAppMenu to be used for this window
2026  *
2027  * Sets the menu to be used for this window. Pass %NULL to remove the
2028  * current menu. Any reference to a previous menu will be dropped.
2029  * #HildonWindow takes ownership of the passed menu and
2030  * you're not supposed to free it yourself anymore.
2031  *
2032  * Note that if you're using a #GtkMenu rather than a #HildonAppMenu
2033  * you should use hildon_window_set_main_menu() instead.
2034  *
2035  * Since: 2.2
2036  **/
2037 void
2038 hildon_window_set_app_menu                      (HildonWindow  *self,
2039                                                  HildonAppMenu *menu)
2040 {
2041     HildonWindowPrivate *priv;
2042     HildonAppMenu *old_menu;
2043
2044     g_return_if_fail (HILDON_IS_WINDOW (self));
2045     g_return_if_fail (!menu || HILDON_IS_APP_MENU (menu));
2046     priv = HILDON_WINDOW_GET_PRIVATE (self);
2047
2048     old_menu = priv->app_menu;
2049
2050     /* Add new menu */
2051     priv->app_menu = menu;
2052     if (menu)
2053         g_object_ref_sink (menu);
2054
2055     /* Unref old menu */
2056     if (old_menu)
2057         g_object_unref (old_menu);
2058 }
2059
2060 /**
2061  * hildon_window_get_app_menu:
2062  * @self: a #HildonWindow
2063  *
2064  * Returns the #HildonAppMenu assigned to @self, or %NULL if it's
2065  * unset. Note that the window is still the owner of the menu.
2066  *
2067  * Note that if you're using a #GtkMenu rather than a #HildonAppMenu
2068  * you should use hildon_window_get_main_menu() instead.
2069  *
2070  * Returns: a #HildonAppMenu
2071  *
2072  * Since: 2.2
2073  **/
2074 HildonAppMenu *
2075 hildon_window_get_app_menu                      (HildonWindow *self)
2076 {
2077     HildonWindowPrivate *priv;
2078
2079     g_return_val_if_fail (HILDON_IS_WINDOW (self), NULL);
2080
2081     priv = HILDON_WINDOW_GET_PRIVATE (self);
2082
2083     return priv->app_menu;
2084 }
2085
2086 static void
2087 hildon_window_update_markup                     (HildonWindow *window)
2088 {
2089     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (window);
2090     GdkAtom markup_atom = gdk_atom_intern ("_HILDON_WM_NAME", FALSE);
2091     GdkAtom utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE);
2092     GdkWindow *gdkwin = GTK_WIDGET (window)->window;
2093
2094     if (priv->markup) {
2095         gdk_property_change (gdkwin, markup_atom, utf8_atom, 8,
2096                              GDK_PROP_MODE_REPLACE, (const guchar *) priv->markup,
2097                              strlen (priv->markup));
2098     } else {
2099         gdk_property_delete (gdkwin, markup_atom);
2100     }
2101 }
2102
2103 /**
2104  * hildon_window_get_markup:
2105  * @window: a #HildonWindow
2106  *
2107  * Gets the marked up title of the window title. See hildon_window_set_markup()
2108  *
2109  * Returns: the marked up title of the window, or %NULL if none has
2110  * been set explicitely. The returned string is owned by the widget
2111  * and must not be modified or freed.
2112  *
2113  * Since: 2.2
2114  **/
2115 const gchar *
2116 hildon_window_get_markup                        (HildonWindow *window)
2117 {
2118     HildonWindowPrivate *priv;
2119
2120     g_return_val_if_fail (HILDON_IS_WINDOW (window), NULL);
2121
2122     priv = HILDON_WINDOW_GET_PRIVATE (window);
2123
2124     return priv->markup;
2125 }
2126
2127 /**
2128  * hildon_window_set_markup:
2129  * @window: a #HildonWindow
2130  * @markup: the marked up title of the window, or %NULL to unset the
2131  * current one
2132  *
2133  * Sets the marked up title of @window. The accepted format is the one
2134  * used in Pango (see #PangoMarkupFormat) with the exception of
2135  * &lt;span&gt;.
2136  *
2137  * Note that you need support from the window manager for this title
2138  * to be used. See gtk_window_set_title() for the standard way of
2139  * setting the title of a window.
2140  *
2141  * Since: 2.2
2142  **/
2143 void
2144 hildon_window_set_markup                        (HildonWindow *window,
2145                                                  const gchar  *markup)
2146 {
2147     HildonWindowPrivate *priv;
2148     gchar *new_markup;
2149
2150     g_return_if_fail (HILDON_IS_WINDOW (window));
2151
2152     priv = HILDON_WINDOW_GET_PRIVATE (window);
2153
2154     new_markup = g_strdup (markup);
2155     g_free (priv->markup);
2156     priv->markup = new_markup;
2157
2158     if (GTK_WIDGET_REALIZED (window))
2159         hildon_window_update_markup (window);
2160
2161     g_object_notify (G_OBJECT (window), "markup");
2162 }