1 //##############################################################################
2 // volumeicon
3 //
4 // config.c - a singleton providing configuration values/functions
5 //
6 // Copyright 2011 Maato
7 //
8 // Authors:
9 // Maato <maato@softwarebakery.com>
10 //
11 // This program is free software: you can redistribute it and/or modify it
12 // under the terms of the GNU General Public License version 3, as published
13 // by the Free Software Foundation.
14 //
15 // This program is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranties of
17 // MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
18 // PURPOSE. See the GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License along
21 // with this program. If not, see <http://www.gnu.org/licenses/>.
22 //##############################################################################
23
24 #include <glib/gstdio.h>
25 #include <assert.h>
26
27 #include "config.h"
28
29 //##############################################################################
30 // Definitions
31 //##############################################################################
32 #define CONFIG_DIRNAME "volumeicon"
33 #define CONFIG_FILENAME "volumeicon"
34
35 //##############################################################################
36 // Static variables
37 //##############################################################################
38 static struct config {
39 gchar *path;
40
41 // Alsa
42 gchar *card; // TODO: Rename this to device.
43 gchar *channel;
44
45 // Notifications
46 gboolean show_notification;
47 gint notification_type;
48
49 // Status icon
50 int stepsize; // TODO: Rename this to volume_stepsize.
51 gchar *helper_program;
52 gchar *theme;
53 gboolean use_panel_specific_icons;
54
55 // Left mouse button action
56 gboolean lmb_slider;
57
58 // Middle mouse button action
59 gboolean mmb_mute;
60
61 // Layout
62 gboolean use_horizontal_slider;
63 gboolean show_sound_level;
64 gboolean use_transparent_background;
65
66 // Hotkeys
67 gboolean hotkey_up_enabled;
68 gboolean hotkey_down_enabled;
69 gboolean hotkey_mute_enabled;
70 gchar *hotkey_up;
71 gchar *hotkey_down;
72 gchar *hotkey_mute;
73 } m_config = {
74 .path = NULL,
75
76 // Alsa
77 .card = NULL,
78 .channel = NULL,
79
80 // Notifications
81 .show_notification = TRUE,
82 .notification_type = 0,
83
84 // Status icon
85 .stepsize = 0,
86 .helper_program = NULL,
87 .theme = NULL,
88 .use_panel_specific_icons = FALSE,
89
90 // Left mouse button action
91 .lmb_slider = FALSE,
92
93 // Middle mouse button action
94 .mmb_mute = FALSE,
95
96 // Layout
97 .use_horizontal_slider = FALSE,
98 .show_sound_level = FALSE,
99 .use_transparent_background = FALSE,
100
101 // Hotkeys
102 .hotkey_up_enabled = FALSE,
103 .hotkey_down_enabled = FALSE,
104 .hotkey_mute_enabled = FALSE,
105 .hotkey_up = NULL,
106 .hotkey_down = NULL,
107 .hotkey_mute = NULL
108 };
109
110 //##############################################################################
111 // Static functions
112 //##############################################################################
config_load_default(void)113 static void config_load_default(void)
114 {
115 if(!m_config.helper_program)
116 config_set_helper(DEFAULT_MIXERAPP);
117 if(!m_config.channel)
118 config_set_channel(NULL);
119 if(!m_config.card)
120 config_set_card("default");
121 if(!m_config.stepsize)
122 config_set_stepsize(5);
123 if(!m_config.theme)
124 config_set_theme("Default");
125 if(!m_config.hotkey_up)
126 config_set_hotkey_up("XF86AudioRaiseVolume");
127 if(!m_config.hotkey_down)
128 config_set_hotkey_down("XF86AudioLowerVolume");
129 if(!m_config.hotkey_mute)
130 config_set_hotkey_mute("XF86AudioMute");
131 }
132
config_read(void)133 static void config_read(void)
134 {
135 // Clean up previously loaded configuration values
136 m_config.stepsize = 0;
137 g_free(m_config.helper_program);
138 g_free(m_config.channel);
139 g_free(m_config.theme);
140
141 // Load keys from keyfile
142 GKeyFile *kf = g_key_file_new();
143 g_key_file_load_from_file(kf, m_config.path, G_KEY_FILE_NONE, NULL);
144
145 #define GET_VALUE(type, section, key) \
146 g_key_file_get_##type(kf, section, key, NULL)
147 #define GET_STRING(s, k) GET_VALUE(value, s, k)
148 #define GET_BOOL(s, k) GET_VALUE(boolean, s, k)
149 #define GET_INT(s, k) GET_VALUE(integer, s, k)
150
151 // Alsa
152 m_config.card = GET_STRING("Alsa", "card");
153 m_config.channel = GET_STRING("Alsa", "channel");
154
155 // Notifications
156 m_config.show_notification = GET_BOOL("Notification", "show_notification");
157 m_config.notification_type = GET_INT("Notification", "notification_type");
158
159 // Status icon
160 m_config.stepsize = GET_INT("StatusIcon", "stepsize");
161 m_config.helper_program = GET_STRING("StatusIcon", "onclick");
162 m_config.theme = GET_STRING("StatusIcon", "theme");
163 m_config.use_panel_specific_icons = GET_BOOL(
164 "StatusIcon", "use_panel_specific_icons");
165
166 // Left mouse button action
167 m_config.lmb_slider = GET_BOOL("StatusIcon", "lmb_slider");
168
169 // Middle mouse button action
170 m_config.mmb_mute = GET_BOOL("StatusIcon", "mmb_mute");
171
172 // Layout
173 m_config.use_horizontal_slider = GET_BOOL(
174 "StatusIcon", "use_horizontal_slider");
175 m_config.show_sound_level = GET_BOOL("StatusIcon", "show_sound_level");
176 m_config.use_transparent_background = GET_BOOL(
177 "StatusIcon", "use_transparent_background");
178
179 // Hotkeys
180 m_config.hotkey_up_enabled = GET_BOOL("Hotkeys", "up_enabled");
181 m_config.hotkey_down_enabled = GET_BOOL("Hotkeys", "down_enabled");
182 m_config.hotkey_mute_enabled = GET_BOOL("Hotkeys", "mute_enabled");
183 m_config.hotkey_up = GET_STRING("Hotkeys", "up");
184 m_config.hotkey_down = GET_STRING("Hotkeys", "down");
185 m_config.hotkey_mute = GET_STRING("Hotkeys", "mute");
186
187 g_key_file_free(kf);
188
189 #undef GET_VALUE
190 #undef GET_STRING
191 #undef GET_BOOL
192 #undef GET_INT
193
194 // Load default values for unset keys
195 config_load_default();
196 }
197
198 //##############################################################################
199 // Exported setter functions
200 //##############################################################################
201
202 // Alsa
config_set_card(const gchar * card)203 void config_set_card(const gchar *card)
204 {
205 g_free(m_config.card);
206 m_config.card = g_strdup(card);
207 }
208
config_set_channel(const gchar * channel)209 void config_set_channel(const gchar *channel)
210 {
211 g_free(m_config.channel);
212 m_config.channel = g_strdup(channel);
213 }
214
215 // Notifications
config_set_show_notification(gboolean active)216 void config_set_show_notification(gboolean active)
217 {
218 m_config.show_notification = active;
219 }
220
config_set_notification_type(gint type)221 void config_set_notification_type(gint type)
222 {
223 m_config.notification_type = type;
224 }
225
226 // Status icon
config_set_stepsize(int stepsize)227 void config_set_stepsize(int stepsize)
228 {
229 m_config.stepsize = stepsize;
230 }
231
config_set_helper(const gchar * helper)232 void config_set_helper(const gchar *helper)
233 {
234 g_free(m_config.helper_program);
235 m_config.helper_program = g_strdup(helper);
236 }
237
config_set_theme(const gchar * theme)238 void config_set_theme(const gchar *theme)
239 {
240 g_free(m_config.theme);
241 m_config.theme = g_strdup(theme);
242 }
243
config_set_use_panel_specific_icons(gboolean active)244 void config_set_use_panel_specific_icons(gboolean active)
245 {
246 m_config.use_panel_specific_icons = active;
247 }
248
249 // Left mouse button action
config_set_left_mouse_slider(gboolean active)250 void config_set_left_mouse_slider(gboolean active)
251 {
252 m_config.lmb_slider = active;
253 }
254
255 // Middle mouse button action
config_set_middle_mouse_mute(gboolean active)256 void config_set_middle_mouse_mute(gboolean active)
257 {
258 m_config.mmb_mute = active;
259 }
260
261 // Layout
config_set_use_horizontal_slider(gboolean active)262 void config_set_use_horizontal_slider(gboolean active)
263 {
264 m_config.use_horizontal_slider = active;
265 }
266
config_set_show_sound_level(gboolean active)267 void config_set_show_sound_level(gboolean active)
268 {
269 m_config.show_sound_level = active;
270 }
271
config_set_use_transparent_background(gboolean active)272 void config_set_use_transparent_background(gboolean active)
273 {
274 m_config.use_transparent_background = active;
275 }
276
277 // Hotkey
config_set_hotkey_up_enabled(gboolean enabled)278 void config_set_hotkey_up_enabled(gboolean enabled)
279 {
280 m_config.hotkey_up_enabled = enabled;
281 }
282
config_set_hotkey_down_enabled(gboolean enabled)283 void config_set_hotkey_down_enabled(gboolean enabled)
284 {
285 m_config.hotkey_down_enabled = enabled;
286 }
287
config_set_hotkey_mute_enabled(gboolean enabled)288 void config_set_hotkey_mute_enabled(gboolean enabled)
289 {
290 m_config.hotkey_mute_enabled = enabled;
291 }
292
config_set_hotkey_up(const gchar * up)293 void config_set_hotkey_up(const gchar *up)
294 {
295 g_free(m_config.hotkey_up);
296 m_config.hotkey_up = g_strdup(up);
297 }
298
config_set_hotkey_down(const gchar * down)299 void config_set_hotkey_down(const gchar *down)
300 {
301 g_free(m_config.hotkey_down);
302 m_config.hotkey_down = g_strdup(down);
303 }
304
config_set_hotkey_mute(const gchar * mute)305 void config_set_hotkey_mute(const gchar *mute)
306 {
307 g_free(m_config.hotkey_mute);
308 m_config.hotkey_mute = g_strdup(mute);
309 }
310
311 //##############################################################################
312 // Exported getter functions
313 //##############################################################################
314
315 // Alsa
config_get_card(void)316 const gchar *config_get_card(void)
317 {
318 return m_config.card;
319 }
320
config_get_channel(void)321 const gchar *config_get_channel(void)
322 {
323 return m_config.channel;
324 }
325
326 // Notifications
config_get_show_notification(void)327 gboolean config_get_show_notification(void)
328 {
329 return m_config.show_notification;
330 }
331
config_get_notification_type(void)332 gint config_get_notification_type(void)
333 {
334 return m_config.notification_type;
335 }
336
337 // Status icon
config_get_stepsize(void)338 int config_get_stepsize(void)
339 {
340 return m_config.stepsize;
341 }
342
config_get_helper(void)343 const gchar *config_get_helper(void)
344 {
345 return m_config.helper_program;
346 }
347
config_get_theme(void)348 const gchar *config_get_theme(void)
349 {
350 return m_config.theme;
351 }
352
config_get_use_gtk_theme(void)353 gboolean config_get_use_gtk_theme(void)
354 {
355 return g_strcmp0(m_config.theme, "Default") == 0 ? TRUE : FALSE;
356 }
357
config_get_use_panel_specific_icons(void)358 gboolean config_get_use_panel_specific_icons(void)
359 {
360 return m_config.use_panel_specific_icons;
361 }
362
363 // Left mouse button action
config_get_left_mouse_slider(void)364 gboolean config_get_left_mouse_slider(void)
365 {
366 return m_config.lmb_slider;
367 }
368
369 // Middle mouse button action
config_get_middle_mouse_mute(void)370 gboolean config_get_middle_mouse_mute(void)
371 {
372 return m_config.mmb_mute;
373 }
374
375 // Layout
config_get_use_horizontal_slider(void)376 gboolean config_get_use_horizontal_slider(void)
377 {
378 return m_config.use_horizontal_slider;
379 }
380
config_get_show_sound_level(void)381 gboolean config_get_show_sound_level(void)
382 {
383 return m_config.show_sound_level;
384 }
385
config_get_use_transparent_background(void)386 gboolean config_get_use_transparent_background(void)
387 {
388 return m_config.use_transparent_background;
389 }
390
391 // Hotkeys
config_get_hotkey_up_enabled(void)392 gboolean config_get_hotkey_up_enabled(void)
393 {
394 return m_config.hotkey_up_enabled;
395 }
396
config_get_hotkey_down_enabled(void)397 gboolean config_get_hotkey_down_enabled(void)
398 {
399 return m_config.hotkey_down_enabled;
400 }
401
config_get_hotkey_mute_enabled(void)402 gboolean config_get_hotkey_mute_enabled(void)
403 {
404 return m_config.hotkey_mute_enabled;
405 }
406
config_get_hotkey_up(void)407 const gchar *config_get_hotkey_up(void)
408 {
409 return m_config.hotkey_up;
410 }
411
config_get_hotkey_down(void)412 const gchar *config_get_hotkey_down(void)
413 {
414 return m_config.hotkey_down;
415 }
416
config_get_hotkey_mute(void)417 const gchar *config_get_hotkey_mute(void)
418 {
419 return m_config.hotkey_mute;
420 }
421
422 //##############################################################################
423 // Exported miscellaneous functions
424 //##############################################################################
config_write(void)425 void config_write(void)
426 {
427 assert(m_config.path);
428
429 GKeyFile *kf = g_key_file_new();
430
431 #define SET_VALUE(type, section, key, value) \
432 g_key_file_set_##type(kf, section, key, value)
433 #define SET_STRING(s, k, v) SET_VALUE(value, s, k, v)
434 #define SET_BOOL(s, k, v) SET_VALUE(boolean, s, k, v)
435 #define SET_INT(s, k, v) SET_VALUE(integer, s, k, v)
436
437 // Alsa
438 if(m_config.card)
439 SET_STRING("Alsa", "card", m_config.card);
440 if(m_config.channel)
441 SET_STRING("Alsa", "channel", m_config.channel);
442
443 // Notifications
444 SET_BOOL("Notification", "show_notification", m_config.show_notification);
445 SET_INT("Notification", "notification_type", m_config.notification_type);
446
447 // Status icon
448 SET_INT("StatusIcon", "stepsize", m_config.stepsize);
449 if(m_config.helper_program)
450 SET_STRING("StatusIcon", "onclick", m_config.helper_program);
451 if(m_config.theme)
452 SET_STRING("StatusIcon", "theme", m_config.theme);
453 SET_BOOL("StatusIcon", "use_panel_specific_icons",
454 m_config.use_panel_specific_icons);
455
456 // Left mouse button action
457 SET_BOOL("StatusIcon", "lmb_slider", m_config.lmb_slider);
458
459 // Middle mouse button action
460 SET_BOOL("StatusIcon", "mmb_mute", m_config.mmb_mute);
461
462 // Layout
463 SET_BOOL("StatusIcon", "use_horizontal_slider",
464 m_config.use_horizontal_slider);
465 SET_BOOL("StatusIcon", "show_sound_level", m_config.show_sound_level);
466 SET_BOOL("StatusIcon", "use_transparent_background",
467 m_config.use_transparent_background);
468
469 // Hotkeys
470 SET_BOOL("Hotkeys", "up_enabled", m_config.hotkey_up_enabled);
471 SET_BOOL("Hotkeys", "down_enabled", m_config.hotkey_down_enabled);
472 SET_BOOL("Hotkeys", "mute_enabled", m_config.hotkey_mute_enabled);
473 if(m_config.hotkey_up)
474 SET_STRING("Hotkeys", "up", m_config.hotkey_up);
475 if(m_config.hotkey_down)
476 SET_STRING("Hotkeys", "down", m_config.hotkey_down);
477 if(m_config.hotkey_mute)
478 SET_STRING("Hotkeys", "mute", m_config.hotkey_mute);
479
480 gchar *data = g_key_file_to_data(kf, NULL, NULL);
481 g_key_file_free(kf);
482 g_file_set_contents(m_config.path, data, -1, NULL);
483 g_free(data);
484
485 #undef SET_VALUE
486 #undef SET_STRING
487 #undef SET_BOOL
488 #undef SET_INT
489 }
490
config_initialize(gchar * config_name)491 void config_initialize(gchar *config_name)
492 {
493 // Build config directory name
494 gchar *config_dir = g_build_filename(g_get_user_config_dir(),
495 CONFIG_DIRNAME, NULL);
496 m_config.path = g_build_filename(
497 config_dir, config_name ? config_name : CONFIG_FILENAME, NULL);
498
499 // Make sure config directory exists
500 if(!g_file_test(config_dir, G_FILE_TEST_IS_DIR))
501 g_mkdir(config_dir, 0777);
502
503 // If a config file doesn't exist, create one with defaults otherwise
504 // read the existing one.
505 if(!g_file_test(m_config.path, G_FILE_TEST_EXISTS))
506 {
507 config_load_default();
508 config_write();
509 }
510 else
511 {
512 config_read();
513 }
514
515 g_free(config_dir);
516 }
517
518