pnmixer
Volume mixer for the system tray
ui-prefs-dialog.c
Go to the documentation of this file.
1 /* ui-prefs-dialog.c
2  * PNmixer is written by Nick Lanham, a fork of OBmixer
3  * which was programmed by Lee Ferrett, derived
4  * from the program "AbsVolume" by Paul Sherman
5  * This program is free software; you can redistribute
6  * it and/or modify it under the terms of the GNU General
7  * Public License v3. source code is available at
8  * <http://github.com/nicklan/pnmixer>
9  */
10 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include <stdlib.h>
22 #include <string.h>
23 #include <glib.h>
24 #include <gtk/gtk.h>
25 #include <gdk/gdk.h>
26 #include <gdk/gdkx.h>
27 #ifndef WITH_GTK3
28 #include <gdk/gdkkeysyms.h>
29 #endif
30 
31 #include "audio.h"
32 #include "prefs.h"
33 #include "hotkey.h"
34 #include "hotkeys.h"
35 #include "support-log.h"
36 #include "support-intl.h"
37 #include "support-ui.h"
38 #include "ui-prefs-dialog.h"
39 #include "ui-hotkey-dialog.h"
40 
41 #include "main.h"
42 
43 #ifdef WITH_GTK3
44 #define PREFS_UI_FILE "prefs-dialog-gtk3.glade"
45 #else
46 #define PREFS_UI_FILE "prefs-dialog-gtk2.glade"
47 #endif
48 
49 /* Helpers */
50 
51 /* Gets one of the hotkey code and mode in the Hotkeys settings
52  * from the specified label (parsed as an accelerator name).
53  */
54 static void
55 get_keycode_for_label(GtkLabel *label, gint *code, GdkModifierType *mods)
56 {
57  const gchar *key_accel;
58 
59  key_accel = gtk_label_get_text(label);
60  hotkey_accel_to_code(key_accel, code, mods);
61 }
62 
63 /* Sets one of the hotkey labels in the Hotkeys settings
64  * to the specified keycode (converted to a accelerator name).
65  */
66 static void
67 set_label_for_keycode(GtkLabel *label, gint code, GdkModifierType mods)
68 {
69  gchar *key_accel;
70 
71  if (code < 0)
72  return;
73 
74  key_accel = hotkey_code_to_accel(code, mods);
75  gtk_label_set_text(label, key_accel);
76  g_free(key_accel);
77 }
78 
88 static void
89 fill_chan_combo(GtkComboBoxText *combo, const gchar *card_name)
90 {
91  int idx, sidx;
92  gchar *selected_channel;
93  GSList *channel_list, *item;
94 
95  DEBUG("Filling channels ComboBox for card '%s'", card_name);
96 
97  selected_channel = prefs_get_channel(card_name);
98  channel_list = audio_get_channel_list(card_name);
99 
100  /* Empty the combo box */
102 
103  /* Fill the combo box with the channels, save the selected channel index */
104  for (sidx = idx = 0, item = channel_list; item; idx++, item = item->next) {
105  const char *channel_name = item->data;
106  gtk_combo_box_text_append_text(combo, channel_name);
107 
108  if (!g_strcmp0(channel_name, selected_channel))
109  sidx = idx;
110  }
111 
112  /* Set the combo box active item */
113  gtk_combo_box_set_active(GTK_COMBO_BOX(combo), sidx);
114 
115  /* Cleanup */
116  g_slist_free_full(channel_list, g_free);
117  g_free(selected_channel);
118 }
119 
128 static void
129 fill_card_combo(GtkComboBoxText *combo, Audio *audio)
130 {
131  int idx, sidx;
132  const gchar *active_card;
133  GSList *card_list, *item;
134 
135  DEBUG("Filling cards ComboBox");
136 
137  active_card = audio_get_card(audio);
138  card_list = audio_get_card_list();
139 
140  /* Empty the combo box */
142 
143  /* Fill the combo box with the cards, save the active card index */
144  for (sidx = idx = 0, item = card_list; item; idx++, item = item->next) {
145  const char *card_name = item->data;
146  gtk_combo_box_text_append_text(combo, card_name);
147 
148  if (!g_strcmp0(card_name, active_card))
149  sidx = idx;
150  }
151 
152  /* Set the combo box active item */
153  gtk_combo_box_set_active(GTK_COMBO_BOX(combo), sidx);
154 
155  /* Cleanup */
156  g_slist_free_full(card_list, g_free);
157 }
158 
159 /* Public functions & signals handlers */
160 
161 struct prefs_dialog {
162  /* Dialog response handling (when OK/Cancel buttons are clicked) */
165  /* Audio system
166  * We need it to display card/channel lists, and also to be notified
167  * if something interesting happens (card disappearing, for example).
168  */
170  /* Hotkeys system
171  * When assigning hotkeys, we must unbind the hotkeys first.
172  * Otherwise the currently assigned keys are intercepted
173  * and can't be used.
174  */
177  /* Top-level widgets */
178  GtkWidget *prefs_dialog;
179  GtkWidget *notebook;
180  GtkWidget *ok_button;
181  GtkWidget *cancel_button;
182  /* View panel */
184  GtkWidget *vol_text_check;
185  GtkWidget *vol_pos_label;
186  GtkWidget *vol_pos_combo;
189  GtkWidget *vol_meter_pos_spin;
190  GtkAdjustment *vol_meter_pos_adjustment;
193  GtkWidget *system_theme;
194  /* Device panel */
195  GtkWidget *card_combo;
196  GtkWidget *chan_combo;
198  /* Behavior panel */
199  GtkWidget *vol_control_entry;
200  GtkWidget *scroll_step_spin;
202  GtkWidget *middle_click_combo;
203  GtkWidget *custom_label;
204  GtkWidget *custom_entry;
205  /* Hotkeys panel */
207  GtkWidget *hotkeys_grid;
209  GtkWidget *hotkeys_mute_label;
211  GtkWidget *hotkeys_up_label;
213  GtkWidget *hotkeys_down_label;
214  /* Notifications panel */
215 #ifdef WITH_LIBNOTIFY
216  GtkWidget *noti_vbox_enabled;
217  GtkWidget *noti_enable_check;
218  GtkWidget *noti_timeout_label;
219  GtkWidget *noti_timeout_spin;
220  GtkWidget *noti_hotkey_check;
221  GtkWidget *noti_mouse_check;
222  GtkWidget *noti_popup_check;
223  GtkWidget *noti_ext_check;
224 #else
225  GtkWidget *noti_vbox_disabled;
226 #endif
227 };
228 
236 void
237 on_vol_text_check_toggled(GtkToggleButton *button, PrefsDialog *dialog)
238 {
239  gboolean active = gtk_toggle_button_get_active(button);
240  gtk_widget_set_sensitive(dialog->vol_pos_label, active);
241  gtk_widget_set_sensitive(dialog->vol_pos_combo, active);
242 }
243 
251 void
252 on_vol_meter_draw_check_toggled(GtkToggleButton *button, PrefsDialog *dialog)
253 {
254  gboolean active = gtk_toggle_button_get_active(button);
255  gtk_widget_set_sensitive(dialog->vol_meter_pos_label, active);
256  gtk_widget_set_sensitive(dialog->vol_meter_pos_spin, active);
257  gtk_widget_set_sensitive(dialog->vol_meter_color_label, active);
258  gtk_widget_set_sensitive(dialog->vol_meter_color_button, active);
259 }
260 
268 void
269 on_card_combo_changed(GtkComboBoxText *box, PrefsDialog *dialog)
270 {
271  gchar *card_name;
272 
273  card_name = gtk_combo_box_text_get_active_text(box);
274  fill_chan_combo(GTK_COMBO_BOX_TEXT(dialog->chan_combo), card_name);
275  g_free(card_name);
276 }
277 
285 void
286 on_middle_click_combo_changed(GtkComboBoxText *box, PrefsDialog *dialog)
287 {
288  gboolean cust = gtk_combo_box_get_active(GTK_COMBO_BOX(box)) == 3;
289  gtk_widget_set_sensitive(dialog->custom_label, cust);
290  gtk_widget_set_sensitive(dialog->custom_entry, cust);
291 }
292 
300 void
301 on_hotkeys_enable_check_toggled(GtkToggleButton *button, PrefsDialog *dialog)
302 {
303  gboolean active = gtk_toggle_button_get_active(button);
304  gtk_widget_set_sensitive(dialog->hotkeys_grid, active);
305 }
306 
319 gboolean
320 on_hotkey_event_box_button_press_event(GtkWidget *widget, GdkEventButton *event,
321  PrefsDialog *dialog)
322 {
323  const gchar *hotkey;
324  GtkLabel *hotkey_label;
325  gchar *key_pressed;
326 
327  /* We want a left-click */
328  if (event->button != 1)
329  return FALSE;
330 
331  /* We want it to be double-click */
332  if (event->type != GDK_2BUTTON_PRESS)
333  return FALSE;
334 
335  /* Let's check which eventbox was clicked */
336  hotkey = NULL;
337  if (widget == dialog->hotkeys_mute_eventbox) {
338  hotkey_label = GTK_LABEL(dialog->hotkeys_mute_label);
339  hotkey = _("Mute/Unmute");
340  } else if (widget == dialog->hotkeys_up_eventbox) {
341  hotkey_label = GTK_LABEL(dialog->hotkeys_up_label);
342  hotkey = _("Volume Up");
343  } else if (widget == dialog->hotkeys_down_eventbox) {
344  hotkey_label = GTK_LABEL(dialog->hotkeys_down_label);
345  hotkey = _("Volume Down");
346  }
347  g_assert(hotkey);
348 
349  /* Ensure there's no dialog already running */
350  if (dialog->hotkey_dialog)
351  return FALSE;
352 
353  /* Unbind hotkeys */
354  hotkeys_unbind(dialog->hotkeys);
355 
356  /* Run the hotkey dialog */
358  (GTK_WINDOW(dialog->prefs_dialog), hotkey);
359  key_pressed = hotkey_dialog_run(dialog->hotkey_dialog);
361  dialog->hotkey_dialog = NULL;
362 
363  /* Bind hotkeys */
364  hotkeys_bind(dialog->hotkeys);
365 
366  /* Check the response */
367  if (key_pressed == NULL)
368  return FALSE;
369 
370  /* <Primary>c is used to disable the hotkey */
371  if (!g_ascii_strcasecmp(key_pressed, "<Primary>c")) {
372  g_free(key_pressed);
373  key_pressed = g_strdup_printf("(%s)", _("None"));
374  }
375 
376  /* Set */
377  gtk_label_set_text(hotkey_label, key_pressed);
378  g_free(key_pressed);
379 
380  return FALSE;
381 }
382 
390 #ifdef WITH_LIBNOTIFY
391 void
392 on_noti_enable_check_toggled(GtkToggleButton *button, PrefsDialog *dialog)
393 {
394  gboolean active = gtk_toggle_button_get_active(button);
395  gtk_widget_set_sensitive(dialog->noti_timeout_label, active);
396  gtk_widget_set_sensitive(dialog->noti_timeout_spin, active);
397  gtk_widget_set_sensitive(dialog->noti_hotkey_check, active);
398  gtk_widget_set_sensitive(dialog->noti_mouse_check, active);
399  gtk_widget_set_sensitive(dialog->noti_popup_check, active);
400  gtk_widget_set_sensitive(dialog->noti_ext_check, active);
401 }
402 #else
403 void
404 on_noti_enable_check_toggled(G_GNUC_UNUSED GtkToggleButton *button,
405  G_GNUC_UNUSED PrefsDialog *dialog)
406 {
407 }
408 #endif
409 
418 static void
419 on_prefs_dialog_response(G_GNUC_UNUSED GtkDialog *widget,
420  gint response_id, PrefsDialog *dialog)
421 {
422  dialog->response_user_cb(dialog, response_id);
423 }
424 
432 static void
433 on_audio_changed(Audio *audio, AudioEvent *event, gpointer data)
434 {
435  PrefsDialog *dialog = (PrefsDialog *) data;
436  GtkComboBoxText *card_combo = GTK_COMBO_BOX_TEXT(dialog->card_combo);
437  GtkComboBoxText *chan_combo = GTK_COMBO_BOX_TEXT(dialog->chan_combo);
438 
439  switch (event->signal) {
442  /* A card may have appeared or disappeared */
443  fill_card_combo(card_combo, audio);
444  fill_chan_combo(chan_combo, audio_get_card(audio));
445  break;
446  default:
447  break;
448  }
449 }
450 
455 void
457 {
458  DEBUG("Retrieving prefs dialog values");
459 
460  // volume slider orientation
461  GtkWidget *soc = dialog->vol_orientation_combo;
462  const gchar *orientation;
463 #ifdef WITH_GTK3
464  orientation = gtk_combo_box_get_active_id(GTK_COMBO_BOX(soc));
465 #else
466  /* Gtk2 ComboBoxes don't have item ids */
467  orientation = "vertical";
468  if (gtk_combo_box_get_active(GTK_COMBO_BOX(soc)) == 1)
469  orientation = "horizontal";
470 #endif
471  prefs_set_string("SliderOrientation", orientation);
472 
473  // volume text display
474  GtkWidget *vtc = dialog->vol_text_check;
475  gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(vtc));
476  prefs_set_boolean("DisplayTextVolume", active);
477 
478  // volume text position
479  GtkWidget *vpc = dialog->vol_pos_combo;
480  gint idx = gtk_combo_box_get_active(GTK_COMBO_BOX(vpc));
481  prefs_set_integer("TextVolumePosition", idx);
482 
483  // volume meter display
484  GtkWidget *dvc = dialog->vol_meter_draw_check;
485  active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dvc));
486  prefs_set_boolean("DrawVolMeter", active);
487 
488  // volume meter position
489  GtkWidget *vmps = dialog->vol_meter_pos_spin;
490  gint vmpos = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(vmps));
491  prefs_set_integer("VolMeterPos", vmpos);
492 
493  // volume meter colors
494  GtkWidget *vcb = dialog->vol_meter_color_button;
495  gdouble colors[3];
496 #ifdef WITH_GTK3
497  GdkRGBA color;
498  gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(vcb), &color);
499  colors[0] = color.red;
500  colors[1] = color.green;
501  colors[2] = color.blue;
502 #else
503  GdkColor color;
504  gtk_color_button_get_color(GTK_COLOR_BUTTON(vcb), &color);
505  colors[0] = (gdouble) color.red / 65536;
506  colors[1] = (gdouble) color.green / 65536;
507  colors[2] = (gdouble) color.blue / 65536;
508 #endif
509  prefs_set_double_list("VolMeterColor", colors, 3);
510 
511  // icon theme
512  GtkWidget *system_theme = dialog->system_theme;
513  active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(system_theme));
514  prefs_set_boolean("SystemTheme", active);
515 
516  // audio card
517  GtkWidget *acc = dialog->card_combo;
518  gchar *card = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(acc));
519  prefs_set_string("AlsaCard", card);
520 
521  // audio channel
522  GtkWidget *ccc = dialog->chan_combo;
523  gchar *chan = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(ccc));
524  prefs_set_channel(card, chan);
525  g_free(card);
526  g_free(chan);
527 
528  // normalize volume
529  GtkWidget *vnorm = dialog->normalize_vol_check;
530  gboolean is_pressed;
531  is_pressed = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(vnorm));
532  prefs_set_boolean("NormalizeVolume", is_pressed);
533 
534  // volume control command
535  GtkWidget *ve = dialog->vol_control_entry;
536  const gchar *vc = gtk_entry_get_text(GTK_ENTRY(ve));
537  prefs_set_string("VolumeControlCommand", vc);
538 
539  // volume scroll steps
540  GtkWidget *sss = dialog->scroll_step_spin;
541  gdouble step = gtk_spin_button_get_value(GTK_SPIN_BUTTON(sss));
542  prefs_set_double("ScrollStep", step);
543 
544  GtkWidget *fsss = dialog->fine_scroll_step_spin;
545  gdouble fine_step = gtk_spin_button_get_value(GTK_SPIN_BUTTON(fsss));
546  prefs_set_double("FineScrollStep", fine_step);
547 
548  // middle click
549  GtkWidget *mcc = dialog->middle_click_combo;
550  idx = gtk_combo_box_get_active(GTK_COMBO_BOX(mcc));
551  prefs_set_integer("MiddleClickAction", idx);
552 
553  // custom command
554  GtkWidget *ce = dialog->custom_entry;
555  const gchar *cc = gtk_entry_get_text(GTK_ENTRY(ce));
556  prefs_set_string("CustomCommand", cc);
557 
558  // hotkeys enabled
559  GtkWidget *hkc = dialog->hotkeys_enable_check;
560  active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(hkc));
561  prefs_set_boolean("EnableHotKeys", active);
562 
563  // hotkeys
564  GtkWidget *kl;
565  gint keycode;
566  GdkModifierType mods;
567 
568  kl = dialog->hotkeys_mute_label;
569  get_keycode_for_label(GTK_LABEL(kl), &keycode, &mods);
570  prefs_set_integer("VolMuteKey", keycode);
571  prefs_set_integer("VolMuteMods", mods);
572 
573  kl = dialog->hotkeys_up_label;
574  get_keycode_for_label(GTK_LABEL(kl), &keycode, &mods);
575  prefs_set_integer("VolUpKey", keycode);
576  prefs_set_integer("VolUpMods", mods);
577 
578  kl = dialog->hotkeys_down_label;
579  get_keycode_for_label(GTK_LABEL(kl), &keycode, &mods);
580  prefs_set_integer("VolDownKey", keycode);
581  prefs_set_integer("VolDownMods", mods);
582 
583  // notifications
584 #ifdef WITH_LIBNOTIFY
585  GtkWidget *nc = dialog->noti_enable_check;
586  gint noti_spin;
587  active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(nc));
588  prefs_set_boolean("EnableNotifications", active);
589 
590  nc = dialog->noti_hotkey_check;
591  active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(nc));
592  prefs_set_boolean("HotkeyNotifications", active);
593 
594  nc = dialog->noti_mouse_check;
595  active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(nc));
596  prefs_set_boolean("MouseNotifications", active);
597 
598  nc = dialog->noti_popup_check;
599  active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(nc));
600  prefs_set_boolean("PopupNotifications", active);
601 
602  nc = dialog->noti_ext_check;
603  active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(nc));
604  prefs_set_boolean("ExternalNotifications", active);
605 
606  nc = dialog->noti_timeout_spin;
607  noti_spin = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(nc));
608  prefs_set_integer("NotificationTimeout", noti_spin);
609 #endif
610 }
611 
616 void
618 {
619  gdouble *vol_meter_clrs;
620  gchar *slider_orientation, *vol_cmd, *custcmd;
621 
622  DEBUG("Populating prefs dialog values");
623 
624  // volume slider orientation
625  slider_orientation = prefs_get_string("SliderOrientation", NULL);
626  if (slider_orientation) {
627  GtkComboBox *combo_box =
628  GTK_COMBO_BOX(dialog->vol_orientation_combo);
629 #ifndef WITH_GTK3
630  /* Gtk2 ComboBoxes don't have item ids */
631  if (!strcmp(slider_orientation, "horizontal"))
632  gtk_combo_box_set_active(combo_box, 1);
633  else
634  gtk_combo_box_set_active(combo_box, 0);
635 #else
636  gtk_combo_box_set_active_id(combo_box, slider_orientation);
637 #endif
638  g_free(slider_orientation);
639  }
640 
641  // volume text display
642  gtk_toggle_button_set_active
643  (GTK_TOGGLE_BUTTON(dialog->vol_text_check),
644  prefs_get_boolean("DisplayTextVolume", FALSE));
645 
647  (GTK_TOGGLE_BUTTON(dialog->vol_text_check), dialog);
648 
649  // volume text position
650  gtk_combo_box_set_active
651  (GTK_COMBO_BOX(dialog->vol_pos_combo),
652  prefs_get_integer("TextVolumePosition", 0));
653 
654  // volume meter display
655  gtk_toggle_button_set_active
656  (GTK_TOGGLE_BUTTON(dialog->vol_meter_draw_check),
657  prefs_get_boolean("DrawVolMeter", FALSE));
658 
660  (GTK_TOGGLE_BUTTON(dialog->vol_meter_draw_check), dialog);
661 
662  // volume meter position
663  gtk_spin_button_set_value
664  (GTK_SPIN_BUTTON(dialog->vol_meter_pos_spin),
665  prefs_get_integer("VolMeterPos", 0));
666 
667  // volume meter colors
668  vol_meter_clrs = prefs_get_double_list("VolMeterColor", NULL);
669 #ifdef WITH_GTK3
670  GdkRGBA vol_meter_color_button_color;
671  vol_meter_color_button_color.red = vol_meter_clrs[0];
672  vol_meter_color_button_color.green = vol_meter_clrs[1];
673  vol_meter_color_button_color.blue = vol_meter_clrs[2];
674  vol_meter_color_button_color.alpha = 1.0;
675  gtk_color_chooser_set_rgba
676  (GTK_COLOR_CHOOSER(dialog->vol_meter_color_button),
677  &vol_meter_color_button_color);
678 #else
679  GdkColor vol_meter_color_button_color;
680  vol_meter_color_button_color.red = (guint32) (vol_meter_clrs[0] * 65536);
681  vol_meter_color_button_color.green = (guint32) (vol_meter_clrs[1] * 65536);
682  vol_meter_color_button_color.blue = (guint32) (vol_meter_clrs[2] * 65536);
683  gtk_color_button_set_color
684  (GTK_COLOR_BUTTON(dialog->vol_meter_color_button),
685  &vol_meter_color_button_color);
686 #endif
687  g_free(vol_meter_clrs);
688 
689  // icon theme
690  gtk_toggle_button_set_active
691  (GTK_TOGGLE_BUTTON(dialog->system_theme),
692  prefs_get_boolean("SystemTheme", FALSE));
693 
694  // fill in card & channel combo boxes
695  fill_card_combo(GTK_COMBO_BOX_TEXT(dialog->card_combo), dialog->audio);
696 #ifdef GTK3
697  /* On Gtk3, refilling the card combo doesn't emit a 'changed' signal,
698  * therefore we must refill channel combo explicitely.
699  */
700  fill_chan_combo(GTK_COMBO_BOX_TEXT(dialog->chan_combo),
701  audio_get_card(dialog->audio));
702 #endif
703 
704  // normalize volume
705  gtk_toggle_button_set_active
706  (GTK_TOGGLE_BUTTON(dialog->normalize_vol_check),
707  prefs_get_boolean("NormalizeVolume", FALSE));
708 
709  // volume control command
710  vol_cmd = prefs_get_string("VolumeControlCommand", NULL);
711  if (vol_cmd) {
712  gtk_entry_set_text(GTK_ENTRY(dialog->vol_control_entry), vol_cmd);
713  g_free(vol_cmd);
714  }
715 
716  // volume scroll steps
717  gtk_spin_button_set_value
718  (GTK_SPIN_BUTTON(dialog->scroll_step_spin),
719  prefs_get_double("ScrollStep", 5));
720 
721  gtk_spin_button_set_value
722  (GTK_SPIN_BUTTON(dialog->fine_scroll_step_spin),
723  prefs_get_double("FineScrollStep", 1));
724 
725  // middle click
726  gtk_combo_box_set_active
727  (GTK_COMBO_BOX(dialog->middle_click_combo),
728  prefs_get_integer("MiddleClickAction", 0));
729 
731  (GTK_COMBO_BOX_TEXT(dialog->middle_click_combo), dialog);
732 
733  // custom command
734  gtk_entry_set_invisible_char(GTK_ENTRY(dialog->custom_entry), 8226);
735 
736  custcmd = prefs_get_string("CustomCommand", NULL);
737  if (custcmd) {
738  gtk_entry_set_text(GTK_ENTRY(dialog->custom_entry), custcmd);
739  g_free(custcmd);
740  }
741 
742  // hotkeys enabled
743  gtk_toggle_button_set_active
744  (GTK_TOGGLE_BUTTON(dialog->hotkeys_enable_check),
745  prefs_get_boolean("EnableHotKeys", FALSE));
746 
747  // hotkeys
748  set_label_for_keycode(GTK_LABEL(dialog->hotkeys_mute_label),
749  prefs_get_integer("VolMuteKey", -1),
750  prefs_get_integer("VolMuteMods", 0));
751 
752  set_label_for_keycode(GTK_LABEL(dialog->hotkeys_up_label),
753  prefs_get_integer("VolUpKey", -1),
754  prefs_get_integer("VolUpMods", 0));
755 
756  set_label_for_keycode(GTK_LABEL(dialog->hotkeys_down_label),
757  prefs_get_integer("VolDownKey", -1),
758  prefs_get_integer("VolDownMods", 0));
759 
761  (GTK_TOGGLE_BUTTON(dialog->hotkeys_enable_check), dialog);
762 
763  // notifications
764 #ifdef WITH_LIBNOTIFY
765  gtk_toggle_button_set_active
766  (GTK_TOGGLE_BUTTON(dialog->noti_enable_check),
767  prefs_get_boolean("EnableNotifications", FALSE));
768 
769  gtk_toggle_button_set_active
770  (GTK_TOGGLE_BUTTON(dialog->noti_hotkey_check),
771  prefs_get_boolean("HotkeyNotifications", TRUE));
772 
773  gtk_toggle_button_set_active
774  (GTK_TOGGLE_BUTTON(dialog->noti_mouse_check),
775  prefs_get_boolean("MouseNotifications", TRUE));
776 
777  gtk_toggle_button_set_active
778  (GTK_TOGGLE_BUTTON(dialog->noti_popup_check),
779  prefs_get_boolean("PopupNotifications", FALSE));
780 
781  gtk_toggle_button_set_active
782  (GTK_TOGGLE_BUTTON(dialog->noti_ext_check),
783  prefs_get_boolean("ExternalNotifications", FALSE));
784 
785  gtk_spin_button_set_value
786  (GTK_SPIN_BUTTON(dialog->noti_timeout_spin),
787  prefs_get_integer("NotificationTimeout", 1500));
788 
790  (GTK_TOGGLE_BUTTON(dialog->noti_enable_check), dialog);
791 #endif
792 }
793 
799 void
801 {
802  GtkWindow *prefs_window = GTK_WINDOW(dialog->prefs_dialog);
803 
804  /* Present the window */
805  gtk_window_present(prefs_window);
806 }
807 
813 void
815 {
816  DEBUG("Destroying");
817 
818  g_signal_handler_disconnect(GTK_WINDOW(dialog->prefs_dialog),
819  dialog->response_handler);
820 
822 
823  if (dialog->hotkey_dialog)
825 
826  gtk_widget_destroy(dialog->prefs_dialog);
827  g_free(dialog);
828 }
829 
839 PrefsDialog *
842 {
843  gchar *uifile = NULL;
844  GtkBuilder *builder = NULL;
845  PrefsDialog *dialog;
846 
847  dialog = g_new0(PrefsDialog, 1);
848 
849  /* Build UI file */
850  uifile = get_ui_file(PREFS_UI_FILE);
851  g_assert(uifile);
852 
853  DEBUG("Building from ui file '%s'", uifile);
854  builder = gtk_builder_new_from_file(uifile);
855 
856  /* Append the notification page.
857  * This has to be done manually here, in the C code,
858  * because notifications support is optional at build time.
859  */
860  gtk_notebook_append_page
861  (GTK_NOTEBOOK(gtk_builder_get_object(builder, "notebook")),
862 #ifdef WITH_LIBNOTIFY
863  GTK_WIDGET(gtk_builder_get_object(builder, "noti_vbox_enabled")),
864 #else
865  GTK_WIDGET(gtk_builder_get_object(builder, "noti_vbox_disabled")),
866 #endif
867  gtk_label_new(_("Notifications")));
868 
869  /* Save some widgets for later use */
870  // Top level widgets
871  assign_gtk_widget(builder, dialog, prefs_dialog);
872  assign_gtk_widget(builder, dialog, notebook);
873  assign_gtk_widget(builder, dialog, ok_button);
874  assign_gtk_widget(builder, dialog, cancel_button);
875  // View panel
876  assign_gtk_widget(builder, dialog, vol_orientation_combo);
877  assign_gtk_widget(builder, dialog, vol_text_check);
878  assign_gtk_widget(builder, dialog, vol_pos_label);
879  assign_gtk_widget(builder, dialog, vol_pos_combo);
880  assign_gtk_widget(builder, dialog, vol_meter_draw_check);
881  assign_gtk_widget(builder, dialog, vol_meter_pos_label);
882  assign_gtk_widget(builder, dialog, vol_meter_pos_spin);
884  assign_gtk_widget(builder, dialog, vol_meter_color_label);
885  assign_gtk_widget(builder, dialog, vol_meter_color_button);
886  assign_gtk_widget(builder, dialog, system_theme);
887  // Device panel
888  assign_gtk_widget(builder, dialog, card_combo);
889  assign_gtk_widget(builder, dialog, chan_combo);
890  assign_gtk_widget(builder, dialog, normalize_vol_check);
891  // Behavior panel
892  assign_gtk_widget(builder, dialog, vol_control_entry);
893  assign_gtk_widget(builder, dialog, scroll_step_spin);
894  assign_gtk_widget(builder, dialog, fine_scroll_step_spin);
895  assign_gtk_widget(builder, dialog, middle_click_combo);
896  assign_gtk_widget(builder, dialog, custom_label);
897  assign_gtk_widget(builder, dialog, custom_entry);
898  // Hotkeys panel
899  assign_gtk_widget(builder, dialog, hotkeys_enable_check);
900  assign_gtk_widget(builder, dialog, hotkeys_grid);
901  assign_gtk_widget(builder, dialog, hotkeys_mute_eventbox);
902  assign_gtk_widget(builder, dialog, hotkeys_mute_label);
903  assign_gtk_widget(builder, dialog, hotkeys_up_eventbox);
904  assign_gtk_widget(builder, dialog, hotkeys_up_label);
905  assign_gtk_widget(builder, dialog, hotkeys_down_eventbox);
906  assign_gtk_widget(builder, dialog, hotkeys_down_label);
907  // Notifications panel
908 #ifdef WITH_LIBNOTIFY
909  assign_gtk_widget(builder, dialog, noti_vbox_enabled);
910  assign_gtk_widget(builder, dialog, noti_enable_check);
911  assign_gtk_widget(builder, dialog, noti_timeout_spin);
912  assign_gtk_widget(builder, dialog, noti_timeout_label);
913  assign_gtk_widget(builder, dialog, noti_hotkey_check);
914  assign_gtk_widget(builder, dialog, noti_mouse_check);
915  assign_gtk_widget(builder, dialog, noti_popup_check);
916  assign_gtk_widget(builder, dialog, noti_ext_check);
917 #else
918  assign_gtk_widget(builder, dialog, noti_vbox_disabled);
919 #endif
920 
921  /* Set transient parent */
922  gtk_window_set_transient_for(GTK_WINDOW(dialog->prefs_dialog), parent);
923 
924  /* Connect ui signal handlers */
925  gtk_builder_connect_signals(builder, dialog);
926 
927  /* Save some references */
928  dialog->hotkeys = hotkeys;
929  dialog->audio = audio;
930 
931  /* Connect audio signal handlers */
932  audio_signals_connect(audio, on_audio_changed, dialog);
933 
934  /* Setup user callback */
935  dialog->response_user_cb = cb;
936  dialog->response_handler = g_signal_connect
937  (GTK_WINDOW(dialog->prefs_dialog),
938  "response",
939  G_CALLBACK(on_prefs_dialog_response),
940  dialog);
941 
942  /* Cleanup */
943  g_object_unref(G_OBJECT(builder));
944  g_free(uifile);
945 
946  return dialog;
947 }
GtkWidget * cancel_button
GtkBuilder * gtk_builder_new_from_file(const gchar *filename)
Definition: support-ui.c:25
#define _(String)
Definition: support-intl.h:44
Internationalization support.
Logging support.
Header for audio.c.
GtkAdjustment * vol_meter_pos_adjustment
static void on_prefs_dialog_response(G_GNUC_UNUSED GtkDialog *widget, gint response_id, PrefsDialog *dialog)
void hotkeys_unbind(Hotkeys *hotkeys)
Definition: hotkeys.c:192
GtkWidget * vol_meter_color_button
HotkeyDialog * hotkey_dialog_create(GtkWindow *parent, const gchar *hotkey)
GtkWidget * vol_text_check
GtkWidget * hotkeys_mute_label
GtkWidget * hotkeys_enable_check
static void get_keycode_for_label(GtkLabel *label, gint *code, GdkModifierType *mods)
const char * audio_get_card(Audio *audio)
Definition: audio.c:353
gchar * hotkey_dialog_run(HotkeyDialog *dialog)
Header for hotkeys.c.
gchar * hotkey_code_to_accel(guint code, GdkModifierType mods)
Definition: hotkey.c:208
GtkWidget * chan_combo
void prefs_set_double(const gchar *key, gdouble value)
Definition: prefs.c:297
GtkWidget * normalize_vol_check
Header for support-ui.c.
void audio_signals_disconnect(Audio *audio, AudioCallback callback, gpointer data)
Definition: audio.c:318
#define assign_gtk_widget(builder, container, name)
Definition: support-ui.h:75
Header for ui-hotkey-dialog.c.
GtkWidget * hotkeys_mute_eventbox
static void on_audio_changed(Audio *audio, AudioEvent *event, gpointer data)
void audio_signals_connect(Audio *audio, AudioCallback callback, gpointer data)
Definition: audio.c:337
void prefs_dialog_present(PrefsDialog *dialog)
Header for prefs.c.
void hotkey_accel_to_code(const gchar *accel, gint *code, GdkModifierType *mods)
Definition: hotkey.c:230
void gtk_combo_box_text_remove_all(GtkComboBoxText *combo_box)
Definition: support-ui.c:38
GtkWidget * custom_entry
gdouble * prefs_get_double_list(const gchar *key, gsize *n)
Definition: prefs.c:206
void prefs_dialog_retrieve(PrefsDialog *dialog)
void prefs_set_channel(const gchar *card, const gchar *channel)
Definition: prefs.c:334
static void set_label_for_keycode(GtkLabel *label, gint code, GdkModifierType mods)
Hotkeys * hotkeys
GtkWidget * scroll_step_spin
GtkWidget * hotkeys_down_eventbox
gboolean prefs_get_boolean(const gchar *key, gboolean def)
Definition: prefs.c:102
#define DEBUG(...)
Definition: support-log.h:38
void on_hotkeys_enable_check_toggled(GtkToggleButton *button, PrefsDialog *dialog)
Header for main.c.
void on_card_combo_changed(GtkComboBoxText *box, PrefsDialog *dialog)
GtkWidget * middle_click_combo
GtkWidget * system_theme
#define PREFS_UI_FILE
gchar * get_ui_file(const char *filename)
Definition: support-ui.c:58
GtkWidget * vol_meter_color_label
GSList * audio_get_channel_list(const char *card_name)
Definition: audio.c:739
Header for hotkey.c.
PrefsDialog * prefs_dialog_create(GtkWindow *parent, Audio *audio, Hotkeys *hotkeys, PrefsDialogResponseCallback cb)
static void fill_chan_combo(GtkComboBoxText *combo, const gchar *card_name)
GtkWidget * vol_meter_pos_label
GtkWidget * ok_button
void(* PrefsDialogResponseCallback)(PrefsDialog *dialog, gint response_id)
void on_noti_enable_check_toggled(G_GNUC_UNUSED GtkToggleButton *button, G_GNUC_UNUSED PrefsDialog *dialog)
Definition: audio.c:198
GtkWidget * vol_meter_draw_check
void prefs_set_integer(const gchar *key, gint value)
Definition: prefs.c:285
gchar * prefs_get_channel(const gchar *card)
Definition: prefs.c:259
AudioSignal signal
Definition: audio.h:74
GtkWidget * hotkeys_grid
gulong response_handler
gchar * prefs_get_string(const gchar *key, const gchar *def)
Definition: prefs.c:171
Definition: hotkey.h:22
#define assign_gtk_adjustment(builder, container, name)
Definition: support-ui.h:81
void prefs_set_double_list(const gchar *key, gdouble *list, gsize n)
Definition: prefs.c:322
GSList * audio_get_card_list(void)
Definition: audio.c:726
void hotkeys_bind(Hotkeys *hotkeys)
Definition: hotkeys.c:210
GtkWidget * card_combo
gboolean on_hotkey_event_box_button_press_event(GtkWidget *widget, GdkEventButton *event, PrefsDialog *dialog)
GtkWidget * vol_pos_label
GtkWidget * vol_control_entry
Header for ui-prefs-dialog.c.
void prefs_set_string(const gchar *key, const gchar *value)
Definition: prefs.c:309
GtkWidget * noti_vbox_disabled
gint prefs_get_integer(const gchar *key, gint def)
Definition: prefs.c:125
GtkWidget * custom_label
GtkWidget * vol_orientation_combo
void on_middle_click_combo_changed(GtkComboBoxText *box, PrefsDialog *dialog)
GtkWidget * prefs_dialog
void on_vol_text_check_toggled(GtkToggleButton *button, PrefsDialog *dialog)
void prefs_dialog_populate(PrefsDialog *dialog)
GtkWidget * fine_scroll_step_spin
GtkWidget * vol_meter_pos_spin
GtkWidget * hotkeys_down_label
void prefs_set_boolean(const gchar *key, gboolean value)
Definition: prefs.c:273
void on_vol_meter_draw_check_toggled(GtkToggleButton *button, PrefsDialog *dialog)
void hotkey_dialog_destroy(HotkeyDialog *dialog)
PrefsDialogResponseCallback response_user_cb
GtkWidget * hotkeys_up_eventbox
GtkWidget * hotkeys_up_label
static void fill_card_combo(GtkComboBoxText *combo, Audio *audio)
HotkeyDialog * hotkey_dialog
void prefs_dialog_destroy(PrefsDialog *dialog)
GtkWidget * vol_pos_combo
gdouble prefs_get_double(const gchar *key, gdouble def)
Definition: prefs.c:148
GtkWidget * notebook