1 /*
2 * Copyright (C) 2014 Michal Ratajsky <michal.ratajsky@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the licence, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <string.h>
19 #include <glib.h>
20 #include <glib-object.h>
21
22 #include "matemixer-device.h"
23 #include "matemixer-enums.h"
24 #include "matemixer-enum-types.h"
25 #include "matemixer-stream.h"
26 #include "matemixer-stream-control.h"
27 #include "matemixer-stream-private.h"
28 #include "matemixer-stream-switch.h"
29 #include "matemixer-switch.h"
30
31 /**
32 * SECTION:matemixer-stream
33 * @include: libmatemixer/matemixer.h
34 */
35
36 struct _MateMixerStreamPrivate
37 {
38 gchar *name;
39 gchar *label;
40 MateMixerDirection direction;
41 MateMixerDevice *device;
42 MateMixerStreamControl *control;
43 };
44
45 enum {
46 PROP_0,
47 PROP_NAME,
48 PROP_LABEL,
49 PROP_DIRECTION,
50 PROP_DEVICE,
51 PROP_DEFAULT_CONTROL,
52 N_PROPERTIES
53 };
54
55 static GParamSpec *properties[N_PROPERTIES] = { NULL, };
56
57 enum {
58 CONTROL_ADDED,
59 CONTROL_REMOVED,
60 SWITCH_ADDED,
61 SWITCH_REMOVED,
62 N_SIGNALS
63 };
64
65 static guint signals[N_SIGNALS] = { 0, };
66
67 static void mate_mixer_stream_get_property (GObject *object,
68 guint param_id,
69 GValue *value,
70 GParamSpec *pspec);
71 static void mate_mixer_stream_set_property (GObject *object,
72 guint param_id,
73 const GValue *value,
74 GParamSpec *pspec);
75
76 static void mate_mixer_stream_dispose (GObject *object);
77 static void mate_mixer_stream_finalize (GObject *object);
78
79 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (MateMixerStream, mate_mixer_stream, G_TYPE_OBJECT)
80
81 static MateMixerStreamControl *mate_mixer_stream_real_get_control (MateMixerStream *stream,
82 const gchar *name);
83 static MateMixerStreamSwitch * mate_mixer_stream_real_get_switch (MateMixerStream *stream,
84 const gchar *name);
85
86 static void
mate_mixer_stream_class_init(MateMixerStreamClass * klass)87 mate_mixer_stream_class_init (MateMixerStreamClass *klass)
88 {
89 GObjectClass *object_class;
90
91 klass->get_control = mate_mixer_stream_real_get_control;
92 klass->get_switch = mate_mixer_stream_real_get_switch;
93
94 object_class = G_OBJECT_CLASS (klass);
95 object_class->dispose = mate_mixer_stream_dispose;
96 object_class->finalize = mate_mixer_stream_finalize;
97 object_class->get_property = mate_mixer_stream_get_property;
98 object_class->set_property = mate_mixer_stream_set_property;
99
100 properties[PROP_NAME] =
101 g_param_spec_string ("name",
102 "Name",
103 "Name of the stream",
104 NULL,
105 G_PARAM_READWRITE |
106 G_PARAM_CONSTRUCT_ONLY |
107 G_PARAM_STATIC_STRINGS);
108
109 properties[PROP_LABEL] =
110 g_param_spec_string ("label",
111 "Label",
112 "Label of the stream",
113 NULL,
114 G_PARAM_READWRITE |
115 G_PARAM_CONSTRUCT_ONLY |
116 G_PARAM_STATIC_STRINGS);
117
118 properties[PROP_DIRECTION] =
119 g_param_spec_enum ("direction",
120 "Direction",
121 "Direction of the stream",
122 MATE_MIXER_TYPE_DIRECTION,
123 MATE_MIXER_DIRECTION_UNKNOWN,
124 G_PARAM_READWRITE |
125 G_PARAM_CONSTRUCT_ONLY |
126 G_PARAM_STATIC_STRINGS);
127
128 properties[PROP_DEVICE] =
129 g_param_spec_object ("device",
130 "Device",
131 "Device the stream belongs to",
132 MATE_MIXER_TYPE_DEVICE,
133 G_PARAM_READWRITE |
134 G_PARAM_CONSTRUCT_ONLY |
135 G_PARAM_STATIC_STRINGS);
136
137 properties[PROP_DEFAULT_CONTROL] =
138 g_param_spec_object ("default-control",
139 "Default control",
140 "Default control of the stream",
141 MATE_MIXER_TYPE_STREAM_CONTROL,
142 G_PARAM_READWRITE |
143 G_PARAM_CONSTRUCT_ONLY |
144 G_PARAM_STATIC_STRINGS);
145
146 g_object_class_install_properties (object_class, N_PROPERTIES, properties);
147
148 signals[CONTROL_ADDED] =
149 g_signal_new ("control-added",
150 G_TYPE_FROM_CLASS (object_class),
151 G_SIGNAL_RUN_FIRST,
152 G_STRUCT_OFFSET (MateMixerStreamClass, control_added),
153 NULL,
154 NULL,
155 g_cclosure_marshal_VOID__STRING,
156 G_TYPE_NONE,
157 1,
158 G_TYPE_STRING);
159
160 signals[CONTROL_REMOVED] =
161 g_signal_new ("control-removed",
162 G_TYPE_FROM_CLASS (object_class),
163 G_SIGNAL_RUN_FIRST,
164 G_STRUCT_OFFSET (MateMixerStreamClass, control_removed),
165 NULL,
166 NULL,
167 g_cclosure_marshal_VOID__STRING,
168 G_TYPE_NONE,
169 1,
170 G_TYPE_STRING);
171
172 signals[SWITCH_ADDED] =
173 g_signal_new ("switch-added",
174 G_TYPE_FROM_CLASS (object_class),
175 G_SIGNAL_RUN_FIRST,
176 G_STRUCT_OFFSET (MateMixerStreamClass, switch_added),
177 NULL,
178 NULL,
179 g_cclosure_marshal_VOID__STRING,
180 G_TYPE_NONE,
181 1,
182 G_TYPE_STRING);
183
184 signals[SWITCH_REMOVED] =
185 g_signal_new ("switch-removed",
186 G_TYPE_FROM_CLASS (object_class),
187 G_SIGNAL_RUN_FIRST,
188 G_STRUCT_OFFSET (MateMixerStreamClass, switch_removed),
189 NULL,
190 NULL,
191 g_cclosure_marshal_VOID__STRING,
192 G_TYPE_NONE,
193 1,
194 G_TYPE_STRING);
195 }
196
197 static void
mate_mixer_stream_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)198 mate_mixer_stream_get_property (GObject *object,
199 guint param_id,
200 GValue *value,
201 GParamSpec *pspec)
202 {
203 MateMixerStream *stream;
204
205 stream = MATE_MIXER_STREAM (object);
206
207 switch (param_id) {
208 case PROP_NAME:
209 g_value_set_string (value, stream->priv->name);
210 break;
211 case PROP_LABEL:
212 g_value_set_string (value, stream->priv->label);
213 break;
214 case PROP_DIRECTION:
215 g_value_set_enum (value, stream->priv->direction);
216 break;
217 case PROP_DEVICE:
218 g_value_set_object (value, stream->priv->device);
219 break;
220 case PROP_DEFAULT_CONTROL:
221 g_value_set_object (value, stream->priv->control);
222 break;
223
224 default:
225 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
226 break;
227 }
228 }
229
230 static void
mate_mixer_stream_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)231 mate_mixer_stream_set_property (GObject *object,
232 guint param_id,
233 const GValue *value,
234 GParamSpec *pspec)
235 {
236 MateMixerStream *stream;
237
238 stream = MATE_MIXER_STREAM (object);
239
240 switch (param_id) {
241 case PROP_NAME:
242 /* Construct-only string */
243 stream->priv->name = g_value_dup_string (value);
244 break;
245 case PROP_LABEL:
246 /* Construct-only string */
247 stream->priv->label = g_value_dup_string (value);
248 break;
249 case PROP_DIRECTION:
250 stream->priv->direction = g_value_get_enum (value);
251 break;
252 case PROP_DEVICE:
253 /* Construct-only object */
254 stream->priv->device = g_value_get_object (value);
255
256 if (stream->priv->device != NULL)
257 g_object_add_weak_pointer (G_OBJECT (stream->priv->device),
258 (gpointer *) &stream->priv->device);
259 break;
260 case PROP_DEFAULT_CONTROL:
261 /* Construct-only object */
262 stream->priv->control = g_value_dup_object (value);
263 break;
264
265 default:
266 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
267 break;
268 }
269 }
270
271 static void
mate_mixer_stream_init(MateMixerStream * stream)272 mate_mixer_stream_init (MateMixerStream *stream)
273 {
274 stream->priv = mate_mixer_stream_get_instance_private (stream);
275 }
276
277 static void
mate_mixer_stream_dispose(GObject * object)278 mate_mixer_stream_dispose (GObject *object)
279 {
280 MateMixerStream *stream;
281
282 stream = MATE_MIXER_STREAM (object);
283
284 g_clear_object (&stream->priv->control);
285
286 G_OBJECT_CLASS (mate_mixer_stream_parent_class)->dispose (object);
287 }
288
289 static void
mate_mixer_stream_finalize(GObject * object)290 mate_mixer_stream_finalize (GObject *object)
291 {
292 MateMixerStream *stream;
293
294 stream = MATE_MIXER_STREAM (object);
295
296 g_free (stream->priv->name);
297 g_free (stream->priv->label);
298
299 G_OBJECT_CLASS (mate_mixer_stream_parent_class)->finalize (object);
300 }
301
302 /**
303 * mate_mixer_stream_get_name:
304 * @stream: a #MateMixerStream
305 */
306 const gchar *
mate_mixer_stream_get_name(MateMixerStream * stream)307 mate_mixer_stream_get_name (MateMixerStream *stream)
308 {
309 g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
310
311 return stream->priv->name;
312 }
313
314 /**
315 * mate_mixer_stream_get_label:
316 * @stream: a #MateMixerStream
317 */
318 const gchar *
mate_mixer_stream_get_label(MateMixerStream * stream)319 mate_mixer_stream_get_label (MateMixerStream *stream)
320 {
321 g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
322
323 return stream->priv->label;
324 }
325
326 /**
327 * mate_mixer_stream_get_direction:
328 * @stream: a #MateMixerStream
329 */
330 MateMixerDirection
mate_mixer_stream_get_direction(MateMixerStream * stream)331 mate_mixer_stream_get_direction (MateMixerStream *stream)
332 {
333 g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), MATE_MIXER_DIRECTION_UNKNOWN);
334
335 return stream->priv->direction;
336 }
337
338 /**
339 * mate_mixer_stream_get_device:
340 * @stream: a #MateMixerStream
341 */
342 MateMixerDevice *
mate_mixer_stream_get_device(MateMixerStream * stream)343 mate_mixer_stream_get_device (MateMixerStream *stream)
344 {
345 g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
346
347 return stream->priv->device;
348 }
349
350 /**
351 * mate_mixer_stream_get_control:
352 * @stream: a #MateMixerStream
353 * @name: the name of a stream control
354 */
355 MateMixerStreamControl *
mate_mixer_stream_get_control(MateMixerStream * stream,const gchar * name)356 mate_mixer_stream_get_control (MateMixerStream *stream, const gchar *name)
357 {
358 g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
359 g_return_val_if_fail (name != NULL, NULL);
360
361 return MATE_MIXER_STREAM_GET_CLASS (stream)->get_control (stream, name);
362 }
363
364 /**
365 * mate_mixer_stream_get_switch:
366 * @stream: a #MateMixerStream
367 * @name: the name of a stream switch
368 *
369 * Gets the switch with the given name.
370 *
371 * Returns: a #MateMixerStreamSwitch or %NULL if there is no such switch.
372 */
373 MateMixerStreamSwitch *
mate_mixer_stream_get_switch(MateMixerStream * stream,const gchar * name)374 mate_mixer_stream_get_switch (MateMixerStream *stream, const gchar *name)
375 {
376 g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
377 g_return_val_if_fail (name != NULL, NULL);
378
379 return MATE_MIXER_STREAM_GET_CLASS (stream)->get_switch (stream, name);
380 }
381
382 /**
383 * mate_mixer_stream_get_default_control:
384 * @stream: a #MateMixerStream
385 */
386 MateMixerStreamControl *
mate_mixer_stream_get_default_control(MateMixerStream * stream)387 mate_mixer_stream_get_default_control (MateMixerStream *stream)
388 {
389 const GList *list;
390
391 g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
392
393 if (stream->priv->control != NULL)
394 return stream->priv->control;
395
396 /* If the stream does not have a default control, just return the first one */
397 list = mate_mixer_stream_list_controls (stream);
398 if (list != NULL)
399 return MATE_MIXER_STREAM_CONTROL (list->data);
400
401 return NULL;
402 }
403
404 /**
405 * mate_mixer_stream_list_controls:
406 * @stream: a #MateMixerStream
407 */
408 const GList *
mate_mixer_stream_list_controls(MateMixerStream * stream)409 mate_mixer_stream_list_controls (MateMixerStream *stream)
410 {
411 MateMixerStreamClass *klass;
412
413 g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
414
415 klass = MATE_MIXER_STREAM_GET_CLASS (stream);
416
417 if (G_LIKELY (klass->list_controls != NULL))
418 return klass->list_controls (stream);
419
420 return NULL;
421 }
422
423 /**
424 * mate_mixer_stream_list_switches:
425 * @stream: a #MateMixerStream
426 */
427 const GList *
mate_mixer_stream_list_switches(MateMixerStream * stream)428 mate_mixer_stream_list_switches (MateMixerStream *stream)
429 {
430 MateMixerStreamClass *klass;
431
432 g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
433
434 klass = MATE_MIXER_STREAM_GET_CLASS (stream);
435
436 if (G_LIKELY (klass->list_switches != NULL))
437 return klass->list_switches (stream);
438
439 return NULL;
440 }
441
442 static MateMixerStreamControl *
mate_mixer_stream_real_get_control(MateMixerStream * stream,const gchar * name)443 mate_mixer_stream_real_get_control (MateMixerStream *stream, const gchar *name)
444 {
445 const GList *list;
446
447 g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
448 g_return_val_if_fail (name != NULL, NULL);
449
450 list = mate_mixer_stream_list_controls (stream);
451 while (list != NULL) {
452 MateMixerStreamControl *control = MATE_MIXER_STREAM_CONTROL (list->data);
453
454 if (strcmp (name, mate_mixer_stream_control_get_name (control)) == 0)
455 return control;
456
457 list = list->next;
458 }
459 return NULL;
460 }
461
462 static MateMixerStreamSwitch *
mate_mixer_stream_real_get_switch(MateMixerStream * stream,const gchar * name)463 mate_mixer_stream_real_get_switch (MateMixerStream *stream, const gchar *name)
464 {
465 const GList *list;
466
467 g_return_val_if_fail (MATE_MIXER_IS_STREAM (stream), NULL);
468 g_return_val_if_fail (name != NULL, NULL);
469
470 list = mate_mixer_stream_list_switches (stream);
471 while (list != NULL) {
472 MateMixerSwitch *swtch = MATE_MIXER_SWITCH (list->data);
473
474 if (strcmp (name, mate_mixer_switch_get_name (swtch)) == 0)
475 return MATE_MIXER_STREAM_SWITCH (swtch);
476
477 list = list->next;
478 }
479 return NULL;
480 }
481
482 void
_mate_mixer_stream_set_default_control(MateMixerStream * stream,MateMixerStreamControl * control)483 _mate_mixer_stream_set_default_control (MateMixerStream *stream,
484 MateMixerStreamControl *control)
485 {
486 g_return_if_fail (MATE_MIXER_IS_STREAM (stream));
487 g_return_if_fail (control == NULL || MATE_MIXER_IS_STREAM_CONTROL (control));
488
489 if (stream->priv->control == control)
490 return;
491
492 if (stream->priv->control != NULL)
493 g_object_unref (stream->priv->control);
494
495 /* The default control is allowed to be NULL */
496 if (control != NULL) {
497 stream->priv->control = g_object_ref (control);
498
499 g_debug ("Stream %s default control changed to %s",
500 mate_mixer_stream_get_name (stream),
501 mate_mixer_stream_control_get_name (control));
502 } else {
503 stream->priv->control = NULL;
504
505 g_debug ("Stream %s default control unset",
506 mate_mixer_stream_get_name (stream));
507 }
508
509 g_object_notify_by_pspec (G_OBJECT (stream), properties[PROP_DEFAULT_CONTROL]);
510 }
511