xed/xedit/xedit-message.c

595 lines
12 KiB
C
Raw Normal View History

2016-01-25 08:13:49 -06:00
#include "xedit-message.h"
#include "xedit-message-type.h"
2011-11-07 13:46:58 -06:00
#include <string.h>
#include <gobject/gvaluecollector.h>
/**
2016-01-25 08:13:49 -06:00
* SECTION:xedit-message
2011-11-07 13:46:58 -06:00
* @short_description: message bus message object
2016-01-25 08:13:49 -06:00
* @include: xedit/xedit-message.h
2011-11-07 13:46:58 -06:00
*
2016-01-25 08:13:49 -06:00
* Communication on a #XeditMessageBus is done through messages. Messages are
2011-11-07 13:46:58 -06:00
* sent over the bus and received by connecting callbacks on the message bus.
2016-01-25 08:13:49 -06:00
* A #XeditMessage is an instantiation of a #XeditMessageType, containing
2011-11-07 13:46:58 -06:00
* values for the arguments as specified in the message type.
*
* A message can be seen as a method call, or signal emission depending on
* who is the sender and who is the receiver. There is no explicit distinction
* between methods and signals.
*
* Since: 2.25.3
*
*/
2016-01-25 08:13:49 -06:00
#define XEDIT_MESSAGE_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), XEDIT_TYPE_MESSAGE, XeditMessagePrivate))
2011-11-07 13:46:58 -06:00
enum {
PROP_0,
PROP_OBJECT_PATH,
PROP_METHOD,
PROP_TYPE
};
2016-01-25 08:13:49 -06:00
struct _XeditMessagePrivate
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
XeditMessageType *type;
2011-11-07 13:46:58 -06:00
gboolean valid;
GHashTable *values;
};
2016-01-25 08:13:49 -06:00
G_DEFINE_TYPE (XeditMessage, xedit_message, G_TYPE_OBJECT)
2011-11-07 13:46:58 -06:00
static void
2016-01-25 08:13:49 -06:00
xedit_message_finalize (GObject *object)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
XeditMessage *message = XEDIT_MESSAGE (object);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
xedit_message_type_unref (message->priv->type);
2011-11-07 13:46:58 -06:00
g_hash_table_destroy (message->priv->values);
2016-01-25 08:13:49 -06:00
G_OBJECT_CLASS (xedit_message_parent_class)->finalize (object);
2011-11-07 13:46:58 -06:00
}
static void
2016-01-25 08:13:49 -06:00
xedit_message_get_property (GObject *object,
2011-11-07 13:46:58 -06:00
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
2016-01-25 08:13:49 -06:00
XeditMessage *msg = XEDIT_MESSAGE (object);
2011-11-07 13:46:58 -06:00
switch (prop_id)
{
case PROP_OBJECT_PATH:
2016-01-25 08:13:49 -06:00
g_value_set_string (value, xedit_message_type_get_object_path (msg->priv->type));
2011-11-07 13:46:58 -06:00
break;
case PROP_METHOD:
2016-01-25 08:13:49 -06:00
g_value_set_string (value, xedit_message_type_get_method (msg->priv->type));
2011-11-07 13:46:58 -06:00
break;
case PROP_TYPE:
g_value_set_boxed (value, msg->priv->type);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
2016-01-25 08:13:49 -06:00
xedit_message_set_property (GObject *object,
2011-11-07 13:46:58 -06:00
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
2016-01-25 08:13:49 -06:00
XeditMessage *msg = XEDIT_MESSAGE (object);
2011-11-07 13:46:58 -06:00
switch (prop_id)
{
case PROP_TYPE:
2016-01-25 08:13:49 -06:00
msg->priv->type = XEDIT_MESSAGE_TYPE (g_value_dup_boxed (value));
2011-11-07 13:46:58 -06:00
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GValue *
2016-01-25 08:13:49 -06:00
add_value (XeditMessage *message,
2011-11-07 13:46:58 -06:00
const gchar *key)
{
GValue *value;
2016-01-25 08:13:49 -06:00
GType type = xedit_message_type_lookup (message->priv->type, key);
2011-11-07 13:46:58 -06:00
if (type == G_TYPE_INVALID)
return NULL;
value = g_new0 (GValue, 1);
g_value_init (value, type);
g_value_reset (value);
g_hash_table_insert (message->priv->values, g_strdup (key), value);
return value;
}
static void
2016-01-25 08:13:49 -06:00
xedit_message_class_init (XeditMessageClass *klass)
2011-11-07 13:46:58 -06:00
{
GObjectClass *object_class = G_OBJECT_CLASS(klass);
2016-01-25 08:13:49 -06:00
object_class->finalize = xedit_message_finalize;
object_class->get_property = xedit_message_get_property;
object_class->set_property = xedit_message_set_property;
2011-11-07 13:46:58 -06:00
/**
2016-01-25 08:13:49 -06:00
* XeditMessage:object_path:
2011-11-07 13:46:58 -06:00
*
2016-01-25 08:13:49 -06:00
* The messages object path (e.g. /xedit/object/path).
2011-11-07 13:46:58 -06:00
*
*/
g_object_class_install_property (object_class, PROP_OBJECT_PATH,
g_param_spec_string ("object-path",
"OBJECT_PATH",
"The message object path",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
2016-01-25 08:13:49 -06:00
* XeditMessage:method:
2011-11-07 13:46:58 -06:00
*
* The messages method.
*
*/
g_object_class_install_property (object_class, PROP_METHOD,
g_param_spec_string ("method",
"METHOD",
"The message method",
NULL,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
2016-01-25 08:13:49 -06:00
* XeditMEssage:type:
2011-11-07 13:46:58 -06:00
*
* The message type.
*
*/
g_object_class_install_property (object_class, PROP_TYPE,
g_param_spec_boxed ("type",
"TYPE",
"The message type",
2016-01-25 08:13:49 -06:00
XEDIT_TYPE_MESSAGE_TYPE,
2011-11-07 13:46:58 -06:00
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
2016-01-25 08:13:49 -06:00
g_type_class_add_private (object_class, sizeof(XeditMessagePrivate));
2011-11-07 13:46:58 -06:00
}
static void
destroy_value (GValue *value)
{
g_value_unset (value);
g_free (value);
}
static void
2016-01-25 08:13:49 -06:00
xedit_message_init (XeditMessage *self)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
self->priv = XEDIT_MESSAGE_GET_PRIVATE (self);
2011-11-07 13:46:58 -06:00
self->priv->values = g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify)g_free,
(GDestroyNotify)destroy_value);
}
static gboolean
set_value_real (GValue *to,
const GValue *from)
{
GType from_type;
GType to_type;
from_type = G_VALUE_TYPE (from);
to_type = G_VALUE_TYPE (to);
if (!g_type_is_a (from_type, to_type))
{
if (!g_value_transform (from, to))
{
g_warning ("%s: Unable to make conversion from %s to %s",
G_STRLOC,
g_type_name (from_type),
g_type_name (to_type));
return FALSE;
}
return TRUE;
}
g_value_copy (from, to);
return TRUE;
}
inline static GValue *
2016-01-25 08:13:49 -06:00
value_lookup (XeditMessage *message,
2011-11-07 13:46:58 -06:00
const gchar *key,
gboolean create)
{
GValue *ret = (GValue *)g_hash_table_lookup (message->priv->values, key);
if (!ret && create)
ret = add_value (message, key);
return ret;
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_get_method:
* @message: the #XeditMessage
2011-11-07 13:46:58 -06:00
*
* Get the message method.
*
* Return value: the message method
*
*/
const gchar *
2016-01-25 08:13:49 -06:00
xedit_message_get_method (XeditMessage *message)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_MESSAGE (message), NULL);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
return xedit_message_type_get_method (message->priv->type);
2011-11-07 13:46:58 -06:00
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_get_object_path:
* @message: the #XeditMessage
2011-11-07 13:46:58 -06:00
*
* Get the message object path.
*
* Return value: the message object path
*
*/
const gchar *
2016-01-25 08:13:49 -06:00
xedit_message_get_object_path (XeditMessage *message)
2011-11-07 13:46:58 -06:00
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_MESSAGE (message), NULL);
2011-11-07 13:46:58 -06:00
2016-01-25 08:13:49 -06:00
return xedit_message_type_get_object_path (message->priv->type);
2011-11-07 13:46:58 -06:00
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_set:
* @message: the #XeditMessage
* @...: a %NULL terminated variable list of key/value pairs
2011-11-07 13:46:58 -06:00
*
* Set values of message arguments. The supplied @var_args should contain
* pairs of keys and argument values.
*
*/
void
2016-01-25 08:13:49 -06:00
xedit_message_set (XeditMessage *message,
2011-11-07 13:46:58 -06:00
...)
{
va_list ap;
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_MESSAGE (message));
2011-11-07 13:46:58 -06:00
va_start (ap, message);
2016-01-25 08:13:49 -06:00
xedit_message_set_valist (message, ap);
2011-11-07 13:46:58 -06:00
va_end (ap);
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_set_valist:
* @message: the #XeditMessage
* @var_args: a %NULL terminated variable list of key/value pairs
2011-11-07 13:46:58 -06:00
*
* Set values of message arguments. The supplied @var_args should contain
* pairs of keys and argument values.
*
*/
void
2016-01-25 08:13:49 -06:00
xedit_message_set_valist (XeditMessage *message,
2011-11-07 13:46:58 -06:00
va_list var_args)
{
const gchar *key;
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_MESSAGE (message));
2011-11-07 13:46:58 -06:00
while ((key = va_arg (var_args, const gchar *)) != NULL)
{
/* lookup the key */
GValue *container = value_lookup (message, key, TRUE);
GValue value = {0,};
gchar *error = NULL;
if (!container)
{
g_warning ("%s: Cannot set value for %s, does not exist",
G_STRLOC,
key);
/* skip value */
va_arg (var_args, gpointer);
continue;
}
g_value_init (&value, G_VALUE_TYPE (container));
G_VALUE_COLLECT (&value, var_args, 0, &error);
if (error)
{
g_warning ("%s: %s", G_STRLOC, error);
continue;
}
set_value_real (container, &value);
g_value_unset (&value);
}
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_set_value:
* @message: the #XeditMessage
2011-11-07 13:46:58 -06:00
* @key: the argument key
* @value: (out): the argument value
2011-11-07 13:46:58 -06:00
*
* Set value of message argument @key to @value.
*
*/
void
2016-01-25 08:13:49 -06:00
xedit_message_set_value (XeditMessage *message,
2011-11-07 13:46:58 -06:00
const gchar *key,
GValue *value)
{
GValue *container;
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_MESSAGE (message));
2011-11-07 13:46:58 -06:00
container = value_lookup (message, key, TRUE);
if (!container)
{
g_warning ("%s: Cannot set value for %s, does not exist",
G_STRLOC,
key);
return;
}
set_value_real (container, value);
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_set_valuesv:
* @message: the #XeditMessage
* @keys: (array-length=n_values): keys to set values for
* @values: (array-length=n_values): values to set
2011-11-07 13:46:58 -06:00
* @n_values: number of arguments to set values for
*
* Set message argument values.
*
*/
void
2016-01-25 08:13:49 -06:00
xedit_message_set_valuesv (XeditMessage *message,
2011-11-07 13:46:58 -06:00
const gchar **keys,
GValue *values,
gint n_values)
{
gint i;
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_MESSAGE (message));
2011-11-07 13:46:58 -06:00
for (i = 0; i < n_values; i++)
{
2016-01-25 08:13:49 -06:00
xedit_message_set_value (message, keys[i], &values[i]);
2011-11-07 13:46:58 -06:00
}
}
/* FIXME this is an issue for introspection */
2011-11-07 13:46:58 -06:00
/**
2016-01-25 08:13:49 -06:00
* xedit_message_get:
* @message: the #XeditMessage
* @...: a %NULL variable argument list of key/value container pairs
2011-11-07 13:46:58 -06:00
*
* Get values of message arguments. The supplied @var_args should contain
* pairs of keys and pointers to variables which are set to the argument
* value for the specified key.
*
*/
void
2016-01-25 08:13:49 -06:00
xedit_message_get (XeditMessage *message,
2011-11-07 13:46:58 -06:00
...)
{
va_list ap;
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_MESSAGE (message));
2011-11-07 13:46:58 -06:00
va_start (ap, message);
2016-01-25 08:13:49 -06:00
xedit_message_get_valist (message, ap);
2011-11-07 13:46:58 -06:00
va_end (ap);
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_get_valist:
* @message: the #XeditMessage
* @var_args: a %NULL variable argument list of key/value container pairs
2011-11-07 13:46:58 -06:00
*
* Get values of message arguments. The supplied @var_args should contain
* pairs of keys and pointers to variables which are set to the argument
* value for the specified key.
*
*/
void
2016-01-25 08:13:49 -06:00
xedit_message_get_valist (XeditMessage *message,
2011-11-07 13:46:58 -06:00
va_list var_args)
{
const gchar *key;
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_MESSAGE (message));
2011-11-07 13:46:58 -06:00
while ((key = va_arg (var_args, const gchar *)) != NULL)
{
GValue *container;
GValue copy = {0,};
gchar *error = NULL;
container = value_lookup (message, key, FALSE);
if (!container)
{
/* skip value */
va_arg (var_args, gpointer);
continue;
}
/* copy the value here, to be sure it isn't tainted */
g_value_init (&copy, G_VALUE_TYPE (container));
g_value_copy (container, &copy);
G_VALUE_LCOPY (&copy, var_args, 0, &error);
if (error)
{
g_warning ("%s: %s", G_STRLOC, error);
g_free (error);
/* purposely leak the value here, because it might
be in a bad state */
continue;
}
g_value_unset (&copy);
}
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_get_value:
* @message: the #XeditMessage
2011-11-07 13:46:58 -06:00
* @key: the argument key
* @value: (out): value return container
2011-11-07 13:46:58 -06:00
*
* Get the value of a specific message argument. @value will be initialized
* with the correct type.
*
*/
void
2016-01-25 08:13:49 -06:00
xedit_message_get_value (XeditMessage *message,
2011-11-07 13:46:58 -06:00
const gchar *key,
GValue *value)
{
GValue *container;
2016-01-25 08:13:49 -06:00
g_return_if_fail (XEDIT_IS_MESSAGE (message));
2011-11-07 13:46:58 -06:00
container = value_lookup (message, key, FALSE);
if (!container)
{
g_warning ("%s: Invalid key `%s'",
G_STRLOC,
key);
return;
}
g_value_init (value, G_VALUE_TYPE (container));
set_value_real (value, container);
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_get_key_type:
* @message: the #XeditMessage
2011-11-07 13:46:58 -06:00
* @key: the argument key
*
* Get the type of a message argument.
*
* Return value: the type of @key
*
*/
GType
2016-01-25 08:13:49 -06:00
xedit_message_get_key_type (XeditMessage *message,
2011-11-07 13:46:58 -06:00
const gchar *key)
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_MESSAGE (message), G_TYPE_INVALID);
2011-11-07 13:46:58 -06:00
g_return_val_if_fail (message->priv->type != NULL, G_TYPE_INVALID);
2016-01-25 08:13:49 -06:00
return xedit_message_type_lookup (message->priv->type, key);
2011-11-07 13:46:58 -06:00
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_has_key:
* @message: the #XeditMessage
2011-11-07 13:46:58 -06:00
* @key: the argument key
*
* Check whether the message has a specific key.
*
* Return value: %TRUE if @message has argument @key
*
*/
gboolean
2016-01-25 08:13:49 -06:00
xedit_message_has_key (XeditMessage *message,
2011-11-07 13:46:58 -06:00
const gchar *key)
{
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_MESSAGE (message), FALSE);
2011-11-07 13:46:58 -06:00
return value_lookup (message, key, FALSE) != NULL;
}
typedef struct
{
2016-01-25 08:13:49 -06:00
XeditMessage *message;
2011-11-07 13:46:58 -06:00
gboolean valid;
} ValidateInfo;
static void
validate_key (const gchar *key,
GType type,
gboolean required,
ValidateInfo *info)
{
GValue *value;
if (!info->valid || !required)
return;
value = value_lookup (info->message, key, FALSE);
if (!value)
info->valid = FALSE;
}
/**
2016-01-25 08:13:49 -06:00
* xedit_message_validate:
* @message: the #XeditMessage
2011-11-07 13:46:58 -06:00
*
* Validates the message arguments according to the message type.
*
* Return value: %TRUE if the message is valid
*
*/
gboolean
2016-01-25 08:13:49 -06:00
xedit_message_validate (XeditMessage *message)
2011-11-07 13:46:58 -06:00
{
ValidateInfo info = {message, TRUE};
2016-01-25 08:13:49 -06:00
g_return_val_if_fail (XEDIT_IS_MESSAGE (message), FALSE);
2011-11-07 13:46:58 -06:00
g_return_val_if_fail (message->priv->type != NULL, FALSE);
if (!message->priv->valid)
{
2016-01-25 08:13:49 -06:00
xedit_message_type_foreach (message->priv->type,
(XeditMessageTypeForeach)validate_key,
2011-11-07 13:46:58 -06:00
&info);
message->priv->valid = info.valid;
}
return message->priv->valid;
}
// ex:ts=8:noet: