1 /*
2 * xmixer:gui_xaw.c
3 *
4 * Copyright (C) 1997-98 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 <X11/Intrinsic.h>
26 #include <X11/StringDefs.h>
27 #define XK_MISCELLANY
28 #define XK_XKB_KEYS
29 #include <X11/keysymdef.h>
30 #include <X11/Shell.h>
31 #include <X11/Xaw/Box.h>
32 #include <X11/Xaw/Panner.h>
33 /**/
34 #include <X11/Xaw/SimpleMenu.h>
35 #include <X11/Xaw/SmeBSB.h>
36 /**/
37 #include <X11/Xaw/Paned.h>
38 #include <X11/Xaw/Form.h>
39 /**/
40 #include <Xw/Button.h>
41 #include <Xw/Label.h>
42 #include <Xw/Toggle.h>
43 /**/
44 #include "gui.h"
45 #include "about.h"
46 #include "mixer.h"
47 #include "input.xbm"
48 #include "norec.xbm"
49 #include "locked.xbm"
50 #include "unlocked.xbm"
51 #include "mute.xbm"
52 #include "icon.xbm"
53 #include "ok.xbm"
54 #include "none.xbm"
55 #include "fallback.h"
56 #include "scf.h"
57
58 #define LEFT 0
59 #define RIGHT 1
60
61 typedef struct {
62 int dev;
63 int locked;
64 int max;
65 int mute;
66 Widget box;
67 Widget sll;
68 Widget slr;
69 Widget vol;
70 Widget lck;
71 Widget rec;
72 Widget lbl;
73 Widget mut;
74 Pixmap rec_bm;
75 Pixmap norec_bm;
76 Pixmap lck_bm;
77 Pixmap unlck_bm;
78 Pixmap none_bm;
79 Pixmap mute_bm;
80 XColor active;
81 } wMixer;
82
83 typedef struct {
84
85 /* resources
86 */
87 char *dev_name;
88 int update_time;
89 char *help_command;
90 Pixel focus_color;
91
92 /* private
93 */
94 char *program;
95 wMixer *devs;
96 XtAppContext context;
97 Widget toplevel;
98 Widget menu_box;
99 Widget label;
100 WidgetList mDev;
101 Pixmap checked;
102 } AppData;
103
104 #define XtNdeviceName "deviceName"
105 #define XtCDeviceName "DeviceName"
106 #define XtNupdateTime "updateTime"
107 #define XtCUpdateTime "UpdateTime"
108 #define XtNhelpCommand "helpCommand"
109 #define XtCHelpCommand "HelpCommand"
110 #define XtNfocusColor "focusColor"
111 #define XtCFocusColor "FocusColor"
112
113 /* some globals
114 */
115
116 static XtResource resources [] = {
117 {
118 XtNdeviceName,
119 XtCDeviceName,
120 XtRString,
121 sizeof(String),
122 XtOffsetOf(AppData, dev_name),
123 XtRString,
124 DEFAULT_MIXER
125 },
126 {
127 XtNupdateTime,
128 XtCUpdateTime,
129 XtRInt,
130 sizeof(int),
131 XtOffsetOf(AppData, update_time),
132 XtRImmediate,
133 (XtPointer)60
134 },
135 {
136 XtNhelpCommand,
137 XtCHelpCommand,
138 XtRString,
139 sizeof(String),
140 XtOffsetOf(AppData, help_command),
141 XtRImmediate,
142 (XtPointer)NULL
143 },
144 {
145 XtNfocusColor,
146 XtCFocusColor,
147 XtRPixel,
148 sizeof (Pixel),
149 XtOffsetOf(AppData, focus_color),
150 XtRImmediate,
151 (XtPointer)NULL
152 }
153 };
154
155 static AppData App;
156
157 #define Toplevel() (App.toplevel)
158
159 /* actions definitions
160 */
161 static void ExitProgAction (Widget, XEvent*, String*, Cardinal*);
162 static void ReleaseMenuAction (Widget, XEvent*, String*, Cardinal*);
163 static void ActivateMenuAction (Widget, XEvent*, String*, Cardinal*);
164 static void ShowMenuAction (Widget, XEvent*, String*, Cardinal*);
165 static void SetFocusAction (Widget, XEvent*, String*, Cardinal*);
166 static void CloseWinAction (Widget, XEvent*, String*, Cardinal*);
167
168 static XtActionsRec actionTable[] = {
169 { "exit-program", ExitProgAction },
170 { "release-menu", ReleaseMenuAction },
171 { "activate-menu", ActivateMenuAction },
172 { "show-menu", ShowMenuAction },
173 { "close-window", CloseWinAction },
174 { "set-focus", SetFocusAction },
175 };
176
177 /* protos
178 */
179 void CbChangeLabel (Widget w, XtPointer client_data, XtPointer call_data);
180 static void RegisterWidget (Widget);
181 static Widget NameToWidget (String);
182
183 /* actions */
184
185 /*
186 * exit xmixer
187 */
188 static void
ExitProgAction(Widget w,XEvent * ev,String * parms,Cardinal * num_parms)189 ExitProgAction (Widget w, XEvent *ev, String *parms, Cardinal *num_parms)
190 {
191 printf ("Program canceld!\n");
192 exit(0);
193 }
194
195 /*
196 * release the focus from the menu bar
197 */
198 static void
ReleaseMenuAction(Widget w,XEvent * ev,String * parms,Cardinal * num_parms)199 ReleaseMenuAction (Widget w, XEvent *ev, String *parms, Cardinal *num_parms)
200 {
201 #ifdef DEBUG
202 printf ("release-menu()\n");
203 #endif
204 }
205
206 /*
207 * set the focus from the menu bar
208 */
209 static void
ActivateMenuAction(Widget w,XEvent * ev,String * parms,Cardinal * num_parms)210 ActivateMenuAction (Widget w, XEvent *ev, String *parms, Cardinal *num_parms)
211 {
212 #ifdef DEBUG
213 printf ("activate-menu()\n");
214 #endif
215 if (*num_parms) {
216 Widget first;
217 first = NameToWidget (parms[0]);
218 if (first) {
219 XtSetKeyboardFocus (Toplevel(), first);
220 }
221 }
222 }
223
224 /*
225 */
226 static void
ShowMenuAction(Widget w,XEvent * ev,String * parms,Cardinal * num_parms)227 ShowMenuAction (Widget w, XEvent *ev, String *parms, Cardinal *num_parms)
228 {
229 Dimension height, bheight;
230 #ifdef DEBUG
231 printf ("show-menu()\n");
232 #endif
233 if (XtIsManaged(App.menu_box))
234 return;
235 XtVaGetValues (XtParent(App.menu_box), XtNheight, &height, NULL);
236 XtVaGetValues (App.menu_box, XtNheight, &bheight, NULL);
237 XtManageChild (App.menu_box);
238 XtVaSetValues (Toplevel(), XtNheight, height + bheight, NULL);
239 }
240
241 /*
242 */
243 static void
SetFocusAction(Widget w,XEvent * ev,String * parms,Cardinal * num_parms)244 SetFocusAction (Widget w, XEvent *ev, String *parms, Cardinal *num_parms)
245 {
246 #ifdef DEBUG
247 printf ("set-focus()\n");
248 #endif
249 if (*num_parms == 2) {
250 Widget widget;
251 Widget tree;
252 tree = NameToWidget (parms[0]);
253 widget = NameToWidget (parms[1]);
254 if (tree && widget) {
255 #ifdef DEBUG
256 printf ("set-focus(%s, %s)\n", XtName(tree), XtName(widget));
257 #endif
258 XtSetKeyboardFocus (tree, widget);
259 }
260 }
261 }
262
263 /*
264 */
265 static void
update_label(wMixer * m)266 update_label (wMixer *m)
267 {
268 int vol_left, vol_right = 0;
269 static char buff[32];
270
271 vol_left = mixer_get_vol_left (1, m->dev);
272 if (mixer_is_stereo (1, m->dev)) {
273 vol_right = mixer_get_vol_right (1, m->dev);
274 sprintf (buff, "%3d:%3d", vol_left, vol_right);
275 } else {
276 sprintf (buff, "%3d ", vol_left);
277 }
278 XtVaSetValues (App.label, XtNlabel, buff, NULL);
279 }
280
281 /*
282 * close the named window
283 */
284 static void
CloseWinAction(Widget w,XEvent * ev,String * parms,Cardinal * num_parms)285 CloseWinAction (Widget w, XEvent *ev, String *parms, Cardinal *num_parms)
286 {
287 if (*num_parms) {
288 Widget win;
289 win = XtNameToWidget (Toplevel(), parms[0]);
290 if (win)
291 XtDestroyWidget (win);
292 }
293 }
294
295
296 /* callbacks */
297 /*
298 */
299 static void
CbExec(Widget w,XtPointer client_data,XtPointer call_data)300 CbExec (Widget w, XtPointer client_data, XtPointer call_data)
301 {
302 char *exec;
303
304 exec = (char *) client_data;
305 system (exec);
306 }
307
308 /*
309 */
310 static void
CbQuit(Widget w,XtPointer client_data,XtPointer call_data)311 CbQuit (Widget w, XtPointer client_data, XtPointer call_data)
312 {
313 exit (0);
314 }
315
316 /*
317 * close the named popup shell
318 */
319 static void
CbClose(Widget w,XtPointer client_data,XtPointer call_data)320 CbClose (Widget w, XtPointer client_data, XtPointer call_data)
321 {
322 XtDestroyWidget ((Widget) client_data);
323 }
324
325 /*
326 */
327 static void
CbMute(Widget w,XtPointer client_data,XtPointer call_data)328 CbMute (Widget w, XtPointer client_data, XtPointer call_data)
329 {
330 Position y;
331 wMixer *dev = (wMixer *)client_data;
332 XColor color;
333
334 if (!XwIsSet(w)) {
335 dev->mute = 1;
336 mixer_set_vol_left (1, dev->dev, 0);
337 if (mixer_is_stereo (1, dev->dev))
338 mixer_set_vol_right (1, dev->dev, 0);
339 XtVaGetValues (w, XtNbackground, &color, NULL);
340 } else {
341 dev->mute = 0;
342 XtVaGetValues (dev->sll, XtNsliderY, &y, NULL);
343 mixer_set_vol_left (1, dev->dev, 100 - y);
344 if (mixer_is_stereo (1, dev->dev)) {
345 XtVaGetValues (dev->slr, XtNsliderY, &y, NULL);
346 mixer_set_vol_right (1, dev->dev, 100 - y);
347 }
348 color = dev->active;
349 }
350 XtVaSetValues (w, XtNforeground, color, NULL);
351 update_label (dev);
352 }
353
354 /*
355 * map or unmap a slider box and adjust the width of the toplevel
356 */
357 static void
CbMap(Widget menu_entry,XtPointer client_data,XtPointer call_data)358 CbMap (Widget menu_entry, XtPointer client_data, XtPointer call_data)
359 {
360 Widget box = (Widget) client_data;
361 Dimension width = 0, dev_width = 0, border_width = 0, space = 0;
362 Dimension height = 0, dev_height;
363 int change_menu_box = 0;
364
365 char *name = XtName (box);
366 if (strcmp (name, "menu_box") == 0) {
367 change_menu_box = 1;
368 }
369
370 XtVaGetValues (box, XtNwidth, &dev_width, XtNheight, &dev_height,
371 XtNborderWidth, &border_width, NULL);
372 XtVaGetValues (XtParent(box), XtNhSpace, &space, XtNheight, &height, NULL);
373 XtVaGetValues (Toplevel(), XtNwidth, &width, NULL);
374 if (XtIsManaged (box)) {
375 XtUnmanageChild (box);
376 if (!change_menu_box) {
377 XtVaSetValues (menu_entry, XtNleftBitmap, None, NULL);
378 XtVaSetValues (Toplevel(),
379 XtNwidth, width - dev_width - space - 2 * border_width,
380 NULL);
381 } else {
382 /* disable menu */
383 XtVaSetValues (Toplevel(),
384 XtNheight, height - dev_height,
385 NULL);
386 }
387 } else {
388 XtManageChild (box);
389 XtVaSetValues (menu_entry, XtNleftBitmap, App.checked, NULL);
390 XtVaSetValues (Toplevel(),
391 XtNwidth, width + dev_width + space + 2 * border_width,
392 NULL);
393 }
394 }
395
396 /*
397 * event handler to close the application or the window if window manager
398 * sends a WM_DELETE_WINDOW message
399 */
400 void
WmDelEH(Widget shell,XtPointer xtp,XEvent * event,Boolean * boo)401 WmDelEH (Widget shell, XtPointer xtp, XEvent *event, Boolean *boo)
402 {
403 #ifdef DEBUG
404 fprintf (stderr, "WmDelEH() event type=%d format=%d\n", event->type,
405 event->type == ClientMessage ? event->xclient.format : -1);
406 #endif
407 if (event->type != ClientMessage) /* =33 */
408 return;
409 if (event->xclient.format != 32)
410 return;
411 if (event->xclient.data.l[0] != *((Atom*)xtp))
412 return;
413
414 if (!XtParent (shell)) {
415 /* destroy the toplevel widget
416 * and terminate the application */
417 XtDestroyWidget (shell);
418 exit (0);
419 } else {
420 XtDestroyWidget (shell);
421 }
422 }
423
424 /*
425 * about popup
426 */
427 static void
CbAbout(Widget w,XtPointer client_data,XtPointer call_data)428 CbAbout (Widget w, XtPointer client_data, XtPointer call_data)
429 {
430 Widget toplevel, shell, box, esc, label;
431 Position x, y;
432 static Atom wm_delete;
433
434 toplevel = Toplevel();
435 wm_delete = (Atom)client_data;
436 shell= XtVaCreatePopupShell ("about", transientShellWidgetClass, toplevel,
437 NULL);
438 box = XtVaCreateManagedWidget ("about_box", boxWidgetClass, shell,
439 NULL);
440 label= XtVaCreateManagedWidget ("about_label", xwLabelWidgetClass, box,
441 XtNlabel, _ABOUT_,
442 NULL);
443 esc = XtVaCreateManagedWidget ("Ok", xwButtonWidgetClass, box,
444 NULL);
445 XtAddCallback (esc, XtNcallback, CbClose, shell);
446 XtTranslateCoords (toplevel, 0, 0, &x ,&y);
447 XtVaSetValues (shell, XtNx, x+25, XtNy, y+25, NULL);
448 XtPopup (shell, XtGrabNonexclusive);
449 XtSetKeyboardFocus (box, esc);
450 XSetWMProtocols (XtDisplay(shell), XtWindow(shell), &wm_delete, 1);
451 XtAddEventHandler (shell, NoEventMask, True, WmDelEH, &wm_delete);
452 }
453
454
455 /*
456 * save current settings in ~/.xmixer.scf
457 */
458 static void
CbSave(Widget w,XtPointer client_data,XtPointer call_data)459 CbSave (Widget w, XtPointer client_data, XtPointer call_data)
460 {
461 AppData *ad = (AppData *) client_data;
462 char *pname = ad->program;
463 const char *fname, *name, *label;
464 FILE *fp;
465 int i, nod;
466
467 fname = scf_file_name (pname, SCF_PRIVAT);
468 if (fname) {
469 #ifdef DEBUG
470 fprintf (stderr, "CbSave() %s\n", fname);
471 #endif
472 nod = ad->devs[0].max;
473 fp = fopen (fname, "wb");
474 if (fp) {
475 fprintf (fp, "#SCFF 1.0\n");
476 fprintf (fp, "# version of the xmixer configuration file\n");
477 fprintf (fp, "version = 1\n\n");
478 fprintf (fp, "# mixer device name\n");
479 fprintf (fp, "[%s]\n\n", ad->dev_name);
480 for (i = 0; i < nod; i++) {
481 name = mixer_get_name(1, i);
482 fprintf (fp, "# Settings for the \"%s\"-device = ", name);
483 if (mixer_is_stereo(1, i))
484 fprintf (fp, "{ Int[0-100]:leftValue Int[0-100]:rightValue }\n");
485 else
486 fprintf (fp, "{ Int[0-100]:value }\n");
487
488 fprintf (fp, "%s = { ", mixer_get_name(1, i));
489 if (mixer_is_stereo(1, i)) {
490 fprintf (fp, "%d %d }\n", mixer_get_vol_left(1,i), mixer_get_vol_right(1,i));
491 } else {
492 fprintf (fp, "%d }\n", mixer_get_vol_left(1,i));
493 }
494 fprintf (fp, "# show slider for device \"%s\" = Bool[True, False]:Map\n", name);
495 if (XtIsManaged(ad->devs[i].box))
496 fprintf (fp, "%s_map = True\n", name);
497 else
498 fprintf (fp, "%s_map = False\n", name);
499 label = NULL;
500 XtVaGetValues (ad->devs[i].lbl, XtNlabel, &label, NULL);
501 if (label) {
502 fprintf (fp,"# label of the device \"%s\" = String:Label\n",
503 name);
504 fprintf (fp,"%s_label = \"%s\"\n\n", name, label);
505 }
506 }
507 fclose (fp);
508 }
509 }
510 }
511
512
513
514 /*
515 */
516 static void
CbPanL(Widget w,XtPointer client_data,XtPointer call_data)517 CbPanL (Widget w, XtPointer client_data, XtPointer call_data)
518 {
519 wMixer *m;
520 int y, vol;
521
522 m = (wMixer *) client_data;
523 y = (int) ((XawPannerReport *)call_data)->slider_y;
524 vol= 100 - y;
525 if (!m->mute)
526 vol = mixer_set_vol_left (1, m->dev, vol);
527 #ifdef DEBUG
528 fprintf (stderr, "CbPanL() %d vol=%d\n", m->dev, vol);
529 #endif
530 if (m->locked && mixer_is_stereo (1, m->dev)) {
531 XtVaSetValues (m->slr, XtNsliderY, y, NULL);
532 if (!m->mute)
533 mixer_set_vol_right (1, m->dev, vol);
534 }
535 update_label (m);
536 }
537
538 /*
539 */
540 static void
CbPanR(Widget w,XtPointer client_data,XtPointer call_data)541 CbPanR (Widget w, XtPointer client_data, XtPointer call_data)
542 {
543 wMixer *m;
544 int y, vol;
545
546 m = (wMixer *) client_data;
547 y = (int) ((XawPannerReport *)call_data)->slider_y;
548 vol=100 - y;
549 #ifdef DEBUG
550 fprintf (stderr, "CbPanR() %d vol=%d\n", m->dev, vol);
551 #endif
552 if (!m->mute)
553 mixer_set_vol_right (1, m->dev, vol);
554 if (m->locked) {
555 XtVaSetValues (m->sll, XtNsliderY, y, NULL);
556 if (!m->mute)
557 mixer_set_vol_left (1, m->dev, vol);
558 }
559 update_label (m);
560 }
561
562
563 /*
564 */
565 static void
CbLock(Widget w,XtPointer client_data,XtPointer call_data)566 CbLock (Widget w, XtPointer client_data, XtPointer call_data)
567 {
568 int state;
569 wMixer *m;
570
571 state = XwIsSet(w);
572 m = (wMixer *) client_data;
573
574 if (!mixer_is_stereo (1, m->dev)) {
575 XtVaSetValues (w, XtNstate, True, NULL);
576 return;
577 }
578 if (state) {
579 XtVaSetValues (w, XtNbitmap, m->lck_bm, NULL);
580 m->locked = 1;
581 } else {
582 XtVaSetValues (w, XtNbitmap, m->unlck_bm, NULL);
583 m->locked = 0;
584 }
585 }
586
587 /*
588 */
589 static void
CbRec(Widget w,XtPointer client_data,XtPointer call_data)590 CbRec (Widget w, XtPointer client_data, XtPointer call_data)
591 {
592 int i;
593 wMixer *devs;
594
595 devs = (wMixer *) client_data;
596
597 if (XwIsSet(w)) {
598 for (i = 0; i < devs[0].max; i++) {
599 if (mixer_is_rec_dev (1, i)) {
600 if (w == devs[i].rec) {
601 mixer_set_rec (1, i, 1);
602 XtVaSetValues (w, XtNbitmap, devs[i].rec_bm, NULL);
603 } else {
604 if (mixer_exclusive_input (1)) {
605 mixer_set_rec (1, i, 0);
606 XtVaSetValues (devs[i].rec, XtNstate, False,
607 XtNbitmap, devs[i].norec_bm, NULL);
608 }
609 }
610 }
611 }
612 } else {
613 for (i = 0; i < devs[0].max; i++) {
614 if (w == devs[i].rec) {
615 mixer_set_rec (1, i, 0);
616 XtVaSetValues (w, XtNbitmap, devs[i].norec_bm, NULL);
617 break;
618 }
619 }
620 }
621 }
622
623 /*
624 * update the values, some other programs may have
625 * changed them..
626 */
627 static void
TCbUpdate(XtPointer client_data,XtIntervalId id)628 TCbUpdate (XtPointer client_data, XtIntervalId id)
629 {
630 int no_of_devs, i, vol;
631 wMixer *devs;
632
633 devs = (wMixer *) client_data;
634 no_of_devs = mixer_num_of_devs (1);
635 for (i = 0; i < no_of_devs; i++) {
636 vol = mixer_get_vol_left (1, i);
637 if (devs[i].mute) {
638 continue;
639 }
640 if (mixer_is_stereo (1, i)) {
641 XtVaSetValues (devs[i].sll, XtNsliderY, 100-vol, NULL);
642 vol = mixer_get_vol_right (1, i);
643 XtVaSetValues (devs[i].slr, XtNsliderY, 100-vol, NULL);
644 #ifdef DEBUG2
645 fprintf (stderr,
646 "%s %d:%d\n", mixer_get_label(1,i), vol, mixer_get_vol_left(1,i));
647 #endif
648 } else {
649 XtVaSetValues (devs[i].sll, XtNsliderY, 100-vol, NULL);
650 #ifdef DEBUG2
651 fprintf (stderr,
652 "%s %d\n", mixer_get_label(1,i), vol);
653 #endif
654 }
655 }
656 XtAppAddTimeOut (App.context, App.update_time * 1000,
657 (XtTimerCallbackProc)TCbUpdate, devs);
658 }
659
660 /*
661 * reload saved settings
662 */
663 static void
CbReload(Widget w,XtPointer client_data,XtPointer call_data)664 CbReload (Widget w, XtPointer client_data, XtPointer call_data)
665 {
666 AppData *ad = (AppData *) client_data;
667 scf_id id;
668 int nod, i;
669 string name;
670 char key[32];
671 int map;
672 int left, right;
673
674 id = scf_init (ad->program, NULL);
675 if (scf_read (id)) {
676 nod = mixer_num_of_devs (1);
677 for ( i = 0; i < nod; i++) {
678 name = (const string) mixer_get_name (1, i);
679 if (scf_get_array_int_val (id, ad->dev_name, name, 0, &left) == SCF_TRUE)
680 mixer_set_vol_left (1, i, left);
681 if (mixer_is_stereo (1, i)) {
682 if (scf_get_array_int_val (id, ad->dev_name, name, 1, &right) == SCF_TRUE)
683 mixer_set_vol_right (1,i, right);
684 }
685 sprintf (key, "%s_map", name);
686 if (scf_get_bool_val (id, ad->dev_name, key, &map)) {
687 if (map == SCF_FALSE) {
688 if (XtIsManaged(ad->devs[i].box))
689 CbMap (ad->mDev[i], ad->devs[i].box, NULL);
690 } else
691 if (!XtIsManaged(ad->devs[i].box))
692 CbMap (ad->mDev[i], ad->devs[i].box, NULL);
693 }
694 }
695 TCbUpdate ((XtPointer)ad->devs, 0);
696 }
697 scf_fini (id);
698 }
699
700
701 /*
702 */
703 void
focusEH(Widget slider,XtPointer subtree,XEvent * event,Boolean * boo)704 focusEH (Widget slider, XtPointer subtree, XEvent *event, Boolean *boo)
705 {
706 static Widget prev = None;
707 static Pixel pp;
708 int i;
709 Widget box;
710 wMixer *m;
711 #ifdef DEBUG
712 printf ("focus() widget=%s\n", XtName(slider));
713 #endif
714 box = XtParent(slider);
715 if (box != prev) {
716 if (prev) {
717 XtVaSetValues (prev, XtNborderColor, pp, NULL);
718 }
719 XtVaGetValues (box, XtNborderColor, &pp, NULL);
720 prev = box;
721 XtVaSetValues (box, XtNborderColor, App.focus_color, NULL);
722 }
723 XtSetKeyboardFocus (Toplevel(), slider);
724 m = App.devs;
725 for (i = 0; i < m->max; i++) {
726 if (m[i].box == box) {
727 update_label(&(m[i]));
728 }
729 }
730 }
731
732 /*
733 */
734 static void
CbMenuTab(Widget w,XtPointer client,XtPointer call)735 CbMenuTab (Widget w, XtPointer client, XtPointer call)
736 {
737 #ifdef DEBUG
738 printf ("CbMenuTab()\n");
739 #endif
740 XtSetKeyboardFocus (Toplevel(), (Widget)client);
741 }
742
743 /*
744 * not ready!
745 */
746 void
tabEH(Widget w,XtPointer xtp,XEvent * event,Boolean * boo)747 tabEH (Widget w, XtPointer xtp, XEvent *event, Boolean *boo)
748 {
749 int len, dev_id, nod, i;
750 KeySym ks;
751 XKeyEvent *xkey;
752 XComposeStatus cs;
753 char key[8];
754 Widget dev;
755 AppData *ad = (AppData *) xtp;
756
757 xkey = &event->xkey;
758 key[1] = '\0';
759 len = XLookupString (xkey, key, 8, &ks, &cs);
760 dev = XtParent(w);
761 #ifdef DEBUG
762 fprintf (stderr, "tabEH() widget=%s box=%s keysym=%X\n", XtName(w), XtName(dev), (int)ks);
763 #endif
764 if ((ks == XK_Tab) || (ks == XK_ISO_Left_Tab) ||
765 (ks == XK_Left) || (ks == XK_Right)) {
766 /*
767 * find next or the previous widget
768 */
769 dev_id = atoi (XtName(dev));
770 nod = mixer_num_of_devs (1);
771 for (i = 0; i < nod; i++) {
772 if (ks == XK_Tab || ks == XK_Right) {
773 dev_id++;
774 if (dev_id > nod-1)
775 dev_id = 0;
776 } else {
777 dev_id--;
778 if (dev_id < 0)
779 dev_id = nod-1;
780 }
781 if (XtIsManaged (ad->devs[dev_id].box)) {
782 focusEH (ad->devs[dev_id].sll, XtParent(ad->devs[dev_id].box), NULL, NULL);
783 return;
784 }
785 }
786 }
787 #ifdef DEBUG
788 else {
789 printf ("tabEH() key sym=%X shift? %d\n", (int)ks, event->xkey.state & ShiftMask);
790 }
791 #endif
792 }
793
794 /*
795 */
796 void
mouseEH(Widget w,XtPointer xtp,XEvent * event,Boolean * boo)797 mouseEH (Widget w, XtPointer xtp, XEvent *event, Boolean *boo)
798 {
799 # define offset 15
800 KeySym ks;
801 XComposeStatus cs;
802 int x,y;
803 #ifdef DEBUG
804 printf ("mouseEH()\n");
805 #endif
806 x = y = 0;
807 XLookupString (&(event->xkey), NULL, 0, &ks, &cs);
808 switch (ks) {
809 case XK_Right:
810 x = offset;
811 break;
812 case XK_Left:
813 x = -offset;
814 break;
815 case XK_Up:
816 y = -offset;
817 break;
818 case XK_Down:
819 y = offset;
820 break;
821 default:
822 break;
823 }
824 XWarpPointer (XtDisplay(w), None, None, 0, 0, 0, 0, x, y);
825 }
826
827
828 /*
829 */
830 char *
gui_init(int * argc,char *** argv)831 gui_init (int *argc, char ***argv)
832 {
833 App.toplevel = XtVaAppInitialize (&App.context, "XMixer", NULL, 0,
834 argc, *argv, fallback, NULL);
835 RegisterWidget (App.toplevel);
836 XtVaGetApplicationResources (App.toplevel,
837 &App,
838 resources,
839 XtNumber (resources),
840 NULL);
841 XtAppAddActions (App.context, actionTable, sizeof(actionTable)/sizeof(XtActionsRec));
842 return ((char *)App.dev_name);
843 }
844
845
846
847 /*
848 * gui main()
849 */
gui_main(char * mixer_dev,char * pname)850 int gui_main (char *mixer_dev, char *pname)
851 {
852 Widget toplevel, frame, menu_box, quit, save, load, about, mixer;
853 Widget file_mb, file_menu, help_mb, help_menu, man;
854 Widget map_mb, map_menu, *menu_entries;
855 Pixmap icon_bm;
856 wMixer *devs;
857 int i, vol, no_of_devs, map;
858 scf_id scf;
859 char key[32], wname[8];
860 const char *name;
861 static Atom wm_delete;
862
863 no_of_devs = mixer_num_of_devs (1);
864 App.program = pname;
865 App.dev_name = mixer_dev;
866 toplevel = App.toplevel;
867 wm_delete = XInternAtom (XtDisplay(toplevel), "WM_DELETE_WINDOW", False);
868
869 devs = (wMixer *) malloc (sizeof (wMixer) * no_of_devs);
870 App.devs = devs;
871
872 icon_bm = XCreateBitmapFromData (XtDisplay(toplevel),
873 RootWindowOfScreen (XtScreen(toplevel)),
874 icon_bits, icon_width, icon_height);
875
876 XtVaSetValues (toplevel, XtNiconPixmap, icon_bm, NULL);
877
878 App.checked = XCreateBitmapFromData (XtDisplay(toplevel),
879 RootWindowOfScreen (XtScreen(toplevel)),
880 ok_bits, ok_width, ok_height);
881
882 /* the main application frame
883 */
884 frame = XtVaCreateManagedWidget (
885 "frame", panedWidgetClass, toplevel,
886 NULL);
887 RegisterWidget (frame);
888
889 App.menu_box = menu_box = XtVaCreateManagedWidget (
890 "menu_box", boxWidgetClass, frame,
891 XtNorientation, XtorientHorizontal,
892 XtNshowGrip, False,
893 NULL);
894 RegisterWidget (menu_box);
895
896 /* menus */
897 file_mb = XtVaCreateManagedWidget ( "file_mb", xwButtonWidgetClass,
898 menu_box,
899 XtNmenuName, "file_menu",
900 NULL);
901 RegisterWidget (file_mb);
902 file_menu = XtVaCreatePopupShell (
903 "file_menu", simpleMenuWidgetClass, file_mb,
904 NULL);
905 XtAddEventHandler (file_menu, KeyPressMask, False, mouseEH, NULL);
906
907 map_mb = XtVaCreateManagedWidget ( "map_mb", xwButtonWidgetClass,
908 menu_box,
909 XtNmenuName, "map_menu",
910 NULL);
911
912 map_menu = XtVaCreatePopupShell ( "map_menu", simpleMenuWidgetClass,
913 map_mb, NULL);
914
915 XtAddEventHandler (map_menu, KeyPressMask, False, mouseEH, NULL);
916
917 help_mb = XtVaCreateManagedWidget (
918 "help_mb", xwButtonWidgetClass, menu_box,
919 XtNmenuName, "help_menu",
920 NULL);
921 help_menu = XtVaCreatePopupShell (
922 "help_menu", simpleMenuWidgetClass, help_mb,
923 NULL);
924 XtAddEventHandler (help_menu, KeyPressMask, False, mouseEH, NULL);
925 App.label = XtVaCreateManagedWidget (
926 "label", xwLabelWidgetClass, menu_box,
927 XtNlabel, "???:???", NULL);
928
929 save = XtVaCreateManagedWidget (
930 "save", smeBSBObjectClass, file_menu, NULL);
931 XtAddCallback (save, XtNcallback, CbSave, &App);
932
933 load = XtVaCreateManagedWidget (
934 "load", smeBSBObjectClass, file_menu, NULL);
935 XtAddCallback (load, XtNcallback, CbReload, &App);
936
937 quit = XtVaCreateManagedWidget (
938 "quit", smeBSBObjectClass, file_menu, NULL);
939 XtAddCallback (quit, XtNcallback, CbQuit, NULL);
940
941 about = XtVaCreateManagedWidget (
942 "about", smeBSBObjectClass, help_menu, NULL);
943 XtAddCallback (about, XtNcallback, CbAbout, (XtPointer)wm_delete);
944
945 man = XtVaCreateManagedWidget (
946 "man", smeBSBObjectClass, help_menu, NULL);
947 XtAddCallback (man, XtNcallback, CbExec, App.help_command);
948
949 XtAddCallback (file_mb, XtNtabCallback, CbMenuTab, map_mb);
950 XtAddCallback (map_mb, XtNtabCallback, CbMenuTab, help_mb);
951 XtAddCallback (help_mb, XtNtabCallback, CbMenuTab, file_mb);
952
953 mixer = XtVaCreateManagedWidget (
954 "mixer_box", boxWidgetClass, frame,
955 XtNorientation, XtorientHorizontal,
956 NULL);
957
958 App.mDev =
959 menu_entries = (Widget *) malloc (sizeof(Widget) * (no_of_devs + 1));
960 for (i = 0; i < no_of_devs; i++) {
961 devs[i].dev = i;
962 devs[i].max = no_of_devs;
963
964 sprintf (wname, "%d", i);
965 devs[i].box = XtVaCreateManagedWidget (
966 wname, formWidgetClass, mixer, NULL);
967 RegisterWidget (devs[i].box);
968
969 devs[i].lbl = XtVaCreateManagedWidget (
970 mixer_get_label (1, i), xwButtonWidgetClass, devs[i].box,
971 XtNborderWidth, 0, XtNresize, True, XtNresizable, True,
972 NULL);
973 XtAddCallback (devs[i].lbl, XtNcallback, CbChangeLabel,
974 (XtPointer)wm_delete);
975
976 devs[i].sll = XtVaCreateManagedWidget (
977 "left", pannerWidgetClass, devs[i].box,
978 XtNfromVert, devs[i].lbl,
979 NULL);
980 XtAddCallback(devs[i].sll,XtNreportCallback,CbPanL,(XtPointer)&devs[i]);
981 XtAddEventHandler (devs[i].sll, ButtonPressMask, False, focusEH, mixer);
982 XtAddEventHandler (devs[i].sll, KeyPressMask, False, tabEH, &App);
983 if (mixer_is_stereo (1, i)) {
984 devs[i].slr = XtVaCreateManagedWidget (
985 "right", pannerWidgetClass, devs[i].box,
986 XtNfromVert, devs[i].lbl,
987 XtNfromHoriz, devs[i].sll,
988 NULL);
989 XtAddCallback (devs[i].slr, XtNreportCallback, CbPanR,
990 (XtPointer)&devs[i]);
991 XtAddEventHandler (devs[i].slr, ButtonPressMask, False,
992 focusEH, mixer);
993 XtAddEventHandler (devs[i].slr, KeyPressMask, False,
994 tabEH, &App);
995 }
996
997 devs[i].lck = XtVaCreateManagedWidget (
998 "lck", xwToggleWidgetClass, devs[i].box,
999 XtNstate, True,
1000 XtNfromVert, devs[i].sll,
1001 NULL);
1002 devs[i].locked = 1;
1003 XtAddCallback (devs[i].lck, XtNcallback, CbLock, (XtPointer)&devs[i]);
1004
1005 if (mixer_is_rec_dev (1, i)) {
1006 devs[i].rec = XtVaCreateManagedWidget (
1007 "rec", xwToggleWidgetClass, devs[i].box,
1008 XtNfromHoriz, devs[i].lck,
1009 XtNfromVert, devs[i].sll,
1010 NULL);
1011 XtAddCallback (devs[i].rec, XtNcallback, CbRec, (XtPointer) devs);
1012 } else {
1013 devs[i].rec = XtVaCreateManagedWidget (
1014 "rec", xwToggleWidgetClass, devs[i].box,
1015 XtNsensitive, False,
1016 /* XtNshadowType, XtShadowNone, */
1017 XtNfromHoriz, devs[i].lck,
1018 XtNfromVert, devs[i].sll,
1019 NULL);
1020 }
1021 devs[i].mut = XtVaCreateManagedWidget ("mut", xwToggleWidgetClass,
1022 devs[i].box,
1023 XtNstate, True,
1024 XtNfromHoriz, devs[i].rec,
1025 XtNfromVert, devs[i].sll,
1026 NULL);
1027 XtVaGetValues (devs[i].mut, XtNforeground, &(devs[i].active), NULL);
1028 XtAddCallback (devs[i].mut, XtNcallback, CbMute, &(devs[i]));
1029 menu_entries[i] = XtVaCreateManagedWidget (mixer_get_label (1,i),
1030 smeBSBObjectClass, map_menu,
1031 XtNleftMargin, ok_width + 2,
1032 XtNleftBitmap, App.checked, NULL);
1033 XtAddCallback (menu_entries[i], XtNcallback, CbMap, devs[i].box);
1034 }
1035 /* */
1036 menu_entries[i] = XtVaCreateManagedWidget ("menu",
1037 smeBSBObjectClass, map_menu,
1038 XtNleftMargin, ok_width + 2,
1039 XtNleftBitmap, App.checked, NULL);
1040 XtAddCallback (menu_entries[i], XtNcallback, CbMap, App.menu_box);
1041
1042 /* prevent flickering while unmapping some devices */
1043 XtVaSetValues (toplevel, XtNmappedWhenManaged, False, NULL);
1044
1045 XtRealizeWidget (toplevel);
1046
1047 devs[0].rec_bm = XCreateBitmapFromData (XtDisplay (mixer), XtWindow (mixer),
1048 input_bits, input_width, input_height);
1049 devs[0].norec_bm=XCreateBitmapFromData (XtDisplay (mixer), XtWindow (mixer),
1050 norec_bits, norec_width, norec_height);
1051 devs[0].lck_bm = XCreateBitmapFromData (XtDisplay (mixer), XtWindow (mixer),
1052 locked_bits, locked_width, locked_height);
1053 devs[0].unlck_bm=XCreateBitmapFromData (XtDisplay (mixer), XtWindow (mixer),
1054 unlocked_bits, unlocked_width, unlocked_height);
1055 devs[0].none_bm=XCreateBitmapFromData (XtDisplay (mixer), XtWindow (mixer),
1056 none_bits, none_width, none_height);
1057 devs[0].mute_bm=XCreateBitmapFromData (XtDisplay (mixer), XtWindow (mixer),
1058 mute_bits, mute_width, mute_height);
1059
1060 for ( i = 0; i < no_of_devs; i++) {
1061 devs[i].rec_bm = devs[0].rec_bm;
1062 devs[i].norec_bm = devs[0].norec_bm;
1063 devs[i].lck_bm = devs[0].lck_bm;
1064 devs[i].unlck_bm = devs[0].unlck_bm;
1065 devs[i].none_bm = devs[0].none_bm;
1066 devs[i].mute_bm = devs[0].mute_bm;
1067 if (mixer_is_rec_dev (1, i)) {
1068 if (mixer_is_rec_on (1, i)) {
1069 XtVaSetValues (devs[i].rec,
1070 XtNstate, True,
1071 XtNbitmap, devs[i].rec_bm,
1072 NULL);
1073 } else {
1074 XtVaSetValues (devs[i].rec,
1075 XtNstate, False,
1076 XtNbitmap, devs[i].norec_bm,
1077 NULL);
1078 }
1079 } else {
1080 XtVaSetValues (devs[i].rec, XtNbitmap, devs[i].none_bm, NULL);
1081 }
1082 vol = mixer_get_vol_left (1, i);
1083 XtVaSetValues (devs[i].mut, XtNbitmap, devs[i].mute_bm, NULL);
1084 XtVaSetValues (devs[i].sll, XtNsliderY, 100-vol, NULL);
1085 if (mixer_is_stereo (1, i)) {
1086 if (vol == mixer_get_vol_right (1, i)) {
1087 XtVaSetValues (devs[i].lck, XtNbitmap, devs[i].lck_bm, NULL);
1088 XtVaSetValues (devs[i].slr, XtNsliderY, 100-vol, NULL);
1089 } else {
1090 XtVaSetValues (devs[i].lck, XtNbitmap, devs[i].unlck_bm,
1091 XtNstate, False, NULL);
1092 vol = mixer_get_vol_right (1, i);
1093 XtVaSetValues (devs[i].slr, XtNsliderY, 100-vol, NULL);
1094 devs[i].locked = 0;
1095 }
1096 } else {
1097 XtVaSetValues (devs[i].lck,
1098 XtNbitmap, devs[i].none_bm,
1099 XtNstate, False,
1100 XtNsensitive, False,
1101 /* XtNshadowType, XtShadowNone, */
1102 NULL);
1103 }
1104 }
1105
1106 /* restore settings for map/unmap
1107 */
1108 scf = scf_init (pname, NULL);
1109 if (scf_read (scf)) {
1110 char *l;
1111 for ( i = 0; i < no_of_devs; i++) {
1112 name = mixer_get_name (1, i);
1113 sprintf (key, "%s_map", name);
1114 if (scf_get_bool_val (scf, mixer_dev, key, &map)) {
1115 if (map == SCF_FALSE) {
1116 CbMap (menu_entries[i], devs[i].box, NULL);
1117 }
1118 }
1119 sprintf (key, "%s_label", name);
1120 l = scf_get_val (scf, mixer_dev, key);
1121 if (l) {
1122 XtVaSetValues (devs[i].lbl, XtNlabel, l, NULL);
1123 XtVaSetValues (menu_entries[i], XtNlabel, l, NULL);
1124 }
1125 }
1126 }
1127 scf_fini (scf);
1128
1129
1130 XtMapWidget (toplevel);
1131 XtAppAddTimeOut (App.context, App.update_time * 1000,
1132 (XtTimerCallbackProc) TCbUpdate, (XtPointer)devs);
1133
1134 XSetWMProtocols (XtDisplay(toplevel), XtWindow(toplevel), &wm_delete, 1);
1135 XtAddEventHandler (toplevel, NoEventMask, True, WmDelEH, &wm_delete);
1136
1137 XtInstallAccelerators (frame, file_mb);
1138 XtInstallAccelerators (frame, map_mb);
1139 XtInstallAccelerators (frame, help_mb);
1140
1141 XtAppMainLoop (App.context);
1142 return (ERROR);
1143 }
1144
1145
1146 /*
1147 * for an internal list ..
1148 */
1149 typedef struct widgets {
1150 Widget w;
1151 struct widgets *next;
1152 } Widgets;
1153
1154 static Widgets *first = NULL;
1155
1156 /*
1157 */
1158 static void
RegisterWidget(Widget w)1159 RegisterWidget (Widget w)
1160 {
1161 Widgets *t = first;
1162 Widgets *new = malloc (sizeof (Widgets));
1163 if (!new)
1164 return;
1165 new->w = w;
1166 new->next = NULL;
1167 if (!t) {
1168 first = new;
1169 } else {
1170 while (t->next)
1171 t = t->next;
1172 t->next = new;
1173 }
1174 }
1175
1176 /*
1177 */
1178 static Widget
NameToWidget(String name)1179 NameToWidget (String name)
1180 {
1181 Widgets *t = first;
1182 while (t && name) {
1183 if (strcmp (XtName(t->w), name) == 0)
1184 return (t->w);
1185 t = t->next;
1186 }
1187 return (None);
1188 }
1189
1190