summaryrefslogtreecommitdiffstats
path: root/vcl/unx/gtk3/gloactiongroup.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/gtk3/gloactiongroup.cxx')
-rw-r--r--vcl/unx/gtk3/gloactiongroup.cxx405
1 files changed, 405 insertions, 0 deletions
diff --git a/vcl/unx/gtk3/gloactiongroup.cxx b/vcl/unx/gtk3/gloactiongroup.cxx
new file mode 100644
index 000000000..1b64da0ff
--- /dev/null
+++ b/vcl/unx/gtk3/gloactiongroup.cxx
@@ -0,0 +1,405 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <unx/gtk/gtksalmenu.hxx>
+
+#include <unx/gtk/gloactiongroup.h>
+
+#include <sal/log.hxx>
+
+/*
+ * 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))
+namespace {
+
+struct GLOAction
+{
+ GObject parent_instance;
+
+ gint item_id; // Menu item ID.
+ bool submenu; // TRUE if action is a submenu action.
+ bool enabled; // TRUE if action is enabled.
+ 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;
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#if defined __clang__
+#if __has_warning("-Wdeprecated-volatile")
+#pragma clang diagnostic ignored "-Wdeprecated-volatile"
+#endif
+#endif
+#endif
+G_DEFINE_TYPE (GLOAction, g_lo_action, G_TYPE_OBJECT);
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+static GLOAction*
+g_lo_action_new()
+{
+ return G_LO_ACTION (g_object_new (G_TYPE_LO_ACTION, nullptr));
+}
+
+static void
+g_lo_action_init (GLOAction *action)
+{
+ action->item_id = -1;
+ action->submenu = false;
+ action->enabled = true;
+ action->parameter_type = nullptr;
+ action->state_type = nullptr;
+ action->state_hint = nullptr;
+ action->state = nullptr;
+}
+
+static void
+g_lo_action_finalize (GObject *object)
+{
+ GLOAction* action = G_LO_ACTION(object);
+
+ 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 -> GLOAction */
+};
+
+static void g_lo_action_group_iface_init (GActionGroupInterface *);
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#if defined __clang__
+#if __has_warning("-Wdeprecated-volatile")
+#pragma clang diagnostic ignored "-Wdeprecated-volatile"
+#endif
+#endif
+#endif
+G_DEFINE_TYPE_WITH_CODE (GLOActionGroup,
+ g_lo_action_group, G_TYPE_OBJECT,
+ G_ADD_PRIVATE(GLOActionGroup)
+ G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP,
+ g_lo_action_group_iface_init));
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+static gchar **
+g_lo_action_group_list_actions (GActionGroup *group)
+{
+ 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, nullptr))
+ keys[i++] = g_strdup (static_cast<gchar*>(key));
+ g_assert_cmpint (i, ==, n);
+ keys[n] = nullptr;
+
+ 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)
+{
+ //SAL_INFO("vcl.unity", "g_lo_action_group_query_action on " << group);
+ GLOActionGroup *lo_group = G_LO_ACTION_GROUP (group);
+ GLOAction* action = G_LO_ACTION (g_hash_table_lookup (lo_group->priv->table, action_name));
+
+ if (action == nullptr)
+ return FALSE;
+
+ if (enabled)
+ {
+ *enabled = action->enabled;
+ }
+
+ if (parameter_type)
+ *parameter_type = action->parameter_type;
+
+ if (state_type)
+ *state_type = action->state_type;
+
+ if (state_hint)
+ *state_hint = (action->state_hint) ? g_variant_ref (action->state_hint) : nullptr;
+
+ if (state)
+ *state = (action->state) ? g_variant_ref (action->state) : nullptr;
+
+ return true;
+}
+
+static void
+g_lo_action_group_perform_submenu_action (GLOActionGroup *group,
+ const gchar *action_name,
+ GVariant *state)
+{
+ bool bState = g_variant_get_boolean (state);
+ SAL_INFO("vcl.unity", "g_lo_action_group_perform_submenu_action on " << group << " to " << bState);
+
+ if (bState)
+ GtkSalMenu::Activate(action_name);
+ else
+ GtkSalMenu::Deactivate(action_name);
+}
+
+static void
+g_lo_action_group_change_state (GActionGroup *group,
+ const gchar *action_name,
+ GVariant *value)
+{
+ SAL_INFO("vcl.unity", "g_lo_action_group_change_state on " << group );
+ g_return_if_fail (value != nullptr);
+
+ g_variant_ref_sink (value);
+
+ if (action_name != nullptr)
+ {
+ GLOActionGroup* lo_group = G_LO_ACTION_GROUP (group);
+ GLOAction* action = G_LO_ACTION (g_hash_table_lookup (lo_group->priv->table, action_name));
+
+ if (action != nullptr)
+ {
+ if (action->submenu)
+ g_lo_action_group_perform_submenu_action (lo_group, action_name, value);
+ else
+ {
+ bool is_new = false;
+
+ /* If action already exists but has no state, it should be removed and added again. */
+ if (action->state_type == nullptr)
+ {
+ g_action_group_action_removed (G_ACTION_GROUP (group), action_name);
+ action->state_type = g_variant_type_copy (g_variant_get_type(value));
+ is_new = true;
+ }
+
+ if (g_variant_is_of_type (value, action->state_type))
+ {
+ if (action->state)
+ g_variant_unref(action->state);
+
+ action->state = g_variant_ref (value);
+
+ if (is_new)
+ g_action_group_action_added (G_ACTION_GROUP (group), action_name);
+ else
+ g_action_group_action_state_changed (group, action_name, value);
+ }
+ }
+ }
+ }
+
+ g_variant_unref (value);
+}
+
+static void
+g_lo_action_group_activate (GActionGroup *group,
+ const gchar *action_name,
+ GVariant *parameter)
+{
+ if (parameter != nullptr)
+ g_action_group_change_action_state(group, action_name, parameter);
+ GtkSalMenu::DispatchCommand(action_name);
+}
+
+void
+g_lo_action_group_insert (GLOActionGroup *group,
+ const gchar *action_name,
+ gint item_id,
+ gboolean submenu)
+{
+ g_lo_action_group_insert_stateful (group, action_name, item_id, submenu, nullptr, nullptr, nullptr, nullptr);
+}
+
+void
+g_lo_action_group_insert_stateful (GLOActionGroup *group,
+ const gchar *action_name,
+ gint item_id,
+ gboolean submenu,
+ const GVariantType *parameter_type,
+ const GVariantType *state_type,
+ GVariant *state_hint,
+ GVariant *state)
+{
+ g_return_if_fail (G_IS_LO_ACTION_GROUP (group));
+
+ GLOAction* old_action = G_LO_ACTION (g_hash_table_lookup (group->priv->table, action_name));
+
+ if (old_action != nullptr && old_action->item_id == item_id)
+ return;
+
+ if (old_action != nullptr)
+ g_lo_action_group_remove (group, action_name);
+
+ GLOAction* action = g_lo_action_new();
+
+ g_hash_table_insert (group->priv->table, g_strdup (action_name), action);
+
+ action->item_id = item_id;
+ action->submenu = submenu;
+
+ if (parameter_type)
+ action->parameter_type = const_cast<GVariantType*>(parameter_type);
+
+ if (state_type)
+ action->state_type = const_cast<GVariantType*>(state_type);
+
+ if (state_hint)
+ action->state_hint = g_variant_ref_sink (state_hint);
+
+ if (state)
+ action->state = g_variant_ref_sink (state);
+
+ g_action_group_action_added (G_ACTION_GROUP (group), action_name);
+}
+
+static void
+g_lo_action_group_finalize (GObject *object)
+{
+ GLOActionGroup *lo_group = G_LO_ACTION_GROUP (object);
+
+ g_hash_table_unref (lo_group->priv->table);
+
+ G_OBJECT_CLASS (g_lo_action_group_parent_class)->finalize (object);
+}
+
+static void
+g_lo_action_group_init (GLOActionGroup *group)
+{
+ SAL_INFO("vcl.unity", "g_lo_action_group_init on " << group);
+ group->priv = static_cast<GLOActionGroupPrivate *>(g_lo_action_group_get_instance_private (group));
+ 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)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = g_lo_action_group_finalize;
+}
+
+static void
+g_lo_action_group_iface_init (GActionGroupInterface *iface)
+{
+ 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;
+}
+
+GLOActionGroup *
+g_lo_action_group_new()
+{
+ GLOActionGroup* group = G_LO_ACTION_GROUP (g_object_new (G_TYPE_LO_ACTION_GROUP, nullptr));
+ return group;
+}
+
+void
+g_lo_action_group_set_action_enabled (GLOActionGroup *group,
+ const gchar *action_name,
+ gboolean enabled)
+{
+ SAL_INFO("vcl.unity", "g_lo_action_group_set_action_enabled on " << group);
+ g_return_if_fail (G_IS_LO_ACTION_GROUP (group));
+ g_return_if_fail (action_name != nullptr);
+
+ GLOAction* action = G_LO_ACTION (g_hash_table_lookup (group->priv->table, action_name));
+
+ if (action == nullptr)
+ return;
+
+ action->enabled = enabled;
+
+ g_action_group_action_enabled_changed (G_ACTION_GROUP (group), action_name, enabled);
+}
+
+void
+g_lo_action_group_remove (GLOActionGroup *group,
+ const gchar *action_name)
+{
+ SAL_INFO("vcl.unity", "g_lo_action_group_remove on " << group);
+ g_return_if_fail (G_IS_LO_ACTION_GROUP (group));
+
+ if (action_name != nullptr)
+ {
+ g_action_group_action_removed (G_ACTION_GROUP (group), action_name);
+ g_hash_table_remove (group->priv->table, action_name);
+ }
+}
+
+void
+g_lo_action_group_clear (GLOActionGroup *group)
+{
+ SAL_INFO("vcl.unity", "g_lo_action_group_clear on " << group);
+ g_return_if_fail (G_IS_LO_ACTION_GROUP (group));
+
+ GList* keys = g_hash_table_get_keys (group->priv->table);
+
+ for (GList* element = g_list_first (keys); element != nullptr; element = g_list_next (element))
+ {
+ g_lo_action_group_remove (group, static_cast<gchar*>(element->data));
+ }
+
+ g_list_free (keys);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */