From 1c6ff93333eead7b3c5a4d8eb932d13abda47e82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sun, 26 Jan 2025 13:54:59 +0100 Subject: [PATCH 01/13] dir-locals: Set display column MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guido Günther --- .dir-locals.el | 1 + 1 file changed, 1 insertion(+) diff --git a/.dir-locals.el b/.dir-locals.el index 476ef0e..4735d45 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -3,6 +3,7 @@ (c-file-style . "linux") (indent-tabs-mode . nil) (c-basic-offset . 2) + (display-fill-column-indicator-column . 100) )) (setq auto-mode-alist (cons '("\\.ui$" . nxml-mode) auto-mode-alist)) (nxml-mode . ( From 9bb2a528c64847530af97c33650914df79fb5d44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sun, 26 Jan 2025 13:55:02 +0100 Subject: [PATCH 02/13] feedback-manager: Split out event feedback preparation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's becoming gradually more complex so move it to a separate function. Signed-off-by: Guido Günther --- src/fbd-feedback-manager.c | 79 +++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 31 deletions(-) diff --git a/src/fbd-feedback-manager.c b/src/fbd-feedback-manager.c index 44b934c..cf50f37 100644 --- a/src/fbd-feedback-manager.c +++ b/src/fbd-feedback-manager.c @@ -1,5 +1,7 @@ /* * Copyright (C) 2020 Purism SPC + * 2024-2025 The Phosh Developers + * * SPDX-License-Identifier: GPL-3.0+ * Author: Guido Günther */ @@ -359,6 +361,48 @@ parse_hints (GVariant *hints, FbdFeedbackProfileLevel *level, gboolean *hint_imp return TRUE; } +/** + * add_event_feedbacks: + * + * Add the suitable feedacks to the event. + * + * Returns: `TRUE` if at least on feedback was added. + */ +static gboolean +add_event_feedbacks (FbdFeedbackManager *self, FbdEvent *event, GSList *feedbacks) +{ + gboolean has_vibra = FALSE; + gboolean found_fb = FALSE; + + if (!feedbacks) + return FALSE; + + for (GSList *l = feedbacks; l; l = l->next) { + FbdFeedbackBase *fb = FBD_FEEDBACK_BASE (l->data); + + if (fbd_feedback_is_available (FBD_FEEDBACK_BASE (fb))) { + /* Handle one haptic feedback at a time. In practice haptics can handle multiple + * patterns but none of the devices supports this atm */ + /* TODO: should respect priorities */ + if (FBD_IS_FEEDBACK_VIBRA (fb)) { + if (fbd_dev_vibra_is_busy (self->vibra)) + continue; + has_vibra = TRUE; + } + + fbd_event_add_feedback (event, fb); + + /* Events take priority over the haptic interface */ + if (has_vibra) + fbd_haptic_manager_end_feedback (self->haptic_manager); + + found_fb = TRUE; + } + } + + return found_fb; +} + static gboolean fbd_feedback_manager_handle_trigger_feedback (LfbGdbusFeedback *object, @@ -370,7 +414,7 @@ fbd_feedback_manager_handle_trigger_feedback (LfbGdbusFeedback *object, { FbdFeedbackManager *self; FbdEvent *event; - GSList *feedbacks, *l; + GSList *feedbacks; guint event_id; const gchar *sender; FbdFeedbackProfileLevel level, hint_level = FBD_FEEDBACK_PROFILE_LEVEL_FULL; @@ -415,38 +459,11 @@ fbd_feedback_manager_handle_trigger_feedback (LfbGdbusFeedback *object, g_hash_table_insert (self->events, GUINT_TO_POINTER (event_id), event); level = fbd_feedback_manager_get_effective_level (self, arg_app_id, hint_level, hint_important); + feedbacks = fbd_feedback_theme_lookup_feedback (self->theme, level, event); - - if (feedbacks) { - gboolean has_vibra = FALSE; - - for (l = feedbacks; l; l = l->next) { - FbdFeedbackBase *fb = FBD_FEEDBACK_BASE (l->data); - - if (fbd_feedback_is_available (FBD_FEEDBACK_BASE (fb))) { - /* Handle one haptic feedback at a time. In practice haptics can handle multiple - * patterns but none of the devices supports this atm */ - /* TODO: should respect priorities */ - if (FBD_IS_FEEDBACK_VIBRA (fb)) { - if (fbd_dev_vibra_is_busy (self->vibra)) - continue; - has_vibra = TRUE; - } - - fbd_event_add_feedback (event, fb); - - /* Events take priority over the haptic interface */ - if (has_vibra) - fbd_haptic_manager_end_feedback (self->haptic_manager); - - found_fb = TRUE; - } - } + found_fb = add_event_feedbacks (self, event, feedbacks); + if (feedbacks) g_slist_free_full (feedbacks, g_object_unref); - } else { - /* No feedbacks found at all */ - found_fb = FALSE; - } lfb_gdbus_feedback_complete_trigger_feedback (object, invocation, event_id); From 9fd06731ae93235f065554f351b9c8834489bee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sun, 26 Jan 2025 13:55:03 +0100 Subject: [PATCH 03/13] feedback-manager: Improve readability of add_event_feedbacks() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Save one indent level and add the feedback at the very end. This makes extending easier. Signed-off-by: Guido Günther --- src/fbd-feedback-manager.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/fbd-feedback-manager.c b/src/fbd-feedback-manager.c index cf50f37..03a9419 100644 --- a/src/fbd-feedback-manager.c +++ b/src/fbd-feedback-manager.c @@ -380,24 +380,24 @@ add_event_feedbacks (FbdFeedbackManager *self, FbdEvent *event, GSList *feedback for (GSList *l = feedbacks; l; l = l->next) { FbdFeedbackBase *fb = FBD_FEEDBACK_BASE (l->data); - if (fbd_feedback_is_available (FBD_FEEDBACK_BASE (fb))) { - /* Handle one haptic feedback at a time. In practice haptics can handle multiple - * patterns but none of the devices supports this atm */ - /* TODO: should respect priorities */ - if (FBD_IS_FEEDBACK_VIBRA (fb)) { - if (fbd_dev_vibra_is_busy (self->vibra)) - continue; - has_vibra = TRUE; - } + if (!fbd_feedback_is_available (FBD_FEEDBACK_BASE (fb))) + continue; - fbd_event_add_feedback (event, fb); - - /* Events take priority over the haptic interface */ - if (has_vibra) - fbd_haptic_manager_end_feedback (self->haptic_manager); - - found_fb = TRUE; + /* Handle one haptic feedback at a time. In practice haptics can handle multiple + * patterns but none of the devices supports this atm */ + /* TODO: should respect priorities */ + if (FBD_IS_FEEDBACK_VIBRA (fb)) { + if (fbd_dev_vibra_is_busy (self->vibra)) + continue; + has_vibra = TRUE; } + + /* Events take priority over the haptic interface */ + if (has_vibra) + fbd_haptic_manager_end_feedback (self->haptic_manager); + + fbd_event_add_feedback (event, fb); + found_fb = TRUE; } return found_fb; From d0f1c3bb2813651a791a25a5ab65235c3bb5278e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sun, 26 Jan 2025 16:11:23 +0100 Subject: [PATCH 04/13] feedback-manager: Drop fb_found boolean MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just check the elements on the event list. This makes it easier to extend as we can't forget to toggle the variable. Signed-off-by: Guido Günther --- src/fbd-feedback-manager.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/fbd-feedback-manager.c b/src/fbd-feedback-manager.c index 03a9419..cfe98ee 100644 --- a/src/fbd-feedback-manager.c +++ b/src/fbd-feedback-manager.c @@ -372,10 +372,6 @@ static gboolean add_event_feedbacks (FbdFeedbackManager *self, FbdEvent *event, GSList *feedbacks) { gboolean has_vibra = FALSE; - gboolean found_fb = FALSE; - - if (!feedbacks) - return FALSE; for (GSList *l = feedbacks; l; l = l->next) { FbdFeedbackBase *fb = FBD_FEEDBACK_BASE (l->data); @@ -397,10 +393,9 @@ add_event_feedbacks (FbdFeedbackManager *self, FbdEvent *event, GSList *feedback fbd_haptic_manager_end_feedback (self->haptic_manager); fbd_event_add_feedback (event, fb); - found_fb = TRUE; } - return found_fb; + return (fbd_event_get_feedbacks (event) != NULL); } From e7df74f5cc94285a7182166eefb4ed5242d36383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sun, 26 Jan 2025 13:55:03 +0100 Subject: [PATCH 05/13] data: Document sound-file hint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guido Günther --- data/org.sigxcpu.Feedback.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/data/org.sigxcpu.Feedback.xml b/data/org.sigxcpu.Feedback.xml index 987ffde..805a677 100644 --- a/data/org.sigxcpu.Feedback.xml +++ b/data/org.sigxcpu.Feedback.xml @@ -26,7 +26,11 @@ Together with the 'profile' hint this allows to trigger feedback for events that would otherwise be disabled. A typical use case is an alarm clock. Note that the feedback daemon (depending on it's configuration) might ignore this flag. - @timeout: When the feedbacks for this event should end latest in seconds. The special values '-1' (just run each feedback once) and '0' (endless loop) are also supported. + - sound-file: A custom sound file to play. This file will be used instead of any + sound event specified in the "full" profile. The sound will only be played if + appropriate for the feedback level of the event. + @timeout: When the feedbacks for this event should end latest in seconds. The special + values '-1' (just run each feedback once) and '0' (endless loop) are also supported. @id: Event id for future reference Give user feedback for an event by triggering feedbacks From 7d89180ddaa0a79c210a4a0e70a63ae087de09d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sun, 26 Jan 2025 13:55:04 +0100 Subject: [PATCH 06/13] libfeedback: Allow to set sound-file hint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guido Günther --- libfeedback/lfb-event.c | 84 +++++++++++++++++++++++++++++++++++++---- libfeedback/lfb-event.h | 2 + tests/test-lfb-event.c | 8 ++++ 3 files changed, 87 insertions(+), 7 deletions(-) diff --git a/libfeedback/lfb-event.c b/libfeedback/lfb-event.c index 62c72f6..21eeda3 100644 --- a/libfeedback/lfb-event.c +++ b/libfeedback/lfb-event.c @@ -1,5 +1,7 @@ /* * Copyright (C) 2020 Purism SPC + * 2024-2025 The Phosh Developers + * * SPDX-License-Identifier: LGPL-2.1+ * Author: Guido Günther */ @@ -81,6 +83,7 @@ enum { PROP_FEEDBACK_PROFILE, PROP_IMPORTANT, PROP_APP_ID, + PROP_SOUND_FILE, PROP_LAST_PROP, }; static GParamSpec *props[PROP_LAST_PROP]; @@ -99,6 +102,7 @@ typedef struct _LfbEvent { gchar *profile; gboolean important; char *app_id; + char *sound_file; guint id; LfbEventState state; @@ -139,10 +143,18 @@ build_hints (LfbEvent *self) GVariantBuilder hints_builder; g_variant_builder_init (&hints_builder, G_VARIANT_TYPE ("a{sv}")); - if (self->profile) - g_variant_builder_add (&hints_builder, "{sv}", "profile", g_variant_new_string (self->profile)); - if (self->important) - g_variant_builder_add (&hints_builder, "{sv}", "important", g_variant_new_boolean (self->important)); + if (self->profile) { + g_variant_builder_add (&hints_builder, "{sv}", "profile", + g_variant_new_string (self->profile)); + } + if (self->important) { + g_variant_builder_add (&hints_builder, "{sv}", "important", + g_variant_new_boolean (self->important)); + } + if (self->sound_file) { + g_variant_builder_add (&hints_builder, "{sv}", "sound-file", + g_variant_new_string (self->sound_file)); + } return g_variant_builder_end (&hints_builder); } @@ -233,6 +245,9 @@ lfb_event_set_property (GObject *object, case PROP_APP_ID: lfb_event_set_app_id (self, g_value_get_string (value)); break; + case PROP_SOUND_FILE: + lfb_event_set_sound_file (self, g_value_get_string (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -264,6 +279,9 @@ lfb_event_get_property (GObject *object, case PROP_APP_ID: g_value_set_string (value, lfb_event_get_app_id (self)); break; + case PROP_SOUND_FILE: + g_value_set_string (value, lfb_event_get_sound_file (self)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -278,6 +296,7 @@ lfb_event_finalize (GObject *object) /* Signal handler is disconnected automatically due to g_signal_connect_object */ self->handler_id = 0; + g_clear_pointer (&self->sound_file, g_free); g_clear_pointer (&self->event, g_free); g_clear_pointer (&self->profile, g_free); g_clear_pointer (&self->app_id, g_free); @@ -340,7 +359,6 @@ lfb_event_class_init (LfbEventClass *klass) LFB_TYPE_EVENT_END_REASON, LFB_EVENT_END_REASON_NATURAL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); - /** * LfbEvent:feedback-profile: * @@ -354,7 +372,6 @@ lfb_event_class_init (LfbEventClass *klass) "Feedback profile to use for this event", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); - /** * LfbEvent:important: * @@ -368,7 +385,6 @@ lfb_event_class_init (LfbEventClass *klass) "Whether to flags this event as important", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); - /** * LfbEvent:app-id: * @@ -382,6 +398,19 @@ lfb_event_class_init (LfbEventClass *klass) "The Application id to use for this event", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); + /** + * LfbEvent:sound-file: + * + * A custom sound-file to play. See [method@LfbEvent.set_sound_file] + * for details. + */ + props[PROP_SOUND_FILE] = + g_param_spec_string ( + "sound-file", + "Sound file", + "Custom sound file to play", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); g_object_class_install_properties (object_class, PROP_LAST_PROP, props); @@ -863,3 +892,44 @@ lfb_event_get_app_id (LfbEvent *self) return self->app_id; } + +/** + * lfb_event_set_sound_file: + * @self: The event + * @sound_file: The sound file + * + * Tells the feedback server to use the given sound file if a sound is + * to be played. It will only be used if sound is suitable for the + * events feedback level. + * + * A value of %NULL (the default) lets the server pick the sound + * based on the event. + */ +void +lfb_event_set_sound_file (LfbEvent *self, const gchar *sound_file) +{ + g_return_if_fail (LFB_IS_EVENT (self)); + + if (!g_strcmp0 (self->sound_file, sound_file)) + return; + + g_free (self->sound_file); + self->sound_file = g_strdup (sound_file); + g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SOUND_FILE]); +} + +/** + * lfb_event_get_sound_file: + * @self: The event + * + * Returns the sound file for this event if set. + * + * Returns:(transfer none): The set sound file for this event or %NULL. + */ +const char * +lfb_event_get_sound_file (LfbEvent *self) +{ + g_return_val_if_fail (LFB_IS_EVENT (self), NULL); + + return self->sound_file; +} diff --git a/libfeedback/lfb-event.h b/libfeedback/lfb-event.h index c4c66cf..3a9a8ea 100644 --- a/libfeedback/lfb-event.h +++ b/libfeedback/lfb-event.h @@ -80,6 +80,8 @@ gboolean lfb_event_get_important (LfbEvent *self); void lfb_event_set_app_id (LfbEvent *self, const char *app_id); const char *lfb_event_get_app_id (LfbEvent *self); const char *lfb_event_get_event (LfbEvent *self); +void lfb_event_set_sound_file (LfbEvent *self, const char *sound_file); +const char *lfb_event_get_sound_file (LfbEvent *self); LfbEventState lfb_event_get_state (LfbEvent *self); LfbEventEndReason lfb_event_get_end_reason (LfbEvent *self); diff --git a/tests/test-lfb-event.c b/tests/test-lfb-event.c index f59237f..743a50c 100644 --- a/tests/test-lfb-event.c +++ b/tests/test-lfb-event.c @@ -15,6 +15,7 @@ test_lfb_event_props (void) g_autofree gchar *evname = NULL; g_autofree gchar *profile = NULL; g_autofree gchar *app_id = NULL; + g_autofree gchar *sound_file = NULL; gboolean important; gint timeout; @@ -29,12 +30,14 @@ test_lfb_event_props (void) "feedback-profile", &profile, "app-id", &app_id, "important", &important, + "sound-file", &sound_file, NULL); g_assert_cmpstr (evname, ==, "window-close"); g_assert_cmpint (timeout, ==, -1); g_assert_null (profile); g_assert_false (important); g_assert_null (app_id); + g_assert_null (sound_file); g_assert_cmpint (lfb_event_get_end_reason (event), ==, LFB_EVENT_END_REASON_NATURAL); g_assert_cmpint (lfb_event_get_state (event), ==, LFB_EVENT_STATE_NONE); @@ -49,6 +52,11 @@ test_lfb_event_props (void) g_assert_cmpstr (app_id, ==, "com.example.foo"); g_assert_cmpstr (lfb_event_get_app_id (event), ==, "com.example.foo"); + g_object_set (event, "sound-file", "/does/not/exist", NULL); + g_object_get (event, "sound-file", &sound_file, NULL); + g_assert_cmpstr (sound_file, ==, "/does/not/exist"); + g_assert_cmpstr (lfb_event_get_sound_file (event), ==, "/does/not/exist"); + lfb_uninit (); } From bff82ef14b8abb289a557dc67dd67253e69ecf1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sun, 26 Jan 2025 13:55:05 +0100 Subject: [PATCH 07/13] fbd-feedback-sound: Allow to set file name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will be preferred over "effect" when set. Signed-off-by: Guido Günther --- src/fbd-feedback-sound.c | 33 +++++++++++++++++++++++++++++++-- src/fbd-feedback-sound.h | 4 +++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/fbd-feedback-sound.c b/src/fbd-feedback-sound.c index e362245..8d26184 100644 --- a/src/fbd-feedback-sound.c +++ b/src/fbd-feedback-sound.c @@ -23,6 +23,7 @@ enum { PROP_0, PROP_EFFECT, + PROP_FILE_NAME, PROP_LAST_PROP, }; static GParamSpec *props[PROP_LAST_PROP]; @@ -30,7 +31,8 @@ static GParamSpec *props[PROP_LAST_PROP]; typedef struct _FbdFeedbackSound { FbdFeedbackBase parent; - gchar *effect; + char *effect; + char *file_name; } FbdFeedbackSound; G_DEFINE_TYPE (FbdFeedbackSound, fbd_feedback_sound, FBD_TYPE_FEEDBACK_BASE); @@ -86,6 +88,9 @@ fbd_feedback_sound_set_property (GObject *object, case PROP_EFFECT: self->effect = g_value_dup_string (value); break; + case PROP_FILE_NAME: + self->file_name = g_value_dup_string (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -104,6 +109,9 @@ fbd_feedback_sound_get_property (GObject *object, case PROP_EFFECT: g_value_set_string (value, fbd_feedback_sound_get_effect (self)); break; + case PROP_FILE_NAME: + g_value_set_string (value, fbd_feedback_sound_get_file_name (self)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -116,6 +124,7 @@ fbd_feedback_sound_finalize (GObject *object) FbdFeedbackSound *self = FBD_FEEDBACK_SOUND (object); g_clear_pointer (&self->effect, g_free); + g_clear_pointer (&self->file_name, g_free); G_OBJECT_CLASS (fbd_feedback_sound_parent_class)->finalize (object); } @@ -142,6 +151,11 @@ fbd_feedback_sound_class_init (FbdFeedbackSoundClass *klass) "", G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + props[PROP_FILE_NAME] = + g_param_spec_string ("file-name", "", "", + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, PROP_LAST_PROP, props); } @@ -150,7 +164,22 @@ fbd_feedback_sound_init (FbdFeedbackSound *self) { } -const char *fbd_feedback_sound_get_effect (FbdFeedbackSound *self) + +FbdFeedbackSound * +fbd_feedback_sound_new_from_file_name (const char *filename) +{ + return g_object_new (FBD_TYPE_FEEDBACK_SOUND, "file-name", filename, NULL); +} + + +const char * +fbd_feedback_sound_get_effect (FbdFeedbackSound *self) { return self->effect; } + +const char * +fbd_feedback_sound_get_file_name (FbdFeedbackSound *self) +{ + return self->file_name; +} diff --git a/src/fbd-feedback-sound.h b/src/fbd-feedback-sound.h index 1df9c2e..c713c05 100644 --- a/src/fbd-feedback-sound.h +++ b/src/fbd-feedback-sound.h @@ -13,6 +13,8 @@ G_BEGIN_DECLS G_DECLARE_FINAL_TYPE (FbdFeedbackSound, fbd_feedback_sound, FBD, FEEDBACK_SOUND, FbdFeedbackBase); -const char *fbd_feedback_sound_get_effect (FbdFeedbackSound *self); +FbdFeedbackSound *fbd_feedback_sound_new_from_file_name (const char *filename); +const char *fbd_feedback_sound_get_effect (FbdFeedbackSound *self); +const char *fbd_feedback_sound_get_file_name (FbdFeedbackSound *self); G_END_DECLS From e105a21a1d90f9df65613788dc55d316aee71e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sun, 26 Jan 2025 13:55:05 +0100 Subject: [PATCH 08/13] fbd-dev-sound: Play custom sound file if specified MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guido Günther --- src/fbd-dev-sound.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/fbd-dev-sound.c b/src/fbd-dev-sound.c index f7861d8..98ca038 100644 --- a/src/fbd-dev-sound.c +++ b/src/fbd-dev-sound.c @@ -176,14 +176,16 @@ on_sound_play_finished_callback (GSoundContext *ctx, g_autoptr (GError) err = NULL; if (!gsound_context_play_full_finish (ctx, res, &err)) { + const char *sound = fbd_feedback_sound_get_file_name (data->feedback); + if (!sound) + sound = fbd_feedback_sound_get_effect (data->feedback); + if (err->domain == GSOUND_ERROR && err->code == GSOUND_ERROR_NOTFOUND) { - g_debug ("Failed to find sound '%s'", fbd_feedback_sound_get_effect (data->feedback)); + g_debug ("Failed to find sound '%s'", sound); } 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)); + g_debug ("Sound '%s' cancelled", sound); } else { - g_warning ("Failed to play sound '%s': %s", - fbd_feedback_sound_get_effect (data->feedback), - err->message); + g_warning ("Failed to play sound '%s': %s", sound, err->message); } } @@ -200,6 +202,7 @@ gboolean fbd_dev_sound_play (FbdDevSound *self, FbdFeedbackSound *feedback, FbdDevSoundPlayedCallback callback) { FbdAsyncData *data; + const char *filename; g_return_val_if_fail (FBD_IS_DEV_SOUND (self), FALSE); g_return_val_if_fail (GSOUND_IS_CONTEXT (self->ctx), FALSE); @@ -209,13 +212,24 @@ fbd_dev_sound_play (FbdDevSound *self, FbdFeedbackSound *feedback, FbdDevSoundPl if (!g_hash_table_insert (self->playbacks, feedback, data)) g_warning ("Feedback %p already present", feedback); - gsound_context_play_full (self->ctx, data->cancel, - (GAsyncReadyCallback) on_sound_play_finished_callback, - data, - GSOUND_ATTR_EVENT_ID, fbd_feedback_sound_get_effect (feedback), - GSOUND_ATTR_EVENT_DESCRIPTION, "Feedbackd sound feedback", - GSOUND_ATTR_MEDIA_ROLE, "event", - NULL); + filename = fbd_feedback_sound_get_file_name (feedback); + if (filename) { + gsound_context_play_full (self->ctx, data->cancel, + (GAsyncReadyCallback) on_sound_play_finished_callback, + data, + GSOUND_ATTR_MEDIA_FILENAME, filename, + GSOUND_ATTR_EVENT_DESCRIPTION, "Feedbackd custom sound feedback", + GSOUND_ATTR_MEDIA_ROLE, "event", + NULL); + } else { + gsound_context_play_full (self->ctx, data->cancel, + (GAsyncReadyCallback) on_sound_play_finished_callback, + data, + GSOUND_ATTR_EVENT_ID, fbd_feedback_sound_get_effect (feedback), + GSOUND_ATTR_EVENT_DESCRIPTION, "Feedbackd sound feedback", + GSOUND_ATTR_MEDIA_ROLE, "event", + NULL); + } return TRUE; } From 24ed50226ef7cbe0cffd8b0a4771d95e05b7af14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sun, 26 Jan 2025 13:55:06 +0100 Subject: [PATCH 09/13] feedback-manager: Parse sound file hint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guido Günther --- src/fbd-feedback-manager.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/fbd-feedback-manager.c b/src/fbd-feedback-manager.c index cfe98ee..f390955 100644 --- a/src/fbd-feedback-manager.c +++ b/src/fbd-feedback-manager.c @@ -342,9 +342,12 @@ get_max_level (FbdFeedbackProfileLevel global_level, } static gboolean -parse_hints (GVariant *hints, FbdFeedbackProfileLevel *level, gboolean *hint_important) +parse_hints (GVariant *hints, + FbdFeedbackProfileLevel *level, + gboolean *hint_important, + char **hint_sound_file) { - const gchar *profile; + const gchar *profile, *sound_file; gboolean found, important; g_auto (GVariantDict) dict = G_VARIANT_DICT_INIT (NULL); @@ -358,6 +361,10 @@ parse_hints (GVariant *hints, FbdFeedbackProfileLevel *level, gboolean *hint_imp if (hint_important && found) *hint_important = important; + found = g_variant_dict_lookup (&dict, "sound-file", "&s", &sound_file); + if (hint_sound_file && found) + *hint_sound_file = g_strdup (sound_file); + return TRUE; } @@ -415,6 +422,7 @@ fbd_feedback_manager_handle_trigger_feedback (LfbGdbusFeedback *object, FbdFeedbackProfileLevel level, hint_level = FBD_FEEDBACK_PROFILE_LEVEL_FULL; gboolean found_fb = FALSE; gboolean hint_important = FALSE; + g_autofree char *sound_file = NULL; sender = g_dbus_method_invocation_get_sender (invocation); g_debug ("Event '%s' for '%s' from %s", arg_event, arg_app_id, sender); @@ -438,7 +446,7 @@ fbd_feedback_manager_handle_trigger_feedback (LfbGdbusFeedback *object, return TRUE; } - if (!parse_hints (arg_hints, &hint_level, &hint_important)) { + if (!parse_hints (arg_hints, &hint_level, &hint_important, &sound_file)) { g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Invalid hints"); From c9c69304e6d475d86ad4f474d2dbf810693c7123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sun, 26 Jan 2025 13:55:07 +0100 Subject: [PATCH 10/13] feedback-manager: Add sound feedback for custom sound file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a custom sound is provided for the event, use that instead of the one from the theme. We always add the sound event, even when the theme doesn't have sound feedback for that event honoring the users choice. Closes: https://source.puri.sm/Librem5/feedbackd/-/merge_requests/150 Signed-off-by: Guido Günther --- src/fbd-feedback-manager.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/fbd-feedback-manager.c b/src/fbd-feedback-manager.c index f390955..5b1e34c 100644 --- a/src/fbd-feedback-manager.c +++ b/src/fbd-feedback-manager.c @@ -376,9 +376,24 @@ parse_hints (GVariant *hints, * Returns: `TRUE` if at least on feedback was added. */ static gboolean -add_event_feedbacks (FbdFeedbackManager *self, FbdEvent *event, GSList *feedbacks) +add_event_feedbacks (FbdFeedbackManager *self, + FbdEvent *event, + GSList *feedbacks, + FbdFeedbackProfileLevel level, + const char *sound_file) { - gboolean has_vibra = FALSE; + gboolean has_vibra = FALSE, has_sound = FALSE; + + /* Synthesize sound event for custom sound */ + if (sound_file && level >= FBD_FEEDBACK_PROFILE_LEVEL_FULL) { + g_autoptr (FbdFeedbackSound) sound = NULL; + + g_debug ("Using custom sound event '%s'", sound_file); + sound = fbd_feedback_sound_new_from_file_name (sound_file); + + fbd_event_add_feedback (event, FBD_FEEDBACK_BASE (sound)); + has_sound = TRUE; + } for (GSList *l = feedbacks; l; l = l->next) { FbdFeedbackBase *fb = FBD_FEEDBACK_BASE (l->data); @@ -386,6 +401,9 @@ add_event_feedbacks (FbdFeedbackManager *self, FbdEvent *event, GSList *feedback if (!fbd_feedback_is_available (FBD_FEEDBACK_BASE (fb))) continue; + if (FBD_IS_FEEDBACK_SOUND (fb) && has_sound) + continue; + /* Handle one haptic feedback at a time. In practice haptics can handle multiple * patterns but none of the devices supports this atm */ /* TODO: should respect priorities */ @@ -464,7 +482,7 @@ fbd_feedback_manager_handle_trigger_feedback (LfbGdbusFeedback *object, level = fbd_feedback_manager_get_effective_level (self, arg_app_id, hint_level, hint_important); feedbacks = fbd_feedback_theme_lookup_feedback (self->theme, level, event); - found_fb = add_event_feedbacks (self, event, feedbacks); + found_fb = add_event_feedbacks (self, event, feedbacks, level, sound_file); if (feedbacks) g_slist_free_full (feedbacks, g_object_unref); From 832d2c3ce5256859471179833f85562f94e9c2e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sun, 26 Jan 2025 13:55:07 +0100 Subject: [PATCH 11/13] cli: Allow to provide custom sound file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guido Günther --- cli/fbcli.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/cli/fbcli.c b/cli/fbcli.c index c412ebf..6fab410 100644 --- a/cli/fbcli.c +++ b/cli/fbcli.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2020 Purism SPC - * 2023-2024 The Phosh Developers + * 2023-2025 The Phosh Developers * * SPDX-License-Identifier: GPL-3.0+ * Author: Guido Günther @@ -60,7 +60,11 @@ on_user_input (GIOChannel *channel, GIOCondition cond, LfbEvent *event) } static gboolean -trigger_event (const char *name, const gchar *profile, gboolean important, gint timeout) +trigger_event (const char *name, + const char *profile, + gboolean important, + gint timeout, + const char *sound_file) { g_autoptr (GError) err = NULL; g_autoptr (LfbEvent) event = NULL; @@ -79,6 +83,9 @@ trigger_event (const char *name, const gchar *profile, gboolean important, gint if (important) lfb_event_set_important (event, TRUE); + if (sound_file) + lfb_event_set_sound_file(event, sound_file); + g_signal_connect (event, "feedback-ended", (GCallback)on_feedback_ended, &success); if (!lfb_event_trigger_feedback (event, &err)) { g_print ("Failed to report event: %s\n", err->message); @@ -140,6 +147,7 @@ main (int argc, char *argv[0]) g_autoptr (GError) err = NULL; g_autofree char *profile = NULL; g_autofree char *app_id = NULL; + g_autofree char *sound_file = NULL; const char *name = NULL; gboolean success, important = FALSE; int watch = 30; @@ -157,6 +165,8 @@ main (int argc, char *argv[0]) "How long to watch for feedback longest", NULL}, {"app-id", 'A', 0, G_OPTION_ARG_STRING, &app_id, "Override used application id"}, + {"sound-file", 'S', 0, G_OPTION_ARG_STRING, &sound_file, + "Override the sound effect used by a file"}, { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL } }; @@ -183,7 +193,7 @@ main (int argc, char *argv[0]) name = g_strdup (DEFAULT_EVENT); g_timeout_add_seconds (watch, (GSourceFunc)on_watch_expired, NULL); - success = trigger_event (name, profile, important, timeout); + success = trigger_event (name, profile, important, timeout, sound_file); } lfb_uninit (); From 27ff654f9df24f3fb490007f2b1ce8ebb60dc8ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sun, 26 Jan 2025 14:07:29 +0100 Subject: [PATCH 12/13] build: Bump dev versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows us to bump symbols and have proper dependencies in consuming projects Signed-off-by: Guido Günther --- debian/changelog | 6 ++++++ meson.build | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 95826f0..eddada9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +feedbackd (0.7.0~dev) UNRELEASED; urgency=medium + + * Unreleased + + -- Guido Günther Sun, 26 Jan 2025 14:07:50 +0100 + feedbackd (0.6.0) experimental; urgency=medium [ Guido Günther ] diff --git a/meson.build b/meson.build index 287baf4..314645e 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('feedbackd', 'c', - version : '0.6.0', + version : '0.7.0-dev', license : 'LGPLv3+', meson_version : '>= 1.0.0', default_options : [ From 9969faef0d51fa4ea452c9c82d2d0c7ab840ea89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Sun, 26 Jan 2025 14:03:00 +0100 Subject: [PATCH 13/13] packaging: Add symbols from 0.7.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Guido Günther --- debian/libfeedback-0.0-0.symbols | 2 ++ 1 file changed, 2 insertions(+) diff --git a/debian/libfeedback-0.0-0.symbols b/debian/libfeedback-0.0-0.symbols index c0976e9..2f17b0b 100644 --- a/debian/libfeedback-0.0-0.symbols +++ b/debian/libfeedback-0.0-0.symbols @@ -10,6 +10,7 @@ libfeedback-0.0.so.0 libfeedback-0.0-0 #MINVER# lfb_event_get_event@LIBFEEDBACK_0_0_0 0.1.1 lfb_event_get_feedback_profile@LIBFEEDBACK_0_0_0 0.1.1 lfb_event_get_important@LIBFEEDBACK_0_0_0 0.2.1 + lfb_event_get_sound_file@LIBFEEDBACK_0_0_0 0.7.0~ lfb_event_get_state@LIBFEEDBACK_0_0_0 0.1.1 lfb_event_get_timeout@LIBFEEDBACK_0_0_0 0.1.1 lfb_event_get_type@LIBFEEDBACK_0_0_0 0.1.1 @@ -17,6 +18,7 @@ libfeedback-0.0.so.0 libfeedback-0.0-0 #MINVER# lfb_event_set_app_id@LIBFEEDBACK_0_0_0 0.2.0 lfb_event_set_feedback_profile@LIBFEEDBACK_0_0_0 0.1.1 lfb_event_set_important@LIBFEEDBACK_0_0_0 0.2.1 + lfb_event_set_sound_file@LIBFEEDBACK_0_0_0 0.7.0~ lfb_event_set_timeout@LIBFEEDBACK_0_0_0 0.1.1 lfb_event_state_get_type@LIBFEEDBACK_0_0_0 0.1.1 lfb_event_trigger_feedback@LIBFEEDBACK_0_0_0 0.1.1