<commit_before>/*
 * Copyright © 2010 Codethink Limited
 * Copyright © 2011 Canonical Limited
 *
 * This program 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.
 *
 * Authors: <NAME> <<EMAIL>>
 */

#include "config.h"

#include "gsimpleasyncresult.h"
#include "gdbusactiongroup.h"
#include "gdbusconnection.h"
#include "gasyncinitable.h"
#include "gactiongroup.h"


/**
 * SECTION:gdbusactiongroup
 * @title: GDBusActionGroup
 * @short_description: A D-Bus GActionGroup implementation
 * @see_also: <link linkend="gio-GActionGroup-exporter">GActionGroup exporter</link>
 *
 * #GDBusActionGroup is an implementation of the #GActionGroup
 * interface that can be used as a proxy for an action group
 * that is exported over D-Bus with g_action_group_dbus_export_start().
 */

struct _GDBusActionGroup
{
  GObject parent_instance;

  GDBusConnection *connection;
  gchar           *bus_name;
  gchar           *object_path;
  guint            subscription_id;
  GHashTable      *actions;

  /* The 'strict' flag indicates that the non-existence of at least one
   * action has potentially been observed through the API.  This means
   * that we should always emit 'action-added' signals for all new
   * actions.
   *
   * The user can observe the non-existence of an action by listing the
   * actions or by performing a query (such as parameter type) on a
   * non-existent action.
   *
   * If the user has no way of knowing that a given action didn't
   * already exist then we can skip emitting 'action-added' signals
   * since they have no way of knowing that it wasn't there from the
   * start.
   */
  gboolean         strict;
};

typedef GObjectClass GDBusActionGroupClass;

typedef struct
{
  gchar        *name;
  GVariantType *parameter_type;
  gboolean      enabled;
  GVariant     *state;
} ActionInfo;

static void
action_info_free (gpointer user_data)
{
  ActionInfo *info = user_data;

  g_free (info->name);

  if (info->state)
    g_variant_unref (info->state);

  if (info->parameter_type)
    g_variant_type_free (info->parameter_type);

  g_slice_free (ActionInfo, info);
}

ActionInfo *
action_info_new_from_iter (GVariantIter *iter)
{
  const gchar *param_str;
  ActionInfo *info;
  gboolean enabled;
  GVariant *state;
  gchar *name;

  if (!g_variant_iter_next (iter, "{s(bg@av)}", &name,
                            &enabled, &param_str, &state))
    return NULL;

  info = g_slice_new (ActionInfo);
  info->name = name;
  info->enabled = enabled;

  if (g_variant_n_children (state))
    g_variant_get_child (state, 0, "v", &info->state);
  else
    info->state = NULL;
  g_variant_unref (state);

  if (param_str[0])
    info->parameter_type = g_variant_type_copy ((GVariantType *) param_str);
  else
    info->parameter_type = NULL;

  return info;
}

static void g_dbus_action_group_iface_init (GActionGroupInterface *);
G_DEFINE_TYPE_WITH_CODE (GDBusActionGroup, g_dbus_action_group, G_TYPE_OBJECT,
  G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, g_dbus_action_group_iface_init))

static gchar **
g_dbus_action_group_list_actions (GActionGroup *g_group)
{
  GDBusActionGroup *group = G_DBUS_ACTION_GROUP (g_group);
  GHashTableIter iter;
  gint n, i = 0;
  gchar **keys;
  gpointer key;

  n = g_hash_table_size (group->actions);
  keys = g_new (gchar *, n + 1);

  g_hash_table_iter_init (&iter, group->actions);
  while (g_hash_table_iter_next (&iter, &key, NULL))
    keys[i++] = g_strdup (key);
  g_assert_cmpint (i, ==, n);
  keys[n] = NULL;

  group->strict = TRUE;

  return keys;
}

static gboolean
g_dbus_action_group_query_action (GActionGroup        *g_group,
                                  const gchar         *action_name,
                                  gboolean            *enabled,
                                  const GVariantType **parameter_type,
                                  const GVariantType **state_type,
                                  GVariant           **state_hint,
                                  GVariant           **state)
{
  GDBusActionGroup *group = G_DBUS_ACTION_GROUP (g_group);
  ActionInfo *info;

  info = g_hash_table_lookup (group->actions, action_name);

  if (info == NULL)
    {
      group->strict = TRUE;
      return FALSE;
    }

  if (enabled)
    *enabled = info->enabled;

  if (parameter_type)
    *parameter_type = info->parameter_type;

  if (state_type)
    *state_type = info->state ? g_variant_get_type (info->state) : NULL;

  if (state_hint)
    *state_hint = NULL;

  if (state)
    *state = g_variant_ref (info->state);

  return TRUE;
}

static void
g_dbus_action_group_change_state (GActionGroup *g_group,
                                  const gchar  *action_name,
                                  GVariant     *value)
{
  GDBusActionGroup *group = G_DBUS_ACTION_GROUP (g_group);

  /* Don't bother with the checks.  The other side will do it again. */
  g_dbus_connection_call (group->connection, group->bus_name, group->object_path, "org.gtk.Actions", "SetState",<commit_msg>Fix the dbus action group query_action implementation<commit_after>/*
 * Copyright © 2010 Codethink Limited
 * Copyright © 2011 Canonical Limited
 *
 * This program 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.
 *
 * Authors: <NAME> <<EMAIL>>
 */

#include "config.h"

#include "gsimpleasyncresult.h"
#include "gdbusactiongroup.h"
#include "gdbusconnection.h"
#include "gasyncinitable.h"
#include "gactiongroup.h"


/**
 * SECTION:gdbusactiongroup
 * @title: GDBusActionGroup
 * @short_description: A D-Bus GActionGroup implementation
 * @see_also: <link linkend="gio-GActionGroup-exporter">GActionGroup exporter</link>
 *
 * #GDBusActionGroup is an implementation of the #GActionGroup
 * interface that can be used as a proxy for an action group
 * that is exported over D-Bus with g_action_group_dbus_export_start().
 */

struct _GDBusActionGroup
{
  GObject parent_instance;

  GDBusConnection *connection;
  gchar           *bus_name;
  gchar           *object_path;
  guint            subscription_id;
  GHashTable      *actions;

  /* The 'strict' flag indicates that the non-existence of at least one
   * action has potentially been observed through the API.  This means
   * that we should always emit 'action-added' signals for all new
   * actions.
   *
   * The user can observe the non-existence of an action by listing the
   * actions or by performing a query (such as parameter type) on a
   * non-existent action.
   *
   * If the user has no way of knowing that a given action didn't
   * already exist then we can skip emitting 'action-added' signals
   * since they have no way of knowing that it wasn't there from the
   * start.
   */
  gboolean         strict;
};

typedef GObjectClass GDBusActionGroupClass;

typedef struct
{
  gchar        *name;
  GVariantType *parameter_type;
  gboolean      enabled;
  GVariant     *state;
} ActionInfo;

static void
action_info_free (gpointer user_data)
{
  ActionInfo *info = user_data;

  g_free (info->name);

  if (info->state)
    g_variant_unref (info->state);

  if (info->parameter_type)
    g_variant_type_free (info->parameter_type);

  g_slice_free (ActionInfo, info);
}

ActionInfo *
action_info_new_from_iter (GVariantIter *iter)
{
  const gchar *param_str;
  ActionInfo *info;
  gboolean enabled;
  GVariant *state;
  gchar *name;

  if (!g_variant_iter_next (iter, "{s(bg@av)}", &name,
                            &enabled, &param_str, &state))
    return NULL;

  info = g_slice_new (ActionInfo);
  info->name = name;
  info->enabled = enabled;

  if (g_variant_n_children (state))
    g_variant_get_child (state, 0, "v", &info->state);
  else
    info->state = NULL;
  g_variant_unref (state);

  if (param_str[0])
    info->parameter_type = g_variant_type_copy ((GVariantType *) param_str);
  else
    info->parameter_type = NULL;

  return info;
}

static void g_dbus_action_group_iface_init (GActionGroupInterface *);
G_DEFINE_TYPE_WITH_CODE (GDBusActionGroup, g_dbus_action_group, G_TYPE_OBJECT,
  G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, g_dbus_action_group_iface_init))

static gchar **
g_dbus_action_group_list_actions (GActionGroup *g_group)
{
  GDBusActionGroup *group = G_DBUS_ACTION_GROUP (g_group);
  GHashTableIter iter;
  gint n, i = 0;
  gchar **keys;
  gpointer key;

  n = g_hash_table_size (group->actions);
  keys = g_new (gchar *, n + 1);

  g_hash_table_iter_init (&iter, group->actions);
  while (g_hash_table_iter_next (&iter, &key, NULL))
    keys[i++] = g_strdup (key);
  g_assert_cmpint (i, ==, n);
  keys[n] = NULL;

  group->strict = TRUE;

  return keys;
}

static gboolean
g_dbus_action_group_query_action (GActionGroup        *g_group,
                                  const gchar         *action_name,
                                  gboolean            *enabled,
                                  const GVariantType **parameter_type,
                                  const GVariantType **state_type,
                                  GVariant           **state_hint,
                                  GVariant           **state)
{
  GDBusActionGroup *group = G_DBUS_ACTION_GROUP (g_group);
  ActionInfo *info;

  info = g_hash_table_lookup (group->actions, action_name);

  if (info == NULL)
    {
      group->strict = TRUE;
      return FALSE;
    }

  if (enabled)
    *enabled = info->enabled;

  if (parameter_type)
    *parameter_type = info->parameter_type;

  if (state_type)
    *state_type = info->state ? g_variant_get_type (info->state) : NULL;

  if (state_hint)
    *state_hint = NULL;

  if (state)
    *state = info->state ? g_variant_ref (info->state) : NULL;

  return TRUE;
}

static void
g_dbus_action_group_change_state (GActionGroup *g_group,
                                  const gchar  *action_name,
                                  GVariant     *value)
{
  GDBusActionGroup *group = G_DBUS_ACTION_GROUP (g_group);

  /* Don't bother with the checks.  The other side will do it again. */
  g_dbus_connection_call (group->connection, group->bus_name, group->object_path, "org.gtk.Actions", "SetState",
{'fraction_non_alphanumeric': 0.08997451893506722, 'fraction_numerical': 0.0047447500219664355, 'mean_word_length': 3.0476529160739685, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 62, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7520216', 'n_tokens_mistral': 3669, 'n_tokens_neox': 3528, 'n_words': 1075}