mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2025-12-22 14:50:11 +01:00
442 lines
12 KiB
C
442 lines
12 KiB
C
|
|
/* -*- mode: C; c-file-style: "gnu" -*- */
|
||
|
|
/* dbus-gtype-specialized.c: Non-DBus-specific functions for specialized GTypes
|
||
|
|
*
|
||
|
|
* Copyright (C) 2005 Red Hat, Inc.
|
||
|
|
*
|
||
|
|
* Licensed under the Academic Free License version 2.1
|
||
|
|
*
|
||
|
|
* This program is free software; you can redistribute it and/or modify
|
||
|
|
* it under the terms of the GNU General Public License as published by
|
||
|
|
* the Free Software Foundation; either version 2 of the License, or
|
||
|
|
* (at your option) any later version.
|
||
|
|
*
|
||
|
|
* This program 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 General Public License for more details.
|
||
|
|
*
|
||
|
|
* You should have received a copy of the GNU General Public License
|
||
|
|
* along with this program; if not, write to the Free Software
|
||
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include "dbus-gtype-specialized.h"
|
||
|
|
#include <glib.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <gobject/gvaluecollector.h>
|
||
|
|
|
||
|
|
typedef enum {
|
||
|
|
DBUS_G_SPECTYPE_COLLECTION,
|
||
|
|
DBUS_G_SPECTYPE_MAP
|
||
|
|
} DBusGTypeSpecializedType;
|
||
|
|
|
||
|
|
typedef struct {
|
||
|
|
DBusGTypeSpecializedType type;
|
||
|
|
const DBusGTypeSpecializedVtable *vtable;
|
||
|
|
} DBusGTypeSpecializedContainer;
|
||
|
|
|
||
|
|
typedef struct {
|
||
|
|
GType types[6];
|
||
|
|
const DBusGTypeSpecializedContainer *klass;
|
||
|
|
} DBusGTypeSpecializedData;
|
||
|
|
|
||
|
|
static GHashTable /* char * -> data* */ *specialized_containers;
|
||
|
|
|
||
|
|
static GQuark
|
||
|
|
specialized_type_data_quark ()
|
||
|
|
{
|
||
|
|
static GQuark quark;
|
||
|
|
if (!quark)
|
||
|
|
quark = g_quark_from_static_string ("DBusGTypeSpecializedData");
|
||
|
|
|
||
|
|
return quark;
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
dbus_g_type_specialized_init (void)
|
||
|
|
{
|
||
|
|
specialized_containers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
static gboolean
|
||
|
|
specialized_types_is_initialized (void)
|
||
|
|
{
|
||
|
|
return specialized_containers != NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
static DBusGTypeSpecializedData *
|
||
|
|
lookup_specialization_data (GType type)
|
||
|
|
{
|
||
|
|
return g_type_get_qdata (type, specialized_type_data_quark ());
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Copied from gboxed.c */
|
||
|
|
static void
|
||
|
|
proxy_value_init (GValue *value)
|
||
|
|
{
|
||
|
|
value->data[0].v_pointer = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Adapted from gboxed.c */
|
||
|
|
static void
|
||
|
|
proxy_value_free (GValue *value)
|
||
|
|
{
|
||
|
|
if (value->data[0].v_pointer && !(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
|
||
|
|
{
|
||
|
|
DBusGTypeSpecializedData *data;
|
||
|
|
GType type;
|
||
|
|
|
||
|
|
type = G_VALUE_TYPE (value);
|
||
|
|
data = lookup_specialization_data (type);
|
||
|
|
g_assert (data != NULL);
|
||
|
|
|
||
|
|
data->klass->vtable->free_func (type, value->data[0].v_pointer);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Adapted from gboxed.c */
|
||
|
|
static void
|
||
|
|
proxy_value_copy (const GValue *src_value,
|
||
|
|
GValue *dest_value)
|
||
|
|
{
|
||
|
|
if (src_value->data[0].v_pointer)
|
||
|
|
{
|
||
|
|
DBusGTypeSpecializedData *data;
|
||
|
|
GType type;
|
||
|
|
type = G_VALUE_TYPE (src_value);
|
||
|
|
data = lookup_specialization_data (type);
|
||
|
|
g_assert (data != NULL);
|
||
|
|
dest_value->data[0].v_pointer = data->klass->vtable->copy_func (type, src_value->data[0].v_pointer);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
dest_value->data[0].v_pointer = src_value->data[0].v_pointer;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Copied from gboxed.c */
|
||
|
|
static gpointer
|
||
|
|
proxy_value_peek_pointer (const GValue *value)
|
||
|
|
{
|
||
|
|
return value->data[0].v_pointer;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Adapted from gboxed.c */
|
||
|
|
static gchar*
|
||
|
|
proxy_collect_value (GValue *value,
|
||
|
|
guint n_collect_values,
|
||
|
|
GTypeCValue *collect_values,
|
||
|
|
guint collect_flags)
|
||
|
|
{
|
||
|
|
DBusGTypeSpecializedData *data;
|
||
|
|
GType type;
|
||
|
|
|
||
|
|
type = G_VALUE_TYPE (value);
|
||
|
|
data = lookup_specialization_data (type);
|
||
|
|
|
||
|
|
if (!collect_values[0].v_pointer)
|
||
|
|
value->data[0].v_pointer = NULL;
|
||
|
|
else
|
||
|
|
{
|
||
|
|
if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
|
||
|
|
{
|
||
|
|
value->data[0].v_pointer = collect_values[0].v_pointer;
|
||
|
|
value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
value->data[0].v_pointer = data->klass->vtable->copy_func (type, collect_values[0].v_pointer);
|
||
|
|
}
|
||
|
|
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Adapted from gboxed.c */
|
||
|
|
static gchar*
|
||
|
|
proxy_lcopy_value (const GValue *value,
|
||
|
|
guint n_collect_values,
|
||
|
|
GTypeCValue *collect_values,
|
||
|
|
guint collect_flags)
|
||
|
|
{
|
||
|
|
gpointer *boxed_p = collect_values[0].v_pointer;
|
||
|
|
|
||
|
|
if (!boxed_p)
|
||
|
|
return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
|
||
|
|
|
||
|
|
if (!value->data[0].v_pointer)
|
||
|
|
*boxed_p = NULL;
|
||
|
|
else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
|
||
|
|
*boxed_p = value->data[0].v_pointer;
|
||
|
|
else
|
||
|
|
{
|
||
|
|
DBusGTypeSpecializedData *data;
|
||
|
|
GType type;
|
||
|
|
|
||
|
|
type = G_VALUE_TYPE (value);
|
||
|
|
data = lookup_specialization_data (type);
|
||
|
|
|
||
|
|
*boxed_p = data->klass->vtable->copy_func (type, value->data[0].v_pointer);
|
||
|
|
}
|
||
|
|
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
static char *
|
||
|
|
build_specialization_name (const char *prefix, GType first_type, GType second_type)
|
||
|
|
{
|
||
|
|
GString *fullname;
|
||
|
|
|
||
|
|
fullname = g_string_new (prefix);
|
||
|
|
g_string_append_c (fullname, '+');
|
||
|
|
g_string_append (fullname, g_type_name (first_type));
|
||
|
|
if (second_type != G_TYPE_INVALID)
|
||
|
|
{
|
||
|
|
g_string_append_c (fullname, '+');
|
||
|
|
g_string_append (fullname, g_type_name (second_type));
|
||
|
|
}
|
||
|
|
return g_string_free (fullname, FALSE);
|
||
|
|
}
|
||
|
|
|
||
|
|
static void
|
||
|
|
register_container (const char *name,
|
||
|
|
DBusGTypeSpecializedType type,
|
||
|
|
const DBusGTypeSpecializedVtable *vtable)
|
||
|
|
{
|
||
|
|
DBusGTypeSpecializedContainer *klass;
|
||
|
|
|
||
|
|
klass = g_new0 (DBusGTypeSpecializedContainer, 1);
|
||
|
|
klass->type = type;
|
||
|
|
klass->vtable = vtable;
|
||
|
|
|
||
|
|
g_hash_table_insert (specialized_containers, g_strdup (name), klass);
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
dbus_g_type_register_collection (const char *name,
|
||
|
|
const DBusGTypeSpecializedCollectionVtable *vtable,
|
||
|
|
guint flags)
|
||
|
|
{
|
||
|
|
g_return_if_fail (specialized_types_is_initialized ());
|
||
|
|
register_container (name, DBUS_G_SPECTYPE_COLLECTION, (const DBusGTypeSpecializedVtable*) vtable);
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
dbus_g_type_register_map (const char *name,
|
||
|
|
const DBusGTypeSpecializedMapVtable *vtable,
|
||
|
|
guint flags)
|
||
|
|
{
|
||
|
|
g_return_if_fail (specialized_types_is_initialized ());
|
||
|
|
register_container (name, DBUS_G_SPECTYPE_MAP, (const DBusGTypeSpecializedVtable*) vtable);
|
||
|
|
}
|
||
|
|
|
||
|
|
static GType
|
||
|
|
register_specialized_instance (const DBusGTypeSpecializedContainer *klass,
|
||
|
|
char *name,
|
||
|
|
GType first_type,
|
||
|
|
GType second_type)
|
||
|
|
{
|
||
|
|
GType ret;
|
||
|
|
|
||
|
|
static const GTypeValueTable vtable =
|
||
|
|
{
|
||
|
|
proxy_value_init,
|
||
|
|
proxy_value_free,
|
||
|
|
proxy_value_copy,
|
||
|
|
proxy_value_peek_pointer,
|
||
|
|
"p",
|
||
|
|
proxy_collect_value,
|
||
|
|
"p",
|
||
|
|
proxy_lcopy_value,
|
||
|
|
};
|
||
|
|
static const GTypeInfo derived_info =
|
||
|
|
{
|
||
|
|
0, /* class_size */
|
||
|
|
NULL, /* base_init */
|
||
|
|
NULL, /* base_finalize */
|
||
|
|
NULL, /* class_init */
|
||
|
|
NULL, /* class_finalize */
|
||
|
|
NULL, /* class_data */
|
||
|
|
0, /* instance_size */
|
||
|
|
0, /* n_preallocs */
|
||
|
|
NULL, /* instance_init */
|
||
|
|
&vtable, /* value_table */
|
||
|
|
};
|
||
|
|
|
||
|
|
ret = g_type_register_static (G_TYPE_BOXED, name, &derived_info, 0);
|
||
|
|
/* install proxy functions upon successfull registration */
|
||
|
|
if (ret != G_TYPE_INVALID)
|
||
|
|
{
|
||
|
|
DBusGTypeSpecializedData *data;
|
||
|
|
data = g_new0 (DBusGTypeSpecializedData, 1);
|
||
|
|
data->types[0] = first_type;
|
||
|
|
data->types[1] = second_type;
|
||
|
|
data->klass = klass;
|
||
|
|
g_type_set_qdata (ret, specialized_type_data_quark (), data);
|
||
|
|
}
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static GType
|
||
|
|
lookup_or_register_specialized (const char *container,
|
||
|
|
GType first_type,
|
||
|
|
GType second_type)
|
||
|
|
{
|
||
|
|
GType ret;
|
||
|
|
char *name;
|
||
|
|
const DBusGTypeSpecializedContainer *klass;
|
||
|
|
|
||
|
|
g_return_val_if_fail (specialized_types_is_initialized (), G_TYPE_INVALID);
|
||
|
|
|
||
|
|
klass = g_hash_table_lookup (specialized_containers, container);
|
||
|
|
g_return_val_if_fail (klass != NULL, G_TYPE_INVALID);
|
||
|
|
|
||
|
|
name = build_specialization_name (container, first_type, second_type);
|
||
|
|
ret = g_type_from_name (name);
|
||
|
|
if (ret == G_TYPE_INVALID)
|
||
|
|
{
|
||
|
|
/* Take ownership of name */
|
||
|
|
ret = register_specialized_instance (klass, name,
|
||
|
|
first_type,
|
||
|
|
second_type);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
g_free (name);
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
GType
|
||
|
|
dbus_g_type_get_collection (const char *container,
|
||
|
|
GType specialization)
|
||
|
|
{
|
||
|
|
return lookup_or_register_specialized (container, specialization, G_TYPE_INVALID);
|
||
|
|
}
|
||
|
|
|
||
|
|
GType
|
||
|
|
dbus_g_type_get_map (const char *container,
|
||
|
|
GType key_specialization,
|
||
|
|
GType value_specialization)
|
||
|
|
{
|
||
|
|
return lookup_or_register_specialized (container, key_specialization, value_specialization);
|
||
|
|
}
|
||
|
|
|
||
|
|
gboolean
|
||
|
|
dbus_g_type_is_collection (GType gtype)
|
||
|
|
{
|
||
|
|
DBusGTypeSpecializedData *data;
|
||
|
|
data = lookup_specialization_data (gtype);
|
||
|
|
if (data == NULL)
|
||
|
|
return FALSE;
|
||
|
|
return data->klass->type == DBUS_G_SPECTYPE_COLLECTION;
|
||
|
|
}
|
||
|
|
|
||
|
|
gboolean
|
||
|
|
dbus_g_type_is_map (GType gtype)
|
||
|
|
{
|
||
|
|
DBusGTypeSpecializedData *data;
|
||
|
|
data = lookup_specialization_data (gtype);
|
||
|
|
if (data == NULL)
|
||
|
|
return FALSE;
|
||
|
|
return data->klass->type == DBUS_G_SPECTYPE_MAP;
|
||
|
|
}
|
||
|
|
|
||
|
|
static GType
|
||
|
|
get_specialization_index (GType gtype, guint i)
|
||
|
|
{
|
||
|
|
DBusGTypeSpecializedData *data;
|
||
|
|
|
||
|
|
data = lookup_specialization_data (gtype);
|
||
|
|
return data->types[i];
|
||
|
|
}
|
||
|
|
|
||
|
|
GType
|
||
|
|
dbus_g_type_get_collection_specialization (GType gtype)
|
||
|
|
{
|
||
|
|
g_return_val_if_fail (dbus_g_type_is_collection (gtype), G_TYPE_INVALID);
|
||
|
|
return get_specialization_index (gtype, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
GType
|
||
|
|
dbus_g_type_get_map_key_specialization (GType gtype)
|
||
|
|
{
|
||
|
|
g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID);
|
||
|
|
return get_specialization_index (gtype, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
GType
|
||
|
|
dbus_g_type_get_map_value_specialization (GType gtype)
|
||
|
|
{
|
||
|
|
g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID);
|
||
|
|
return get_specialization_index (gtype, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
gpointer
|
||
|
|
dbus_g_type_specialized_construct (GType type)
|
||
|
|
{
|
||
|
|
DBusGTypeSpecializedData *data;
|
||
|
|
g_return_val_if_fail (specialized_types_is_initialized (), FALSE);
|
||
|
|
|
||
|
|
data = lookup_specialization_data (type);
|
||
|
|
g_return_val_if_fail (data != NULL, FALSE);
|
||
|
|
|
||
|
|
return data->klass->vtable->constructor (type);
|
||
|
|
}
|
||
|
|
|
||
|
|
gboolean
|
||
|
|
dbus_g_type_collection_get_fixed (GValue *value,
|
||
|
|
gpointer *data_ret,
|
||
|
|
guint *len_ret)
|
||
|
|
{
|
||
|
|
DBusGTypeSpecializedData *data;
|
||
|
|
GType gtype;
|
||
|
|
|
||
|
|
g_return_val_if_fail (specialized_types_is_initialized (), FALSE);
|
||
|
|
g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE);
|
||
|
|
|
||
|
|
gtype = G_VALUE_TYPE (value);
|
||
|
|
data = lookup_specialization_data (gtype);
|
||
|
|
g_return_val_if_fail (data != NULL, FALSE);
|
||
|
|
|
||
|
|
return ((DBusGTypeSpecializedCollectionVtable *) (data->klass->vtable))->fixed_accessor (gtype,
|
||
|
|
g_value_get_boxed (value),
|
||
|
|
data_ret, len_ret);
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
dbus_g_type_collection_value_iterate (GValue *value,
|
||
|
|
DBusGTypeSpecializedCollectionIterator iterator,
|
||
|
|
gpointer user_data)
|
||
|
|
{
|
||
|
|
DBusGTypeSpecializedData *data;
|
||
|
|
GType gtype;
|
||
|
|
|
||
|
|
g_return_if_fail (specialized_types_is_initialized ());
|
||
|
|
g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
|
||
|
|
|
||
|
|
gtype = G_VALUE_TYPE (value);
|
||
|
|
data = lookup_specialization_data (gtype);
|
||
|
|
g_return_if_fail (data != NULL);
|
||
|
|
|
||
|
|
((DBusGTypeSpecializedCollectionVtable *) data->klass->vtable)->iterator (gtype,
|
||
|
|
g_value_get_boxed (value),
|
||
|
|
iterator, user_data);
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
dbus_g_type_map_value_iterate (GValue *value,
|
||
|
|
DBusGTypeSpecializedMapIterator iterator,
|
||
|
|
gpointer user_data)
|
||
|
|
{
|
||
|
|
DBusGTypeSpecializedData *data;
|
||
|
|
GType gtype;
|
||
|
|
|
||
|
|
g_return_if_fail (specialized_types_is_initialized ());
|
||
|
|
g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
|
||
|
|
|
||
|
|
gtype = G_VALUE_TYPE (value);
|
||
|
|
data = lookup_specialization_data (gtype);
|
||
|
|
g_return_if_fail (data != NULL);
|
||
|
|
|
||
|
|
((DBusGTypeSpecializedMapVtable *) data->klass->vtable)->iterator (gtype,
|
||
|
|
g_value_get_boxed (value),
|
||
|
|
iterator, user_data);
|
||
|
|
}
|