e61c920c87479386bbc07c4b82cd20085748f2cc
[hildon] / hildon / 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: Rodrigo Novo <rodrigo.novo@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24
25 /**
26  * SECTION:hildon-window
27  * @short_description: Top-level window in the Hildon framework.
28  * @see_also: #HildonProgram, #HildonStackableWindow
29  *
30  * #HildonWindow is a top-level
31  * window in the Hildon framework. It is derived from #GtkWindow
32  * and provides additional commodities specific to the Hildon
33  * framework.
34  *
35  * #HildonWindow<!-- -->s can have a menu attached, which is toggled
36  * with a hardware key or by tapping on the window frame. This menu
37  * can be either a #GtkMenu or a #HildonAppMenu (set with
38  * hildon_window_set_main_menu() and hildon_window_set_app_menu()
39  * respectively). Only one type of menu can be used at the same time.
40  * In Hildon 2.2, #HildonAppMenu is the recommended menu to use.
41  *
42  * Similarly, a #HildonWindow can have several toolbars
43  * attached. These can be added with hildon_window_add_toolbar(). In
44  * addition to those, a #HildonWindow can also have a
45  * #HildonEditToolbar. To add it to the window use
46  * hildon_window_set_edit_toolbar().
47  *
48  * <example>
49  * <title>Creating a HildonWindow</title>
50  * <programlisting>
51  * HildonWindow *window;
52  * GtkToolbar *toolbar;
53  * HildonAppMenu *menu;
54  * GdkPixbuf *icon_pixbuf;
55  * <!-- -->
56  * window = HILDON_WINDOW (hildon_window_new());
57  * <!-- -->
58  * toolbar = create_toolbar();
59  * <!-- -->
60  * menu = create_menu();
61  * <!-- -->
62  * icon_pixbuf = create_icon();
63  * <!-- -->
64  * hildon_window_set_app_menu (window, menu);
65  * <!-- -->
66  * hildon_window_add_toolbar (window, toolbar);
67  * <!-- -->
68  * // Can be used to set the window fullscreen
69  * gtk_window_fullscreen (GTK_WINDOW (window));
70  * <!-- -->
71  * // Used to trigger the blinking of the window's icon in the task navigator
72  * gtk_window_set_urgency_hint (GTK_WINDOW (window), TRUE);
73  * <!-- -->
74  * // Change the window's icon in the task navigator
75  * gtk_window_set_icon (GTK_WINDOW (window), icon_pixbuf);
76  * </programlisting>
77  * </example>
78  */
79
80 #undef                                          HILDON_DISABLE_DEPRECATED
81
82 #include                                        <memory.h>
83 #include                                        <string.h>
84 #include                                        <strings.h>
85 #include                                        <stdio.h>
86 #include                                        <libintl.h>
87 #include                                        <X11/X.h>
88 #include                                        <X11/Xatom.h>
89 #include                                        <gdk/gdkkeysyms.h>
90 #include                                        <gdk/gdkx.h>
91 #include                                        <gtk/gtkprivate.h>
92
93 #include                                        "hildon-window.h"
94 #include                                        "hildon-window-private.h"
95 #include                                        "hildon-app-menu-private.h"
96 #include                                        "hildon-find-toolbar.h"
97 #include                                        "hildon-defines.h"
98
99 #define                                         _(String) gettext(String)
100
101 #define                                         TOOLBAR_HEIGHT 70
102
103 #define                                         TOOLBAR_MIDDLE 0
104
105 /*FIXME*/
106 #define                                         CAN_HIBERNATE "CANKILL"
107
108 #define                                         CAN_HIBERNATE_LENGTH 7
109
110 #define                                         CAN_HIBERNATE_PROPERTY "_HILDON_ABLE_TO_HIBERNATE"
111
112 #define                                         LEGACY_MENU_PROPERTY_NAME  "_HILDON_WM_WINDOW_TYPE"
113 #define                                         LEGACY_MENU_PROPERTY_VALUE "_HILDON_WM_WINDOW_TYPE_LEGACY_MENU"
114
115 #define TITLE_SEPARATOR                         " - "
116
117 typedef void                                    (*HildonWindowSignal) (HildonWindow *, gint, gpointer);
118
119 static void
120 hildon_window_init                              (HildonWindow * self);
121
122 static void
123 hildon_window_class_init                        (HildonWindowClass * window_class);
124
125 static void
126 hildon_window_menu_popup_func                   (GtkMenu *menu, 
127                                                  gint *x, 
128                                                  gint *y,
129                                                  gboolean *push_in,
130                                                  GtkWidget *widget);
131 static void
132 hildon_window_menu_popup_func_full              (GtkMenu *menu, 
133                                                  gint *x, 
134                                                  gint *y,
135                                                  gboolean *push_in,
136                                                  GtkWidget *widget);
137 static gboolean
138 hildon_window_expose                            (GtkWidget *widget, 
139                                                  GdkEventExpose *event);
140 static void 
141 hildon_window_forall                            (GtkContainer *container,
142                                                  gboolean include_internals,
143                                                  GtkCallback callback,
144                                                  gpointer callback_data);
145 static void
146 hildon_window_show_all                          (GtkWidget *widget);
147
148 static void
149 hildon_window_size_allocate                     (GtkWidget * widget,
150                                                  GtkAllocation *allocation);
151 static void
152 hildon_window_size_request                      (GtkWidget * widget,
153                                                  GtkRequisition *requisition);
154 static void
155 hildon_window_finalize                          (GObject *obj_self);
156
157 static void
158 hildon_window_get_property                      (GObject *object,
159                                                  guint property_id,
160                                                  GValue *value, 
161                                                  GParamSpec *pspec);
162
163 static void
164 hildon_window_set_property                      (GObject      *object,
165                                                  guint         property_id,
166                                                  const GValue *value,
167                                                  GParamSpec   *pspec);
168
169 static void
170 hildon_window_update_markup                     (HildonWindow *window);
171
172 static void
173 hildon_window_destroy                           (GtkObject *obj);
174
175 static void
176 hildon_window_realize                           (GtkWidget *widget);
177
178 static void
179 hildon_window_unrealize                         (GtkWidget *widget);
180
181 static void
182 hildon_window_map                               (GtkWidget *widget);
183
184 static void
185 hildon_window_unmap                             (GtkWidget *widget);
186
187 static gboolean
188 hildon_window_key_press_event                   (GtkWidget *widget,
189                                                  GdkEventKey *event);
190
191 static gboolean
192 hildon_window_key_release_event                 (GtkWidget *widget, 
193                                                  GdkEventKey *event);
194 static gboolean
195 hildon_window_window_state_event                (GtkWidget *widget, 
196                                                  GdkEventWindowState *event);
197 static gboolean
198 hildon_window_focus_out_event                   (GtkWidget *widget, 
199                                                  GdkEventFocus *event);
200
201 static void
202 hildon_window_notify                            (GObject *gobject, 
203                                                  GParamSpec *param);
204
205 static void
206 hildon_window_is_topmost_notify                 (HildonWindow *window);
207
208 static gboolean
209 hildon_window_toggle_menu                       (HildonWindow * self,
210                                                  guint button,
211                                                  guint32 time);
212
213 static gboolean
214 hildon_window_toggle_menu_real                  (HildonWindow * self,
215                                                  guint button,
216                                                  guint32 time);
217
218 static gboolean
219 hildon_window_escape_timeout                    (gpointer data);
220
221 static GdkFilterReturn
222 hildon_window_event_filter                      (GdkXEvent *xevent, 
223                                                  GdkEvent *event, 
224                                                  gpointer data);
225
226 static GdkFilterReturn
227 hildon_window_root_window_event_filter          (GdkXEvent *xevent, 
228                                                  GdkEvent *event, 
229                                                  gpointer data );
230
231 static void
232 hildon_window_get_borders                       (HildonWindow *window);
233
234 static void
235 visible_toolbar                                 (gpointer data, 
236                                                  gpointer user_data);
237
238 static void
239 paint_toolbar                                   (GtkWidget *widget, 
240                                                  GtkBox *box, 
241                                                  GdkEventExpose * event, 
242                                                  gboolean fullscreen);
243
244 static void
245 paint_edit_toolbar                              (GtkWidget *widget,
246                                                  GtkWidget *toolbar,
247                                                  GdkEventExpose *event,
248                                                  gboolean fullscreen);
249
250 enum
251 {
252     PROP_0,
253     PROP_IS_TOPMOST,
254     PROP_MARKUP
255 };
256
257 enum
258 {
259     WIN_TYPE = 0,
260     WIN_TYPE_MESSAGE,
261     MAX_WIN_MESSAGES
262 };
263
264 G_DEFINE_TYPE (HildonWindow, hildon_window, GTK_TYPE_WINDOW);
265
266 static void 
267 hildon_window_class_init                        (HildonWindowClass * window_class)
268 {
269     /* Get convenience variables */
270     GtkWidgetClass *widget_class        = GTK_WIDGET_CLASS (window_class);
271     GObjectClass *object_class          = G_OBJECT_CLASS (window_class);
272     GtkContainerClass *container_class  = GTK_CONTAINER_CLASS (window_class);
273
274     object_class->get_property          = hildon_window_get_property;
275     object_class->set_property          = hildon_window_set_property;
276     object_class->notify                = hildon_window_notify;
277     widget_class->size_allocate         = hildon_window_size_allocate;
278     widget_class->size_request          = hildon_window_size_request;
279     widget_class->expose_event          = hildon_window_expose;
280     widget_class->show_all              = hildon_window_show_all;
281     widget_class->realize               = hildon_window_realize;
282     widget_class->unrealize             = hildon_window_unrealize;
283     widget_class->key_press_event       = hildon_window_key_press_event;
284     widget_class->key_release_event     = hildon_window_key_release_event;
285     widget_class->window_state_event    = hildon_window_window_state_event;
286     widget_class->focus_out_event       = hildon_window_focus_out_event;
287     widget_class->map                   = hildon_window_map;
288     widget_class->unmap                 = hildon_window_unmap;
289
290     /* now the object stuff */
291     object_class->finalize              = hildon_window_finalize;
292
293     /* To the container */
294     container_class->forall             = hildon_window_forall;
295
296     /* To this class */
297     window_class->toggle_menu           = hildon_window_toggle_menu_real;
298
299     /* gtkobject stuff*/
300     GTK_OBJECT_CLASS (window_class)->destroy = hildon_window_destroy; 
301
302     g_type_class_add_private (window_class,
303             sizeof (struct _HildonWindowPrivate));
304
305     /* Install properties */
306
307     g_object_class_install_property (object_class, PROP_IS_TOPMOST,
308             g_param_spec_boolean ("is-topmost",
309                 "Is top-most",
310                 "Whether the window is currently activated by the window "
311                 "manager",
312                 FALSE,
313                 G_PARAM_READABLE));
314
315     g_object_class_install_property (object_class, PROP_MARKUP,
316             g_param_spec_string ("markup",
317                 "Marked up text for the window title",
318                 "Marked up text for the window title",
319                 NULL,
320                 G_PARAM_READWRITE));
321
322     gtk_widget_class_install_style_property (widget_class,
323             g_param_spec_boxed ("borders",
324                 "Graphical borders",
325                 "Size of graphical window borders",
326                 GTK_TYPE_BORDER,
327                 G_PARAM_READABLE));
328
329     gtk_widget_class_install_style_property (widget_class,
330             g_param_spec_boxed ("toolbar-borders",
331                 "Graphical toolbar borders",
332                 "Size of graphical toolbar borders",
333                 GTK_TYPE_BORDER,
334                 G_PARAM_READABLE));
335
336     /* opera hack, install clip operation signal */
337     g_signal_new ("clipboard_operation",
338             G_OBJECT_CLASS_TYPE (object_class),
339             G_SIGNAL_RUN_FIRST,
340             G_STRUCT_OFFSET (HildonWindowClass, clipboard_operation),
341             NULL, NULL,
342             g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1,
343             G_TYPE_INT);
344 }
345
346 static void
347 hildon_window_init                              (HildonWindow *self)
348 {
349     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
350     g_assert (priv != NULL);
351
352     priv->vbox = gtk_vbox_new (TRUE, TOOLBAR_MIDDLE);
353     gtk_widget_set_parent (priv->vbox, GTK_WIDGET(self));
354     priv->menu = NULL;
355     priv->app_menu = NULL;
356     priv->edit_toolbar = NULL;
357     priv->visible_toolbars = 0;
358     priv->is_topmost = FALSE;
359     priv->borders = NULL;
360     priv->toolbar_borders = NULL;
361     priv->escape_timeout = 0;
362     priv->markup = NULL;
363
364     priv->fullscreen = FALSE;
365
366     priv->program = NULL;
367
368     /* We need to track the root window _MB_CURRENT_APP_WINDOW property */
369     gdk_window_set_events (gdk_get_default_root_window (),
370             gdk_window_get_events (gdk_get_default_root_window ()) | GDK_PROPERTY_CHANGE_MASK);
371
372     gdk_window_add_filter (gdk_get_default_root_window (), 
373             hildon_window_root_window_event_filter, self);
374 }
375
376 static void
377 hildon_window_finalize                          (GObject * obj_self)
378 {
379     HildonWindowPrivate *priv; 
380       
381     g_return_if_fail (HILDON_WINDOW (obj_self));
382
383     priv = HILDON_WINDOW_GET_PRIVATE (obj_self);
384     g_assert (priv != NULL);
385     
386     g_free (priv->markup);
387
388     if (priv->escape_timeout) {
389       g_source_remove (priv->escape_timeout);
390       priv->escape_timeout = 0;
391     }
392
393     if (priv->borders)
394         gtk_border_free (priv->borders);
395
396     if (priv->toolbar_borders)
397         gtk_border_free (priv->toolbar_borders);
398
399     if (G_OBJECT_CLASS (hildon_window_parent_class)->finalize)
400         G_OBJECT_CLASS (hildon_window_parent_class)->finalize (obj_self);
401
402 }
403
404 static void
405 hildon_window_realize                           (GtkWidget *widget)
406 {
407     Atom *old_atoms, *new_atoms;
408     Display *disp;
409     Window window;
410     gint atom_count;
411     Window active_window;
412     HildonWindowPrivate *priv;
413
414     GTK_WIDGET_CLASS (hildon_window_parent_class)->realize (widget);
415
416     priv = HILDON_WINDOW_GET_PRIVATE (widget);
417     g_assert (priv != NULL);
418
419     gtk_widget_realize (GTK_WIDGET (priv->vbox));
420
421     if (priv->edit_toolbar != NULL)
422         gtk_widget_realize (priv->edit_toolbar);
423
424     /* catch the custom button signal from mb to display the menu */
425     gdk_window_add_filter (widget->window, hildon_window_event_filter, widget);
426
427     window = GDK_WINDOW_XID (widget->window);
428     disp = GDK_WINDOW_XDISPLAY (widget->window);
429
430     /* Enable custom button that is used for menu */
431     XGetWMProtocols (disp, window, &old_atoms, &atom_count);
432     new_atoms = g_new (Atom, atom_count + 1);
433
434     memcpy (new_atoms, old_atoms, sizeof(Atom) * atom_count);
435
436     new_atoms[atom_count++] =
437         XInternAtom (disp, "_NET_WM_CONTEXT_CUSTOM", False);
438
439     XSetWMProtocols (disp, window, new_atoms, atom_count);
440
441     XFree(old_atoms);
442     g_free(new_atoms);
443
444     /* rely on GDK to set the window group to its default */
445     gdk_window_set_group (widget->window, NULL);
446
447     if (priv->program) {
448         gboolean can_hibernate = hildon_program_get_can_hibernate (priv->program);
449
450         hildon_window_set_can_hibernate_property (HILDON_WINDOW (widget),
451                 &can_hibernate);
452     }
453
454     if (priv->markup)
455         hildon_window_update_markup (HILDON_WINDOW (widget));
456
457     /* Update the topmost status */
458     active_window = hildon_window_get_active_window();
459     hildon_window_update_topmost (HILDON_WINDOW (widget), active_window);
460 }
461
462 static void
463 hildon_window_unrealize                         (GtkWidget *widget)
464 {
465     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
466     g_assert (priv != NULL);
467
468     gdk_window_remove_filter (widget->window, hildon_window_event_filter,
469             widget);
470
471     gtk_widget_unrealize (GTK_WIDGET (priv->vbox));
472
473     if (priv->edit_toolbar != NULL)
474         gtk_widget_unrealize (priv->edit_toolbar);
475
476     GTK_WIDGET_CLASS(hildon_window_parent_class)->unrealize(widget);
477 }
478
479 static void
480 hildon_window_map                             (GtkWidget *widget)
481 {
482   HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
483   g_assert (priv != NULL);
484
485   if (GTK_WIDGET_CLASS (hildon_window_parent_class)->map)
486     GTK_WIDGET_CLASS (hildon_window_parent_class)->map (widget);
487
488   if (priv->vbox != NULL && GTK_WIDGET_VISIBLE (priv->vbox))
489     gtk_widget_map (priv->vbox);
490
491   if (priv->edit_toolbar != NULL && GTK_WIDGET_VISIBLE (priv->edit_toolbar))
492     gtk_widget_map (priv->edit_toolbar);
493 }
494
495 static void
496 hildon_window_unmap                             (GtkWidget *widget)
497 {
498   HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
499   g_assert (priv != NULL);
500
501   gtk_widget_unmap (priv->vbox);
502
503   if (priv->edit_toolbar != NULL)
504     gtk_widget_unmap (priv->edit_toolbar);
505
506   if (GTK_WIDGET_CLASS (hildon_window_parent_class)->unmap)
507     GTK_WIDGET_CLASS (hildon_window_parent_class)->unmap (widget);
508 }
509
510 static void
511 hildon_window_get_property                      (GObject *object, 
512                                                  guint property_id,
513                                                  GValue *value, 
514                                                  GParamSpec * pspec)
515 {
516     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (object);
517     g_assert (priv != NULL);
518
519     switch (property_id) {
520
521         case PROP_IS_TOPMOST:
522             g_value_set_boolean (value, priv->is_topmost);
523             break;
524
525         case PROP_MARKUP:
526             g_value_set_string (value, priv->markup);
527             break;
528
529         default:
530             G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
531             break;
532     }
533 }
534
535 static void
536 hildon_window_set_property                      (GObject      *object,
537                                                  guint         property_id,
538                                                  const GValue *value,
539                                                  GParamSpec   *pspec)
540 {
541     switch (property_id) {
542
543         case PROP_MARKUP:
544             hildon_window_set_markup (HILDON_WINDOW (object), g_value_get_string (value));
545             break;
546
547         default:
548             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
549             break;
550     }
551 }
552
553 /*
554  * Retrieve the graphical borders size used by the themes
555  */
556 static void
557 hildon_window_get_borders                       (HildonWindow *window)
558 {
559     GtkBorder zero = {0, 0, 0, 0};
560     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (window);
561     g_assert (priv);
562
563     GtkBorder *borders = NULL;
564     GtkBorder *toolbar_borders = NULL;
565
566     if (priv->borders)
567         gtk_border_free (priv->borders);
568     if (priv->toolbar_borders)
569         gtk_border_free (priv->toolbar_borders);
570
571     priv->borders = NULL;
572     priv->toolbar_borders = NULL;
573
574     gtk_widget_style_get (GTK_WIDGET (window), "borders",&borders,
575             "toolbar-borders", &toolbar_borders,
576             NULL);
577
578     // We're doing a copy here instead of reusing the pointer, 
579     // as we don't know where it comes from (has it been allocated using 
580     // malloc or slices... and we want to free it sanely. Blowing on 
581     // cold probbably.
582
583     if (borders) {
584         priv->borders = gtk_border_copy (borders);
585         gtk_border_free (borders);
586     } else
587         priv->borders = g_boxed_copy (GTK_TYPE_BORDER, &zero);
588
589     if (toolbar_borders) {
590         priv->toolbar_borders = gtk_border_copy (toolbar_borders);
591         gtk_border_free (toolbar_borders);
592     } else
593         priv->toolbar_borders = g_boxed_copy (GTK_TYPE_BORDER, &zero);
594 }
595
596 static gboolean
597 hildon_window_expose                            (GtkWidget *widget, 
598                                                  GdkEventExpose * event)
599 {
600     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
601     g_assert (priv);
602
603     GtkWidget *bx = priv->vbox;
604     GtkBox *box = GTK_BOX(bx);
605     GtkBorder *b = priv->borders;
606     GtkBorder *tb = priv->toolbar_borders;
607     gint tb_height = 0;
608
609     if (! priv->borders) {
610         hildon_window_get_borders (HILDON_WINDOW (widget));
611         b = priv->borders;
612         tb = priv->toolbar_borders;
613     }
614
615     tb_height = bx->allocation.height + tb->top + tb->bottom;
616
617     paint_toolbar (widget, box,
618             event, priv->fullscreen);
619
620     if (priv->edit_toolbar != NULL)
621     {
622         paint_edit_toolbar (widget, priv->edit_toolbar,
623                             event, priv->fullscreen);
624     }
625
626     if (! priv->fullscreen) {
627
628         /* Draw the left and right window border */
629         gint side_borders_height = widget->allocation.height - b->top;
630
631         if (priv->visible_toolbars)
632             side_borders_height -= tb_height;
633         else
634             side_borders_height -= b->bottom;
635
636         if (b->left > 0) 
637         {
638             gtk_paint_box (widget->style, widget->window,
639                     GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
640                     &event->area, widget, "left-border",
641                     widget->allocation.x, widget->allocation.y +
642                     b->top, b->left, side_borders_height);
643         } 
644
645         if (b->right > 0)
646         {
647             gtk_paint_box (widget->style, widget->window,
648                     GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
649                     &event->area, widget, "right-border",
650                     widget->allocation.x + widget->allocation.width -
651                     b->right, widget->allocation.y + b->top,
652                     b->right, side_borders_height);
653         }
654
655         /* If no toolbar, draw the bottom window border */
656         if (! priv->visible_toolbars && b->bottom > 0)
657         {
658             gtk_paint_box (widget->style, widget->window,
659                     GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
660                     &event->area, widget, "bottom-border",
661                     widget->allocation.x, widget->allocation.y +
662                     (widget->allocation.height - b->bottom),
663                     widget->allocation.width, b->bottom);
664         }
665
666         /* Draw the top border */
667         if (b->top > 0)
668         {
669             gtk_paint_box (widget->style, widget->window,
670                     GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
671                     &event->area, widget, "top-border",
672                     widget->allocation.x, widget->allocation.y,
673                     widget->allocation.width, b->top);
674         } 
675
676
677     }
678
679     /* don't draw the window stuff as it overwrites our borders with a blank
680      * rectangle. Instead start with the drawing of the GtkBin */
681     GTK_WIDGET_CLASS (g_type_class_peek_parent (hildon_window_parent_class))->expose_event (widget, event);
682
683     /* FIXME Not sure why this is commented out 
684      * GTK_WIDGET_CLASS (hildon_window_parent_class))->
685      *  expose_event (widget, event); 
686      */
687
688     return FALSE;
689 }
690
691 static void
692 hildon_window_size_request                      (GtkWidget *widget, 
693                                                  GtkRequisition *requisition)
694 {
695     GdkScreen *screen = gtk_widget_get_screen (widget);
696     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
697     GtkWidget *child;
698     GtkRequisition req;
699     g_assert (priv);
700
701     child = gtk_bin_get_child (GTK_BIN (widget));
702
703     if (child != NULL && GTK_WIDGET_VISIBLE (child))
704         gtk_widget_size_request (child, &req);
705
706     if (priv->vbox != NULL && GTK_WIDGET_VISIBLE (priv->vbox))
707         gtk_widget_size_request (priv->vbox, &req);
708
709     if (priv->edit_toolbar != NULL && GTK_WIDGET_VISIBLE (priv->edit_toolbar))
710         gtk_widget_size_request (priv->edit_toolbar, &req);
711
712     /* Request the full size of the screen */
713     requisition->width = gdk_screen_get_width (screen);
714     requisition->height = gdk_screen_get_height (screen);
715
716     if (! priv->fullscreen)
717         requisition->height -= HILDON_WINDOW_TITLEBAR_HEIGHT;
718 }
719
720 static void
721 hildon_window_size_allocate                     (GtkWidget *widget, 
722                                                  GtkAllocation *allocation)
723 {
724     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
725     g_assert (priv);
726
727     GtkAllocation box_alloc = { 0 };
728     GtkAllocation edittb_alloc = { 0 };
729     GtkAllocation alloc = *allocation;
730
731     GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
732     GtkBorder *tb;
733
734     if (!priv->borders)
735         hildon_window_get_borders (HILDON_WINDOW (widget));
736
737     tb = priv->toolbar_borders;
738
739     widget->allocation = *allocation;
740
741     /* Calculate allocation of edit toolbar */
742     if (priv->edit_toolbar != NULL && GTK_WIDGET_VISIBLE (priv->edit_toolbar))
743     {
744         GtkRequisition req;
745         gtk_widget_get_child_requisition (priv->edit_toolbar, &req);
746         edittb_alloc.width = alloc.width - tb->left - tb->right;
747         edittb_alloc.height = MIN (req.height, alloc.height);
748         edittb_alloc.x = alloc.x + tb->left;
749         edittb_alloc.y = alloc.y + tb->top;
750
751         if (edittb_alloc.height > 0)
752         {
753             alloc.y += tb->top + tb->bottom + edittb_alloc.height;
754             alloc.height -= tb->top + tb->bottom + edittb_alloc.height;
755             gtk_widget_size_allocate (priv->edit_toolbar, &edittb_alloc);
756         }
757     }
758
759     /* Calculate allocation of normal toolbars */
760     if (priv->vbox != NULL && GTK_WIDGET_VISIBLE (priv->vbox))
761     {
762         GtkRequisition req;
763         gtk_widget_get_child_requisition (priv->vbox, &req);
764         box_alloc.width = alloc.width - tb->left - tb->right;
765         box_alloc.height = MIN (req.height, alloc.height);
766         box_alloc.x = alloc.x + tb->left;
767         box_alloc.y = alloc.y + alloc.height - box_alloc.height - tb->bottom;
768
769         if (box_alloc.height > 0)
770         {
771             alloc.height -= tb->top + tb->bottom + box_alloc.height;
772             gtk_widget_size_allocate (priv->vbox, &box_alloc);
773         }
774     }
775
776     /* Calculate allocation of the child widget */
777     if (child != NULL && GTK_WIDGET_VISIBLE (child))
778     {
779         guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
780         alloc.x += border_width;
781         alloc.y += border_width;
782         alloc.width -= (border_width * 2);
783         alloc.height -= (border_width * 2);
784
785         if (! priv->fullscreen)
786         {
787             GtkBorder *b = priv->borders;
788             alloc.x += b->left;
789             alloc.width -= (b->left + b->right);
790
791             /* Use the top border if there's no edit toolbar */
792             if (edittb_alloc.height <= 0)
793             {
794                 alloc.y += b->top;
795                 alloc.height -= b->top;
796             }
797
798             /* Use the top border if there are no standard toolbars */
799             if (box_alloc.height <= 0)
800                 alloc.height -= b->bottom;
801         }
802
803         gtk_widget_size_allocate (child, &alloc);
804     }
805
806     if (priv->previous_vbox_y != box_alloc.y)
807     {
808         /* The size of the VBox has changed, we need to redraw part
809          * of the window borders */
810         gint draw_from_y = MIN (priv->previous_vbox_y, box_alloc.y) - tb->top;
811
812         gtk_widget_queue_draw_area (widget, 0, draw_from_y, 
813                 widget->allocation.width,
814                 widget->allocation.height - draw_from_y);
815
816         priv->previous_vbox_y = box_alloc.y;
817     }
818
819 }
820
821 static void
822 hildon_window_forall                            (GtkContainer *container, 
823                                                  gboolean include_internals,
824                                                  GtkCallback callback, 
825                                                  gpointer callback_data)
826 {
827     HildonWindow *self = HILDON_WINDOW (container);
828     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
829
830     g_return_if_fail (callback != NULL);
831     g_assert (priv);
832
833     GTK_CONTAINER_CLASS (hildon_window_parent_class)->forall (container, include_internals,
834             callback, callback_data);
835
836     if (include_internals && priv->vbox != NULL)
837         (* callback)(GTK_WIDGET (priv->vbox), callback_data);
838
839     if (include_internals && priv->edit_toolbar != NULL)
840         (* callback)(GTK_WIDGET (priv->edit_toolbar), callback_data);
841 }
842
843 static void
844 hildon_window_show_all                          (GtkWidget *widget)
845 {
846     HildonWindow *self = HILDON_WINDOW (widget);
847     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
848
849     g_assert (priv != NULL);
850
851     GTK_WIDGET_CLASS (hildon_window_parent_class)->show_all (widget);
852
853     gtk_widget_show_all (priv->vbox);
854
855     if (priv->edit_toolbar)
856         gtk_widget_show_all (priv->edit_toolbar);
857 }
858
859 static void
860 hildon_window_destroy                           (GtkObject *obj)
861 {
862     HildonWindow *self = HILDON_WINDOW (obj);
863     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (obj);
864     GList *menu_list = NULL;
865     GList *menu_node = NULL;
866
867     g_assert (priv != NULL);
868
869     if (priv->vbox != NULL)
870     {
871         if (priv->program)
872         {
873             GtkWidget * common_toolbar = 
874                 GTK_WIDGET (hildon_program_get_common_toolbar (priv->program));
875             if (common_toolbar && common_toolbar->parent == priv->vbox)
876             {
877                 gtk_container_remove (GTK_CONTAINER (priv->vbox),
878                         common_toolbar);
879             }
880         }
881
882         gtk_widget_unparent (priv->vbox);
883         priv->vbox = NULL;    
884
885     }
886
887     if (priv->edit_toolbar != NULL)
888     {
889         gtk_widget_unparent (priv->edit_toolbar);
890         priv->edit_toolbar = NULL;
891     }
892
893     if (priv->app_menu)
894     {
895         hildon_app_menu_set_parent_window (priv->app_menu, NULL);
896         g_object_unref (priv->app_menu);
897         priv->app_menu = NULL;
898     }
899
900     menu_list = g_list_copy (gtk_menu_get_for_attach_widget (GTK_WIDGET (obj)));
901     menu_node = menu_list;
902
903     while (menu_node)
904     {
905         if (GTK_IS_MENU (menu_node->data))
906         {
907             if (GTK_WIDGET_VISIBLE (GTK_WIDGET (menu_node->data)))
908             {
909                 gtk_menu_popdown (GTK_MENU (menu_node->data));
910                 gtk_menu_shell_deactivate (GTK_MENU_SHELL (menu_node->data));
911             }
912             gtk_menu_detach (GTK_MENU (menu_node->data));
913
914             /* Destroy it, but only if it's not a common menu */
915             if (priv->program && 
916                 hildon_program_get_common_menu (priv->program) != menu_node->data) {
917                     gtk_object_destroy (GTK_OBJECT (menu_node->data));
918                     g_object_unref (menu_node->data);
919             }
920         }
921         menu_node = menu_node->next;
922     }
923
924     g_list_free (menu_list);
925     menu_list = NULL;
926
927     if (priv->program)
928     {
929         hildon_program_remove_window (priv->program, self);
930     }
931
932     gdk_window_remove_filter (gdk_get_default_root_window(), 
933             hildon_window_root_window_event_filter,
934             obj);
935
936     gtk_widget_set_events (GTK_WIDGET(obj), 0);
937
938     GTK_OBJECT_CLASS (hildon_window_parent_class)->destroy (obj);
939 }
940
941 static void
942 hildon_window_notify                            (GObject *gobject, 
943                                                  GParamSpec *param)
944 {
945     HildonWindow *window = HILDON_WINDOW (gobject);
946
947     if (g_str_equal (param->name, "is-topmost"))
948     {
949         hildon_window_is_topmost_notify (window);
950     }
951
952     if (G_OBJECT_CLASS(hildon_window_parent_class)->notify)
953         G_OBJECT_CLASS(hildon_window_parent_class)->notify (gobject, param);
954 }
955
956
957 static void
958 visible_toolbar                                 (gpointer data, 
959                                                  gpointer user_data)
960 {
961     if (GTK_WIDGET_VISIBLE (((GtkBoxChild *)data)->widget))
962         (*((gint *)user_data))++;
963 }
964
965 static void
966 paint_toolbar                                   (GtkWidget *widget, 
967                                                  GtkBox *box, 
968                                                  GdkEventExpose * event, 
969                                                  gboolean fullscreen)
970 {
971     gint toolbar_num = 0; 
972     gint count;
973
974     /* collect info to help on painting the boxes */
975     g_list_foreach (box->children, visible_toolbar, 
976             (gpointer) &toolbar_num);
977
978     if(toolbar_num <= 0)
979         return;
980
981     /*top most toolbar painting*/
982     gtk_paint_box (widget->style, widget->window,
983             GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
984             &event->area, widget, "toolbar-primary",
985             widget->allocation.x,
986             GTK_WIDGET(box)->allocation.y,
987             widget->allocation.width,
988             TOOLBAR_HEIGHT);
989
990     /*multi toolbar painting*/
991     for (count = 0; count < toolbar_num - 1; count++)
992     {
993             gtk_paint_box (widget->style, widget->window,
994                            GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
995                            &event->area, widget, "toolbar-secondary",
996                            widget->allocation.x,
997                            GTK_WIDGET(box)->allocation.y +
998                            (1 + count) * (TOOLBAR_HEIGHT),
999                            widget->allocation.width,
1000                            TOOLBAR_HEIGHT);
1001     }
1002 }
1003
1004 static void
1005 paint_edit_toolbar                              (GtkWidget *widget,
1006                                                  GtkWidget *toolbar,
1007                                                  GdkEventExpose *event,
1008                                                  gboolean fullscreen)
1009 {
1010     if (!GTK_WIDGET_VISIBLE (toolbar))
1011         return;
1012
1013     gtk_paint_box (widget->style, widget->window,
1014                    GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT,
1015                    &event->area, widget, "toolbar-edit-mode",
1016                    toolbar->allocation.x,
1017                    toolbar->allocation.y,
1018                    toolbar->allocation.width,
1019                    toolbar->allocation.height);
1020 }
1021
1022 /*
1023  * Checks the root window to know which is the topped window
1024  */
1025 Window
1026 hildon_window_get_active_window                 (void)
1027 {
1028     Atom realtype;
1029     gint xerror;
1030     int format;
1031     int status;
1032     Window ret;
1033     unsigned long n;
1034     unsigned long extra;
1035     union
1036     {
1037         Window *win;
1038         unsigned char *char_pointer;
1039     } win;
1040     Atom active_app_atom = 
1041         XInternAtom (GDK_DISPLAY (), "_MB_CURRENT_APP_WINDOW", False);
1042
1043     win.win = NULL;
1044
1045     gdk_error_trap_push ();
1046     status = XGetWindowProperty (GDK_DISPLAY(), GDK_ROOT_WINDOW(),
1047             active_app_atom, 0L, 16L,
1048             0, XA_WINDOW, &realtype, &format,
1049             &n, &extra, &win.char_pointer);
1050     xerror = gdk_error_trap_pop ();
1051     if (xerror || !(status == Success && realtype == XA_WINDOW && format == 32
1052                 && n == 1 && win.win != NULL))
1053     {
1054         if (win.win != NULL)
1055             XFree (win.char_pointer);
1056         return None;
1057     }
1058
1059     ret = win.win[0];
1060
1061     if (win.win != NULL)
1062         XFree(win.char_pointer);
1063
1064     return ret;
1065 }
1066
1067 static int
1068 xclient_message_type_check                      (XClientMessageEvent *cm, 
1069                                                  const gchar *name)
1070 {
1071     return cm->message_type == XInternAtom(GDK_DISPLAY(), name, FALSE);
1072 }
1073
1074 /*
1075  * Handle the window border custom button, which toggles the menu,
1076  * and the Hildon input method copy paste messages
1077  */
1078 static GdkFilterReturn
1079 hildon_window_event_filter                      (GdkXEvent *xevent, 
1080                                                  GdkEvent *event, 
1081                                                  gpointer data)
1082 {
1083     XAnyEvent *eventti = xevent;
1084
1085     if (eventti->type == ClientMessage)
1086     {
1087         XClientMessageEvent *cm = xevent;
1088
1089         if (xclient_message_type_check (cm, "_MB_GRAB_TRANSFER"))
1090         {
1091             hildon_window_toggle_menu (HILDON_WINDOW ( data ), cm->data.l[2], cm->data.l[0]);
1092             return GDK_FILTER_REMOVE;
1093         }
1094         /* opera hack clipboard client message */
1095         else if (xclient_message_type_check (cm, "_HILDON_IM_CLIPBOARD_COPY"))
1096         {
1097             g_signal_emit_by_name(G_OBJECT(data), "clipboard_operation",
1098                     HILDON_WINDOW_CO_COPY);
1099             return GDK_FILTER_REMOVE;
1100         }
1101         else if (xclient_message_type_check(cm, "_HILDON_IM_CLIPBOARD_CUT"))
1102         {
1103             g_signal_emit_by_name(G_OBJECT(data), "clipboard_operation",
1104                     HILDON_WINDOW_CO_CUT);
1105             return GDK_FILTER_REMOVE;
1106         }
1107         else if (xclient_message_type_check(cm, "_HILDON_IM_CLIPBOARD_PASTE"))
1108         {
1109             g_signal_emit_by_name(G_OBJECT(data), "clipboard_operation",
1110                     HILDON_WINDOW_CO_PASTE);
1111             return GDK_FILTER_REMOVE;
1112         }
1113     }
1114
1115     return GDK_FILTER_CONTINUE;
1116 }
1117
1118 /*
1119  * Here we keep track of changes in the _MB_CURRENT_APP_WINDOW,
1120  * to know when we acquire/lose topmost status
1121  */
1122 static GdkFilterReturn
1123 hildon_window_root_window_event_filter          (GdkXEvent *xevent, 
1124                                                  GdkEvent *event, 
1125                                                  gpointer data)
1126 {
1127     XAnyEvent *eventti = xevent;
1128     HildonWindow *hwindow = HILDON_WINDOW (data);
1129
1130     if (eventti->type == PropertyNotify)
1131     {
1132         XPropertyEvent *pevent = xevent;
1133         Atom active_app_atom = 
1134             XInternAtom (GDK_DISPLAY (), "_MB_CURRENT_APP_WINDOW", False);
1135
1136         if (pevent->atom == active_app_atom)
1137         {
1138             Window active_window = hildon_window_get_active_window();
1139
1140             hildon_window_update_topmost (hwindow, active_window);
1141         }
1142     }
1143
1144     return GDK_FILTER_CONTINUE;
1145 }
1146
1147 /*
1148  * Handle the menu hardware key here
1149  */
1150 static gboolean
1151 hildon_window_key_press_event                   (GtkWidget *widget, 
1152                                                  GdkEventKey *event)
1153 {
1154     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
1155
1156     g_return_val_if_fail (HILDON_IS_WINDOW (widget),FALSE);
1157     g_assert (priv);
1158
1159     switch (event->keyval)
1160     {
1161         case HILDON_HARDKEY_MENU:
1162             if (hildon_window_toggle_menu (HILDON_WINDOW (widget), 0, GDK_CURRENT_TIME))
1163                 return TRUE;
1164             break;
1165         case HILDON_HARDKEY_ESC:
1166             if (!priv->escape_timeout)
1167             {
1168                 priv->escape_timeout = gdk_threads_add_timeout
1169                     (HILDON_WINDOW_LONG_PRESS_TIME,
1170                      hildon_window_escape_timeout, widget);
1171             }
1172             break;
1173     }
1174
1175     return GTK_WIDGET_CLASS (hildon_window_parent_class)->key_press_event (widget, event);
1176 }
1177
1178 static gboolean
1179 hildon_window_key_release_event                 (GtkWidget *widget, 
1180                                                  GdkEventKey *event)
1181 {
1182     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
1183
1184     g_return_val_if_fail (HILDON_IS_WINDOW (widget), FALSE);
1185     g_assert (priv);
1186
1187     switch (event->keyval)
1188     {
1189         case HILDON_HARDKEY_ESC:
1190             if (priv->escape_timeout)
1191             {
1192                 g_source_remove (priv->escape_timeout);
1193                 priv->escape_timeout = 0;
1194             }
1195             break;
1196     }
1197
1198     return GTK_WIDGET_CLASS (hildon_window_parent_class)->key_release_event (widget, event);
1199
1200 }
1201
1202 /*
1203  * We keep track of the window state changes, because the drawing
1204  * (borders) differs whether we are in fullscreen mode or not
1205  */
1206 static gboolean
1207 hildon_window_window_state_event                (GtkWidget *widget, 
1208                                                  GdkEventWindowState *event)
1209 {
1210     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
1211     g_assert (priv != NULL);
1212
1213     if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
1214         priv->fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN;
1215
1216     if (GTK_WIDGET_CLASS (hildon_window_parent_class)->window_state_event)
1217     {
1218         return GTK_WIDGET_CLASS (hildon_window_parent_class)->window_state_event (
1219                 widget,
1220                 event);
1221     }
1222     else
1223     {
1224         return FALSE;
1225     }
1226 }
1227
1228 /*
1229  * If the window lost focus while the user started to press the ESC key, we
1230  * won't get the release event. We need to stop the timeout.
1231  */
1232 static gboolean
1233 hildon_window_focus_out_event                   (GtkWidget *widget, 
1234                                                  GdkEventFocus *event)
1235 {
1236   HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
1237
1238   if (priv->escape_timeout)
1239   {
1240       g_source_remove (priv->escape_timeout);
1241       priv->escape_timeout = 0;
1242   }
1243
1244   return GTK_WIDGET_CLASS (hildon_window_parent_class)->focus_out_event (widget, event);
1245 }
1246
1247 static void
1248 set_legacy_menu_type                            (GtkMenu  *menu,
1249                                                  gboolean  set)
1250 {
1251     GdkWindow *gdkwin = GTK_WIDGET (menu->toplevel)->window;
1252     GdkAtom property = gdk_atom_intern_static_string (LEGACY_MENU_PROPERTY_NAME);
1253     if (set) {
1254         GdkAtom type = gdk_x11_xatom_to_atom (XA_ATOM);
1255         GdkAtom value = gdk_atom_intern_static_string (LEGACY_MENU_PROPERTY_VALUE);
1256         gdk_property_change (gdkwin, property, type, 32,
1257                              GDK_PROP_MODE_REPLACE, (const guchar *) &value, 1);
1258     } else {
1259         gdk_property_delete (gdkwin, property);
1260     }
1261 }
1262
1263 static void
1264 legacy_menu_realized                            (GtkMenu *menu)
1265 {
1266     set_legacy_menu_type (menu, TRUE);
1267     g_signal_handlers_disconnect_by_func (menu, legacy_menu_realized, NULL);
1268 }
1269
1270 static void
1271 legacy_menu_unmapped                            (GtkMenu *menu)
1272 {
1273     set_legacy_menu_type (menu, FALSE);
1274     g_signal_handlers_disconnect_by_func (menu, legacy_menu_unmapped, NULL);
1275 }
1276
1277 /*
1278  * The menu popuping needs a menu popup-function
1279  */
1280 static void
1281 hildon_window_menu_popup_func                   (GtkMenu *menu, 
1282                                                  gint *x, 
1283                                                  gint *y,
1284                                                  gboolean *push_in, 
1285                                                  GtkWidget *widget)
1286 {
1287     gint window_x = 0;
1288     gint window_y = 0;
1289     GdkWindow *window = GTK_WIDGET(widget)->window;
1290
1291     if (window)
1292     {
1293         gdk_window_get_origin (window, &window_x, &window_y);
1294     }
1295
1296     gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
1297             "vertical-offset", y, NULL);
1298
1299     if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1300     {
1301         *x = GTK_WIDGET (widget)->allocation.width + window_x - GTK_WIDGET (menu)->allocation.width - *x;
1302     }
1303     else
1304         *x += window_x;
1305
1306     *y += window_y;
1307
1308 }
1309
1310 static void
1311 hildon_window_menu_popup_func_full              (GtkMenu *menu, 
1312                                                  gint *x, 
1313                                                  gint *y,
1314                                                  gboolean *push_in, 
1315                                                  GtkWidget *widget)
1316 {
1317     gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
1318             "vertical-offset", y, NULL);
1319
1320     if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
1321         *x = GTK_WIDGET (widget)->allocation.width - GTK_WIDGET (menu)->allocation.width - *x;
1322     else
1323         *x = MAX (0, *x);
1324
1325     *y = MAX (0, *y);
1326 }
1327
1328
1329 /*
1330  * Takes the common toolbar when we acquire the top-most status
1331  */
1332 static void
1333 hildon_window_is_topmost_notify                 (HildonWindow *window)
1334 {
1335     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (window);
1336
1337     g_assert (priv);
1338
1339     if (priv->is_topmost)
1340     {
1341         hildon_window_take_common_toolbar (window);
1342     }
1343 }
1344
1345 /*
1346  * Sets the program to which the window belongs. This should only be called
1347  * by hildon_program_add_window
1348  */
1349 void G_GNUC_INTERNAL
1350 hildon_window_set_program                       (HildonWindow *self, 
1351                                                  GObject *program)
1352 {
1353     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1354
1355     g_return_if_fail (HILDON_IS_WINDOW (self));
1356     g_assert (priv != NULL);
1357
1358     if (priv->program)
1359     {
1360         g_object_unref (priv->program);
1361     }
1362
1363     /* Now that we are bound to a program, we can rely on it to track the
1364      * root window */
1365     gdk_window_remove_filter (gdk_get_default_root_window(), 
1366             hildon_window_root_window_event_filter,
1367             self);
1368
1369     priv->program = HILDON_PROGRAM (program);
1370     g_object_ref (program);
1371 }
1372
1373 /*
1374  * Unsets the program to which the window belongs. This should only be called
1375  * by hildon_program_remove_window
1376  */
1377 void G_GNUC_INTERNAL
1378 hildon_window_unset_program                     (HildonWindow *self)
1379 {
1380     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1381
1382     g_return_if_fail(HILDON_IS_WINDOW (self));
1383     g_assert (priv != NULL);
1384
1385     if (priv->program)
1386     {
1387         g_object_unref (priv->program);
1388         priv->program = NULL;
1389
1390         /* We need to start tacking the root window again */
1391         gdk_window_set_events (gdk_get_default_root_window (),
1392                 gdk_window_get_events (gdk_get_default_root_window ())
1393                 | GDK_PROPERTY_CHANGE_MASK);
1394
1395         gdk_window_add_filter (gdk_get_default_root_window (),
1396                 hildon_window_root_window_event_filter, self );
1397     }
1398
1399     priv->program = NULL;
1400 }
1401
1402 /*
1403  * Sets whether or not the program to which this window belongs is
1404  * killable. This is used by the HildonProgram to signify to the
1405  * Task Navigator whether or not it can hibernate in memory-low situations
1406  **/    
1407 void G_GNUC_INTERNAL
1408 hildon_window_set_can_hibernate_property        (HildonWindow *self, 
1409                                                  gpointer _can_hibernate)
1410 {
1411     GdkAtom killable_atom;
1412     gboolean can_hibernate;
1413
1414     g_return_if_fail(self && HILDON_IS_WINDOW (self));
1415
1416     if (!GTK_WIDGET_REALIZED ((GTK_WIDGET (self))))
1417     {
1418         return;
1419     }
1420
1421     can_hibernate = * ((gboolean *)_can_hibernate);
1422
1423     killable_atom = gdk_atom_intern (CAN_HIBERNATE_PROPERTY, FALSE);
1424
1425     if (can_hibernate)
1426     {
1427         gdk_property_change (GTK_WIDGET (self)->window, killable_atom,
1428                 (GdkAtom)31/* XA_STRING */, 8,
1429                 GDK_PROP_MODE_REPLACE, (const guchar *)CAN_HIBERNATE,
1430                 CAN_HIBERNATE_LENGTH);
1431     }
1432     else
1433     {
1434         gdk_property_delete (GTK_WIDGET (self)->window, killable_atom);
1435     }
1436
1437 }
1438
1439 /*
1440  * If a common toolbar was set to the program, reparent it to
1441  * us
1442  */
1443 void G_GNUC_INTERNAL
1444 hildon_window_take_common_toolbar               (HildonWindow *self)
1445 {
1446     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1447
1448     g_return_if_fail(HILDON_IS_WINDOW (self));
1449     g_assert (priv);
1450
1451     if (priv->program)
1452     {
1453         GtkWidget *common_toolbar =  
1454             GTK_WIDGET (hildon_program_get_common_toolbar (priv->program));
1455
1456         if (common_toolbar && common_toolbar->parent != priv->vbox)
1457         {
1458             g_object_ref (common_toolbar);
1459             if (common_toolbar->parent)
1460             {
1461                 gtk_container_remove (GTK_CONTAINER (common_toolbar->parent),
1462                         common_toolbar);
1463             }
1464
1465             gtk_box_pack_end (GTK_BOX(priv->vbox), common_toolbar,
1466                     TRUE, TRUE, 0);
1467             g_object_unref (common_toolbar);
1468
1469             gtk_widget_set_size_request (common_toolbar, -1, TOOLBAR_HEIGHT);
1470
1471             gtk_widget_show  (priv->vbox);
1472
1473         }
1474     }
1475 }
1476
1477 /*
1478  * Compare the window that was last topped, and act consequently
1479  */
1480 void
1481 hildon_window_update_topmost                    (HildonWindow *self, 
1482                                                  Window window_id)
1483 {
1484     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1485
1486     GdkWindow *my_window;
1487
1488     g_return_if_fail (HILDON_IS_WINDOW (self));
1489     g_assert (priv);
1490
1491     my_window = GTK_WIDGET (self)->window;
1492
1493     if (my_window && window_id == GDK_WINDOW_XID (my_window))
1494     {
1495         if (! priv->is_topmost)
1496         {
1497             priv->is_topmost = TRUE;
1498             hildon_window_is_topmost_notify (self);
1499             g_object_notify (G_OBJECT (self), "is-topmost");
1500         }
1501     }
1502     else if (priv->is_topmost)
1503     {
1504         /* Should this go in the signal handler? */
1505         GtkWidget *focus = gtk_window_get_focus (GTK_WINDOW (self));
1506
1507         if (GTK_IS_ENTRY (focus))
1508             gtk_im_context_focus_out (GTK_ENTRY (focus)->im_context);
1509         if (GTK_IS_TEXT_VIEW (focus))
1510             gtk_im_context_focus_out (GTK_TEXT_VIEW (focus)->im_context);
1511
1512         priv->is_topmost = FALSE;
1513         hildon_window_is_topmost_notify (self);
1514         g_object_notify (G_OBJECT (self), "is-topmost");
1515     }
1516 }
1517
1518 static void
1519 detach_menu_func                                (GtkWidget *attach_widget, 
1520                                                  GtkMenu *menu)
1521 {
1522     /* FIXME Why is this even needed here? */
1523 }
1524
1525 static gboolean
1526 hildon_window_toggle_menu                       (HildonWindow *self,
1527                                                  guint button,
1528                                                  guint32 time)
1529 {
1530     g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
1531
1532     if (HILDON_WINDOW_GET_CLASS (self)->toggle_menu != NULL)
1533     {
1534         return HILDON_WINDOW_GET_CLASS (self)->toggle_menu (self, button, time);
1535     }
1536     else
1537     {
1538         return FALSE;
1539     }
1540 }
1541
1542
1543 static gboolean
1544 hildon_window_toggle_gtk_menu                   (HildonWindow *self,
1545                                                  GtkMenu      *menu,
1546                                                  guint         button,
1547                                                  guint32       time)
1548 {
1549     gboolean retvalue = FALSE;
1550
1551     g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
1552     g_return_val_if_fail (GTK_IS_MENU (menu), FALSE);
1553
1554     if (gtk_menu_get_attach_widget (menu) != GTK_WIDGET (self))
1555     {
1556         g_object_ref (menu);
1557         if (gtk_menu_get_attach_widget (menu))
1558         {
1559             gtk_menu_detach (menu);
1560         }
1561         gtk_menu_attach_to_widget (menu, GTK_WIDGET (self), &detach_menu_func);
1562         g_object_unref (menu);
1563     }
1564
1565     if (GTK_WIDGET_MAPPED (menu))
1566     {
1567         gtk_menu_popdown (menu);
1568         gtk_menu_shell_deactivate (GTK_MENU_SHELL (menu));
1569         retvalue = TRUE;
1570     }
1571     else
1572     {
1573         /* Check if the menu has items */
1574         GList *menu_children = gtk_container_get_children (GTK_CONTAINER (menu));
1575
1576         if (menu_children)
1577         {
1578             HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1579             g_list_free (menu_children);
1580
1581             /* Set the 'legacy app menu' property when the widget is realized */
1582             if (GTK_WIDGET_REALIZED (menu)) {
1583                 set_legacy_menu_type (menu, TRUE);
1584             } else {
1585                 g_signal_connect (menu, "realize",
1586                                   G_CALLBACK (legacy_menu_realized), NULL);
1587             }
1588
1589             /* Remove it when it's unmapped */
1590             g_signal_connect (menu, "unmap",
1591                               G_CALLBACK (legacy_menu_unmapped), NULL);
1592
1593             /* Apply right theming */
1594             gtk_widget_set_name (GTK_WIDGET (menu), "menu_force_with_corners");
1595
1596             if (priv->fullscreen)
1597             {
1598                 gtk_menu_popup (menu, NULL, NULL,
1599                                 (GtkMenuPositionFunc)
1600                                 hildon_window_menu_popup_func_full,
1601                                 self, button, time);
1602             }
1603             else
1604             {
1605                 gtk_menu_popup (menu, NULL, NULL,
1606                                 (GtkMenuPositionFunc)
1607                                 hildon_window_menu_popup_func,
1608                                 self, button, time);
1609             }
1610             gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), TRUE);
1611             retvalue = TRUE;
1612         }
1613     }
1614
1615     return retvalue;
1616 }
1617
1618 static gboolean
1619 hildon_window_toggle_app_menu                   (HildonWindow  *self,
1620                                                  HildonAppMenu *menu)
1621 {
1622     g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
1623     g_return_val_if_fail (HILDON_IS_APP_MENU (menu), FALSE);
1624
1625     if (self != hildon_app_menu_get_parent_window (menu))
1626     {
1627         gtk_widget_hide (GTK_WIDGET (menu));
1628     }
1629
1630     if (GTK_WIDGET_MAPPED (menu))
1631     {
1632         gtk_widget_hide (GTK_WIDGET (menu));
1633     }
1634     else
1635     {
1636         hildon_app_menu_popup (menu, GTK_WINDOW (self));
1637     }
1638
1639     return TRUE;
1640 }
1641
1642 /*
1643  * Toggles the display of the HildonWindow menu.
1644  * Returns whether or not something was done (whether or not we had a menu
1645  * to toggle)
1646  */
1647 static gboolean
1648 hildon_window_toggle_menu_real                  (HildonWindow * self,
1649                                                  guint button,
1650                                                  guint32 time)
1651 {
1652     gboolean retvalue = FALSE;
1653     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
1654
1655     g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
1656
1657     /* Select which menu to use, Window specific has highest priority,
1658      * then program specific */
1659     if (priv->menu)
1660     {
1661         retvalue = hildon_window_toggle_gtk_menu (self, priv->menu, button, time);
1662     }
1663     else if (priv->app_menu)
1664     {
1665         retvalue = hildon_window_toggle_app_menu (self, priv->app_menu);
1666     }
1667     else if (priv->program)
1668     {
1669         GtkMenu *gtkmenu = hildon_program_get_common_menu (priv->program);
1670         HildonAppMenu *appmenu = hildon_program_get_common_app_menu (priv->program);
1671
1672         if (gtkmenu)
1673         {
1674             retvalue = hildon_window_toggle_gtk_menu (self, gtkmenu, button, time);
1675         }
1676         else if (appmenu)
1677         {
1678             retvalue = hildon_window_toggle_app_menu (self, appmenu);
1679         }
1680     }
1681
1682     return retvalue;
1683 }
1684
1685 /*
1686  * If the ESC key was not released when the timeout expires,
1687  * close the window
1688  */
1689 static gboolean
1690 hildon_window_escape_timeout                    (gpointer data)
1691 {
1692     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (data);
1693     GdkEvent *event;
1694
1695     g_assert (priv);
1696
1697     /* Send fake event, simulation a situation that user
1698        pressed 'x' from the corner */
1699     event = gdk_event_new(GDK_DELETE);
1700     ((GdkEventAny *)event)->window = GDK_WINDOW (g_object_ref (GTK_WIDGET(data)->window));
1701     gtk_main_do_event(event);
1702
1703     /* That unrefs the window, so we're reffing it above */
1704     gdk_event_free(event);
1705
1706     priv->escape_timeout = 0;
1707
1708     return FALSE;
1709 }
1710
1711 /**
1712  * hildon_window_new: 
1713  * 
1714  * Creates a new #HildonWindow.
1715  * 
1716  * Return value: A #HildonWindow.
1717  **/
1718 GtkWidget*
1719 hildon_window_new                               (void)
1720 {
1721     HildonWindow *newwindow = g_object_new (HILDON_TYPE_WINDOW, NULL);
1722
1723     return GTK_WIDGET (newwindow);
1724 }
1725
1726 /**
1727  * hildon_window_add_with_scrollbar:
1728  * @self: A #HildonWindow
1729  * @child: A #GtkWidget
1730  *
1731  * Adds @child to the #HildonWindow and creates a scrollbar for
1732  * it. Similar to adding first a #GtkScrolledWindow and then @child to
1733  * it.
1734  */
1735 void
1736 hildon_window_add_with_scrollbar                (HildonWindow *self,
1737                                                  GtkWidget *child)
1738 {
1739     GtkScrolledWindow *scrolledw;
1740
1741     g_return_if_fail (HILDON_IS_WINDOW (self));
1742     g_return_if_fail (GTK_IS_WIDGET (child));
1743     g_return_if_fail (child->parent == NULL);
1744
1745     scrolledw = GTK_SCROLLED_WINDOW (gtk_scrolled_window_new (NULL, NULL));
1746     gtk_scrolled_window_set_policy (scrolledw, GTK_POLICY_NEVER,
1747             GTK_POLICY_AUTOMATIC);
1748     gtk_scrolled_window_set_shadow_type (scrolledw, GTK_SHADOW_NONE);
1749
1750     if (GTK_IS_VIEWPORT (child))
1751         gtk_container_add (GTK_CONTAINER (scrolledw), child);
1752     else
1753     {
1754         if (GTK_IS_CONTAINER (child) )
1755             gtk_container_set_focus_vadjustment (GTK_CONTAINER(child),
1756                     gtk_scrolled_window_get_vadjustment (scrolledw) );
1757         gtk_scrolled_window_add_with_viewport (scrolledw, child);
1758     }
1759
1760     gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (scrolledw));
1761 }
1762
1763 static void
1764 calculate_visible_toolbars                      (gpointer data,
1765                                                  gpointer user_data)
1766 {
1767   if (GTK_WIDGET_VISIBLE (GTK_WIDGET (((GtkBoxChild *)data)->widget)))
1768     (*((gint *)user_data)) ++;
1769 }
1770
1771 static void
1772 toolbar_visible_notify                          (GtkWidget *toolbar, GParamSpec *pspec,
1773                                                  HildonWindow *window)
1774 {
1775   HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (window);
1776
1777   g_assert (priv);
1778
1779   /* Recalculate from scratch the value just in case */
1780   priv->visible_toolbars = 0;
1781
1782   g_list_foreach (GTK_BOX (priv->vbox)->children, calculate_visible_toolbars, 
1783                   &priv->visible_toolbars);
1784
1785   if (priv->visible_toolbars == 0)
1786     gtk_widget_hide (priv->vbox);
1787   else
1788     gtk_widget_show (priv->vbox);
1789 }
1790
1791 /**
1792  * hildon_window_add_toolbar:
1793  * @self: A #HildonWindow
1794  * @toolbar: A #GtkToolbar to add to the #HildonWindow
1795  *
1796  * Adds a toolbar to the window. Note that the toolbar is not automatically
1797  * shown. You need to call gtk_widget_show_all() on it to make it visible.
1798  * It's also possible to hide the toolbar (without removing it) by calling
1799  * gtk_widget_hide()
1800  **/
1801 void 
1802 hildon_window_add_toolbar                       (HildonWindow *self, 
1803                                                  GtkToolbar *toolbar)
1804 {
1805     GtkBox *vbox;
1806     HildonWindowPrivate *priv;
1807
1808     g_return_if_fail (HILDON_IS_WINDOW (self));
1809     g_return_if_fail (toolbar && GTK_IS_TOOLBAR (toolbar));
1810
1811     priv = HILDON_WINDOW_GET_PRIVATE (self);
1812
1813     vbox = GTK_BOX (priv->vbox);
1814
1815     gtk_box_pack_start (vbox, GTK_WIDGET (toolbar), TRUE, TRUE, 0);
1816     gtk_box_reorder_child (vbox, GTK_WIDGET (toolbar), 0);
1817     gtk_widget_set_size_request (GTK_WIDGET (toolbar), -1, TOOLBAR_HEIGHT);
1818
1819     g_signal_connect (G_OBJECT (toolbar), "notify::visible",
1820                       G_CALLBACK (toolbar_visible_notify), self);
1821
1822     if (GTK_WIDGET_VISIBLE (toolbar))
1823       {
1824         priv->visible_toolbars++;
1825         gtk_widget_show (priv->vbox);
1826       }
1827
1828     gtk_widget_queue_resize (GTK_WIDGET (self));
1829 }
1830
1831 /**
1832  * hildon_window_remove_toolbar:
1833  * @self: A #HildonWindow
1834  * @toolbar: A #GtkToolbar to remove from the #HildonWindow
1835  *
1836  * Removes a toolbar from the window. Note that this decreases the refference
1837  * count on the widget. If you want to keep the toolbar alive call g_object_ref()
1838  * before calling this function.
1839  **/
1840 void
1841 hildon_window_remove_toolbar                    (HildonWindow *self, 
1842                                                  GtkToolbar *toolbar)
1843 {
1844     HildonWindowPrivate *priv;
1845
1846     g_return_if_fail (HILDON_IS_WINDOW (self));
1847     
1848     priv = HILDON_WINDOW_GET_PRIVATE (self);
1849
1850     if (GTK_WIDGET_VISIBLE (toolbar))
1851       {
1852         if (--(priv->visible_toolbars) == 0)
1853           gtk_widget_hide (priv->vbox);
1854       }
1855
1856     g_signal_handlers_disconnect_by_func (toolbar, toolbar_visible_notify, self);
1857
1858     gtk_container_remove (GTK_CONTAINER (priv->vbox), GTK_WIDGET (toolbar));
1859 }
1860
1861 /**
1862  * hildon_window_set_edit_toolbar:
1863  * @self: A #HildonWindow
1864  * @toolbar: A #HildonEditToolbar, or %NULL to remove the current one.
1865  *
1866  * Adds a #HildonEditToolbar to the window. Note that the toolbar is
1867  * not automatically shown. You need to call gtk_widget_show() on it
1868  * to make it visible. It's also possible to hide the toolbar (without
1869  * removing it) by calling gtk_widget_hide().
1870  *
1871  * A window can only have at most one edit toolbar at a time, so the
1872  * previous toolbar (if any) is replaced after calling this function.
1873  *
1874  * Since: 2.2
1875  **/
1876 void
1877 hildon_window_set_edit_toolbar                  (HildonWindow      *self,
1878                                                  HildonEditToolbar *toolbar)
1879 {
1880     HildonWindowPrivate *priv;
1881
1882     g_return_if_fail (HILDON_IS_WINDOW (self));
1883     g_return_if_fail (toolbar == NULL || HILDON_IS_EDIT_TOOLBAR (toolbar));
1884
1885     priv = HILDON_WINDOW_GET_PRIVATE (self);
1886
1887     if (priv->edit_toolbar != GTK_WIDGET (toolbar))
1888     {
1889         GtkWidget *old_toolbar = priv->edit_toolbar;
1890         priv->edit_toolbar = GTK_WIDGET (toolbar);
1891
1892         if (priv->edit_toolbar)
1893             gtk_widget_set_parent (priv->edit_toolbar, GTK_WIDGET (self));
1894
1895         if (old_toolbar)
1896             gtk_widget_unparent (old_toolbar);
1897     }
1898 }
1899
1900 /**
1901  * hildon_window_get_main_menu:
1902  * @self: a #HildonWindow
1903  *
1904  * Gets the #GtkMenu assigned to the #HildonWindow. Note that the
1905  * window is still the owner of the menu.
1906  *
1907  * Note that if you're using a #HildonAppMenu rather than a #GtkMenu
1908  * you should use hildon_window_get_app_menu() instead.
1909  *
1910  * Return value: The #GtkMenu assigned to this application view. 
1911  *
1912  * Since: 2.2
1913  **/
1914 GtkMenu*
1915 hildon_window_get_main_menu                     (HildonWindow * self)
1916 {
1917     HildonWindowPrivate *priv;
1918
1919     g_return_val_if_fail (HILDON_IS_WINDOW (self), NULL);
1920
1921     priv = HILDON_WINDOW_GET_PRIVATE (self);
1922
1923     return priv->menu;
1924 }
1925
1926 /**
1927  * hildon_window_get_menu:
1928  * @self: a #HildonWindow
1929  *
1930  * Gets the #GtkMenu assigned to @self
1931  *
1932  * Return value: a #GtkMenu
1933  *
1934  * Deprecated: In Hildon 2.2 this function has been renamed to
1935  * hildon_window_get_main_menu() for consistency
1936  **/
1937 GtkMenu*
1938 hildon_window_get_menu                          (HildonWindow * self)
1939 {
1940     return hildon_window_get_main_menu (self);
1941 }
1942
1943 /* Since we've been asking developers to call gtk_window_add_accel_group()
1944  * themselves, do not trigger criticals by trying it again.
1945  */
1946 static void
1947 hildon_window_add_accel_group (HildonWindow *self,
1948                                GtkAccelGroup *accel_group)
1949 {
1950     GSList *groups, *l;
1951
1952     groups = gtk_accel_groups_from_object (G_OBJECT (self));
1953     for (l = groups; l != NULL; l = l->next)
1954       if (l->data == (gpointer)accel_group)
1955         /* Maybe print a warning here? */
1956         return;
1957
1958     gtk_window_add_accel_group (GTK_WINDOW (self), accel_group);
1959 }
1960
1961 /**
1962  * hildon_window_set_main_menu:
1963  * @self: A #HildonWindow
1964  * @menu: The #GtkMenu to be used for this #HildonWindow
1965  *
1966  * Sets the menu to be used for this window. This menu overrides
1967  * a program-wide menu that may have been set with
1968  * hildon_program_set_common_menu(). Pass %NULL to remove the current
1969  * menu. #HildonWindow takes ownership of the passed menu and you're
1970  * not supposed to free it yourself anymore.
1971  *
1972  * Note that if you're using a #HildonAppMenu rather than a #GtkMenu
1973  * you should use hildon_window_set_app_menu() instead.
1974  **/
1975 void
1976 hildon_window_set_main_menu (HildonWindow* self,
1977                              GtkMenu     * menu)
1978 {
1979     HildonWindowPrivate *priv;
1980     GtkAccelGroup *accel_group;
1981
1982     g_return_if_fail (HILDON_IS_WINDOW (self));
1983
1984     priv = HILDON_WINDOW_GET_PRIVATE (self);
1985
1986     if (priv->menu != NULL)
1987     {
1988         accel_group = gtk_menu_get_accel_group (priv->menu);
1989         if (accel_group != NULL)
1990             gtk_window_remove_accel_group (GTK_WINDOW (self), accel_group);
1991
1992         gtk_menu_detach (priv->menu);
1993         g_object_unref (priv->menu);
1994     }
1995
1996     priv->menu = menu;
1997     if (priv->menu != NULL)
1998     {
1999         gtk_widget_set_name (GTK_WIDGET (priv->menu), "menu_force_with_corners");
2000         gtk_menu_attach_to_widget (priv->menu, GTK_WIDGET (self), &detach_menu_func);
2001         g_object_ref (priv->menu);
2002
2003         accel_group = gtk_menu_get_accel_group (priv->menu);
2004         if (accel_group != NULL)
2005             hildon_window_add_accel_group (self, accel_group);
2006     }
2007 }
2008
2009 /**
2010  * hildon_window_set_menu:
2011  * @self: A #HildonWindow
2012  * @menu: The #GtkMenu to be used for this #HildonWindow
2013  *
2014  * Sets the menu to be used for this window. This menu overrides
2015  * a program-wide menu that may have been set with
2016  * hildon_program_set_common_menu(). Pass %NULL to remove the current
2017  * menu. HildonWindow takes ownership of the passed menu and you're
2018  * not supposed to free it yourself anymore.
2019  *
2020  * Note: hildon_window_set_menu() calls gtk_widget_show_all() for the
2021  * #GtkMenu. To pass control about visibility to the application
2022  * developer, hildon_window_set_main_menu() was introduced, which
2023  * doesn't do this.
2024  *
2025  * Deprecated: Hildon 2.2: use hildon_window_set_main_menu()
2026  **/
2027 void
2028 hildon_window_set_menu                          (HildonWindow *self, 
2029                                                  GtkMenu *menu)
2030 {
2031     HildonWindowPrivate *priv;
2032
2033     g_return_if_fail (HILDON_IS_WINDOW (self));
2034
2035     hildon_window_set_main_menu (self, menu);
2036
2037     priv = HILDON_WINDOW_GET_PRIVATE (self);
2038
2039     if (priv->menu != NULL)
2040         gtk_widget_show_all (GTK_WIDGET (priv->menu));
2041 }
2042
2043 /**
2044  * hildon_window_get_is_topmost:
2045  * @self: A #HildonWindow
2046  *
2047  * Returns whether the #HildonWindow is currenty activated by the
2048  * window manager.
2049  *
2050  * Return value: %TRUE if @self is currently activated, %FALSE otherwise.
2051  **/
2052 gboolean
2053 hildon_window_get_is_topmost                    (HildonWindow *self)
2054 {
2055     HildonWindowPrivate *priv;
2056
2057     g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
2058
2059     priv = HILDON_WINDOW_GET_PRIVATE (self);
2060     return priv->is_topmost;
2061 }
2062
2063 /**
2064  * hildon_window_set_app_menu:
2065  * @self: a #HildonWindow
2066  * @menu: a #HildonAppMenu to be used for this window
2067  *
2068  * Sets the menu to be used for this window. Pass %NULL to remove the
2069  * current menu. Any reference to a previous menu will be dropped.
2070  * #HildonWindow takes ownership of the passed menu and
2071  * you're not supposed to free it yourself anymore.
2072  *
2073  * Note that if you're using a #GtkMenu rather than a #HildonAppMenu
2074  * you should use hildon_window_set_main_menu() instead.
2075  *
2076  * Since: 2.2
2077  **/
2078 void
2079 hildon_window_set_app_menu                      (HildonWindow  *self,
2080                                                  HildonAppMenu *menu)
2081 {
2082     HildonWindowPrivate *priv;
2083     HildonAppMenu *old_menu;
2084
2085     g_return_if_fail (HILDON_IS_WINDOW (self));
2086     g_return_if_fail (!menu || HILDON_IS_APP_MENU (menu));
2087     priv = HILDON_WINDOW_GET_PRIVATE (self);
2088
2089     old_menu = priv->app_menu;
2090
2091     /* Add new menu */
2092     priv->app_menu = menu;
2093     if (menu)
2094         g_object_ref_sink (menu);
2095
2096     /* Unref old menu */
2097     if (old_menu)
2098         g_object_unref (old_menu);
2099 }
2100
2101 /**
2102  * hildon_window_get_app_menu:
2103  * @self: a #HildonWindow
2104  *
2105  * Returns the #HildonAppMenu assigned to @self, or %NULL if it's
2106  * unset. Note that the window is still the owner of the menu.
2107  *
2108  * Note that if you're using a #GtkMenu rather than a #HildonAppMenu
2109  * you should use hildon_window_get_main_menu() instead.
2110  *
2111  * Returns: a #HildonAppMenu
2112  *
2113  * Since: 2.2
2114  **/
2115 HildonAppMenu *
2116 hildon_window_get_app_menu                      (HildonWindow *self)
2117 {
2118     HildonWindowPrivate *priv;
2119
2120     g_return_val_if_fail (HILDON_IS_WINDOW (self), NULL);
2121
2122     priv = HILDON_WINDOW_GET_PRIVATE (self);
2123
2124     return priv->app_menu;
2125 }
2126
2127 static void
2128 hildon_window_update_markup                     (HildonWindow *window)
2129 {
2130     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (window);
2131     GdkAtom markup_atom = gdk_atom_intern ("_HILDON_WM_NAME", FALSE);
2132     GdkAtom utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE);
2133     GdkWindow *gdkwin = GTK_WIDGET (window)->window;
2134
2135     if (priv->markup) {
2136         gdk_property_change (gdkwin, markup_atom, utf8_atom, 8,
2137                              GDK_PROP_MODE_REPLACE, (const guchar *) priv->markup,
2138                              strlen (priv->markup));
2139     } else {
2140         gdk_property_delete (gdkwin, markup_atom);
2141     }
2142 }
2143
2144 /**
2145  * hildon_window_get_markup:
2146  * @window: a #HildonWindow
2147  *
2148  * Gets the marked up title of the window title. See hildon_window_set_markup()
2149  *
2150  * Returns: the marked up title of the window, or %NULL if none has
2151  * been set explicitely. The returned string is owned by the widget
2152  * and must not be modified or freed.
2153  *
2154  * Since: 2.2
2155  **/
2156 const gchar *
2157 hildon_window_get_markup                        (HildonWindow *window)
2158 {
2159     HildonWindowPrivate *priv;
2160
2161     g_return_val_if_fail (HILDON_IS_WINDOW (window), NULL);
2162
2163     priv = HILDON_WINDOW_GET_PRIVATE (window);
2164
2165     return priv->markup;
2166 }
2167
2168 /**
2169  * hildon_window_set_markup:
2170  * @window: a #HildonWindow
2171  * @markup: the marked up title of the window, or %NULL to unset the
2172  * current one
2173  *
2174  * Sets the marked up title of @window. The accepted format is the one
2175  * used in Pango (see #PangoMarkupFormat) with the exception of
2176  * &lt;span&gt;.
2177  *
2178  * Note that you need support from the window manager for this title
2179  * to be used. See gtk_window_set_title() for the standard way of
2180  * setting the title of a window.
2181  *
2182  * Since: 2.2
2183  **/
2184 void
2185 hildon_window_set_markup                        (HildonWindow *window,
2186                                                  const gchar  *markup)
2187 {
2188     HildonWindowPrivate *priv;
2189     gchar *new_markup;
2190
2191     g_return_if_fail (HILDON_IS_WINDOW (window));
2192
2193     priv = HILDON_WINDOW_GET_PRIVATE (window);
2194
2195     new_markup = g_strdup (markup);
2196     g_free (priv->markup);
2197     priv->markup = new_markup;
2198
2199     if (GTK_WIDGET_REALIZED (window))
2200         hildon_window_update_markup (window);
2201
2202     g_object_notify (G_OBJECT (window), "markup");
2203 }