Merge branch 'vibra-pattern' into 'main'
Add org.sigxcup.org.Feedback.Haptic interface Closes #80 See merge request Librem5/feedbackd!147
This commit is contained in:
@@ -277,11 +277,32 @@ export GSETTINGS_SCHEMA_DIR=_build/data/
|
||||
gsettings set org.sigxcpu.feedbackd.application:/org/sigxcpu/feedbackd/application/sm-puri-phosh/ profile quiet
|
||||
```
|
||||
|
||||
## Haptic API
|
||||
|
||||
In order to give applications like browsers and games more control
|
||||
over the haptic motor `Feebackd` implements an interface that allows
|
||||
to set vibra patterns. The vibration pattern is given as a sequence of
|
||||
rumble magnitude and duration pairs like:
|
||||
|
||||
```
|
||||
busctl call --user org.sigxcpu.Feedback /org/sigxcpu/Feedback org.sigxcpu.Feedback.Haptic Vibrate 'sa(du)' org.foo.app 3 1.0 200 0.0 50 0.5 300
|
||||
```
|
||||
|
||||
Vibration can be ended by submitting an empty array:
|
||||
|
||||
```sh
|
||||
busctl call --user org.sigxcpu.Feedback /org/sigxcpu/Feedback org.sigxcpu.Feedback.Haptic Vibrate 'sa(du)' org.foo.app 0
|
||||
```
|
||||
|
||||
The API is exported as a separate interface `org.sigxcpu.Feedback.Haptic` which is only available when
|
||||
a haptic device is found.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [Libfeedback API](https://honk.sigxcpu.org/projects/feedbackd/doc/)
|
||||
- [Event naming spec draft](./doc/Event-naming-spec-0.0.0.md)
|
||||
- [Feedback-theme-spec draft](./doc/Feedback-theme-spec-0.0.0.md)
|
||||
- [W3's vibration API draft](https://www.w3.org/TR/vibration/)
|
||||
|
||||
[debian/control]: ./debian/control#L5
|
||||
[1]: https://source.puri.sm/Librem5/feedbackd-device-themes
|
||||
|
||||
+4
-1
@@ -4,7 +4,10 @@ namespace = 'LfbGdbus'
|
||||
|
||||
generated_dbus_sources = []
|
||||
|
||||
dbus_interfaces = [ 'org.sigxcpu.Feedback.xml' ]
|
||||
dbus_interfaces = [
|
||||
'org.sigxcpu.Feedback.xml',
|
||||
'org.sigxcpu.Feedback.Haptic.xml',
|
||||
]
|
||||
|
||||
generated_dbus_sources += gnome.gdbus_codegen('lfb-gdbus',
|
||||
sources : dbus_interfaces,
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<node>
|
||||
<!-- org.sigxcpu.Feedback.Haptic
|
||||
@short_description: Interface to make a device vibrate
|
||||
|
||||
This D-Bus interface is used to make a device's haptic motor
|
||||
vibrate. This is can be useful e.g. for games.
|
||||
|
||||
To provider user feedback the event based interface should be
|
||||
preferred.
|
||||
-->
|
||||
<interface name="org.sigxcpu.Feedback.Haptic">
|
||||
<!--
|
||||
Vibrate:
|
||||
@app_id: The application id usually in "reverse DNS" format
|
||||
@pattern: The vibration pattern.
|
||||
@success: Whether vibration was triggered
|
||||
|
||||
Triggers the given vibration pattern on the haptic device. The
|
||||
pattern is a sequence of relative amplitude and duration pairs.
|
||||
The amplitude must be between 0.0 and 1.0.
|
||||
-->
|
||||
<method name="Vibrate">
|
||||
<arg direction="in" name="app_id" type="s"/>
|
||||
<arg direction="in" name="pattern" type="a(du)"/>
|
||||
<arg direction="out" name="success" type="b"/>
|
||||
</method>
|
||||
|
||||
</interface>
|
||||
|
||||
</node>
|
||||
+33
-5
@@ -219,6 +219,7 @@ fbd_dev_vibra_class_init (FbdDevVibraClass *klass)
|
||||
static void
|
||||
fbd_dev_vibra_init (FbdDevVibra *self)
|
||||
{
|
||||
self->id = -1;
|
||||
}
|
||||
|
||||
FbdDevVibra *
|
||||
@@ -232,7 +233,7 @@ fbd_dev_vibra_new (GUdevDevice *device, GError **error)
|
||||
}
|
||||
|
||||
gboolean
|
||||
fbd_dev_vibra_rumble (FbdDevVibra *self, guint duration, gboolean upload)
|
||||
fbd_dev_vibra_rumble (FbdDevVibra *self, double magnitude, guint duration, gboolean upload)
|
||||
{
|
||||
struct input_event event = { 0 };
|
||||
struct ff_effect effect = { 0 };
|
||||
@@ -242,7 +243,7 @@ fbd_dev_vibra_rumble (FbdDevVibra *self, guint duration, gboolean upload)
|
||||
memset(&effect, 0, sizeof(effect));
|
||||
effect.type = FF_RUMBLE;
|
||||
effect.id = -1;
|
||||
effect.u.rumble.strong_magnitude = 0x8000;
|
||||
effect.u.rumble.strong_magnitude = (0x8000 * magnitude);
|
||||
effect.u.rumble.weak_magnitude = 0;
|
||||
effect.replay.length = duration;
|
||||
effect.replay.delay = 0;
|
||||
@@ -272,7 +273,7 @@ fbd_dev_vibra_rumble (FbdDevVibra *self, guint duration, gboolean upload)
|
||||
/* TODO: fall back to multiple rumbles when sine not supported */
|
||||
gboolean
|
||||
fbd_dev_vibra_periodic (FbdDevVibra *self, guint duration, guint magnitude,
|
||||
guint fade_in_level, guint fade_in_time)
|
||||
guint fade_in_level, guint fade_in_time)
|
||||
{
|
||||
struct input_event event;
|
||||
struct ff_effect effect = { 0 };
|
||||
@@ -330,22 +331,30 @@ fbd_dev_vibra_remove_effect (FbdDevVibra *self)
|
||||
{
|
||||
g_return_val_if_fail (FBD_IS_DEV_VIBRA (self), FALSE);
|
||||
|
||||
if (self->id == -1)
|
||||
return TRUE;
|
||||
|
||||
g_debug("Erasing vibra effect (%d)", self->fd);
|
||||
if (ioctl(self->fd, EVIOCRMFF, self->id) == -1) {
|
||||
g_warning ("Failed to erase vibra effect with id %d: %s", self->id, strerror(errno));
|
||||
self->id = -1;
|
||||
return FALSE;
|
||||
}
|
||||
self->id = -1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
fbd_dev_vibra_stop(FbdDevVibra *self)
|
||||
fbd_dev_vibra_stop (FbdDevVibra *self)
|
||||
{
|
||||
struct input_event stop = { 0 };
|
||||
|
||||
g_return_val_if_fail (FBD_IS_DEV_VIBRA (self), FALSE);
|
||||
|
||||
if (self->id == -1)
|
||||
return TRUE;
|
||||
|
||||
stop.type = EV_FF;
|
||||
stop.code = self->id;
|
||||
stop.value = 0;
|
||||
@@ -359,9 +368,28 @@ fbd_dev_vibra_stop(FbdDevVibra *self)
|
||||
}
|
||||
|
||||
GUdevDevice *
|
||||
fbd_dev_vibra_get_device(FbdDevVibra *self)
|
||||
fbd_dev_vibra_get_device (FbdDevVibra *self)
|
||||
{
|
||||
g_return_val_if_fail (FBD_IS_DEV_VIBRA (self), FALSE);
|
||||
|
||||
return self->device;
|
||||
}
|
||||
|
||||
/**
|
||||
* fbd_dev_vibra_is_busy:
|
||||
* @self: The vibra device
|
||||
*
|
||||
* Check whether the device is currently in used
|
||||
*
|
||||
* Returns: `TRUE` when the device is in use, otherwise `FALSE`
|
||||
*/
|
||||
gboolean
|
||||
fbd_dev_vibra_is_busy (FbdDevVibra *self)
|
||||
{
|
||||
if (self == NULL)
|
||||
return FALSE;
|
||||
|
||||
g_return_val_if_fail (FBD_IS_DEV_VIBRA (self), TRUE);
|
||||
|
||||
return self->id != -1;
|
||||
}
|
||||
|
||||
+5
-2
@@ -15,12 +15,15 @@ G_BEGIN_DECLS
|
||||
G_DECLARE_FINAL_TYPE (FbdDevVibra, fbd_dev_vibra, FBD, DEV_VIBRA, GObject);
|
||||
|
||||
FbdDevVibra *fbd_dev_vibra_new (GUdevDevice *device, GError **error);
|
||||
gboolean fbd_dev_vibra_rumble (FbdDevVibra *device, guint duration, gboolean upload);
|
||||
gboolean fbd_dev_vibra_rumble (FbdDevVibra *device,
|
||||
double magnitude,
|
||||
guint duration,
|
||||
gboolean upload);
|
||||
gboolean fbd_dev_vibra_periodic (FbdDevVibra *self, guint duration, guint magnitude,
|
||||
guint fade_in_level, guint fade_in_time);
|
||||
gboolean fbd_dev_vibra_stop (FbdDevVibra *self);
|
||||
gboolean fbd_dev_vibra_remove_effect (FbdDevVibra *self);
|
||||
GUdevDevice *fbd_dev_vibra_get_device(FbdDevVibra *self);
|
||||
|
||||
gboolean fbd_dev_vibra_is_busy (FbdDevVibra *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
+75
-10
@@ -12,8 +12,10 @@
|
||||
#include "fbd-dev-leds.h"
|
||||
#include "fbd-event.h"
|
||||
#include "fbd-feedback-vibra.h"
|
||||
#include "fbd-feedback-vibra-pattern.h"
|
||||
#include "fbd-feedback-manager.h"
|
||||
#include "fbd-feedback-theme.h"
|
||||
#include "fbd-haptic-manager.h"
|
||||
#include "fbd-theme-expander.h"
|
||||
|
||||
#include <gmobile.h>
|
||||
@@ -40,6 +42,9 @@
|
||||
* based on the incoming events.
|
||||
*/
|
||||
|
||||
FbdDebugFlags fbd_debug_flags;
|
||||
|
||||
|
||||
typedef struct _FbdFeedbackManager {
|
||||
LfbGdbusFeedbackSkeleton parent;
|
||||
|
||||
@@ -54,6 +59,9 @@ typedef struct _FbdFeedbackManager {
|
||||
/* Key: DBus name, value: watch_id */
|
||||
GHashTable *clients;
|
||||
|
||||
/* org.sigxcpu.Feedbackd.Haptic */
|
||||
FbdHapticManager *haptic_manager;
|
||||
|
||||
/* Hardware interaction */
|
||||
GUdevClient *client;
|
||||
FbdDevVibra *vibra;
|
||||
@@ -351,6 +359,7 @@ parse_hints (GVariant *hints, FbdFeedbackProfileLevel *level, gboolean *hint_imp
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
fbd_feedback_manager_handle_trigger_feedback (LfbGdbusFeedback *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
@@ -364,9 +373,9 @@ fbd_feedback_manager_handle_trigger_feedback (LfbGdbusFeedback *object,
|
||||
GSList *feedbacks, *l;
|
||||
guint event_id;
|
||||
const gchar *sender;
|
||||
FbdFeedbackProfileLevel app_level, level, hint_level = FBD_FEEDBACK_PROFILE_LEVEL_FULL;
|
||||
FbdFeedbackProfileLevel level, hint_level = FBD_FEEDBACK_PROFILE_LEVEL_FULL;
|
||||
gboolean found_fb = FALSE;
|
||||
gboolean hint_important = FALSE, can_important;
|
||||
gboolean hint_important = FALSE;
|
||||
|
||||
sender = g_dbus_method_invocation_get_sender (invocation);
|
||||
g_debug ("Event '%s' for '%s' from %s", arg_event, arg_app_id, sender);
|
||||
@@ -405,21 +414,31 @@ fbd_feedback_manager_handle_trigger_feedback (LfbGdbusFeedback *object,
|
||||
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);
|
||||
can_important = app_is_important (self, arg_app_id);
|
||||
|
||||
if (hint_important && can_important)
|
||||
level = hint_level;
|
||||
else
|
||||
level = get_max_level (self->level, app_level, hint_level);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -495,6 +514,9 @@ fbd_feedback_manager_constructed (GObject *object)
|
||||
g_signal_connect_swapped (self->settings, "changed::" FEEDBACKD_KEY_ALLOW_IMPORTANT,
|
||||
G_CALLBACK (on_feedbackd_allow_important_changed), self);
|
||||
on_feedbackd_allow_important_changed (self, FEEDBACKD_KEY_ALLOW_IMPORTANT, self->settings);
|
||||
|
||||
if (self->vibra || fbd_debug_flags & FBD_DEBUG_FLAG_FORCE_HAPTIC)
|
||||
self->haptic_manager = fbd_haptic_manager_new ();
|
||||
}
|
||||
|
||||
|
||||
@@ -503,6 +525,8 @@ fbd_feedback_manager_dispose (GObject *object)
|
||||
{
|
||||
FbdFeedbackManager *self = FBD_FEEDBACK_MANAGER (object);
|
||||
|
||||
g_clear_object (&self->haptic_manager);
|
||||
|
||||
g_clear_object (&self->settings);
|
||||
g_clear_object (&self->theme);
|
||||
g_clear_object (&self->sound);
|
||||
@@ -662,3 +686,44 @@ fbd_feedback_manager_set_profile (FbdFeedbackManager *self, const gchar *profile
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
FbdHapticManager *
|
||||
fbd_feedback_manager_get_haptic_manager (FbdFeedbackManager *self)
|
||||
{
|
||||
g_assert (FBD_IS_FEEDBACK_MANAGER (self));
|
||||
|
||||
return self->haptic_manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* fbd_feedback_manager_get_effective_level:
|
||||
* @self: The feedback manager
|
||||
* @app_id: The app-id of the app that triggered the feedback
|
||||
* @want_level: The wanted level
|
||||
* @important: Whether the important hint is set
|
||||
*
|
||||
* Calculates the effective feedback level taking the hints sent for the event
|
||||
* and the system configuration into account
|
||||
*
|
||||
* Returns: The effective feedback level
|
||||
*/
|
||||
FbdFeedbackProfileLevel
|
||||
fbd_feedback_manager_get_effective_level (FbdFeedbackManager *self,
|
||||
const char *app_id,
|
||||
FbdFeedbackProfileLevel want_level,
|
||||
gboolean important)
|
||||
{
|
||||
gboolean can_important;
|
||||
FbdFeedbackProfileLevel app_level, level;
|
||||
|
||||
app_level = app_get_feedback_level (app_id);
|
||||
can_important = app_is_important (self, app_id);
|
||||
|
||||
if (important && can_important)
|
||||
level = want_level;
|
||||
else
|
||||
level = get_max_level (self->level, app_level, want_level);
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
@@ -8,21 +8,34 @@
|
||||
#include "fbd-dev-vibra.h"
|
||||
#include "fbd-dev-leds.h"
|
||||
#include "fbd-dev-sound.h"
|
||||
#include "fbd-feedback-profile.h"
|
||||
#include "fbd-haptic-manager.h"
|
||||
|
||||
#include "lfb-gdbus.h"
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
FBD_DEBUG_FLAG_FORCE_HAPTIC = 1 << 0,
|
||||
} FbdDebugFlags;
|
||||
|
||||
extern FbdDebugFlags fbd_debug_flags;
|
||||
|
||||
#define FBD_TYPE_FEEDBACK_MANAGER (fbd_feedback_manager_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FbdFeedbackManager, fbd_feedback_manager, FBD, FEEDBACK_MANAGER, LfbGdbusFeedbackSkeleton);
|
||||
|
||||
FbdFeedbackManager *fbd_feedback_manager_get_default (void);
|
||||
FbdHapticManager *fbd_feedback_manager_get_haptic_manager (FbdFeedbackManager *self);
|
||||
FbdDevVibra *fbd_feedback_manager_get_dev_vibra (FbdFeedbackManager *self);
|
||||
FbdDevSound *fbd_feedback_manager_get_dev_sound (FbdFeedbackManager *self);
|
||||
FbdDevLeds *fbd_feedback_manager_get_dev_leds (FbdFeedbackManager *self);
|
||||
void fbd_feedback_manager_load_theme (FbdFeedbackManager *self);
|
||||
gboolean fbd_feedback_manager_set_profile (FbdFeedbackManager *self, const gchar *profile);
|
||||
FbdFeedbackProfileLevel fbd_feedback_manager_get_effective_level (FbdFeedbackManager *self,
|
||||
const char *app_id,
|
||||
FbdFeedbackProfileLevel want_level,
|
||||
gboolean important);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Phosh Developers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
* Author: Guido Günther <agx@sigxcpu.org>
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "fbd-feedback-vibra-pattern"
|
||||
|
||||
#include "fbd-enums.h"
|
||||
#include "fbd-feedback-vibra-pattern.h"
|
||||
#include "fbd-feedback-vibra-priv.h"
|
||||
#include "fbd-feedback-manager.h"
|
||||
|
||||
/**
|
||||
* FbdFeedbackVibraPattern:
|
||||
*
|
||||
* Describes a pattern feedback via a haptic motor
|
||||
*
|
||||
* The #FbdVibraVibraPattern describes the properties of a haptic feedback
|
||||
* event. It knows nothing about the hardware itself but calls
|
||||
* #FbdDevVibra for that.
|
||||
*/
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_MAGNITUDES,
|
||||
PROP_DURATIONS,
|
||||
PROP_LAST_PROP,
|
||||
};
|
||||
static GParamSpec *props[PROP_LAST_PROP];
|
||||
|
||||
typedef struct _FbdFeedbackVibraPattern {
|
||||
FbdFeedbackVibra parent;
|
||||
|
||||
GArray *magnitudes;
|
||||
GArray *durations;
|
||||
int pos;
|
||||
|
||||
guint timer_id;
|
||||
} FbdFeedbackVibraPattern;
|
||||
|
||||
G_DEFINE_TYPE (FbdFeedbackVibraPattern, fbd_feedback_vibra_pattern, FBD_TYPE_FEEDBACK_VIBRA);
|
||||
|
||||
|
||||
static void
|
||||
set_magnitudes (FbdFeedbackVibraPattern *self, GArray *magnitudes)
|
||||
{
|
||||
g_clear_pointer (&self->magnitudes, g_array_unref);
|
||||
self->magnitudes = g_array_ref (magnitudes);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
set_durations (FbdFeedbackVibraPattern *self, GArray *durations)
|
||||
{
|
||||
guint total_duration = 0;
|
||||
|
||||
g_clear_pointer (&self->durations, g_array_unref);
|
||||
self->durations = g_array_ref (durations);
|
||||
|
||||
for (int i = 0; i < self->durations->len; i++) {
|
||||
guint *duration = &g_array_index (self->durations, guint, i);
|
||||
total_duration += *duration;
|
||||
}
|
||||
|
||||
fbd_feedback_vibra_set_duration (FBD_FEEDBACK_VIBRA (self), total_duration);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fbd_feedback_vibra_pattern_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FbdFeedbackVibraPattern *self = FBD_FEEDBACK_VIBRA_PATTERN (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_MAGNITUDES:
|
||||
set_magnitudes (self, g_value_get_boxed (value));
|
||||
break;
|
||||
case PROP_DURATIONS:
|
||||
set_durations (self, g_value_get_boxed (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fbd_feedback_vibra_pattern_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FbdFeedbackVibraPattern *self = FBD_FEEDBACK_VIBRA_PATTERN (object);
|
||||
|
||||
switch (property_id) {
|
||||
case PROP_MAGNITUDES:
|
||||
g_value_set_boxed (value, self->magnitudes);
|
||||
break;
|
||||
case PROP_DURATIONS:
|
||||
g_value_set_boxed (value, self->durations);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void on_timer_expired (gpointer data);
|
||||
|
||||
|
||||
static void
|
||||
do_pattern_step (FbdFeedbackVibraPattern *self)
|
||||
{
|
||||
FbdFeedbackManager *manager = fbd_feedback_manager_get_default ();
|
||||
FbdDevVibra *dev = fbd_feedback_manager_get_dev_vibra (manager);
|
||||
double *magnitude;
|
||||
guint *duration;
|
||||
|
||||
magnitude = &g_array_index (self->magnitudes, double, self->pos);
|
||||
duration = &g_array_index (self->durations, guint, self->pos);
|
||||
|
||||
g_debug ("step: pos: %d/%d, magn: %f, timeout %u",
|
||||
self->pos,
|
||||
self->durations->len,
|
||||
*magnitude,
|
||||
*duration);
|
||||
|
||||
/* Removing any pending effect */
|
||||
fbd_dev_vibra_remove_effect (dev);
|
||||
|
||||
if (*magnitude != 0.0)
|
||||
fbd_dev_vibra_rumble (dev, *magnitude, *duration, TRUE);
|
||||
|
||||
self->timer_id = g_timeout_add_once (*duration,
|
||||
on_timer_expired,
|
||||
self);
|
||||
g_source_set_name_by_id (self->timer_id, "feedback-vibra-pattern-timer");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
on_timer_expired (gpointer data)
|
||||
{
|
||||
FbdFeedbackVibraPattern *self = data;
|
||||
|
||||
g_return_if_fail (FBD_IS_FEEDBACK_VIBRA_PATTERN (self));
|
||||
g_return_if_fail (self->pos < self->durations->len);
|
||||
|
||||
self->pos++;
|
||||
|
||||
if (self->pos == self->durations->len) {
|
||||
self->timer_id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
do_pattern_step (self);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fbd_feedback_vibra_pattern_end_vibra (FbdFeedbackVibra *vibra)
|
||||
{
|
||||
FbdFeedbackVibraPattern *self = FBD_FEEDBACK_VIBRA_PATTERN (vibra);
|
||||
FbdFeedbackManager *manager = fbd_feedback_manager_get_default ();
|
||||
FbdDevVibra *dev = fbd_feedback_manager_get_dev_vibra (manager);
|
||||
|
||||
if (self->timer_id) {
|
||||
self->pos = 0;
|
||||
g_clear_handle_id (&self->timer_id, g_source_remove);
|
||||
}
|
||||
|
||||
fbd_dev_vibra_stop (dev);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fbd_feedback_vibra_pattern_start_vibra (FbdFeedbackVibra *vibra)
|
||||
{
|
||||
FbdFeedbackVibraPattern *self = FBD_FEEDBACK_VIBRA_PATTERN (vibra);
|
||||
FbdFeedbackManager *manager = fbd_feedback_manager_get_default ();
|
||||
FbdDevVibra *dev = fbd_feedback_manager_get_dev_vibra (manager);
|
||||
|
||||
g_return_if_fail (FBD_IS_DEV_VIBRA (dev));
|
||||
g_return_if_fail (self->magnitudes);
|
||||
g_return_if_fail (self->durations);
|
||||
g_return_if_fail (self->durations->len == self->magnitudes->len);
|
||||
g_return_if_fail (self->pos == 0);
|
||||
|
||||
g_debug ("Pattern Vibra: %u elements", self->durations->len);
|
||||
|
||||
if (self->durations->len == 0)
|
||||
return;
|
||||
|
||||
do_pattern_step (self);
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
fbd_feedback_vibra_pattern_is_available (FbdFeedbackBase *base)
|
||||
{
|
||||
FbdFeedbackManager *manager = fbd_feedback_manager_get_default ();
|
||||
FbdDevVibra *dev = fbd_feedback_manager_get_dev_vibra (manager);
|
||||
|
||||
return FBD_IS_DEV_VIBRA (dev);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fbd_feedback_vibra_pattern_finalize (GObject *object)
|
||||
{
|
||||
FbdFeedbackVibraPattern *self = FBD_FEEDBACK_VIBRA_PATTERN (object);
|
||||
|
||||
fbd_feedback_vibra_pattern_end_vibra (FBD_FEEDBACK_VIBRA (self));
|
||||
g_clear_pointer (&self->magnitudes, g_array_unref);
|
||||
g_clear_pointer (&self->durations, g_array_unref);
|
||||
|
||||
G_OBJECT_CLASS (fbd_feedback_vibra_pattern_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fbd_feedback_vibra_pattern_class_init (FbdFeedbackVibraPatternClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
FbdFeedbackBaseClass *base_class = FBD_FEEDBACK_BASE_CLASS (klass);
|
||||
FbdFeedbackVibraClass *vibra_class = FBD_FEEDBACK_VIBRA_CLASS (klass);
|
||||
|
||||
object_class->finalize = fbd_feedback_vibra_pattern_finalize;
|
||||
object_class->set_property = fbd_feedback_vibra_pattern_set_property;
|
||||
object_class->get_property = fbd_feedback_vibra_pattern_get_property;
|
||||
|
||||
base_class->is_available = fbd_feedback_vibra_pattern_is_available;
|
||||
|
||||
vibra_class->start_vibra = fbd_feedback_vibra_pattern_start_vibra;
|
||||
vibra_class->end_vibra = fbd_feedback_vibra_pattern_end_vibra;
|
||||
|
||||
/**
|
||||
* FbdFeedbackVibraPattern:magnitudes
|
||||
*
|
||||
* The magnitudes as array of doubles. The values specify
|
||||
* the relative magnitude of a rumble. A value of 0 indicates
|
||||
* a pause.
|
||||
*/
|
||||
props[PROP_MAGNITUDES] =
|
||||
g_param_spec_boxed ("magnitudes", "", "",
|
||||
G_TYPE_ARRAY,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||
/**
|
||||
* FbdFeedbackVibraPattern:durations
|
||||
*
|
||||
* The durations as array of unsigned integers. The values specify
|
||||
* an the length of each rumble.
|
||||
*/
|
||||
props[PROP_DURATIONS] =
|
||||
g_param_spec_boxed ("durations", "", "",
|
||||
G_TYPE_ARRAY,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (object_class, PROP_LAST_PROP, props);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fbd_feedback_vibra_pattern_init (FbdFeedbackVibraPattern *self)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
FbdFeedbackVibraPattern *
|
||||
fbd_feedback_vibra_pattern_new (GArray *magnitudes, GArray *durations)
|
||||
{
|
||||
return g_object_new (FBD_TYPE_FEEDBACK_VIBRA_PATTERN,
|
||||
"magnitudes", magnitudes,
|
||||
"durations", durations,
|
||||
NULL);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Phosh Developers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0+
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "fbd-feedback-vibra.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define FBD_TYPE_FEEDBACK_VIBRA_PATTERN (fbd_feedback_vibra_pattern_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FbdFeedbackVibraPattern, fbd_feedback_vibra_pattern, FBD,
|
||||
FEEDBACK_VIBRA_PATTERN,
|
||||
FbdFeedbackVibra);
|
||||
|
||||
FbdFeedbackVibraPattern *fbd_feedback_vibra_pattern_new (GArray *magnitudes, GArray *durations);
|
||||
|
||||
G_END_DECLS
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Phosh Developers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0+
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <fbd-feedback-vibra.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void fbd_feedback_vibra_set_duration (FbdFeedbackVibra *self, guint duration);
|
||||
|
||||
G_END_DECLS
|
||||
@@ -18,6 +18,8 @@
|
||||
* The #FbdVibraVibraRumble describes the properties of a haptic feedback
|
||||
* event. It knows nothing about the hardware itself but calls
|
||||
* #FbdDevVibra for that.
|
||||
*
|
||||
* TODO: could be dropped in favor of the more flexible `FbdFeedbackVibraPattern`.
|
||||
*/
|
||||
|
||||
enum {
|
||||
@@ -43,9 +45,9 @@ G_DEFINE_TYPE (FbdFeedbackVibraRumble, fbd_feedback_vibra_rumble, FBD_TYPE_FEEDB
|
||||
|
||||
static void
|
||||
fbd_feedback_vibra_rumble_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FbdFeedbackVibraRumble *self = FBD_FEEDBACK_VIBRA_RUMBLE (object);
|
||||
|
||||
@@ -63,10 +65,10 @@ fbd_feedback_vibra_rumble_set_property (GObject *object,
|
||||
}
|
||||
|
||||
static void
|
||||
fbd_feedback_vibra_rumble_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
fbd_feedback_vibra_rumble_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FbdFeedbackVibraRumble *self = FBD_FEEDBACK_VIBRA_RUMBLE (object);
|
||||
|
||||
@@ -92,7 +94,7 @@ on_period_ended (FbdFeedbackVibraRumble *self)
|
||||
g_return_val_if_fail (FBD_IS_FEEDBACK_VIBRA_RUMBLE (self), G_SOURCE_REMOVE);
|
||||
|
||||
if (self->periods) {
|
||||
fbd_dev_vibra_rumble (dev, self->rumble, FALSE);
|
||||
fbd_dev_vibra_rumble (dev, 1.0, self->rumble, FALSE);
|
||||
self->periods--;
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
@@ -129,8 +131,8 @@ fbd_feedback_vibra_rumble_start_vibra (FbdFeedbackVibra *vibra)
|
||||
self->periods = self->count;
|
||||
|
||||
g_debug ("Rumble Vibra event: duration %d, rumble: %d, pause: %d, period: %d",
|
||||
duration, self->rumble, self->pause, period);
|
||||
fbd_dev_vibra_rumble (dev, self->rumble, TRUE);
|
||||
duration, self->rumble, self->pause, period);
|
||||
fbd_dev_vibra_rumble (dev, 1.0, self->rumble, TRUE);
|
||||
self->periods--;
|
||||
if (self->periods) {
|
||||
self->timer_id = g_timeout_add (period, (GSourceFunc) on_period_ended, self);
|
||||
|
||||
+39
-16
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "fbd-enums.h"
|
||||
#include "fbd-feedback-vibra.h"
|
||||
#include "fbd-feedback-vibra-priv.h"
|
||||
#include "fbd-feedback-manager.h"
|
||||
|
||||
/**
|
||||
@@ -35,17 +36,19 @@ typedef struct _FbdFeedbackVibraPrivate {
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (FbdFeedbackVibra, fbd_feedback_vibra, FBD_TYPE_FEEDBACK_BASE);
|
||||
|
||||
|
||||
static gboolean
|
||||
static void
|
||||
on_timeout_expired (FbdFeedbackVibra *self)
|
||||
{
|
||||
FbdFeedbackManager *manager = fbd_feedback_manager_get_default ();
|
||||
FbdFeedbackVibraPrivate *priv = fbd_feedback_vibra_get_instance_private (self);
|
||||
FbdDevVibra *dev = fbd_feedback_manager_get_dev_vibra (manager);
|
||||
|
||||
fbd_dev_vibra_remove_effect (dev);
|
||||
fbd_feedback_base_done (FBD_FEEDBACK_BASE(self));
|
||||
return G_SOURCE_REMOVE;
|
||||
fbd_dev_vibra_stop (dev);
|
||||
priv->timer_id = 0;
|
||||
fbd_feedback_base_done (FBD_FEEDBACK_BASE (self));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fbd_feedback_vibra_run (FbdFeedbackBase *base)
|
||||
{
|
||||
@@ -57,9 +60,9 @@ fbd_feedback_vibra_run (FbdFeedbackBase *base)
|
||||
g_return_if_fail (klass->start_vibra);
|
||||
klass->start_vibra (self);
|
||||
|
||||
priv->timer_id = g_timeout_add (priv->duration,
|
||||
(GSourceFunc)on_timeout_expired,
|
||||
self);
|
||||
priv->timer_id = g_timeout_add_once (priv->duration,
|
||||
(GSourceOnceFunc)on_timeout_expired,
|
||||
self);
|
||||
g_source_set_name_by_id (priv->timer_id, "feedback-vibra-timer");
|
||||
}
|
||||
|
||||
@@ -75,8 +78,8 @@ fbd_feedback_vibra_end (FbdFeedbackBase *base)
|
||||
return;
|
||||
|
||||
g_return_if_fail (klass->end_vibra);
|
||||
klass->end_vibra(self);
|
||||
g_clear_handle_id(&priv->timer_id, g_source_remove);
|
||||
klass->end_vibra (self);
|
||||
g_clear_handle_id (&priv->timer_id, g_source_remove);
|
||||
fbd_feedback_base_done (FBD_FEEDBACK_BASE(self));
|
||||
}
|
||||
|
||||
@@ -102,9 +105,9 @@ fbd_feedback_vibra_set_property (GObject *object,
|
||||
|
||||
static void
|
||||
fbd_feedback_vibra_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FbdFeedbackVibra *self = FBD_FEEDBACK_VIBRA (object);
|
||||
FbdFeedbackVibraPrivate *priv = fbd_feedback_vibra_get_instance_private (self);
|
||||
@@ -131,13 +134,16 @@ fbd_feedback_vibra_class_init (FbdFeedbackVibraClass *klass)
|
||||
base_class->run = fbd_feedback_vibra_run;
|
||||
base_class->end = fbd_feedback_vibra_end;
|
||||
|
||||
/**
|
||||
* FbdFeedbackVibra:duration:
|
||||
*
|
||||
* The total duration of the feedback event in milliseconds.
|
||||
*/
|
||||
props[PROP_DURATION] =
|
||||
g_param_spec_uint (
|
||||
"duration",
|
||||
"Duration",
|
||||
"Vibra event duration in msecs",
|
||||
"duration", "", "",
|
||||
0, G_MAXUINT, FBD_FEEDBACK_VIBRA_DEFAULT_DURATION,
|
||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||
G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (object_class, PROP_LAST_PROP, props);
|
||||
}
|
||||
@@ -156,3 +162,20 @@ fbd_feedback_vibra_get_duration (FbdFeedbackVibra *self)
|
||||
priv = fbd_feedback_vibra_get_instance_private (self);
|
||||
return priv->duration;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fbd_feedback_vibra_set_duration (FbdFeedbackVibra *self, guint duration)
|
||||
{
|
||||
FbdFeedbackVibraPrivate *priv;
|
||||
|
||||
g_return_if_fail (FBD_IS_FEEDBACK_VIBRA (self));
|
||||
|
||||
priv = fbd_feedback_vibra_get_instance_private (self);
|
||||
|
||||
if (duration == priv->duration)
|
||||
return;
|
||||
|
||||
priv->duration = duration;
|
||||
g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DURATION]);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Phosh Developers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Author: Guido Günther <agx@sigxcpu.org>
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "fbd-haptic-manager"
|
||||
|
||||
#include "fbd-feedback-manager.h"
|
||||
#include "fbd-haptic-manager.h"
|
||||
#include "fbd-feedback-base.h"
|
||||
#include "fbd-feedback-profile.h"
|
||||
#include "fbd-feedback-vibra-pattern.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#define MAX_ITEMS 10
|
||||
#define MAX_LEN 10000
|
||||
|
||||
/**
|
||||
* FbdHapticManager:
|
||||
*
|
||||
* Handles the org.sigxcpu.Feedback.Haptic interface
|
||||
*/
|
||||
|
||||
struct _FbdHapticManager {
|
||||
LfbGdbusFeedbackHapticSkeleton parent;
|
||||
|
||||
FbdFeedbackVibraPattern *vibra;
|
||||
};
|
||||
|
||||
static void fbd_feedback_manager_feedback_haptic_iface_init (LfbGdbusFeedbackHapticIface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (FbdHapticManager,
|
||||
fbd_haptic_manager,
|
||||
LFB_GDBUS_TYPE_FEEDBACK_HAPTIC_SKELETON,
|
||||
G_IMPLEMENT_INTERFACE (
|
||||
LFB_GDBUS_TYPE_FEEDBACK_HAPTIC,
|
||||
fbd_feedback_manager_feedback_haptic_iface_init));
|
||||
|
||||
|
||||
/**
|
||||
* build_pattern:
|
||||
* @pattern: The pattern as GVariant
|
||||
* @out_magnitudes:(out): The magnitudes
|
||||
* @out_durations: The durations
|
||||
*
|
||||
* Parses the pattern (applying the limits) into an array of magnitudes
|
||||
* and durations.
|
||||
*
|
||||
* Returns: The `TRUE` if here were elements in the pattern, otherwise `FALSE`
|
||||
*/
|
||||
static gboolean
|
||||
build_pattern (GVariant *pattern, GArray **out_magnitudes, GArray **out_durations)
|
||||
{
|
||||
GVariantIter iter;
|
||||
GArray *durations, *magnitudes;
|
||||
double magnitude;
|
||||
guint duration, n_items;
|
||||
|
||||
g_variant_iter_init (&iter, pattern);
|
||||
|
||||
n_items = MIN (g_variant_iter_n_children (&iter), MAX_ITEMS);
|
||||
|
||||
if (n_items == 0)
|
||||
return FALSE;
|
||||
|
||||
durations = g_array_sized_new (FALSE, FALSE, sizeof (guint), n_items);
|
||||
magnitudes = g_array_sized_new (FALSE, FALSE, sizeof (double), n_items);
|
||||
|
||||
for (guint pos = 0; pos < n_items; pos++) {
|
||||
g_variant_iter_next (&iter, "(du)", &magnitude, &duration);
|
||||
|
||||
duration = MIN (duration, MAX_LEN);
|
||||
g_array_append_val (durations, duration);
|
||||
|
||||
magnitude = MAX(0.0, MIN (magnitude, 1.0));
|
||||
g_array_append_val (magnitudes, magnitude);
|
||||
}
|
||||
|
||||
*out_durations = durations;
|
||||
*out_magnitudes = magnitudes;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
fbd_feedback_manager_handle_vibrate (LfbGdbusFeedbackHaptic *object,
|
||||
GDBusMethodInvocation *invocation,
|
||||
const gchar *app_id,
|
||||
GVariant *pattern)
|
||||
{
|
||||
FbdFeedbackManager *manager = fbd_feedback_manager_get_default ();
|
||||
FbdHapticManager *self = FBD_HAPTIC_MANAGER (object);
|
||||
FbdDevVibra *vibra_dev;
|
||||
FbdFeedbackProfileLevel level;
|
||||
gboolean non_empty;
|
||||
g_autoptr (FbdFeedbackVibraPattern) fb = NULL;
|
||||
g_autoptr (GArray) magnitudes = NULL, durations = NULL;
|
||||
|
||||
g_debug ("Haptic triggered for %s", app_id);
|
||||
|
||||
level = fbd_feedback_manager_get_effective_level (manager,
|
||||
app_id,
|
||||
FBD_FEEDBACK_PROFILE_LEVEL_QUIET,
|
||||
FALSE);
|
||||
if (level < FBD_FEEDBACK_PROFILE_LEVEL_QUIET) {
|
||||
g_debug ("Feedback level too low for haptic");
|
||||
lfb_gdbus_feedback_haptic_complete_vibrate (object, invocation, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
vibra_dev = fbd_feedback_manager_get_dev_vibra (manager);
|
||||
if (!vibra_dev) {
|
||||
g_debug ("No haptic device");
|
||||
lfb_gdbus_feedback_haptic_complete_vibrate (object, invocation, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
non_empty = build_pattern (pattern, &magnitudes, &durations);
|
||||
if (!non_empty) {
|
||||
g_debug ("Empty pattern, ending feedback");
|
||||
fbd_haptic_manager_end_feedback (self);
|
||||
g_clear_object (&self->vibra);
|
||||
lfb_gdbus_feedback_haptic_complete_vibrate (object, invocation, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (self->vibra)
|
||||
fbd_feedback_end (FBD_FEEDBACK_BASE (self->vibra));
|
||||
if (fbd_dev_vibra_is_busy (vibra_dev)) {
|
||||
g_debug ("Haptic busy");
|
||||
/* If there's an event with haptic deny haptic patter */
|
||||
lfb_gdbus_feedback_haptic_complete_vibrate (object, invocation, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
fb = fbd_feedback_vibra_pattern_new (magnitudes, durations);
|
||||
fbd_feedback_run (FBD_FEEDBACK_BASE (fb));
|
||||
self->vibra = g_steal_pointer (&fb);
|
||||
|
||||
lfb_gdbus_feedback_haptic_complete_vibrate (object, invocation, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fbd_feedback_manager_feedback_haptic_iface_init (LfbGdbusFeedbackHapticIface *iface)
|
||||
{
|
||||
iface->handle_vibrate = fbd_feedback_manager_handle_vibrate;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fbd_haptic_manager_finalize (GObject *object)
|
||||
{
|
||||
FbdHapticManager *self = FBD_HAPTIC_MANAGER (object);
|
||||
|
||||
fbd_haptic_manager_end_feedback (self);
|
||||
|
||||
G_OBJECT_CLASS (fbd_haptic_manager_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fbd_haptic_manager_class_init (FbdHapticManagerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = fbd_haptic_manager_finalize;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fbd_haptic_manager_init (FbdHapticManager *self)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
FbdHapticManager *
|
||||
fbd_haptic_manager_new (void)
|
||||
{
|
||||
return g_object_new (FBD_TYPE_HAPTIC_MANAGER, NULL);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fbd_haptic_manager_end_feedback (FbdHapticManager *self)
|
||||
{
|
||||
g_return_if_fail (FBD_IS_HAPTIC_MANAGER (self));
|
||||
|
||||
if (!self->vibra)
|
||||
return;
|
||||
|
||||
fbd_feedback_end (FBD_FEEDBACK_BASE (self->vibra));
|
||||
g_clear_object (&self->vibra);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Phosh Developers
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lfb-gdbus.h"
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define FBD_TYPE_HAPTIC_MANAGER (fbd_haptic_manager_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FbdHapticManager, fbd_haptic_manager, FBD, HAPTIC_MANAGER,
|
||||
LfbGdbusFeedbackHapticSkeleton)
|
||||
|
||||
FbdHapticManager *fbd_haptic_manager_new (void);
|
||||
void fbd_haptic_manager_end_feedback (FbdHapticManager *self);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
@@ -8,15 +8,24 @@
|
||||
|
||||
#include "fbd.h"
|
||||
#include "fbd-feedback-manager.h"
|
||||
#include "fbd-haptic-manager.h"
|
||||
#include "lfb-names.h"
|
||||
#include "lfb-gdbus.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <glib-unix.h>
|
||||
|
||||
|
||||
static GMainLoop *loop;
|
||||
|
||||
|
||||
static GDebugKey debug_keys[] =
|
||||
{
|
||||
{ .key = "force-haptic",
|
||||
.value = FBD_DEBUG_FLAG_FORCE_HAPTIC,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static gboolean
|
||||
quit_cb (gpointer user_data)
|
||||
{
|
||||
@@ -45,17 +54,29 @@ reload_cb (gpointer user_data)
|
||||
|
||||
static void
|
||||
bus_acquired_cb (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
FbdFeedbackManager *manager = fbd_feedback_manager_get_default ();
|
||||
FbdHapticManager *haptic_manager;
|
||||
|
||||
g_debug ("Bus acquired, creating manager...");
|
||||
g_assert (FBD_IS_FEEDBACK_MANAGER (manager));
|
||||
|
||||
g_debug ("Bus acquired, exporting manager...");
|
||||
|
||||
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (manager),
|
||||
connection,
|
||||
FB_DBUS_PATH,
|
||||
NULL);
|
||||
|
||||
haptic_manager = fbd_feedback_manager_get_haptic_manager (manager);
|
||||
if (haptic_manager) {
|
||||
g_debug ("Exporting haptic manager...");
|
||||
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (haptic_manager),
|
||||
connection,
|
||||
FB_DBUS_PATH,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,11 +109,13 @@ name_lost_cb (GDBusConnection *connection,
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
g_autoptr(GError) err = NULL;
|
||||
g_autoptr(GOptionContext) opt_context = NULL;
|
||||
g_autoptr (FbdFeedbackManager) manager = NULL;
|
||||
const char *debugenv;
|
||||
|
||||
opt_context = g_option_context_new ("- A daemon to trigger event feedback");
|
||||
if (!g_option_context_parse (opt_context, &argc, &argv, &err)) {
|
||||
@@ -101,6 +124,11 @@ int main(int argc, char *argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
debugenv = g_getenv ("FEEDBACKD_DEBUG");
|
||||
fbd_debug_flags = g_parse_debug_string (debugenv,
|
||||
debug_keys,
|
||||
G_N_ELEMENTS (debug_keys));
|
||||
|
||||
manager = fbd_feedback_manager_get_default ();
|
||||
fbd_feedback_manager_load_theme (manager);
|
||||
|
||||
|
||||
@@ -30,8 +30,10 @@ sources = [
|
||||
'fbd-feedback-sound.c',
|
||||
'fbd-feedback-theme.c',
|
||||
'fbd-feedback-vibra.c',
|
||||
'fbd-feedback-vibra-pattern.c',
|
||||
'fbd-feedback-vibra-periodic.c',
|
||||
'fbd-feedback-vibra-rumble.c',
|
||||
'fbd-haptic-manager.c',
|
||||
'fbd-theme-expander.c',
|
||||
'fbd-udev.c',
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user