[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[SCM] LibreOffice packaging repository branch, ubuntu-quantal-3.6, updated. libreoffice_3.6.1_rc2-1-64-gaef91e7



The following commit has been merged in the ubuntu-quantal-3.6 branch:
commit aef91e751ca9e7bc1ba991db276de72a05fc5a9f
Author: Bjoern Michaelsen <bjoern.michaelsen@canonical.com>
Date:   Tue Aug 28 01:32:53 2012 +0200

    update unitymenus patch, add patch generator script

diff --git a/patches/unitymenus.diff b/patches/unitymenus.diff
index 861a9ff..8d7114e 100644
--- a/patches/unitymenus.diff
+++ b/patches/unitymenus.diff
@@ -1,10 +1,37 @@
-commit 5e07b8e29fc3f0cf61edf8478e686f593c89105b
-Author: Antonio Fernandez <antonio.fernandez@aentos.es>
-Date:   Mon Aug 20 09:44:24 2012 +0100
+commit e9db2efab56f37b59fc10da18af73d9cf09846d8
+Author: Antonio Fernández <antonio.fernandez@aentos.es>
+Date:   Mon Aug 27 14:38:15 2012 +0100
 
-    Actions are generated during the item info filling.
+    Radio button action data is now properly set.
     
-    Change-Id: I79be19a8ca565da9ca9bb8b31efc4e6e1463ba31
+    Change-Id: Icbd44308631278e6ab65cef123d4d32befff87fc
+ framework/inc/classes/menumanager.hxx         |   22 +-
+ framework/inc/uielement/menubarmanager.hxx    |   24 +-
+ framework/inc/uielement/menubarmerger.hxx     |   16 +-
+ framework/inc/uielement/menubarwrapper.hxx    |    1 +
+ framework/source/classes/menumanager.cxx      |   16 +-
+ framework/source/uielement/menubarmanager.cxx |   40 +-
+ framework/source/uielement/menubarmerger.cxx  |   18 +-
+ framework/source/uielement/menubarwrapper.cxx |   16 +
+ vcl/Library_vcl.mk                            |    1 +
+ vcl/Library_vclplug_gtk.mk                    |   11 +-
+ vcl/Library_vclplug_gtk3.mk                   |    3 +
+ vcl/inc/salmenu.hxx                           |    7 +-
+ vcl/inc/unx/gtk/gloactiongroup.h              |   99 ++++
+ vcl/inc/unx/gtk/glomenu.h                     |  114 +++++
+ vcl/inc/unx/gtk/gtkinst.hxx                   |    4 +
+ vcl/inc/unx/gtk/gtksalmenu.hxx                |  108 ++++
+ vcl/inc/unx/salmenu.h                         |    8 +-
+ vcl/inc/vcl/menu.hxx                          |  156 ++++--
+ vcl/source/window/menu.cxx                    |   21 +-
+ vcl/unx/gtk/app/gtkinst.cxx                   |   29 ++
+ vcl/unx/gtk/window/gloactiongroup.cxx         |  441 +++++++++++++++++
+ vcl/unx/gtk/window/glomenu.cxx                |  488 ++++++++++++++++++
+ vcl/unx/gtk/window/gtksalmenu.cxx             |  660 +++++++++++++++++++++++++
+ vcl/unx/gtk3/window/gtk3gloactiongroup.cxx    |    2 +
+ vcl/unx/gtk3/window/gtk3glomenu.cxx           |    2 +
+ vcl/unx/gtk3/window/gtk3gtksalmenu.cxx        |    2 +
+ 26 files changed, 2199 insertions(+), 110 deletions(-)
 diff --git a/framework/inc/classes/menumanager.hxx b/framework/inc/classes/menumanager.hxx
 index 3ac4588..56ecc90 100644
 --- a/framework/inc/classes/menumanager.hxx
@@ -657,10 +684,33 @@ index 1d14a7e..2f8d680 100644
      // but rectangle cannot be determined
 diff --git a/vcl/inc/unx/gtk/gloactiongroup.h b/vcl/inc/unx/gtk/gloactiongroup.h
 new file mode 100644
-index 0000000..852a40f
+index 0000000..4392e18
 --- /dev/null
 +++ b/vcl/inc/unx/gtk/gloactiongroup.h
-@@ -0,0 +1,63 @@
+@@ -0,0 +1,99 @@
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++
++/*
++ * Copyright © 2011 Canonical Ltd.
++ *
++ * 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; either version 2 of the
++ * licence, 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
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
++ * USA.
++ *
++ * Author: Antonio Fernández <antonio.fernandez@aentos.es>
++ */
++
 +#ifndef GLOACTIONGROUP_H
 +#define GLOACTIONGROUP_H
 +
@@ -709,10 +759,21 @@ index 0000000..852a40f
 +                                                             const gchar    *action_name,
 +                                                             gpointer        action_info);
 +
++void                g_lo_action_group_insert_stateful       (GLOActionGroup     *group,
++                                                             const gchar        *action_name,
++                                                             gpointer            action_info,
++                                                             const GVariantType *parameter_type,
++                                                             const GVariantType *state_type,
++                                                             GVariant           *state_hint,
++                                                             GVariant           *state);
++
 +void                g_lo_action_group_set_action_enabled    (GLOActionGroup *group,
 +                                                             const gchar    *action_name,
 +                                                             gboolean        enabled);
 +
++gpointer            g_lo_action_group_get_action_item       (GLOActionGroup *group,
++                                                             const gchar    *action_name);
++
 +void                g_lo_action_group_remove                (GLOActionGroup *group,
 +                                                             const gchar    *action_name);
 +
@@ -724,12 +785,16 @@ index 0000000..852a40f
 +G_END_DECLS
 +
 +#endif // GLOACTIONGROUP_H
++
++/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
 diff --git a/vcl/inc/unx/gtk/glomenu.h b/vcl/inc/unx/gtk/glomenu.h
 new file mode 100644
-index 0000000..db2f034
+index 0000000..21c048f
 --- /dev/null
 +++ b/vcl/inc/unx/gtk/glomenu.h
-@@ -0,0 +1,134 @@
+@@ -0,0 +1,114 @@
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++
 +/*
 + * Copyright © 2011 Canonical Ltd.
 + *
@@ -748,7 +813,7 @@ index 0000000..db2f034
 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
 + * USA.
 + *
-+ * Author: Ryan Lortie <desrt@desrt.ca>
++ * Author: Antonio Fernández <antonio.fernandez@aentos.es>
 + */
 +
 +#ifndef __G_LO_MENU_H__
@@ -756,6 +821,8 @@ index 0000000..db2f034
 +
 +#include <gio/gio.h>
 +
++#define G_LO_MENU_ATTRIBUTE_ACCELERATOR     "accel"
++
 +G_BEGIN_DECLS
 +
 +#define G_TYPE_LO_MENU          (g_lo_menu_get_type ())
@@ -764,106 +831,82 @@ index 0000000..db2f034
 +#define G_IS_LO_MENU(inst)      (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
 +                                 G_TYPE_LO_MENU))
 +
-+#define G_TYPE_LO_MENU_ITEM     (g_lo_menu_item_get_type ())
-+#define G_LO_MENU_ITEM(inst)    (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
-+                                 G_TYPE_LO_MENU_ITEM, GLOMenuItem))
-+#define G_IS_LO_MENU_ITEM(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
-+                                 G_TYPE_LO_MENU_ITEM))
++typedef struct _GLOMenu GLOMenu;
 +
-+typedef struct _GLOMenuItem GLOMenuItem;
-+typedef struct _GLOMenu     GLOMenu;
++class GtkSalMenuItem;
 +
 +GLIB_AVAILABLE_IN_2_32
-+GType           g_lo_menu_get_type                          (void) G_GNUC_CONST;
++GType       g_lo_menu_get_type                                          (void) G_GNUC_CONST;
 +GLIB_AVAILABLE_IN_2_32
-+GLOMenu *       g_lo_menu_new                               (void);
-+
-+void            g_lo_menu_freeze                            (GLOMenu     *menu);
-+
-+void            g_lo_menu_insert_item                       (GLOMenu     *menu,
-+                                                             gint         position,
-+                                                             GLOMenuItem *item);
-+void            g_lo_menu_prepend_item                      (GLOMenu     *menu,
-+                                                             GLOMenuItem *item);
-+void            g_lo_menu_append_item                       (GLOMenu     *menu,
-+                                                             GLOMenuItem *item);
-+void            g_lo_menu_remove                            (GLOMenu     *menu,
-+                                                             gint         position);
-+
-+void            g_lo_menu_insert                            (GLOMenu     *menu,
-+                                                             gint         position,
-+                                                             const gchar *label,
-+                                                             const gchar *detailed_action);
-+void            g_lo_menu_prepend                           (GLOMenu     *menu,
-+                                                             const gchar *label,
-+                                                             const gchar *detailed_action);
-+void            g_lo_menu_append                            (GLOMenu     *menu,
-+                                                             const gchar *label,
-+                                                             const gchar *detailed_action);
-+
-+void            g_lo_menu_insert_section                    (GLOMenu     *menu,
-+                                                             gint         position,
-+                                                             const gchar *label,
-+                                                             GMenuModel  *section);
-+void            g_lo_menu_prepend_section                   (GLOMenu     *menu,
-+                                                             const gchar *label,
-+                                                             GMenuModel  *section);
-+void            g_lo_menu_append_section                    (GLOMenu     *menu,
-+                                                             const gchar *label,
-+                                                             GMenuModel  *section);
-+
-+void            g_lo_menu_insert_submenu                    (GLOMenu     *menu,
-+                                                             gint         position,
-+                                                             const gchar *label,
-+                                                             GMenuModel  *submenu);
-+void            g_lo_menu_prepend_submenu                   (GLOMenu     *menu,
-+                                                             const gchar *label,
-+                                                             GMenuModel  *submenu);
-+void            g_lo_menu_append_submenu                    (GLOMenu     *menu,
-+                                                             const gchar *label,
-+                                                             GMenuModel  *submenu);
-+
-+
-+GType           g_lo_menu_item_get_type                     (void) G_GNUC_CONST;
-+GLOMenuItem *   g_lo_menu_item_new                          (const gchar *label,
-+                                                             const gchar *detailed_action);
-+
-+GLOMenuItem *   g_lo_menu_item_new_submenu                  (const gchar *label,
-+                                                             GMenuModel  *submenu);
-+
-+GLOMenuItem *   g_lo_menu_item_new_section                  (const gchar *label,
-+                                                             GMenuModel  *section);
-+
-+void            g_lo_menu_item_set_attribute_value          (GLOMenuItem *menu_item,
-+                                                             const gchar *attribute,
-+                                                             GVariant    *value);
-+void            g_lo_menu_item_set_attribute                (GLOMenuItem *menu_item,
-+                                                             const gchar *attribute,
-+                                                             const gchar *format_string,
-+                                                             ...);
-+void            g_lo_menu_item_set_link                     (GLOMenuItem *menu_item,
-+                                                             const gchar *link,
-+                                                             GMenuModel  *model);
-+void            g_lo_menu_item_set_label                    (GLOMenuItem *menu_item,
-+                                                             const gchar *label);
-+void            g_lo_menu_item_set_submenu                  (GLOMenuItem *menu_item,
-+                                                             GMenuModel  *submenu);
-+void            g_lo_menu_item_set_section                  (GLOMenuItem *menu_item,
-+                                                             GMenuModel  *section);
-+void            g_lo_menu_item_set_action_and_target_value  (GLOMenuItem *menu_item,
-+                                                             const gchar *action,
-+                                                             GVariant    *target_value);
-+void            g_lo_menu_item_set_action_and_target        (GLOMenuItem *menu_item,
-+                                                             const gchar *action,
-+                                                             const gchar *format_string,
-+                                                             ...);
-+void            g_lo_menu_item_set_detailed_action          (GLOMenuItem *menu_item,
-+                                                             const gchar *detailed_action);
++GLOMenu *   g_lo_menu_new                                               (void);
++
++void        g_lo_menu_insert                                            (GLOMenu     *menu,
++                                                                         gint         position,
++                                                                         const char  *label);
++
++void        g_lo_menu_insert_in_section                                 (GLOMenu     *menu,
++                                                                         gint         section,
++                                                                         gint         position,
++                                                                         const gchar *label);
++
++void        g_lo_menu_new_section                                       (GLOMenu     *menu,
++                                                                         gint         position,
++                                                                         const gchar *label);
++
++void        g_lo_menu_insert_section                                    (GLOMenu     *menu,
++                                                                         gint         position,
++                                                                         const gchar *label,
++                                                                         GMenuModel  *section);
++
++GLOMenu *   g_lo_menu_get_section                                       (GLOMenu     *menu,
++                                                                         gint         section);
++
++void        g_lo_menu_remove                                            (GLOMenu     *menu,
++                                                                         gint         position);
++
++void        g_lo_menu_remove_from_section                               (GLOMenu     *menu,
++                                                                         gint         section,
++                                                                         gint         position);
++
++void        g_lo_menu_set_label                                         (GLOMenu     *menu,
++                                                                         gint         position,
++                                                                         const gchar *label);
++
++void        g_lo_menu_set_label_to_item_in_section                      (GLOMenu     *menu,
++                                                                         gint         section,
++                                                                         gint         position,
++                                                                         const gchar *label);
++
++gchar *     g_lo_menu_get_label_from_item_in_section                    (GLOMenu     *menu,
++                                                                         gint         section,
++                                                                         gint         position);
++
++void        g_lo_menu_set_action_and_target_value                       (GLOMenu     *menu,
++                                                                         gint         position,
++                                                                         const gchar *command,
++                                                                         GVariant    *target_value);
++
++void        g_lo_menu_set_action_and_target_value_to_item_in_section    (GLOMenu     *menu,
++                                                                         gint         section,
++                                                                         gint         position,
++                                                                         const gchar *command,
++                                                                         GVariant    *target_value);
++
++void        g_lo_menu_set_accelerator_to_item_in_section                (GLOMenu     *menu,
++                                                                         gint         section,
++                                                                         gint         position,
++                                                                         const gchar *accelerator);
++
++void        g_lo_menu_set_submenu_to_item_in_section                    (GLOMenu     *menu,
++                                                                         gint         section,
++                                                                         gint         position,
++                                                                         GMenuModel  *submenu);
 +
 +G_END_DECLS
 +
 +#endif /* __G_LO_MENU_H__ */
 +
++/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
 diff --git a/vcl/inc/unx/gtk/gtkinst.hxx b/vcl/inc/unx/gtk/gtkinst.hxx
 index 89743ca..5ec226e 100644
 --- a/vcl/inc/unx/gtk/gtkinst.hxx
@@ -881,37 +924,32 @@ index 89743ca..5ec226e 100644
      virtual SalVirtualDevice*   CreateVirtualDevice( SalGraphics*,
 diff --git a/vcl/inc/unx/gtk/gtksalmenu.hxx b/vcl/inc/unx/gtk/gtksalmenu.hxx
 new file mode 100644
-index 0000000..c57d39d
+index 0000000..324b430
 --- /dev/null
 +++ b/vcl/inc/unx/gtk/gtksalmenu.hxx
-@@ -0,0 +1,123 @@
+@@ -0,0 +1,108 @@
 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-+/*************************************************************************
-+ *
-+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-+ *
-+ * Copyright 2000, 2010 Oracle and/or its affiliates.
-+ *
-+ * OpenOffice.org - a multi-platform office productivity suite
-+ *
-+ * This file is part of OpenOffice.org.
++
++/*
++ * Copyright © 2011 Canonical Ltd.
 + *
-+ * OpenOffice.org is free software: you can redistribute it and/or modify
-+ * it under the terms of the GNU Lesser General Public License version 3
-+ * only, as published by the Free Software Foundation.
++ * 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; either version 2 of the
++ * licence, or (at your option) any later version.
 + *
-+ * OpenOffice.org is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU Lesser General Public License version 3 for more details
-+ * (a copy is included in the LICENSE file that accompanied this code).
++ * This library is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Lesser General Public License for more details.
 + *
-+ * You should have received a copy of the GNU Lesser General Public License
-+ * version 3 along with OpenOffice.org.  If not, see
-+ * <http://www.openoffice.org/license.html>
-+ * for a copy of the LGPLv3 License.
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
++ * USA.
 + *
-+ ************************************************************************/
++ * Author: Antonio Fernández <antonio.fernandez@aentos.es>
++ */
 +
 +#ifndef GTKSALMENU_HXX
 +#define GTKSALMENU_HXX
@@ -926,34 +964,25 @@ index 0000000..c57d39d
 +#include "glomenu.h"
 +#include "gloactiongroup.h"
 +
-+#include <vector>
-+
 +
++class MenuItemList;
 +class GtkSalMenuItem;
 +
 +class GtkSalMenu : public SalMenu
 +{
 +private:
++    std::vector< GtkSalMenuItem* >  maItems;
++
 +    sal_Bool                        mbMenuBar;
 +    Menu*                           mpVCLMenu;
 +    GtkSalMenu*                     mpParentSalMenu;
 +    const GtkSalFrame*              mpFrame;
 +
-+    std::vector< GMenuModel* >      maSections;
-+    std::vector< GtkSalMenuItem* >  maItems;
-+
-+    // DBus attributes
-+    GDBusConnection*                pSessionBus;
-+    sal_Int32                       mMenubarId;
-+    sal_Int32                       mActionGroupId;
-+
 +    // GMenuModel and GActionGroup attributes
 +    GMenuModel*                     mpMenuModel;
-+    GMenuModel*                     mpCurrentSection;
 +    GActionGroup*                   mpActionGroup;
 +
-+    GtkSalMenuItem* GetSalMenuItem( sal_uInt16 nId );
-+    sal_Int16      GetSectionNumber( GMenuModel* pSection );
++    void            GetItemSectionAndPosition( unsigned nPos, unsigned *insertSection, unsigned *insertPos );
 +
 +public:
 +    GtkSalMenu( sal_Bool bMenuBar );
@@ -980,7 +1009,6 @@ index 0000000..c57d39d
 +    virtual Menu*               GetMenu() { return mpVCLMenu; }
 +    virtual GtkSalMenu*         GetParentSalMenu() { return mpParentSalMenu; }
 +    virtual GMenuModel*         GetMenuModel() { return mpMenuModel; }
-+    virtual GMenuModel*         GetCurrentSection() { return mpCurrentSection; }
 +    virtual unsigned            GetItemCount() { return maItems.size(); }
 +    virtual GtkSalMenuItem*     GetItemAtPos( unsigned nPos ) { return maItems[ nPos ]; }
 +    virtual GActionGroup*       GetActionGroup() { return mpActionGroup; }
@@ -994,15 +1022,15 @@ index 0000000..c57d39d
 +
 +    sal_uInt16          mnId;               // Item ID
 +    MenuItemBits        mnBits;             // Item bits
-+    sal_uInt16          mnPos;              // Item position
-+    gchar*              maCommand;          // Item command
++    MenuItemType        mnType;             // Item type
 +    Menu*               mpVCLMenu;          // VCL Menu into which this MenuItem is inserted
 +    GtkSalMenu*         mpParentMenu;       // The menu in which this menu item is inserted
 +    GtkSalMenu*         mpSubMenu;          // Sub menu of this item (if defined)
-+    GMenuModel*         mpParentSection;    // Section where this item is added.
-+    GLOMenuItem*        mpMenuItem;         // The GMenuItem
-+    GVariantType*       mpStateType;        // A GVariantType with item state type
-+    GVariant*           mpState;            // A GVariant with current item state
++
++    // FIXME: Most of this info should be retrieved from the GMenuModel, but doing that crashes the application at the moment.
++    gchar*              maCommand;          // Item command
++    gchar*              maLabel;            // Item label
++    gchar*              maAccel;            // Item accelerator
 +};
 +
 +#endif // GTKSALMENU_HXX
@@ -1354,7 +1382,7 @@ index 3b4ac0d..e921805 100644
  // - MenuBar -
  // -----------
 diff --git a/vcl/unx/gtk/app/gtkinst.cxx b/vcl/unx/gtk/app/gtkinst.cxx
-index 845e2fc..2e00b34 100644
+index 845e2fc..6c9e198 100644
 --- a/vcl/unx/gtk/app/gtkinst.cxx
 +++ b/vcl/unx/gtk/app/gtkinst.cxx
 @@ -38,6 +38,7 @@
@@ -1393,7 +1421,7 @@ index 845e2fc..2e00b34 100644
 +void GtkInstance::DestroyMenuItem( SalMenuItem* pItem )
 +{
 +    (void)pItem;
-+//    delete pItem;
++    delete pItem;
 +//    OSL_ENSURE( pItem == 0, "DestroyMenu called with non-native menus" );
 +}
 +
@@ -1402,10 +1430,33 @@ index 845e2fc..2e00b34 100644
      GtkSalTimer *pTimer = new GtkSalTimer();
 diff --git a/vcl/unx/gtk/window/gloactiongroup.cxx b/vcl/unx/gtk/window/gloactiongroup.cxx
 new file mode 100644
-index 0000000..51bf2f0
+index 0000000..1a0e88f
 --- /dev/null
 +++ b/vcl/unx/gtk/window/gloactiongroup.cxx
-@@ -0,0 +1,295 @@
+@@ -0,0 +1,441 @@
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++
++/*
++ * Copyright © 2011 Canonical Ltd.
++ *
++ * 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; either version 2 of the
++ * licence, 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
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
++ * USA.
++ *
++ * Author: Antonio Fernández <antonio.fernandez@aentos.es>
++ */
++
 +#include <unx/gtk/gloactiongroup.h>
 +
 +#include <unx/gtk/gtkinst.hxx>
@@ -1418,6 +1469,84 @@ index 0000000..51bf2f0
 +
 +using namespace std;
 +
++/*
++ * GLOAction
++ */
++
++#define G_TYPE_LO_ACTION                                (g_lo_action_get_type ())
++#define G_LO_ACTION(inst)                               (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
++                                                         G_TYPE_LO_ACTION, GLOAction))
++#define G_IS_LO_ACTION(inst)                            (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
++                                                         G_TYPE_LO_ACTION))
++
++struct _GLOAction
++{
++    GObject         parent_instance;
++
++    GtkSalMenuItem* item;               // A pointer to the menu item.
++    gboolean        enabled;            // TRUE if action is enabled, FALSE otherwise.
++    GVariantType*   parameter_type;     // A GVariantType with the action parameter type.
++    GVariantType*   state_type;         // A GVariantType with item state type
++    GVariant*       state_hint;         // A GVariant with state hints.
++    GVariant*       state;              // A GVariant with current item state
++};
++
++typedef GObjectClass GLOActionClass;
++typedef struct _GLOAction GLOAction;
++
++G_DEFINE_TYPE (GLOAction, g_lo_action, G_TYPE_OBJECT);
++
++GLOAction*
++g_lo_action_new (void)
++{
++    return G_LO_ACTION (g_object_new (G_TYPE_LO_ACTION, NULL));
++}
++
++static void
++g_lo_action_init (GLOAction *action)
++{
++    action->item = NULL;
++    action->enabled = TRUE;
++    action->parameter_type = NULL;
++    action->state_type = NULL;
++    action->state_hint = NULL;
++    action->state = NULL;
++}
++
++static void
++g_lo_action_finalize (GObject *object)
++{
++    GLOAction* action = G_LO_ACTION(object);
++
++    action->item = NULL;
++
++    if (action->parameter_type)
++        g_variant_type_free (action->parameter_type);
++
++    if (action->state_type)
++        g_variant_type_free (action->state_type);
++
++    if (action->state_hint)
++        g_variant_unref (action->state_hint);
++
++    if (action->state)
++        g_variant_unref (action->state);
++
++    G_OBJECT_CLASS (g_lo_action_parent_class)->finalize (object);
++}
++
++static void
++g_lo_action_class_init (GLOActionClass *klass)
++{
++    GObjectClass *object_class = G_OBJECT_CLASS(klass);
++
++    object_class->finalize = g_lo_action_finalize;
++}
++
++/*
++ * GLOActionGroup
++ */
++
 +struct _GLOActionGroupPrivate
 +{
 +    GHashTable *table;  /* string -> GtkSalMenuItem* */
@@ -1460,35 +1589,31 @@ index 0000000..51bf2f0
 +                                GVariant           **state_hint,
 +                                GVariant           **state)
 +{
-+    GLOActionGroup *loGroup = G_LO_ACTION_GROUP (group);
-+    GtkSalMenuItem* item_info;
++    GLOActionGroup *lo_group = G_LO_ACTION_GROUP (group);
++    GLOAction* action;
 +
-+    item_info = static_cast< GtkSalMenuItem* >( g_hash_table_lookup (loGroup->priv->table, action_name) );
++    action = G_LO_ACTION (g_hash_table_lookup (lo_group->priv->table, action_name));
 +
-+    if (item_info == NULL)
++    if (action == NULL)
 +        return FALSE;
 +
-+    if (enabled) {
-+        sal_Bool bEnabled = item_info->mpVCLMenu->IsItemEnabled( item_info->mnId );
-+        *enabled = (bEnabled) ? TRUE : FALSE;
-+    }
++    if (enabled)
++        *enabled = action->enabled;
 +
-+    if (parameter_type)
-+        *parameter_type = NULL;
++    if (parameter_type) {
++        *parameter_type = action->parameter_type;
++    }
 +
-+    if (state_type)
-+        *state_type = item_info->mpStateType;
++    if (state_type) {
++        *state_type = action->state_type;
++    }
 +
-+    if (state_hint)
-+        *state_hint = NULL;
++    if (state_hint) {
++        *state_hint = (action->state_hint) ? g_variant_ref(action->state_hint) : NULL;
++    }
 +
 +    if (state) {
-+        if (item_info->mpState) {
-+            g_variant_ref( item_info->mpState );
-+            *state = item_info->mpState;
-+        } else {
-+            *state = NULL;
-+        }
++        *state = (action->state) ? g_variant_ref(action->state) : NULL;
 +    }
 +
 +    return TRUE;
@@ -1503,24 +1628,23 @@ index 0000000..51bf2f0
 +        return;
 +
 +    GLOActionGroup* lo_group = G_LO_ACTION_GROUP (group);
-+    GtkSalMenuItem* item_info;
 +
-+    item_info = static_cast<GtkSalMenuItem*>( g_hash_table_lookup (lo_group->priv->table, action_name) );
++    GLOAction* action = G_LO_ACTION (g_hash_table_lookup (lo_group->priv->table, action_name));
 +
-+    if (!item_info)
++    if (action == NULL)
 +        return;
 +
-+    if (!item_info->mpStateType) {
-+        item_info->mpStateType = g_variant_type_copy(g_variant_get_type(value));
-+    }
++    if (action->state_type == NULL)
++        action->state_type = g_variant_type_copy(g_variant_get_type(value));
 +
-+    if (g_variant_is_of_type(value, item_info->mpStateType)) {
-+        if (item_info->mpState)
-+            g_variant_unref(item_info->mpState);
++    g_return_if_fail (g_variant_is_of_type(value, action->state_type) == TRUE);
 +
-+        item_info->mpState = g_variant_new_variant(value);
-+        g_action_group_action_state_changed(group, action_name, value);
-+    }
++    if (action->state)
++        g_variant_unref(action->state);
++
++    action->state = g_variant_take_ref(value);
++
++    g_action_group_action_state_changed(group, action_name, value);
 +}
 +
 +static void
@@ -1528,16 +1652,15 @@ index 0000000..51bf2f0
 +                            const gchar  *action_name,
 +                            GVariant     *parameter)
 +{
-+    GLOActionGroup *loGroup = G_LO_ACTION_GROUP (group);
-+    GtkSalMenuItem *pSalMenuItem;
++    GTK_YIELD_GRAB();
 +
-+    pSalMenuItem = static_cast< GtkSalMenuItem* >( g_hash_table_lookup (loGroup->priv->table, action_name) );
++    GLOActionGroup *loGroup = G_LO_ACTION_GROUP (group);
++    GLOAction* action = G_LO_ACTION (g_hash_table_lookup (loGroup->priv->table, action_name));
++    GtkSalMenuItem *pSalMenuItem = action->item;
 +
 +    if (pSalMenuItem == NULL || pSalMenuItem->mpSubMenu )
 +        return;
 +
-+    GTK_YIELD_GRAB();
-+
 +    const GtkSalFrame *pFrame = pSalMenuItem->mpParentMenu ? pSalMenuItem->mpParentMenu->GetFrame() : NULL;
 +
 +    if ( pFrame && !pFrame->GetParent() ) {
@@ -1585,18 +1708,44 @@ index 0000000..51bf2f0
 +                          const gchar    *action_name,
 +                          gpointer        action_info)
 +{
-+    g_return_if_fail (G_IS_LO_ACTION_GROUP (group));
++    g_lo_action_group_insert_stateful (group, action_name, action_info, NULL, NULL, NULL, NULL);
++}
 +
-+    gpointer old_action;
++void
++g_lo_action_group_insert_stateful (GLOActionGroup     *group,
++                                   const gchar        *action_name,
++                                   gpointer            action_info,
++                                   const GVariantType *parameter_type,
++                                   const GVariantType *state_type,
++                                   GVariant           *state_hint,
++                                   GVariant           *state)
++{
++    g_return_if_fail (G_IS_LO_ACTION_GROUP (group));
 +
-+    old_action = g_hash_table_lookup (group->priv->table, action_name);
++    GLOAction* old_action = G_LO_ACTION (g_hash_table_lookup (group->priv->table, action_name));
 +
-+    if (old_action != action_info)
++    if (old_action == NULL || old_action->item != action_info)
 +    {
 +        if (old_action != NULL)
 +            g_action_group_action_removed (G_ACTION_GROUP (group), action_name);
 +
-+        g_hash_table_insert (group->priv->table, g_strdup (action_name), action_info);
++        GLOAction* action = g_lo_action_new();
++
++        g_hash_table_insert (group->priv->table, g_strdup (action_name), action);
++
++        action->item = static_cast< GtkSalMenuItem* >( action_info );
++
++        if (parameter_type)
++            action->parameter_type = (GVariantType*) parameter_type;
++
++        if (state_type)
++            action->state_type = (GVariantType*) state_type;
++
++        if (state_hint)
++            action->state_hint = g_variant_take_ref (state_hint);
++
++        if (state)
++            action->state = g_variant_take_ref (state);
 +
 +        g_action_group_action_added (G_ACTION_GROUP (group), action_name);
 +    }
@@ -1605,9 +1754,9 @@ index 0000000..51bf2f0
 +static void
 +g_lo_action_group_finalize (GObject *object)
 +{
-+    GLOActionGroup *loGroup = G_LO_ACTION_GROUP (object);
++    GLOActionGroup *lo_group = G_LO_ACTION_GROUP (object);
 +
-+    g_hash_table_unref (loGroup->priv->table);
++    g_hash_table_unref (lo_group->priv->table);
 +
 +    G_OBJECT_CLASS (g_lo_action_group_parent_class)->finalize (object);
 +}
@@ -1619,7 +1768,7 @@ index 0000000..51bf2f0
 +                                                 G_TYPE_LO_ACTION_GROUP,
 +                                                 GLOActionGroupPrivate);
 +    group->priv->table = g_hash_table_new_full (g_str_hash, g_str_equal,
-+                                                  g_free, NULL );
++                                                  g_free, g_object_unref);
 +}
 +
 +static void
@@ -1652,13 +1801,31 @@ index 0000000..51bf2f0
 +                                      const gchar    *action_name,
 +                                      gboolean        enabled)
 +{
-+    cout << __FUNCTION__ << " - " << action_name << endl;
 +    g_return_if_fail (G_IS_LO_ACTION_GROUP (group));
++    g_return_if_fail (action_name != NULL);
++
++    GLOAction* action = G_LO_ACTION (g_hash_table_lookup (group->priv->table, action_name));
++
++    if (action == NULL)
++        return;
++
++    action->enabled = enabled;
 +
 +    g_action_group_action_enabled_changed(G_ACTION_GROUP(group),
 +                                          action_name,
 +                                          enabled);
++}
++
++gpointer
++g_lo_action_group_get_action_item (GLOActionGroup *group,
++                                   const gchar    *action_name)
++{
++    g_return_val_if_fail (G_IS_LO_ACTION_GROUP (group), NULL);
++    g_return_val_if_fail (action_name != NULL, NULL);
 +
++    GLOAction* action = G_LO_ACTION (g_hash_table_lookup (group->priv->table, action_name));
++
++    return (action != NULL) ? action->item : NULL;
 +}
 +
 +void
@@ -1679,7 +1846,12 @@ index 0000000..51bf2f0
 +{
 +    g_return_if_fail (G_IS_LO_ACTION_GROUP (group));
 +
-+    g_hash_table_remove_all(group->priv->table);
++    GList* keys = g_hash_table_get_keys (group->priv->table);
++
++    for (GList* element = g_list_first (keys); element != NULL; element = g_list_next (element))
++    {
++        g_lo_action_group_remove (group, (gchar*) element->data);
++    }
 +}
 +
 +void
@@ -1701,12 +1873,16 @@ index 0000000..51bf2f0
 +        g_lo_action_group_insert(output_group, (gchar*) key, value);
 +    }
 +}
++
++/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
 diff --git a/vcl/unx/gtk/window/glomenu.cxx b/vcl/unx/gtk/window/glomenu.cxx
 new file mode 100644
-index 0000000..7ada474
+index 0000000..77be471
 --- /dev/null
 +++ b/vcl/unx/gtk/window/glomenu.cxx
-@@ -0,0 +1,577 @@
+@@ -0,0 +1,488 @@
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++
 +/*
 + * Copyright © 2011 Canonical Ltd.
 + *
@@ -1725,51 +1901,84 @@ index 0000000..7ada474
 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
 + * USA.
 + *
-+ * Author: Ryan Lortie <desrt@desrt.ca>
++ * Author: Antonio Fernández <antonio.fernandez@aentos.es>
 + */
 +
 +#include <stdio.h>
 +#include <string.h>
 +
-+#include <unx/gtk/glomenu.h>
-+
-+
-+struct _GLOMenuItem
-+{
-+    GObject parent_instance;
-+
-+    GHashTable *attributes;
-+    GHashTable *links;
-+    gboolean    cow;
-+};
++#include <unx/gtk/gtksalmenu.hxx>
 +
-+typedef GObjectClass GLOMenuItemClass;
++#include <unx/gtk/glomenu.h>
 +
 +struct _GLOMenu
 +{
-+    GMenuModel parent_instance;
++    GMenuModel  parent_instance;
 +
-+    GArray   *items;
-+//    gboolean  mutable;
++    GArray      *items;
 +};
 +
 +typedef GMenuModelClass GLOMenuClass;
 +
-+G_DEFINE_TYPE (GLOMenu, g_lo_menu, G_TYPE_MENU_MODEL)
-+G_DEFINE_TYPE (GLOMenuItem, g_lo_menu_item, G_TYPE_OBJECT)
++G_DEFINE_TYPE (GLOMenu, g_lo_menu, G_TYPE_MENU_MODEL);
 +
 +struct item
 +{
-+    GHashTable *attributes;
-+    GHashTable *links;
++    GHashTable*     attributes;     // Item attributes.
++    GHashTable*     links;          // Item links.
 +};
 +
++
++static void
++g_lo_menu_struct_item_init (struct item *menu_item)
++{
++    menu_item->attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
++    menu_item->links = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
++}
++
++/* We treat attribute names the same as GSettings keys:
++ * - only lowercase ascii, digits and '-'
++ * - must start with lowercase
++ * - must not end with '-'
++ * - no consecutive '-'
++ * - not longer than 1024 chars
++ */
 +static gboolean
-+g_lo_menu_is_mutable (GMenuModel *model)
++valid_attribute_name (const gchar *name)
 +{
-+//    GMenu *menu = G_MENU (model);
++    gint i;
++
++    if (!g_ascii_islower (name[0]))
++        return FALSE;
++
++    for (i = 1; name[i]; i++)
++    {
++        if (name[i] != '-' &&
++                !g_ascii_islower (name[i]) &&
++                !g_ascii_isdigit (name[i]))
++            return FALSE;
++
++        if (name[i] == '-' && name[i + 1] == '-')
++            return FALSE;
++    }
++
++    if (name[i - 1] == '-')
++        return FALSE;
++
++    if (i > 1024)
++        return FALSE;
++
++    return TRUE;
++}
++
++/*
++ * GLOMenu
++ */
 +
-+//    return menu->mutable;
++static gboolean
++g_lo_menu_is_mutable (GMenuModel *model)
++{
++    // Menu is always mutable.
 +    return TRUE;
 +}
 +
@@ -1783,8 +1992,8 @@ index 0000000..7ada474
 +
 +static void
 +g_lo_menu_get_item_attributes (GMenuModel  *model,
-+                            gint         position,
-+                            GHashTable **table)
++                               gint         position,
++                               GHashTable **table)
 +{
 +    GLOMenu *menu = G_LO_MENU (model);
 +
@@ -1793,8 +2002,8 @@ index 0000000..7ada474
 +
 +static void
 +g_lo_menu_get_item_links (GMenuModel  *model,
-+                       gint         position,
-+                       GHashTable **table)
++                          gint         position,
++                          GHashTable **table)
 +{
 +    GLOMenu *menu = G_LO_MENU (model);
 +
@@ -1802,46 +2011,41 @@ index 0000000..7ada474
 +}
 +
 +void
-+g_lo_menu_insert_item (GLOMenu     *menu,
-+                    gint       position,
-+                    GLOMenuItem *item)
++g_lo_menu_insert (GLOMenu        *menu,
++                  gint            position,
++                  const gchar    *label)
 +{
-+    struct item new_item;
-+
 +    g_return_if_fail (G_IS_LO_MENU (menu));
-+    g_return_if_fail (G_IS_LO_MENU_ITEM (item));
 +
 +    if (position < 0 || position > (gint) menu->items->len)
 +        position = menu->items->len;
 +
-+    new_item.attributes = g_hash_table_ref (item->attributes);
-+    new_item.links = g_hash_table_ref (item->links);
-+    item->cow = TRUE;
++    struct item menu_item;
 +
-+    g_array_insert_val (menu->items, position, new_item);
-+    g_menu_model_items_changed (G_MENU_MODEL (menu), position, 0, 1);
-+}
++    g_lo_menu_struct_item_init(&menu_item);
 +
-+void
-+g_lo_menu_prepend_item (GLOMenu     *menu,
-+                     GLOMenuItem *item)
-+{
-+    g_lo_menu_insert_item (menu, 0, item);
-+}
++    g_array_insert_val (menu->items, position, menu_item);
 +
-+void
-+g_lo_menu_append_item (GLOMenu     *menu,
-+                    GLOMenuItem *item)
-+{
-+    g_lo_menu_insert_item (menu, -1, item);
++    g_lo_menu_set_label (menu, position, label);
++
++    g_menu_model_items_changed (G_MENU_MODEL (menu), position, 0, 1);
 +}
 +
 +void
-+g_lo_menu_freeze (GLOMenu *menu)
++g_lo_menu_insert_in_section (GLOMenu        *menu,
++                             gint            section,
++                             gint            position,
++                             const gchar    *label)
 +{
 +    g_return_if_fail (G_IS_LO_MENU (menu));
++    g_return_if_fail (0 <= section && section < (gint) menu->items->len);
++
++    GLOMenu *model = G_LO_MENU (G_MENU_MODEL_CLASS (g_lo_menu_parent_class)
++                                ->get_item_link (G_MENU_MODEL (menu), section, G_MENU_LINK_SECTION));
 +
-+//    menu->mutable = FALSE;
++    g_return_if_fail (model != NULL);
++
++    g_lo_menu_insert (model, position, label);
 +}
 +
 +GLOMenu *
@@ -1851,445 +2055,347 @@ index 0000000..7ada474
 +}
 +
 +void
-+g_lo_menu_insert (GLOMenu     *menu,
-+                  gint         position,
-+                  const gchar *label,
-+                  const gchar *detailed_action)
++g_lo_menu_set_attribute_value (GLOMenu     *menu,
++                               gint         position,
++                               const gchar *attribute,
++                               GVariant    *value)
 +{
-+    GLOMenuItem *menu_item;
++    g_return_if_fail (G_IS_LO_MENU (menu));
++    g_return_if_fail (attribute != NULL);
++    g_return_if_fail (valid_attribute_name (attribute));
 +
-+    menu_item = g_lo_menu_item_new (label, detailed_action);
-+    g_lo_menu_insert_item (menu, position, menu_item);
-+    g_object_unref (menu_item);
-+}
++    if (position >= menu->items->len)
++        return;
++
++    struct item menu_item = g_array_index (menu->items, struct item, position);
++
++    if (value != NULL)
++        g_hash_table_insert (menu_item.attributes, g_strdup (attribute), g_variant_ref_sink (value));
++    else
++        g_hash_table_remove (menu_item.attributes, attribute);
 +
-+void
-+g_lo_menu_prepend (GLOMenu     *menu,
-+                   const gchar *label,
-+                   const gchar *detailed_action)
-+{
-+    g_lo_menu_insert (menu, 0, label, detailed_action);
 +}
 +
 +void
-+g_lo_menu_append (GLOMenu     *menu,
-+                  const gchar *label,
-+                  const gchar *detailed_action)
++g_lo_menu_set_label (GLOMenu     *menu,
++                     gint         position,
++                     const gchar *label)
 +{
-+    g_lo_menu_insert (menu, -1, label, detailed_action);
++    g_return_if_fail (G_IS_LO_MENU (menu));
++
++    GVariant *value;
++
++    if (label != NULL)
++        value = g_variant_new_string (label);
++    else
++        value = NULL;
++
++    g_lo_menu_set_attribute_value (menu, position, G_MENU_ATTRIBUTE_LABEL, value);
 +}
 +
 +void
-+g_lo_menu_insert_section (GLOMenu     *menu,
-+                          gint         position,
-+                          const gchar *label,
-+                          GMenuModel  *section)
++g_lo_menu_set_label_to_item_in_section (GLOMenu     *menu,
++                                        gint         section,
++                                        gint         position,
++                                        const gchar *label)
 +{
-+    GLOMenuItem *menu_item;
++    g_return_if_fail (G_IS_LO_MENU (menu));
 +
-+    menu_item = g_lo_menu_item_new_section (label, section);
-+    g_lo_menu_insert_item (menu, position, menu_item);
-+    g_object_unref (menu_item);
++    GLOMenu *model = G_LO_MENU (G_MENU_MODEL_CLASS (g_lo_menu_parent_class)
++                                ->get_item_link (G_MENU_MODEL (menu), section, G_MENU_LINK_SECTION));
++
++    g_return_if_fail (model != NULL);
++
++    g_lo_menu_set_label (model, position, label);
++
++    // Notify the update.
++    g_menu_model_items_changed (G_MENU_MODEL (model), position, 1, 1);
 +}
 +
-+void
-+g_lo_menu_prepend_section (GLOMenu     *menu,
-+                           const gchar *label,
-+                           GMenuModel  *section)
++gchar *
++g_lo_menu_get_label_from_item_in_section (GLOMenu     *menu,
++                                          gint         section,
++                                          gint         position)
 +{
-+    g_lo_menu_insert_section (menu, 0, label, section);
-+}
++    g_return_val_if_fail (G_IS_LO_MENU (menu), NULL);
 +
-+void
-+g_lo_menu_append_section (GLOMenu     *menu,
-+                          const gchar *label,
-+                          GMenuModel  *section)
-+{
-+    g_lo_menu_insert_section (menu, -1, label, section);
-+}
++    GLOMenu *model = G_LO_MENU (G_MENU_MODEL_CLASS (g_lo_menu_parent_class)
++                                ->get_item_link (G_MENU_MODEL (menu), section, G_MENU_LINK_SECTION));
 +
-+void
-+g_lo_menu_insert_submenu (GLOMenu     *menu,
-+                          gint         position,
-+                          const gchar *label,
-+                          GMenuModel  *submenu)
-+{
-+    GLOMenuItem *menu_item;
++    g_return_val_if_fail (model != NULL, NULL);
 +
-+    menu_item = g_lo_menu_item_new_submenu (label, submenu);
-+    g_lo_menu_insert_item (menu, position, menu_item);
-+    g_object_unref (menu_item);
-+}
++    struct item menu_item = g_array_index (model->items, struct item, position);
 +
-+void
-+g_lo_menu_prepend_submenu (GLOMenu     *menu,
-+                           const gchar *label,
-+                           GMenuModel  *submenu)
-+{
-+    g_lo_menu_insert_submenu (menu, 0, label, submenu);
-+}
 +
-+void
-+g_lo_menu_append_submenu (GLOMenu     *menu,
-+                          const gchar *label,
-+                          GMenuModel  *submenu)
-+{
-+    g_lo_menu_insert_submenu (menu, -1, label, submenu);
-+}
 +
-+static void
-+g_lo_menu_clear_item (struct item *item)
-+{
-+    if (item->attributes != NULL)
-+        g_hash_table_unref (item->attributes);
-+    if (item->links != NULL)
-+        g_hash_table_unref (item->links);
++    GVariant *current_label = (GVariant*) g_hash_table_lookup (menu_item.attributes, G_MENU_ATTRIBUTE_LABEL);
++
++    if (current_label)
++        return (gchar*) g_variant_get_string (current_label, NULL);
++    else
++        return NULL;
 +}
 +
 +void
-+g_lo_menu_remove (GLOMenu *menu,
-+                  gint     position)
++g_lo_menu_set_action_and_target_value (GLOMenu     *menu,
++                                       gint         position,
++                                       const gchar *action,
++                                       GVariant    *target_value)
 +{
 +    g_return_if_fail (G_IS_LO_MENU (menu));
-+    g_return_if_fail (0 <= position && position < (gint) menu->items->len);
-+
-+    g_lo_menu_clear_item (&g_array_index (menu->items, struct item, position));
-+    g_array_remove_index (menu->items, position);
-+    g_menu_model_items_changed (G_MENU_MODEL (menu), position, 1, 0);
-+}
-+
-+static void
-+g_lo_menu_finalize (GObject *object)
-+{
-+    GLOMenu *menu = G_LO_MENU (object);
-+    struct item *items;
-+    gint n_items;
-+    gint i;
-+
-+    n_items = menu->items->len;
-+    items = (struct item *) g_array_free (menu->items, FALSE);
-+    for (i = 0; i < n_items; i++)
-+        g_lo_menu_clear_item (&items[i]);
-+    g_free (items);
-+
-+    G_OBJECT_CLASS (g_lo_menu_parent_class)
-+            ->finalize (object);
-+}
-+
-+static void
-+g_lo_menu_init (GLOMenu *menu)
-+{
-+    menu->items = g_array_new (FALSE, FALSE, sizeof (struct item));
-+//    menu->mutable = TRUE;
-+}
-+
-+static void
-+g_lo_menu_class_init (GLOMenuClass *klass)
-+{
-+    GMenuModelClass *model_class = G_MENU_MODEL_CLASS (klass);
-+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
-+
-+    object_class->finalize = g_lo_menu_finalize;
-+
-+    model_class->is_mutable = g_lo_menu_is_mutable;
-+    model_class->get_n_items = g_lo_menu_get_n_items;
-+    model_class->get_item_attributes = g_lo_menu_get_item_attributes;
-+    model_class->get_item_links = g_lo_menu_get_item_links;
-+}
 +
++    GVariant *action_value;
 +
-+static void
-+g_lo_menu_item_clear_cow (GLOMenuItem *menu_item)
-+{
-+    if (menu_item->cow)
++    if (action != NULL)
 +    {
-+        GHashTableIter iter;
-+        GHashTable *newHash;
-+        gpointer key;
-+        gpointer val;
-+
-+        newHash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
-+        g_hash_table_iter_init (&iter, menu_item->attributes);
-+        while (g_hash_table_iter_next (&iter, &key, &val))
-+            g_hash_table_insert (newHash, g_strdup ((gchar*) key), g_variant_ref ((GVariant*) val));
-+        g_hash_table_unref (menu_item->attributes);
-+        menu_item->attributes = newHash;
-+
-+        newHash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref);
-+        g_hash_table_iter_init (&iter, menu_item->links);
-+        while (g_hash_table_iter_next (&iter, &key, &val))
-+            g_hash_table_insert (newHash, g_strdup ((gchar*) key), g_object_ref (val));
-+        g_hash_table_unref (menu_item->links);
-+        menu_item->links = newHash;
-+
-+        menu_item->cow = FALSE;
++        action_value = g_variant_new_string (action);
++    }
++    else
++    {
++        action_value = NULL;
++        target_value = NULL;
 +    }
-+}
-+
-+static void
-+g_lo_menu_item_finalize (GObject *object)
-+{
-+    GLOMenuItem *menu_item = G_LO_MENU_ITEM (object);
-+
-+    g_hash_table_unref (menu_item->attributes);
-+    g_hash_table_unref (menu_item->links);
-+
-+    G_OBJECT_CLASS (g_lo_menu_item_parent_class)
-+            ->finalize (object);
-+}
-+
-+static void
-+g_lo_menu_item_init (GLOMenuItem *menu_item)
-+{
-+    menu_item->attributes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
-+    menu_item->links = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
-+    menu_item->cow = FALSE;
-+}
 +
-+static void
-+g_lo_menu_item_class_init (GLOMenuItemClass *klass)
-+{
-+    klass->finalize = g_lo_menu_item_finalize;
++    g_lo_menu_set_attribute_value (menu, position, G_MENU_ATTRIBUTE_ACTION, action_value);
++    g_lo_menu_set_attribute_value (menu, position, G_MENU_ATTRIBUTE_TARGET, target_value);
 +}
 +
-+/* We treat attribute names the same as GSettings keys:
-+ * - only lowercase ascii, digits and '-'
-+ * - must start with lowercase
-+ * - must not end with '-'
-+ * - no consecutive '-'
-+ * - not longer than 1024 chars
-+ */
-+static gboolean
-+valid_attribute_name (const gchar *name)
++void
++g_lo_menu_set_action_and_target_value_to_item_in_section (GLOMenu     *menu,
++                                                          gint         section,
++                                                          gint         position,
++                                                          const gchar *command,
++                                                          GVariant    *target_value)
 +{
-+    gint i;
-+
-+    if (!g_ascii_islower (name[0]))
-+        return FALSE;
++    g_return_if_fail (G_IS_LO_MENU (menu));
 +
-+    for (i = 1; name[i]; i++)
-+    {
-+        if (name[i] != '-' &&
-+                !g_ascii_islower (name[i]) &&
-+                !g_ascii_isdigit (name[i]))
-+            return FALSE;
++    struct item menu_item = g_array_index (menu->items, struct item, section);
 +
-+        if (name[i] == '-' && name[i + 1] == '-')
-+            return FALSE;
-+    }
++    GLOMenu *model = G_LO_MENU (g_hash_table_lookup (menu_item.links, G_MENU_LINK_SECTION));
 +
-+    if (name[i - 1] == '-')
-+        return FALSE;
++    g_return_if_fail (model != NULL);
 +
-+    if (i > 1024)
-+        return FALSE;
++    g_lo_menu_set_action_and_target_value (model, position, command, target_value);
 +
-+    return TRUE;
++    // Notify the update.
++    g_menu_model_items_changed (G_MENU_MODEL (model), position, 1, 1);
 +}
 +
 +void
-+g_lo_menu_item_set_attribute_value (GLOMenuItem *menu_item,
-+                                    const gchar *attribute,
-+                                    GVariant    *value)
++g_lo_menu_set_accelerator_to_item_in_section (GLOMenu     *menu,
++                                              gint         section,
++                                              gint         position,
++                                              const gchar *accelerator)
 +{
-+    g_return_if_fail (G_IS_LO_MENU_ITEM (menu_item));
-+    g_return_if_fail (attribute != NULL);
-+    g_return_if_fail (valid_attribute_name (attribute));
++    g_return_if_fail (G_IS_LO_MENU (menu));
 +
-+    g_lo_menu_item_clear_cow (menu_item);
++    GMenuModel *model = G_MENU_MODEL_CLASS (g_lo_menu_parent_class)
++                        ->get_item_link (G_MENU_MODEL (menu), section, G_MENU_LINK_SECTION);
 +
-+    if (value != NULL)
-+        g_hash_table_insert (menu_item->attributes, g_strdup (attribute), g_variant_ref_sink (value));
-+    else
-+        g_hash_table_remove (menu_item->attributes, attribute);
-+}
++    g_return_if_fail (model != NULL);
 +
-+void
-+g_lo_menu_item_set_attribute (GLOMenuItem *menu_item,
-+                              const gchar *attribute,
-+                              const gchar *format_string,
-+                              ...)
-+{
 +    GVariant *value;
 +
-+    if (format_string != NULL)
-+    {
-+        va_list ap;
-+
-+        va_start (ap, format_string);
-+        value = g_variant_new_va (format_string, NULL, &ap);
-+        va_end (ap);
-+    }
++    if (accelerator != NULL)
++        value = g_variant_new_string (accelerator);
 +    else
 +        value = NULL;
 +
-+    g_lo_menu_item_set_attribute_value (menu_item, attribute, value);
++    g_lo_menu_set_attribute_value (G_LO_MENU (model), position, "accel", value);
++
++    // Notify the update.
++    g_menu_model_items_changed (model, position, 1, 1);
 +}
 +
 +void
-+g_lo_menu_item_set_link (GLOMenuItem *menu_item,
-+                         const gchar *link,
-+                         GMenuModel  *model)
++g_lo_menu_set_link (GLOMenu     *menu,
++                    gint         position,
++                    const gchar *link,
++                    GMenuModel  *model)
 +{
-+    g_return_if_fail (G_IS_LO_MENU_ITEM (menu_item));
++    g_return_if_fail (G_IS_LO_MENU (menu));
 +    g_return_if_fail (link != NULL);
 +    g_return_if_fail (valid_attribute_name (link));
 +
-+    g_lo_menu_item_clear_cow (menu_item);
++    if (position < 0 || position >= (gint) menu->items->len)
++        position = menu->items->len - 1;
++
++    struct item menu_item = g_array_index (menu->items, struct item, position);
 +
 +    if (model != NULL)
-+        g_hash_table_insert (menu_item->links, g_strdup (link), g_object_ref (model));
++        g_hash_table_insert (menu_item.links, g_strdup (link), g_object_ref (model));
 +    else
-+        g_hash_table_remove (menu_item->links, link);
++        g_hash_table_remove (menu_item.links, link);
 +}
 +
 +void
-+g_lo_menu_item_set_label (GLOMenuItem *menu_item,
-+                          const gchar *label)
++g_lo_menu_insert_section (GLOMenu *menu,
++                          gint position,
++                          const gchar *label,
++                          GMenuModel* section)
 +{
-+    GVariant *value;
++    g_return_if_fail (G_IS_LO_MENU (menu));
 +
-+    if (label != NULL)
-+        value = g_variant_new_string (label);
-+    else
-+        value = NULL;
++    if (position < 0 || position > (gint) menu->items->len)
++        position = menu->items->len;
 +
-+    g_lo_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_LABEL, value);
-+}
++    struct item menu_item;
 +
-+void
-+g_lo_menu_item_set_submenu (GLOMenuItem *menu_item,
-+                            GMenuModel  *submenu)
-+{
-+    g_lo_menu_item_set_link (menu_item, G_MENU_LINK_SUBMENU, submenu);
-+}
++    g_lo_menu_struct_item_init(&menu_item);
 +
-+void
-+g_lo_menu_item_set_section (GLOMenuItem *menu_item,
-+                            GMenuModel  *section)
-+{
-+    g_lo_menu_item_set_link (menu_item, G_MENU_LINK_SECTION, section);
++    g_array_insert_val (menu->items, position, menu_item);
++
++    g_lo_menu_set_label (menu, position, label);
++    g_lo_menu_set_link (menu, position, G_MENU_LINK_SECTION, section);
++
++    g_menu_model_items_changed (G_MENU_MODEL (menu), position, 0, 1);
 +}
 +
 +void
-+g_lo_menu_item_set_action_and_target_value (GLOMenuItem *menu_item,
-+                                            const gchar *action,
-+                                            GVariant    *target_value)
++g_lo_menu_new_section (GLOMenu     *menu,
++                       gint         position,
++                       const gchar *label)
 +{
-+    GVariant *action_value;
++    GMenuModel *section = G_MENU_MODEL (g_lo_menu_new());
 +
-+    if (action != NULL)
-+    {
-+        action_value = g_variant_new_string (action);
-+    }
-+    else
-+    {
-+        action_value = NULL;
-+        target_value = NULL;
-+    }
++    g_lo_menu_insert_section (menu, position, label, section);
 +
-+    g_lo_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_ACTION, action_value);
-+    g_lo_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_TARGET, target_value);
++//    g_object_unref (section);
 +}
 +
-+void
-+g_lo_menu_item_set_action_and_target (GLOMenuItem *menu_item,
-+                                      const gchar *action,
-+                                      const gchar *format_string,
-+                                      ...)
-+{
-+    GVariant *value;
 +
-+    if (format_string != NULL)
-+    {
-+        va_list ap;
 +
-+        va_start (ap, format_string);
-+        value = g_variant_new_va (format_string, NULL, &ap);
-+        va_end (ap);
-+    }
-+    else
-+        value = NULL;
++GLOMenu *
++g_lo_menu_get_section (GLOMenu *menu,
++                       gint section)
++{
++    g_return_val_if_fail (G_IS_LO_MENU (menu), NULL);
 +
-+    g_lo_menu_item_set_action_and_target_value (menu_item, action, value);
++    return G_LO_MENU (G_MENU_MODEL_CLASS (g_lo_menu_parent_class)
++                      ->get_item_link (G_MENU_MODEL (menu), section, G_MENU_LINK_SECTION));
 +}
 +
 +void
-+g_lo_menu_item_set_detailed_action (GLOMenuItem *menu_item,
-+                                    const gchar *detailed_action)
++g_lo_menu_set_submenu_to_item_in_section (GLOMenu    *menu,
++                                          gint        section,
++                                          gint        position,
++                                          GMenuModel *submenu)
 +{
-+    const gchar *sep;
++//    puts(__FUNCTION__);
++    g_return_if_fail (G_IS_LO_MENU (menu));
++    g_return_if_fail (0 <= section && section < (gint) menu->items->len);
 +
-+    sep = strstr (detailed_action, "::");
++    GLOMenu *model = G_LO_MENU (G_MENU_MODEL_CLASS (g_lo_menu_parent_class)
++                                ->get_item_link (G_MENU_MODEL (menu), section, G_MENU_LINK_SECTION));
 +
-+    if (sep != NULL)
-+    {
-+        gchar *action;
++    g_return_if_fail (model != NULL);
 +
-+        action = g_strndup (detailed_action, sep - detailed_action);
-+        g_lo_menu_item_set_action_and_target (menu_item, action, "s", sep + 2);
-+        g_free (action);
-+    }
++    g_lo_menu_set_link (model, position, G_MENU_LINK_SUBMENU, submenu);
++}
 +
-+    else
-+        g_lo_menu_item_set_action_and_target_value (menu_item, detailed_action, NULL);
++static void
++g_lo_menu_clear_item (struct item *menu_item)
++{
++    if (menu_item->attributes != NULL)
++        g_hash_table_unref (menu_item->attributes);
++    if (menu_item->links != NULL)
++        g_hash_table_unref (menu_item->links);
 +}
 +
-+GLOMenuItem *
-+g_lo_menu_item_new (const gchar *label,
-+                    const gchar *detailed_action)
++void
++g_lo_menu_remove (GLOMenu *menu,
++                  gint     position)
 +{
-+    GLOMenuItem *menu_item;
++    g_return_if_fail (G_IS_LO_MENU (menu));
++    g_return_if_fail (0 <= position && position < (gint) menu->items->len);
++
++    g_lo_menu_clear_item (&g_array_index (menu->items, struct item, position));
++    g_array_remove_index (menu->items, position);
++    g_menu_model_items_changed (G_MENU_MODEL (menu), position, 1, 0);
++}
 +
-+    menu_item = G_LO_MENU_ITEM( g_object_new (G_TYPE_LO_MENU_ITEM, NULL) );
++void
++g_lo_menu_remove_from_section (GLOMenu *menu,
++                               gint     section,
++                               gint     position)
++{
++    g_return_if_fail (G_IS_LO_MENU (menu));
++    g_return_if_fail (0 <= section && section < (gint) menu->items->len);
 +
-+    if (label != NULL)
-+        g_lo_menu_item_set_label (menu_item, label);
++    GLOMenu *model = G_LO_MENU (G_MENU_MODEL_CLASS (g_lo_menu_parent_class)
++                                ->get_item_link (G_MENU_MODEL (menu), section, G_MENU_LINK_SECTION));
 +
-+    if (detailed_action != NULL)
-+        g_lo_menu_item_set_detailed_action (menu_item, detailed_action);
++    g_return_if_fail (model != NULL);
 +
-+    return menu_item;
++    g_lo_menu_remove (model, position);
 +}
 +
-+GLOMenuItem *
-+g_lo_menu_item_new_submenu (const gchar *label,
-+                            GMenuModel  *submenu)
++static void
++g_lo_menu_finalize (GObject *object)
 +{
-+    GLOMenuItem *menu_item;
-+
-+    menu_item = G_LO_MENU_ITEM( g_object_new (G_TYPE_LO_MENU_ITEM, NULL) );
-+
-+    if (label != NULL)
-+        g_lo_menu_item_set_label (menu_item, label);
++    GLOMenu *menu = G_LO_MENU (object);
++    struct item *items;
++    gint n_items;
++    gint i;
 +
-+    g_lo_menu_item_set_submenu (menu_item, submenu);
++    n_items = menu->items->len;
++    items = (struct item *) g_array_free (menu->items, FALSE);
++    for (i = 0; i < n_items; i++)
++        g_lo_menu_clear_item (&items[i]);
++    g_free (items);
 +
-+    return menu_item;
++    G_OBJECT_CLASS (g_lo_menu_parent_class)
++            ->finalize (object);
 +}
 +
-+GLOMenuItem *
-+g_lo_menu_item_new_section (const gchar *label,
-+                            GMenuModel  *section)
++static void
++g_lo_menu_init (GLOMenu *menu)
 +{
-+    GLOMenuItem *menu_item;
-+
-+    menu_item = G_LO_MENU_ITEM( g_object_new (G_TYPE_LO_MENU_ITEM, NULL) );
++    menu->items = g_array_new (FALSE, FALSE, sizeof (struct item));
++}
 +
-+    if (label != NULL)
-+        g_lo_menu_item_set_label (menu_item, label);
++static void
++g_lo_menu_class_init (GLOMenuClass *klass)
++{
++    GMenuModelClass *model_class = G_MENU_MODEL_CLASS (klass);
++    GObjectClass *object_class = G_OBJECT_CLASS (klass);
 +
-+    g_lo_menu_item_set_section (menu_item, section);
++    object_class->finalize = g_lo_menu_finalize;
 +
-+    return menu_item;
++    model_class->is_mutable = g_lo_menu_is_mutable;
++    model_class->get_n_items = g_lo_menu_get_n_items;
++    model_class->get_item_attributes = g_lo_menu_get_item_attributes;
++    model_class->get_item_links = g_lo_menu_get_item_links;
 +}
 +
++/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
 diff --git a/vcl/unx/gtk/window/gtksalmenu.cxx b/vcl/unx/gtk/window/gtksalmenu.cxx
 new file mode 100644
-index 0000000..a82dbe2
+index 0000000..712f868
 --- /dev/null
 +++ b/vcl/unx/gtk/window/gtksalmenu.cxx
-@@ -0,0 +1,511 @@
+@@ -0,0 +1,660 @@
++/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
++/*
++ * Copyright © 2011 Canonical Ltd.
++ *
++ * 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; either version 2 of the
++ * licence, 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
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
++ * USA.
++ *
++ * Author: Antonio Fernández <antonio.fernandez@aentos.es>
++ */
 +
 +#include "unx/gtk/gtksalmenu.hxx"
 +
@@ -2304,50 +2410,61 @@ index 0000000..a82dbe2
 +using namespace std;
 +
 +//Some menus are special, this is the list of them
-+gboolean
-+isSpecialSubmenu (OUString command)
-+{
-+    const gchar * specialSubmenus[11] = {".uno:CharFontName",
-+                                         ".uno:FontHeight",
-+                                         ".uno:ObjectMenue",
-+                                         ".uno:InsertPageHeader",
-+                                         ".uno:InsertPageFooter",
-+                                         ".uno:ChangeControlType",
-+                                         ".uno:AvailableToolbars",
-+                                         ".uno:ScriptOrganizer",
-+                                         ".uno:RecentFileList",
-+                                         ".uno:AddDirect",
-+                                         ".uno:AutoPilotMenu"};
-+
-+    for (gint i = 0; i < 11; i++)
-+    {
-+        if (command.equals (OUString::createFromAscii (specialSubmenus[i])))
-+            return TRUE;
-+    }
-+    return FALSE;
-+}
++//gboolean
++//isSpecialSubmenu (OUString command)
++//{
++//    const gchar * specialSubmenus[11] = {".uno:CharFontName",
++//                                         ".uno:FontHeight",
++//                                         ".uno:ObjectMenue",
++//                                         ".uno:InsertPageHeader",
++//                                         ".uno:InsertPageFooter",
++//                                         ".uno:ChangeControlType",
++//                                         ".uno:AvailableToolbars",
++//                                         ".uno:ScriptOrganizer",
++//                                         ".uno:RecentFileList",
++//                                         ".uno:AddDirect",
++//                                         ".uno:AutoPilotMenu"};
++
++//    for (gint i = 0; i < 11; i++)
++//    {
++//        if (command.equals (OUString::createFromAscii (specialSubmenus[i])))
++//            return TRUE;
++//    }
++//    return FALSE;
++//}
++
++static void UpdateNativeMenu( GtkSalMenu* pMenu ) {
++    if ( pMenu == NULL )
++        return;
 +
-+void updateNativeMenu( GtkSalMenu* pMenu ) {
-+    if ( pMenu ) {
-+        for ( sal_uInt16 i = 0; i < pMenu->GetItemCount(); i++ ) {
-+            GtkSalMenuItem* pSalMenuItem = pMenu->GetItemAtPos( i );
++    Menu* pVCLMenu = pMenu->GetMenu();
 +
-+            if ( !pSalMenuItem->mpVCLMenu )
-+                continue;
++    for ( sal_uInt16 i = 0; i < pMenu->GetItemCount(); i++ ) {
++        GtkSalMenuItem *pSalMenuItem = pMenu->GetItemAtPos( i );
++        sal_uInt16 nId = pSalMenuItem->mnId;
 +
-+            String aText = pSalMenuItem->mpVCLMenu->GetItemText( pSalMenuItem->mnId );
++        if ( pSalMenuItem->mnType == MENUITEM_SEPARATOR )
++            continue;
 +
-+            // Force updating of native menu labels.
-+            pMenu->SetItemText( i, pSalMenuItem, aText );
++        String aText = pVCLMenu->GetItemText( nId );
++        String aCommand = pVCLMenu->GetItemCommand( nId );
++        sal_Bool itemEnabled = pVCLMenu->IsItemEnabled( nId );
++        KeyCode nAccelKey = pVCLMenu->GetAccelKey( nId );
++        sal_Bool itemChecked = pVCLMenu->IsItemChecked( nId );
 +
-+            if ( pSalMenuItem->mpSubMenu && pSalMenuItem->mpSubMenu->GetMenu() ) {
-+                pSalMenuItem->mpSubMenu->GetMenu()->Activate();
-+                updateNativeMenu( pSalMenuItem->mpSubMenu );
++        // Force updating of native menu labels.
++        pMenu->SetItemCommand( i, pSalMenuItem, aCommand );
++        pMenu->SetItemText( i, pSalMenuItem, aText );
++        pMenu->EnableItem( i, itemEnabled );
++        pMenu->SetAccelerator( i, pSalMenuItem, nAccelKey, nAccelKey.GetName( pMenu->GetFrame()->GetWindow() ) );
++        pMenu->CheckItem( i, itemChecked );
 +
-+                // FIXME: Using Deactivate() let the menu to update itself correctly, but generates
-+                // duplicated popup menus.
-+//                pSalMenuItem->mpSubMenu->GetMenu()->Deactivate();
-+            }
++        GtkSalMenu* pSubmenu = pSalMenuItem->mpSubMenu;
++
++        if ( pSubmenu && pSubmenu->GetMenu() ) {
++            pSubmenu->GetMenu()->Activate();
++            pSubmenu->GetMenu()->Deactivate();
++            UpdateNativeMenu( pSubmenu );
 +        }
 +    }
 +}
@@ -2355,7 +2472,7 @@ index 0000000..a82dbe2
 +gboolean GenerateMenu(gpointer user_data) {
 +    GtkSalMenu* pSalMenu = static_cast< GtkSalMenu* >( user_data );
 +
-+    updateNativeMenu( pSalMenu );
++    UpdateNativeMenu( pSalMenu );
 +
 +    return TRUE;
 +}
@@ -2404,44 +2521,102 @@ index 0000000..a82dbe2
 +    return ( pSalMenu ) ? pSalMenu->GetActionGroup() : NULL;
 +}
 +
-+/*
-+ * GtkSalMenu
-+ */
-+
-+GtkSalMenuItem* GtkSalMenu::GetSalMenuItem( sal_uInt16 nId )
++// FIXME: Check for missing keys. Maybe translating keycodes would be safer...
++rtl::OUString GetGtkKeyName( rtl::OUString keyName )
 +{
-+    for ( sal_uInt16 i = 0; i < maItems.size(); i++ )
-+    {
-+        GtkSalMenuItem* pSalMenuItem = maItems[ i ];
++    rtl::OUString aGtkKeyName("");
 +
-+        if ( pSalMenuItem->mnId == nId ) {
-+            return pSalMenuItem;
-+        }
++    sal_Int32 nIndex = 0;
 +
-+        if ( pSalMenuItem->mpSubMenu )
-+        {
-+            pSalMenuItem = pSalMenuItem->mpSubMenu->GetSalMenuItem( nId );
-+            if (pSalMenuItem) {
-+                return pSalMenuItem;
-+            }
++    do
++    {
++        rtl::OUString token = keyName.getToken( 0, '+', nIndex );
++
++        if ( token == "Ctrl" ) {
++            aGtkKeyName += "<Control>";
++        } else if ( token == "Alt" ) {
++            aGtkKeyName += "<Alt>";
++        } else if ( token == "Shift" ) {
++            aGtkKeyName += "<Shift>";
++        } else {
++            aGtkKeyName += token;
 +        }
-+    }
++    } while ( nIndex >= 0 );
 +
-+    return NULL;
++    return aGtkKeyName;
 +}
 +
-+sal_Int16 GtkSalMenu::GetSectionNumber( GMenuModel* pSection )
-+{
-+    if ( pSection == NULL )
-+        return -1;
++//GVariant* GetRadioButtonHints( GtkSalMenuItem *pSalMenuItem )
++//{
++//    GVariantBuilder *pBuilder;
++//    GVariant *pHints;
++
++//    pBuilder = g_variant_builder_new( G_VARIANT_TYPE_STRING );
++
++//    Menu* pMenu = pSalMenuItem->mpVCLMenu;
++
++//    gboolean bItemIncluded = FALSE;
++
++//    for ( sal_uInt16 i = 0; i < pMenu->GetItemCount(); i++ )
++//    {
++//        sal_uInt16 nId = pMenu->GetItemId( i );
++//        MenuItemBits itemBits = pMenu->GetItemBits( nId );
++//        MenuItemType itemType = pMenu->GetItemType( nId );
++
++//        if ( itemBits & MIB_RADIOCHECK )
++//        {
++//            rtl::OString aValue = rtl::OUStringToOString( pMenu->GetItemText( nId ), RTL_TEXTENCODING_UTF8 );
++//            g_variant_builder_add( pBuilder, "s", aValue.getStr() );
++
++//            if ( nId == pSalMenuItem->mnId )
++//                bItemIncluded = TRUE;
++//        }
++//        else if ( itemType == MENUITEM_SEPARATOR )
++//        {
++//            if ( bItemIncluded == FALSE )
++//            {
++//                g_variant_builder_clear( pBuilder );
++//            }
++//            else
++//                break;
++//        }
++//    }
 +
-+    for ( int i = 0; maSections.size(); i++ )
++//    // Build an array of G_VARIANT_TYPE_STRING.
++//    pHints = g_variant_new ("as", pBuilder);
++//    g_variant_builder_unref ( pBuilder );
++
++//    return pHints;
++//}
++
++/*
++ * GtkSalMenu
++ */
++
++// FIXME: Iterating through the whole list everytime is slow, but works. Some fine tuning would be required here...
++void GtkSalMenu::GetItemSectionAndPosition( unsigned nPos, unsigned *insertSection, unsigned *insertPos )
++{
++    if ( mpVCLMenu == NULL || nPos >= mpVCLMenu->GetItemCount() )
 +    {
-+        if ( maSections[ i ] == pSection )
-+            return i;
++        *insertSection = g_menu_model_get_n_items( mpMenuModel ) - 1;
++        *insertPos = MENU_APPEND;
 +    }
++    else
++    {
++        unsigned nItem;
++        gint nItemPos;
++
++        for ( nItem = 0, *insertSection = 0, nItemPos = -1; nItem <= nPos; nItem++ )
++        {
++            if ( mpVCLMenu->GetItemType( nItem ) == MENUITEM_SEPARATOR ) {
++                (*insertSection)++;
++                nItemPos = -1;
++            } else
++                nItemPos++;
++        }
 +
-+    return -1;
++        *insertPos = nItemPos;
++    }
 +}
 +
 +GtkSalMenu::GtkSalMenu( sal_Bool bMenuBar ) :
@@ -2449,132 +2624,108 @@ index 0000000..a82dbe2
 +    mpVCLMenu( NULL ),
 +    mpParentSalMenu( NULL ),
 +    mpFrame( NULL ),
-+    pSessionBus( NULL ),
-+    mMenubarId( 0 ),
-+    mActionGroupId ( 0 ),
 +    mpMenuModel( NULL ),
 +    mpActionGroup( NULL )
 +{
-+    mpCurrentSection = G_MENU_MODEL( g_lo_menu_new() );
-+    maSections.push_back( mpCurrentSection );
-+
-+    if (bMenuBar) {
-+        mpActionGroup = G_ACTION_GROUP( g_lo_action_group_new() );
-+
-+        pSessionBus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
-+        if(!pSessionBus) puts ("Fail bus get");
-+    } else {
-+        mpMenuModel = G_MENU_MODEL( g_lo_menu_new() );
-+        g_lo_menu_append_section( G_LO_MENU( mpMenuModel ), NULL, mpCurrentSection );
-+    }
++    mpMenuModel = G_MENU_MODEL( g_lo_menu_new() );
++    g_lo_menu_new_section( G_LO_MENU( mpMenuModel ), 0, NULL);
 +}
 +
 +GtkSalMenu::~GtkSalMenu()
 +{
-+    g_source_remove_by_user_data( this );
-+
-+    g_object_unref( mpCurrentSection );
++    if ( mpActionGroup ) {
++        g_lo_action_group_clear( G_LO_ACTION_GROUP( mpActionGroup ) );
++    }
 +
 +    if ( mbMenuBar ) {
++        g_source_remove_by_user_data( this );
 +        g_lo_menu_remove( G_LO_MENU( mpMenuModel ), 0 );
-+        mpMenuModel = NULL;
 +    } else {
 +        g_object_unref( mpMenuModel );
 +    }
 +
-+    if ( mpActionGroup ) {
-+        g_lo_action_group_clear( G_LO_ACTION_GROUP( mpActionGroup ) );
-+    }
-+
-+    pSessionBus = NULL;
-+
-+    maSections.clear();
 +    maItems.clear();
 +}
 +
 +sal_Bool GtkSalMenu::VisibleMenuBar()
 +{
-+    return sal_False;
++    return sal_True;
 +}
 +
 +void GtkSalMenu::InsertItem( SalMenuItem* pSalMenuItem, unsigned nPos )
 +{
-+    GtkSalMenuItem *pGtkSalMenuItem = static_cast<GtkSalMenuItem*>( pSalMenuItem );
-+
-+    maItems.push_back( pGtkSalMenuItem );
++    GtkSalMenuItem *pItem = static_cast<GtkSalMenuItem*>( pSalMenuItem );
 +
-+    if ( pGtkSalMenuItem->mpMenuItem ) {
-+        if ( !mpCurrentSection ) {
-+            mpCurrentSection = G_MENU_MODEL( g_lo_menu_new() );
-+            maSections.push_back( mpCurrentSection );
-+
-+            if ( mpMenuModel ) {
-+                g_lo_menu_append_section( G_LO_MENU( mpMenuModel ), NULL, mpCurrentSection );
-+            }
-+        }
++    if ( nPos == MENU_APPEND )
++        maItems.push_back( pItem );
++    else
++        maItems.insert( maItems.begin() + nPos, pItem );
 +
-+        pGtkSalMenuItem->mpParentSection = mpCurrentSection;
-+        pGtkSalMenuItem->mnPos = g_menu_model_get_n_items( mpCurrentSection );
++    pItem->mpParentMenu = this;
 +
-+        g_lo_menu_insert_item( G_LO_MENU( mpCurrentSection ), pGtkSalMenuItem->mnPos, pGtkSalMenuItem->mpMenuItem );
-+    } else {
-+        // If no mpMenuItem exists, then item is a separator.
-+        mpCurrentSection = G_MENU_MODEL( g_lo_menu_new() );
-+        maSections.push_back( mpCurrentSection );
++    if ( pItem->mnType != MENUITEM_SEPARATOR )
++    {
++        unsigned nInsertSection, nInsertPos;
++        GetItemSectionAndPosition( nPos, &nInsertSection, &nInsertPos );
 +
-+        if ( mpMenuModel ) {
-+            g_lo_menu_append_section( G_LO_MENU( mpMenuModel ), NULL, mpCurrentSection );
-+        }
++        g_lo_menu_insert_in_section( G_LO_MENU( mpMenuModel ), nInsertSection, nInsertPos, "EMPTY STRING" );
++    }
++    else
++    {
++        g_lo_menu_new_section( G_LO_MENU( mpMenuModel ), MENU_APPEND, NULL );
 +    }
-+
-+    pGtkSalMenuItem->mpParentMenu = this;
 +}
 +
 +void GtkSalMenu::RemoveItem( unsigned nPos )
 +{
-+    // FIXME: This method makes the application crash.
-+//    GtkSalMenuItem* pSalMenuItem = maItems[ nPos ];
-+
-+//    GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( GetActionGroupFromMenubar( this ) );
-+//    if ( pActionGroup ) {
-+//        g_lo_action_group_remove( pActionGroup, pSalMenuItem->maCommand );
-+//    }
++    GLOMenu* pMenu = G_LO_MENU( mpMenuModel );
++    GtkSalMenuItem *pItem = maItems[ nPos ];
 +
-+//    cout << __FUNCTION__ << " - " << pSalMenuItem->mpParentSection << " - " << pSalMenuItem->mnPos << endl;
++    // If item is a separator, the last section of the menu is removed.
++    if ( pItem->mnType != MENUITEM_SEPARATOR )
++    {
++        if ( pItem->maCommand ) {
++            GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( GetActionGroupFromMenubar( this ) );
 +
-+//    if ( pSalMenuItem->mpParentSection ) {
-+//        if ( GetSectionNumber( pSalMenuItem->mpParentSection ) > -1 )
-+//            g_lo_menu_remove( G_LO_MENU( pSalMenuItem->mpParentSection ), pSalMenuItem->mnPos );
++            if ( pActionGroup != NULL )
++                g_lo_action_group_remove( pActionGroup, pItem->maCommand );
 +
-+//        if ( g_menu_model_get_n_items( pSalMenuItem->mpParentSection ) == 0 ) {
-+//            sal_uInt16 nSection = GetSectionNumber( pSalMenuItem->mpParentSection );
++            g_free ( pItem->maCommand );
++            pItem->maCommand = NULL;
++        }
 +
-+//            cout << "Removing section " << nSection << endl;
++        unsigned nSection, nItemPos;
++        GetItemSectionAndPosition( nPos, &nSection, &nItemPos );
 +
-+//            g_lo_menu_remove( G_LO_MENU( mpMenuModel ), nSection );
-+//            maSections.erase( maSections.begin() + nSection, maSections.begin() + nSection );
++        g_lo_menu_remove_from_section( pMenu, nSection, nItemPos );
++    }
++    else
++    {
++        gint nSection = g_menu_model_get_n_items( mpMenuModel ) - 1;
 +
-+//            if ( pSalMenuItem->mpParentSection == mpCurrentSection )
-+//                mpCurrentSection = maSections.back();
-+//        }
-+//    }
++        if ( nSection > 0 )
++            g_lo_menu_remove( pMenu, nSection );
++    }
 +
-+//    maItems.erase( maItems.begin() + nPos, maItems.begin() + nPos );
++    maItems.erase( maItems.begin() + nPos );
 +}
 +
 +void GtkSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsigned nPos )
 +{
-+    GtkSalMenuItem *pGtkSalMenuItem = static_cast<GtkSalMenuItem*>( pSalMenuItem );
-+    GtkSalMenu *pGtkSubMenu = static_cast<GtkSalMenu*>( pSubMenu );
++    GtkSalMenuItem *pItem = static_cast< GtkSalMenuItem* >( pSalMenuItem );
++    GtkSalMenu *pGtkSubMenu = static_cast< GtkSalMenu* >( pSubMenu );
++
++    if ( pGtkSubMenu == NULL )
++        return;
 +
-+    if ( pGtkSubMenu ) {
-+        pGtkSalMenuItem->mpSubMenu = pGtkSubMenu;
-+        g_lo_menu_item_set_submenu( pGtkSalMenuItem->mpMenuItem, pGtkSubMenu->mpMenuModel );
++    pGtkSubMenu->mpParentSalMenu = this;
++    pItem->mpSubMenu = pGtkSubMenu;
 +
-+        if ( !pGtkSubMenu->mpParentSalMenu ) {
-+            pGtkSubMenu->mpParentSalMenu = this;
-+        }
-+    }
++    // Update item in GMenuModel.
++    unsigned nSection, nItemPos;
++    GetItemSectionAndPosition( nPos, &nSection, &nItemPos );
++
++    g_lo_menu_set_submenu_to_item_in_section( G_LO_MENU( mpMenuModel ), nSection, nItemPos, pGtkSubMenu->mpMenuModel );
 +}
 +
 +void GtkSalMenu::SetFrame( const SalFrame* pFrame )
@@ -2586,24 +2737,17 @@ index 0000000..a82dbe2
 +    GdkWindow *gdkWindow = gtk_widget_get_window( widget );
 +
 +    if (gdkWindow) {
-+        gpointer pMenu = g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-menubar" );
++        GLOMenu* pMainMenu = G_LO_MENU( g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-menubar" ) );
 +        GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( g_object_get_data( G_OBJECT( gdkWindow ), "g-lo-action-group" ) );
 +
-+        if ( pMenu && pActionGroup ) {
-+            mpMenuModel = G_MENU_MODEL( pMenu );
-+
-+            // Merge current action group with the exported one
-+            g_lo_action_group_clear( pActionGroup );
-+            g_lo_action_group_merge( G_LO_ACTION_GROUP( mpActionGroup ), pActionGroup );
-+            g_lo_action_group_clear( G_LO_ACTION_GROUP( mpActionGroup ) );
-+            g_object_unref( mpActionGroup );
-+
-+            mpActionGroup = G_ACTION_GROUP( pActionGroup );
++        if ( pMainMenu && pActionGroup ) {
++            g_lo_menu_remove( pMainMenu, 0 );
 +        } else {
-+            mpMenuModel = G_MENU_MODEL( g_lo_menu_new() );
++            pMainMenu = g_lo_menu_new();
++            pActionGroup = g_lo_action_group_new();
 +
-+            g_object_set_data_full( G_OBJECT( gdkWindow ), "g-lo-menubar", mpMenuModel, ObjectDestroyedNotify );
-+            g_object_set_data_full( G_OBJECT( gdkWindow ), "g-lo-action-group", mpActionGroup, ObjectDestroyedNotify );
++            g_object_set_data_full( G_OBJECT( gdkWindow ), "g-lo-menubar", pMainMenu, ObjectDestroyedNotify );
++            g_object_set_data_full( G_OBJECT( gdkWindow ), "g-lo-action-group", pActionGroup, ObjectDestroyedNotify );
 +
 +            XLIB_Window windowId = GDK_WINDOW_XID( gdkWindow );
 +
@@ -2611,27 +2755,38 @@ index 0000000..a82dbe2
 +            gchar* aDBusWindowPath = g_strdup_printf( "/window/%lu", windowId );
 +            gchar* aDBusMenubarPath = g_strdup_printf( "/window/%lu/menus/menubar", windowId );
 +
-+            gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_UNIQUE_BUS_NAME", g_dbus_connection_get_unique_name( pSessionBus ) );
-+            gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_APPLICATION_OBJECT_PATH", "" );
-+            gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_WINDOW_OBJECT_PATH", aDBusWindowPath );
-+            gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_MENUBAR_OBJECT_PATH", aDBusMenubarPath );
++            // Get a DBus session connection.
++            GDBusConnection* pSessionBus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
++            if(!pSessionBus) puts ("Failed to get DBus session connection");
 +
 +            // Publish the menu.
 +            if ( aDBusMenubarPath ) {
-+                mMenubarId = g_dbus_connection_export_menu_model (pSessionBus, aDBusMenubarPath, mpMenuModel, NULL);
-+                if(!mMenubarId) puts("Fail export menubar");
++                sal_uInt16 menubarId = g_dbus_connection_export_menu_model (pSessionBus, aDBusMenubarPath, G_MENU_MODEL( pMainMenu ), NULL);
++                if(!menubarId) puts("Failed to export menubar");
 +            }
 +
 +            if ( aDBusPath ) {
-+                mActionGroupId = g_dbus_connection_export_action_group( pSessionBus, aDBusPath, mpActionGroup, NULL);
++                sal_uInt16 actionGroupId = g_dbus_connection_export_action_group( pSessionBus, aDBusPath, G_ACTION_GROUP( pActionGroup ), NULL);
++                if(!actionGroupId) puts("Failed to export action group");
 +            }
 +
++            // Set window properties.
++            gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_UNIQUE_BUS_NAME", g_dbus_connection_get_unique_name( pSessionBus ) );
++            gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_APPLICATION_OBJECT_PATH", "" );
++            gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_WINDOW_OBJECT_PATH", aDBusWindowPath );
++            gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_MENUBAR_OBJECT_PATH", aDBusMenubarPath );
++
 +            g_free( aDBusPath );
 +            g_free( aDBusWindowPath );
 +            g_free( aDBusMenubarPath );
 +        }
 +
-+        g_lo_menu_append_section( G_LO_MENU( mpMenuModel ), NULL, mpCurrentSection );
++        // Menubar has only one section, so we put it on the exported menu.
++        g_lo_menu_insert_section( pMainMenu, 0, NULL, mpMenuModel );
++        mpActionGroup = G_ACTION_GROUP( pActionGroup );
++
++//        UpdateNativeMenu( this );
++//        UpdateNativeMenu( this );
 +
 +        // Refresh the menu every second.
 +        // This code is a workaround until required modifications in Gtk+ are available.
@@ -2649,72 +2804,91 @@ index 0000000..a82dbe2
 +
 +void GtkSalMenu::CheckItem( unsigned nPos, sal_Bool bCheck )
 +{
-+//    cout << __FUNCTION__ << " - " << nPos << " - " << bCheck << endl;
-+//    GActionGroup* pActionGroup = GetActionGroupFromMenubar( this );
++    GtkSalMenuItem* pItem = maItems[ nPos ];
 +
-+//    if ( !pActionGroup )
-+//        return;
++    if ( pItem->mpSubMenu )
++        return;
 +
-+//    GtkSalMenuItem* pSalMenuItem = maItems[ nPos ];
++    if ( pItem->maCommand == NULL || g_strcmp0( pItem->maCommand, "" ) == 0 )
++        return;
 +
-+//    if ( !pSalMenuItem || pSalMenuItem->mpSubMenu )
-+//        return;
++    GActionGroup* pActionGroup = GetActionGroupFromMenubar( this );
 +
-+//    MenuItemBits itemBits = pSalMenuItem->mnBits;
-+//    GVariant *pCheckValue = NULL;
++    if ( !pActionGroup )
++        return;
 +
-+//    if ( itemBits & MIB_CHECKABLE ) {
-+//        gboolean bCheckedValue = ( bCheck == sal_True ) ? TRUE : FALSE;
-+//        pCheckValue = g_variant_new_boolean( bCheckedValue );
-+//    }
++    GVariant *pCheckValue = NULL;
++    gboolean bCheckedValue = ( bCheck == sal_True ) ? TRUE : FALSE;
++
++    // FIXME: Why pItem->mnBits differs from GetItemBits value?
++    MenuItemBits bits = pItem->mpVCLMenu->GetItemBits( pItem->mnId );
++
++    if ( bits & MIB_CHECKABLE ) {
++        GVariant* pState = g_action_group_get_action_state( pActionGroup, pItem->maCommand );
++        gboolean bCurrentState = g_variant_get_boolean( pState );
++
++        if ( bCurrentState != bCheck )
++            pCheckValue = g_variant_new_boolean( bCheckedValue );
++    }
++    else if ( bits & MIB_RADIOCHECK )
++    {
++        GVariant* pState = g_action_group_get_action_state( pActionGroup, pItem->maCommand );
++        gchar* aCurrentState = (gchar*) g_variant_get_string( pState, NULL );
++        gboolean bCurrentState = g_strcmp0( aCurrentState, "" ) != 0;
++
++        if ( bCurrentState != bCheck )
++            pCheckValue = (bCheckedValue) ? g_variant_new_string( pItem->maCommand ) : g_variant_new_string( "" );
++    }
 +
-+//    if ( pCheckValue )
-+//        g_action_group_change_action_state( pActionGroup, pSalMenuItem->maCommand, pCheckValue );
++    if ( pCheckValue )
++        g_action_group_change_action_state( pActionGroup, pItem->maCommand, pCheckValue );
 +}
 +
 +void GtkSalMenu::EnableItem( unsigned nPos, sal_Bool bEnable )
 +{
 +    GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( GetActionGroupFromMenubar( this ) );
 +
-+    if ( pActionGroup ) {
-+        GtkSalMenuItem* pSalMenuItem = maItems[ nPos ];
++    if ( pActionGroup == NULL )
++        return;
 +
-+        gboolean bItemEnabled = (bEnable == sal_True) ? TRUE : FALSE;
++    sal_uInt16 nId = mpVCLMenu->GetItemId( nPos );
++    rtl::OUString aOUCommand = mpVCLMenu->GetItemCommand( nId );
 +
-+        if ( g_strcmp0( pSalMenuItem->maCommand, "" ) == 0 )
-+            return;
++    if ( aOUCommand == NULL || aOUCommand.isEmpty() )
++        return;
 +
-+        g_lo_action_group_set_action_enabled( pActionGroup, pSalMenuItem->maCommand, bItemEnabled );
-+    }
++    gchar* aCommand = (gchar*) rtl::OUStringToOString( aOUCommand, RTL_TEXTENCODING_UTF8 ).getStr();
++
++    gboolean bItemEnabled = (bEnable == sal_True) ? TRUE : FALSE;
++
++    if ( g_action_group_get_action_enabled( G_ACTION_GROUP( pActionGroup ), aCommand ) != bItemEnabled )
++        g_lo_action_group_set_action_enabled( pActionGroup, aCommand, bItemEnabled );
 +}
 +
 +void GtkSalMenu::SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const rtl::OUString& rText )
 +{
 +    // Replace the "~" character with "_".
 +    rtl::OUString aText = rText.replace( '~', '_' );
-+    rtl::OString aConvertedText = OUStringToOString(aText, RTL_TEXTENCODING_UTF8);
-+
-+    GtkSalMenuItem *pGtkSalMenuItem = static_cast<GtkSalMenuItem*>( pSalMenuItem );
++    rtl::OString aConvertedText = OUStringToOString( aText, RTL_TEXTENCODING_UTF8 );
 +
-+    GLOMenuItem *pMenuItem = G_LO_MENU_ITEM( pGtkSalMenuItem->mpMenuItem );
-+
-+    GVariant* aCurrentLabel = g_menu_model_get_item_attribute_value( pGtkSalMenuItem->mpParentSection, pGtkSalMenuItem->mnPos, G_MENU_ATTRIBUTE_LABEL, G_VARIANT_TYPE_STRING );
++    unsigned nSection, nItemPos;
++    GetItemSectionAndPosition( nPos, &nSection, &nItemPos );
 +
++    // Update item text only when necessary.
 +    sal_Bool bSetLabel = sal_True;
 +
-+    if ( aCurrentLabel ) {
-+        if ( g_strcmp0( g_variant_get_string( aCurrentLabel, NULL ), aConvertedText.getStr() ) == 0 ) {
-+            bSetLabel = sal_False;
-+        }
-+    }
++    GtkSalMenuItem* pItem = static_cast< GtkSalMenuItem* >( pSalMenuItem );
++
++    // FIXME: It would be better retrieving the label from the menu itself, but it currently crashes the app.
++    if ( pItem->maLabel && g_strcmp0( pItem->maLabel, aConvertedText.getStr() ) == 0 )
++        bSetLabel = sal_False;
 +
 +    if ( bSetLabel == sal_True ) {
-+        g_lo_menu_item_set_label( pMenuItem, aConvertedText.getStr() );
++        if ( pItem->maLabel )
++            g_free( pItem->maLabel );
 +
-+        if ( pGtkSalMenuItem->mpParentSection ) {
-+            g_lo_menu_remove( G_LO_MENU( pGtkSalMenuItem->mpParentSection ), pGtkSalMenuItem->mnPos );
-+            g_lo_menu_insert_item( G_LO_MENU( pGtkSalMenuItem->mpParentSection ), pGtkSalMenuItem->mnPos, pGtkSalMenuItem->mpMenuItem );
-+        }
++        pItem->maLabel = g_strdup( aConvertedText.getStr() );
++        g_lo_menu_set_label_to_item_in_section( G_LO_MENU( mpMenuModel ), nSection, nItemPos, pItem->maLabel );
 +    }
 +}
 +
@@ -2724,36 +2898,101 @@ index 0000000..a82dbe2
 +
 +void GtkSalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode& rKeyCode, const rtl::OUString& rKeyName )
 +{
++    GtkSalMenuItem *pItem = static_cast< GtkSalMenuItem* >( pSalMenuItem );
++
++    if ( rKeyName.isEmpty() )
++        return;
++
++    rtl::OString aAccelerator = rtl::OUStringToOString( GetGtkKeyName( rKeyName ), RTL_TEXTENCODING_UTF8 );
++
++    unsigned nSection, nItemPos;
++    GetItemSectionAndPosition( nPos, &nSection, &nItemPos );
++
++    sal_Bool bSetAccel = sal_True;
++
++    if ( pItem->maAccel && g_strcmp0( pItem->maAccel, aAccelerator.getStr() ) == 0 )
++            bSetAccel = sal_False;
++
++    if ( bSetAccel == sal_True ) {
++        if (pItem->maAccel)
++            g_free( pItem->maAccel );
++
++        pItem->maAccel = g_strdup( aAccelerator.getStr() );
++        g_lo_menu_set_accelerator_to_item_in_section ( G_LO_MENU( mpMenuModel ), nSection, nItemPos, pItem->maAccel );
++    }
 +}
 +
 +void GtkSalMenu::SetItemCommand( unsigned nPos, SalMenuItem* pSalMenuItem, const rtl::OUString& aCommandStr )
 +{
-+    GtkSalMenuItem* pGtkSalMenuItem = static_cast< GtkSalMenuItem* >( pSalMenuItem );
++    GtkSalMenuItem* pItem = static_cast< GtkSalMenuItem* >( pSalMenuItem );
 +
-+    if ( pGtkSalMenuItem && pGtkSalMenuItem->mpMenuItem ) {
-+        rtl::OString aOCommandStr = rtl::OUStringToOString( aCommandStr, RTL_TEXTENCODING_UTF8 );
++    if ( pItem->mnType == MENUITEM_SEPARATOR ||
++         pItem->mpVCLMenu->GetPopupMenu( pItem->mnId ) != NULL ||
++         aCommandStr.isEmpty() )
++        return;
 +
-+        if ( pGtkSalMenuItem->maCommand )
-+            g_free( pGtkSalMenuItem->maCommand );
++    gchar* aCommand = (gchar*) rtl::OUStringToOString( aCommandStr, RTL_TEXTENCODING_UTF8 ).getStr();
 +
-+        pGtkSalMenuItem->maCommand = g_strdup( aOCommandStr.getStr() );
++    GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( GetActionGroupFromMenubar( this ) );
++    if ( pActionGroup == NULL )
++        return;
 +
-+        GLOActionGroup* pActionGroup = G_LO_ACTION_GROUP( GetActionGroupFromMenubar( this ) );
-+        if ( !pGtkSalMenuItem->mpVCLMenu->GetPopupMenu( pGtkSalMenuItem->mnId ) && pActionGroup ) {
-+            g_lo_action_group_insert( pActionGroup, pGtkSalMenuItem->maCommand, pGtkSalMenuItem );
-+        }
++    GVariant *pTarget = NULL;
 +
-+        gchar* aItemCommand = g_strconcat("win.", pGtkSalMenuItem->maCommand, NULL );
++    if ( g_action_group_has_action( G_ACTION_GROUP( pActionGroup ), aCommand ) == FALSE ) {
++        gboolean bChecked = ( pItem->mpVCLMenu->IsItemChecked( pItem->mnId ) ) ? TRUE : FALSE;
 +
-+        g_lo_menu_item_set_action_and_target( pGtkSalMenuItem->mpMenuItem, aItemCommand, NULL );
++        // FIXME: Why pItem->mnBits differs from GetItemBits value?
++        MenuItemBits bits = pItem->mpVCLMenu->GetItemBits( pItem->mnId );
 +
-+        g_free( aItemCommand );
++        if ( bits & MIB_CHECKABLE )
++        {
++            // Item is a checkmark button.
++            GVariantType* pStateType = g_variant_type_new( (gchar*) G_VARIANT_TYPE_BOOLEAN );
++            GVariant* pState = g_variant_new_boolean( bChecked );
 +
-+        if ( pGtkSalMenuItem->mpParentSection ) {
-+            g_lo_menu_remove( G_LO_MENU( pGtkSalMenuItem->mpParentSection ), pGtkSalMenuItem->mnPos );
-+            g_lo_menu_insert_item( G_LO_MENU( pGtkSalMenuItem->mpParentSection ), pGtkSalMenuItem->mnPos, pGtkSalMenuItem->mpMenuItem );
++            g_lo_action_group_insert_stateful( pActionGroup, aCommand, pItem, NULL, pStateType, NULL, pState );
++        }
++        else if ( bits & MIB_RADIOCHECK )
++        {
++            // Item is a radio button.
++            GVariantType* pParameterType = g_variant_type_new( (gchar*) G_VARIANT_TYPE_STRING );
++            GVariantType* pStateType = g_variant_type_new( (gchar*) G_VARIANT_TYPE_STRING );
++            //        GVariant* pStateHint = GetRadioButtonHints( pItem );
++            GVariant* pState = g_variant_new_string( "" );
++            pTarget = g_variant_new_string( aCommand );
++
++            g_lo_action_group_insert_stateful( pActionGroup, aCommand, pItem, pParameterType, pStateType, NULL, pState );
++        }
++        else
++        {
++            // Item is not special, so insert a stateless action.
++            g_lo_action_group_insert( pActionGroup, aCommand, pItem );
 +        }
 +    }
++
++    // Menu item is not updated unless it's necessary.
++    if ( ( pItem->maCommand != NULL ) && ( g_strcmp0( pItem->maCommand, aCommand ) == 0 ) )
++        return;
++
++    if ( pItem->maCommand != NULL )
++        g_free( pItem->maCommand );
++
++    pItem->maCommand = g_strdup( aCommand );
++
++    unsigned nSection, nItemPos;
++    GetItemSectionAndPosition( nPos, &nSection, &nItemPos );
++
++    gchar* aItemCommand = g_strconcat("win.", aCommand, NULL );
++
++    if ( pItem->maCommand )
++        g_free( pItem->maCommand );
++
++    pItem->maCommand = g_strdup( aCommand );
++
++    g_lo_menu_set_action_and_target_value_to_item_in_section( G_LO_MENU( mpMenuModel ), nSection, nItemPos, aItemCommand, pTarget );
++
++    g_free( aItemCommand );
 +}
 +
 +void GtkSalMenu::GetSystemMenuData( SystemMenuData* pData )
@@ -2773,34 +3012,29 @@ index 0000000..a82dbe2
 +GtkSalMenuItem::GtkSalMenuItem( const SalItemParams* pItemData ) :
 +    mnId( pItemData->nId ),
 +    mnBits( pItemData->nBits ),
-+    mnPos( 0 ),
-+    maCommand( NULL ),
++    mnType( pItemData->eType ),
 +    mpVCLMenu( pItemData->pMenu ),
 +    mpParentMenu( NULL ),
 +    mpSubMenu( NULL ),
-+    mpMenuItem( NULL ),
-+    mpStateType( NULL ),
-+    mpState( NULL )
++    maCommand( NULL ),
++    maLabel( NULL ),
++    maAccel( NULL )
 +{
-+    if ( pItemData->eType != MENUITEM_SEPARATOR ) {
-+        mpMenuItem = g_lo_menu_item_new( "EMPTY STRING", NULL );
-+
-+        maCommand = g_strdup( rtl::OUStringToOString( mpVCLMenu->GetItemCommand( mnId ), RTL_TEXTENCODING_UTF8 ).getStr() );
-+        gchar* aActionCommand = g_strconcat( "win.", maCommand, NULL );
-+        g_lo_menu_item_set_action_and_target( mpMenuItem, aActionCommand, NULL );
-+
-+        g_free( aActionCommand );
-+    }
 +}
 +
 +GtkSalMenuItem::~GtkSalMenuItem()
 +{
-+
-+    if ( mpMenuItem ) {
-+        g_object_unref( mpMenuItem );
++    if ( maCommand )
 +        g_free( maCommand );
-+    }
++
++    if ( maLabel )
++        g_free( maLabel );
++
++    if ( maAccel )
++        g_free( maAccel );
 +}
++
++/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
 diff --git a/vcl/unx/gtk3/window/gtk3gloactiongroup.cxx b/vcl/unx/gtk3/window/gtk3gloactiongroup.cxx
 new file mode 100644
 index 0000000..14a2bbb
diff --git a/scripts/update-unitymenus b/scripts/update-unitymenus
new file mode 100755
index 0000000..f75bdbb
--- /dev/null
+++ b/scripts/update-unitymenus
@@ -0,0 +1,12 @@
+#!/bin/bash
+CURDIR=`readlink -f .`
+TMPDIR=`mktemp -d`
+git clone $1 $TMPDIR/core
+cd $TMPDIR/core
+git checkout feature/unitymenus
+git rebase $2
+git log -1 feature/unitymenus > $CURDIR/patches/unitymenus.diff
+git diff --stat $2 feature/unitymenus >> $CURDIR/patches/unitymenus.diff
+git diff $2 feature/unitymenus >> $CURDIR/patches/unitymenus.diff
+cd $CURDIR
+rm -rf $TMPDIR

-- 
LibreOffice packaging repository


Reply to: