[Libreoffice-commits] .: Branch 'feature/unitymenus' - vcl/inc vcl/Library_vclplug_gtk.mk vcl/source vcl/unx

Antonio Fernandez afernandez at kemper.freedesktop.org
Wed Aug 8 08:19:37 PDT 2012


 vcl/Library_vclplug_gtk.mk            |    2 
 vcl/inc/salmenu.hxx                   |    2 
 vcl/inc/unx/gtk/gloactiongroup.h      |   62 +++
 vcl/inc/unx/gtk/glomenu.h             |   87 +++++
 vcl/inc/unx/gtk/gtksalmenu.hxx        |   10 
 vcl/source/window/menu.cxx            |    7 
 vcl/unx/gtk/window/gloactiongroup.cxx |  325 +++++++++++++++++++
 vcl/unx/gtk/window/glomenu.cxx        |  574 ++++++++++++++++++++++++++++++++++
 vcl/unx/gtk/window/gtksalmenu.cxx     |  284 ++++++++++------
 9 files changed, 1238 insertions(+), 115 deletions(-)

New commits:
commit e90a58c3403b6b4dc99970ee95aeebd44b496330
Author: Antonio Fernandez <antonio.fernandez at aentos.es>
Date:   Wed Aug 8 16:18:14 2012 +0100

    Added GLOMenu and GLOActionGroup. Menu is published with actions (not working)
    
    Change-Id: I3400980e4605fbf78755532c696e021d3466675b

diff --git a/vcl/Library_vclplug_gtk.mk b/vcl/Library_vclplug_gtk.mk
index 01f95af..c4cce2a 100644
--- a/vcl/Library_vclplug_gtk.mk
+++ b/vcl/Library_vclplug_gtk.mk
@@ -99,7 +99,9 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_gtk,\
     vcl/unx/gtk/gdi/salnativewidgets-gtk \
     vcl/unx/gtk/window/gtkframe \
     vcl/unx/gtk/window/gtkobject \
+    vcl/unx/gtk/window/gloactiongroup \
     vcl/unx/gtk/window/gtksalmenu \
+    vcl/unx/gtk/window/glomenu \
     vcl/unx/gtk/fpicker/resourceprovider \
     vcl/unx/gtk/fpicker/SalGtkPicker \
     vcl/unx/gtk/fpicker/SalGtkFilePicker \
diff --git a/vcl/inc/salmenu.hxx b/vcl/inc/salmenu.hxx
index b3dc25f..dafe19a 100644
--- a/vcl/inc/salmenu.hxx
+++ b/vcl/inc/salmenu.hxx
@@ -90,6 +90,8 @@ public:
     virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const Rectangle& rRect, sal_uLong nFlags);
     virtual bool AddMenuBarButton( const SalMenuButtonItem& ); // return false if not implemented or failure
     virtual void RemoveMenuBarButton( sal_uInt16 nId );
+
+    virtual void SetItemCommand( unsigned nPos, SalMenuItem* pSalMenuItem, const rtl::OUString& aCommandStr ) {}
     virtual void Freeze() {}
 
     // return an empty rectangle if not implemented
diff --git a/vcl/inc/unx/gtk/gloactiongroup.h b/vcl/inc/unx/gtk/gloactiongroup.h
new file mode 100644
index 0000000..b71ae47
--- /dev/null
+++ b/vcl/inc/unx/gtk/gloactiongroup.h
@@ -0,0 +1,62 @@
+#ifndef GLOACTIONGROUP_H
+#define GLOACTIONGROUP_H
+
+#include <gio/gio.h>
+//#include "gactionmap.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_LO_ACTION_GROUP                          (g_lo_action_group_get_type ())
+#define G_LO_ACTION_GROUP(inst)                         (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
+                                                         G_TYPE_LO_ACTION_GROUP, GLOActionGroup))
+#define G_LO_ACTION_GROUP_CLASS(klass)                  (G_TYPE_CHECK_CLASS_CAST ((klass),                       \
+                                                         G_TYPE_LO_ACTION_GROUP, GLOActionGroupClass))
+#define G_IS_LO_ACTION_GROUP(inst)                      (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
+                                                         G_TYPE_LO_ACTION_GROUP))
+#define G_IS_LO_ACTION_GROUP_CLASS(klass)               (G_TYPE_CHECK_CLASS_TYPE ((klass),                       \
+                                                         G_TYPE_LO_ACTION_GROUP))
+#define G_LO_ACTION_GROUP_GET_CLASS(inst)               (G_TYPE_INSTANCE_GET_CLASS ((inst),                      \
+                                                         G_TYPE_LO_ACTION_GROUP, GLOActionGroupClass))
+
+typedef struct _GLOActionGroupPrivate                   GLOActionGroupPrivate;
+typedef struct _GLOActionGroupClass                     GLOActionGroupClass;
+typedef struct _GLOActionGroup                          GLOActionGroup;
+
+struct _GLOActionGroup
+{
+    /*< private >*/
+    GObject parent_instance;
+
+    GLOActionGroupPrivate *priv;
+};
+
+struct _GLOActionGroupClass
+{
+    /*< private >*/
+    GObjectClass parent_class;
+
+    /*< private >*/
+    gpointer padding[12];
+};
+
+GType               g_lo_action_group_get_type                  (void) G_GNUC_CONST;
+
+GLOActionGroup *    g_lo_action_group_new                       (void);
+
+GAction *           g_lo_action_group_lookup                    (GLOActionGroup     *group,
+                                                                 const gchar        *action_name);
+
+void                g_lo_action_group_insert                    (GLOActionGroup     *group,
+                                                                 GAction            *action);
+
+void                g_lo_action_group_remove                    (GLOActionGroup     *group,
+                                                                 const gchar        *action_name);
+
+void                g_lo_action_group_add_entries               (GLOActionGroup     *group,
+                                                                 const GActionEntry *entries,
+                                                                 gint                n_entries,
+                                                                 gpointer            user_data);
+
+G_END_DECLS
+
+#endif // GLOACTIONGROUP_H
diff --git a/vcl/inc/unx/gtk/glomenu.h b/vcl/inc/unx/gtk/glomenu.h
new file mode 100644
index 0000000..d1df683
--- /dev/null
+++ b/vcl/inc/unx/gtk/glomenu.h
@@ -0,0 +1,87 @@
+#ifndef GLOMENU_H
+#define GLOMENU_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_LO_MENU                  (g_lo_menu_get_type())
+#define G_LO_MENU(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_LO_MENU, GLOMenu))
+#define G_IS_LO_MENU(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_LO_MENU))
+
+#define G_TYPE_LO_MENU_ITEM             (g_lo_menu_item_get_type())
+#define G_LO_MENU_ITEM(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_LO_MENU_ITEM, GLOMenuItem))
+#define G_IS_LO_MENU_ITEM(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_LO_MENU_ITEM))
+
+typedef struct _GLOMenuItem GLOMenuItem;
+typedef struct _GLOMenu     GLOMenu;
+
+GLIB_AVAILABLE_IN_2_32
+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_insert_item                       (GLOMenu        *menu,
+                                                             gint            position,
+                                                             GLOMenuItem    *item);
+void            g_lo_menu_insert                            (GLOMenu        *menu,
+                                                             gint            position,
+                                                             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_append_item                       (GLOMenu        *menu,
+                                                             GLOMenuItem    *item);
+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_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_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);
+
+G_END_DECLS
+
+
+#endif // GLOMENU_H
diff --git a/vcl/inc/unx/gtk/gtksalmenu.hxx b/vcl/inc/unx/gtk/gtksalmenu.hxx
index 65c2bc8..03c07bb 100644
--- a/vcl/inc/unx/gtk/gtksalmenu.hxx
+++ b/vcl/inc/unx/gtk/gtksalmenu.hxx
@@ -34,6 +34,7 @@
 #include <unx/gtk/gtkframe.hxx>
 #include <unx/salmenu.h>
 #include <gio/gio.h>
+#include "gloactiongroup.h"
 
 #include <vector>
 
@@ -43,15 +44,16 @@ class GtkSalMenuSection;
 class GtkSalMenu : public SalMenu
 {
 private:
-
+//    static GLOActionGroup*  pCurrentActionGroup;
     sal_Bool                mbMenuBar;
 
-    virtual void publishMenu( GMenuModel* );
+    virtual void publishMenu( GMenuModel*, GActionGroup* );
 
 public:
     std::vector< GtkSalMenuSection* >       maSections;
     std::vector< GtkSalMenuItem* >          maItems;
     GtkSalMenuSection*                      mpCurrentSection;
+    GActionEntry*                           mpActionEntry;
 
     Menu*                   mpVCLMenu;
     const GtkSalFrame*      mpFrame;
@@ -59,6 +61,7 @@ public:
     GDBusConnection*        pSessionBus;
     sal_Int32               mBusId;
     sal_Int32               mMenubarId;
+    sal_Int32               mActionGroupId;
 
     GtkSalMenu( sal_Bool bMenuBar );
     virtual ~GtkSalMenu();
@@ -76,6 +79,8 @@ public:
     virtual void SetItemImage( unsigned nPos, SalMenuItem* pSalMenuItem, const Image& rImage);
     virtual void SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const KeyCode& rKeyCode, const rtl::OUString& rKeyName );
     virtual void GetSystemMenuData( SystemMenuData* pData );
+    virtual void SetItemCommand( unsigned nPos, SalMenuItem* pSalMenuItem, const rtl::OUString& aCommandStr );
+    virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const Rectangle& rRect, sal_uLong nFlags);
     virtual void Freeze();
 };
 
@@ -100,6 +105,7 @@ public:
     GtkSalMenu*         mpParentMenu;         // The menu in which this menu item is inserted
     GtkSalMenu*         mpSubMenu;            // Sub menu of this item (if defined)
     GMenuItem*          mpMenuItem;           // The GMenuItem
+    GAction*            mpAction;             // The GAction associated with this item
 };
 
 #endif // GTKSALMENU_HXX
diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx
index cc15191..02fbe67 100644
--- a/vcl/source/window/menu.cxx
+++ b/vcl/source/window/menu.cxx
@@ -1958,10 +1958,15 @@ sal_Bool Menu::GetItemImageMirrorMode( sal_uInt16 nItemId ) const
 
 void Menu::SetItemCommand( sal_uInt16 nItemId, const String& rCommand )
 {
-    MenuItemData* pData = pItemList->GetData( nItemId );
+    size_t        nPos;
+    MenuItemData* pData = pItemList->GetData( nItemId, nPos );
 
     if ( pData )
         pData->aCommandStr = rCommand;
+
+    // update native menu
+    if( ImplGetSalMenu() && pData->pSalMenuItem )
+        ImplGetSalMenu()->SetItemCommand( nPos, pData->pSalMenuItem, rCommand );
 }
 
 const XubString& Menu::GetItemCommand( sal_uInt16 nItemId ) const
diff --git a/vcl/unx/gtk/window/gloactiongroup.cxx b/vcl/unx/gtk/window/gloactiongroup.cxx
new file mode 100644
index 0000000..dc3fb39
--- /dev/null
+++ b/vcl/unx/gtk/window/gloactiongroup.cxx
@@ -0,0 +1,325 @@
+#include <unx/gtk/gloactiongroup.h>
+
+//#include "gsimpleaction.h"
+//#include "gactionmap.h"
+//#include "gaction.h"
+
+#include <stdio.h>
+
+
+struct _GLOActionGroupPrivate
+{
+    GHashTable *table;  /* string -> GAction */
+};
+
+static void g_lo_action_group_iface_init (GActionGroupInterface *);
+static void g_lo_action_group_map_iface_init (GActionMapInterface *);
+
+G_DEFINE_TYPE_WITH_CODE (GLOActionGroup,
+    g_lo_action_group, G_TYPE_OBJECT,
+    G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP,
+                           g_lo_action_group_iface_init);
+    G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_MAP,
+                           g_lo_action_group_map_iface_init))
+
+static gchar **
+g_lo_action_group_list_actions (GActionGroup *group)
+{
+    puts(__FUNCTION__);
+    GLOActionGroup *loGroup = G_LO_ACTION_GROUP (group);
+    GHashTableIter iter;
+    gint n, i = 0;
+    gchar **keys;
+    gpointer key;
+
+    n = g_hash_table_size (loGroup->priv->table);
+    keys = g_new (gchar *, n + 1);
+
+    g_hash_table_iter_init (&iter, loGroup->priv->table);
+    while (g_hash_table_iter_next (&iter, &key, NULL))
+        keys[i++] = g_strdup ((gchar*) key);
+    g_assert_cmpint (i, ==, n);
+    keys[n] = NULL;
+
+    return keys;
+}
+
+static gboolean
+g_lo_action_group_query_action (GActionGroup        *group,
+                                const gchar         *action_name,
+                                gboolean            *enabled,
+                                const GVariantType **parameter_type,
+                                const GVariantType **state_type,
+                                GVariant           **state_hint,
+                                GVariant           **state)
+{
+    puts(__FUNCTION__);
+    GLOActionGroup *loGroup = G_LO_ACTION_GROUP (group);
+    GAction *action;
+
+    action = G_ACTION( g_hash_table_lookup (loGroup->priv->table, action_name) );
+
+    if (action == NULL)
+        return FALSE;
+
+    if (enabled)
+        *enabled = g_action_get_enabled (action);
+
+    if (parameter_type)
+        *parameter_type = g_action_get_parameter_type (action);
+
+    if (state_type)
+        *state_type = g_action_get_state_type (action);
+
+    if (state_hint)
+        *state_hint = g_action_get_state_hint (action);
+
+    if (state)
+        *state = g_action_get_state (action);
+
+    return TRUE;
+}
+
+static void
+g_lo_action_group_change_state (GActionGroup *group,
+                                const gchar  *action_name,
+                                GVariant     *value)
+{
+    puts(__FUNCTION__);
+    GLOActionGroup *loGroup = G_LO_ACTION_GROUP (group);
+    GAction *action;
+
+    action = G_ACTION( g_hash_table_lookup (loGroup->priv->table, action_name) );
+
+    if (action == NULL)
+        return;
+
+    g_action_change_state (action, value);
+}
+
+static void
+g_lo_action_group_activate (GActionGroup *group,
+                            const gchar  *action_name,
+                            GVariant     *parameter)
+{
+
+
+    puts(__FUNCTION__);
+    GLOActionGroup *loGroup = G_LO_ACTION_GROUP (group);
+    GAction *action;
+
+    action = G_ACTION( g_hash_table_lookup (loGroup->priv->table, action_name) );
+
+    if (action == NULL)
+        return;
+
+    g_action_activate (action, parameter);
+
+
+}
+
+static void
+action_enabled_notify (GAction     *action,
+                       GParamSpec  *pspec,
+                       gpointer     user_data)
+{
+    puts(__FUNCTION__);
+    g_action_group_action_enabled_changed (G_ACTION_GROUP( user_data ),
+                                           g_action_get_name (action),
+                                           g_action_get_enabled (action));
+}
+
+static void
+action_state_notify (GAction    *action,
+                     GParamSpec *pspec,
+                     gpointer    user_data)
+{
+    puts(__FUNCTION__);
+    GVariant *value;
+
+    value = g_action_get_state (action);
+    g_action_group_action_state_changed (G_ACTION_GROUP( user_data ),
+                                         g_action_get_name (action),
+                                         value);
+    g_variant_unref (value);
+}
+
+static void
+g_lo_action_group_disconnect (gpointer key,
+                              gpointer value,
+                              gpointer user_data)
+{
+    puts(__FUNCTION__);
+    g_signal_handlers_disconnect_by_func (value, (gpointer) action_enabled_notify,
+                                          user_data);
+    g_signal_handlers_disconnect_by_func (value, (gpointer) action_state_notify,
+                                          user_data);
+}
+
+static GAction *
+g_lo_action_group_lookup_action (GActionMap     *action_map,
+                                 const gchar    *action_name)
+{
+    puts(__FUNCTION__);
+    GLOActionGroup *loGroup = G_LO_ACTION_GROUP (action_map);
+
+    return G_ACTION( g_hash_table_lookup (loGroup->priv->table, action_name) );
+}
+
+static void
+g_lo_action_group_add_action (GActionMap *action_map,
+                              GAction    *action)
+{
+    puts(__FUNCTION__);
+    GLOActionGroup *loGroup = G_LO_ACTION_GROUP (action_map);
+    const gchar *action_name;
+    GAction *old_action;
+
+    action_name = g_action_get_name (action);
+    old_action = G_ACTION( g_hash_table_lookup (loGroup->priv->table, action_name) );
+
+    if (old_action != action)
+    {
+        if (old_action != NULL)
+        {
+            g_action_group_action_removed (G_ACTION_GROUP (loGroup),
+                                           action_name);
+            g_lo_action_group_disconnect (NULL, old_action, loGroup);
+        }
+
+        g_signal_connect (action, "notify::enabled",
+                          G_CALLBACK (action_enabled_notify), loGroup);
+
+        if (g_action_get_state_type (action) != NULL)
+            g_signal_connect (action, "notify::state",
+                              G_CALLBACK (action_state_notify), loGroup);
+
+        g_hash_table_insert (loGroup->priv->table,
+                             g_strdup (action_name),
+                             g_object_ref (action));
+
+        g_action_group_action_added (G_ACTION_GROUP (loGroup), action_name);
+    }
+}
+
+static void
+g_lo_action_group_remove_action (GActionMap  *action_map,
+                                 const gchar *action_name)
+{
+    puts(__FUNCTION__);
+    GLOActionGroup *loGroup = G_LO_ACTION_GROUP (action_map);
+    GAction *action;
+
+    action = G_ACTION( g_hash_table_lookup (loGroup->priv->table, action_name) );
+
+    if (action != NULL)
+    {
+        g_action_group_action_removed (G_ACTION_GROUP (loGroup), action_name);
+        g_lo_action_group_disconnect (NULL, action, loGroup);
+        g_hash_table_remove (loGroup->priv->table, action_name);
+    }
+}
+
+static void
+g_lo_action_group_finalize (GObject *object)
+{
+    puts(__FUNCTION__);
+    GLOActionGroup *loGroup = G_LO_ACTION_GROUP (object);
+
+    g_hash_table_foreach (loGroup->priv->table,
+                          g_lo_action_group_disconnect,
+                          loGroup);
+    g_hash_table_unref (loGroup->priv->table);
+
+    G_OBJECT_CLASS (g_lo_action_group_parent_class)
+            ->finalize (object);
+}
+
+static void
+g_lo_action_group_init (GLOActionGroup *group)
+{
+    puts(__FUNCTION__);
+    group->priv = G_TYPE_INSTANCE_GET_PRIVATE (group,
+                                                 G_TYPE_LO_ACTION_GROUP,
+                                                 GLOActionGroupPrivate);
+    group->priv->table = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                  g_free, g_object_unref);
+}
+
+static void
+g_lo_action_group_class_init (GLOActionGroupClass *klass)
+{
+    puts(__FUNCTION__);
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+    object_class->finalize = g_lo_action_group_finalize;
+
+    g_type_class_add_private (klass, sizeof (GLOActionGroupPrivate));
+}
+
+static void
+g_lo_action_group_iface_init (GActionGroupInterface *iface)
+{
+    puts(__FUNCTION__);
+    iface->list_actions = g_lo_action_group_list_actions;
+    iface->query_action = g_lo_action_group_query_action;
+    iface->change_action_state = g_lo_action_group_change_state;
+    iface->activate_action = g_lo_action_group_activate;
+}
+
+static void
+g_lo_action_group_map_iface_init (GActionMapInterface *iface)
+{
+    puts(__FUNCTION__);
+    iface->add_action = g_lo_action_group_add_action;
+    iface->remove_action = g_lo_action_group_remove_action;
+    iface->lookup_action = g_lo_action_group_lookup_action;
+}
+
+GLOActionGroup *
+g_lo_action_group_new (void)
+{
+    puts(__FUNCTION__);
+    return G_LO_ACTION_GROUP( g_object_new (G_TYPE_LO_ACTION_GROUP, NULL) );
+}
+
+GAction *
+g_lo_action_group_lookup (GLOActionGroup *group,
+                          const gchar    *action_name)
+{
+    puts(__FUNCTION__);
+    g_return_val_if_fail (G_IS_LO_ACTION_GROUP (group), NULL);
+
+    return g_action_map_lookup_action (G_ACTION_MAP (group), action_name);
+}
+
+void
+g_lo_action_group_insert (GLOActionGroup *group,
+                          GAction        *action)
+{
+    puts(__FUNCTION__);
+    g_return_if_fail (G_IS_LO_ACTION_GROUP (group));
+
+    g_action_map_add_action (G_ACTION_MAP (group), action);
+}
+
+void
+g_lo_action_group_remove (GLOActionGroup *group,
+                          const gchar    *action_name)
+{
+    puts(__FUNCTION__);
+    g_return_if_fail (G_IS_LO_ACTION_GROUP (group));
+
+    g_action_map_remove_action (G_ACTION_MAP (group), action_name);
+}
+
+void
+g_lo_action_group_add_entries (GLOActionGroup     *group,
+                               const GActionEntry *entries,
+                               gint                n_entries,
+                               gpointer            user_data)
+{
+    puts(__FUNCTION__);
+    g_action_map_add_action_entries (G_ACTION_MAP (group), entries, n_entries, user_data);
+}
+
diff --git a/vcl/unx/gtk/window/glomenu.cxx b/vcl/unx/gtk/window/glomenu.cxx
new file mode 100644
index 0000000..0da7245
--- /dev/null
+++ b/vcl/unx/gtk/window/glomenu.cxx
@@ -0,0 +1,574 @@
+#include <stdio.h>
+#include <string.h>
+
+#include <unx/gtk/glomenu.h>
+
+struct _GLOMenuItem
+{
+  GObject parent_instance;
+
+  GHashTable *attributes;
+  GHashTable *links;
+  gboolean    cow;
+};
+
+typedef GObjectClass GLOMenuItemClass;
+
+
+struct _GLOMenu
+{
+    GMenuModel  parent_instance;
+
+    GArray      *items;
+//    gboolean    mutable;
+};
+
+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);
+
+struct item
+{
+  GHashTable *attributes;
+  GHashTable *links;
+};
+
+static gboolean
+g_lo_menu_is_mutable (GMenuModel *model)
+{
+    puts(__FUNCTION__);
+//  GMenu *menu = G_MENU (model);
+
+//  return menu->mutable;
+    return TRUE;
+}
+
+static gint
+g_lo_menu_get_n_items (GMenuModel *model)
+{
+    puts(__FUNCTION__);
+    GLOMenu *menu = G_LO_MENU (model);
+
+    return menu->items->len;
+}
+
+static void
+g_lo_menu_get_item_attributes (GMenuModel  *model,
+                               gint         position,
+                               GHashTable **table)
+{
+    puts(__FUNCTION__);
+    GLOMenu *menu = G_LO_MENU (model);
+
+    *table = g_hash_table_ref (g_array_index (menu->items, struct item, position).attributes);
+}
+
+static void
+g_lo_menu_get_item_links (GMenuModel  *model,
+                          gint         position,
+                          GHashTable **table)
+{
+    puts(__FUNCTION__);
+    GLOMenu *menu = G_LO_MENU (model);
+
+    *table = g_hash_table_ref (g_array_index (menu->items, struct item, position).links);
+}
+
+static GMenuLinkIter *
+g_lo_menu_real_iterate_item_links (GMenuModel *model,
+                                      gint        item_index)
+{
+    puts(__FUNCTION__);
+    GHashTable *table = NULL;
+    GMenuLinkIter *result;
+
+    G_MENU_MODEL_GET_CLASS (model)
+            ->get_item_links (model, item_index, &table);
+
+    if (table)
+    {
+//        GMenuLinkHashIter *iter = g_object_new (g_menu_link_hash_iter_get_type (), NULL);
+//        g_hash_table_iter_init (&iter->iter, table);
+//        iter->table = g_hash_table_ref (table);
+//        result = G_MENU_LINK_ITER (iter);
+    }
+    else
+    {
+        g_critical ("GMenuModel implementation '%s' doesn't override iterate_item_links() "
+                    "and fails to return sane values from get_item_links()",
+                    G_OBJECT_TYPE_NAME (model));
+        result = NULL;
+    }
+
+    if (table != NULL)
+        g_hash_table_unref (table);
+
+    return result;
+}
+
+static GMenuModel *
+g_lo_menu_real_get_item_link (GMenuModel  *model,
+                                 gint         item_index,
+                                 const gchar *link)
+{
+    puts(__FUNCTION__);
+    GHashTable *table = NULL;
+    GMenuModel *value = NULL;
+
+    G_MENU_MODEL_GET_CLASS (model)
+            ->get_item_links (model, item_index, &table);
+
+    if (table != NULL)
+        value = G_MENU_MODEL( g_hash_table_lookup (table, link) );
+    else
+        g_assert_not_reached ();
+
+    if (value != NULL)
+        g_object_ref (value);
+
+    if (table != NULL)
+        g_hash_table_unref (table);
+
+    return value;
+}
+
+GLOMenu *
+g_lo_menu_new (void)
+{
+    puts(__FUNCTION__);
+    return G_LO_MENU( g_object_new (G_TYPE_LO_MENU, NULL) );
+}
+
+void
+g_lo_menu_insert (GLOMenu       *menu,
+                  gint           position,
+                  const gchar   *label,
+                  const gchar   *detailed_action)
+{
+    puts(__FUNCTION__);
+    GLOMenuItem *menu_item;
+
+    menu_item = g_lo_menu_item_new (label, detailed_action);
+    g_lo_menu_insert_item (menu, position, menu_item);
+    g_object_unref (menu_item);
+}
+
+void
+g_lo_menu_append (GLOMenu       *menu,
+                  const gchar   *label,
+                  const gchar   *detailed_action)
+{
+    puts(__FUNCTION__);
+    g_lo_menu_insert (menu, -1, label, detailed_action);
+}
+
+void
+g_lo_menu_insert_section (GLOMenu       *menu,
+                          gint          position,
+                          const gchar   *label,
+                          GMenuModel    *section)
+{
+    GLOMenuItem *menu_item;
+
+    menu_item = g_lo_menu_item_new_section (label, section);
+    g_lo_menu_insert_item (menu, position, menu_item);
+    g_object_unref (menu_item);
+}
+
+void
+g_lo_menu_prepend_section (GLOMenu      *menu,
+                           const gchar  *label,
+                           GMenuModel   *section)
+{
+    g_lo_menu_insert_section (menu, 0, label, section);
+}
+
+void
+g_lo_menu_append_section (GLOMenu       *menu,
+                          const gchar   *label,
+                          GMenuModel    *section)
+{
+    g_lo_menu_insert_section (menu, -1, label, section);
+}
+
+
+
+void
+g_lo_menu_insert_submenu (GLOMenu       *menu,
+                          gint           position,
+                          const gchar   *label,
+                          GMenuModel    *submenu)
+{
+    GLOMenuItem *menu_item;
+
+    menu_item = g_lo_menu_item_new_submenu (label, submenu);
+    g_lo_menu_insert_item (menu, position, menu_item);
+    g_object_unref (menu_item);
+}
+
+void
+g_lo_menu_append_submenu (GLOMenu       *menu,
+                          const gchar   *label,
+                          GMenuModel    *submenu)
+{
+    puts(__FUNCTION__);
+    g_lo_menu_insert_submenu (menu, -1, label, submenu);
+}
+
+static void
+g_lo_menu_clear_item (struct item *item)
+{
+    puts(__FUNCTION__);
+    if (item->attributes != NULL)
+        g_hash_table_unref (item->attributes);
+    if (item->links != NULL)
+        g_hash_table_unref (item->links);
+}
+
+static void
+g_lo_menu_dispose (GObject *gobject)
+{
+    puts(__FUNCTION__);
+    G_OBJECT_CLASS (g_lo_menu_parent_class)->dispose (gobject);
+}
+
+static void
+g_lo_menu_finalize (GObject *gobject)
+{
+    puts(__FUNCTION__);
+    GLOMenu *menu = G_LO_MENU (gobject);
+    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 (gobject);
+}
+
+static void
+g_lo_menu_class_init (GLOMenuClass *klass)
+{
+    puts(__FUNCTION__);
+    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;
+    model_class->iterate_item_links = g_lo_menu_real_iterate_item_links;
+    model_class->get_item_link = g_lo_menu_real_get_item_link;
+}
+
+static void
+g_lo_menu_init (GLOMenu *self)
+{
+    puts(__FUNCTION__);
+    self->items = g_array_new (FALSE, FALSE, sizeof (struct item));
+}
+
+void
+g_lo_menu_insert_item (GLOMenu      *menu,
+                       gint          position,
+                       GLOMenuItem  *item)
+{
+    puts(__FUNCTION__);
+    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 > 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;
+
+    g_array_insert_val (menu->items, position, new_item);
+    g_menu_model_items_changed (G_MENU_MODEL (menu), position, 0, 1);
+}
+
+void
+g_lo_menu_append_item (GLOMenu      *menu,
+                       GLOMenuItem  *item)
+{
+  g_lo_menu_insert_item (menu, -1, item);
+}
+
+/*
+ * GLOMenuItem
+ */
+
+static void
+g_lo_menu_item_clear_cow (GLOMenuItem *menu_item)
+{
+  if (menu_item->cow)
+    {
+      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 ((GVariant*) val));
+      g_hash_table_unref (menu_item->links);
+      menu_item->links = newHash;
+
+      menu_item->cow = FALSE;
+    }
+}
+
+static void
+g_lo_menu_item_finalize (GObject *object)
+{
+    puts(__FUNCTION__);
+    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)
+{
+    puts(__FUNCTION__);
+    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)
+{
+    puts(__FUNCTION__);
+    klass->finalize = g_lo_menu_item_finalize;
+}
+
+static gboolean
+valid_attribute_name (const gchar *name)
+{
+    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;
+}
+
+void
+g_lo_menu_item_set_attribute_value (GLOMenuItem *menu_item,
+                                    const gchar *attribute,
+                                    GVariant    *value)
+{
+    puts(__FUNCTION__);
+    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_lo_menu_item_clear_cow (menu_item);
+
+    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_item_set_link (GLOMenuItem *menu_item,
+                         const gchar *link,
+                         GMenuModel  *model)
+{
+    g_return_if_fail (G_IS_LO_MENU_ITEM (menu_item));
+    g_return_if_fail (link != NULL);
+    g_return_if_fail (valid_attribute_name (link));
+
+    g_lo_menu_item_clear_cow (menu_item);
+
+    if (model != NULL)
+        g_hash_table_insert (menu_item->links, g_strdup (link), g_object_ref (model));
+    else
+        g_hash_table_remove (menu_item->links, link);
+}
+
+void
+g_lo_menu_item_set_label (GLOMenuItem   *menu_item,
+                          const gchar   *label)
+{
+    puts(__FUNCTION__);
+    GVariant *value;
+
+    if (label != NULL)
+        value = g_variant_new_string (label);
+    else
+        value = NULL;
+
+    g_lo_menu_item_set_attribute_value (menu_item, G_MENU_ATTRIBUTE_LABEL, value);
+}
+
+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);
+}
+
+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);
+}
+
+void
+g_lo_menu_item_set_action_and_target_value (GLOMenuItem *menu_item,
+                                            const gchar *action,
+                                            GVariant    *target_value)
+{
+  GVariant *action_value;
+
+  if (action != NULL)
+    {
+      action_value = g_variant_new_string (action);
+    }
+  else
+    {
+      action_value = NULL;
+      target_value = NULL;
+    }
+
+  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);
+}
+
+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;
+
+  g_lo_menu_item_set_action_and_target_value (menu_item, action, value);
+}
+
+void
+g_lo_menu_item_set_detailed_action (GLOMenuItem *menu_item,
+                                    const gchar *detailed_action)
+{
+    puts(__FUNCTION__);
+    const gchar *sep;
+
+    sep = strstr (detailed_action, "::");
+
+    if (sep != NULL)
+    {
+        gchar *action;
+
+        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);
+    }
+
+    else
+        g_lo_menu_item_set_action_and_target_value (menu_item, detailed_action, NULL);
+}
+
+GLOMenuItem *
+g_lo_menu_item_new (const gchar *label,
+                    const gchar *detailed_action)
+{
+    puts(__FUNCTION__);
+    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);
+
+    if (detailed_action != NULL)
+      g_lo_menu_item_set_detailed_action (menu_item, detailed_action);
+
+    return menu_item;
+}
+
+GLOMenuItem *
+g_lo_menu_item_new_submenu (const gchar *label,
+                            GMenuModel  *submenu)
+{
+  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);
+
+  g_lo_menu_item_set_submenu (menu_item, submenu);
+
+  return menu_item;
+}
+
+GLOMenuItem *
+g_lo_menu_item_new_section (const gchar *label,
+                            GMenuModel  *section)
+{
+    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);
+
+    g_lo_menu_item_set_section (menu_item, section);
+
+    return menu_item;
+}
+
+
diff --git a/vcl/unx/gtk/window/gtksalmenu.cxx b/vcl/unx/gtk/window/gtksalmenu.cxx
index f612a23..134d5e2 100644
--- a/vcl/unx/gtk/window/gtksalmenu.cxx
+++ b/vcl/unx/gtk/window/gtksalmenu.cxx
@@ -1,87 +1,125 @@
 
 #include "unx/gtk/gtksalmenu.hxx"
 
-#include <gtk/gtk.h>
+//#include <gtk/gtk.h>
+#include <unx/gtk/glomenu.h>
+#include <unx/gtk/gloactiongroup.h>
+
 #include <iostream>
 
 using namespace std;
 
-
-//const GtkSalMenu * GtkSalMenu::pCurrentMenubar = NULL;
-
-#define BUS_NAME "org.gtk.LibreOffice"
-#define OBJ_PATH "/org/gtk/LibreOffice"
+#define GTK_MENU_BUS_NAME   "org.libreoffice"
+#define GTK_MENU_OBJ_PATH   "/org/libreoffice"
 
 static void
-quit (GSimpleAction *action,
-      GVariant      *parameter,
-      gpointer       user_data)
+dispatchAction (GSimpleAction   *action,
+                GVariant        *parameter,
+                gpointer        user_data)
 {
-    exit(1);
+    cout << "ACTION: " << g_action_get_name( G_ACTION( action ) ) << " triggered." << endl;
+
+    if ( user_data ) {
+        GtkSalMenuItem *pSalMenuItem = static_cast< GtkSalMenuItem* >( user_data );
+
+        if ( !pSalMenuItem->mpSubMenu ) {
+            if ( !pSalMenuItem->mpVCLMenu->IsMenuBar() ) {
+//                ((PopupMenu*) pSalMenuItem->mpVCLMenu)->SetSelectedEntry( pSalMenuItem->mnId );
+//                pSalMenuItem->mpVCLMenu->Select();
+//                pSalMenuItem->mpVCLMenu->DeSelect();
+            }
+        }
+    }
 }
 
-GMenuModel* generateMenuModel2( Menu *pVCLMenu )
-{
-    if (!pVCLMenu)
-        return NULL;
+//GMenuModel* generateMenuModel2( Menu *pVCLMenu )
+//{
+//    if (!pVCLMenu)
+//        return NULL;
 
-    GMenu *pMenuModel = g_menu_new();
-    GMenu *pSectionMenuModel = g_menu_new();
+//    GMenu *pMenuModel = g_menu_new();
+//    GMenu *pSectionMenuModel = g_menu_new();
 
-    for (int i = 0; i < pVCLMenu->GetItemCount(); i++) {
-        MenuItemType itemType = pVCLMenu->GetItemType( i );
+//    for (int i = 0; i < pVCLMenu->GetItemCount(); i++) {
+//        MenuItemType itemType = pVCLMenu->GetItemType( i );
 
-        if ( itemType == MENUITEM_SEPARATOR ) {
-            g_menu_append_section( pMenuModel, NULL, G_MENU_MODEL( pSectionMenuModel ) );
-            pSectionMenuModel = g_menu_new();
-        } else {
-            sal_Int16 nId = pVCLMenu->GetItemId( i );
+//        if ( itemType == MENUITEM_SEPARATOR ) {
+//            g_menu_append_section( pMenuModel, NULL, G_MENU_MODEL( pSectionMenuModel ) );
+//            pSectionMenuModel = g_menu_new();
+//        } else {
+//            sal_Int16 nId = pVCLMenu->GetItemId( i );
 
-            // Menu item label
-            rtl::OUString aTextLabel = pVCLMenu->GetItemText( nId );
-            rtl::OUString aText = aTextLabel.replace( '~', '_' );
-            rtl::OString aConvertedText = OUStringToOString(aText, RTL_TEXTENCODING_UTF8);
+//            // Menu item label
+//            rtl::OUString aTextLabel = pVCLMenu->GetItemText( nId );
+//            rtl::OUString aText = aTextLabel.replace( '~', '_' );
+//            rtl::OString aConvertedText = OUStringToOString(aText, RTL_TEXTENCODING_UTF8);
 
-            // Menu item accelerator key
-//            KeyCode accelKey = pVCLMenu->GetAccelKey( nId );
+//            // Menu item accelerator key
+////            KeyCode accelKey = pVCLMenu->GetAccelKey( nId );
 
-            GMenuItem *menuItem = g_menu_item_new( (char*) aConvertedText.getStr(), NULL);
+//            GMenuItem *menuItem = g_menu_item_new( (char*) aConvertedText.getStr(), NULL);
 
-            GMenuModel *pSubmenu = generateMenuModel2( pVCLMenu->GetPopupMenu( nId ) );
+//            GMenuModel *pSubmenu = generateMenuModel2( pVCLMenu->GetPopupMenu( nId ) );
 
-            g_menu_item_set_submenu( menuItem, pSubmenu );
+//            g_menu_item_set_submenu( menuItem, pSubmenu );
 
-            g_menu_append_item( pSectionMenuModel, menuItem );
-        }
-    }
+//            g_menu_append_item( pSectionMenuModel, menuItem );
+//        }
+//    }
 
-    g_menu_append_section( pMenuModel, NULL, G_MENU_MODEL( pSectionMenuModel ) );
+//    g_menu_append_section( pMenuModel, NULL, G_MENU_MODEL( pSectionMenuModel ) );
 
-    return G_MENU_MODEL( pMenuModel );
-}
+//    return G_MENU_MODEL( pMenuModel );
+//}
 
 GMenuModel *generateMockMenuModel()
 {
-    GMenu *menu = g_menu_new ();
-    //            g_menu_append (menu, "Add", "app.add");
-    //            g_menu_append (menu, "Del", "app.del");
+//    GLOMenu *menu = g_lo_menu_new ();
+
+//    GLOMenu *fileMenu = g_lo_menu_new();
+//    GLOMenu *fileSubmenu = g_lo_menu_new ();
+//    g_lo_menu_append( fileSubmenu, "NewMenuOption1", NULL );
+//    g_lo_menu_append_submenu( fileMenu, "New", G_MENU_MODEL( fileSubmenu ) );
+//    g_lo_menu_append( fileMenu, "Quit", "app.quit" );
+
+//    GLOMenu *editMenu = g_lo_menu_new();
+//    GLOMenu *editSubmenu = g_lo_menu_new ();
+//    g_lo_menu_append( editSubmenu, "EditMenuOption1", NULL );
+//    g_lo_menu_append_item( editSubmenu, editMenuItem );
+//    g_lo_menu_append_submenu( editMenu, "Format", G_MENU_MODEL( editSubmenu ) );
+
+//    g_lo_menu_append_submenu( menu, "File", G_MENU_MODEL( fileMenu ) );
+//    g_lo_menu_append_submenu( menu, "Edit", G_MENU_MODEL( editMenu ) );
+
+    GMenu *menu = g_menu_new();
+
     GMenu *fileMenu = g_menu_new();
-    GMenu *submenu = g_menu_new ();
-    g_menu_append( submenu, "Option1", NULL );
-    g_menu_append( submenu, "Option2", NULL );
+    GMenu *fileSubmenu = g_menu_new();
+    g_menu_append( fileSubmenu, "Text Document", "app.private:factory/swriter" );
+    g_menu_append_submenu( fileMenu, "New", G_MENU_MODEL( fileSubmenu ) );
+    g_menu_append( fileMenu, "Exit", "app..uno:Quit" );
 
-    g_menu_append_section( fileMenu, NULL, G_MENU_MODEL(submenu));
+//    g_lo_menu_append_section( fileMenu, NULL, G_MENU_MODEL(submenu));
+//    GMenu *editMenu = g_menu_new();
+//    GMenu *editSubmenu = g_menu_new();
+//    g_menu_append( editSubmenu, "EditMenuOption1", "app.dispatch" );
+//    g_lo_menu_append_item( editSubmenu, editMenuItem );
+//    g_menu_append_submenu( editMenu, "Format", G_MENU_MODEL( editSubmenu ) );
+//    g_lo_menu_append( editMenu, "Quit", "app.quit" );
 
-    g_menu_append (fileMenu, "Quit", "app.quit");
 
-    g_menu_append_submenu( menu, "Test", G_MENU_MODEL( fileMenu ));
+    g_menu_append_submenu( menu, "File", G_MENU_MODEL( fileMenu ) );
+//    g_menu_append_submenu( menu, "Edit", G_MENU_MODEL( editMenu ) );
+
+//    g_menu_append_submenu( menu, "Test", G_MENU_MODEL( fileMenu ));
+
 
     return G_MENU_MODEL( menu );
 }
 
-GMenuModel *generateMenuModel( GtkSalMenu* );
+GMenuModel *generateMenuModelAndActions( GtkSalMenu*, GLOActionGroup* );
 
-GMenuModel *generateSectionMenuModel( GtkSalMenuSection *pSection )
+GMenuModel *generateSectionMenuModel( GtkSalMenuSection *pSection, GLOActionGroup *pActionGroup )
 {
     if ( !pSection )
         return NULL;
@@ -93,17 +131,21 @@ GMenuModel *generateSectionMenuModel( GtkSalMenuSection *pSection )
         GMenuItem *pMenuItem = pSalMenuItem->mpMenuItem;
 
         if (pSalMenuItem->mpSubMenu) {
-            GMenuModel *pSubmenu = generateMenuModel( pSalMenuItem->mpSubMenu );
+            GMenuModel *pSubmenu = generateMenuModelAndActions( pSalMenuItem->mpSubMenu, pActionGroup );
             g_menu_item_set_submenu( pMenuItem, pSubmenu );
         }
 
         g_menu_append_item( pSectionMenuModel, pMenuItem );
+
+        if (pSalMenuItem->mpAction) {
+            g_lo_action_group_insert( pActionGroup, pSalMenuItem->mpAction );
+        }
     }
 
     return G_MENU_MODEL( pSectionMenuModel );
 }
 
-GMenuModel *generateMenuModel( GtkSalMenu *pMenu )
+GMenuModel *generateMenuModelAndActions( GtkSalMenu *pMenu, GLOActionGroup *pActionGroup )
 {
     if ( !pMenu )
         return NULL;
@@ -115,17 +157,18 @@ GMenuModel *generateMenuModel( GtkSalMenu *pMenu )
         GMenuItem *pMenuItem = pSalMenuItem->mpMenuItem;
 
         if (pSalMenuItem->mpSubMenu) {
-            GMenuModel *pSubmenu = generateMenuModel( pSalMenuItem->mpSubMenu );
+            GMenuModel *pSubmenu = generateMenuModelAndActions( pSalMenuItem->mpSubMenu, pActionGroup );
             g_menu_item_set_submenu( pMenuItem, pSubmenu );
         }
 
         g_menu_append_item( pMenuModel, pMenuItem );
+        g_lo_action_group_insert( pActionGroup, pSalMenuItem->mpAction );
     }
 
     for (int i=0; i < pMenu->maSections.size(); i++) {
         GtkSalMenuSection *pSection = pMenu->maSections[ i ];
 
-        GMenuModel *pSectionMenuModel = generateSectionMenuModel( pSection );
+        GMenuModel *pSectionMenuModel = generateSectionMenuModel( pSection, pActionGroup );
 
         g_menu_append_section( pMenuModel, NULL, pSectionMenuModel );
     }
@@ -161,19 +204,20 @@ gdk_x11_window_set_utf8_property  (GdkWindow *window,
     }
 }
 
-void GtkSalMenu::publishMenu( GMenuModel *pMenu )
+void GtkSalMenu::publishMenu( GMenuModel *pMenu, GActionGroup *pActionGroup )
 {
-    pSessionBus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
-    if(!pSessionBus) puts ("Fail bus get");
-    mBusId = g_bus_own_name_on_connection (pSessionBus, "org.libreoffice", G_BUS_NAME_OWNER_FLAGS_NONE, NULL, NULL, NULL, NULL);
-    if(!mBusId) puts ("Fail own name");
-
 //        guint appmenuID = g_dbus_connection_export_menu_model (bus, "/org/libreoffice/menus/appmenu", mpMenuModel, NULL);
 //        if(!appmenuID) puts("Fail export appmenu");
+
+    if ( mMenubarId ) {
+        g_dbus_connection_unexport_menu_model( pSessionBus, mMenubarId );
+        mbMenuBar = 0;
+    }
+
     mMenubarId = g_dbus_connection_export_menu_model (pSessionBus, "/org/libreoffice/menus/menubar", pMenu, NULL);
     if(!mMenubarId) puts("Fail export menubar");
 
-//        g_object_unref (menu);
+    g_dbus_connection_export_action_group( pSessionBus, GTK_MENU_OBJ_PATH, pActionGroup, NULL);
 }
 
 GtkSalMenu::GtkSalMenu( sal_Bool bMenuBar ) :
@@ -181,13 +225,22 @@ GtkSalMenu::GtkSalMenu( sal_Bool bMenuBar ) :
     mpVCLMenu( NULL ),
     aDBusMenubarPath( NULL ),
     pSessionBus( NULL ),
+    mpActionEntry( NULL ),
     mBusId( 0 ),
-    mMenubarId( 0 )
+    mMenubarId( 0 ),
+    mActionGroupId ( 0 )
 {
     if (!bMenuBar) {
         mpCurrentSection = new GtkSalMenuSection();
         maSections.push_back( mpCurrentSection );
+    } else {
+        pSessionBus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
+        if(!pSessionBus) puts ("Fail bus get");
+
+        mBusId = g_bus_own_name_on_connection (pSessionBus, GTK_MENU_BUS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE, NULL, NULL, NULL, NULL);
+        if(!mBusId) puts ("Fail own name");
     }
+
 }
 
 GtkSalMenu::~GtkSalMenu()
@@ -274,12 +327,20 @@ void GtkSalMenu::SetFrame( const SalFrame* pFrame )
     GdkWindow *gdkWindow = gtk_widget_get_window( widget );
 
     if (gdkWindow) {
-        gdk_x11_window_set_utf8_property (gdkWindow, "_GTK_APPLICATION_ID", "org.libreoffice");
-        gdk_x11_window_set_utf8_property (gdkWindow, "_GTK_UNIQUE_BUS_NAME", "org.libreoffice");
-        gdk_x11_window_set_utf8_property (gdkWindow, "_GTK_APPLICATION_OBJECT_PATH", "/org/libreoffice");
-        gdk_x11_window_set_utf8_property (gdkWindow, "_GTK_WINDOW_OBJECT_PATH", "/org/libreoffice/windows");
+        XLIB_Window windowId = GDK_WINDOW_XID( gdkWindow );
+
+        gchar *aWindowObjectPath = g_strdup_printf( "%s/window/%u", GTK_MENU_OBJ_PATH, windowId );
+        gchar *aMenubarObjectPath = g_strconcat( GTK_MENU_OBJ_PATH, "/menus/menubar", NULL );
+
+//        gdk_x11_window_set_utf8_property (gdkWindow, "_GTK_APPLICATION_ID", "org.libreoffice");
+        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", GTK_MENU_OBJ_PATH );
+        gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_WINDOW_OBJECT_PATH", aWindowObjectPath );
 //        gdk_x11_window_set_utf8_property (gdkWindow, "_GTK_APP_MENU_OBJECT_PATH", "/org/libreoffice/menus/appmenu");
-        gdk_x11_window_set_utf8_property (gdkWindow, "_GTK_MENUBAR_OBJECT_PATH", "/org/libreoffice/menus/menubar");
+        gdk_x11_window_set_utf8_property ( gdkWindow, "_GTK_MENUBAR_OBJECT_PATH", aMenubarObjectPath );
+
+        g_free( aWindowObjectPath );
+        g_free( aMenubarObjectPath );
     }
 }
 
@@ -291,6 +352,14 @@ void GtkSalMenu::CheckItem( unsigned nPos, sal_Bool bCheck )
 void GtkSalMenu::EnableItem( unsigned nPos, sal_Bool bEnable )
 {
     cout << __FUNCTION__ << endl;
+
+    if (nPos < maItems.size()) {
+        GtkSalMenuItem *pSalMenuItem = maItems[ nPos ];
+
+        if ( pSalMenuItem->mpAction ) {
+            g_simple_action_set_enabled( G_SIMPLE_ACTION( pSalMenuItem->mpAction ), (gboolean) bEnable );
+        }
+    }
 }
 
 void GtkSalMenu::SetItemText( unsigned nPos, SalMenuItem* pSalMenuItem, const rtl::OUString& rText )
@@ -318,7 +387,7 @@ void GtkSalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const
 {
     cout << __FUNCTION__ << " KeyName: " << rKeyName << endl;
 
-//    GtkSalMenuItem *pMenuItem = static_cast< GtkSalMenuItem* >( pSalMenuItem );
+    GtkSalMenuItem *pMenuItem = static_cast< GtkSalMenuItem* >( pSalMenuItem );
 
 //    rtl::OString aConvertedKeyName = OUStringToOString( rKeyName, RTL_TEXTENCODING_UTF8 );
 
@@ -326,63 +395,53 @@ void GtkSalMenu::SetAccelerator( unsigned nPos, SalMenuItem* pSalMenuItem, const
 //    g_menu_item_set_attribute_value( pMenuItem->mpMenuItem, "accel", gaKeyCode );
 }
 
-void GtkSalMenu::GetSystemMenuData( SystemMenuData* pData )
+void GtkSalMenu::SetItemCommand( unsigned nPos, SalMenuItem* pSalMenuItem, const rtl::OUString& aCommandStr )
 {
-    cout << __FUNCTION__ << endl;
-}
-
-void printMenu( GtkSalMenu * );
+    GtkSalMenuItem* pGtkSalMenuItem = static_cast< GtkSalMenuItem* >( pSalMenuItem );
 
-void printSection ( GtkSalMenuSection *pSection )
-{
-    if (pSection) {
-        for (int i = 0; i < pSection->maItems.size(); i++) {
-            GtkSalMenuItem *pSalMenuItem = static_cast< GtkSalMenuItem* >(pSection->maItems[ i ]);
-            cout << pSalMenuItem->mpVCLMenu->GetItemText( pSalMenuItem->mnId ) << endl;
-
-            if (pSalMenuItem->mpSubMenu) {
-                cout << "--- Submenu ---" << endl;
-                printMenu( pSalMenuItem->mpSubMenu);
-                cout << "---------------" << endl;
-            }
-        }
+    if ( pGtkSalMenuItem->mpAction ) {
+        g_object_unref( pGtkSalMenuItem->mpAction );
     }
+
+    rtl::OString aOCommandStr = rtl::OUStringToOString( aCommandStr, RTL_TEXTENCODING_UTF8 );
+
+    GSimpleAction *pAction = g_simple_action_new( aOCommandStr.getStr(), NULL );
+
+    // Disable action by default.
+//    g_simple_action_set_enabled( pAction, FALSE );
+
+    g_signal_connect(pAction, "activate", G_CALLBACK( dispatchAction ), pGtkSalMenuItem);
+
+    pGtkSalMenuItem->mpAction = G_ACTION( pAction );
+
+
+    rtl::OString aItemCommand = "app." + aOCommandStr;
+    g_menu_item_set_action_and_target( pGtkSalMenuItem->mpMenuItem, aItemCommand.getStr(), NULL );
+//    g_object_unref( aGCommand );
 }
 
-void printMenu( GtkSalMenu *pMenu )
+void GtkSalMenu::GetSystemMenuData( SystemMenuData* pData )
 {
-    if ( pMenu ) {
-        for (int i = 0; i < pMenu->maItems.size(); i++) {
-            GtkSalMenuItem *pSalMenuItem = static_cast< GtkSalMenuItem* >(pMenu->maItems[ i ]);
-            cout << pSalMenuItem->mpVCLMenu->GetItemText( pSalMenuItem->mnId ) << endl;
-
-            if (pSalMenuItem->mpSubMenu) {
-                cout << "--- Submenu ---" << endl;
-                printMenu( pSalMenuItem->mpSubMenu);
-                cout << "---------------" << endl;
-            }
-        }
-
-        for (int i = 0; i < pMenu->maSections.size(); i++) {
-            GtkSalMenuSection *pSalMenuSection = static_cast< GtkSalMenuSection* >(pMenu->maSections[ i ]);
+    cout << __FUNCTION__ << endl;
+}
 
-            cout << "--- Submenu ---" << endl;
-            printSection( pSalMenuSection );
-            cout << "---------------" << endl;
-        }
-    }
+bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow * pWin, const Rectangle& rRect, sal_uLong nFlags)
+{
+    cout << __FUNCTION__ << endl;
+    return TRUE;
 }
 
 void GtkSalMenu::Freeze()
 {
     cout << __FUNCTION__ << endl;
-    GMenuModel *mpMenuModel = generateMenuModel( this );
-    this->publishMenu( mpMenuModel );
-    g_object_unref( mpMenuModel );
+    GLOActionGroup *mpActionGroup = g_lo_action_group_new();
 
-    cout << "==================== MENUBAR ===================" << endl;
-    printMenu( this );
-    cout << "================================================" << endl;
+    GMenuModel *mpMenuModel = generateMenuModelAndActions( this, mpActionGroup );
+//    GMenuModel *mpMenuModel = generateMockMenuModel();
+
+//    this->publishMenu( mpMenuModel, G_ACTION_GROUP( mpActionGroup ) );
+    this->publishMenu( mpMenuModel, G_ACTION_GROUP( mpActionGroup ) );
+    g_object_unref( mpMenuModel );
 }
 
 // =======================================================================
@@ -407,7 +466,8 @@ GtkSalMenuItem::GtkSalMenuItem( const SalItemParams* pItemData ) :
     mpVCLMenu( pItemData->pMenu ),
     mpParentMenu( NULL ),
     mpSubMenu( NULL ),
-    mpMenuItem( NULL )
+    mpMenuItem( NULL ),
+    mpAction( NULL )
 {
     cout << __FUNCTION__ << "Type: " << pItemData->eType << endl;
 


More information about the Libreoffice-commits mailing list