1 /* GSequencer - Advanced GTK Sequencer
2 * Copyright (C) 2005-2020 Joël Krähemann
3 *
4 * This file is part of GSequencer.
5 *
6 * GSequencer is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GSequencer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GSequencer. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <ags/object/ags_priority.h>
21
22 #include <ags/object/ags_marshal.h>
23
24 #include <gio/gio.h>
25
26 #include <sys/types.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #ifndef AGS_W32API
32 #include <pwd.h>
33 #endif
34
35 #include <ags/config.h>
36 #include <ags/i18n.h>
37
38 void ags_priority_class_init(AgsPriorityClass *priority_class);
39 void ags_priority_init(AgsPriority *priority);
40 void ags_priority_set_property(GObject *gobject,
41 guint prop_id,
42 const GValue *value,
43 GParamSpec *param_spec);
44 void ags_priority_get_property(GObject *gobject,
45 guint prop_id,
46 GValue *value,
47 GParamSpec *param_spec);
48 void ags_priority_dispose(GObject *gobject);
49 void ags_priority_finalize(GObject *gobject);
50
51 gchar* ags_priority_get_version(AgsPriority *priority);
52 void ags_priority_set_version(AgsPriority *priority, gchar *version);
53 gchar* ags_priority_get_build_id(AgsPriority *priority);
54 void ags_priority_set_build_id(AgsPriority *priority, gchar *build_id);
55
56 void ags_priority_real_load_defaults(AgsPriority *priority);
57 void ags_priority_real_set_value(AgsPriority *priority, gchar *group, gchar *key, gchar *value);
58 gchar* ags_priority_real_get_value(AgsPriority *priority, gchar *group, gchar *key);
59
60 /**
61 * SECTION:ags_priority
62 * @short_description: Priority Advanced Gtk+ Sequencer
63 * @title: AgsPriority
64 * @section_id:
65 * @include: ags/object/ags_priority.h
66 *
67 * #AgsPriority provides priorities to Advanced Gtk+ Sequencer.
68 */
69
70 enum{
71 LOAD_DEFAULTS,
72 SET_VALUE,
73 GET_VALUE,
74 LAST_SIGNAL,
75 };
76
77 enum{
78 PROP_0,
79 };
80
81 static gpointer ags_priority_parent_class = NULL;
82 static guint priority_signals[LAST_SIGNAL];
83
84 AgsPriority *ags_priority = NULL;
85
86 GType
ags_priority_get_type(void)87 ags_priority_get_type (void)
88 {
89 static volatile gsize g_define_type_id__volatile = 0;
90
91 if(g_once_init_enter (&g_define_type_id__volatile)){
92 GType ags_type_priority = 0;
93
94 static const GTypeInfo ags_priority_info = {
95 sizeof (AgsPriorityClass),
96 NULL, /* base_init */
97 NULL, /* base_finalize */
98 (GClassInitFunc) ags_priority_class_init,
99 NULL, /* class_finalize */
100 NULL, /* class_data */
101 sizeof (AgsPriority),
102 0, /* n_preallocs */
103 (GInstanceInitFunc) ags_priority_init,
104 };
105
106 ags_type_priority = g_type_register_static(G_TYPE_OBJECT,
107 "AgsPriority",
108 &ags_priority_info,
109 0);
110
111 g_once_init_leave(&g_define_type_id__volatile, ags_type_priority);
112 }
113
114 return g_define_type_id__volatile;
115 }
116
117 GType
ags_priority_flags_get_type()118 ags_priority_flags_get_type()
119 {
120 static volatile gsize g_flags_type_id__volatile;
121
122 if(g_once_init_enter (&g_flags_type_id__volatile)){
123 static const GFlagsValue values[] = {
124 { AGS_PRIORITY_CONNECTED, "AGS_PRIORITY_CONNECTED", "priority-connected" },
125 { 0, NULL, NULL }
126 };
127
128 GType g_flags_type_id = g_flags_register_static(g_intern_static_string("AgsPriorityFlags"), values);
129
130 g_once_init_leave (&g_flags_type_id__volatile, g_flags_type_id);
131 }
132
133 return g_flags_type_id__volatile;
134 }
135
136 void
ags_priority_class_init(AgsPriorityClass * priority)137 ags_priority_class_init(AgsPriorityClass *priority)
138 {
139 GObjectClass *gobject;
140 GParamSpec *param_spec;
141
142 ags_priority_parent_class = g_type_class_peek_parent(priority);
143
144 /* GObjectClass */
145 gobject = (GObjectClass *) priority;
146
147 gobject->set_property = ags_priority_set_property;
148 gobject->get_property = ags_priority_get_property;
149
150 gobject->dispose = ags_priority_dispose;
151 gobject->finalize = ags_priority_finalize;
152
153 /* properties */
154
155 /* AgsPriorityClass */
156 priority->load_defaults = ags_priority_real_load_defaults;
157 priority->set_value = ags_priority_real_set_value;
158 priority->get_value = ags_priority_real_get_value;
159
160 /* signals */
161 /**
162 * AgsPriority::load-defaults:
163 * @priority: the object to resolve
164 *
165 * The ::load-defaults signal notifies about loading defaults
166 *
167 * Since: 3.0.0
168 */
169 priority_signals[LOAD_DEFAULTS] =
170 g_signal_new("load-defaults",
171 G_TYPE_FROM_CLASS (priority),
172 G_SIGNAL_RUN_LAST,
173 G_STRUCT_OFFSET (AgsPriorityClass, load_defaults),
174 NULL, NULL,
175 g_cclosure_marshal_VOID__VOID,
176 G_TYPE_NONE, 0);
177
178
179 /**
180 * AgsPriority::set-value:
181 * @priority: the object to resolve
182 * @group: the group to apply to
183 * @key: the key to set
184 * @value: the value to apply
185 *
186 * The ::set-value signal notifies about value been setting.
187 *
188 * Since: 3.0.0
189 */
190 priority_signals[SET_VALUE] =
191 g_signal_new("set-value",
192 G_TYPE_FROM_CLASS (priority),
193 G_SIGNAL_RUN_LAST,
194 G_STRUCT_OFFSET (AgsPriorityClass, set_value),
195 NULL, NULL,
196 ags_cclosure_marshal_VOID__STRING_STRING_STRING,
197 G_TYPE_NONE, 3,
198 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
199
200 /**
201 * AgsPriority::get-value:
202 * @priority: the object to resolve
203 * @group: the group to retrieve from
204 * @key: the key to get
205 *
206 * The ::get-value signal notifies about value been getting.
207 *
208 * Returns: the value
209 *
210 * Since: 3.0.0
211 */
212 priority_signals[GET_VALUE] =
213 g_signal_new("get-value",
214 G_TYPE_FROM_CLASS (priority),
215 G_SIGNAL_RUN_LAST,
216 G_STRUCT_OFFSET (AgsPriorityClass, get_value),
217 NULL, NULL,
218 ags_cclosure_marshal_STRING__STRING_STRING,
219 G_TYPE_STRING, 2,
220 G_TYPE_STRING, G_TYPE_STRING);
221 }
222
223 void
ags_priority_init(AgsPriority * priority)224 ags_priority_init(AgsPriority *priority)
225 {
226 priority->flags = 0;
227
228 g_rec_mutex_init(&(priority->obj_mutex));
229
230 /* version and build id */
231 priority->version = g_strdup(AGS_PRIORITY_DEFAULT_VERSION);
232 priority->build_id = g_strdup(AGS_PRIORITY_DEFAULT_BUILD_ID);
233
234 priority->key_file = g_key_file_new();
235 g_key_file_ref(priority->key_file);
236 }
237
238 void
ags_priority_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)239 ags_priority_set_property(GObject *gobject,
240 guint prop_id,
241 const GValue *value,
242 GParamSpec *param_spec)
243 {
244 AgsPriority *priority;
245
246 GRecMutex *priority_mutex;
247
248 priority = AGS_PRIORITY(gobject);
249
250 /* get priority mutex */
251 priority_mutex = AGS_PRIORITY_GET_OBJ_MUTEX(priority);
252
253 switch(prop_id){
254 default:
255 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
256 break;
257 }
258 }
259
260 void
ags_priority_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)261 ags_priority_get_property(GObject *gobject,
262 guint prop_id,
263 GValue *value,
264 GParamSpec *param_spec)
265 {
266 AgsPriority *priority;
267
268 GRecMutex *priority_mutex;
269
270 priority = AGS_PRIORITY(gobject);
271
272 /* get priority mutex */
273 priority_mutex = AGS_PRIORITY_GET_OBJ_MUTEX(priority);
274
275 switch(prop_id){
276 default:
277 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
278 break;
279 }
280 }
281 void
ags_priority_dispose(GObject * gobject)282 ags_priority_dispose(GObject *gobject)
283 {
284 AgsPriority *priority;
285
286 priority = (AgsPriority *) gobject;
287
288 /* call parent */
289 G_OBJECT_CLASS(ags_priority_parent_class)->dispose(gobject);
290 }
291
292 void
ags_priority_finalize(GObject * gobject)293 ags_priority_finalize(GObject *gobject)
294 {
295 AgsPriority *priority;
296
297 priority = (AgsPriority *) gobject;
298
299 /* key file */
300 if(priority->key_file != NULL){
301 g_key_file_unref(priority->key_file);
302 }
303
304 /* global variable */
305 if(ags_priority == priority){
306 ags_priority = NULL;
307 }
308
309 /* call parent */
310 G_OBJECT_CLASS(ags_priority_parent_class)->finalize(gobject);
311 }
312
313 gchar*
ags_priority_get_version(AgsPriority * priority)314 ags_priority_get_version(AgsPriority *priority)
315 {
316 gchar *version;
317
318 GRecMutex *priority_mutex;
319
320 if(!AGS_IS_PRIORITY(priority)){
321 return(NULL);
322 }
323
324 priority_mutex = AGS_PRIORITY_GET_OBJ_MUTEX(priority);
325
326 /* get version */
327 g_rec_mutex_lock(priority_mutex);
328
329 version = priority->version;
330
331 g_rec_mutex_unlock(priority_mutex);
332
333 return(version);
334 }
335
336 void
ags_priority_set_version(AgsPriority * priority,gchar * version)337 ags_priority_set_version(AgsPriority *priority, gchar *version)
338 {
339 GRecMutex *priority_mutex;
340
341 if(!AGS_IS_PRIORITY(priority)){
342 return;
343 }
344
345 priority_mutex = AGS_PRIORITY_GET_OBJ_MUTEX(priority);
346
347 /* set version */
348 g_rec_mutex_lock(priority_mutex);
349
350 priority->version = g_strdup(version);
351
352 g_rec_mutex_unlock(priority_mutex);
353 }
354
355 gchar*
ags_priority_get_build_id(AgsPriority * priority)356 ags_priority_get_build_id(AgsPriority *priority)
357 {
358 gchar *build_id;
359
360 GRecMutex *priority_mutex;
361
362 if(!AGS_IS_PRIORITY(priority)){
363 return(NULL);
364 }
365
366 priority_mutex = AGS_PRIORITY_GET_OBJ_MUTEX(priority);
367
368 /* get build id */
369 g_rec_mutex_lock(priority_mutex);
370
371 build_id = priority->build_id;
372
373 g_rec_mutex_unlock(priority_mutex);
374
375 return(build_id);
376 }
377
378 void
ags_priority_set_build_id(AgsPriority * priority,gchar * build_id)379 ags_priority_set_build_id(AgsPriority *priority, gchar *build_id)
380 {
381 GRecMutex *priority_mutex;
382
383 if(!AGS_IS_PRIORITY(priority)){
384 return;
385 }
386
387 priority_mutex = AGS_PRIORITY_GET_OBJ_MUTEX(priority);
388
389 /* set version */
390 g_rec_mutex_lock(priority_mutex);
391
392 priority->build_id = g_strdup(build_id);
393
394 g_rec_mutex_unlock(priority_mutex);
395 }
396
397 void
ags_priority_real_load_defaults(AgsPriority * priority)398 ags_priority_real_load_defaults(AgsPriority *priority)
399 {
400
401 GRecMutex *priority_mutex;
402
403 priority_mutex = AGS_PRIORITY_GET_OBJ_MUTEX(priority);
404
405 /* load defaults */
406 g_rec_mutex_lock(priority_mutex);
407
408 ags_priority_set_value(priority, AGS_PRIORITY_RT_THREAD, AGS_PRIORITY_KEY_LIBAGS, "0"); // 45
409
410 ags_priority_set_value(priority, AGS_PRIORITY_RT_THREAD, AGS_PRIORITY_KEY_SERVER_MAIN_LOOP, "0"); // 15
411
412 ags_priority_set_value(priority, AGS_PRIORITY_RT_THREAD, AGS_PRIORITY_KEY_AUDIO_MAIN_LOOP, "0"); // 15
413 ags_priority_set_value(priority, AGS_PRIORITY_RT_THREAD, AGS_PRIORITY_KEY_AUDIO, "0"); // 45
414 ags_priority_set_value(priority, AGS_PRIORITY_RT_THREAD, AGS_PRIORITY_KEY_OSC_SERVER_MAIN_LOOP, "0"); // 15
415
416 ags_priority_set_value(priority, AGS_PRIORITY_RT_THREAD, AGS_PRIORITY_KEY_GUI_MAIN_LOOP, "0"); // 15
417
418 g_rec_mutex_unlock(priority_mutex);
419 }
420
421 /**
422 * ags_priority_load_defaults:
423 * @priority: the #AgsPriority
424 *
425 * Load priorities from default values.
426 *
427 * Since: 3.0.0
428 */
429 void
ags_priority_load_defaults(AgsPriority * priority)430 ags_priority_load_defaults(AgsPriority *priority)
431 {
432 g_return_if_fail(AGS_IS_PRIORITY(priority));
433
434 g_object_ref(G_OBJECT(priority));
435 g_signal_emit(G_OBJECT(priority),
436 priority_signals[LOAD_DEFAULTS], 0);
437 g_object_unref(G_OBJECT(priority));
438 }
439
440 /**
441 * ags_priority_load_from_file:
442 * @priority: the #AgsPriority
443 * @filename: the priorityuration file
444 *
445 * Load priorities from @filename.
446 *
447 * Since: 3.0.0
448 */
449 void
ags_priority_load_from_file(AgsPriority * priority,gchar * filename)450 ags_priority_load_from_file(AgsPriority *priority, gchar *filename)
451 {
452 GFile *file;
453
454 GRecMutex *priority_mutex;
455
456 if(!AGS_IS_PRIORITY(priority)){
457 return;
458 }
459
460 priority_mutex = AGS_PRIORITY_GET_OBJ_MUTEX(priority);
461
462 file = g_file_new_for_path(filename);
463
464 g_message("loading priorities for: %s", filename);
465
466 if(!g_file_query_exists(file,
467 NULL)){
468 ags_priority_load_defaults(priority);
469 }else{
470 GKeyFile *key_file;
471
472 gchar **groups, **groups_start;
473 gchar **keys, **keys_start;
474 gchar *value;
475
476 GError *error;
477
478 g_rec_mutex_lock(priority_mutex);
479
480 error = NULL;
481
482 key_file = g_key_file_new();
483 g_key_file_load_from_file(key_file,
484 filename,
485 G_KEY_FILE_NONE,
486 &error);
487
488 if(error != NULL){
489 g_warning("%s", error->message);
490
491 g_error_free(error);
492 }
493
494 groups =
495 groups_start = g_key_file_get_groups(key_file,
496 NULL);
497
498 while(*groups != NULL){
499 keys =
500 keys_start = g_key_file_get_keys(key_file,
501 *groups,
502 NULL,
503 NULL);
504
505 while(*keys != NULL){
506 value = g_key_file_get_value(key_file,
507 *groups,
508 *keys,
509 NULL);
510 ags_priority_set_value(priority,
511 *groups,
512 *keys,
513 value);
514
515 keys++;
516 }
517
518 g_strfreev(keys_start);
519
520 groups++;
521 }
522
523 g_strfreev(groups_start);
524 g_key_file_unref(key_file);
525
526 g_rec_mutex_unlock(priority_mutex);
527 }
528
529 g_object_unref(file);
530 }
531
532
533 void
ags_priority_real_set_value(AgsPriority * priority,gchar * group,gchar * key,gchar * value)534 ags_priority_real_set_value(AgsPriority *priority, gchar *group, gchar *key, gchar *value)
535 {
536 GRecMutex *priority_mutex;
537
538 priority_mutex = AGS_PRIORITY_GET_OBJ_MUTEX(priority);
539
540 /* set value */
541 g_rec_mutex_lock(priority_mutex);
542
543 g_key_file_set_value(priority->key_file, group, key, value);
544
545 g_rec_mutex_unlock(priority_mutex);
546 }
547
548 /**
549 * ags_priority_set_value:
550 * @priority: the #AgsPriority
551 * @group: the priority group identifier
552 * @key: the key of the property
553 * @value: the value to set
554 *
555 * Set priority by @group and @key, applying @value.
556 *
557 * Since: 3.0.0
558 */
559 void
ags_priority_set_value(AgsPriority * priority,gchar * group,gchar * key,gchar * value)560 ags_priority_set_value(AgsPriority *priority, gchar *group, gchar *key, gchar *value)
561 {
562 g_return_if_fail(AGS_IS_PRIORITY(priority));
563
564 g_object_ref(G_OBJECT(priority));
565 g_signal_emit(G_OBJECT(priority),
566 priority_signals[SET_VALUE], 0,
567 group, key, value);
568 g_object_unref(G_OBJECT(priority));
569 }
570
571 gchar*
ags_priority_real_get_value(AgsPriority * priority,gchar * group,gchar * key)572 ags_priority_real_get_value(AgsPriority *priority, gchar *group, gchar *key)
573 {
574 gchar *str;
575 GError *error;
576
577 GRecMutex *priority_mutex;
578
579 priority_mutex = AGS_PRIORITY_GET_OBJ_MUTEX(priority);
580
581 /* get value */
582 g_rec_mutex_lock(priority_mutex);
583
584 error = NULL;
585
586 str = g_key_file_get_value(priority->key_file, group, key, &error);
587
588 if(error != NULL){
589 // g_warning("%s", error->message);
590
591 g_error_free(error);
592 }
593
594 g_rec_mutex_unlock(priority_mutex);
595
596 return(str);
597 }
598
599 /**
600 * ags_priority_get_value:
601 * @priority: the #AgsPriority
602 * @group: the priority group identifier
603 * @key: the key of the property
604 *
605 * Retrieve priority by @group and @key.
606 *
607 * Returns: (transfer full): the property's value
608 *
609 * Since: 3.0.0
610 */
611 gchar*
ags_priority_get_value(AgsPriority * priority,gchar * group,gchar * key)612 ags_priority_get_value(AgsPriority *priority, gchar *group, gchar *key)
613 {
614 gchar *value;
615
616 g_return_val_if_fail(AGS_IS_PRIORITY(priority), NULL);
617
618 g_object_ref(G_OBJECT(priority));
619 g_signal_emit(G_OBJECT(priority),
620 priority_signals[GET_VALUE], 0,
621 group, key,
622 &value);
623 g_object_unref(G_OBJECT(priority));
624
625 return(value);
626 }
627
628 /**
629 * ags_priority_get_instance:
630 *
631 * Get priority instance.
632 *
633 * Returns: (transfer none): the priority instance
634 *
635 * Since: 3.0.0
636 */
637 AgsPriority*
ags_priority_get_instance()638 ags_priority_get_instance()
639 {
640 static GMutex mutex;
641
642 g_mutex_lock(&mutex);
643
644 if(ags_priority == NULL){
645 ags_priority = ags_priority_new(NULL);
646 }
647
648 g_mutex_unlock(&mutex);
649
650 return(ags_priority);
651 }
652
653 /**
654 * ags_priority_new:
655 *
656 * Create a new instance of #AgsPriority.
657 *
658 * Returns: the new #AgsPriority.
659 *
660 * Since: 3.0.0
661 */
662 AgsPriority*
ags_priority_new()663 ags_priority_new()
664 {
665 AgsPriority *priority;
666
667 priority = (AgsPriority *) g_object_new(AGS_TYPE_PRIORITY,
668 NULL);
669
670 return(priority);
671 }
672