Merge branch 'custom-sound' into 'main'

Allow to use custom sound files

Closes #81

See merge request Librem5/feedbackd!150
This commit is contained in:
Guido Günther
2025-02-03 13:07:25 +00:00
13 changed files with 247 additions and 61 deletions
+1
View File
@@ -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 . (
+13 -3
View File
@@ -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 <agx@sigxcpu.org>
@@ -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 ();
+5 -1
View File
@@ -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
+6
View File
@@ -1,3 +1,9 @@
feedbackd (0.7.0~dev) UNRELEASED; urgency=medium
* Unreleased
-- Guido Günther <agx@sigxcpu.org> Sun, 26 Jan 2025 14:07:50 +0100
feedbackd (0.6.0) experimental; urgency=medium
[ Guido Günther ]
+2
View File
@@ -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
+77 -7
View File
@@ -1,5 +1,7 @@
/*
* Copyright (C) 2020 Purism SPC
* 2024-2025 The Phosh Developers
*
* SPDX-License-Identifier: LGPL-2.1+
* Author: Guido Günther <agx@sigxcpu.org>
*/
@@ -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;
}
+2
View File
@@ -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);
+1 -1
View File
@@ -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 : [
+26 -12
View File
@@ -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;
}
+72 -34
View File
@@ -1,5 +1,7 @@
/*
* Copyright (C) 2020 Purism SPC
* 2024-2025 The Phosh Developers
*
* SPDX-License-Identifier: GPL-3.0+
* Author: Guido Günther <agx@sigxcpu.org>
*/
@@ -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);
+31 -2
View File
@@ -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;
}
+3 -1
View File
@@ -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
+8
View File
@@ -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 ();
}