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 . ( 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 (); 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 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/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 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/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 : [ 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; } diff --git a/src/fbd-feedback-manager.c b/src/fbd-feedback-manager.c index 44b934c..5b1e34c 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 */ @@ -340,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); @@ -356,9 +361,68 @@ 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; } +/** + * 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, + FbdFeedbackProfileLevel level, + const char *sound_file) +{ + 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); + + 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 */ + 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); + } + + return (fbd_event_get_feedbacks (event) != NULL); +} + static gboolean fbd_feedback_manager_handle_trigger_feedback (LfbGdbusFeedback *object, @@ -370,12 +434,13 @@ 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; 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); @@ -399,7 +464,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"); @@ -415,38 +480,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, level, sound_file); + 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); 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 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 (); }