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