Remove HILDON_ENABLE_UNSTABLE_API.
[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     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (window);
500     g_assert (priv);
501
502     GtkBorder *borders = NULL;
503     GtkBorder *toolbar_borders = NULL;
504
505     if (priv->borders)
506         gtk_border_free (priv->borders);
507     if (priv->toolbar_borders)
508         gtk_border_free (priv->toolbar_borders);
509
510     priv->borders = NULL;
511     priv->toolbar_borders = NULL;
512
513     gtk_widget_style_get (GTK_WIDGET (window), "borders",&borders,
514             "toolbar-borders", &toolbar_borders,
515             NULL);
516
517     // We're doing a copy here instead of reusing the pointer, 
518     // as we don't know where it comes from (has it been allocated using 
519     // malloc or slices... and we want to free it sanely. Blowing on 
520     // cold probbably.
521
522     if (borders) {
523         priv->borders = gtk_border_copy (borders);
524         gtk_border_free (borders);
525     } else 
526         priv->borders = g_slice_new0 (GtkBorder);
527
528     if (toolbar_borders) {
529         priv->toolbar_borders = gtk_border_copy (toolbar_borders);
530         gtk_border_free (toolbar_borders);
531     } else
532         priv->toolbar_borders = g_slice_new0 (GtkBorder);
533 }
534
535 static gboolean
536 hildon_window_expose                            (GtkWidget *widget, 
537                                                  GdkEventExpose * event)
538 {
539     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
540     g_assert (priv);
541
542     GtkWidget *bx = priv->vbox;
543     GtkBox *box = GTK_BOX(bx);
544     GtkBorder *b = priv->borders;
545     GtkBorder *tb = priv->toolbar_borders;
546     gint tb_height = 0;
547
548     if (! priv->borders) {
549         hildon_window_get_borders (HILDON_WINDOW (widget));
550         b = priv->borders;
551         tb = priv->toolbar_borders;
552     }
553
554     tb_height = bx->allocation.height + tb->top + tb->bottom;
555
556     paint_toolbar (widget, box,
557             event, priv->fullscreen);
558
559     if (! priv->fullscreen) {
560
561         /* Draw the left and right window border */
562         gint side_borders_height = widget->allocation.height - b->top;
563
564         if (priv->visible_toolbars)
565             side_borders_height -= tb_height;
566         else
567             side_borders_height -= b->bottom;
568
569         if (b->left > 0) 
570         {
571             gtk_paint_box (widget->style, widget->window,
572                     GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
573                     &event->area, widget, "left-border",
574                     widget->allocation.x, widget->allocation.y +
575                     b->top, b->left, side_borders_height);
576         } 
577
578         if (b->right > 0)
579         {
580             gtk_paint_box (widget->style, widget->window,
581                     GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
582                     &event->area, widget, "right-border",
583                     widget->allocation.x + widget->allocation.width -
584                     b->right, widget->allocation.y + b->top,
585                     b->right, side_borders_height);
586         }
587
588         /* If no toolbar, draw the bottom window border */
589         if (! priv->visible_toolbars && b->bottom > 0)
590         {
591             gtk_paint_box (widget->style, widget->window,
592                     GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
593                     &event->area, widget, "bottom-border",
594                     widget->allocation.x, widget->allocation.y +
595                     (widget->allocation.height - b->bottom),
596                     widget->allocation.width, b->bottom);
597         }
598
599         /* Draw the top border */
600         if (b->top > 0)
601         {
602             gtk_paint_box (widget->style, widget->window,
603                     GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
604                     &event->area, widget, "top-border",
605                     widget->allocation.x, widget->allocation.y,
606                     widget->allocation.width, b->top);
607         } 
608
609
610     }
611
612     /* don't draw the window stuff as it overwrites our borders with a blank
613      * rectangle. Instead start with the drawing of the GtkBin */
614     GTK_WIDGET_CLASS (g_type_class_peek_parent (hildon_window_parent_class))->expose_event (widget, event);
615
616     /* FIXME Not sure why this is commented out 
617      * GTK_WIDGET_CLASS (hildon_window_parent_class))->
618      *  expose_event (widget, event); 
619      */
620
621     return FALSE;
622 }
623
624 static void
625 hildon_window_size_request                      (GtkWidget *widget, 
626                                                  GtkRequisition *requisition)
627 {
628     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
629     g_assert (priv);
630
631     GtkWidget *child = GTK_BIN (widget)->child;
632     GtkRequisition req2;
633     gint border_width = GTK_CONTAINER(widget)->border_width;
634
635     if (! priv->borders)
636     {
637         hildon_window_get_borders (HILDON_WINDOW (widget));
638     }
639
640     if (child)
641         gtk_widget_size_request (child, requisition);
642
643     if (priv->vbox != NULL)
644         gtk_widget_size_request (priv->vbox, &req2);
645
646     requisition->height += req2.height;
647     requisition->width = (requisition->width < req2.width) ? 
648         req2.width : requisition->width;
649
650     requisition->width  += 2 * border_width;
651     requisition->height += 2 * border_width;
652
653     if (! priv->fullscreen)
654     {
655         requisition->height += priv->borders->top;
656         if (req2.height == 0)
657             requisition->height += priv->borders->bottom;
658         requisition->width += priv->borders->left + priv->borders->right;
659     }
660 }
661
662 static void
663 hildon_window_size_allocate                     (GtkWidget *widget, 
664                                                  GtkAllocation *allocation)
665 {
666     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
667     g_assert (priv);
668
669     GtkAllocation box_alloc;
670     GtkAllocation alloc = *allocation;
671     GtkRequisition req;
672     gint border_width = GTK_CONTAINER(widget)->border_width;
673
674     GtkWidget *box = priv->vbox;
675     GtkBin *bin = GTK_BIN(widget);
676     GtkBorder *b = priv->borders;
677     GtkBorder *tb = priv->toolbar_borders;
678
679     if (!priv->borders)
680     {
681         hildon_window_get_borders (HILDON_WINDOW (widget));
682         b = priv->borders;
683         tb = priv->toolbar_borders;
684     }
685
686     widget->allocation = *allocation;
687
688     gtk_widget_get_child_requisition (box, &req);
689
690     box_alloc.width = allocation->width - tb->left - tb->right;
691     box_alloc.height = ( (req.height < allocation->height) ?
692             req.height : allocation->height );
693     box_alloc.x = allocation->x + tb->left;
694     box_alloc.y = allocation->y + allocation->height - box_alloc.height - tb->bottom;
695
696     if (bin->child != NULL && GTK_IS_WIDGET (bin->child)
697             && GTK_WIDGET_VISIBLE (bin->child))
698     {
699         alloc.x += border_width;
700         alloc.y += border_width;
701         alloc.width -= (border_width * 2);
702         alloc.height -= (border_width * 2) + box_alloc.height;
703
704         if (! priv->fullscreen)
705         {
706             alloc.x += b->left;
707             alloc.width -= (b->left + b->right);
708             alloc.y += b->top;
709
710             alloc.height -= b->top;
711
712             if (box_alloc.height <= 0)
713                 alloc.height -= b->bottom;
714             else
715                 alloc.height -= (tb->top + tb->bottom);            
716         }
717         else
718         {
719             if (!(box_alloc.height <= 0))
720                 alloc.height -= (tb->top + tb->bottom);              
721         }
722
723         gtk_widget_size_allocate (bin->child, &alloc);
724     }
725
726     gtk_widget_size_allocate (box, &box_alloc);
727
728     if (priv->previous_vbox_y != box_alloc.y)
729     {
730         /* The size of the VBox has changed, we need to redraw part
731          * of the window borders */
732         gint draw_from_y = priv->previous_vbox_y < box_alloc.y?
733             priv->previous_vbox_y - tb->top:
734             box_alloc.y - tb->top;
735
736         gtk_widget_queue_draw_area (widget, 0, draw_from_y, 
737                 widget->allocation.width,
738                 widget->allocation.height - draw_from_y);
739
740         priv->previous_vbox_y = box_alloc.y;
741     }
742
743 }
744
745 static void
746 hildon_window_forall                            (GtkContainer *container, 
747                                                  gboolean include_internals,
748                                                  GtkCallback callback, 
749                                                  gpointer callback_data)
750 {
751     HildonWindow *self = HILDON_WINDOW (container);
752     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
753
754     g_return_if_fail (callback != NULL);
755     g_assert (priv);
756
757     GTK_CONTAINER_CLASS (hildon_window_parent_class)->forall (container, include_internals,
758             callback, callback_data);
759     if (include_internals && priv->vbox != NULL)
760         (* callback)(GTK_WIDGET (priv->vbox), callback_data);
761 }
762
763 static void
764 hildon_window_show_all                          (GtkWidget *widget)
765 {
766     HildonWindow *self = HILDON_WINDOW (widget);
767     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
768
769     g_assert (priv != NULL);
770
771     GTK_WIDGET_CLASS (hildon_window_parent_class)->show_all (widget);
772     gtk_widget_show_all (priv->vbox);
773 }
774
775 static void
776 hildon_window_destroy                           (GtkObject *obj)
777 {
778     HildonWindow *self = HILDON_WINDOW (obj);
779     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (obj);
780     GList *menu_list = NULL;
781     GList *menu_node = NULL;
782
783     g_assert (priv != NULL);
784
785     if (priv->vbox != NULL)
786     {
787         if (priv->program)
788         {
789             GtkWidget * common_toolbar = 
790                 GTK_WIDGET (hildon_program_get_common_toolbar (priv->program));
791             if (common_toolbar && common_toolbar->parent == priv->vbox)
792             {
793                 gtk_container_remove (GTK_CONTAINER (priv->vbox),
794                         common_toolbar);
795             }
796         }
797
798         gtk_widget_unparent (priv->vbox);
799         priv->vbox = NULL;    
800
801     }
802
803     menu_list = g_list_copy (gtk_menu_get_for_attach_widget (GTK_WIDGET (obj)));
804     menu_node = menu_list;
805
806     while (menu_node)
807     {
808         if (GTK_IS_MENU (menu_node->data))
809         {
810             if (GTK_WIDGET_VISIBLE (GTK_WIDGET (menu_node->data)))
811             {
812                 gtk_menu_popdown (GTK_MENU (menu_node->data));
813                 gtk_menu_shell_deactivate (GTK_MENU_SHELL (menu_node->data));
814             }
815             gtk_menu_detach (GTK_MENU (menu_node->data));
816
817             /* Destroy it, but only if it's not a common menu */
818             if (priv->program && 
819                 hildon_program_get_common_menu (priv->program) != menu_node->data) {
820                     gtk_object_destroy (GTK_OBJECT (menu_node->data));
821                     g_object_unref (menu_node->data);
822             }
823         }
824         menu_node = menu_node->next;
825     }
826
827     g_list_free (menu_list);
828     menu_list = NULL;
829
830     if (priv->program)
831     {
832         hildon_program_remove_window (priv->program, self);
833     }
834
835     gdk_window_remove_filter (gdk_get_default_root_window(), 
836             hildon_window_root_window_event_filter,
837             obj);
838
839     gtk_widget_set_events (GTK_WIDGET(obj), 0);
840
841     GTK_OBJECT_CLASS (hildon_window_parent_class)->destroy (obj);
842 }
843
844 static void
845 hildon_window_notify                            (GObject *gobject, 
846                                                  GParamSpec *param)
847 {
848     HildonWindow *window = HILDON_WINDOW (gobject);
849
850     if (g_str_equal (param->name, "title"))
851     {
852
853         hildon_window_update_title (window);
854     }
855     else if (g_str_equal (param->name, "is-topmost"))
856     {
857         hildon_window_is_topmost_notify (window);
858     }
859
860     if (G_OBJECT_CLASS(hildon_window_parent_class)->notify)
861         G_OBJECT_CLASS(hildon_window_parent_class)->notify (gobject, param);
862 }
863
864
865 static void
866 visible_toolbar                                 (gpointer data, 
867                                                  gpointer user_data)
868 {
869     if (GTK_WIDGET_VISIBLE (((GtkBoxChild *)data)->widget))
870         (*((gint *)user_data))++;
871 }
872
873 static void 
874 find_findtoolbar_index                          (gpointer data, 
875                                                  gpointer user_data)
876 {
877     gint *pass_bundle = (gint *)user_data;
878
879     if(((GtkBoxChild *)data)->widget->allocation.y < pass_bundle[0]
880             && GTK_WIDGET_VISIBLE (((GtkBoxChild *)data)->widget))
881         pass_bundle[1]++;
882 }
883
884 static void
885 find_findtoolbar                                (gpointer data, 
886                                                  gpointer user_data)
887 {
888     if(HILDON_IS_FIND_TOOLBAR (((GtkBoxChild *)data)->widget)
889             && GTK_WIDGET_VISIBLE (((GtkBoxChild *)data)->widget))
890         (*((GtkWidget **)user_data)) = ((GtkBoxChild *)data)->widget;
891 }
892
893 static void
894 paint_toolbar                                   (GtkWidget *widget, 
895                                                  GtkBox *box, 
896                                                  GdkEventExpose * event, 
897                                                  gboolean fullscreen)
898 {
899     gint toolbar_num = 0; 
900     gint ftb_index = 0;
901     gint count;
902     GtkWidget *findtoolbar = NULL;
903     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
904     gchar toolbar_mode[40];
905     GtkBorder *tb = priv->toolbar_borders;
906
907     g_assert (priv != NULL);
908
909     /* collect info to help on painting the boxes */
910     g_list_foreach (box->children, visible_toolbar, 
911             (gpointer) &toolbar_num);
912
913     if(toolbar_num <= 0)
914         return;
915
916     g_list_foreach (box->children, find_findtoolbar, (gpointer) &findtoolbar);
917
918     if (findtoolbar != NULL)
919     {
920         gint pass_bundle[2];/* an array for convient data passing
921                                the first member contains the y allocation
922                                of the find toolbar, and the second allocation
923                                contains the index(how many toolbars are above
924                                find toolbar) */
925         pass_bundle[0] = findtoolbar->allocation.y;
926         pass_bundle[1] = ftb_index;
927         g_list_foreach(box->children, find_findtoolbar_index,
928                 (gpointer) pass_bundle);
929         ftb_index = pass_bundle[1];
930     }
931
932     /*upper border*/
933     sprintf (toolbar_mode, "toolbar%sframe-top", 
934             fullscreen ? "-fullscreen-" : "-");
935     gtk_paint_box (widget->style, widget->window,
936             GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT,
937             &event->area, widget, toolbar_mode,
938             widget->allocation.x,
939             GTK_WIDGET (box)->allocation.y - tb->top,
940             widget->allocation.width, tb->top);
941
942     /*top most toolbar painting*/
943     if (findtoolbar != NULL && ftb_index == 0 )
944     {
945         sprintf (toolbar_mode, "findtoolbar%s", 
946                 fullscreen ? "-fullscreen" : "");
947
948         gtk_paint_box (widget->style, widget->window,
949                 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
950                 &event->area, widget, toolbar_mode,
951                 widget->allocation.x,
952                 GTK_WIDGET(box)->allocation.y,
953                 widget->allocation.width,
954                 TOOLBAR_HEIGHT);
955     }
956     else
957     {
958         sprintf (toolbar_mode, "toolbar%s", 
959                 fullscreen ? "-fullscreen" : "");
960
961         gtk_paint_box (widget->style, widget->window,
962                 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
963                 &event->area, widget, toolbar_mode,
964                 widget->allocation.x,
965                 GTK_WIDGET(box)->allocation.y,
966                 widget->allocation.width,
967                 TOOLBAR_HEIGHT);
968     }
969     /*multi toolbar painting*/
970     for (count = 0; count < toolbar_num - 1; count++)
971     {
972         sprintf (toolbar_mode, "toolbar%sframe-middle", 
973                 fullscreen ? "-fullscreen-" : "-");
974
975         gtk_paint_box (widget->style, widget->window,
976                 GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
977                 &event->area, widget, toolbar_mode,
978                 widget->allocation.x,
979                 GTK_WIDGET(box)->allocation.y + 
980                 (1 + count) * TOOLBAR_HEIGHT + 
981                 count * TOOLBAR_MIDDLE,
982                 widget->allocation.width,
983                 TOOLBAR_MIDDLE);
984
985         if (findtoolbar != NULL && count + 1 == ftb_index)
986         {
987
988             sprintf (toolbar_mode, "findtoolbar%s", 
989                     fullscreen ? "-fullscreen" : "");
990
991             gtk_paint_box (widget->style, widget->window,
992                     GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
993                     &event->area, widget, toolbar_mode,
994                     widget->allocation.x,
995                     GTK_WIDGET(box)->allocation.y + 
996                     (1 + count) * (TOOLBAR_HEIGHT + TOOLBAR_MIDDLE),
997                     widget->allocation.width,
998                     TOOLBAR_HEIGHT);
999         }
1000         else
1001         {
1002             sprintf (toolbar_mode, "toolbar%s", 
1003                     fullscreen ? "-fullscreen" : "");
1004
1005             gtk_paint_box (widget->style, widget->window,
1006                     GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
1007                     &event->area, widget, toolbar_mode,
1008                     widget->allocation.x,
1009                     GTK_WIDGET(box)->allocation.y + 
1010                     (1 + count) * (TOOLBAR_HEIGHT + TOOLBAR_MIDDLE),
1011                     widget->allocation.width,
1012                     TOOLBAR_HEIGHT);
1013         }
1014     }
1015     sprintf (toolbar_mode, "toolbar%sframe-bottom", 
1016             fullscreen ? "-fullscreen-" : "-");
1017
1018     gtk_paint_box (widget->style, widget->window,
1019             GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
1020             &event->area, widget, toolbar_mode,
1021             widget->allocation.x,
1022             GTK_WIDGET(box)->allocation.y + 
1023             GTK_WIDGET(box)->allocation.height,
1024             widget->allocation.width, tb->bottom);
1025 }
1026
1027 /*
1028  * Checks the root window to know which is the topped window
1029  */
1030 Window
1031 hildon_window_get_active_window                 (void)
1032 {
1033     Atom realtype;
1034     gint xerror;
1035     int format;
1036     int status;
1037     Window ret;
1038     unsigned long n;
1039     unsigned long extra;
1040     union
1041     {
1042         Window *win;
1043         unsigned char *char_pointer;
1044     } win;
1045     Atom active_app_atom = 
1046         XInternAtom (GDK_DISPLAY (), "_MB_CURRENT_APP_WINDOW", False);
1047
1048     win.win = NULL;
1049
1050     gdk_error_trap_push ();
1051     status = XGetWindowProperty (GDK_DISPLAY(), GDK_ROOT_WINDOW(),
1052             active_app_atom, 0L, 16L,
1053             0, XA_WINDOW, &realtype, &format,
1054             &n, &extra, &win.char_pointer);
1055     xerror = gdk_error_trap_pop ();
1056     if (xerror || !(status == Success && realtype == XA_WINDOW && format == 32
1057                 && n == 1 && win.win != NULL))
1058     {
1059         if (win.win != NULL)
1060             XFree (win.char_pointer);
1061         return None;
1062     }
1063
1064     ret = win.win[0];
1065
1066     if (win.win != NULL)
1067         XFree(win.char_pointer);
1068
1069     return ret;
1070 }
1071
1072 static int
1073 xclient_message_type_check                      (XClientMessageEvent *cm, 
1074                                                  const gchar *name)
1075 {
1076     return cm->message_type == XInternAtom(GDK_DISPLAY(), name, FALSE);
1077 }
1078
1079 /*
1080  * Handle the window border custom button, which toggles the menu,
1081  * and the Hildon input method copy paste messages
1082  */
1083 static GdkFilterReturn
1084 hildon_window_event_filter                      (GdkXEvent *xevent, 
1085                                                  GdkEvent *event, 
1086                                                  gpointer data)
1087 {
1088     XAnyEvent *eventti = xevent;
1089
1090     if (eventti->type == ClientMessage)
1091     {
1092         XClientMessageEvent *cm = xevent;
1093
1094         if (xclient_message_type_check (cm, "_MB_GRAB_TRANSFER"))
1095         {
1096             hildon_window_toggle_menu (HILDON_WINDOW ( data ), cm->data.l[2], cm->data.l[0]);
1097             return GDK_FILTER_REMOVE;
1098         }
1099         /* opera hack clipboard client message */
1100         else if (xclient_message_type_check (cm, "_HILDON_IM_CLIPBOARD_COPY"))
1101         {
1102             g_signal_emit_by_name(G_OBJECT(data), "clipboard_operation",
1103                     HILDON_WINDOW_CO_COPY);
1104             return GDK_FILTER_REMOVE;
1105         }
1106         else if (xclient_message_type_check(cm, "_HILDON_IM_CLIPBOARD_CUT"))
1107         {
1108             g_signal_emit_by_name(G_OBJECT(data), "clipboard_operation",
1109                     HILDON_WINDOW_CO_CUT);
1110             return GDK_FILTER_REMOVE;
1111         }
1112         else if (xclient_message_type_check(cm, "_HILDON_IM_CLIPBOARD_PASTE"))
1113         {
1114             g_signal_emit_by_name(G_OBJECT(data), "clipboard_operation",
1115                     HILDON_WINDOW_CO_PASTE);
1116             return GDK_FILTER_REMOVE;
1117         }
1118     }
1119
1120     return GDK_FILTER_CONTINUE;
1121 }
1122
1123 /*
1124  * Here we keep track of changes in the _MB_CURRENT_APP_WINDOW,
1125  * to know when we acquire/lose topmost status
1126  */
1127 static GdkFilterReturn
1128 hildon_window_root_window_event_filter          (GdkXEvent *xevent, 
1129                                                  GdkEvent *event, 
1130                                                  gpointer data)
1131 {
1132     XAnyEvent *eventti = xevent;
1133     HildonWindow *hwindow = HILDON_WINDOW (data);
1134
1135     if (eventti->type == PropertyNotify)
1136     {
1137         XPropertyEvent *pevent = xevent;
1138         Atom active_app_atom = 
1139             XInternAtom (GDK_DISPLAY (), "_MB_CURRENT_APP_WINDOW", False);
1140
1141         if (pevent->atom == active_app_atom)
1142         {
1143             Window active_window = hildon_window_get_active_window();
1144
1145             hildon_window_update_topmost (hwindow, active_window);
1146         }
1147     }
1148
1149     return GDK_FILTER_CONTINUE;
1150 }
1151
1152 /*
1153  * Handle the menu hardware key here
1154  */
1155 static gboolean
1156 hildon_window_key_press_event                   (GtkWidget *widget, 
1157                                                  GdkEventKey *event)
1158 {
1159     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
1160
1161     g_return_val_if_fail (HILDON_IS_WINDOW (widget),FALSE);
1162     g_assert (priv);
1163
1164     switch (event->keyval)
1165     {
1166         case HILDON_HARDKEY_MENU:
1167             if (hildon_window_toggle_menu (HILDON_WINDOW (widget), 0, GDK_CURRENT_TIME))
1168                 return TRUE;
1169             break;
1170         case HILDON_HARDKEY_ESC:
1171             if (!priv->escape_timeout)
1172             {
1173                 priv->escape_timeout = g_timeout_add 
1174                     (HILDON_WINDOW_LONG_PRESS_TIME,
1175                      hildon_window_escape_timeout, widget);
1176             }
1177             break;
1178     }
1179
1180     return GTK_WIDGET_CLASS (hildon_window_parent_class)->key_press_event (widget, event);
1181 }
1182
1183 static gboolean
1184 hildon_window_key_release_event                 (GtkWidget *widget, 
1185                                                  GdkEventKey *event)
1186 {
1187     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
1188
1189     g_return_val_if_fail (HILDON_IS_WINDOW (widget), FALSE);
1190     g_assert (priv);
1191
1192     switch (event->keyval)
1193     {
1194         case HILDON_HARDKEY_ESC:
1195             if (priv->escape_timeout)
1196             {
1197                 g_source_remove (priv->escape_timeout);
1198                 priv->escape_timeout = 0;
1199             }
1200             break;
1201     }
1202
1203     return GTK_WIDGET_CLASS (hildon_window_parent_class)->key_release_event (widget, event);
1204
1205 }
1206
1207 /*
1208  * We keep track of the window state changes, because the drawing
1209  * (borders) differs whether we are in fullscreen mode or not
1210  */
1211 static gboolean
1212 hildon_window_window_state_event                (GtkWidget *widget, 
1213                                                  GdkEventWindowState *event)
1214 {
1215     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
1216     g_assert (priv != NULL);
1217
1218     if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
1219         priv->fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN;
1220
1221     if (GTK_WIDGET_CLASS (hildon_window_parent_class)->window_state_event)
1222     {
1223         return GTK_WIDGET_CLASS (hildon_window_parent_class)->window_state_event (
1224                 widget,
1225                 event);
1226     }
1227     else
1228     {
1229         return FALSE;
1230     }
1231 }
1232
1233 /*
1234  * If the window lost focus while the user started to press the ESC key, we
1235  * won't get the release event. We need to stop the timeout.
1236  */
1237 static gboolean
1238 hildon_window_focus_out_event                   (GtkWidget *widget, 
1239                                                  GdkEventFocus *event)
1240 {
1241   HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
1242
1243   if (priv->escape_timeout)
1244   {
1245       g_source_remove (priv->escape_timeout);
1246       priv->escape_timeout = 0;
1247   }
1248
1249   return GTK_WIDGET_CLASS (hildon_window_parent_class)->focus_out_event (widget, event);
1250 }
1251
1252 /*
1253  * The menu popuping needs a menu popup-function
1254  */
1255 static void
1256 hildon_window_menu_popup_func                   (GtkMenu *menu, 
1257                                                  gint *x, 
1258                                                  gint *y,
1259                                                  gboolean *push_in, 
1260                                                  GtkWidget *widget)
1261 {
1262     gint window_x = 0;
1263     gint window_y = 0;
1264     GdkWindow *window = GTK_WIDGET(widget)->window;
1265
1266     if (window)
1267     {
1268         gdk_window_get_origin (window, &window_x, &window_y);
1269     }
1270
1271     gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
1272             "vertical-offset", y, NULL);
1273
1274     *x += window_x;
1275     *y += window_y;
1276
1277 }
1278
1279 static void
1280 hildon_window_menu_popup_func_full              (GtkMenu *menu, 
1281                                                  gint *x, 
1282                                                  gint *y,
1283                                                  gboolean *push_in, 
1284                                                  GtkWidget *widget)
1285 {
1286     gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
1287             "vertical-offset", y, NULL);
1288
1289     *x = MAX (0, *x);
1290     *y = MAX (0, *y);
1291 }
1292
1293
1294 /*
1295  * Takes the common toolbar when we acquire the top-most status
1296  */
1297 static void
1298 hildon_window_is_topmost_notify                 (HildonWindow *window)
1299 {
1300     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (window);
1301
1302     g_assert (priv);
1303
1304     if (priv->is_topmost)
1305     {
1306         hildon_window_take_common_toolbar (window);
1307     }
1308 }
1309
1310 /*
1311  * Sets the program to which the window belongs. This should only be called
1312  * by hildon_program_add_window
1313  */
1314 void G_GNUC_INTERNAL
1315 hildon_window_set_program                       (HildonWindow *self, 
1316                                                  GObject *program)
1317 {
1318     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1319
1320     g_return_if_fail (HILDON_IS_WINDOW (self));
1321     g_assert (priv != NULL);
1322
1323     if (priv->program)
1324     {
1325         g_object_unref (priv->program);
1326     }
1327
1328     /* Now that we are bound to a program, we can rely on it to track the
1329      * root window */
1330     gdk_window_remove_filter (gdk_get_default_root_window(), 
1331             hildon_window_root_window_event_filter,
1332             self);
1333
1334     priv->program = HILDON_PROGRAM (program);
1335     g_object_ref (program);
1336 }
1337
1338 /*
1339  * Unsets the program to which the window belongs. This should only be called
1340  * by hildon_program_add_window
1341  */
1342 void G_GNUC_INTERNAL
1343 hildon_window_unset_program                     (HildonWindow *self)
1344 {
1345     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1346
1347     g_return_if_fail(HILDON_IS_WINDOW (self));
1348     g_assert (priv != NULL);
1349
1350     if (priv->program)
1351     {
1352         g_object_unref (priv->program);
1353         priv->program = NULL;
1354
1355         /* We need to start tacking the root window again */
1356         gdk_window_set_events (gdk_get_default_root_window (),
1357                 gdk_window_get_events (gdk_get_default_root_window ())
1358                 | GDK_PROPERTY_CHANGE_MASK);
1359
1360         gdk_window_add_filter (gdk_get_default_root_window (),
1361                 hildon_window_root_window_event_filter, self );
1362     }
1363
1364     priv->program = NULL;
1365 }
1366
1367 /*
1368  * Sets whether or not the program to which this window belongs is
1369  * killable. This is used by the HildonProgram to signify to the
1370  * Task Navigator whether or not it can hibernate in memory-low situations
1371  **/    
1372 void G_GNUC_INTERNAL
1373 hildon_window_set_can_hibernate_property        (HildonWindow *self, 
1374                                                  gpointer _can_hibernate)
1375 {
1376     GdkAtom killable_atom;
1377     gboolean can_hibernate;
1378
1379     g_return_if_fail(self && HILDON_IS_WINDOW (self));
1380
1381     if (!GTK_WIDGET_REALIZED ((GTK_WIDGET (self))))
1382     {
1383         return;
1384     }
1385
1386     can_hibernate = * ((gboolean *)_can_hibernate);
1387
1388     killable_atom = gdk_atom_intern (CAN_HIBERNATE_PROPERTY, FALSE);
1389
1390     if (can_hibernate)
1391     {
1392         gdk_property_change (GTK_WIDGET (self)->window, killable_atom,
1393                 (GdkAtom)31/* XA_STRING */, 8,
1394                 GDK_PROP_MODE_REPLACE, (const guchar *)CAN_HIBERNATE,
1395                 CAN_HIBERNATE_LENGTH);
1396     }
1397     else
1398     {
1399         gdk_property_delete (GTK_WIDGET (self)->window, killable_atom);
1400     }
1401
1402 }
1403
1404 /*
1405  * If a common toolbar was set to the program, reparent it to
1406  * us
1407  */
1408 void G_GNUC_INTERNAL
1409 hildon_window_take_common_toolbar               (HildonWindow *self)
1410 {
1411     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1412
1413     g_return_if_fail(HILDON_IS_WINDOW (self));
1414     g_assert (priv);
1415
1416     if (priv->program)
1417     {
1418         GtkWidget *common_toolbar =  
1419             GTK_WIDGET (hildon_program_get_common_toolbar (priv->program));
1420
1421         if (common_toolbar && common_toolbar->parent != priv->vbox)
1422         {
1423             g_object_ref (common_toolbar);
1424             if (common_toolbar->parent)
1425             {
1426                 gtk_container_remove (GTK_CONTAINER (common_toolbar->parent),
1427                         common_toolbar);
1428             }
1429
1430             gtk_box_pack_end (GTK_BOX(priv->vbox), common_toolbar,
1431                     TRUE, TRUE, 0);
1432             g_object_unref (common_toolbar);
1433
1434             gtk_widget_set_size_request (common_toolbar, -1, TOOLBAR_HEIGHT);
1435
1436             gtk_widget_show  (priv->vbox);
1437
1438         }
1439     }
1440 }
1441
1442 /*
1443  * Compare the window that was last topped, and act consequently
1444  */
1445 void
1446 hildon_window_update_topmost                    (HildonWindow *self, 
1447                                                  Window window_id)
1448 {
1449     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1450
1451     Window my_window;
1452
1453     g_return_if_fail (HILDON_IS_WINDOW (self));
1454     g_assert (priv);
1455
1456     my_window = GDK_WINDOW_XID (GTK_WIDGET (self)->window);
1457
1458     if (window_id == my_window)
1459     {
1460         if (! priv->is_topmost)
1461         {
1462             priv->is_topmost = TRUE;
1463             hildon_window_is_topmost_notify (self);
1464             g_object_notify (G_OBJECT (self), "is-topmost");
1465         }
1466     }
1467     else if (priv->is_topmost)
1468     {
1469         /* Should this go in the signal handler? */
1470         GtkWidget *focus = gtk_window_get_focus (GTK_WINDOW (self));
1471
1472         if (GTK_IS_ENTRY (focus))
1473             gtk_im_context_focus_out (GTK_ENTRY (focus)->im_context);
1474         if (GTK_IS_TEXT_VIEW (focus))
1475             gtk_im_context_focus_out (GTK_TEXT_VIEW (focus)->im_context);
1476
1477         priv->is_topmost = FALSE;
1478         hildon_window_is_topmost_notify (self);
1479         g_object_notify (G_OBJECT (self), "is-topmost");
1480     }
1481 }
1482
1483 /*
1484  * If the application
1485  * was given a name (with g_set_application_name(), set 
1486  * "ProgramName - WindowTitle" as the displayed
1487  * title
1488  */
1489 void G_GNUC_INTERNAL
1490 hildon_window_update_title                      (HildonWindow *window)
1491 {
1492     const gchar * application_name;
1493
1494     g_return_if_fail (HILDON_IS_WINDOW (window));
1495
1496     if (!GTK_WIDGET_REALIZED (window))
1497     {
1498         return;
1499     }
1500
1501     application_name = g_get_application_name ();
1502
1503     if (application_name && application_name[0])
1504     {
1505         const gchar *old_title = gtk_window_get_title (GTK_WINDOW (window));
1506
1507         if (old_title)
1508         {
1509             gchar *title = NULL;
1510                 
1511             if (strlen (old_title) == 0) 
1512                 title = g_strdup (application_name);
1513             else
1514                 title = g_strjoin (TITLE_SEPARATOR, application_name,
1515                                    old_title, NULL);
1516
1517             gdk_window_set_title (GTK_WIDGET (window)->window, title);
1518
1519             g_free (title);
1520         }
1521
1522     }
1523 }
1524
1525 static void
1526 detach_menu_func                                (GtkWidget *attach_widget, 
1527                                                  GtkMenu *menu)
1528 {
1529     /* FIXME Why is this even needed here? */
1530 }
1531
1532 /*
1533  * Toggles the display of the HildonWindow menu.
1534  * Returns whether or not something was done (whether or not we had a menu
1535  * to toggle)
1536  */
1537 static gboolean
1538 hildon_window_toggle_menu                       (HildonWindow * self,
1539                                                  guint button,
1540                                                  guint32 time)
1541 {
1542     GtkMenu *menu_to_use = NULL;
1543     GList *menu_children = NULL;
1544     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1545
1546     g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
1547     g_assert (priv != NULL);
1548
1549     /* Select which menu to use, Window specific has highest priority,
1550      * then program specific */
1551     if (priv->menu)
1552     {
1553         menu_to_use = GTK_MENU (priv->menu);
1554     }
1555     else if (priv->program)
1556     {
1557         menu_to_use = hildon_program_get_common_menu (priv->program);
1558         if (menu_to_use && gtk_menu_get_attach_widget (menu_to_use) != 
1559                 GTK_WIDGET (self))
1560         {
1561             g_object_ref (menu_to_use);
1562             if (gtk_menu_get_attach_widget (menu_to_use))
1563             {
1564                 gtk_menu_detach (menu_to_use);
1565             }
1566
1567             gtk_menu_attach_to_widget (menu_to_use, GTK_WIDGET (self), 
1568                     &detach_menu_func);
1569             g_object_unref (menu_to_use);
1570         }
1571     }
1572
1573     if (! menu_to_use)
1574     {
1575         return FALSE;
1576     }
1577
1578
1579     if (GTK_WIDGET_MAPPED (GTK_WIDGET (menu_to_use)))
1580     {
1581         gtk_menu_popdown (menu_to_use);
1582         gtk_menu_shell_deactivate (GTK_MENU_SHELL (menu_to_use));
1583         return TRUE;
1584     }
1585
1586     /* Check if the menu has items */
1587     menu_children = gtk_container_get_children (GTK_CONTAINER (menu_to_use));
1588
1589     if (menu_children)
1590     {
1591         g_list_free (menu_children);
1592
1593         /* Apply right theming */
1594         gtk_widget_set_name (GTK_WIDGET (menu_to_use),
1595                 "menu_force_with_corners");
1596
1597         if (priv->fullscreen) 
1598         {
1599             gtk_menu_popup (menu_to_use, NULL, NULL,
1600                     (GtkMenuPositionFunc)
1601                     hildon_window_menu_popup_func_full,
1602                     self, button, time);
1603         }
1604         else
1605         {
1606             gtk_menu_popup (menu_to_use, NULL, NULL,
1607                     (GtkMenuPositionFunc)
1608                     hildon_window_menu_popup_func,
1609                     self, button, time);
1610         }
1611         gtk_menu_shell_select_first (GTK_MENU_SHELL (menu_to_use), TRUE);
1612         return TRUE;
1613     }
1614
1615     return FALSE;
1616 }
1617
1618 /*
1619  * If the ESC key was not released when the timeout expires,
1620  * close the window
1621  */
1622 static gboolean
1623 hildon_window_escape_timeout                    (gpointer data)
1624 {
1625     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (data);
1626     GdkEvent *event;
1627
1628     g_assert (priv);
1629
1630     GDK_THREADS_ENTER ();
1631
1632     /* Send fake event, simulation a situation that user
1633        pressed 'x' from the corner */
1634     event = gdk_event_new(GDK_DELETE);
1635     ((GdkEventAny *)event)->window = GDK_WINDOW (g_object_ref (GTK_WIDGET(data)->window));
1636     gtk_main_do_event(event);
1637
1638     /* That unrefs the window, so we're reffing it above */
1639     gdk_event_free(event);
1640
1641     priv->escape_timeout = 0;
1642
1643     GDK_THREADS_LEAVE ();
1644
1645     return FALSE;
1646 }
1647
1648 /**
1649  * hildon_window_new: 
1650  * 
1651  * Creates a new HildonWindow.
1652  * 
1653  * Return value: A @HildonWindow.
1654  **/
1655 GtkWidget*
1656 hildon_window_new                               (void)
1657 {
1658     HildonWindow *newwindow = g_object_new (HILDON_TYPE_WINDOW, NULL);
1659
1660     return GTK_WIDGET (newwindow);
1661 }
1662
1663 /**
1664  * hildon_window_add_with_scrollbar
1665  * @self : A @HildonWindow
1666  * @child : A @GtkWidget
1667  *
1668  * Adds the @child to the HildonWindow and creates a scrollbar
1669  * for it. Similar as adding first a @GtkScrolledWindow and then the
1670  * @child to it.
1671  */
1672 void
1673 hildon_window_add_with_scrollbar                (HildonWindow *self,
1674                                                  GtkWidget *child)
1675 {
1676     GtkScrolledWindow *scrolledw;
1677
1678     g_return_if_fail (HILDON_IS_WINDOW (self));
1679     g_return_if_fail (GTK_IS_WIDGET (child));
1680     g_return_if_fail (child->parent == NULL);
1681
1682     scrolledw = GTK_SCROLLED_WINDOW (gtk_scrolled_window_new (NULL, NULL));
1683     gtk_scrolled_window_set_policy (scrolledw, GTK_POLICY_NEVER,
1684             GTK_POLICY_AUTOMATIC);
1685     gtk_scrolled_window_set_shadow_type (scrolledw, GTK_SHADOW_NONE);
1686
1687     if (GTK_IS_VIEWPORT (child))
1688         gtk_container_add (GTK_CONTAINER (scrolledw), child);
1689     else
1690     {
1691         if (GTK_IS_CONTAINER (child) )
1692             gtk_container_set_focus_vadjustment (GTK_CONTAINER(child),
1693                     gtk_scrolled_window_get_vadjustment (scrolledw) );
1694         gtk_scrolled_window_add_with_viewport (scrolledw, child);
1695     }
1696
1697     gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (scrolledw));
1698 }
1699
1700 static void
1701 calculate_visible_toolbars                      (gpointer data,
1702                                                  gpointer user_data)
1703 {
1704   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (((GtkBoxChild *)data)->widget)))
1705     (*((gint *)user_data)) ++;
1706 }
1707
1708 static void
1709 toolbar_visible_notify                          (GtkWidget *toolbar, GParamSpec *pspec,
1710                                                  HildonWindow *window)
1711 {
1712   HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (window);
1713
1714   g_assert (priv);
1715
1716   /* Recalculate from scratch the value just in case */
1717   priv->visible_toolbars = 0;
1718
1719   g_list_foreach (GTK_BOX (priv->vbox)->children, calculate_visible_toolbars, 
1720                   &priv->visible_toolbars);
1721
1722   if (priv->visible_toolbars == 0)
1723     gtk_widget_hide (priv->vbox);
1724   else
1725     gtk_widget_show (priv->vbox);
1726 }
1727
1728 /**
1729  * hildon_window_add_toolbar:
1730  * @self: A @HildonWindow
1731  * @toolbar: A #GtkToolbar to add to the HildonWindow
1732  *
1733  * Adds a toolbar to the window. Note that the toolbar is not automatically
1734  * shown. You need to call #gtk_widget_show_all on it to make it visible. 
1735  * It's also possible to hide the toolbar (without removing it) by calling
1736  * #gtk_widget_hide.
1737  **/
1738 void 
1739 hildon_window_add_toolbar                       (HildonWindow *self, 
1740                                                  GtkToolbar *toolbar)
1741 {
1742     GtkBox *vbox;
1743     HildonWindowPrivate *priv;
1744
1745     g_return_if_fail (HILDON_IS_WINDOW (self));
1746     g_return_if_fail (toolbar && GTK_IS_TOOLBAR (toolbar));
1747
1748     priv = HILDON_WINDOW_GET_PRIVATE (self);
1749
1750     vbox = GTK_BOX (priv->vbox);
1751
1752     gtk_box_pack_start (vbox, GTK_WIDGET (toolbar), TRUE, TRUE, 0);
1753     gtk_box_reorder_child (vbox, GTK_WIDGET (toolbar), 0);
1754     gtk_widget_set_size_request (GTK_WIDGET (toolbar), -1, TOOLBAR_HEIGHT);
1755
1756     g_signal_connect (G_OBJECT (toolbar), "notify::visible",
1757                       G_CALLBACK (toolbar_visible_notify), self);
1758
1759     if (GTK_WIDGET_VISIBLE (toolbar))
1760       {
1761         priv->visible_toolbars++;
1762         gtk_widget_show (priv->vbox);
1763       }
1764
1765     gtk_widget_queue_resize (GTK_WIDGET (self));
1766 }
1767
1768 /**
1769  * hildon_window_remove_toolbar:
1770  * @self: A @HildonWindow
1771  * @toolbar: A #GtkToolbar to remove from the HildonWindow
1772  *
1773  * Removes a toolbar from the window. Note that this decreases the refference
1774  * count on the widget. If you want to keep the toolbar alive call #g_object_ref 
1775  * before calling this function.
1776  **/
1777 void
1778 hildon_window_remove_toolbar                    (HildonWindow *self, 
1779                                                  GtkToolbar *toolbar)
1780 {
1781     HildonWindowPrivate *priv;
1782
1783     g_return_if_fail (HILDON_IS_WINDOW (self));
1784     
1785     priv = HILDON_WINDOW_GET_PRIVATE (self);
1786
1787     if (GTK_WIDGET_VISIBLE (toolbar))
1788       {
1789         if (--(priv->visible_toolbars) == 0)
1790           gtk_widget_hide (priv->vbox);
1791       }
1792
1793     g_signal_handlers_disconnect_by_func (toolbar, toolbar_visible_notify, self);
1794
1795     gtk_container_remove (GTK_CONTAINER (priv->vbox), GTK_WIDGET (toolbar));
1796 }
1797
1798 /**
1799  * hildon_window_get_menu:
1800  * @self : #HildonWindow
1801  * 
1802  * Gets the #GtMenu assigned to the #HildonAppview. Note that the 
1803  * window is still the owner of the menu.
1804  * 
1805  * Return value: The #GtkMenu assigned to this application view. 
1806  **/
1807 GtkMenu*
1808 hildon_window_get_menu                          (HildonWindow * self)
1809 {
1810     HildonWindowPrivate *priv;
1811
1812     g_return_val_if_fail (HILDON_IS_WINDOW (self), NULL);
1813
1814     priv = HILDON_WINDOW_GET_PRIVATE (self);
1815
1816     return GTK_MENU (priv->menu);
1817 }
1818
1819 /**
1820  * hildon_window_set_menu:
1821  * @self: A #HildonWindow
1822  * @menu: The #GtkMenu to be used for this #HildonWindow
1823  * 
1824  * Sets the menu to be used for this window. This menu overrides
1825  * a program-wide menu that may have been set with
1826  * hildon_program_set_common_menu. Pass NULL to remove the current
1827  * menu. HildonWindow takes ownership of the passed menu and you're
1828  * not supposed to free it yourself anymore.
1829  **/ 
1830 void
1831 hildon_window_set_menu                          (HildonWindow *self, 
1832                                                  GtkMenu *menu)
1833 {
1834     HildonWindowPrivate *priv;
1835
1836     g_return_if_fail (HILDON_IS_WINDOW (self));
1837
1838     priv = HILDON_WINDOW_GET_PRIVATE (self);
1839
1840     if (priv->menu != NULL)
1841     {
1842         gtk_menu_detach (GTK_MENU (priv->menu));
1843         g_object_unref (priv->menu);
1844     }
1845
1846     priv->menu = (menu != NULL) ? GTK_WIDGET (menu) : NULL;
1847     if (priv->menu != NULL)
1848     {
1849         gtk_widget_set_name (priv->menu, "menu_force_with_corners");
1850         gtk_menu_attach_to_widget (GTK_MENU (priv->menu), GTK_WIDGET (self), &detach_menu_func);
1851         g_object_ref (GTK_MENU (priv->menu));
1852         gtk_widget_show_all (GTK_WIDGET (priv->menu));
1853     }
1854 }
1855
1856 /**
1857  * hildon_window_get_is_topmost:
1858  * @self: A #HildonWindow
1859  * 
1860  * Return value: Whether or not the #HildonWindow is currenltly activated
1861  * by the window manager.
1862  **/
1863 gboolean
1864 hildon_window_get_is_topmost                    (HildonWindow *self)
1865 {
1866     HildonWindowPrivate *priv;
1867
1868     g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
1869
1870     priv = HILDON_WINDOW_GET_PRIVATE (self);
1871     return priv->is_topmost;
1872 }
1873