1 /*
2 * Copyright (C) 2020 Purism SPC
3 * SPDX-License-Identifier: GPL-3.0+
4 * Author: Guido Günther <agx@sigxcpu.org>
5 */
6
7 #define G_LOG_DOMAIN "fbd-feedback-base"
8
9 #include "fbd-feedback-base.h"
10
11 /**
12 * SECTION:fbd-feedback-base
13 * @short_description: Base class for different feedback types
14 * @Title: FbdFeedbackManager
15 *
16 * You usually don't want to create objects of this type. It just
17 * serves as a base class for other feedback types.
18 */
19
20 enum {
21 PROP_0,
22 PROP_EVENT_NAME,
23 PROP_LAST_PROP,
24 };
25 static GParamSpec *props[PROP_LAST_PROP];
26
27 enum {
28 SIGNAL_ENDED,
29 N_SIGNALS
30 };
31 static guint signals[N_SIGNALS];
32
33 typedef struct _FbdFeedbackBasePrivate {
34 gchar *event_name;
35 gboolean ended;
36 } FbdFeedbackBasePrivate;
37
38 G_DEFINE_TYPE_WITH_PRIVATE (FbdFeedbackBase, fbd_feedback_base, G_TYPE_OBJECT);
39
40 static void
fbd_feedback_base_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)41 fbd_feedback_base_set_property (GObject *object,
42 guint property_id,
43 const GValue *value,
44 GParamSpec *pspec)
45 {
46 FbdFeedbackBase *self = FBD_FEEDBACK_BASE (object);
47 FbdFeedbackBasePrivate *priv = fbd_feedback_base_get_instance_private (self);
48
49 switch (property_id) {
50 case PROP_EVENT_NAME:
51 g_free (priv->event_name);
52 priv->event_name = g_value_dup_string (value);
53 break;
54 default:
55 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
56 break;
57 }
58 }
59
60
61 static void
fbd_feedback_base_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)62 fbd_feedback_base_get_property (GObject *object,
63 guint property_id,
64 GValue *value,
65 GParamSpec *pspec)
66 {
67 FbdFeedbackBase *self = FBD_FEEDBACK_BASE (object);
68 FbdFeedbackBasePrivate *priv = fbd_feedback_base_get_instance_private (self);
69
70 switch (property_id) {
71 case PROP_EVENT_NAME:
72 g_value_set_string (value, priv->event_name);
73 break;
74 default:
75 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
76 break;
77 }
78 }
79
80 static void
fbd_feedback_base_dispose(GObject * object)81 fbd_feedback_base_dispose (GObject *object)
82 {
83 FbdFeedbackBase *self = FBD_FEEDBACK_BASE (object);
84
85 /* end feedback if running */
86 if (!fbd_feedback_get_ended (self))
87 fbd_feedback_end (self);
88
89 G_OBJECT_CLASS (fbd_feedback_base_parent_class)->dispose (object);
90 }
91
92 static void
fbd_feedback_base_finalize(GObject * object)93 fbd_feedback_base_finalize (GObject *object)
94 {
95 FbdFeedbackBase *self = FBD_FEEDBACK_BASE (object);
96 FbdFeedbackBasePrivate *priv = fbd_feedback_base_get_instance_private (self);
97
98 g_clear_pointer (&priv->event_name, g_free);
99
100 G_OBJECT_CLASS (fbd_feedback_base_parent_class)->finalize (object);
101 }
102
103 static void
fbd_feedback_base_class_init(FbdFeedbackBaseClass * klass)104 fbd_feedback_base_class_init (FbdFeedbackBaseClass *klass)
105 {
106 GObjectClass *object_class = G_OBJECT_CLASS (klass);
107
108 object_class->set_property = fbd_feedback_base_set_property;
109 object_class->get_property = fbd_feedback_base_get_property;
110
111 object_class->dispose = fbd_feedback_base_dispose;
112 object_class->finalize = fbd_feedback_base_finalize;
113
114 props[PROP_EVENT_NAME] =
115 g_param_spec_string (
116 "event-name",
117 "Event Name",
118 "The event this feedback is associated with",
119 NULL,
120 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
121
122 g_object_class_install_properties (object_class, PROP_LAST_PROP, props);
123
124 /**
125 * FbdFeedbackBase::ended:
126 *
127 * Emitted when the feedback has ended
128 */
129 signals[SIGNAL_ENDED] = g_signal_new ("ended",
130 G_TYPE_FROM_CLASS (klass),
131 G_SIGNAL_RUN_LAST, 0, NULL, NULL,
132 NULL,
133 G_TYPE_NONE,
134 0);
135 }
136
137 static void
fbd_feedback_base_init(FbdFeedbackBase * self)138 fbd_feedback_base_init (FbdFeedbackBase *self)
139 {
140 }
141
142 /**
143 * fbd_feedback_get_event_name:
144 * @self: The feedback
145 *
146 * Returns: the name from the event naming spec this feedback is associated with.
147 */
148 const gchar *
fbd_feedback_get_event_name(FbdFeedbackBase * self)149 fbd_feedback_get_event_name (FbdFeedbackBase *self)
150 {
151 FbdFeedbackBasePrivate *priv;
152
153 g_return_val_if_fail (FBD_IS_FEEDBACK_BASE (self), NULL);
154 priv = fbd_feedback_base_get_instance_private (self);
155
156 return priv->event_name;
157 }
158
159 /**
160 * fbd_feedback_run:
161 * @self: The feedback to run
162 *
163 * Emit the feedback.
164 */
165 void
fbd_feedback_run(FbdFeedbackBase * self)166 fbd_feedback_run (FbdFeedbackBase *self)
167 {
168 FbdFeedbackBaseClass *klass;
169 FbdFeedbackBasePrivate *priv;
170
171 g_return_if_fail (FBD_IS_FEEDBACK_BASE (self));
172 priv = fbd_feedback_base_get_instance_private (self);
173
174 priv->ended = FALSE;
175 klass = FBD_FEEDBACK_BASE_GET_CLASS (self);
176 g_return_if_fail (klass->run);
177 klass->run (self);
178 }
179
180 /**
181 * fbd_feedback_end:
182 * @self: The feedback to end
183 *
184 * End the feedback immediately.
185 */
186 void
fbd_feedback_end(FbdFeedbackBase * self)187 fbd_feedback_end (FbdFeedbackBase *self)
188 {
189 FbdFeedbackBaseClass *klass;
190
191 g_return_if_fail (FBD_IS_FEEDBACK_BASE (self));
192
193 klass = FBD_FEEDBACK_BASE_GET_CLASS (self);
194 g_return_if_fail (klass->end);
195 klass->end (self);
196 }
197
198
199 /**
200 * fbd_feedback_get_ended:
201 * @self: The feedback
202 *
203 * Whether the feedback is ended.
204 *
205 * Returns: %TRUE if feedback has ended, otherwise %FALSE.
206 */
207 gboolean
fbd_feedback_get_ended(FbdFeedbackBase * self)208 fbd_feedback_get_ended (FbdFeedbackBase *self)
209 {
210 FbdFeedbackBasePrivate *priv = fbd_feedback_base_get_instance_private (self);
211
212 return priv->ended;
213 }
214
215 /**
216 * fbd_feedback_base_done:
217 * @self: The feedback
218 *
219 * Invoked by a derived classes to notify that it's done emitting feedback,
220 * e.g. when the vibra motor stopped or a sound finished playing.
221 */
222 void
fbd_feedback_base_done(FbdFeedbackBase * self)223 fbd_feedback_base_done (FbdFeedbackBase *self)
224 {
225 FbdFeedbackBasePrivate *priv = fbd_feedback_base_get_instance_private (self);
226
227 priv->ended = TRUE;
228 g_signal_emit (self, signals[SIGNAL_ENDED], 0);
229 }
230
231 /**
232 * fbd_feedback_available:
233 * @self: The feedback
234 *
235 * Whether this feedback type is available at all. This can be %FALSE e.g.
236 * due to missing hardware.
237 *
238 * Returns: %FALSE if the feedback type is not available at all %TRUE if unsure
239 * or available.
240 */
241 gboolean
fbd_feedback_is_available(FbdFeedbackBase * self)242 fbd_feedback_is_available (FbdFeedbackBase *self)
243 {
244 FbdFeedbackBaseClass *klass;
245
246 g_return_val_if_fail (FBD_IS_FEEDBACK_BASE (self), FALSE);
247
248 klass = FBD_FEEDBACK_BASE_GET_CLASS (self);
249 if (klass->is_available)
250 return klass->is_available (self);
251 else
252 return TRUE;
253 }
254
255