diff options
Diffstat (limited to 'vcl/unx/gtk3/gtk3gloactiongroup.cxx')
-rw-r--r-- | vcl/unx/gtk3/gtk3gloactiongroup.cxx | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/vcl/unx/gtk3/gtk3gloactiongroup.cxx b/vcl/unx/gtk3/gtk3gloactiongroup.cxx new file mode 100644 index 000000000..c6d5eaf03 --- /dev/null +++ b/vcl/unx/gtk3/gtk3gloactiongroup.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) + { + 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: */ |