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