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