Commit 578c36d3 authored by Guido Gunther's avatar Guido Gunther
Browse files

Update upstream source from tag 'v0.0.0+git20210426'

Update to upstream version '0.0.0+git20210426'
with Debian dir ce67e973f713e33c09e66e1871ba0e0c60111e2c
parents 357ef585 48b4bb97
(
(c-mode . (
(c-file-style . "linux")
(indent-tabs-mode . nil)
(c-basic-offset . 2)
))
(setq auto-mode-alist (cons '("\\.ui$" . nxml-mode) auto-mode-alist))
(nxml-mode . (
(indent-tabs-mode . nil)
))
(css-mode . (
(css-indent-offset . 2)
))
)
......@@ -57,7 +57,12 @@ gdbus introspect --session --dest org.sigxcpu.Feedback --object-path /org/sigxcp
and to request feedback for an event
```sh
gdbus call --session --dest org.sigxcpu.Feedback --object-path /org/sigxcpu/Feedback --method org.sigxcpu.Feedback.Feedback 'my.app.id' 'phone-incoming-call' '[]' 0
gdbus call --session --dest org.sigxcpu.Feedback --object-path /org/sigxcpu/Feedback --method org.sigxcpu.Feedback.TriggerFeedback 'my.app.id' 'phone-incoming-call' '[]' 0
```
This will return an Event id which you should memorize if you ever want to end the ringtone with:
```sh
gdbus call --session --dest org.sigxcpu.Feedback --object-path /org/sigxcpu/Feedback --method org.sigxcpu.Feedback.EndFeedback EVENTID
```
See `examples/` for a simple python example using GObject introspection.
......
......@@ -148,7 +148,7 @@ on_trigger_feedback_finished (LfbGdbusFeedback *proxy,
{
GTask *task = data->task;
LfbEvent *self = data->event;
GError *err = NULL;
g_autoptr (GError) err = NULL;
gboolean success;
LfbEventState state;
......@@ -161,7 +161,7 @@ on_trigger_feedback_finished (LfbGdbusFeedback *proxy,
res,
&err);
if (!success) {
g_task_return_error (task, err);
g_task_return_error (task, g_steal_pointer (&err));
state = LFB_EVENT_STATE_ERRORED;
} else {
g_task_return_boolean (task, TRUE);
......@@ -183,7 +183,7 @@ on_end_feedback_finished (LfbGdbusFeedback *proxy,
{
GTask *task = data->task;
LfbEvent *self = data->event;
GError *err = NULL;
g_autoptr (GError) err = NULL;
gboolean success;
g_return_if_fail (G_IS_TASK (task));
......@@ -194,7 +194,7 @@ on_end_feedback_finished (LfbGdbusFeedback *proxy,
res,
&err);
if (!success) {
g_task_return_error (task, err);
g_task_return_error (task, g_steal_pointer (&err));
} else
g_task_return_boolean (task, TRUE);
......
......@@ -56,6 +56,7 @@ static void
fbd_dev_led_free (FbdDevLed *led)
{
g_object_unref (led->dev);
g_free (led);
}
static gboolean
......@@ -93,8 +94,7 @@ initable_init (GInitable *initable,
{
const gchar * const subsystems[] = { LED_SUBSYSTEM, NULL };
FbdDevLeds *self = FBD_DEV_LEDS (initable);
g_autoptr (GList) leds;
g_autolist (GUdevDevice) leds = NULL;
gboolean found = FALSE;
self->client = g_udev_client_new (subsystems);
......@@ -116,11 +116,13 @@ initable_init (GInitable *initable,
color LEDSs so go with fixed colors until the kernel gives us
enough information */
for (int i = 0; i <= FBD_FEEDBACK_LED_COLOR_LAST; i++) {
g_autofree gchar *color;
g_autofree char *color = NULL;
g_autofree char *enum_name = NULL;
gchar *c;
c = strrchr (g_enum_to_string (FBD_TYPE_FEEDBACK_LED_COLOR, i), '_');
color = g_strdup (g_ascii_strdown (c+1, -1));
enum_name = g_enum_to_string (FBD_TYPE_FEEDBACK_LED_COLOR, i);
c = strrchr (enum_name, '_');
color = g_ascii_strdown (c+1, -1);
if (g_strstr_len (name, -1, color)) {
g_autoptr (GError) err = NULL;
guint brightness = g_udev_device_get_sysfs_attr_as_int (dev, "max_brightness");
......@@ -129,7 +131,7 @@ initable_init (GInitable *initable,
continue;
led = g_malloc0 (sizeof(FbdDevLed));
led->dev = dev;
led->dev = g_object_ref (dev);
led->color = i;
led->max_brightness = brightness;
path = g_udev_device_get_sysfs_path (dev);
......@@ -139,9 +141,6 @@ initable_init (GInitable *initable,
break;
}
}
if (!led)
g_object_unref (dev);
}
/* TODO: listen for new leds via udev events */
......
......@@ -29,6 +29,8 @@
typedef struct _FbdAsyncData {
FbdDevSoundPlayedCallback callback;
FbdFeedbackSound *feedback;
FbdDevSound *dev;
GCancellable *playback;
} FbdAsyncData;
typedef struct _FbdDevSound {
......@@ -36,6 +38,7 @@ typedef struct _FbdDevSound {
GSoundContext *ctx;
GSettings *sound_settings;
GHashTable *playbacks;
} FbdDevSound;
static void initable_iface_init (GInitableIface *iface);
......@@ -69,6 +72,29 @@ on_sound_theme_name_changed (FbdDevSound *self,
g_warning ("Failed to set sound theme name to %s: %s", key, error->message);
}
static FbdAsyncData*
fbd_async_data_new (FbdDevSound *dev, FbdFeedbackSound *feedback, FbdDevSoundPlayedCallback callback)
{
FbdAsyncData* data;
data = g_new0 (FbdAsyncData, 1);
data->callback = callback;
data->feedback = g_object_ref (feedback);
data->dev = g_object_ref (dev);
data->playback = g_cancellable_new ();
return data;
}
static void
fbd_async_data_dispose (FbdAsyncData *object)
{
g_object_unref (object->feedback);
g_object_unref (object->dev);
g_object_unref (object->playback);
g_free (object);
}
static void
fbd_dev_sound_dispose (GObject *object)
{
......@@ -76,6 +102,7 @@ fbd_dev_sound_dispose (GObject *object)
g_clear_object (&self->ctx);
g_clear_object (&self->sound_settings);
g_clear_pointer (&self->playbacks, g_hash_table_unref);
G_OBJECT_CLASS (fbd_dev_sound_parent_class)->dispose (object);
}
......@@ -88,6 +115,7 @@ initable_init (GInitable *initable,
FbdDevSound *self = FBD_DEV_SOUND (initable);
const char *desktop;
self->playbacks = g_hash_table_new (g_direct_hash, g_direct_equal);
self->ctx = gsound_context_new(NULL, error);
if (!self->ctx)
return FALSE;
......@@ -139,11 +167,13 @@ on_sound_play_finished_callback (GSoundContext *ctx,
GAsyncResult *res,
FbdAsyncData *data)
{
GError *err = NULL;
g_autoptr (GError) err = NULL;
if (!gsound_context_play_full_finish (ctx, res, &err)) {
if (err->domain == GSOUND_ERROR && err->code == GSOUND_ERROR_NOTFOUND) {
g_debug ("Failed to find sound '%s'", fbd_feedback_sound_get_effect (data->feedback));
} else if (g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
g_debug ("Sound '%s' cancelled", fbd_feedback_sound_get_effect (data->feedback));
} else {
g_warning ("Failed to play sound '%s': %s",
fbd_feedback_sound_get_effect (data->feedback),
......@@ -152,8 +182,9 @@ on_sound_play_finished_callback (GSoundContext *ctx,
}
(*data->callback)(data->feedback);
g_object_unref (data->feedback);
g_free (data);
g_hash_table_remove (data->dev->playbacks, data->feedback);
fbd_async_data_dispose (data);
}
......@@ -165,11 +196,11 @@ fbd_dev_sound_play (FbdDevSound *self, FbdFeedbackSound *feedback, FbdDevSoundPl
g_return_val_if_fail (FBD_IS_DEV_SOUND (self), FALSE);
g_return_val_if_fail (GSOUND_IS_CONTEXT (self->ctx), FALSE);
data = g_new0 (FbdAsyncData, 1);
data->callback = callback;
data->feedback = g_object_ref (feedback);
data = fbd_async_data_new (self, feedback, callback);
gsound_context_play_full (self->ctx, NULL,
g_hash_table_insert (self->playbacks, feedback, data);
gsound_context_play_full (self->ctx, data->playback,
(GAsyncReadyCallback)on_sound_play_finished_callback,
data,
GSOUND_ATTR_EVENT_ID, fbd_feedback_sound_get_effect (feedback),
......@@ -178,3 +209,20 @@ fbd_dev_sound_play (FbdDevSound *self, FbdFeedbackSound *feedback, FbdDevSoundPl
NULL);
return TRUE;
}
gboolean
fbd_dev_sound_stop(FbdDevSound *self, FbdFeedbackSound *feedback)
{
FbdAsyncData *data;
g_return_val_if_fail (FBD_IS_DEV_SOUND (self), FALSE);
data = g_hash_table_lookup (self->playbacks, feedback);
if (data == NULL)
return FALSE;
g_cancellable_cancel (data->playback);
return TRUE;
}
......@@ -4,7 +4,7 @@
* Author: Guido Günther <agx@sigxcpu.org>
*/
#define G_LOG_DOMAIN "fbd-feedback-event"
#define G_LOG_DOMAIN "fbd-event"
#include "lfb-names.h"
#include "fbd.h"
......@@ -25,6 +25,7 @@ enum {
PROP_END_REASON,
PROP_FEEDBACKS_ENDED,
PROP_TIMEOUT,
PROP_SENDER,
PROP_LAST_PROP,
};
static GParamSpec *props[PROP_LAST_PROP];
......@@ -35,8 +36,9 @@ typedef struct _FbdEvent {
guint id;
char *app_id;
char *event;
char *sender;
gint timeout;
int timeout;
gboolean expired;
guint timeout_id;
......@@ -118,6 +120,10 @@ fbd_event_set_property (GObject *object,
case PROP_END_REASON:
fbd_event_set_end_reason (self, g_value_get_enum (value));
break;
case PROP_SENDER:
g_free (self->sender);
self->sender = g_value_dup_string (value);
break;
case PROP_FEEDBACKS_ENDED:
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
......@@ -152,6 +158,9 @@ fbd_event_get_property (GObject *object,
case PROP_FEEDBACKS_ENDED:
g_value_set_boolean (value, self->ended);
break;
case PROP_SENDER:
g_value_set_string (value, self->sender);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
......@@ -181,6 +190,7 @@ fbd_event_finalize (GObject *object)
g_clear_pointer (&self->app_id, g_free);
g_clear_pointer (&self->event, g_free);
g_clear_pointer (&self->sender, g_free);
G_OBJECT_CLASS (fbd_event_parent_class)->finalize (object);
}
......@@ -245,6 +255,19 @@ fbd_event_class_init (FbdEventClass *klass)
FBD_EVENT_END_REASON_NATURAL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
/**
* FbdEvent:Sender:
*
* The DBus name of the sender
*/
props[PROP_SENDER] =
g_param_spec_string (
"sender",
"",
"",
NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (object_class, PROP_LAST_PROP, props);
/**
......@@ -267,17 +290,18 @@ fbd_event_init (FbdEvent *self)
}
FbdEvent *
fbd_event_new (gint id, const gchar *app_id, const gchar *event, gint timeout)
fbd_event_new (int id, const char *app_id, const char *event, int timeout, const char *sender)
{
return FBD_EVENT (g_object_new (FBD_TYPE_EVENT,
"id", id,
"app_id", app_id,
"event", event,
"timeout", timeout,
"sender", sender,
NULL));
}
const gchar *
const char *
fbd_event_get_event (FbdEvent *self)
{
g_return_val_if_fail (FBD_IS_EVENT (self), NULL);
......@@ -285,7 +309,7 @@ fbd_event_get_event (FbdEvent *self)
return self->event;
}
const gchar *
const char *
fbd_event_get_app_id (FbdEvent *self)
{
g_return_val_if_fail (FBD_IS_EVENT (self), NULL);
......@@ -301,7 +325,7 @@ fbd_event_get_id (FbdEvent *self)
return self->id;
}
gint
int
fbd_event_get_timeout (FbdEvent *self)
{
g_return_val_if_fail (FBD_IS_EVENT (self), -1);
......@@ -334,7 +358,7 @@ fbd_event_get_feedbacks (FbdEvent *self)
return self->feedbacks;
}
gint
int
fbd_event_remove_feedback (FbdEvent *self, FbdFeedbackBase *feedback)
{
g_return_val_if_fail (FBD_IS_EVENT (self), 0);
......@@ -447,3 +471,17 @@ fbd_event_get_end_reason (FbdEvent *self)
return self->end_reason;
}
/**
* fbd_event_get_sender:
* @self: The Event
*
* Returns: The DBus sender that triggered the event.
*/
const char *
fbd_event_get_sender (FbdEvent *self)
{
g_return_val_if_fail (FBD_IS_EVENT (self), FBD_EVENT_END_REASON_NATURAL);
return self->sender;
}
......@@ -33,20 +33,21 @@ typedef enum _FbdEventTimeout {
G_DECLARE_FINAL_TYPE (FbdEvent, fbd_event, FBD, EVENT, GObject);
FbdEvent *fbd_event_new (gint id, const gchar *app_id, const gchar *event, gint timeout);
const gchar *fbd_event_get_event (FbdEvent *event);
const gchar *fbd_event_get_app_id (FbdEvent *event);
FbdEvent *fbd_event_new (gint id, const char *app_id, const char *event, int timeout, const char *sender);
const char *fbd_event_get_event (FbdEvent *event);
const char *fbd_event_get_app_id (FbdEvent *event);
guint fbd_event_get_id (FbdEvent *event);
gint fbd_event_get_timeout (FbdEvent *self);
int fbd_event_get_timeout (FbdEvent *self);
void fbd_event_set_end_reason (FbdEvent *self, FbdEventEndReason reason);
FbdEventEndReason fbd_event_get_end_reason (FbdEvent *self);
GSList * fbd_event_get_feedbacks (FbdEvent *self);
void fbd_event_add_feedback (FbdEvent *self,
FbdFeedbackBase *feedback);
gint fbd_event_remove_feedback (FbdEvent *self,
int fbd_event_remove_feedback (FbdEvent *self,
FbdFeedbackBase *feedback);
void fbd_event_run_feedbacks (FbdEvent *self);
void fbd_event_end_feedbacks (FbdEvent *self);
gboolean fbd_event_get_feedbacks_ended (FbdEvent *self);
const char *fbd_event_get_sender (FbdEvent *self);
G_END_DECLS
......@@ -47,7 +47,10 @@ typedef struct _FbdFeedbackManager {
FbdFeedbackTheme *theme;
guint next_id;
/* Key: event id, value: event */
GHashTable *events;
/* Key: DBus name, value: watch_id */
GHashTable *clients;
/* Hardware interaction */
GUdevClient *client;
......@@ -127,7 +130,8 @@ app_get_feedback_level (const gchar *app_id)
static void
init_devices (FbdFeedbackManager *self)
{
GList *devices, *l;
GList *l;
g_autolist (GUdevClient) devices = NULL;
g_autoptr(GError) err = NULL;
devices = g_udev_client_query_by_subsystem (self->client, "input");
......@@ -214,6 +218,72 @@ on_feedbackd_setting_changed (FbdFeedbackManager *self,
fbd_feedback_manager_set_profile (self, profile);
}
static void
on_client_vanished (GDBusConnection *connection,
const gchar *name,
gpointer user_data)
{
FbdFeedbackManager *self = FBD_FEEDBACK_MANAGER (user_data);
GHashTableIter iter;
gpointer key, value;
FbdEvent *event;
GSList *l;
g_autoptr (GSList) events = NULL;
g_return_if_fail (name);
g_debug ("Client %s vanished", name);
/*
* Prepare a list of events to end feedback for so we don't modify
* the hash table in place when 'feedbacks-ended' fires.
*/
g_hash_table_iter_init (&iter, self->events);
while (g_hash_table_iter_next (&iter, &key, &value)) {
event = FBD_EVENT (value);
if (!g_strcmp0 (fbd_event_get_sender (event), name))
events = g_slist_append (events, event);
}
for (l = events; l; l = l->next) {
event = l->data;
g_debug ("Ending event %s (%d) since %s vanished",
fbd_event_get_event (event),
fbd_event_get_id (event),
name);
fbd_event_end_feedbacks (event);
}
g_hash_table_remove (self->clients, name);
}
static void
watch_client (FbdFeedbackManager *self, GDBusMethodInvocation *invocation)
{
guint watch_id;
GDBusConnection *conn = g_dbus_method_invocation_get_connection (invocation);
const char *sender = g_dbus_method_invocation_get_sender (invocation);
watch_id = g_bus_watch_name_on_connection (conn,
sender,
G_BUS_NAME_WATCHER_FLAGS_NONE,
NULL,
on_client_vanished,
self,
NULL);
g_hash_table_insert (self->clients, g_strdup (sender), GUINT_TO_POINTER (watch_id));
}
static void
free_client_watch (gpointer data)
{
guint watch_id = GPOINTER_TO_UINT (data);
if (watch_id == 0)
return;
g_bus_unwatch_name (watch_id);
}
static FbdFeedbackProfileLevel
get_max_level (FbdFeedbackProfileLevel global_level,
FbdFeedbackProfileLevel app_level,
......@@ -254,10 +324,12 @@ fbd_feedback_manager_handle_trigger_feedback (LfbGdbusFeedback *object,
FbdEvent *event;
GSList *feedbacks, *l;
gint event_id;
const gchar *sender;
FbdFeedbackProfileLevel app_level, level, hint_level = FBD_FEEDBACK_PROFILE_LEVEL_FULL;
gboolean found_fb = FALSE;
g_debug ("Event '%s' for '%s'", arg_event, arg_app_id);
sender = g_dbus_method_invocation_get_sender (invocation);
g_debug ("Event '%s' for '%s' from %s", arg_event, arg_app_id, sender);
g_return_val_if_fail (FBD_IS_FEEDBACK_MANAGER (object), FALSE);
g_return_val_if_fail (arg_app_id, FALSE);
......@@ -290,7 +362,7 @@ fbd_feedback_manager_handle_trigger_feedback (LfbGdbusFeedback *object,
event_id = self->next_id++;
event = fbd_event_new (event_id, arg_app_id, arg_event, arg_timeout);
event = fbd_event_new (event_id, arg_app_id, arg_event, arg_timeout, sender);
g_hash_table_insert (self->events, GUINT_TO_POINTER (event_id), event);
app_level = app_get_feedback_level (arg_app_id);
......@@ -318,6 +390,7 @@ fbd_feedback_manager_handle_trigger_feedback (LfbGdbusFeedback *object,
self,
G_CONNECT_SWAPPED);
fbd_event_run_feedbacks (event);
watch_client (self, invocation);
} else {
g_hash_table_remove (self->events, GUINT_TO_POINTER (event_id));
lfb_gdbus_feedback_emit_feedback_ended (LFB_GDBUS_FEEDBACK (self), event_id,
......@@ -365,7 +438,6 @@ find_themefile (void)
g_autoptr (GError) err = NULL;
gchar **xdg_data_dirs = (gchar **) g_get_system_data_dirs ();
g_autofree gchar *config_path = NULL;
g_autofree gchar *compatibles = NULL;
// Try to read the device name
......@@ -381,6 +453,8 @@ find_themefile (void)
// Iterate over $XDG_DATA_DIRS
for (i = 0; i < g_strv_length (xdg_data_dirs); i++) {
g_autofree gchar *config_path = NULL;
config_path = g_strconcat (xdg_data_dirs[i], "feedbackd/themes/", comp, ".json", NULL);
g_debug ("Searching for device specific themefile in %s", config_path);
......@@ -445,10 +519,12 @@ fbd_feedback_manager_dispose (GObject *object)
g_clear_object (&self->settings);
g_clear_object (&self->theme);
g_clear_object (&self->sound);
g_clear_object (&self->vibra);
g_clear_object (&self->leds);
g_clear_object (&self->client);
g_clear_pointer (&self->events, g_hash_table_destroy);
g_clear_pointer (&self->clients, g_hash_table_destroy);
G_OBJECT_CLASS (fbd_feedback_manager_parent_class)->dispose (object);
}
......@@ -486,6 +562,10 @@ fbd_feedback_manager_init (FbdFeedbackManager *self)
g_direct_equal,
NULL,
(GDestroyNotify)g_object_unref);
self->clients = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
free_client_watch);
}
FbdFeedbackManager *
......
......@@ -154,10 +154,3 @@ const char *fbd_feedback_sound_get_effect (FbdFeedbackSound *self)
{
return self->effect;
}
gboolean
fbd_dev_sound_stop(FbdDevSound *self, FbdFeedbackSound *feedback)
{
/* TODO: can we use cancellable to actually end playback? */
return TRUE;
}
......@@ -249,7 +249,7 @@ fbd_feedback_theme_new (const gchar *name)
FbdFeedbackTheme *
fbd_feedback_theme_new_from_data (const gchar *data, GError **error)
{
JsonNode *node = json_from_string(data, error);
g_autoptr (JsonNode) node = json_from_string(data, error);
if (!node)
return NULL;
......
......@@ -102,6 +102,7 @@ set_trigger (const char *sysfs_path, const char *trigger)
* same trigger over and over again in a udev rule.
*/
val = read_sysfs_attr (sysfs_path, LED_TRIGGER_ATTR);
g_strstrip(val);
triggers = g_strsplit (val, " ", 0);
/*
......
......@@ -67,6 +67,7 @@ test_fbd_deps = [
fbd_tests = [
'fbd-feedback-profile',
'fbd-feedback-theme',
'fbd-event',
]
foreach test : fbd_tests
......
......@@ -15,10 +15,11 @@ test_fbd_event (void)
g_autoptr(FbdEvent) event = NULL;
g_autofree gchar *appid = NULL;
g_autofree gchar *name = NULL;
g_autofree gchar *sender = NULL;
FbdEventEndReason reason;
gint timeout;
event = fbd_event_new (1, TEST_APP_ID, TEST_EVENT, 2);
event = fbd_event_new (1, TEST_APP_ID, TEST_EVENT, 2, "sender-id");
g_assert_true (FBD_IS_EVENT (event));
g_object_get (event,
......@@ -26,6 +27,7 @@ test_fbd_event (void)
"event", &name,
"app-id", &appid,
"timeout", &timeout,
"sender", &sender,
NULL);
g_assert_cmpstr (fbd_event_get_event (event),