2dbf36132a
Change-Id: I219798ed42aff11d09fd45c26ca1a018c2d22c08 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/115239 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolanm@redhat.com>
405 lines
12 KiB
C++
405 lines
12 KiB
C++
/* -*- 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: */
|