1 /*
2  * xmixer:gui_gtk.c
3  *
4  * Copyright (C) 1997-99 Rasca, Berlin
5  * EMail: thron@gmx.de
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <string.h>
26 #include <gtk/gtk.h>
27 #include <gdk/gdk.h>
28 #include <gdk/gdkkeysyms.h>
29 /**/
30 #include "gui.h"
31 #include "about.h"
32 #include "mixer.h"
33 #include "scf.h"
34 
35 #define LEFT	0
36 #define RIGHT	1
37 
38 #define GSIG	GTK_SIGNAL_FUNC
39 #define GOBJ	GTK_OBJECT
40 
41 typedef struct {
42 	int dev;
43 	int locked;
44 	int mute;
45 	GtkWidget *box;
46 	GtkWidget *label;
47 	GtkWidget *lock;
48 	GtkObject *left;
49 	GtkObject *right;
50 } wMixer, mixer_t;
51 
52 typedef struct {
53 
54 	/* resources
55 	 */
56 	char *dev_name;
57 	int update_time;
58 	char *help_command;
59 
60 	/* private
61 	 */
62 	char *program;
63 	mixer_t *devs;
64 	int max;
65 	GtkWidget *menu;
66 	GtkWidget *label;
67 	GtkTooltips *tips;
68 } AppData;
69 
70 /* some globals
71  */
72 
73 static AppData App;
74 
75 #define Toplevel()	(App.toplevel)
76 
77 /* actions definitions
78  */
79 
80 /*
81  */
82 static void
83 update_label (mixer_t *m)
84 {
85 	int vol_left, vol_right = 0;
86 	static char buff[32];
87 
88 	vol_left = mixer_get_vol_left (1, m->dev);
89 	if (mixer_is_stereo (1, m->dev)) {
90 		vol_right = mixer_get_vol_right (1, m->dev);
91 		sprintf (buff, "%3d:%3d", vol_left, vol_right);
92 	} else {
93 		sprintf (buff, "%3d    ", vol_left);
94 	}
95 	gtk_label_set_text (GTK_LABEL(App.label), buff);
96 }
97 
98 /*
99  * called before gui_main()
100  */
101 char *
102 gui_init (int *argc, char ***argv)
103 {
104 	char *home, *rc, *rc_path, *p;
105 
106 	home = getenv ("HOME");
107 	if (home) {
108 		/* check for the program name .. */
109 		p = strrchr (*argv[0], '/');
110 		if (!p)
111 			p = *argv[0];
112 		else
113 			p = p+1;
114 
115 		rc = malloc (strlen (p) + 4);
116 		if (!rc)
117 			exit;
118 		sprintf (rc, "%s.rc", p);
119 		rc_path = malloc (strlen (home) + strlen (rc) + 2);
120 		if (rc_path) {
121 			sprintf (rc_path, "%s/.gtk/%s", home, rc);
122 			gtk_rc_add_default_file (rc_path);
123 			free (rc_path);
124 		}
125 		free (rc);
126 	}
127 	gtk_init (argc, argv);
128 	return ((char *)NULL);
129 }
130 
131 /*
132  */
133 static void
134 cb_mute (GtkWidget *w, gpointer data)
135 {
136 	mixer_t *mix = (mixer_t *) data;
137 	int vol;
138 
139 	if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w))) {
140 		mix->mute = 1;
141 		mixer_set_vol_left (1, mix->dev, 0);
142 		if (mixer_is_stereo (1, mix->dev))
143 			mixer_set_vol_right (1, mix->dev, 0);
144 	} else {
145 		mix->mute = 0;
146 		vol = 100 - GTK_ADJUSTMENT(mix->left)->value;
147 		mixer_set_vol_left (1, mix->dev, vol);
148 		if (mixer_is_stereo (1, mix->dev)) {
149 			vol = 100 - GTK_ADJUSTMENT(mix->right)->value;
150 			mixer_set_vol_right (1, mix->dev, vol);
151 		}
152 	}
153 }
154 
155 /*
156  */
157 static void
158 cb_rec (GtkWidget *w, gpointer data)
159 {
160 	mixer_t *mix = (mixer_t *) data;
161 	if (mix) {
162 		if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w))) {
163 			mixer_set_rec (1, mix->dev, 1);
164 		} else {
165 			mixer_set_rec (1, mix->dev, 0);
166 		}
167 	}
168 }
169 
170 typedef struct {
171 	mixer_t *mix;
172 	AppData *ad;
173 	GtkWidget *ok;
174 	GtkWidget *cancel;
175 	GtkWidget *dlg;
176 	GtkWidget *en;
177 } dlg_data_t;
178 
179 
180 /*
181  * change label
182  */
183 static void
184 cb_change (GtkWidget *w, gpointer data)
185 {
186 	dlg_data_t *dlg_data = (dlg_data_t *) data;
187 	char *str;
188 
189 	if (w == dlg_data->ok) {
190 		str = gtk_entry_get_text(GTK_ENTRY(dlg_data->en));
191 		if (str && *str) {
192 			gtk_label_set_text (
193 					GTK_LABEL(GTK_BIN(dlg_data->mix->label)->child), str);
194 		}
195 	}
196 	gtk_widget_destroy(GTK_WIDGET(dlg_data->dlg));
197 }
198 
199 /*
200  */
201 static gint
202 cb_key (GtkWidget *w, GdkEventKey *event, gpointer data)
203 {
204 	dlg_data_t *dlg_data = (dlg_data_t *) data;
205 	if (event->keyval == GDK_Escape) {
206 		cb_change (dlg_data->cancel, dlg_data);
207 		return TRUE;
208 	}
209 	if (event->keyval == GDK_Return) {
210 		cb_change (dlg_data->ok, dlg_data);
211 		return TRUE;
212 	}
213 	return FALSE;
214 }
215 
216 /*
217  * called if the user wants to change the label form a device slider
218  */
219 static void
220 cb_label (GtkWidget *w, gpointer data)
221 {
222 	mixer_t *mix = (mixer_t *) data;
223 	GtkWidget *label, *btn, *entry, *box;
224 	static GtkWidget *dlg = NULL;
225 	static dlg_data_t dlg_data;
226 	char *str;
227 
228 	if (dlg)
229 		return;
230 	dlg = gtk_dialog_new ();
231 
232 	dlg_data.mix = mix;
233 	dlg_data.ad = &App;
234 	dlg_data.dlg = dlg;
235 
236 	gtk_signal_connect (GOBJ(dlg), "destroy", GSIG(gtk_widget_destroyed), &dlg);
237 	gtk_window_set_title (GTK_WINDOW(dlg), "Change Label Dialog");
238 	gtk_window_position (GTK_WINDOW(dlg), GTK_WIN_POS_MOUSE);
239 
240 	box = gtk_hbox_new (FALSE, 5);
241 	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->vbox),box,FALSE,TRUE,4);
242 
243 	label = gtk_label_new ("New Label:");
244 	gtk_box_pack_start(GTK_BOX(box),label,TRUE,TRUE,0);
245 
246 	entry = gtk_entry_new ();
247 	str = GTK_LABEL(GTK_BIN(mix->label)->child)->label;
248 	gtk_entry_set_text (GTK_ENTRY(entry), str);
249 	gtk_box_pack_start(GTK_BOX(box),entry,TRUE,TRUE,0);
250 	gtk_signal_connect(GOBJ(entry),"key_press_event",GSIG(cb_key),&dlg_data);
251 	dlg_data.en = entry;
252 	gtk_widget_grab_focus (entry);
253 
254 	btn = gtk_button_new_with_label ("Ok");
255 	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area),btn,TRUE,TRUE,0);
256 	gtk_signal_connect (GOBJ(btn), "clicked", GSIG(cb_change), &dlg_data);
257 	dlg_data.ok = btn;
258 
259 	btn = gtk_button_new_with_label ("Cancel");
260 	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area),btn,TRUE,TRUE,0);
261 	gtk_signal_connect (GOBJ(btn), "clicked", GSIG(cb_change), &dlg_data);
262 	dlg_data.cancel = btn;
263 
264 	gtk_widget_show_all (dlg);
265 }
266 
267 /*
268  */
269 static void
270 cb_left (GtkWidget *w, gpointer data)
271 {
272 	mixer_t *mix = (mixer_t *) data;
273 	int vol;
274 	if (mixer_is_stereo (1, mix->dev)) {
275 		if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(mix->lock))) {
276 			if (GTK_ADJUSTMENT(mix->left)->value
277 					!= GTK_ADJUSTMENT(mix->right)->value) {
278 
279 				GTK_ADJUSTMENT(mix->right)->value =
280 					GTK_ADJUSTMENT(mix->left)->value;
281 				gtk_signal_emit_by_name(GTK_OBJECT(mix->right),"value_changed");
282 			}
283 		}
284 	}
285 	vol = 100 - GTK_ADJUSTMENT(mix->left)->value;
286 	if (!mix->mute)
287 		mixer_set_vol_left (1, mix->dev, vol);
288 	update_label (mix);
289 }
290 
291 /*
292  */
293 static void
294 cb_right (GtkWidget *w, gpointer data)
295 {
296 	mixer_t *mix = (mixer_t *) data;
297 	int vol;
298 
299 	if (mixer_is_stereo (1, mix->dev)) {
300 		if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(mix->lock))) {
301 			if (GTK_ADJUSTMENT(mix->left)->value
302 					!= GTK_ADJUSTMENT(mix->right)->value) {
303 
304 				GTK_ADJUSTMENT(mix->left)->value =
305 					GTK_ADJUSTMENT(mix->right)->value;
306 				gtk_signal_emit_by_name(GTK_OBJECT(mix->left),"value_changed");
307 			}
308 		}
309 	}
310 	vol = 100 - GTK_ADJUSTMENT(mix->right)->value;
311 	if (!mix->mute)
312 		mixer_set_vol_right (1, mix->dev, vol);
313 	update_label (mix);
314 }
315 
316 /*
317  */
318 static void
319 cb_save (GtkWidget *w, gpointer data)
320 {
321 	AppData *ad = (AppData *) data;
322 	const char *fname;
323 	FILE *fp;
324 	char *name, *label;
325 	int i;
326 
327 	fname = scf_file_name (ad->program, SCF_PRIVAT);
328 	if (fname) {
329 		fp = fopen (fname, "w");
330 		if (!fp)
331 			return;
332 		fprintf (fp, "#SCFF 1.0\n");
333 		fprintf (fp, "# mixer device name\n");
334 		fprintf (fp, "[%s]\n\n", ad->dev_name);
335 		for (i = 0; i < ad->max; i++) {
336 			name = (char *) mixer_get_name (1, i);
337 			fprintf (fp, "# Settings for the %s-device = ", name);
338 			if (mixer_is_stereo(1, i))
339 				fprintf(fp,"{ Int[0-100]:leftValue Int[0-100]:rightValue }\n");
340 			else
341 				fprintf (fp, "{ Int[0-100]:value }\n");
342 
343 			fprintf (fp, "%s = { ", mixer_get_name(1, i));
344 			if (mixer_is_stereo(1, i)) {
345 				fprintf (fp, "%d %d }\n", mixer_get_vol_left(1,i),
346 					mixer_get_vol_right(1,i));
347 			} else {
348 				fprintf (fp, "%d }\n", mixer_get_vol_left(1,i));
349 			}
350 			fprintf (fp,
351 				"# show slider for device \"%s\" = Bool[True, False]:Map\n",
352 				name);
353 			if (GTK_WIDGET_VISIBLE(ad->devs[i].box))
354 				fprintf (fp, "%s_map = True\n", name);
355 			else
356 				fprintf (fp, "%s_map = False\n", name);
357 			label = GTK_LABEL(GTK_BIN(ad->devs[i].label)->child)->label;
358 			if (label) {
359 				fprintf (fp,"# label of the device \"%s\" = String:Label\n",
360 						name);
361 				fprintf (fp,"%s_label = \"%s\"\n\n", name, label);
362 			}
363 		}
364 		if (!GTK_WIDGET_VISIBLE(ad->menu)) {
365 			fprintf (fp, "[%s]\n", GLOBAL);
366 			fprintf (fp, "# we don't want to see the menu bar\n");
367 			fprintf (fp, "menu_map = False\n");
368 		}
369 		fclose (fp);
370 	}
371 }
372 
373 /*
374  * load settings from config file
375  */
376 static void
377 cb_load (GtkWidget *w, gpointer data)
378 {
379 	AppData *ad = (AppData *) data;
380 	scf_id id;
381 	int i, left, right, map;
382 	char *name;
383 	char key[32];
384 
385 	id = scf_init (ad->program, NULL);
386 	if (scf_read(id)) {
387 		for (i = 0; i < ad->max; i++) {
388 			name = (char *)mixer_get_name (1, i);
389 			if (scf_get_array_int_val (id, ad->dev_name, name, 0, &left)
390 				== SCF_TRUE) {
391 				/* mixer_set_vol_left (1, i, left); */
392 				gtk_adjustment_set_value (GTK_ADJUSTMENT(ad->devs[i].left),
393 					(gfloat)(100-left));
394 			}
395 			if (scf_get_array_int_val (id, ad->dev_name, name, 1, &right)
396 				== SCF_TRUE) {
397 				/* mixer_set_vol_right (1, i, right); */
398 				if (mixer_is_stereo (1, i))
399 				gtk_adjustment_set_value (GTK_ADJUSTMENT(ad->devs[i].right),
400 					(gfloat)(100-right));
401 			}
402 			sprintf (key, "%s_map", name);
403 			if (scf_get_bool_val (id, ad->dev_name, key, &map)) {
404 				if (map == SCF_FALSE) {
405 					gtk_widget_hide_all (ad->devs[i].box);
406 				} else {
407 					gtk_widget_show_all (ad->devs[i].box);
408 				}
409 			}
410 		}
411 	}
412 	scf_fini(id);
413 }
414 
415 /*
416  */
417 static void
418 cb_quit (GtkWidget *w, gpointer data)
419 {
420 	gtk_exit (0);
421 }
422 
423 /*
424  */
425 static void
426 cb_menu (GtkWidget *w, gpointer data)
427 {
428 	AppData *ad = (AppData *) data;
429 	if (ad) {
430 		if (GTK_WIDGET_VISIBLE(ad->menu)) {
431 			gtk_widget_hide_all (ad->menu);
432 		} else {
433 			gtk_widget_show_all (ad->menu);
434 		}
435 	}
436 }
437 
438 /*
439  * hide or view a named device
440  */
441 static void
442 cb_hide (GtkWidget *w, gpointer data)
443 {
444 	mixer_t *mix = (mixer_t *)data;
445 	if (GTK_WIDGET_VISIBLE(mix->box)) {
446 		gtk_widget_hide_all (mix->box);
447 	} else {
448 		gtk_widget_show_all (mix->box);
449 	}
450 }
451 
452 /*
453  */
454 static void
455 cb_about (GtkWidget *w, gpointer data)
456 {
457 	static GtkWidget *dlg = NULL;
458 	GtkWidget *label;
459 
460 	if (dlg)
461 		return;
462 	dlg = gtk_dialog_new ();
463 	gtk_signal_connect (GOBJ(dlg), "destroy", GSIG(gtk_widget_destroyed), &dlg);
464 	gtk_window_set_title (GTK_WINDOW(dlg), "About");
465 	label = gtk_label_new (_ABOUT_);
466 	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dlg)->action_area),label,TRUE,TRUE,0);
467 	gtk_widget_show_all (dlg);
468 }
469 
470 /*
471  */
472 static void
473 cb_help (GtkWidget *w, gpointer data)
474 {
475 	system ("xterm -e man xmixer &");
476 }
477 
478 static GtkItemFactoryEntry menu_items [] = {
479 	{"/_File",						NULL,		NULL,		0,	"<Branch>"},
480 	{"/File/_Save Settings",		"<ctrl>S",	cb_save,	(guint)&App},
481 	{"/File/_Load Settings",		"<ctrl>O",	cb_load,	(guint)&App},
482 	{"/File/<Separator>",			NULL,		NULL,		0,	"<Separator>"},
483 	{"/File/_Quit",					"<alt>Q",	cb_quit,	0},
484 	{"/_View",						NULL,		NULL,		0,	"<Branch>"},
485 	{"/View/_Menu",				"<alt>M",cb_menu,(guint)&App,	"<ToggleItem>"},
486 	{"/View/<Separator>",			NULL,		NULL,		0,	"<Separator>"},
487 	{"/_Help",						NULL,		NULL,		0,	"<Branch>"},
488 	{"/Help/About ..",				"<ctrl>A",	cb_about,	0},
489 	{"/Help/Manual ..",				"<ctrl>H",	cb_help,	0},
490 	{"/       ",					NULL,		NULL,		0,	"<Item>"},
491 };
492 
493 /*
494  * gui_main()
495  */
496 int
497 gui_main (char *mixer_dev, char *pname)
498 {
499 	GtkWidget *top, *frame, *menubar, *dbox, *btn, *slider,
500 				*bbox, *scale_box, *toggle;
501 	GtkObject *adj;
502 	GtkAccelGroup *accel;
503 	int nmenu_items = sizeof (menu_items) / sizeof (*menu_items);
504 	GtkItemFactory *factory;
505 	GtkItemFactoryEntry if_entry;
506 	int no_of_devs, i;
507 	wMixer *devs;
508 	double vol_left, vol_right;
509 	scf_id id;
510 	int have_config;
511 	char key[32], path[64], *name, *p;
512 	int map;
513 
514 	no_of_devs = mixer_num_of_devs (1);
515 	devs = (wMixer *) malloc (sizeof (wMixer) * no_of_devs);
516 	if (!devs) {
517 		perror ("malloc()");
518 		return ERROR;
519 	}
520 	App.program = pname;
521 	App.max = no_of_devs;
522 	App.devs = devs;
523 	App.dev_name = mixer_dev;
524 	App.tips = gtk_tooltips_new ();
525 
526 	top = gtk_window_new (GTK_WINDOW_TOPLEVEL);
527 	gtk_signal_connect (GOBJ(top), "destroy", GSIG(cb_quit), NULL);
528 
529 
530 	frame = gtk_vbox_new (FALSE, 0);
531 	gtk_container_add (GTK_CONTAINER(top), frame);
532 
533 	accel = gtk_accel_group_new();
534 	factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<menu>", accel);
535 	gtk_item_factory_create_items (factory, nmenu_items, menu_items, NULL);
536 	gtk_accel_group_attach (accel, GOBJ(top));
537 	menubar = gtk_item_factory_get_widget (factory, "<menu>");
538 	gtk_box_pack_start (GTK_BOX(frame), menubar, FALSE, TRUE, 0);
539 	App.menu = menubar;
540 
541 	dbox = gtk_hbox_new (TRUE, 5);
542 	gtk_box_pack_start (GTK_BOX(frame), dbox, TRUE, TRUE, 1);
543 
544 	gtk_widget_show_all (top);
545 
546 	App.label = gtk_item_factory_get_widget (factory, "/       ");
547 	App.label = GTK_BIN(App.label)->child;
548 
549 	id = scf_init (App.program, NULL);
550 	if (scf_read (id))
551 		have_config = 1;
552 	else
553 		have_config = 0;
554 
555 	for (i = 0; i < no_of_devs; i++) {
556 		devs[i].box = gtk_vbox_new (FALSE, 0);
557 		devs[i].dev = i;
558 		devs[i].mute = 0;
559 		gtk_box_pack_start (GTK_BOX(dbox), devs[i].box, TRUE, TRUE, 0);
560 
561 		btn = gtk_button_new_with_label (mixer_get_label(1, i));
562 		gtk_box_pack_start (GTK_BOX(devs[i].box), btn, FALSE, TRUE, 0);
563 		gtk_signal_connect (GOBJ(btn), "clicked", GSIG(cb_label), &devs[i]);
564 		devs[i].label = btn;
565 
566 		/* */
567 		scale_box = gtk_hbox_new (TRUE, 0);
568 		gtk_box_pack_start (GTK_BOX(devs[i].box), scale_box, TRUE, TRUE, 0);
569 
570 		vol_left = vol_right = 100 - mixer_get_vol_left (1, i);
571 		adj = gtk_adjustment_new (vol_left, 0.0, 101.0, 1.0, 10.0, 1.0);
572 		gtk_signal_connect(GOBJ(adj), "value_changed", GSIG(cb_left), &devs[i]);
573 		slider = gtk_vscale_new (GTK_ADJUSTMENT (adj));
574 		gtk_scale_set_draw_value (GTK_SCALE(slider), FALSE);
575 		gtk_box_pack_start (GTK_BOX(scale_box), slider, TRUE, TRUE, 0);
576 		devs[i].left = adj;
577 		if (mixer_is_stereo (1, i)) {
578 			vol_right = 100 - mixer_get_vol_right (1, i);
579 			adj = gtk_adjustment_new (vol_right, 0.0, 101.0, 1.0, 10.0, 1.0);
580 			gtk_signal_connect(GOBJ(adj),
581 				"value_changed",GSIG(cb_right),&devs[i]);
582 			slider = gtk_vscale_new (GTK_ADJUSTMENT (adj));
583 			gtk_scale_set_draw_value (GTK_SCALE(slider), FALSE);
584 			gtk_box_pack_start (GTK_BOX(scale_box), slider, TRUE, TRUE, 0);
585 			devs[i].right = adj;
586 		}
587 
588 		/* add the buttons add the end */
589 		bbox = gtk_hbox_new (TRUE, 0);
590 		gtk_box_pack_start (GTK_BOX(devs[i].box), bbox, FALSE, TRUE, 0);
591 
592 		/* lock button */
593 		btn = gtk_toggle_button_new_with_label ("L");
594 		gtk_box_pack_start (GTK_BOX(bbox), btn, FALSE, TRUE, 0);
595 		if (!mixer_is_stereo (1, i)) {
596 			gtk_widget_set_sensitive (btn, 0);
597 		} else {
598 			if (vol_left == vol_right) {
599 				gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (btn), 1);
600 			}
601 		}
602 		devs[i].lock = btn;
603 		gtk_tooltips_set_tip (App.tips, btn, "Lock on/off", "/Tooltips/");
604 
605 		/* rec button */
606 		btn = gtk_toggle_button_new_with_label ("R");
607 		gtk_box_pack_start (GTK_BOX(bbox), btn, FALSE, TRUE, 0);
608 		if (mixer_is_rec_dev (1, i)) {
609 			if (mixer_is_rec_on (1, i)) {
610 				gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (btn), 1);
611 			}
612 			gtk_signal_connect (GOBJ(btn), "toggled", GSIG(cb_rec), &devs[i]);
613 			gtk_tooltips_set_tip (App.tips, btn, "Record on/off", "/Tooltips/");
614 		} else {
615 			gtk_widget_set_sensitive (btn, 0);
616 		}
617 		gtk_widget_set_name (btn, "recButton");
618 
619 		/* mute button */
620 		btn = gtk_toggle_button_new_with_label ("M");
621 		gtk_box_pack_start (GTK_BOX(bbox), btn, FALSE, TRUE, 0);
622 		gtk_signal_connect (GOBJ(btn), "toggled", GSIG(cb_mute), &devs[i]);
623 		gtk_tooltips_set_tip (App.tips, btn, "Mute on/off", "/Tooltips/");
624 		gtk_widget_set_name (btn, "muteButton");
625 
626 		name = (char *)mixer_get_name (1, i);
627 		/* check if it should be shown */
628 		map = TRUE;
629 		if (have_config) {
630 			char *str;
631 
632 			sprintf (key, "%s_map", name);
633 			if (scf_get_bool_val (id, App.dev_name, key, &map)) {
634 				if (map != FALSE) {
635 					gtk_widget_show_all (devs[i].box);
636 				}
637 			} else {
638 				gtk_widget_show_all (devs[i].box);
639 			}
640 			sprintf (key, "%s_label", name);
641 			str = scf_get_val (id, App.dev_name, key);
642 			if (str) {
643 				gtk_label_set_text (
644 					GTK_LABEL(GTK_BIN(devs[i].label)->child), str);
645 				name = str;
646 			}
647 		} else {
648 			gtk_widget_show_all (devs[i].box);
649 		}
650 		/* add menu entries */
651 		sprintf (path, "/View/%s", name);
652 		if_entry.path = path;
653 		if_entry.accelerator = NULL;
654 		if_entry.callback = cb_hide;
655 		if_entry.callback_action = (guint)&devs[i];
656 		if_entry.item_type = "<ToggleItem>";
657 		gtk_item_factory_create_item (factory, &if_entry, NULL, 1);
658 		toggle = gtk_item_factory_get_widget (factory, path);
659 		if (toggle) {
660 			if (map == TRUE) {
661 				GTK_CHECK_MENU_ITEM(toggle)->active = 1;
662 			}
663 		}
664 	}
665 
666 	toggle = gtk_item_factory_get_widget (factory, "/View/Menu");
667 	map = TRUE;
668 	if (have_config) {
669 		if (scf_get_bool_val (id, GLOBAL, "menu_map", &map)) {
670 			if (map == FALSE)
671 				gtk_widget_hide_all (App.menu);
672 		}
673 	}
674 	if (map) {
675 		GTK_CHECK_MENU_ITEM(toggle)->active = 1;
676 	}
677 	scf_fini(id);
678 
679 	p = strrchr (pname, '/');
680 	if (p)
681 		p++;
682 	else
683 		p = pname;
684 
685 	name = malloc (strlen (p) + strlen (mixer_dev) + 10);
686 	if (name) {
687 		sprintf (name, "%s: %s", p, mixer_dev);
688 		gtk_window_set_title (GTK_WINDOW(top), name);
689 		free (name);
690 	}
691 
692 	/* main loop */
693 	gtk_main ();
694 	return (ERROR);
695 }
696 
697