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