2009-04-01 Alberto Garcia <agarcia@igalia.com>
[hildon] / src / hildon-window.c
index bb63e57..73ef13f 100644 (file)
@@ -3,12 +3,12 @@
  *
  * Copyright (C) 2006 Nokia Corporation, all rights reserved.
  *
- * Contact: Michael Dominic Kostrzewa <michael.kostrzewa@nokia.com>
+ * Contact: Rodrigo Novo <rodrigo.novo@nokia.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
  * as published by the Free Software Foundation; version 2.1 of
- * the License.
+ * the License, or (at your option) any later version.
  *
  * This library is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
 /**
  * SECTION:hildon-window
  * @short_description: Widget representing a top-level window in the Hildon framework.
+ * @see_also: #HildonProgram, #HildonStackableWindow
  *
- * The HildonWindow is a GTK widget which represents a top-level
- * window in the Hildon framework. It is derived from the GtkWindow
+ * #HildonWindow is a GTK widget which represents a top-level
+ * window in the Hildon framework. It is derived from #GtkWindow
  * and provides additional commodities specific to the Hildon
  * framework.
-
- * Among these windows in the Hildon framework can have a single menu
- * attached, which is toggled with a hardware key or by tapping
- * a custom button in the window frame. This menu can be set
- * by providing a GtkMenu to the hildon_window_set_menu() method.
-
- * Similarly a window in the Hildon framework can have several toolbars
- * attached. These can be added to the HildonWindow with
- * hildon_window_add_toolbar()..
- * 
+ *
+ * #HildonWindow<!-- -->s can have a menu attached, which is toggled
+ * with a hardware key or by tapping on the window frame. This menu
+ * can be either a #GtkMenu or a #HildonAppMenu (set with
+ * hildon_window_set_main_menu() and hildon_window_set_app_menu()
+ * respectively). Only one type of menu can be used at the same time.
+ * In Hildon 2.2, #HildonAppMenu is the recommended menu to use.
+ *
+ * Similarly, a #HildonWindow can have several toolbars
+ * attached. These can be added with hildon_window_add_toolbar(). In
+ * addition to those, a #HildonWindow can also have a
+ * #HildonEditToolbar. To add it to the window use
+ * hildon_window_set_edit_toolbar().
+ *
  * <example>
  * <title>Creating a HildonWindow</title>
  * <programlisting>
  * HildonWindow *window;
  * GtkToolbar *toolbar;
- * GtkMenu *menu;
+ * HildonAppMenu *menu;
  * GdkPixbuf *icon_pixbuf;
  * <!-- -->
  * window = HILDON_WINDOW (hildon_window_new());
@@ -56,7 +61,7 @@
  * <!-- -->
  * icon_pixbuf = create_icon();
  * <!-- -->
- * hildon_window_set_menu (window, menu);
+ * hildon_window_set_app_menu (window, menu);
  * <!-- -->
  * hildon_window_add_toolbar (window, toolbar);
  * <!-- -->
  * gtk_window_set_icon (GTK_WINDOW (window), icon_pixbuf);
  * </programlisting>
  * </example>
- *
  */
 
-#include                                        "hildon-window.h"
+#undef                                          HILDON_DISABLE_DEPRECATED
+
 #include                                        <memory.h>
 #include                                        <string.h>
 #include                                        <strings.h>
 #include                                        <stdio.h>
-#include                                        "hildon-program.h"
-#include                                        "hildon-window-private.h"
-#include                                        "hildon-find-toolbar.h"
-
-#include                                        <gtk/gtkmenu.h>
-#include                                        <gtk/gtkimcontext.h>
-#include                                        <gtk/gtkmenuitem.h>
-#include                                        <gtk/gtkcheckmenuitem.h>
-#include                                        <gtk/gtkmenushell.h>
-#include                                        <gtk/gtkwindow.h>
-#include                                        <gtk/gtkwidget.h>
-#include                                        <gtk/gtkvbox.h>
-#include                                        <gtk/gtklabel.h>
-#include                                        <gtk/gtkentry.h>
-#include                                        <gtk/gtktextview.h>
-#include                                        <gtk/gtkscrolledwindow.h>
-#include                                        <gtk/gtkmain.h>
-#include                                        <gdk/gdkkeysyms.h>
-#include                                        <gdk/gdk.h>
-#include                                        <gtk/gtkprivate.h>
+#include                                        <libintl.h>
 #include                                        <X11/X.h>
-#include                                        <X11/Xlib.h>
 #include                                        <X11/Xatom.h>
-#include                                        <libintl.h>
+#include                                        <gdk/gdkkeysyms.h>
+#include                                        <gdk/gdkx.h>
+#include                                        <gtk/gtkprivate.h>
+
+#include                                        "hildon-window.h"
+#include                                        "hildon-window-private.h"
+#include                                        "hildon-app-menu-private.h"
+#include                                        "hildon-find-toolbar.h"
+#include                                        "hildon-defines.h"
 
 #define                                         _(String) gettext(String)
 
-#define                                         TOOLBAR_HEIGHT 40
+#define                                         TOOLBAR_HEIGHT 70
 
-#define                                         TOOLBAR_MIDDLE 10
+#define                                         TOOLBAR_MIDDLE 0
 
 /*FIXME*/
 #define                                         CAN_HIBERNATE "CANKILL"
 
 #define TITLE_SEPARATOR                         " - "
 
-static GtkWindowClass                           *parent_class;
-
 typedef void                                    (*HildonWindowSignal) (HildonWindow *, gint, gpointer);
 
 static void
@@ -175,6 +166,12 @@ hildon_window_realize                           (GtkWidget *widget);
 static void
 hildon_window_unrealize                         (GtkWidget *widget);
 
+static void
+hildon_window_map                               (GtkWidget *widget);
+
+static void
+hildon_window_unmap                             (GtkWidget *widget);
+
 static gboolean
 hildon_window_key_press_event                   (GtkWidget *widget,
                                                  GdkEventKey *event);
@@ -185,6 +182,9 @@ hildon_window_key_release_event                 (GtkWidget *widget,
 static gboolean
 hildon_window_window_state_event                (GtkWidget *widget, 
                                                  GdkEventWindowState *event);
+static gboolean
+hildon_window_focus_out_event                   (GtkWidget *widget, 
+                                                 GdkEventFocus *event);
 
 static void
 hildon_window_notify                            (GObject *gobject, 
@@ -194,7 +194,14 @@ static void
 hildon_window_is_topmost_notify                 (HildonWindow *window);
 
 static gboolean
-hildon_window_toggle_menu                       (HildonWindow * self);
+hildon_window_toggle_menu                       (HildonWindow * self,
+                                                guint button,
+                                                guint32 time);
+
+static gboolean
+hildon_window_toggle_menu_real                  (HildonWindow * self,
+                                                guint button,
+                                                guint32 time);
 
 static gboolean
 hildon_window_escape_timeout                    (gpointer data);
@@ -222,6 +229,12 @@ paint_toolbar                                   (GtkWidget *widget,
                                                  GdkEventExpose * event, 
                                                  gboolean fullscreen);
 
+static void
+paint_edit_toolbar                              (GtkWidget *widget,
+                                                 GtkWidget *toolbar,
+                                                 GdkEventExpose *event,
+                                                 gboolean fullscreen);
+
 enum
 {
     PROP_0,
@@ -235,36 +248,7 @@ enum
     MAX_WIN_MESSAGES
 };
 
-/**
- * hildon_window_get_type:
- *
- * Initializes and returns the type of a hildon window.
- *
- * @Returns: GType of #HildonWindow
- */
-GType G_GNUC_CONST
-hildon_window_get_type                          (void)
-{
-    static GType window_type = 0;
-
-    if (!window_type) {
-        static const GTypeInfo window_info = {
-            sizeof(HildonWindowClass),
-            NULL,       /* base_init */
-            NULL,       /* base_finalize */
-            (GClassInitFunc) hildon_window_class_init,
-            NULL,       /* class_finalize */
-            NULL,       /* class_data */
-            sizeof(HildonWindow),
-            0,  /* n_preallocs */
-            (GInstanceInitFunc) hildon_window_init,
-        };
-        window_type = g_type_register_static(GTK_TYPE_WINDOW,
-                "HildonWindow",
-                &window_info, 0);
-    }
-    return window_type;
-}
+G_DEFINE_TYPE (HildonWindow, hildon_window, GTK_TYPE_WINDOW);
 
 static void 
 hildon_window_class_init                        (HildonWindowClass * window_class)
@@ -274,9 +258,6 @@ hildon_window_class_init                        (HildonWindowClass * window_clas
     GObjectClass *object_class          = G_OBJECT_CLASS (window_class);
     GtkContainerClass *container_class  = GTK_CONTAINER_CLASS (window_class);
 
-    /* Set the global parent_class here */
-    parent_class = g_type_class_peek_parent (window_class);
-
     object_class->get_property          = hildon_window_get_property;
     object_class->notify                = hildon_window_notify;
     widget_class->size_allocate         = hildon_window_size_allocate;
@@ -288,6 +269,9 @@ hildon_window_class_init                        (HildonWindowClass * window_clas
     widget_class->key_press_event       = hildon_window_key_press_event;
     widget_class->key_release_event     = hildon_window_key_release_event;
     widget_class->window_state_event    = hildon_window_window_state_event;
+    widget_class->focus_out_event       = hildon_window_focus_out_event;
+    widget_class->map                   = hildon_window_map;
+    widget_class->unmap                 = hildon_window_unmap;
 
     /* now the object stuff */
     object_class->finalize              = hildon_window_finalize;
@@ -295,6 +279,9 @@ hildon_window_class_init                        (HildonWindowClass * window_clas
     /* To the container */
     container_class->forall             = hildon_window_forall;
 
+    /* To this class */
+    window_class->toggle_menu           = hildon_window_toggle_menu_real;
+
     /* gtkobject stuff*/
     GTK_OBJECT_CLASS (window_class)->destroy = hildon_window_destroy; 
 
@@ -302,12 +289,7 @@ hildon_window_class_init                        (HildonWindowClass * window_clas
             sizeof (struct _HildonWindowPrivate));
 
     /* Install properties */
-    
-    /**
-     * HildonWindow:is-topmost:
-     *
-     * Whether the window is currently activated by the window manager.
-     */
+
     g_object_class_install_property (object_class, PROP_IS_TOPMOST,
             g_param_spec_boolean ("is-topmost",
                 "Is top-most",
@@ -349,6 +331,8 @@ hildon_window_init                              (HildonWindow *self)
     priv->vbox = gtk_vbox_new (TRUE, TOOLBAR_MIDDLE);
     gtk_widget_set_parent (priv->vbox, GTK_WIDGET(self));
     priv->menu = NULL;
+    priv->app_menu = NULL;
+    priv->edit_toolbar = NULL;
     priv->visible_toolbars = 0;
     priv->is_topmost = FALSE;
     priv->borders = NULL;
@@ -370,7 +354,6 @@ hildon_window_init                              (HildonWindow *self)
 static void
 hildon_window_finalize                          (GObject * obj_self)
 {
-    HildonWindow *self;
     HildonWindowPrivate *priv; 
       
     g_return_if_fail (HILDON_WINDOW (obj_self));
@@ -378,13 +361,19 @@ hildon_window_finalize                          (GObject * obj_self)
     priv = HILDON_WINDOW_GET_PRIVATE (obj_self);
     g_assert (priv != NULL);
     
-    self = HILDON_WINDOW (obj_self);
+    if (priv->escape_timeout) {
+      g_source_remove (priv->escape_timeout);
+      priv->escape_timeout = 0;
+    }
 
-    g_free (priv->borders);
-    g_free (priv->toolbar_borders);
+    if (priv->borders)
+        gtk_border_free (priv->borders);
 
-    if (G_OBJECT_CLASS (parent_class)->finalize)
-        G_OBJECT_CLASS (parent_class)->finalize (obj_self);
+    if (priv->toolbar_borders)
+        gtk_border_free (priv->toolbar_borders);
+
+    if (G_OBJECT_CLASS (hildon_window_parent_class)->finalize)
+        G_OBJECT_CLASS (hildon_window_parent_class)->finalize (obj_self);
 
 }
 
@@ -398,13 +387,16 @@ hildon_window_realize                           (GtkWidget *widget)
     Window active_window;
     HildonWindowPrivate *priv;
 
-    GTK_WIDGET_CLASS (parent_class)->realize (widget);
+    GTK_WIDGET_CLASS (hildon_window_parent_class)->realize (widget);
 
     priv = HILDON_WINDOW_GET_PRIVATE (widget);
     g_assert (priv != NULL);
 
     gtk_widget_realize (GTK_WIDGET (priv->vbox));
 
+    if (priv->edit_toolbar != NULL)
+        gtk_widget_realize (priv->edit_toolbar);
+
     /* catch the custom button signal from mb to display the menu */
     gdk_window_add_filter (widget->window, hildon_window_event_filter, widget);
 
@@ -438,9 +430,6 @@ hildon_window_realize                           (GtkWidget *widget)
     /* Update the topmost status */
     active_window = hildon_window_get_active_window();
     hildon_window_update_topmost (HILDON_WINDOW (widget), active_window);
-
-    /* Update the window title */
-    hildon_window_update_title(HILDON_WINDOW (widget));
 }
 
 static void
@@ -453,7 +442,42 @@ hildon_window_unrealize                         (GtkWidget *widget)
             widget);
 
     gtk_widget_unrealize (GTK_WIDGET (priv->vbox));
-    GTK_WIDGET_CLASS(parent_class)->unrealize(widget);
+
+    if (priv->edit_toolbar != NULL)
+        gtk_widget_unrealize (priv->edit_toolbar);
+
+    GTK_WIDGET_CLASS(hildon_window_parent_class)->unrealize(widget);
+}
+
+static void
+hildon_window_map                             (GtkWidget *widget)
+{
+  HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
+  g_assert (priv != NULL);
+
+  if (GTK_WIDGET_CLASS (hildon_window_parent_class)->map)
+    GTK_WIDGET_CLASS (hildon_window_parent_class)->map (widget);
+
+  if (GTK_WIDGET_VISIBLE (priv->vbox))
+    gtk_widget_map (priv->vbox);
+
+  if (priv->edit_toolbar != NULL && GTK_WIDGET_VISIBLE (priv->edit_toolbar))
+    gtk_widget_map (priv->edit_toolbar);
+}
+
+static void
+hildon_window_unmap                             (GtkWidget *widget)
+{
+  HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
+  g_assert (priv != NULL);
+
+  gtk_widget_unmap (priv->vbox);
+
+  if (priv->edit_toolbar != NULL)
+    gtk_widget_unmap (priv->edit_toolbar);
+
+  if (GTK_WIDGET_CLASS (hildon_window_parent_class)->unmap)
+    GTK_WIDGET_CLASS (hildon_window_parent_class)->unmap (widget);
 }
 
 static void
@@ -483,29 +507,41 @@ hildon_window_get_property                      (GObject *object,
 static void
 hildon_window_get_borders                       (HildonWindow *window)
 {
+    GtkBorder zero = {0, 0, 0, 0};
     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (window);
     g_assert (priv);
 
-    g_free (priv->borders);
-    g_free (priv->toolbar_borders);
+    GtkBorder *borders = NULL;
+    GtkBorder *toolbar_borders = NULL;
 
-    gtk_widget_style_get (GTK_WIDGET (window), "borders",&priv->borders,
-            "toolbar-borders", &priv->toolbar_borders,
-            NULL);
+    if (priv->borders)
+        gtk_border_free (priv->borders);
+    if (priv->toolbar_borders)
+        gtk_border_free (priv->toolbar_borders);
 
-    if (! priv->borders)
-        priv->borders = (GtkBorder *) g_malloc0 (sizeof (GtkBorder));
+    priv->borders = NULL;
+    priv->toolbar_borders = NULL;
 
-    if (! priv->toolbar_borders)
-        priv->toolbar_borders = (GtkBorder *) g_malloc0 (sizeof (GtkBorder));
-}
+    gtk_widget_style_get (GTK_WIDGET (window), "borders",&borders,
+            "toolbar-borders", &toolbar_borders,
+            NULL);
 
-static void
-visible_toolbars                                (gpointer data, 
-                                                 gpointer user_data)
-{
-    if (GTK_WIDGET_VISIBLE (GTK_WIDGET (((GtkBoxChild *)data)->widget)))
-        (*((gint *)user_data)) ++;
+    // We're doing a copy here instead of reusing the pointer, 
+    // as we don't know where it comes from (has it been allocated using 
+    // malloc or slices... and we want to free it sanely. Blowing on 
+    // cold probbably.
+
+    if (borders) {
+        priv->borders = gtk_border_copy (borders);
+        gtk_border_free (borders);
+    } else
+        priv->borders = g_boxed_copy (GTK_TYPE_BORDER, &zero);
+
+    if (toolbar_borders) {
+        priv->toolbar_borders = gtk_border_copy (toolbar_borders);
+        gtk_border_free (toolbar_borders);
+    } else
+        priv->toolbar_borders = g_boxed_copy (GTK_TYPE_BORDER, &zero);
 }
 
 static gboolean
@@ -520,7 +556,6 @@ hildon_window_expose                            (GtkWidget *widget,
     GtkBorder *b = priv->borders;
     GtkBorder *tb = priv->toolbar_borders;
     gint tb_height = 0;
-    gint currently_visible_toolbars = 0;
 
     if (! priv->borders) {
         hildon_window_get_borders (HILDON_WINDOW (widget));
@@ -530,18 +565,21 @@ hildon_window_expose                            (GtkWidget *widget,
 
     tb_height = bx->allocation.height + tb->top + tb->bottom;
 
-    g_list_foreach (box->children, visible_toolbars, 
-            &currently_visible_toolbars);
-
     paint_toolbar (widget, box,
             event, priv->fullscreen);
 
+    if (priv->edit_toolbar != NULL)
+    {
+        paint_edit_toolbar (widget, priv->edit_toolbar,
+                            event, priv->fullscreen);
+    }
+
     if (! priv->fullscreen) {
 
         /* Draw the left and right window border */
         gint side_borders_height = widget->allocation.height - b->top;
 
-        if (currently_visible_toolbars)
+        if (priv->visible_toolbars)
             side_borders_height -= tb_height;
         else
             side_borders_height -= b->bottom;
@@ -566,7 +604,7 @@ hildon_window_expose                            (GtkWidget *widget,
         }
 
         /* If no toolbar, draw the bottom window border */
-        if (!currently_visible_toolbars && b->bottom > 0)
+        if (! priv->visible_toolbars && b->bottom > 0)
         {
             gtk_paint_box (widget->style, widget->window,
                     GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
@@ -591,10 +629,10 @@ hildon_window_expose                            (GtkWidget *widget,
 
     /* don't draw the window stuff as it overwrites our borders with a blank
      * rectangle. Instead start with the drawing of the GtkBin */
-    GTK_WIDGET_CLASS (g_type_class_peek_parent (parent_class))->expose_event (widget, event);
+    GTK_WIDGET_CLASS (g_type_class_peek_parent (hildon_window_parent_class))->expose_event (widget, event);
 
     /* FIXME Not sure why this is commented out 
-     * GTK_WIDGET_CLASS (parent_class))->
+     * GTK_WIDGET_CLASS (hildon_window_parent_class))->
      *  expose_event (widget, event); 
      */
 
@@ -609,7 +647,7 @@ hildon_window_size_request                      (GtkWidget *widget,
     g_assert (priv);
 
     GtkWidget *child = GTK_BIN (widget)->child;
-    GtkRequisition req2;
+    GtkRequisition req2 = { 0 };
     gint border_width = GTK_CONTAINER(widget)->border_width;
 
     if (! priv->borders)
@@ -624,8 +662,15 @@ hildon_window_size_request                      (GtkWidget *widget,
         gtk_widget_size_request (priv->vbox, &req2);
 
     requisition->height += req2.height;
-    requisition->width = (requisition->width < req2.width) ? 
-        req2.width : requisition->width;
+    requisition->width = MAX (requisition->width, req2.width);
+
+    if (priv->edit_toolbar != NULL && GTK_WIDGET_VISIBLE (priv->edit_toolbar))
+    {
+        GtkRequisition req;
+        gtk_widget_size_request (priv->edit_toolbar, &req);
+        requisition->height += req.height;
+        requisition->width = MAX (requisition->width, req.width);
+    }
 
     requisition->width  += 2 * border_width;
     requisition->height += 2 * border_width;
@@ -646,72 +691,90 @@ hildon_window_size_allocate                     (GtkWidget *widget,
     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
     g_assert (priv);
 
-    GtkAllocation box_alloc;
+    GtkAllocation box_alloc = { 0 };
+    GtkAllocation edittb_alloc = { 0 };
     GtkAllocation alloc = *allocation;
-    GtkRequisition req;
-    gint border_width = GTK_CONTAINER(widget)->border_width;
 
-    GtkWidget *box = priv->vbox;
-    GtkBin *bin = GTK_BIN(widget);
-    GtkBorder *b = priv->borders;
-    GtkBorder *tb = priv->toolbar_borders;
+    GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
+    GtkBorder *tb;
 
     if (!priv->borders)
-    {
         hildon_window_get_borders (HILDON_WINDOW (widget));
-        b = priv->borders;
-        tb = priv->toolbar_borders;
-    }
+
+    tb = priv->toolbar_borders;
 
     widget->allocation = *allocation;
 
-    gtk_widget_get_child_requisition (box, &req);
+    /* Calculate allocation of edit toolbar */
+    if (priv->edit_toolbar != NULL && GTK_WIDGET_VISIBLE (priv->edit_toolbar))
+    {
+        GtkRequisition req;
+        gtk_widget_get_child_requisition (priv->edit_toolbar, &req);
+        edittb_alloc.width = alloc.width - tb->left - tb->right;
+        edittb_alloc.height = MIN (req.height, alloc.height);
+        edittb_alloc.x = alloc.x + tb->left;
+        edittb_alloc.y = alloc.y + tb->top;
+
+        if (edittb_alloc.height > 0)
+        {
+            alloc.y += tb->top + tb->bottom + edittb_alloc.height;
+            alloc.height -= tb->top + tb->bottom + edittb_alloc.height;
+            gtk_widget_size_allocate (priv->edit_toolbar, &edittb_alloc);
+        }
+    }
 
-    box_alloc.width = allocation->width - tb->left - tb->right;
-    box_alloc.height = ( (req.height < allocation->height) ?
-            req.height : allocation->height );
-    box_alloc.x = allocation->x + tb->left;
-    box_alloc.y = allocation->y + allocation->height - box_alloc.height - tb->bottom;
+    /* Calculate allocation of normal toolbars */
+    if (priv->vbox != NULL && GTK_WIDGET_VISIBLE (priv->vbox))
+    {
+        GtkRequisition req;
+        gtk_widget_get_child_requisition (priv->vbox, &req);
+        box_alloc.width = alloc.width - tb->left - tb->right;
+        box_alloc.height = MIN (req.height, alloc.height);
+        box_alloc.x = alloc.x + tb->left;
+        box_alloc.y = alloc.y + alloc.height - box_alloc.height - tb->bottom;
+
+        if (box_alloc.height > 0)
+        {
+            alloc.height -= tb->top + tb->bottom + box_alloc.height;
+            gtk_widget_size_allocate (priv->vbox, &box_alloc);
+        }
+    }
 
-    if (bin->child != NULL && GTK_IS_WIDGET (bin->child)
-            && GTK_WIDGET_VISIBLE (bin->child))
+    /* Calculate allocation of the child widget */
+    if (child != NULL && GTK_WIDGET_VISIBLE (child))
     {
+        guint border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
         alloc.x += border_width;
         alloc.y += border_width;
         alloc.width -= (border_width * 2);
-        alloc.height -= (border_width * 2) + box_alloc.height;
+        alloc.height -= (border_width * 2);
 
         if (! priv->fullscreen)
         {
+            GtkBorder *b = priv->borders;
             alloc.x += b->left;
             alloc.width -= (b->left + b->right);
-            alloc.y += b->top;
 
-            alloc.height -= b->top;
+            /* Use the top border if there's no edit toolbar */
+            if (edittb_alloc.height <= 0)
+            {
+                alloc.y += b->top;
+                alloc.height -= b->top;
+            }
 
+            /* Use the top border if there are no standard toolbars */
             if (box_alloc.height <= 0)
                 alloc.height -= b->bottom;
-            else
-                alloc.height -= (tb->top + tb->bottom);            
-        }
-        else
-        {
-            if (!(box_alloc.height <= 0))
-                alloc.height -= (tb->top + tb->bottom);              
         }
 
-        gtk_widget_size_allocate (bin->child, &alloc);
+        gtk_widget_size_allocate (child, &alloc);
     }
 
-    gtk_widget_size_allocate (box, &box_alloc);
-
     if (priv->previous_vbox_y != box_alloc.y)
     {
         /* The size of the VBox has changed, we need to redraw part
          * of the window borders */
-        gint draw_from_y = priv->previous_vbox_y < box_alloc.y?
-            priv->previous_vbox_y - tb->top:
-            box_alloc.y - tb->top;
+        gint draw_from_y = MIN (priv->previous_vbox_y, box_alloc.y) - tb->top;
 
         gtk_widget_queue_draw_area (widget, 0, draw_from_y, 
                 widget->allocation.width,
@@ -734,10 +797,14 @@ hildon_window_forall                            (GtkContainer *container,
     g_return_if_fail (callback != NULL);
     g_assert (priv);
 
-    GTK_CONTAINER_CLASS (parent_class)->forall (container, include_internals,
+    GTK_CONTAINER_CLASS (hildon_window_parent_class)->forall (container, include_internals,
             callback, callback_data);
+
     if (include_internals && priv->vbox != NULL)
         (* callback)(GTK_WIDGET (priv->vbox), callback_data);
+
+    if (include_internals && priv->edit_toolbar != NULL)
+        (* callback)(GTK_WIDGET (priv->edit_toolbar), callback_data);
 }
 
 static void
@@ -748,8 +815,12 @@ hildon_window_show_all                          (GtkWidget *widget)
 
     g_assert (priv != NULL);
 
-    GTK_WIDGET_CLASS (parent_class)->show_all (widget);
+    GTK_WIDGET_CLASS (hildon_window_parent_class)->show_all (widget);
+
     gtk_widget_show_all (priv->vbox);
+
+    if (priv->edit_toolbar)
+        gtk_widget_show_all (priv->edit_toolbar);
 }
 
 static void
@@ -757,8 +828,9 @@ hildon_window_destroy                           (GtkObject *obj)
 {
     HildonWindow *self = HILDON_WINDOW (obj);
     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (obj);
-    GList *menu_list;
-    
+    GList *menu_list = NULL;
+    GList *menu_node = NULL;
+
     g_assert (priv != NULL);
 
     if (priv->vbox != NULL)
@@ -779,30 +851,45 @@ hildon_window_destroy                           (GtkObject *obj)
 
     }
 
+    if (priv->edit_toolbar != NULL)
+    {
+        gtk_widget_unparent (priv->edit_toolbar);
+        priv->edit_toolbar = NULL;
+    }
+
+    if (priv->app_menu)
+    {
+        hildon_app_menu_set_parent_window (priv->app_menu, NULL);
+        g_object_unref (priv->app_menu);
+        priv->app_menu = NULL;
+    }
+
     menu_list = g_list_copy (gtk_menu_get_for_attach_widget (GTK_WIDGET (obj)));
+    menu_node = menu_list;
 
-    while (menu_list)
+    while (menu_node)
     {
-        if (GTK_IS_MENU (menu_list->data))
+        if (GTK_IS_MENU (menu_node->data))
         {
-            if (GTK_WIDGET_VISIBLE (GTK_WIDGET (menu_list->data)))
+            if (GTK_WIDGET_VISIBLE (GTK_WIDGET (menu_node->data)))
             {
-                gtk_menu_popdown (GTK_MENU (menu_list->data));
-                gtk_menu_shell_deactivate (GTK_MENU_SHELL (menu_list->data));
+                gtk_menu_popdown (GTK_MENU (menu_node->data));
+                gtk_menu_shell_deactivate (GTK_MENU_SHELL (menu_node->data));
             }
-            gtk_menu_detach (GTK_MENU (menu_list->data));
+            gtk_menu_detach (GTK_MENU (menu_node->data));
 
             /* Destroy it, but only if it's not a common menu */
             if (priv->program && 
-                hildon_program_get_common_menu (priv->program) != menu_list->data) {
-                    g_object_unref (menu_list->data);
-                    gtk_object_destroy (GTK_OBJECT (menu_list->data));
+                hildon_program_get_common_menu (priv->program) != menu_node->data) {
+                    gtk_object_destroy (GTK_OBJECT (menu_node->data));
+                    g_object_unref (menu_node->data);
             }
         }
-        menu_list = menu_list->next;
+        menu_node = menu_node->next;
     }
 
     g_list_free (menu_list);
+    menu_list = NULL;
 
     if (priv->program)
     {
@@ -815,28 +902,22 @@ hildon_window_destroy                           (GtkObject *obj)
 
     gtk_widget_set_events (GTK_WIDGET(obj), 0);
 
-    GTK_OBJECT_CLASS (parent_class)->destroy (obj);
+    GTK_OBJECT_CLASS (hildon_window_parent_class)->destroy (obj);
 }
 
-
 static void
 hildon_window_notify                            (GObject *gobject, 
                                                  GParamSpec *param)
 {
     HildonWindow *window = HILDON_WINDOW (gobject);
 
-    if (g_str_equal (param->name, "title"))
-    {
-
-        hildon_window_update_title (window);
-    }
-    else if (g_str_equal (param->name, "is-topmost"))
+    if (g_str_equal (param->name, "is-topmost"))
     {
         hildon_window_is_topmost_notify (window);
     }
 
-    if (G_OBJECT_CLASS(parent_class)->notify)
-        G_OBJECT_CLASS(parent_class)->notify (gobject, param);
+    if (G_OBJECT_CLASS(hildon_window_parent_class)->notify)
+        G_OBJECT_CLASS(hildon_window_parent_class)->notify (gobject, param);
 }
 
 
@@ -848,26 +929,6 @@ visible_toolbar                                 (gpointer data,
         (*((gint *)user_data))++;
 }
 
-static void 
-find_findtoolbar_index                          (gpointer data, 
-                                                 gpointer user_data)
-{
-    gint *pass_bundle = (gint *)user_data;
-
-    if(((GtkBoxChild *)data)->widget->allocation.y < pass_bundle[0]
-            && GTK_WIDGET_VISIBLE (((GtkBoxChild *)data)->widget))
-        pass_bundle[1]++;
-}
-
-static void
-find_findtoolbar                                (gpointer data, 
-                                                 gpointer user_data)
-{
-    if(HILDON_IS_FIND_TOOLBAR (((GtkBoxChild *)data)->widget)
-            && GTK_WIDGET_VISIBLE (((GtkBoxChild *)data)->widget))
-        (*((GtkWidget **)user_data)) = ((GtkBoxChild *)data)->widget;
-}
-
 static void
 paint_toolbar                                   (GtkWidget *widget, 
                                                  GtkBox *box, 
@@ -875,14 +936,7 @@ paint_toolbar                                   (GtkWidget *widget,
                                                  gboolean fullscreen)
 {
     gint toolbar_num = 0; 
-    gint ftb_index = 0;
     gint count;
-    GtkWidget *findtoolbar = NULL;
-    HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
-    gchar toolbar_mode[40];
-    GtkBorder *tb = priv->toolbar_borders;
-
-    g_assert (priv != NULL);
 
     /* collect info to help on painting the boxes */
     g_list_foreach (box->children, visible_toolbar, 
@@ -891,115 +945,45 @@ paint_toolbar                                   (GtkWidget *widget,
     if(toolbar_num <= 0)
         return;
 
-    g_list_foreach (box->children, find_findtoolbar, (gpointer) &findtoolbar);
-
-    if (findtoolbar != NULL)
-    {
-        gint pass_bundle[2];/* an array for convient data passing
-                               the first member contains the y allocation
-                               of the find toolbar, and the second allocation
-                               contains the index(how many toolbars are above
-                               find toolbar) */
-        pass_bundle[0] = findtoolbar->allocation.y;
-        pass_bundle[1] = ftb_index;
-        g_list_foreach(box->children, find_findtoolbar_index,
-                (gpointer) pass_bundle);
-        ftb_index = pass_bundle[1];
-    }
-
-    /*upper border*/
-    sprintf (toolbar_mode, "toolbar%sframe-top", 
-            fullscreen ? "-fullscreen-" : "-");
+    /*top most toolbar painting*/
     gtk_paint_box (widget->style, widget->window,
-            GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT,
-            &event->area, widget, toolbar_mode,
+            GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
+            &event->area, widget, "toolbar-primary",
             widget->allocation.x,
-            GTK_WIDGET (box)->allocation.y - tb->top,
-            widget->allocation.width, tb->top);
+            GTK_WIDGET(box)->allocation.y,
+            widget->allocation.width,
+            TOOLBAR_HEIGHT);
 
-    /*top most toolbar painting*/
-    if (findtoolbar != NULL && ftb_index == 0 )
-    {
-        sprintf (toolbar_mode, "findtoolbar%s", 
-                fullscreen ? "-fullscreen" : "");
-
-        gtk_paint_box (widget->style, widget->window,
-                GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
-                &event->area, widget, toolbar_mode,
-                widget->allocation.x,
-                GTK_WIDGET(box)->allocation.y,
-                widget->allocation.width,
-                TOOLBAR_HEIGHT);
-    }
-    else
-    {
-        sprintf (toolbar_mode, "toolbar%s", 
-                fullscreen ? "-fullscreen" : "");
-
-        gtk_paint_box (widget->style, widget->window,
-                GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
-                &event->area, widget, toolbar_mode,
-                widget->allocation.x,
-                GTK_WIDGET(box)->allocation.y,
-                widget->allocation.width,
-                TOOLBAR_HEIGHT);
-    }
     /*multi toolbar painting*/
     for (count = 0; count < toolbar_num - 1; count++)
     {
-        sprintf (toolbar_mode, "toolbar%sframe-middle", 
-                fullscreen ? "-fullscreen-" : "-");
-
-        gtk_paint_box (widget->style, widget->window,
-                GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
-                &event->area, widget, toolbar_mode,
-                widget->allocation.x,
-                GTK_WIDGET(box)->allocation.y + 
-                (1 + count) * TOOLBAR_HEIGHT + 
-                count * TOOLBAR_MIDDLE,
-                widget->allocation.width,
-                TOOLBAR_MIDDLE);
-
-        if (findtoolbar != NULL && count + 1 == ftb_index)
-        {
-
-            sprintf (toolbar_mode, "findtoolbar%s", 
-                    fullscreen ? "-fullscreen" : "");
-
-            gtk_paint_box (widget->style, widget->window,
-                    GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
-                    &event->area, widget, toolbar_mode,
-                    widget->allocation.x,
-                    GTK_WIDGET(box)->allocation.y + 
-                    (1 + count) * (TOOLBAR_HEIGHT + TOOLBAR_MIDDLE),
-                    widget->allocation.width,
-                    TOOLBAR_HEIGHT);
-        }
-        else
-        {
-            sprintf (toolbar_mode, "toolbar%s", 
-                    fullscreen ? "-fullscreen" : "");
-
             gtk_paint_box (widget->style, widget->window,
-                    GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
-                    &event->area, widget, toolbar_mode,
-                    widget->allocation.x,
-                    GTK_WIDGET(box)->allocation.y + 
-                    (1 + count) * (TOOLBAR_HEIGHT + TOOLBAR_MIDDLE),
-                    widget->allocation.width,
-                    TOOLBAR_HEIGHT);
-        }
+                           GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
+                           &event->area, widget, "toolbar-secondary",
+                           widget->allocation.x,
+                           GTK_WIDGET(box)->allocation.y +
+                           (1 + count) * (TOOLBAR_HEIGHT),
+                           widget->allocation.width,
+                           TOOLBAR_HEIGHT);
     }
-    sprintf (toolbar_mode, "toolbar%sframe-bottom", 
-            fullscreen ? "-fullscreen-" : "-");
+}
+
+static void
+paint_edit_toolbar                              (GtkWidget *widget,
+                                                 GtkWidget *toolbar,
+                                                 GdkEventExpose *event,
+                                                 gboolean fullscreen)
+{
+    if (!GTK_WIDGET_VISIBLE (toolbar))
+        return;
 
     gtk_paint_box (widget->style, widget->window,
-            GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
-            &event->area, widget, toolbar_mode,
-            widget->allocation.x,
-            GTK_WIDGET(box)->allocation.y + 
-            GTK_WIDGET(box)->allocation.height,
-            widget->allocation.width, tb->bottom);
+                   GTK_WIDGET_STATE (widget), GTK_SHADOW_OUT,
+                   &event->area, widget, "toolbar-edit-mode",
+                   toolbar->allocation.x,
+                   toolbar->allocation.y,
+                   toolbar->allocation.width,
+                   toolbar->allocation.height);
 }
 
 /*
@@ -1071,7 +1055,7 @@ hildon_window_event_filter                      (GdkXEvent *xevent,
 
         if (xclient_message_type_check (cm, "_MB_GRAB_TRANSFER"))
         {
-            hildon_window_toggle_menu (HILDON_WINDOW ( data ));
+            hildon_window_toggle_menu (HILDON_WINDOW ( data ), cm->data.l[2], cm->data.l[0]);
             return GDK_FILTER_REMOVE;
         }
         /* opera hack clipboard client message */
@@ -1142,7 +1126,7 @@ hildon_window_key_press_event                   (GtkWidget *widget,
     switch (event->keyval)
     {
         case HILDON_HARDKEY_MENU:
-            if (hildon_window_toggle_menu (HILDON_WINDOW (widget)))
+            if (hildon_window_toggle_menu (HILDON_WINDOW (widget), 0, GDK_CURRENT_TIME))
                 return TRUE;
             break;
         case HILDON_HARDKEY_ESC:
@@ -1155,7 +1139,7 @@ hildon_window_key_press_event                   (GtkWidget *widget,
             break;
     }
 
-    return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
+    return GTK_WIDGET_CLASS (hildon_window_parent_class)->key_press_event (widget, event);
 }
 
 static gboolean
@@ -1178,7 +1162,7 @@ hildon_window_key_release_event                 (GtkWidget *widget,
             break;
     }
 
-    return GTK_WIDGET_CLASS (parent_class)->key_release_event (widget, event);
+    return GTK_WIDGET_CLASS (hildon_window_parent_class)->key_release_event (widget, event);
 
 }
 
@@ -1196,9 +1180,9 @@ hildon_window_window_state_event                (GtkWidget *widget,
     if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
         priv->fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN;
 
-    if (GTK_WIDGET_CLASS (parent_class)->window_state_event)
+    if (GTK_WIDGET_CLASS (hildon_window_parent_class)->window_state_event)
     {
-        return GTK_WIDGET_CLASS (parent_class)->window_state_event (
+        return GTK_WIDGET_CLASS (hildon_window_parent_class)->window_state_event (
                 widget,
                 event);
     }
@@ -1209,6 +1193,25 @@ hildon_window_window_state_event                (GtkWidget *widget,
 }
 
 /*
+ * If the window lost focus while the user started to press the ESC key, we
+ * won't get the release event. We need to stop the timeout.
+ */
+static gboolean
+hildon_window_focus_out_event                   (GtkWidget *widget, 
+                                                 GdkEventFocus *event)
+{
+  HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (widget);
+
+  if (priv->escape_timeout)
+  {
+      g_source_remove (priv->escape_timeout);
+      priv->escape_timeout = 0;
+  }
+
+  return GTK_WIDGET_CLASS (hildon_window_parent_class)->focus_out_event (widget, event);
+}
+
+/*
  * The menu popuping needs a menu popup-function
  */
 static void
@@ -1230,7 +1233,13 @@ hildon_window_menu_popup_func                   (GtkMenu *menu,
     gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
             "vertical-offset", y, NULL);
 
-    *x += window_x;
+    if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+    {
+        *x = GTK_WIDGET (widget)->allocation.width + window_x - GTK_WIDGET (menu)->allocation.width - *x;
+    }
+    else
+        *x += window_x;
+
     *y += window_y;
 
 }
@@ -1245,7 +1254,11 @@ hildon_window_menu_popup_func_full              (GtkMenu *menu,
     gtk_widget_style_get (GTK_WIDGET (menu), "horizontal-offset", x,
             "vertical-offset", y, NULL);
 
-    *x = MAX (0, *x);
+    if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+        *x = GTK_WIDGET (widget)->allocation.width - GTK_WIDGET (menu)->allocation.width - *x;
+    else
+        *x = MAX (0, *x);
+
     *y = MAX (0, *y);
 }
 
@@ -1264,18 +1277,6 @@ hildon_window_is_topmost_notify                 (HildonWindow *window)
     {
         hildon_window_take_common_toolbar (window);
     }
-
-    else
-    {
-        /* If the window lost focus while the user started to press
-         * the ESC key, we won't get the release event. We need to
-         * stop the timeout*/
-        if (priv->escape_timeout)
-        {
-            g_source_remove (priv->escape_timeout);
-            priv->escape_timeout = 0;
-        }
-    }
 }
 
 /*
@@ -1308,7 +1309,7 @@ hildon_window_set_program                       (HildonWindow *self,
 
 /*
  * Unsets the program to which the window belongs. This should only be called
- * by hildon_program_add_window
+ * by hildon_program_remove_window
  */
 void G_GNUC_INTERNAL
 hildon_window_unset_program                     (HildonWindow *self)
@@ -1419,14 +1420,14 @@ hildon_window_update_topmost                    (HildonWindow *self,
 {
     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
 
-    Window my_window;
+    GdkWindow *my_window;
 
     g_return_if_fail (HILDON_IS_WINDOW (self));
     g_assert (priv);
 
-    my_window = GDK_WINDOW_XID (GTK_WIDGET (self)->window);
+    my_window = GTK_WIDGET (self)->window;
 
-    if (window_id == my_window)
+    if (my_window && window_id == GDK_WINDOW_XID (my_window))
     {
         if (! priv->is_topmost)
         {
@@ -1451,50 +1452,116 @@ hildon_window_update_topmost                    (HildonWindow *self,
     }
 }
 
-/*
- * If the application
- * was given a name (with g_set_application_name(), set 
- * "ProgramName - WindowTitle" as the displayed
- * title
- */
-void G_GNUC_INTERNAL
-hildon_window_update_title                      (HildonWindow *window)
+static void
+detach_menu_func                                (GtkWidget *attach_widget, 
+                                                 GtkMenu *menu)
 {
-    const gchar * application_name;
+    /* FIXME Why is this even needed here? */
+}
 
-    g_return_if_fail (HILDON_IS_WINDOW (window));
+static gboolean
+hildon_window_toggle_menu                       (HildonWindow *self,
+                                                guint button,
+                                                guint32 time)
+{
+    g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
 
-    if (!GTK_WIDGET_REALIZED (window))
+    if (HILDON_WINDOW_GET_CLASS (self)->toggle_menu != NULL)
     {
-        return;
+        return HILDON_WINDOW_GET_CLASS (self)->toggle_menu (self, button, time);
+    }
+    else
+    {
+        return FALSE;
     }
+}
 
-    application_name = g_get_application_name ();
 
-    if (application_name && application_name[0])
-    {
-        const gchar *old_title = gtk_window_get_title (GTK_WINDOW (window));
+static gboolean
+hildon_window_toggle_gtk_menu                   (HildonWindow *self,
+                                                GtkMenu      *menu,
+                                                guint         button,
+                                                guint32       time)
+{
+    gboolean retvalue = FALSE;
 
-        if (old_title && old_title[0])
+    g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
+    g_return_val_if_fail (GTK_IS_MENU (menu), FALSE);
+
+    if (gtk_menu_get_attach_widget (menu) != GTK_WIDGET (self))
+    {
+        g_object_ref (menu);
+        if (gtk_menu_get_attach_widget (menu))
         {
-            gchar *title = NULL;
+            gtk_menu_detach (menu);
+        }
+        gtk_menu_attach_to_widget (menu, GTK_WIDGET (self), &detach_menu_func);
+        g_object_unref (menu);
+    }
+
+    if (GTK_WIDGET_MAPPED (menu))
+    {
+        gtk_menu_popdown (menu);
+        gtk_menu_shell_deactivate (GTK_MENU_SHELL (menu));
+        retvalue = TRUE;
+    }
+    else
+    {
+        /* Check if the menu has items */
+        GList *menu_children = gtk_container_get_children (GTK_CONTAINER (menu));
 
-            title = g_strjoin (TITLE_SEPARATOR, application_name,
-                    old_title, NULL);
+        if (menu_children)
+        {
+            HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
+            g_list_free (menu_children);
 
-            gdk_window_set_title (GTK_WIDGET (window)->window, title);
+            /* Apply right theming */
+            gtk_widget_set_name (GTK_WIDGET (menu), "menu_force_with_corners");
 
-            g_free (title);
+            if (priv->fullscreen)
+            {
+                gtk_menu_popup (menu, NULL, NULL,
+                                (GtkMenuPositionFunc)
+                                hildon_window_menu_popup_func_full,
+                                self, button, time);
+            }
+            else
+            {
+                gtk_menu_popup (menu, NULL, NULL,
+                                (GtkMenuPositionFunc)
+                                hildon_window_menu_popup_func,
+                                self, button, time);
+            }
+            gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), TRUE);
+            retvalue = TRUE;
         }
-
     }
+
+    return retvalue;
 }
 
-static void
-detach_menu_func                                (GtkWidget *attach_widget, 
-                                                 GtkMenu *menu)
+static gboolean
+hildon_window_toggle_app_menu                   (HildonWindow  *self,
+                                                HildonAppMenu *menu)
 {
-    /* FIXME Why is this even needed here? */
+    g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
+    g_return_val_if_fail (HILDON_IS_APP_MENU (menu), FALSE);
+
+    if (self != hildon_app_menu_get_parent_window (menu))
+    {
+        gtk_widget_hide (GTK_WIDGET (menu));
+    }
+
+    if (GTK_WIDGET_MAPPED (menu))
+    {
+        gtk_widget_hide (GTK_WIDGET (menu));
+    }
+    else
+    {
+        hildon_app_menu_popup (menu, GTK_WINDOW (self));
+    }
+
+    return TRUE;
 }
 
 /*
@@ -1503,84 +1570,41 @@ detach_menu_func                                (GtkWidget *attach_widget,
  * to toggle)
  */
 static gboolean
-hildon_window_toggle_menu                       (HildonWindow * self)
+hildon_window_toggle_menu_real                  (HildonWindow * self,
+                                                guint button,
+                                                guint32 time)
 {
-    GtkMenu *menu_to_use = NULL;
-    GList *menu_children = NULL;
+    gboolean retvalue = FALSE;
     HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
 
     g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
-    g_assert (priv != NULL);
 
     /* Select which menu to use, Window specific has highest priority,
      * then program specific */
     if (priv->menu)
     {
-        menu_to_use = GTK_MENU (priv->menu);
-    }
-    else if (priv->program)
-    {
-        menu_to_use = hildon_program_get_common_menu (priv->program);
-        if (menu_to_use && gtk_menu_get_attach_widget (menu_to_use) != 
-                GTK_WIDGET (self))
-        {
-            g_object_ref (menu_to_use);
-            if (gtk_menu_get_attach_widget (menu_to_use))
-            {
-                gtk_menu_detach (menu_to_use);
-            }
-
-            gtk_menu_attach_to_widget (menu_to_use, GTK_WIDGET (self), 
-                    &detach_menu_func);
-            g_object_unref (menu_to_use);
-        }
+        retvalue = hildon_window_toggle_gtk_menu (self, priv->menu, button, time);
     }
-
-    if (! menu_to_use)
-    {
-        return FALSE;
-    }
-
-
-    if (GTK_WIDGET_MAPPED (GTK_WIDGET (menu_to_use)))
+    else if (priv->app_menu)
     {
-        gtk_menu_popdown (menu_to_use);
-        gtk_menu_shell_deactivate (GTK_MENU_SHELL (menu_to_use));
-        return TRUE;
+        retvalue = hildon_window_toggle_app_menu (self, priv->app_menu);
     }
-
-    /* Check if the menu has items */
-    menu_children = gtk_container_get_children (GTK_CONTAINER (menu_to_use));
-
-    if (menu_children)
+    else if (priv->program)
     {
-        g_list_free (menu_children);
-
-        /* Apply right theming */
-        gtk_widget_set_name (GTK_WIDGET (menu_to_use),
-                "menu_force_with_corners");
+        GtkMenu *gtkmenu = hildon_program_get_common_menu (priv->program);
+        HildonAppMenu *appmenu = hildon_program_get_common_app_menu (priv->program);
 
-        if (priv->fullscreen) 
+        if (gtkmenu)
         {
-            gtk_menu_popup (menu_to_use, NULL, NULL,
-                    (GtkMenuPositionFunc)
-                    hildon_window_menu_popup_func_full,
-                    self, 0, 
-                    gtk_get_current_event_time ());
+            retvalue = hildon_window_toggle_gtk_menu (self, gtkmenu, button, time);
         }
-        else
+        else if (appmenu)
         {
-            gtk_menu_popup (menu_to_use, NULL, NULL,
-                    (GtkMenuPositionFunc)
-                    hildon_window_menu_popup_func,
-                    self, 0, 
-                    gtk_get_current_event_time ());
+            retvalue = hildon_window_toggle_app_menu (self, appmenu);
         }
-        gtk_menu_shell_select_first (GTK_MENU_SHELL (menu_to_use), TRUE);
-        return TRUE;
     }
 
-    return FALSE;
+    return retvalue;
 }
 
 /*
@@ -1616,9 +1640,9 @@ hildon_window_escape_timeout                    (gpointer data)
 /**
  * hildon_window_new: 
  * 
- * Creates a new HildonWindow.
+ * Creates a new #HildonWindow.
  * 
- * Return value: A @HildonWindow.
+ * Return value: A #HildonWindow.
  **/
 GtkWidget*
 hildon_window_new                               (void)
@@ -1629,13 +1653,13 @@ hildon_window_new                               (void)
 }
 
 /**
- * hildon_window_add_with_scrollbar
- * @self : A @HildonWindow
- * @child : A @GtkWidget
+ * hildon_window_add_with_scrollbar:
+ * @self: A #HildonWindow
+ * @child: A #GtkWidget
  *
- * Adds the @child to the HildonWindow and creates a scrollbar
- * for it. Similar as adding first a @GtkScrolledWindow and then the
- * @child to it.
+ * Adds @child to the #HildonWindow and creates a scrollbar for
+ * it. Similar to adding first a #GtkScrolledWindow and then @child to
+ * it.
  */
 void
 hildon_window_add_with_scrollbar                (HildonWindow *self,
@@ -1665,121 +1689,360 @@ hildon_window_add_with_scrollbar                (HildonWindow *self,
     gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (scrolledw));
 }
 
+static void
+calculate_visible_toolbars                      (gpointer data,
+                                                 gpointer user_data)
+{
+  if (GTK_WIDGET_VISIBLE (GTK_WIDGET (((GtkBoxChild *)data)->widget)))
+    (*((gint *)user_data)) ++;
+}
+
+static void
+toolbar_visible_notify                          (GtkWidget *toolbar, GParamSpec *pspec,
+                                                 HildonWindow *window)
+{
+  HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (window);
+
+  g_assert (priv);
+
+  /* Recalculate from scratch the value just in case */
+  priv->visible_toolbars = 0;
+
+  g_list_foreach (GTK_BOX (priv->vbox)->children, calculate_visible_toolbars, 
+                  &priv->visible_toolbars);
+
+  if (priv->visible_toolbars == 0)
+    gtk_widget_hide (priv->vbox);
+  else
+    gtk_widget_show (priv->vbox);
+}
+
 /**
  * hildon_window_add_toolbar:
- * @self: A @HildonWindow
- * @toolbar: A #GtkToolbar to add to the HildonWindow
+ * @self: A #HildonWindow
+ * @toolbar: A #GtkToolbar to add to the #HildonWindow
  *
- * Adds a toolbar to the window.
+ * Adds a toolbar to the window. Note that the toolbar is not automatically
+ * shown. You need to call gtk_widget_show_all() on it to make it visible.
+ * It's also possible to hide the toolbar (without removing it) by calling
+ * gtk_widget_hide()
  **/
 void 
 hildon_window_add_toolbar                       (HildonWindow *self, 
                                                  GtkToolbar *toolbar)
 {
     GtkBox *vbox;
-    HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
+    HildonWindowPrivate *priv;
 
     g_return_if_fail (HILDON_IS_WINDOW (self));
     g_return_if_fail (toolbar && GTK_IS_TOOLBAR (toolbar));
-    g_assert (priv);
+
+    priv = HILDON_WINDOW_GET_PRIVATE (self);
 
     vbox = GTK_BOX (priv->vbox);
 
-    gtk_box_pack_start (vbox, GTK_WIDGET(toolbar), TRUE, TRUE, 0);
-    gtk_box_reorder_child (vbox, GTK_WIDGET(toolbar), 0);
+    gtk_box_pack_start (vbox, GTK_WIDGET (toolbar), TRUE, TRUE, 0);
+    gtk_box_reorder_child (vbox, GTK_WIDGET (toolbar), 0);
     gtk_widget_set_size_request (GTK_WIDGET (toolbar), -1, TOOLBAR_HEIGHT);
 
-    gtk_widget_queue_resize (GTK_WIDGET(self));
+    g_signal_connect (G_OBJECT (toolbar), "notify::visible",
+                      G_CALLBACK (toolbar_visible_notify), self);
+
+    if (GTK_WIDGET_VISIBLE (toolbar))
+      {
+        priv->visible_toolbars++;
+        gtk_widget_show (priv->vbox);
+      }
+
+    gtk_widget_queue_resize (GTK_WIDGET (self));
 }
 
 /**
  * hildon_window_remove_toolbar:
- * @self: A @HildonWindow
- * @toolbar: A #GtkToolbar to remove from the HildonWindow
+ * @self: A #HildonWindow
+ * @toolbar: A #GtkToolbar to remove from the #HildonWindow
  *
- * Removes a toolbar from the window.
+ * Removes a toolbar from the window. Note that this decreases the refference
+ * count on the widget. If you want to keep the toolbar alive call g_object_ref()
+ * before calling this function.
  **/
 void
 hildon_window_remove_toolbar                    (HildonWindow *self, 
                                                  GtkToolbar *toolbar)
 {
-    HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
-    
+    HildonWindowPrivate *priv;
+
     g_return_if_fail (HILDON_IS_WINDOW (self));
-    g_assert (priv);
     
-    gtk_container_remove (GTK_CONTAINER (priv->vbox), GTK_WIDGET(toolbar));
+    priv = HILDON_WINDOW_GET_PRIVATE (self);
+
+    if (GTK_WIDGET_VISIBLE (toolbar))
+      {
+        if (--(priv->visible_toolbars) == 0)
+          gtk_widget_hide (priv->vbox);
+      }
+
+    g_signal_handlers_disconnect_by_func (toolbar, toolbar_visible_notify, self);
+
+    gtk_container_remove (GTK_CONTAINER (priv->vbox), GTK_WIDGET (toolbar));
 }
 
 /**
- * hildon_window_get_menu:
- * @self : #HildonWindow
- * 
- * Gets the #GtMenu assigned to the #HildonAppview. Note that the 
+ * hildon_window_set_edit_toolbar:
+ * @self: A #HildonWindow
+ * @toolbar: A #HildonEditToolbar, or %NULL to remove the current one.
+ *
+ * Adds a #HildonEditToolbar to the window. Note that the toolbar is
+ * not automatically shown. You need to call gtk_widget_show() on it
+ * to make it visible. It's also possible to hide the toolbar (without
+ * removing it) by calling gtk_widget_hide().
+ *
+ * A window can only have at most one edit toolbar at a time, so the
+ * previous toolbar (if any) is replaced after calling this function.
+ **/
+void
+hildon_window_set_edit_toolbar                  (HildonWindow      *self,
+                                                 HildonEditToolbar *toolbar)
+{
+    HildonWindowPrivate *priv;
+
+    g_return_if_fail (HILDON_IS_WINDOW (self));
+    g_return_if_fail (toolbar == NULL || HILDON_IS_EDIT_TOOLBAR (toolbar));
+
+    priv = HILDON_WINDOW_GET_PRIVATE (self);
+
+    if (priv->edit_toolbar != GTK_WIDGET (toolbar))
+    {
+        GtkWidget *old_toolbar = priv->edit_toolbar;
+        priv->edit_toolbar = GTK_WIDGET (toolbar);
+
+        if (priv->edit_toolbar)
+            gtk_widget_set_parent (priv->edit_toolbar, GTK_WIDGET (self));
+
+        if (old_toolbar)
+            gtk_widget_unparent (old_toolbar);
+    }
+}
+
+/**
+ * hildon_window_get_main_menu:
+ * @self: a #HildonWindow
+ *
+ * Gets the #GtkMenu assigned to the #HildonAppview. Note that the
  * window is still the owner of the menu.
- * 
+ *
+ * Note that if you're using a #HildonAppMenu rather than a #GtkMenu
+ * you should use hildon_window_get_app_menu() instead.
+ *
  * Return value: The #GtkMenu assigned to this application view. 
  **/
 GtkMenu*
-hildon_window_get_menu                          (HildonWindow * self)
+hildon_window_get_main_menu                     (HildonWindow * self)
 {
-    HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
-    
+    HildonWindowPrivate *priv;
+
     g_return_val_if_fail (HILDON_IS_WINDOW (self), NULL);
-    g_assert (priv);
 
-    return GTK_MENU (priv->menu);
+    priv = HILDON_WINDOW_GET_PRIVATE (self);
+
+    return priv->menu;
+}
+
+/**
+ * hildon_window_get_menu:
+ * @self: a #HildonWindow
+ *
+ * Return value: a #GtkMenu
+ *
+ * Deprecated: In Hildon 2.2 this function has been renamed to
+ * hildon_window_get_main_menu() for consistency
+ **/
+GtkMenu*
+hildon_window_get_menu                          (HildonWindow * self)
+{
+    return hildon_window_get_main_menu (self);
+}
+
+/* Since we've been asking developers to call gtk_window_add_accel_group()
+ * themselves, do not trigger criticals by trying it again.
+ */
+static void
+hildon_window_add_accel_group (HildonWindow *self,
+                              GtkAccelGroup *accel_group)
+{
+    GSList *groups, *l;
+
+    groups = gtk_accel_groups_from_object (G_OBJECT (self));
+    for (l = groups; l != NULL; l = l->next)
+      if (l->data == (gpointer)accel_group)
+       /* Maybe print a warning here? */
+       return;
+
+    gtk_window_add_accel_group (GTK_WINDOW (self), accel_group);
+}
+
+/**
+ * hildon_window_set_main_menu:
+ * @self: A #HildonWindow
+ * @menu: The #GtkMenu to be used for this #HildonWindow
+ *
+ * Sets the menu to be used for this window. This menu overrides
+ * a program-wide menu that may have been set with
+ * hildon_program_set_common_menu(). Pass %NULL to remove the current
+ * menu. #HildonWindow takes ownership of the passed menu and you're
+ * not supposed to free it yourself anymore.
+ *
+ * Note that if you're using a #HildonAppMenu rather than a #GtkMenu
+ * you should use hildon_window_set_app_menu() instead.
+ **/
+void
+hildon_window_set_main_menu (HildonWindow* self,
+                            GtkMenu     * menu)
+{
+    HildonWindowPrivate *priv;
+    GtkAccelGroup *accel_group;
+
+    g_return_if_fail (HILDON_IS_WINDOW (self));
+
+    priv = HILDON_WINDOW_GET_PRIVATE (self);
+
+    if (priv->menu != NULL)
+    {
+       accel_group = gtk_menu_get_accel_group (priv->menu);
+       if (accel_group != NULL)
+           gtk_window_remove_accel_group (GTK_WINDOW (self), accel_group);
+
+        gtk_menu_detach (priv->menu);
+        g_object_unref (priv->menu);
+    }
+
+    priv->menu = menu;
+    if (priv->menu != NULL)
+    {
+        gtk_widget_set_name (GTK_WIDGET (priv->menu), "menu_force_with_corners");
+        gtk_menu_attach_to_widget (priv->menu, GTK_WIDGET (self), &detach_menu_func);
+        g_object_ref (priv->menu);
+
+       accel_group = gtk_menu_get_accel_group (priv->menu);
+       if (accel_group != NULL)
+           hildon_window_add_accel_group (self, accel_group);
+    }
 }
 
 /**
  * hildon_window_set_menu:
  * @self: A #HildonWindow
  * @menu: The #GtkMenu to be used for this #HildonWindow
- * 
+ *
  * Sets the menu to be used for this window. This menu overrides
  * a program-wide menu that may have been set with
- * hildon_program_set_common_menu. Pass NULL to remove the current
+ * hildon_program_set_common_menu(). Pass %NULL to remove the current
  * menu. HildonWindow takes ownership of the passed menu and you're
  * not supposed to free it yourself anymore.
- **/ 
+ *
+ * Note: hildon_window_set_menu() calls gtk_widget_show_all() for the
+ * #GtkMenu. To pass control about visibility to the application
+ * developer, hildon_window_set_main_menu() was introduced, which
+ * doesn't do this.
+ *
+ * Deprecated: Hildon 2.2: use hildon_window_set_main_menu()
+ **/
 void
 hildon_window_set_menu                          (HildonWindow *self, 
                                                  GtkMenu *menu)
 {
-    HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
+    HildonWindowPrivate *priv;
 
     g_return_if_fail (HILDON_IS_WINDOW (self));
-    g_assert (priv);
 
-    if (priv->menu != NULL) {
-        gtk_menu_detach (GTK_MENU (priv->menu));
-        g_object_unref (priv->menu);
-    }
+    hildon_window_set_main_menu (self, menu);
+
+    priv = HILDON_WINDOW_GET_PRIVATE (self);
 
-    priv->menu = (menu != NULL) ? GTK_WIDGET (menu) : NULL;
-    if (priv->menu != NULL) {
-        gtk_widget_set_name (priv->menu, "menu_force_with_corners");
-        gtk_menu_attach_to_widget (GTK_MENU (priv->menu), GTK_WIDGET (self), &detach_menu_func);
-        g_object_ref (GTK_MENU (priv->menu));
+    if (priv->menu != NULL)
         gtk_widget_show_all (GTK_WIDGET (priv->menu));
-    }
 }
 
 /**
  * hildon_window_get_is_topmost:
  * @self: A #HildonWindow
- * 
- * Return value: Whether or not the #HildonWindow is currenltly activated
- * by the window manager.
+ *
+ * Returns whether the #HildonWindow is currenty activated by the
+ * window manager.
+ *
+ * Return value: %TRUE if @self is currently activated, %FALSE otherwise.
  **/
 gboolean
 hildon_window_get_is_topmost                    (HildonWindow *self)
 {
-    HildonWindowPrivate *priv = HILDON_WINDOW_GET_PRIVATE (self);
+    HildonWindowPrivate *priv;
 
     g_return_val_if_fail (HILDON_IS_WINDOW (self), FALSE);
-    g_assert (priv);
 
+    priv = HILDON_WINDOW_GET_PRIVATE (self);
     return priv->is_topmost;
 }
 
+/**
+ * hildon_window_set_app_menu:
+ * @self: a #HildonWindow
+ * @menu: a #HildonAppMenu to be used for this window
+ *
+ * Sets the menu to be used for this window. Pass %NULL to remove the
+ * current menu. Any reference to a previous menu will be dropped.
+ * #HildonWindow takes ownership of the passed menu and
+ * you're not supposed to free it yourself anymore.
+ *
+ * Note that if you're using a #GtkMenu rather than a #HildonAppMenu
+ * you should use hildon_window_set_main_menu() instead.
+ *
+ * Since: 2.2
+ **/
+void
+hildon_window_set_app_menu                      (HildonWindow  *self,
+                                                 HildonAppMenu *menu)
+{
+    HildonWindowPrivate *priv;
+    HildonAppMenu *old_menu;
+
+    g_return_if_fail (HILDON_IS_WINDOW (self));
+    g_return_if_fail (!menu || HILDON_IS_APP_MENU (menu));
+    priv = HILDON_WINDOW_GET_PRIVATE (self);
+
+    old_menu = priv->app_menu;
+
+    /* Add new menu */
+    priv->app_menu = menu;
+    if (menu)
+        g_object_ref_sink (menu);
+
+    /* Unref old menu */
+    if (old_menu)
+        g_object_unref (old_menu);
+}
+
+/**
+ * hildon_window_get_app_menu:
+ * @self: a #HildonWindow
+ *
+ * Returns the #HildonAppMenu assigned to @self, or %NULL if it's
+ * unset. Note that the window is still the owner of the menu.
+ *
+ * Note that if you're using a #GtkMenu rather than a #HildonAppMenu
+ * you should use hildon_window_get_main_menu() instead.
+ *
+ * Returns: a #HildonAppMenu
+ *
+ * Since: 2.2
+ **/
+HildonAppMenu *
+hildon_window_get_app_menu                      (HildonWindow *self)
+{
+    HildonWindowPrivate *priv;
+
+    g_return_val_if_fail (HILDON_IS_WINDOW (self), NULL);
+
+    priv = HILDON_WINDOW_GET_PRIVATE (self);
+
+    return priv->app_menu;
+}