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