/* -*- 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 */ #include #include #include #include /* * 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; gint item_id; // Menu item ID. gboolean submenu; // TRUE if action is a submenu action. gboolean 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; 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_id = -1; action->submenu = FALSE; 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); 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 */ GtkSalFrame *frame; /* Frame to which GActionGroup is associated. */ }; static void g_lo_action_group_iface_init (GActionGroupInterface *); 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)); 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, 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) { GLOActionGroup *lo_group = G_LO_ACTION_GROUP (group); GLOAction* action; action = G_LO_ACTION (g_hash_table_lookup (lo_group->priv->table, action_name)); if (action == NULL) 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) : NULL; if (state) *state = (action->state) ? g_variant_ref(action->state) : NULL; return TRUE; } static void g_lo_action_group_perform_submenu_action (GLOActionGroup *group, const gchar *action_name, GVariant *state) { GTK_YIELD_GRAB(); GtkSalFrame* pFrame = group->priv->frame; if (pFrame == NULL) return; GtkSalMenu* pSalMenu = static_cast (pFrame->GetMenu()); if (pSalMenu != NULL) { gboolean bState = g_variant_get_boolean (state); if (bState == TRUE) pSalMenu->Activate (action_name); else pSalMenu->Deactivate (action_name); } } static void g_lo_action_group_change_state (GActionGroup *group, const gchar *action_name, GVariant *value) { g_return_if_fail (value != NULL); g_variant_ref_sink (value); if (action_name != NULL) { 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 != NULL) { if (action->submenu == TRUE) g_lo_action_group_perform_submenu_action (lo_group, action_name, value); else { if (action->state_type == NULL) action->state_type = g_variant_type_copy (g_variant_get_type(value)); if (g_variant_is_of_type (value, action->state_type) == TRUE) { if (action->state) g_variant_unref(action->state); action->state = g_variant_ref (value); 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) { GTK_YIELD_GRAB(); GLOActionGroup *lo_group = G_LO_ACTION_GROUP (group); GtkSalFrame *pFrame = lo_group->priv->frame; if ( pFrame != NULL ) { GtkSalMenu* pSalMenu = static_cast< GtkSalMenu* >( pFrame->GetMenu() ); if ( pSalMenu != NULL ) { GLOAction* action = G_LO_ACTION (g_hash_table_lookup (lo_group->priv->table, action_name)); pSalMenu->DispatchCommand( action->item_id, 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, NULL, NULL, NULL, NULL); } 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 == NULL || old_action->item_id != item_id) { if (old_action != NULL) g_lo_action_group_remove (group, action_name); // g_action_group_action_removed (G_ACTION_GROUP (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 = (GVariantType*) parameter_type; if (state_type) action->state_type = (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) { 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); group->priv->frame = NULL; } 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; g_type_class_add_private (klass, sizeof (GLOActionGroupPrivate)); } 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 (gpointer frame) { GLOActionGroup* group = G_LO_ACTION_GROUP (g_object_new (G_TYPE_LO_ACTION_GROUP, NULL)); group->priv->frame = static_cast< GtkSalFrame* > (frame); return group; } void g_lo_action_group_set_action_enabled (GLOActionGroup *group, const gchar *action_name, gboolean enabled) { 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); } void g_lo_action_group_remove (GLOActionGroup *group, const gchar *action_name) { g_return_if_fail (G_IS_LO_ACTION_GROUP (group)); if (action_name != NULL) { 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) { 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 != NULL; element = g_list_next (element)) { g_lo_action_group_remove (group, (gchar*) element->data); } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */