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