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