xed/xedit/xedit-message-type.c

528 lines
12 KiB
C
Raw Normal View History

2016-01-25 08:13:49 -06:00
#include "xedit-message-type.h"
2011-11-07 13:46:58 -06:00
/**
2016-01-25 08:13:49 -06:00
* SECTION:xedit-message-type
2011-11-07 13:46:58 -06:00
* @short_description: message type description
2016-01-25 08:13:49 -06:00
* @include: xedit/xedit-message-type.h
2011-11-07 13:46:58 -06:00
*
2016-01-25 08:13:49 -06:00
* A message type is a prototype description for a #XeditMessage used to
* transmit messages on a #XeditMessageBus. The message type describes
2011-11-07 13:46:58 -06:00
* the Object Path, Method and Arguments of the message.
*
* A message type can contain any number of required and optional arguments.
2016-01-25 08:13:49 -06:00
* To instantiate a #XeditMessage from a #XeditMessageType, use
* xedit_message_type_instantiate().
2011-11-07 13:46:58 -06:00
*
2016-01-25 08:13:49 -06:00
* Registering a new message type on a #XeditMessageBus with
* xedit_message_bus_register() internally creates a new #XeditMessageType. When
* then using xedit_message_bus_send(), an actual instantiation of the
2011-11-07 13:46:58 -06:00
* registered type is internally created and send over the bus.
*
* <example>
* <programlisting>
* // Defining a new message type
2016-01-25 08:13:49 -06:00
* XeditMessageType *message_type = xedit_message_type_new ("/plugins/example",
2011-11-07 13:46:58 -06:00
* "method",
* 0,
* "arg1", G_TYPE_STRING,
* NULL);
*
* // Instantiating an actual message from the type
2016-01-25 08:13:49 -06:00
* XeditMessage *message = xedit_message_type_instantiate (message_type,
2011-11-07 13:46:58 -06:00
* "arg1", "Hello World",
* NULL);
* </programlisting>
* </example>
*
* Since: 2.25.3
*
*/
typedef struct
{
GType type;
gboolean required;
} ArgumentInfo;
2016-01-25 08:13:49 -06:00
struct _XeditMessageType
2011-11-07 13:46:58 -06:00
{
/* FIXME this is an issue for introspection */
2011-11-07 13:46:58 -06:00
gint ref_count;
gchar *object_path;
gchar *method;
guint num_arguments;
guint num_required;
GHashTable *arguments; // mapping of key -> ArgumentInfo
};
/**
2016-01-25 08:13:49 -06:00
* xedit_message_type_ref:
* @message_type: the #XeditMessageType
2011-11-07 13:46:58 -06:00
*
* Increases the reference count on @message_type.
*
* Return value: @message_type
*
*/
2016-01-25 08:13:49 -06:00
XeditMessageType *
xedit_message_type_ref (XeditMessageType *message_type)
2011-11-07 13:46:58 -06:00
{
g_return_val_if_fail (message_type != NULL, NULL);
g_atomic_int_inc (&message_type->ref_count);
return message_type;
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_type_unref:
* @message_type: the #XeditMessageType
2011-11-07 13:46:58 -06:00
*
* Decreases the reference count on @message_type. When the reference count
* drops to 0, @message_type is destroyed.
*
*/
void
2016-01-25 08:13:49 -06:00
xedit_message_type_unref (XeditMessageType *message_type)
2011-11-07 13:46:58 -06:00
{
g_return_if_fail (message_type != NULL);
if (!g_atomic_int_dec_and_test (&message_type->ref_count))
return;
g_free (message_type->object_path);
g_free (message_type->method);
g_hash_table_destroy (message_type->arguments);
g_free (message_type);
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_type_get_type:
2011-11-07 13:46:58 -06:00
*
* Retrieves the GType object which is associated with the
2016-01-25 08:13:49 -06:00
* #XeditMessageType class.
2011-11-07 13:46:58 -06:00
*
2016-01-25 08:13:49 -06:00
* Return value: the GType associated with #XeditMessageType.
2011-11-07 13:46:58 -06:00
**/
GType
2016-01-25 08:13:49 -06:00
xedit_message_type_get_type (void)
2011-11-07 13:46:58 -06:00
{
static GType our_type = 0;
if (!our_type)
our_type = g_boxed_type_register_static (
2016-01-25 08:13:49 -06:00
"XeditMessageType",
(GBoxedCopyFunc) xedit_message_type_ref,
(GBoxedFreeFunc) xedit_message_type_unref);
2011-11-07 13:46:58 -06:00
return our_type;
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_type_identifier:
* @object_path: (allow-none): the object path
* @method: (allow-none): the method
2011-11-07 13:46:58 -06:00
*
* Get the string identifier for @method at @object_path.
*
* Return value: the identifier for @method at @object_path
*
*/
gchar *
2016-01-25 08:13:49 -06:00
xedit_message_type_identifier (const gchar *object_path,
2011-11-07 13:46:58 -06:00
const gchar *method)
{
return g_strconcat (object_path, ".", method, NULL);
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_type_is_valid_object_path:
* @object_path: (allow-none): the object path
2011-11-07 13:46:58 -06:00
*
* Returns whether @object_path is a valid object path
*
* Return value: %TRUE if @object_path is a valid object path
*
*/
gboolean
2016-01-25 08:13:49 -06:00
xedit_message_type_is_valid_object_path (const gchar *object_path)
2011-11-07 13:46:58 -06:00
{
if (!object_path)
return FALSE;
/* needs to start with / */
if (*object_path != '/')
return FALSE;
while (*object_path)
{
if (*object_path == '/')
{
++object_path;
if (!*object_path || !(g_ascii_isalpha (*object_path) || *object_path == '_'))
return FALSE;
}
else if (!(g_ascii_isalnum (*object_path) || *object_path == '_'))
{
return FALSE;
}
++object_path;
}
return TRUE;
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_type_is_supported:
2011-11-07 13:46:58 -06:00
* @type: the #GType
*
* Returns if @type is #GType supported by the message system.
*
* Return value: %TRUE if @type is a supported #GType
*
*/
gboolean
2016-01-25 08:13:49 -06:00
xedit_message_type_is_supported (GType type)
2011-11-07 13:46:58 -06:00
{
gint i = 0;
static const GType type_list[] =
{
G_TYPE_BOOLEAN,
G_TYPE_CHAR,
G_TYPE_UCHAR,
G_TYPE_INT,
G_TYPE_UINT,
G_TYPE_LONG,
G_TYPE_ULONG,
G_TYPE_INT64,
G_TYPE_UINT64,
G_TYPE_ENUM,
G_TYPE_FLAGS,
G_TYPE_FLOAT,
G_TYPE_DOUBLE,
G_TYPE_STRING,
G_TYPE_POINTER,
G_TYPE_BOXED,
G_TYPE_OBJECT,
G_TYPE_INVALID
};
if (!G_TYPE_IS_VALUE_TYPE (type))
return FALSE;
while (type_list[i] != G_TYPE_INVALID)
{
if (g_type_is_a (type, type_list[i]))
return TRUE;
i++;
}
return FALSE;
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_type_new_valist:
* @object_path: (allow-none): the object path
* @method: (allow-none): the method
2011-11-07 13:46:58 -06:00
* @num_optional: number of optional arguments
* @var_args: key/gtype pair variable argument list
*
2016-01-25 08:13:49 -06:00
* Create a new #XeditMessageType for @method at @object_path. Argument names
2011-11-07 13:46:58 -06:00
* and values are supplied by the NULL terminated variable argument list.
* The last @num_optional provided arguments are considered optional.
*
2016-01-25 08:13:49 -06:00
* Return value: the newly constructed #XeditMessageType
2011-11-07 13:46:58 -06:00
*
*/
2016-01-25 08:13:49 -06:00
XeditMessageType *
xedit_message_type_new_valist (const gchar *object_path,
2011-11-07 13:46:58 -06:00
const gchar *method,
guint num_optional,
va_list var_args)
{
2016-01-25 08:13:49 -06:00
XeditMessageType *message_type;
2011-11-07 13:46:58 -06:00
g_return_val_if_fail (object_path != NULL, NULL);
g_return_val_if_fail (method != NULL, NULL);
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (xedit_message_type_is_valid_object_path (object_path), NULL);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
message_type = g_new0(XeditMessageType, 1);
2011-11-07 13:46:58 -06:00
message_type->ref_count = 1;
message_type->object_path = g_strdup(object_path);
message_type->method = g_strdup(method);
message_type->num_arguments = 0;
message_type->arguments = g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify)g_free,
(GDestroyNotify)g_free);
2016-01-25 08:13:49 -06:00
xedit_message_type_set_valist (message_type, num_optional, var_args);
2011-11-07 13:46:58 -06:00
return message_type;
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_type_new:
* @object_path: (allow-none): the object path
* @method: (allow-none): the method
2011-11-07 13:46:58 -06:00
* @num_optional: number of optional arguments
* @...: key/gtype pair variable argument list
*
2016-01-25 08:13:49 -06:00
* Create a new #XeditMessageType for @method at @object_path. Argument names
2011-11-07 13:46:58 -06:00
* and values are supplied by the NULL terminated variable argument list.
* The last @num_optional provided arguments are considered optional.
*
2016-01-25 08:13:49 -06:00
* Return value: the newly constructed #XeditMessageType
2011-11-07 13:46:58 -06:00
*
*/
2016-01-25 08:13:49 -06:00
XeditMessageType *
xedit_message_type_new (const gchar *object_path,
2011-11-07 13:46:58 -06:00
const gchar *method,
guint num_optional,
...)
{
2016-01-25 08:13:49 -06:00
XeditMessageType *message_type;
2011-11-07 13:46:58 -06:00
va_list var_args;
va_start(var_args, num_optional);
2016-01-25 08:13:49 -06:00
message_type = xedit_message_type_new_valist (object_path, method, num_optional, var_args);
2011-11-07 13:46:58 -06:00
va_end(var_args);
return message_type;
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_type_set:
* @message_type: the #XeditMessageType
2011-11-07 13:46:58 -06:00
* @num_optional: number of optional arguments
* @...: key/gtype pair variable argument list
*
* Sets argument names/types supplied by the NULL terminated variable
* argument list. The last @num_optional provided arguments are considered
* optional.
*
*/
void
2016-01-25 08:13:49 -06:00
xedit_message_type_set (XeditMessageType *message_type,
2011-11-07 13:46:58 -06:00
guint num_optional,
...)
{
va_list va_args;
va_start (va_args, num_optional);
2016-01-25 08:13:49 -06:00
xedit_message_type_set_valist (message_type, num_optional, va_args);
2011-11-07 13:46:58 -06:00
va_end (va_args);
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_type_set_valist:
* @message_type: the #XeditMessageType
2011-11-07 13:46:58 -06:00
* @num_optional: number of optional arguments
* @var_args: key/gtype pair variable argument list
*
* Sets argument names/types supplied by the NULL terminated variable
* argument list @var_args. The last @num_optional provided arguments are
* considered optional.
*
*/
void
2016-01-25 08:13:49 -06:00
xedit_message_type_set_valist (XeditMessageType *message_type,
2011-11-07 13:46:58 -06:00
guint num_optional,
va_list var_args)
{
const gchar *key;
ArgumentInfo **optional = g_new0(ArgumentInfo *, num_optional);
guint i;
guint added = 0;
// parse key -> gtype pair arguments
while ((key = va_arg (var_args, const gchar *)) != NULL)
{
// get corresponding GType
GType gtype = va_arg (var_args, GType);
ArgumentInfo *info;
2016-01-25 08:13:49 -06:00
if (!xedit_message_type_is_supported (gtype))
2011-11-07 13:46:58 -06:00
{
g_error ("Message type '%s' is not supported", g_type_name (gtype));
2016-01-25 08:13:49 -06:00
xedit_message_type_unref (message_type);
2011-11-07 13:46:58 -06:00
g_free (optional);
return;
}
info = g_new(ArgumentInfo, 1);
info->type = gtype;
info->required = TRUE;
g_hash_table_insert (message_type->arguments, g_strdup (key), info);
++message_type->num_arguments;
++added;
if (num_optional > 0)
{
for (i = num_optional - 1; i > 0; --i)
optional[i] = optional[i - 1];
*optional = info;
}
}
message_type->num_required += added;
// set required for last num_optional arguments
for (i = 0; i < num_optional; ++i)
{
if (optional[i])
{
optional[i]->required = FALSE;
--message_type->num_required;
}
}
g_free (optional);
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_type_instantiate_valist:
* @message_type: the #XeditMessageType
2011-11-07 13:46:58 -06:00
* @va_args: NULL terminated variable list of key/value pairs
*
* Instantiate a new message from the message type with specific values
* for the message arguments.
*
* Return value: the newly created message
*
*/
2016-01-25 08:13:49 -06:00
XeditMessage *
xedit_message_type_instantiate_valist (XeditMessageType *message_type,
2011-11-07 13:46:58 -06:00
va_list va_args)
{
2016-01-25 08:13:49 -06:00
XeditMessage *message;
2011-11-07 13:46:58 -06:00
g_return_val_if_fail (message_type != NULL, NULL);
2016-01-25 08:13:49 -06:00
message = XEDIT_MESSAGE (g_object_new (XEDIT_TYPE_MESSAGE, "type", message_type, NULL));
xedit_message_set_valist (message, va_args);
2011-11-07 13:46:58 -06:00
return message;
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_type_instantiate:
* @message_type: the #XeditMessageType
2011-11-07 13:46:58 -06:00
* @...: NULL terminated variable list of key/value pairs
*
* Instantiate a new message from the message type with specific values
* for the message arguments.
*
* Return value: the newly created message
*
*/
2016-01-25 08:13:49 -06:00
XeditMessage *
xedit_message_type_instantiate (XeditMessageType *message_type,
2011-11-07 13:46:58 -06:00
...)
{
2016-01-25 08:13:49 -06:00
XeditMessage *message;
2011-11-07 13:46:58 -06:00
va_list va_args;
va_start (va_args, message_type);
2016-01-25 08:13:49 -06:00
message = xedit_message_type_instantiate_valist (message_type, va_args);
2011-11-07 13:46:58 -06:00
va_end (va_args);
return message;
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_type_get_object_path:
* @message_type: the #XeditMessageType
2011-11-07 13:46:58 -06:00
*
* Get the message type object path.
*
* Return value: the message type object path
*
*/
const gchar *
2016-01-25 08:13:49 -06:00
xedit_message_type_get_object_path (XeditMessageType *message_type)
2011-11-07 13:46:58 -06:00
{
return message_type->object_path;
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_type_get_method:
* @message_type: the #XeditMessageType
2011-11-07 13:46:58 -06:00
*
* Get the message type method.
*
* Return value: the message type method
*
*/
const gchar *
2016-01-25 08:13:49 -06:00
xedit_message_type_get_method (XeditMessageType *message_type)
2011-11-07 13:46:58 -06:00
{
return message_type->method;
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_type_lookup:
* @message_type: the #XeditMessageType
2011-11-07 13:46:58 -06:00
* @key: the argument key
*
* Get the argument key #GType.
*
* Return value: the #GType of @key
*
*/
GType
2016-01-25 08:13:49 -06:00
xedit_message_type_lookup (XeditMessageType *message_type,
2011-11-07 13:46:58 -06:00
const gchar *key)
{
ArgumentInfo *info = g_hash_table_lookup (message_type->arguments, key);
if (!info)
return G_TYPE_INVALID;
return info->type;
}
typedef struct
{
2016-01-25 08:13:49 -06:00
XeditMessageTypeForeach func;
2011-11-07 13:46:58 -06:00
gpointer user_data;
} ForeachInfo;
static void
foreach_gtype (const gchar *key,
ArgumentInfo *info,
ForeachInfo *finfo)
{
finfo->func (key, info->type, info->required, finfo->user_data);
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_type_foreach:
* @message_type: the #XeditMessageType
2011-11-07 13:46:58 -06:00
* @func: the callback function
* @user_data: user data supplied to the callback function
*
* Calls @func for each argument in the message type.
*
*/
void
2016-01-25 08:13:49 -06:00
xedit_message_type_foreach (XeditMessageType *message_type,
XeditMessageTypeForeach func,
2011-11-07 13:46:58 -06:00
gpointer user_data)
{
ForeachInfo info = {func, user_data};
g_hash_table_foreach (message_type->arguments, (GHFunc)foreach_gtype, &info);
}
// ex:ts=8:noet: