@@ -0,0 +1,341 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Purism SPC
|
||||
* SPDX-License-Identifier: GPL-3.0+
|
||||
* Author: Guido Günther <agx@sigxcpu.org>
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "fbd-feedback-profile"
|
||||
|
||||
#include "fbd-feedback-dummy.h"
|
||||
#include "fbd-feedback-profile.h"
|
||||
#include "fbd-feedback-sound.h"
|
||||
#include "fbd-feedback-vibra-periodic.h"
|
||||
#include "fbd-feedback-vibra-rumble.h"
|
||||
|
||||
#include <json-glib/json-glib.h>
|
||||
|
||||
#define FBD_FEEDBACK_CLS_PREFIX "FbdFeedback"
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_NAME,
|
||||
PROP_FEEDBACKS,
|
||||
PROP_LAST_PROP,
|
||||
};
|
||||
static GParamSpec *props[PROP_LAST_PROP];
|
||||
|
||||
/**
|
||||
* SECTION:fbd-feedback-profile
|
||||
* @short_description: A single profile in a #FbdFeedback
|
||||
* @Title: FbdFeedbackProfile
|
||||
*/
|
||||
|
||||
typedef struct _FbdFeedbackProfile {
|
||||
GObject parent;
|
||||
|
||||
gchar *name;
|
||||
GHashTable *feedbacks;
|
||||
} FbdFeedbackProfile;
|
||||
|
||||
static void json_serializable_iface_init (JsonSerializableIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (FbdFeedbackProfile, fbd_feedback_profile, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (JSON_TYPE_SERIALIZABLE,
|
||||
json_serializable_iface_init));
|
||||
|
||||
|
||||
static JsonNode *
|
||||
fbd_feedback_profile_serializable_serialize_property (JsonSerializable *serializable,
|
||||
const gchar *property_name,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FbdFeedbackProfile *self = FBD_FEEDBACK_PROFILE (serializable);
|
||||
JsonNode *node = NULL;
|
||||
|
||||
if (g_strcmp0 (property_name, "feedbacks") == 0) {
|
||||
GHashTableIter iter;
|
||||
gpointer key;
|
||||
FbdFeedbackProfile *profile;
|
||||
JsonArray *array = json_array_sized_new (FBD_FEEDBACK_PROFILE_N_PROFILES);
|
||||
|
||||
g_hash_table_iter_init (&iter, self->feedbacks);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *) &profile)) {
|
||||
json_array_add_element (array, json_gobject_serialize (G_OBJECT(profile)));
|
||||
}
|
||||
node = json_node_init_array (json_node_alloc (), array);
|
||||
} else {
|
||||
node = json_serializable_default_serialize_property (serializable,
|
||||
property_name,
|
||||
value,
|
||||
pspec);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static GType
|
||||
feedback_get_type (JsonNode *feedback_node)
|
||||
{
|
||||
g_autofree gchar *type_name = NULL;
|
||||
JsonObject *obj = json_node_get_object (feedback_node);
|
||||
JsonNode *type_node = json_object_get_member (obj, "type");
|
||||
GType gtype = 0;
|
||||
|
||||
/* Ensure all feedback types so the json parsing can use them */
|
||||
g_type_ensure (FBD_TYPE_FEEDBACK_DUMMY);
|
||||
g_type_ensure (FBD_TYPE_FEEDBACK_VIBRA_PERIODIC);
|
||||
g_type_ensure (FBD_TYPE_FEEDBACK_VIBRA_RUMBLE);
|
||||
g_type_ensure (FBD_TYPE_FEEDBACK_SOUND);
|
||||
|
||||
g_return_val_if_fail (type_node, FBD_TYPE_FEEDBACK_DUMMY);
|
||||
|
||||
type_name = g_strdup_printf ("FbdFeedback%s",
|
||||
json_node_get_string (type_node));
|
||||
type_name[strlen(FBD_FEEDBACK_CLS_PREFIX)] =
|
||||
g_ascii_toupper (type_name[strlen(FBD_FEEDBACK_CLS_PREFIX)]);
|
||||
gtype = g_type_from_name (type_name);
|
||||
|
||||
g_debug ("Feedback %s, type %lu", type_name, gtype);
|
||||
g_return_val_if_fail (gtype, FBD_TYPE_FEEDBACK_DUMMY);
|
||||
return gtype;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fbd_feedback_profile_serializable_deserialize_property (JsonSerializable *serializable,
|
||||
const gchar *property_name,
|
||||
GValue *value,
|
||||
GParamSpec *pspec,
|
||||
JsonNode *property_node)
|
||||
{
|
||||
if (g_strcmp0 (property_name, "feedbacks") == 0) {
|
||||
if (JSON_NODE_TYPE (property_node) == JSON_NODE_NULL) {
|
||||
g_value_set_pointer (value, NULL);
|
||||
return TRUE;
|
||||
} else if (JSON_NODE_TYPE (property_node) == JSON_NODE_ARRAY) {
|
||||
JsonArray *array = json_node_get_array (property_node);
|
||||
guint i, array_len = json_array_get_length (array);
|
||||
GHashTable *feedbacks = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
g_free,
|
||||
(GDestroyNotify)g_object_unref);
|
||||
for (i = 0; i < array_len; i++) {
|
||||
JsonNode *element_node = json_array_get_element (array, i);
|
||||
|
||||
if (JSON_NODE_HOLDS_OBJECT (element_node)) {
|
||||
gchar *event_name;
|
||||
FbdFeedbackBase *feedback;
|
||||
GType gtype = feedback_get_type (element_node);
|
||||
|
||||
feedback = FBD_FEEDBACK_BASE (json_gobject_deserialize (gtype, element_node));
|
||||
event_name = g_strdup (fbd_feedback_get_event_name (FBD_FEEDBACK_BASE(feedback)));
|
||||
g_hash_table_insert (feedbacks, event_name, feedback);
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
g_value_set_boxed (value, feedbacks);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
} else {
|
||||
return json_serializable_default_deserialize_property (serializable,
|
||||
property_name,
|
||||
value,
|
||||
pspec,
|
||||
property_node);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
fbd_feedback_profile_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FbdFeedbackProfile *self = FBD_FEEDBACK_PROFILE (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_NAME:
|
||||
g_free (self->name);
|
||||
self->name = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_FEEDBACKS:
|
||||
if (self->feedbacks)
|
||||
g_hash_table_unref (self->feedbacks);
|
||||
self->feedbacks = g_value_get_boxed (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fbd_feedback_profile_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FbdFeedbackProfile *self = FBD_FEEDBACK_PROFILE (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_NAME:
|
||||
g_value_set_string (value, self->name);
|
||||
break;
|
||||
case PROP_FEEDBACKS:
|
||||
g_value_set_boxed (value, self->feedbacks);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fbd_feedback_profile_dispose (GObject *object)
|
||||
{
|
||||
FbdFeedbackProfile *self = FBD_FEEDBACK_PROFILE (object);
|
||||
|
||||
g_clear_pointer (&self->feedbacks, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (fbd_feedback_profile_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
fbd_feedback_profile_finalize (GObject *object)
|
||||
{
|
||||
FbdFeedbackProfile *self = FBD_FEEDBACK_PROFILE (object);
|
||||
|
||||
g_clear_pointer (&self->name, g_free);
|
||||
|
||||
G_OBJECT_CLASS (fbd_feedback_profile_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
json_serializable_iface_init (JsonSerializableIface *iface)
|
||||
{
|
||||
iface->serialize_property = fbd_feedback_profile_serializable_serialize_property;
|
||||
iface->deserialize_property = fbd_feedback_profile_serializable_deserialize_property;
|
||||
}
|
||||
|
||||
static void
|
||||
fbd_feedback_profile_constructed (GObject *object)
|
||||
{
|
||||
FbdFeedbackProfile *self = FBD_FEEDBACK_PROFILE (object);
|
||||
|
||||
G_OBJECT_CLASS (fbd_feedback_profile_parent_class)->constructed (object);
|
||||
|
||||
if (!self->feedbacks) {
|
||||
self->feedbacks = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
g_free,
|
||||
(GDestroyNotify)g_object_unref);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fbd_feedback_profile_class_init (FbdFeedbackProfileClass *klass)
|
||||
{
|
||||
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->set_property = fbd_feedback_profile_set_property;
|
||||
object_class->get_property = fbd_feedback_profile_get_property;
|
||||
|
||||
object_class->constructed = fbd_feedback_profile_constructed;
|
||||
object_class->dispose = fbd_feedback_profile_dispose;
|
||||
object_class->finalize = fbd_feedback_profile_finalize;
|
||||
|
||||
props[PROP_NAME] =
|
||||
g_param_spec_string (
|
||||
"name",
|
||||
"Name",
|
||||
"The feedback name",
|
||||
NULL,
|
||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
props[PROP_FEEDBACKS] =
|
||||
g_param_spec_boxed (
|
||||
"feedbacks",
|
||||
"Feedbacks",
|
||||
"The feedbacks for this profile",
|
||||
G_TYPE_HASH_TABLE,
|
||||
/* Can't be CONSTRUCT_ONLY since json-glib can't handle it */
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (object_class, PROP_LAST_PROP, props);
|
||||
}
|
||||
|
||||
static void
|
||||
fbd_feedback_profile_init (FbdFeedbackProfile *self)
|
||||
{
|
||||
}
|
||||
|
||||
FbdFeedbackProfile *
|
||||
fbd_feedback_profile_new (const gchar *name)
|
||||
{
|
||||
return g_object_new(FBD_TYPE_FEEDBACK_PROFILE,
|
||||
"name", name,
|
||||
NULL);
|
||||
}
|
||||
|
||||
const char *
|
||||
fbd_feedback_profile_get_name (FbdFeedbackProfile *self)
|
||||
{
|
||||
g_return_val_if_fail (FBD_IS_FEEDBACK_PROFILE (self), "");
|
||||
|
||||
return self->name;
|
||||
}
|
||||
|
||||
void
|
||||
fbd_feedback_profile_add_feedback (FbdFeedbackProfile *self, FbdFeedbackBase *feedback)
|
||||
{
|
||||
g_return_if_fail (FBD_IS_FEEDBACK_PROFILE (self));
|
||||
gchar *name = g_strdup (fbd_feedback_get_event_name (feedback));
|
||||
|
||||
/* TODO: allow for more than one feedback per event and profile */
|
||||
g_hash_table_insert (self->feedbacks, name, g_object_ref (feedback));
|
||||
}
|
||||
|
||||
FbdFeedbackBase *
|
||||
fbd_feedback_profile_get_feedback (FbdFeedbackProfile *self, const char *event_name)
|
||||
{
|
||||
g_return_val_if_fail (FBD_IS_FEEDBACK_PROFILE (self), NULL);
|
||||
|
||||
return g_hash_table_lookup (self->feedbacks, event_name);
|
||||
}
|
||||
|
||||
FbdFeedbackProfileLevel
|
||||
fbd_feedback_profile_level (const char *name)
|
||||
{
|
||||
FbdFeedbackProfileLevel profile = FBD_FEEDBACK_PROFILE_LEVEL_UNKNOWN;
|
||||
|
||||
if (!g_strcmp0("silent", name)) {
|
||||
profile = FBD_FEEDBACK_PROFILE_LEVEL_SILENT;
|
||||
} else if (!g_strcmp0("quiet", name)) {
|
||||
profile = FBD_FEEDBACK_PROFILE_LEVEL_QUIET;
|
||||
} else if (!g_strcmp0("full", name)) {
|
||||
profile = FBD_FEEDBACK_PROFILE_LEVEL_FULL;
|
||||
}
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
const char*
|
||||
fbd_feedback_profile_level_to_string (FbdFeedbackProfileLevel level)
|
||||
{
|
||||
switch (level) {
|
||||
case FBD_FEEDBACK_PROFILE_LEVEL_SILENT:
|
||||
return "silent";
|
||||
case FBD_FEEDBACK_PROFILE_LEVEL_QUIET:
|
||||
return "quiet";
|
||||
case FBD_FEEDBACK_PROFILE_LEVEL_FULL:
|
||||
return "full";
|
||||
case FBD_FEEDBACK_PROFILE_LEVEL_UNKNOWN:
|
||||
default:
|
||||
return "full";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user