OSDN Git Service

Make mute show
[timidity41/timidity41.git] / interface / xaw_i.c
1 /*
2     TiMidity++ -- MIDI to WAVE converter and player
3     Copyright (C) 1999-2004 Masanao Izumo <iz@onicos.co.jp>
4     Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
19
20     xaw_i.c - XAW Interface
21         from Tomokazu Harada <harada@prince.pe.u-tokyo.ac.jp>
22         modified by Yoshishige Arai <ryo2@on.rim.or.jp>
23         modified by Yair Kalvariski <cesium2@gmail.com>
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif /* HAVE_CONFIG_H */
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <math.h>
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif /* HAVE_UNISTD_H */
35 #ifndef NO_STRING_H
36 #include <string.h>
37 #else
38 #include <strings.h>
39 #endif /* !NO_STRING_H */
40 #ifdef HAVE_SYS_TYPES_H
41 #include <sys/types.h>
42 #endif /* HAVE_SYS_TYPES_H */
43 #include <pwd.h>
44 #ifdef HAVE_SYS_STAT_H
45 #include <sys/stat.h>
46 #endif /* HAVE_SYS_STAT_H */
47
48 #include "xaw.h"
49 #include "x_trace.h"
50 #include "timidity.h"
51 #include "common.h"
52 #include "instrum.h"
53 #include "playmidi.h"
54 #include "readmidi.h"
55 #include "controls.h"
56 #include "strtab.h"
57 #include "arc.h"
58
59 #include <X11/IntrinsicP.h>
60 #include <X11/StringDefs.h>
61 #include <X11/Xatom.h>
62
63 #include XAWINCDIR(AsciiText.h)
64 #include XAWINCDIR(Box.h)
65 #include XAWINCDIR(Cardinals.h)
66 #include XAWINCDIR(Dialog.h)
67 #include XAWINCDIR(Form.h)
68 #include XAWINCDIR(Label.h)
69 #include XAWINCDIR(List.h)
70 #include XAWINCDIR(MenuButton.h)
71 #include XAWINCDIR(Paned.h)
72 #include XAWINCDIR(Scrollbar.h)
73 #include XAWINCDIR(Simple.h)
74 #include XAWINCDIR(SimpleMenu.h)
75 #include XAWINCDIR(SmeBSB.h)
76 #include XAWINCDIR(SmeLine.h)
77 #if defined(HAVE_TIP) && !defined(XAWPLUS)
78 #include XAWINCDIR(Tip.h)
79 #endif /* HAVE_TIP && !XAWPLUS */
80 #include XAWINCDIR(Toggle.h)
81 #ifdef XawTraversal
82 #include XAWINCDIR(Traversal.h)
83 #endif /* XawTraversal */
84 #include XAWINCDIR(Viewport.h)
85
86 #ifdef OFFIX
87 #include <OffiX/DragAndDrop.h>
88 #include <OffiX/DragAndDropTypes.h>
89 #endif /* OFFIX */
90 #ifdef XDND
91 #include "xdnd.h"
92 #endif /* XDND */
93
94 #include "bitmaps/arrow.xbm"
95 #include "bitmaps/back.xbm"
96 #include "bitmaps/check.xbm"
97 #include "bitmaps/fast.xbm"
98 #include "bitmaps/fwrd.xbm"
99 #include "bitmaps/keyup.xbm"
100 #include "bitmaps/keydown.xbm"
101 #include "bitmaps/next.xbm"
102 #include "bitmaps/on.xbm"
103 #include "bitmaps/off.xbm"
104 #include "bitmaps/pause.xbm"
105 #include "bitmaps/play.xbm"
106 #include "bitmaps/prev.xbm"
107 #include "bitmaps/quit.xbm"
108 #include "bitmaps/random.xbm"
109 #include "bitmaps/repeat.xbm"
110 #include "bitmaps/slow.xbm"
111 #include "bitmaps/stop.xbm"
112 #include "bitmaps/timidity.xbm"
113
114 #ifndef S_ISDIR
115 #define S_ISDIR(mode)   (((mode)&0xF000) == 0x4000)
116 #endif /* !S_ISDIR */
117
118 #define DEFAULT_REG_WIDTH       400 /* default width when not in trace mode */
119
120 #define INIT_FLISTNUM MAX_DIRECTORY_ENTRY
121
122 #define MAX_POPUPNAME 15
123 #define MAX_FILTER 20
124 #define POPUP_HEIGHT 400
125 #define PANE_HEIGHT 200
126 #define INFO_HEIGHT 20
127 #define ran() (int) (51.0 * (rand() / (RAND_MAX + 1.0))) - 25;
128
129 typedef struct {
130   char *dirname;
131   char *basename;
132 } DirPath;
133
134 typedef struct {
135   String *StringArray;
136   unsigned int number;
137 } StringList;
138
139 typedef struct {
140  char ld_basepath[PATH_MAX];
141  char ld_popupname[MAX_POPUPNAME];
142  Widget ld_popup_load;
143  Widget ld_load_d;
144  Widget ld_load_f;
145  Widget ld_load_ok;
146  Widget ld_load_pane;
147  Widget ld_load_vport;
148  Widget ld_load_vportdir;
149  Widget ld_load_flist;
150  Widget ld_load_dlist;
151  Widget ld_cwd_l;
152  Widget ld_load_info;
153  Dimension ld_ldwidth;
154  Dimension ld_ldheight;
155  StringList ld_fdirlist;
156  StringList ld_fulldirlist;
157  StringList ld_ddirlist;
158  char ld_filter[MAX_FILTER];
159  char ld_cur_filter[MAX_FILTER];
160 } load_dialog;
161
162 typedef load_dialog *ldPointer;
163
164 typedef struct {
165  ldPointer ld;
166  char *name; 
167  struct ldStore_t *next;
168 } ldStore;
169
170 typedef ldStore *ldStorePointer;
171
172 static ldStorePointer ldSstart;
173 static ldPointer ld;
174
175 #define basepath ld->ld_basepath
176 #define popupname ld->ld_popupname
177 #define popup_load ld->ld_popup_load
178 #define load_d ld->ld_load_d
179 #define load_f ld->ld_load_f
180 #define load_ok ld->ld_load_ok
181 #define load_pane ld->ld_load_pane
182 #define load_vport ld->ld_load_vport
183 #define load_vportdir ld->ld_load_vportdir
184 #define load_flist ld->ld_load_flist
185 #define load_dlist ld->ld_load_dlist
186 #define cwd_l ld->ld_cwd_l
187 #define load_info ld->ld_load_info
188 #define ldwidth ld->ld_ldwidth
189 #define ldheight ld->ld_ldheight
190 #define fdirlist ld->ld_fdirlist.StringArray
191 #define filenum ld->ld_fdirlist.number
192 #define fulldirlist ld->ld_fulldirlist.StringArray
193 #define fullfilenum ld->ld_fulldirlist.number
194 #define ddirlist ld->ld_ddirlist.StringArray
195 #define dirnum ld->ld_ddirlist.number
196 #define filter ld->ld_filter
197 #define cur_filter ld->ld_cur_filter
198
199 #define LISTDIALOGBASENAME "dialog_list"
200
201 static Widget toplevel, m_box, base_f, file_mb, file_sm, bsb, quit_b, play_b,
202   pause_b, stop_b, prev_b, next_b, fwd_b, back_b, random_b, repeat_b,
203   fast_b, slow_b, keyup_b, keydown_b, b_box, v_box, t_box,
204   vol_l, vol_bar, tune_l0, tune_l, tune_bar, trace_vport, trace, file_vport,
205   file_list, title_mb, title_sm, time_l, lyric_t, chorus_b,
206   popup_file = NULL, popup_opt = NULL;
207 static Widget *psmenu = NULL;
208 #ifndef TimNmenu
209 /* We'll be using XAWs implementation of submenus (XtNmenuName).
210  * If its parameter isn't constantly available, it will fail to work.
211  */
212 static String *sb;
213 #endif /* !TimNmenu */
214 static char local_buf[PIPE_LENGTH];
215 static char window_title[300];
216 static char *home;
217 static int amplitude = DEFAULT_AMPLIFICATION;
218
219 static int maxentry_on_a_menu = 0, current_n_displayed = 0;
220 static long submenu_n = 0;
221 #define IsRealized(w) (((w) != NULL) && (XtIsRealized(w)))
222
223 static Boolean lockevents = False;
224 /*
225  * After writing a request to the pipe which changes the current song
226  * (like "N" for next song) events from the (then current) song may remain
227  * in the pipe and pass through, which may lead to them being counted
228  * as events from the next song. This variable is used for rudimentary
229  * locking to prevent such events from influencing the trace display.
230  */
231
232 typedef struct {
233   Boolean       confirmexit;
234   Boolean       repeat;
235   Boolean       autostart;
236   Boolean       autoexit;
237   Boolean       disptext;
238   Boolean       shuffle;
239   Boolean       disptrace;
240   int           amplitude;
241   int           extendopt;
242   int           chorusopt;
243   Boolean       tooltips;
244   Boolean       showdotfiles;
245   char          *DefaultDir;
246   Boolean       save_list;
247   Boolean       save_config;
248 } Config;
249
250 /* Default configuration for Xaw interface */
251 /* (confirmexit repeat autostart autoexit disptext shuffle disptrace amplitude
252     options chorus tooltips showdotfiles defaultdir savelist saveconfig) */
253 static Config Cfg = {
254   False, False, True, False, True, False, False,
255   DEFAULT_AMPLIFICATION, DEFAULT_OPTIONS, DEFAULT_CHORUS,
256 #ifndef XAW3D
257   True,
258 #else
259 /* The Xaw3d v1.5E tooltip function is surprisingly slow. */
260   False,
261 #endif /* !XAW3D */
262   False, NULL, True, True
263 };
264
265 enum {
266   S_ConfirmExit = 0,
267   S_RepeatPlay,
268   S_AutoStart,
269   S_DispText,
270   S_DispTrace,
271   S_CurVol,
272   S_ShufflePlay,
273   S_AutoExit,
274   S_ExtOptions,
275   S_ChorusOption,
276   S_Tooltips,
277   S_Showdotfiles,
278   S_DefaultDirectory,
279   S_SaveList,
280   S_SaveConfig,
281   S_MidiFile,
282   CFGITEMSNUMBER
283 };
284
285 static const char *cfg_items[CFGITEMSNUMBER] = {
286   "ConfirmExit", "RepeatPlay", "AutoStart", "Disp:text", "Disp:trace",
287   "CurVol", "ShufflePlay", "AutoExit", "ExtOptions", "ChorusOption",
288   "Tooltips", "Showdotfiles", "DefaultDir", "SaveList", "SaveConfigOnExit",
289   "File"
290 };
291
292 #define COMMON_BGCOLOR          "gray67"
293 #define COMMANDBUTTON_COLOR     "gray78"
294 #define TEXTBG_COLOR            "gray82"
295
296 typedef struct {
297   char id_char;
298   char *id_name;
299 } id_list;
300
301 typedef struct {
302   id_list *output_list;
303   unsigned short max;
304   unsigned short current;
305   unsigned short def;
306   char *lbuf;
307   Widget formatGroup;
308   Widget *toggleGroup;
309 } outputs;
310
311 static Display *disp;
312 static Atom wm_delete_window, net_wm_pid;
313 static pid_t pid;
314 static XtAppContext app_con;
315 static Pixmap check_mark, arrow_mark, on_mark, off_mark;
316
317 #define GET_BITMAP(Pix) XCreateBitmapFromData(disp, \
318                         RootWindowOfScreen(XtScreen(toplevel)), \
319                         (char *)Pix##_bits, Pix##_width, Pix##_height)
320
321 #ifdef XDND
322 static DndClass _DND;
323 static DndClass *dnd = &_DND;
324 #endif /* XDND */
325
326 static int root_height, root_width;
327 static Dimension curr_width, curr_height, base_height, lyric_height,
328        trace_v_height;
329 static int max_files = 0,
330            init_options = DEFAULT_OPTIONS, init_chorus = DEFAULT_CHORUS;
331 static outputs *record, *play;
332 static Boolean recording = False, use_own_start_scroll = False;
333 static String *flist = NULL;
334 static int max_num = INIT_FLISTNUM;
335 static int total_time = 0, curr_time = 0, halt = 0;
336
337 typedef enum {
338   NORESPONSE = -1,
339   OK,
340   CANCEL
341 } resvalues;
342 typedef struct {
343   resvalues val;
344   Widget widget;
345 } resvar;
346 static resvar response = {NORESPONSE, NULL};
347
348 static struct _app_resources {
349   tconfig tracecfg;
350   Boolean arrange_title;
351   Dimension text_height, menu_width;
352   Pixel common_bgcolor, menub_bgcolor, text2_bgcolor, toggle_fgcolor,
353         button_fgcolor, button_bgcolor;
354   String more_text, file_text, no_playing;
355   XFontSet label_font, volume_font, text_font;
356   String labelfile, popup_confirm, load_LISTDIALOGBASENAME_title,
357          save_LISTDIALOGBASENAME_title;
358 } app_resources;
359
360 #define capcolor        app_resources.tracecfg.caption_color
361 #define bgcolor         app_resources.common_bgcolor
362 #define buttonbgcolor   app_resources.button_bgcolor
363 #define buttoncolor     app_resources.button_fgcolor
364 #define menubcolor      app_resources.menub_bgcolor
365 #define textcolor       app_resources.tracecfg.common_fgcolor
366 #define textbgcolor     app_resources.tracecfg.text_bgcolor
367 #define text2bgcolor    app_resources.text2_bgcolor
368 #define togglecolor     app_resources.toggle_fgcolor
369
370 /* These numbers are hardcoded in the resource files */
371 #define ID_LOAD                 100
372 #define ID_SAVE                 101
373 #define ID_LOAD_PLAYLIST        102
374 #define ID_SAVE_PLAYLIST        103
375 #define ID_SAVECONFIG           104
376 #define ID_HIDETXT              105
377 #define ID_HIDETRACE            106
378 #define ID_SHUFFLE              107
379 #define ID_REPEAT               108
380 #define ID_AUTOSTART            109
381 #define ID_AUTOQUIT             110
382 #define ID_LINE                 111
383 #define ID_FILELIST             112
384 #define ID_OPTIONS              113
385 #define ID_LINE2                114
386 #define ID_ABOUT                115
387 #define ID_QUIT                 116
388
389 #define R(x) #x
390 #define S(x) R(x)
391
392 typedef struct {
393   const int     id;
394   const String  name;
395   WidgetClass   *wclass;
396   Widget        widget;
397 } ButtonRec;
398
399 static ButtonRec file_menu[] = {
400   {ID_LOAD, "load", &smeBSBObjectClass},
401   {ID_SAVE, "save", &smeBSBObjectClass},
402   {ID_LOAD_PLAYLIST, "load_playlist", &smeBSBObjectClass},
403   {ID_SAVE_PLAYLIST, "save_playlist", &smeBSBObjectClass},
404   {ID_SAVECONFIG, "saveconfig", &smeBSBObjectClass},
405   {ID_HIDETXT, "hidetext", &smeBSBObjectClass},
406   {ID_HIDETRACE, "hidetrace", &smeBSBObjectClass},
407   {ID_SHUFFLE, "shuffle", &smeBSBObjectClass},
408   {ID_REPEAT, "repeat", &smeBSBObjectClass},
409   {ID_AUTOSTART, "autostart", &smeBSBObjectClass},
410   {ID_AUTOQUIT, "autoquit", &smeBSBObjectClass},
411   {ID_LINE, "line", &smeLineObjectClass},
412   {ID_FILELIST, "filelist", &smeBSBObjectClass},
413   {ID_OPTIONS, "modes", &smeBSBObjectClass},
414   {ID_LINE2, "line2", &smeLineObjectClass},
415   {ID_ABOUT, "about", &smeBSBObjectClass},
416   {ID_QUIT, "quit", &smeBSBObjectClass},
417 };
418
419 typedef struct {
420   const int     bit;
421   Widget        widget;
422 } OptionRec;
423
424 static OptionRec option_num[] = {
425   {MODUL_BIT, NULL},
426   {PORTA_BIT, NULL},
427   {NRPNV_BIT, NULL},
428   {REVERB_BIT, NULL},
429   {CHPRESSURE_BIT, NULL},
430   {OVERLAPV_BIT, NULL},
431   {TXTMETA_BIT, NULL},
432 };
433
434 typedef union {
435   float f;
436   XtArgVal x;
437 } barfloat;
438
439 static char *dotfile = NULL;
440 #define SPREFIX "set "
441 #define SPLEN 4
442 #define SLINELEN PATH_MAX+SPLEN+20
443
444 static void a_init_interface(int);
445 void a_start_interface(int);
446 extern void a_pipe_write(const char *, ...);
447 extern int a_pipe_read(char *, size_t);
448 extern int a_pipe_nread(char *, size_t);
449 extern void a_pipe_sync(void);
450 static void a_print_text(Widget, const char *);
451 static void a_print_msg(Widget);
452 static void handle_input(XtPointer, int *, XtInputId *);
453
454 static int a_readconfig(Config *, char ***);
455 static void a_saveconfig(const char *, Boolean);
456 static void aboutACT(Widget, XEvent *, String *, Cardinal *);
457 static void addOneFile(int, long, const char *);
458 static void addFlist(const char *, long);
459 static void backspaceACT(Widget, XEvent *, String *, Cardinal *);
460 static void backCB(Widget, XtPointer, XtPointer);
461 static void callFilterDirList(Widget, XtPointer, XtPointer);
462 static void callRedrawTrace(Boolean);
463 static void callInitTrace(void);
464 static void cancelACT(Widget, XEvent *, String *, Cardinal *);
465 static void cancelCB(Widget, XtPointer, XtPointer);
466 static char *canonicalize_path(char *);
467 #ifdef TimNmenu
468 static void checkRightAndPopupSubmenuACT(Widget, XEvent *, String *,Cardinal *);
469 static void popdownSubmenuCB(Widget, XtPointer, XtPointer);
470 static void popdownSubmenuACT(Widget, XEvent *, String *, Cardinal *);
471 #endif /* TimNmenu */
472 #ifdef CLEARVALUE
473 static void clearValue(Widget);
474 #endif /* CLEARVALUE */
475 static void closeParentACT(Widget, XEvent *, String *, Cardinal *);
476 static void closeWidgetCB(Widget, XtPointer, XtPointer);
477 static int configcmp(const char *, int *);
478 static int confirmCB(Widget, const char *, Boolean);
479 static void completeDirACT(Widget , XEvent *, String *, Cardinal *);
480 static void createBars(void);
481 static void createButtons(void);
482 static void createDialog(Widget, ldPointer);
483 static void createFlist(void);
484 static void createOptions(void);
485 static void createTraceWidgets(void);
486 static Widget
487   createOutputSelectionWidgets(Widget, Widget, Widget, outputs *, Boolean);
488 #ifndef WIDGET_IS_LABEL_WIDGET
489 static void deleteTextACT(Widget, XEvent *, String *, Cardinal *);
490 #endif /* !WIDGET_IS_LABEL_WIDGET */
491 static void destroyWidgetCB(Widget, XtPointer, XtPointer);
492 static void downACT(Widget, XEvent *, String *, Cardinal *);
493 static void exchgWidthACT(Widget, XEvent *, String *, Cardinal *);
494 static char *expandDir(char *, DirPath *, const char *);
495 static void fdelallCB(Widget, XtPointer, XtPointer);
496 static void fdeleteCB(Widget, XtPointer, XtPointer);
497 #ifdef OFFIX
498 static void FileDropedHandler(Widget, XtPointer, XEvent *, Boolean *);
499 #endif /* OFFIX */
500 static void filemenuACT(Widget, XEvent *, String *, Cardinal *);
501 static void filemenuCB(Widget, XtPointer, XtPointer);
502 static void filterDirList(ldPointer, Boolean);
503 static void flistMoveACT(Widget, XEvent *, String *, Cardinal *);
504 static void flistpopupACT(Widget, XEvent *, String *, Cardinal *);
505 static void forwardCB(Widget, XtPointer, XtPointer);
506 static void fselectCB(Widget, XtPointer, XtPointer);
507 #if 0
508 static void free_ldS(ldStorePointer ldS);
509 #endif
510 static void freevarCB(Widget, XtPointer, XtPointer);
511 static char *get_user_home_dir(void);
512 static int getClickedChan(XEvent *);
513 static ldStorePointer getldsPointer(ldStorePointer lds, const char *Popname);
514 static ldStorePointer init_ldS(void);
515 static void init_output_lists(void);
516 static Boolean IsTracePlaying(void);
517 static Boolean IsEffectiveFile(char *);
518 static void leaveSubmenuACT(Widget, XEvent *, String *, Cardinal *);
519 static void menuCB(Widget, XtPointer, XtPointer);
520 static void muteChanACT(Widget, XEvent *, String *, Cardinal *);
521 static void nextCB(Widget, XtPointer, XtPointer);
522 static void offPauseButton(void);
523 static void offPlayButton(void);
524 static Boolean onPlayOffPause(void);
525 static void okCB(Widget, XtPointer, XtPointer);
526 static void okACT(Widget, XEvent *, String *, Cardinal *);
527 static void optionsCB(Widget, XtPointer, XtPointer);
528 static void optionscloseCB(Widget, XtPointer, XtPointer);
529 static void optionspopupACT(Widget, XEvent *, String *, Cardinal *);
530 static void pauseCB(Widget, XtPointer, XtPointer);
531 static void pitchCB(Widget, XtPointer, XtPointer);
532 static void playCB(Widget, XtPointer, XtPointer);
533 static void popdownAddALL(Widget, XtPointer, XtPointer);
534 static void popdownAddALLACT(Widget, XEvent *, String *, Cardinal *);
535 static void popdownCB(Widget, XtPointer, XtPointer);
536 static void popdownLoadfile(Widget, XtPointer, XtPointer);
537 static void popdownLoadPL(Widget, XtPointer, XtPointer);
538 static void popdownSavefile(Widget, XtPointer, XtPointer);
539 static void popdownSavePL(Widget, XtPointer, XtPointer);
540 static void popdownfilemenuACT(Widget, XEvent *, String *, Cardinal *);
541 static void popupfilemenuACT(Widget, XEvent *, String *, Cardinal *);
542 static void popupDialog(Widget, char *, String *, XtCallbackProc,
543                         ldStorePointer);
544 static void prevCB(Widget, XtPointer, XtPointer);
545 static void quitCB(Widget, XtPointer, XtPointer);
546 static void randomCB(Widget, XtPointer, XtPointer);
547 static int readPlaylist(const char *);
548 static void recordCB(Widget, XtPointer, XtPointer);
549 static void recordACT(Widget, XEvent *, String *, Cardinal *);
550 static void redrawACT(Widget, XEvent *, String *, Cardinal *);
551 static void redrawCaptionACT(Widget, XEvent *, String *, Cardinal *);
552 static void repeatCB(Widget, XtPointer, XtPointer);
553 static void resizeToplevelACT(Widget, XEvent *, String *, Cardinal *);
554 static void restoreDefaultOSelectionCB(Widget, XtPointer, XtPointer);
555 static void restoreLDPointer(Widget, XtPointer, XEvent *, Boolean *);
556 static void savePlaylist(const char *, int);
557 static void saveformatDialog(Widget);
558 static void setupWindow(Widget, String, Boolean, Boolean);
559 static int setDirList(ldPointer, char *);
560 static void setSizeHints(Dimension);
561 static void scrollTextACT(Widget, XEvent *, String *, Cardinal *);
562 static void scrollTraceACT(Widget, XEvent *, String *, Cardinal *);
563 static void scrollListACT(Widget, XEvent *, String *, Cardinal *);
564 static void setDirACT(Widget, XEvent *, String *, Cardinal *);
565 static void setDirLoadCB(Widget, XtPointer, XawListReturnStruct *);
566 static void setFileLoadCB(Widget, XtPointer, XawListReturnStruct *);
567 static void setThumb(Widget, barfloat);
568 static Widget seekTransientShell(Widget);
569 static void sndspecACT(Widget, XEvent *, String *, Cardinal *);
570 static void soloChanACT(Widget, XEvent *, String *, Cardinal *);
571 static void soundkeyACT(Widget, XEvent *, String *, Cardinal *);
572 static void speedACT(Widget, XEvent *, String *, Cardinal *);
573 static void simulateArrowsCB(Widget, XtPointer, XtPointer);
574 static void StartScrollACT(Widget, XEvent *, String *, Cardinal *);
575 static void stopCB(Widget, XtPointer, XtPointer);
576 static char *strmatch(char *, const char *);
577 static void tempoCB(Widget, XtPointer, XtPointer);
578 #ifdef HAVE_TIP
579 static void TipEnable(Widget, String);
580 static void TipDisable(Widget);
581 static void xawTipSet(Boolean);
582 #endif /* HAVE_TIP */
583 static void tnotifyCB(Widget, XtPointer, XtPointer);
584 static void toggleMark(Widget, Boolean);
585 static void toggleTraceACT(Widget, XEvent *, String *, Cardinal *);
586 static void tunesetACT(Widget, XEvent *, String *, Cardinal *);
587 static void tuneslideCB(Widget, XtPointer, XtPointer);
588 static void upACT(Widget, XEvent *, String *, Cardinal *);
589 static void voiceACT(Widget, XEvent *, String *, Cardinal *);
590 static void volsetCB(Widget, XtPointer, XtPointer);
591 static void volupdownACT(Widget, XEvent *, String *, Cardinal *);
592 static Widget warnCB(Widget, const char *, Boolean);
593 static void xaw_vendor_setup(void);
594 static void xawtipsetACT(Widget, XEvent *, String *, Cardinal *);
595 #ifdef XDND
596 static void a_dnd_init(void);
597 static void enable_dnd_for_widget(DndClass *, Widget, dnd_callback_t);
598 static void xdnd_file_drop_handler(const char *);
599 static void xdnd_listener(Widget, XtPointer, XEvent *, Boolean *);
600 #endif /* XDND */
601
602 static void
603 offPauseButton(void) {
604   Boolean s;
605
606   XtVaGetValues(pause_b, XtNstate,&s, NULL);
607   if (s == True) a_pipe_write("%c", S_TOGGLE_PAUSE);
608 }
609
610 static void
611 offPlayButton(void) {
612   Boolean s;
613
614   XtVaGetValues(play_b, XtNstate,&s, NULL);
615   if (s == True) {
616     XtVaSetValues(play_b, XtNstate,False, NULL);
617     a_pipe_write("%c0", S_SET_TIME);
618   }
619 }
620
621 static Boolean
622 IsTracePlaying(void) {
623   Boolean s;
624
625   if ((!ctl->trace_playing) || (lockevents == True)) return False;
626   XtVaGetValues(play_b, XtNstate,&s, NULL);
627   return s;
628 }
629
630 static Boolean
631 IsEffectiveFile(char *file) {
632   char *p2;
633   struct stat st;
634
635   if ((p2 = strrchr(file, '#')) != NULL) *p2 = '\0';
636   if (stat(file, &st) != -1)
637     if (st.st_mode & S_IFMT & (S_IFDIR|S_IFREG|S_IFLNK)) {
638       if (p2 != NULL) *p2 = '#';
639       return True;
640     }
641   return False;
642 }
643
644 static Boolean
645 onPlayOffPause(void) {
646   Boolean s, play_on = False;
647
648   XtVaGetValues(play_b, XtNstate,&s, NULL);
649   if (s == False) {
650     XtVaSetValues(play_b, XtNstate,True, NULL);
651     play_on = True;
652   }
653   offPauseButton();
654   return play_on;
655 }
656
657 static void
658 optionsCB(Widget w, XtPointer id_data, XtPointer data) {
659   Boolean s;
660
661   XtVaGetValues(w, XtNstate,&s, NULL);
662   XtVaSetValues(w, XtNbitmap,s?on_mark:off_mark, NULL);
663 }
664
665 static void
666 optionspopupACT(Widget w, XEvent *e, String *v, Cardinal *n) {
667   if (popup_opt == NULL) createOptions();
668   setupWindow(popup_opt, "do-optionsclose()", False, False);
669 }
670
671 static void
672 flistpopupACT(Widget w, XEvent *e, String *v, Cardinal *n) {
673   Dimension x, y;
674
675   createFlist();
676   XtVaGetValues(toplevel, XtNx,&x, XtNy,&y, NULL);
677   XtVaSetValues(popup_file, XtNx,x+DEFAULT_REG_WIDTH, XtNy,y, NULL);
678   setupWindow(popup_file, "do-closeparent()", True, False);
679 }
680
681 static void
682 aboutACT(Widget w, XEvent *e, String *v, Cardinal *n) {
683   char s[12], *p;
684   char lbuf[30];
685   int i;
686   Widget popup_about, popup_abox, popup_aok;
687
688   char *info[] = {"TiMidity++ %s%s - Xaw interface",
689                   "- MIDI to WAVE converter and player -",
690                   "by Masanao Izumo and Tomokazu Harada",
691                   "modified by Yoshishige Arai",
692                   "modified by Yair Kalvariski", " ", NULL};
693
694   if ((popup_about = XtNameToWidget(toplevel, "popup_about")) != NULL) {
695     XtPopup(popup_about, XtGrabNone);
696     XSync(disp, False);
697     XSetInputFocus(disp, XtWindow(popup_about), RevertToParent, CurrentTime);
698     return;
699   }
700   popup_about = XtVaCreatePopupShell("popup_about",transientShellWidgetClass,
701                                 toplevel,NULL);
702   popup_abox = XtVaCreateManagedWidget("popup_abox",boxWidgetClass,
703                                 popup_about, XtNwidth,320, XtNheight,120,
704                                 XtNorientation,XtorientVertical,
705                                 XtNbackground,bgcolor, NULL);
706   for(i=0, p=info[0]; p; p=info[++i]) {
707     snprintf(s, sizeof(s), "about_lbl%d", i);
708     snprintf(lbuf, sizeof(lbuf), p,
709                 (strcmp(timidity_version, "current")) ? "version " : "",
710                 timidity_version);
711     XtVaCreateManagedWidget(s,labelWidgetClass,popup_abox,
712                                 XtNlabel,lbuf, XtNwidth,320, XtNresize,False,
713                                 XtNfontSet,app_resources.label_font,
714                                 XtNforeground,textcolor, XtNborderWidth,0,
715                                 XtNbackground,bgcolor, NULL);
716   }
717   popup_aok = XtVaCreateManagedWidget("OK",commandWidgetClass,popup_abox,
718                                 XtNwidth,320, XtNresize,False, NULL);
719   XtAddCallback(popup_aok, XtNcallback,closeWidgetCB, (XtPointer)popup_about);
720   XtVaSetValues(popup_about, XtNx,root_width/2 - 160,
721                   XtNy,root_height/2 - 60, NULL);
722   setupWindow(popup_about, "do-closeparent()", False, True);
723   XtSetKeyboardFocus(popup_about, popup_abox);
724 }
725
726 static void
727 optionscloseCB(Widget w, XtPointer client_data, XtPointer call_data) {
728   Boolean s1;
729   id_list *result = NULL;
730   int flags = 0, cflag = 0, i;
731
732   if (play != NULL) result = (id_list *)XawToggleGetCurrent(play->formatGroup);
733   for(i=0; i<MAX_OPTION_N; i++) {
734     XtVaGetValues(option_num[i].widget, XtNstate,&s1, NULL);
735     flags |= s1?option_num[i].bit:0;
736   }
737   XtVaGetValues(chorus_b, XtNstate,&s1, NULL);
738   if (s1 == True) cflag = Cfg.chorusopt?Cfg.chorusopt:DEFAULT_CHORUS;
739   if ((init_options != flags) || (init_chorus != cflag) ||
740       (recording == True)) {
741     stopCB(NULL, NULL, NULL);
742   }
743   if (init_options != flags) {
744     init_options = flags;
745     a_pipe_write("%c%03d", S_SET_OPTIONS, init_options);
746   }
747   if (init_chorus != cflag) {
748     init_chorus = cflag;
749     if (s1 == False) a_pipe_write("%c0", S_SET_CHORUS);
750     else a_pipe_write("%c%03d", S_SET_CHORUS, init_chorus);
751   }
752
753   if (result != NULL) {
754     a_pipe_write("%c%c", S_SET_PLAYMODE, result->id_char);
755     while (strncmp(local_buf, CHECKPOST "3", 2)) {
756       XtAppProcessEvent(app_con, XtIMAll);
757     }
758     if (*(local_buf + 2) == 'E') goto popdownopt;
759     play->def = play->current;
760   }
761 popdownopt:
762   XtPopdown(popup_opt);
763 }
764
765 static Widget
766 warnCB(Widget w, const char *mesname, Boolean destroy) {
767   Widget popup_warning, popup_wbox, popup_wok;
768
769   if (mesname == NULL) return None;
770   popup_warning = XtVaCreatePopupShell("popup_warning",
771             transientShellWidgetClass,toplevel, NULL);
772   popup_wbox = XtVaCreateManagedWidget("popup_wbox", boxWidgetClass,
773                                   popup_warning, XtNbackground,bgcolor,
774                                   XtNorientation,XtorientVertical, NULL);
775   XtVaCreateManagedWidget(mesname, labelWidgetClass,
776                                           popup_wbox,
777                                           XtNfontSet,app_resources.label_font,
778                                           XtNforeground,textcolor,
779                                           XtNbackground,bgcolor,
780                                           XtNresize,False,
781                                           XtNborderWidth,0, NULL);
782   popup_wok = XtVaCreateManagedWidget("OK",commandWidgetClass,
783                     popup_wbox, XtNbackground,buttonbgcolor,
784                     XtNresize,False, NULL);
785   XtAddCallback(popup_wok, XtNcallback,closeWidgetCB, (XtPointer)popup_warning);
786   XtSetKeyboardFocus(popup_warning, popup_wbox);
787   setupWindow(popup_warning, "do-closeparent()", False, destroy);
788   return popup_warning;
789 }
790
791 static void
792 closeWidgetCB(Widget w, XtPointer client_data, XtPointer call_data) {
793   XtPopdown((Widget)client_data);
794 }
795
796 static int
797 confirmCB(Widget w, const char *mesname, Boolean multiple) {
798   Widget popup_confirm, popup_cform, popup_message, popup_ccancel, popup_cok;
799   char s[21];
800   Dimension mw, ow, cw;
801
802   if (mesname == NULL) return NORESPONSE;
803   snprintf(s, sizeof(s), "confirm_%s", mesname);
804   if ((multiple == False) && ((popup_confirm = XtNameToWidget(w, s)) != NULL)) {
805     XtPopup(popup_confirm, XtGrabNone);
806     XSync(disp, False);
807     XSetInputFocus(disp, XtWindow(popup_confirm), RevertToParent, CurrentTime);
808     return CANCEL;
809   }
810   popup_confirm = XtVaCreatePopupShell(s,transientShellWidgetClass,w,
811                                        XtNtitle,app_resources.popup_confirm,
812                                        NULL);
813   popup_cform = XtVaCreateManagedWidget("popup_cform",formWidgetClass,
814                                   popup_confirm, XtNbackground,bgcolor,
815                                   XtNorientation,XtorientVertical, NULL);
816   popup_message = XtVaCreateManagedWidget(mesname,labelWidgetClass,
817                                           popup_cform, XtNresize,False,
818                                           XtNfontSet,app_resources.label_font,
819                                           XtNforeground,textcolor,
820                                           XtNbackground,bgcolor,
821                                           XtNborderWidth,0, NULL);
822   popup_cok = XtVaCreateManagedWidget("OK",commandWidgetClass,
823                     popup_cform, XtNbackground,buttonbgcolor,
824                     XtNresize,False, XtNfromVert,popup_message, NULL);
825   popup_ccancel = XtVaCreateManagedWidget("Cancel",commandWidgetClass,
826                     popup_cform, XtNbackground,buttonbgcolor,
827                     XtNresize,False, XtNfromVert,popup_message, 
828                     XtNfromHoriz,popup_cok, NULL);
829   XtVaGetValues(popup_message, XtNwidth,&mw, NULL);
830   XtVaGetValues(popup_cok, XtNwidth,&ow, NULL);
831   XtVaGetValues(popup_ccancel, XtNwidth,&cw, NULL);
832   if (mw > ow+cw) XtVaSetValues(popup_cok, XtNhorizDistance,(mw-ow-cw)/2, NULL);
833
834   XtAddCallback(popup_cok, XtNcallback,okCB, (XtPointer)popup_confirm);
835   XtAddCallback(popup_ccancel, XtNcallback,cancelCB, (XtPointer)popup_confirm);
836   XtSetKeyboardFocus(popup_confirm, popup_cform);
837   setupWindow(popup_confirm, "do-cancel()", False, True);
838   response.val = NORESPONSE;
839   while ((response.val == NORESPONSE) || (response.widget != popup_confirm)) {
840     XtAppProcessEvent(app_con, XtIMAll);
841   }
842   XtPopdown(popup_confirm);
843   return response.val;
844 }
845
846 static void
847 okCB(Widget w, XtPointer client_data, XtPointer call_data) {
848   response.widget = (Widget)client_data;
849   response.val = OK;
850 }
851
852 static void
853 okACT(Widget w, XEvent *e, String *v, Cardinal *n) {
854   response.widget = seekTransientShell(w);
855   response.val = OK;
856 }
857
858 static void
859 cancelCB(Widget w, XtPointer client_data, XtPointer call_data) {
860   response.widget = (Widget)client_data;
861   response.val = CANCEL;
862 }
863
864 static void
865 cancelACT(Widget w, XEvent *e, String *v, Cardinal *n) {
866   response.widget = seekTransientShell(w);
867   response.val = CANCEL;
868 }
869
870 static void
871 quitCB(Widget w, XtPointer client_data, XtPointer call_data) {
872   if (Cfg.confirmexit == True) {
873 #ifdef XAW3D
874       XtPopdown(file_sm); 
875      /* Otherwise, when selecting "Quit" from the file menu, the menu
876       * may obscure the confirm dialog on XAW3D v1.5.
877       */
878 #endif
879      if (confirmCB(toplevel, "confirmexit", False) != OK) return;
880   }
881   if (Cfg.save_config) a_saveconfig(dotfile, Cfg.save_list);
882   a_pipe_write("%c", S_QUIT);
883 }
884
885 static void
886 sndspecACT(Widget w, XEvent *e, String *v, Cardinal *n) {
887 #ifdef SUPPORT_SOUNDSPEC
888   a_pipe_write("%c", S_TOGGLE_SPEC);
889 #endif
890 }
891
892 static void
893 playCB(Widget w, XtPointer client_data, XtPointer call_data) {
894   float thumb;
895   Boolean s;
896
897   if (max_files == 0) return;
898   onPlayOffPause();
899   XtVaGetValues(tune_bar, XtNtopOfThumb,&thumb, NULL);
900   XtVaGetValues(pause_b, XtNstate,&s, NULL);
901   if ((s == False) && (thumb != 0)) {
902     /* This is very ugly. Doing it cleanly would require a change in
903      * playmidi.c to send a CTLE when playback loop starts  */
904     int next_time = total_time * thumb;
905
906     a_pipe_write("%c", S_PLAY);
907     while (*local_buf != M_CUR_TIME) {
908       XtAppProcessEvent(app_con, XtIMAll);
909       /* If RC_LOAD_FILE fails, M_LOADING_DONE will return the failure */
910       if ((*local_buf == M_LOADING_DONE) && (local_buf[1] != '0')) return;
911     }
912     a_pipe_write("%c%d", S_SET_TIME, next_time);
913   }
914   else a_pipe_write("%c", S_PLAY);
915 }
916
917 static void
918 soundkeyACT(Widget w, XEvent *e, String *v, Cardinal *n) {
919   if (*(int *)n == 0) {
920     if (IsTracePlaying())
921       XtCallActionProc(keyup_b, (String)"set", NULL, NULL, ZERO);
922     a_pipe_write("%c", S_INC_PITCH);
923   } else {
924     if (IsTracePlaying())
925       XtCallActionProc(keydown_b, (String)"set", NULL, NULL, ZERO);
926     a_pipe_write("%c", S_DEC_PITCH);
927   }
928 }
929
930 static void
931 speedACT(Widget w, XEvent *e, String *v, Cardinal *n) {
932   if (*(int *)n == 0) {
933     if (IsTracePlaying())
934       XtCallActionProc(fast_b, (String)"set", NULL, NULL, ZERO);
935     a_pipe_write("%c", S_INC_SPEED);
936   } else {
937     if (IsTracePlaying())
938       XtCallActionProc(slow_b, (String)"set", NULL, NULL, ZERO);
939     a_pipe_write("%c", S_DEC_SPEED);
940   }
941 }
942
943 static void
944 voiceACT(Widget w, XEvent *e, String *v, Cardinal *n) {
945   a_pipe_write("%c", *(int *)n == 0 ? S_DEC_VOL:S_INC_VOL);
946 }
947
948 static void
949 pauseCB(Widget w, XtPointer client_data, XtPointer call_data) {
950   Boolean s;
951
952   XtVaGetValues(play_b, XtNstate,&s, NULL);
953   if (s == True) {
954     halt = 1;
955     a_pipe_write("%c", S_TOGGLE_PAUSE);
956   }
957 }
958
959 static void
960 stopCB(Widget w, XtPointer client_data, XtPointer call_data) {
961   offPlayButton();
962   offPauseButton();
963   a_pipe_write("%c", S_STOP);
964   lockevents = True;
965   if (recording == True) a_pipe_write("%c%c", S_STOP_RECORDING, SR_USER_STOP);
966   if (ctl->trace_playing) initStatus();
967   XtVaSetValues(tune_l0, XtNlabel,"0:00", NULL);
968   XawScrollbarSetThumb(tune_bar, 0.0, -1.0);
969   snprintf(window_title, sizeof(window_title), "%s : %s",
970            APP_CLASS, app_resources.no_playing);
971   XtVaSetValues(toplevel, XtNtitle,window_title, NULL);
972   callRedrawTrace(False);
973 }
974
975 static void
976 nextCB(Widget w, XtPointer client_data, XtPointer call_data) {
977   onPlayOffPause();
978   a_pipe_write("%c", S_NEXT);
979   lockevents = True;
980   /* M_LOADING_DONE signal will do initStatus() for nextCB/prevCB/menuCB */
981 }
982
983 static void
984 prevCB(Widget w, XtPointer client_data, XtPointer call_data) {
985   onPlayOffPause();
986   a_pipe_write("%c", S_PREV);
987   lockevents = True;
988 }
989
990 static void
991 forwardCB(Widget w, XtPointer client_data, XtPointer call_data) {
992   if (onPlayOffPause()) a_pipe_write("%c", S_PLAY);
993   a_pipe_write("%c", S_FWD);
994   if (ctl->trace_playing) initStatus();
995 }
996
997 static void
998 backCB(Widget w, XtPointer client_data, XtPointer call_data) {
999   if (onPlayOffPause()) a_pipe_write("%c", S_PLAY);
1000   a_pipe_write("%c", S_BACK);
1001   if (ctl->trace_playing) initStatus();
1002 }
1003
1004 static void
1005 repeatCB(Widget w, XtPointer client_data, XtPointer call_data) {
1006   Boolean s;
1007   Boolean *set = (Boolean *)client_data;
1008
1009   if (set != NULL) {
1010     s = *set;
1011     XtVaSetValues(repeat_b, XtNstate,s, NULL);
1012     toggleMark(file_menu[ID_REPEAT-100].widget, s);
1013   } else {
1014     XtVaGetValues(repeat_b, XtNstate,&s, NULL);
1015     toggleMark(file_menu[ID_REPEAT-100].widget, s);
1016     Cfg.repeat = s;
1017   }
1018   if (s == True) a_pipe_write("%c1", S_SET_REPEAT);
1019   else a_pipe_write("%c0", S_SET_REPEAT);
1020 }
1021
1022 static void
1023 randomCB(Widget w, XtPointer client_data, XtPointer call_data) {
1024   Boolean s;
1025   Boolean *set = (Boolean *)client_data;
1026
1027   onPlayOffPause();
1028   if (set != NULL) {
1029     s = *set;
1030     XtVaSetValues(random_b, XtNstate,s, NULL);
1031     toggleMark(file_menu[ID_SHUFFLE-100].widget, s);
1032   } else {
1033     XtVaGetValues(random_b, XtNstate,&s, NULL);
1034     toggleMark(file_menu[ID_SHUFFLE-100].widget, s);
1035     Cfg.shuffle = s;
1036   }
1037   if (s == True) {
1038     onPlayOffPause();
1039     a_pipe_write("%c1", S_SET_RANDOM);
1040   } else {
1041     offPlayButton();
1042     offPauseButton();
1043     a_pipe_write("%c2", S_SET_RANDOM);
1044   }
1045 }
1046
1047 static void
1048 tempoCB(Widget w, XtPointer client_data, XtPointer call_data) {
1049   a_pipe_write("%c", (client_data == (XtPointer)TRUE) ? S_INC_SPEED:S_DEC_SPEED);
1050 }
1051
1052 static void
1053 pitchCB(Widget w, XtPointer client_data, XtPointer call_data) {
1054   a_pipe_write("%c", (client_data == (XtPointer)TRUE) ? S_INC_PITCH:S_DEC_PITCH);
1055 }
1056
1057 static void
1058 menuCB(Widget w, XtPointer client_data, XtPointer call_data) {
1059   onPlayOffPause();
1060   lockevents = True;
1061   a_pipe_write("%c%ld", S_PLAY_FILE, ((long)client_data)+1);
1062 }
1063
1064 static void
1065 setVolbar(int val) {
1066   char s[8];
1067   barfloat thumb;
1068
1069   amplitude = (val > MAXVOLUME)? MAXVOLUME : val;
1070   a_pipe_write("%c%03d", S_SET_VOL, amplitude);
1071   snprintf(s, sizeof(s), "%d", amplitude);
1072   XtVaSetValues(vol_l, XtNlabel,s, NULL);
1073   thumb.f = (float)amplitude / (float)MAXVOLUME;
1074   setThumb(vol_bar, thumb);
1075 }
1076
1077 static void
1078 volsetCB(Widget w, XtPointer client_data, XtPointer percent_ptr) {
1079   float percent = *(float *)percent_ptr;
1080   int val = MAXVOLUME * percent;
1081
1082   if (amplitude == val) return;
1083   setVolbar(val);
1084 }
1085
1086 static void
1087 volupdownACT(Widget w, XEvent *e, String *v, Cardinal *n) {
1088   int i = atoi(*v);
1089
1090   i += amplitude;
1091   setVolbar(i);
1092 }
1093
1094 static void
1095 tunesetACT(Widget w, XEvent *e, String *v, Cardinal *n) {
1096   int click_y;
1097   Dimension h;
1098   barfloat thumb;
1099
1100   if (!halt) return;
1101   halt = 0;
1102   XtVaGetValues(tune_bar, XtNtopOfThumb,&thumb.f, XtNheight,&h, NULL);
1103   click_y = e->xbutton.y;
1104   if ((click_y > h) || (click_y < 0)) {
1105     char s[10];
1106
1107     snprintf(s, sizeof(s), "%d:%02d", curr_time / 60, curr_time % 60);
1108     XtVaSetValues(tune_l0, XtNlabel,s, NULL);
1109     thumb.f = (float)curr_time / (float)total_time;
1110     setThumb(tune_bar, thumb);
1111     return;
1112   }
1113   a_pipe_write("%c%d", S_SET_TIME, (int)(total_time * thumb.f));
1114   /*  local_buf[0] = '\0';
1115   a_print_text(lyric_t, local_buf);*/
1116 }
1117
1118 static void
1119 tuneslideCB(Widget w, XtPointer client_data, XtPointer percent_ptr) {
1120   char s[16];
1121   int value;
1122   float l_thumb = *(float *)percent_ptr;
1123
1124   halt = 1;
1125   value = l_thumb * total_time;
1126   snprintf(s, sizeof(s), "%d:%02d", value / 60, value % 60);
1127   XtVaSetValues(tune_l0, XtNlabel,s, NULL);
1128 }
1129
1130 static void
1131 setSizeHints(Dimension height) {
1132   XSizeHints *xsh;
1133
1134   xsh = XAllocSizeHints();
1135   if (xsh == NULL) return;
1136
1137   xsh->flags = PMaxSize; /* | PMinSize*/
1138   if (Cfg.disptrace == False) {
1139     xsh->max_width = root_width;
1140     xsh->min_height = base_height;
1141   } else {
1142     xsh->max_width = TRACE_WIDTH+8;
1143     xsh->min_height = base_height + trace_v_height;
1144   }
1145   xsh->min_width = DEFAULT_REG_WIDTH;
1146   if (XtIsManaged(lyric_t)) xsh->max_height = root_height;
1147   else xsh->max_height = height;
1148
1149   XSetWMNormalHints(disp, XtWindow(toplevel), xsh);
1150   XFree(xsh);
1151   return;
1152 }
1153
1154 static void
1155 resizeToplevelACT(Widget w, XEvent *e, String *v, Cardinal *n) {
1156   XConfigureEvent *xce = (XConfigureEvent *)e;
1157
1158   if (xce != NULL) {
1159     if ((xce->width == curr_width) && (xce->height == curr_height))
1160       return;
1161     curr_width = xce->width;
1162     curr_height = xce->height;
1163   }
1164
1165   XawFormDoLayout(base_f, False);
1166   setSizeHints(curr_height);
1167
1168   if (XtIsManaged(lyric_t)) {
1169     if (Cfg.disptrace == True) {
1170       if (base_height + trace_v_height + 4 > curr_height) lyric_height = 4;
1171       else lyric_height = curr_height - base_height - trace_v_height;
1172     } else {
1173       if (base_height + 4 > curr_height) lyric_height = 4;
1174       else lyric_height = curr_height - base_height;
1175     }
1176     XtResizeWidget(lyric_t, curr_width-10,lyric_height, 1);
1177     XtVaGetValues(lyric_t, XtNheight,&lyric_height, NULL);
1178   }
1179
1180   if (Cfg.disptrace == True) {
1181     XtManageChild(trace_vport);
1182     XtVaSetValues(trace_vport, XtNtop,XawChainBottom, NULL);
1183   }
1184
1185   XawFormDoLayout(base_f, True);
1186   XSync(disp, False);
1187 }
1188
1189 static ldStorePointer
1190 init_ldS(void) {
1191   ldStorePointer p;
1192   p = (ldStorePointer)safe_malloc(sizeof(ldStore));
1193   p->name = NULL;
1194   return p;
1195 }
1196
1197 #if 0
1198 static void
1199 free_ldS(ldStorePointer ldS) {
1200   if (ldS == NULL) return;
1201   if (ldS->name == NULL) free(ldS);
1202   else {
1203     free_ldS( (ldStorePointer)ldS->next);
1204     free(ldS->fdirlist); free(ldS->ddirlist); free(ldS->fulldirlist);
1205     free(ldS->ld);
1206     free(ldS->name);
1207     free(ldS);
1208   }
1209   return;
1210 }
1211 #endif
1212
1213 static ldStorePointer
1214 getldsPointer(ldStorePointer lds, const char *Popname) {
1215   if ((lds == NULL) || (Popname == NULL)) {
1216     fprintf(stderr, "getldPointer received NULL parameter!\n");
1217     exit(1);
1218   }
1219   if (lds->name == NULL) {
1220     lds->name = safe_strdup(Popname);
1221     lds->ld = (ldPointer)safe_malloc(sizeof(load_dialog));
1222     strlcpy(lds->ld->ld_popupname, Popname, MAX_POPUPNAME);
1223     strlcpy(lds->ld->ld_basepath, Cfg.DefaultDir, sizeof(lds->ld->ld_basepath));
1224     lds->ld->ld_cur_filter[0] = '\0';
1225     if (strcmp(LISTDIALOGBASENAME, Popname))
1226       strlcpy(lds->ld->ld_filter, "*.mid", 6);
1227     else strlcpy(lds->ld->ld_filter, "*.tpl", 6);
1228     lds->ld->ld_popup_load = NULL;
1229     lds->ld->ld_fdirlist.StringArray = NULL;
1230     lds->ld->ld_ddirlist.StringArray = NULL;
1231     lds->ld->ld_fulldirlist.StringArray = NULL;
1232     lds->next = (struct ldStore_t *)init_ldS();
1233     return lds;
1234   }
1235   if (!strncmp(lds->name, Popname, MAX_POPUPNAME)) return lds;
1236   return getldsPointer( (ldStorePointer)lds->next, Popname);
1237 }
1238
1239 static void
1240 restoreLDPointer(Widget w, XtPointer client_data, XEvent *ev, Boolean *b) {
1241   if (ev->xany.type == FocusIn) ld = (ldPointer)client_data;
1242   return;
1243 }
1244
1245 static void
1246 createDialog(Widget w, ldPointer ld) {
1247   Position popup_x, popup_y, top_x, top_y;
1248   Widget load_l,load_t;
1249
1250   XtVaGetValues(toplevel, XtNx,&top_x, XtNy,&top_y, XtNwidth,&ldwidth, NULL);
1251   ldheight = POPUP_HEIGHT;
1252   popup_x = top_x + 20 + ran();
1253   popup_y = top_y + 72 + ran();
1254   if (popup_x+ldwidth > root_width)
1255         popup_x = root_width - ldwidth - 20;
1256   if (popup_y+ldheight > root_height)
1257         popup_y = root_height - POPUP_HEIGHT - 20;
1258   ldwidth += 100-4;
1259
1260   popup_load = XtVaCreatePopupShell(popupname, transientShellWidgetClass,
1261                toplevel, XtNx,popup_x, XtNy,popup_y, XtNheight,ldheight, NULL);
1262   load_d = XtVaCreateManagedWidget("load_dialog",dialogWidgetClass,
1263            popup_load, XtNbackground,bgcolor, XtNresize,True,
1264            XtNvalue,"", NULL);
1265           /* We set XtNvalue because we need load_t to exist now so it
1266            * can be given the correct size.
1267            */
1268   load_t = XtNameToWidget(load_d, "value");
1269   load_l = XtNameToWidget(load_d, "label");
1270   load_ok = XtVaCreateManagedWidget("OK",commandWidgetClass,load_d, NULL);
1271   XawDialogAddButton(load_d, "add", popdownAddALL, (XtPointer)ld);
1272   XawDialogAddButton(load_d, "Cancel", popdownCB, (XtPointer)ld);
1273   load_f = XtVaCreateManagedWidget("filter",toggleWidgetClass,load_d,
1274            XtNforeground,togglecolor, XtNbackground,buttonbgcolor, NULL);
1275
1276   cwd_l = XtVaCreateManagedWidget("cwd_label",labelWidgetClass,
1277              load_d, XtNlabel,basepath, XtNborderWidth,0,
1278              XtNfromVert,load_f, XtNwidth,ldwidth, XtNheight,INFO_HEIGHT,
1279              XtNbackground,text2bgcolor, XtNresize,False, NULL);
1280   load_pane = XtVaCreateManagedWidget("pane",panedWidgetClass,load_d,
1281              XtNfromVert,cwd_l, XtNwidth,ldwidth, XtNheight,PANE_HEIGHT,
1282              XtNorientation,XtorientHorizontal, NULL);
1283   load_vportdir = XtVaCreateManagedWidget("vdport",viewportWidgetClass,
1284              load_pane, XtNallowHoriz,True, XtNallowVert,True,
1285              XtNbackground,textbgcolor, XtNpreferredPaneSize,ldwidth/5, NULL);
1286   load_vport = XtVaCreateManagedWidget("vport",viewportWidgetClass,
1287              load_pane, XtNallowHoriz,True, XtNallowVert,True,
1288              XtNbackground,textbgcolor, XtNpreferredPaneSize,ldwidth*4/5, NULL);
1289   load_dlist = XtVaCreateManagedWidget("dirs",listWidgetClass,load_vportdir,
1290              XtNverticalList,True, XtNforceColumns,True,
1291              XtNbackground,textbgcolor, XtNdefaultColumns,1, NULL);
1292   load_flist = XtVaCreateManagedWidget("files",listWidgetClass,load_vport,
1293              XtNverticalList,True, XtNforceColumns,False,
1294              XtNbackground,textbgcolor, XtNdefaultColumns,3, NULL);
1295   load_info = XtVaCreateManagedWidget("cwd_info",labelWidgetClass,
1296              load_d, XtNborderWidth,0, XtNwidth,ldwidth,
1297              XtNheight,INFO_HEIGHT, XtNresize,False,
1298              XtNbackground,text2bgcolor, XtNfromVert,load_pane, NULL);
1299   XtVaSetValues(load_t, XtNwidth,(int)(ldwidth/1.5), NULL);
1300   XtVaSetValues(load_l, XtNwidth,(int)(ldwidth/1.5), NULL);
1301
1302   XtAddCallback(load_flist, XtNcallback,
1303                  (XtCallbackProc)setFileLoadCB, (XtPointer)ld); 
1304   XtAddCallback(load_dlist, XtNcallback,
1305                  (XtCallbackProc)setDirLoadCB, (XtPointer)ld); 
1306   XtAddCallback(load_f, XtNcallback,callFilterDirList, (XtPointer)ld);
1307   XtInstallAccelerators(load_t, load_f);
1308   XtAddEventHandler(popup_load, FocusChangeMask, False,
1309                     restoreLDPointer, (XtPointer)ld);
1310 }
1311
1312 static void
1313 popupDialog(Widget w, char *Popname, String *title,
1314             XtCallbackProc OKfunc, ldStorePointer ldS) {
1315   ldPointer ldlocal;
1316
1317   ldlocal = getldsPointer(ldS, Popname)->ld;
1318   ld = ldlocal;
1319   if (popup_load == NULL) createDialog(w, ldlocal);
1320
1321   XtRemoveAllCallbacks(load_ok,XtNcallback);
1322   XtAddCallback(load_ok, XtNcallback,OKfunc, (XtPointer)ldlocal);
1323   if (title != NULL) XtVaSetValues(popup_load, XtNtitle,*title, NULL);
1324
1325   setDirList(ldlocal, basepath);
1326   XtVaSetValues(cwd_l, XtNlabel,basepath, NULL);
1327
1328   setupWindow(popup_load, "MenuPopdown()", False, False);
1329   /* Uses MenuPopdown() (see intrinsics p.88) becuase FocusIn events
1330    * are not always recieved on pressing the X button so ld can be
1331    * incorrect for do-popdown().
1332    */
1333
1334   XtVaSetValues(load_flist, XtNwidth,0, XtNheight,0, NULL);
1335   XtVaSetValues(load_dlist, XtNwidth,0, XtNheight,0, NULL);
1336   /* Neccesary to bypass Xaw8 bug: The listwidget will always inherit
1337    * width and height regardless of original setting. This should be
1338    * harmless on other implementations.
1339    */
1340 }
1341
1342 static void
1343 popdownCB(Widget w, XtPointer client_data, XtPointer call_data) {
1344   XtPopdown(popup_load); /* uses global ld */
1345 }
1346
1347 static void
1348 popdownAddALLACT(Widget w, XEvent *e, String *v, Cardinal *n) {
1349   popdownAddALL(w, ld, NULL); /* uses global ld */
1350 }
1351
1352 static void
1353 popdownAddALL(Widget w, XtPointer client_data, XtPointer call_data) {
1354   char *p;
1355   ldPointer ld = (ldPointer)client_data;
1356   String *filelist = fdirlist;
1357   Boolean toggle;
1358
1359   XtVaGetValues(load_f, XtNstate,&toggle, NULL);
1360   if ((toggle == False) || (filelist == NULL)) {
1361     a_pipe_write("%c%s/", S_ADD_TO_PLAYLIST, basepath);
1362     /*
1363      * Speed shortcut - timidity internals can get a directory name, and
1364      * get the midi files from it.
1365      */
1366     goto addallpopdown;
1367   }
1368   while ((p = *(filelist++)) != NULL) {
1369     a_pipe_write("%c%s/%s", S_ADD_TO_PLAYLIST, basepath, p);
1370   }
1371 addallpopdown:
1372   XtPopdown(popup_load);
1373 }
1374
1375 static void
1376 popdownLoadfile(Widget w, XtPointer client_data, XtPointer call_data) {
1377   char *p, *p2;
1378   ldPointer ld = (ldPointer)client_data;
1379
1380   p = XawDialogGetValueString(load_d);
1381   if ((!strncmp(p, "http:", 5)) || (!strncmp(p, "ftp:", 4))) goto lfiledown;
1382   if ((p2 = expandDir(p, NULL, basepath)) != NULL) p = p2;
1383   if (!IsEffectiveFile(p)) {
1384     char *s = strrchr(p, '/');
1385
1386     if (s == NULL) return;
1387     else s++;
1388     p2 = s;
1389     while ((*s) != '\0') {
1390       if ((*s == '*') || (*s == '?')) {
1391         strlcpy(filter, p2, sizeof(filter));
1392         XtVaSetValues(load_f, XtNstate,True, NULL);
1393         filterDirList(ld, True);
1394         return;
1395       }
1396       s++;
1397     }
1398   }
1399 lfiledown:
1400   a_pipe_write("%c%s", S_ADD_TO_PLAYLIST, p);
1401 #ifdef CLEARVALUE
1402   clearValue(load_d);
1403 #endif /* CLEARVALUE */
1404   XtVaSetValues(load_d, XtNvalue,"", NULL);
1405   XtPopdown(popup_load);
1406 }
1407
1408 static void
1409 popdownSavefile(Widget w, XtPointer client_data, XtPointer call_data) {
1410   char *p, *p2;
1411   char lbuf[PIPE_LENGTH];
1412   struct stat st;
1413   ldPointer ld = (ldPointer)client_data;
1414
1415   p = XawDialogGetValueString(XtParent(w));
1416   if ((p2 = expandDir(p, NULL, basepath)) != NULL) p = p2;
1417   strlcpy(lbuf, p, sizeof(lbuf));
1418   if (stat(lbuf, &st) != -1) {
1419     if (st.st_mode & S_IFMT & (S_IFREG|S_IFLNK)) {
1420       if (confirmCB(popup_load, "warnoverwrite", True) != OK) return;
1421     }
1422     else return;
1423   }
1424
1425   record->lbuf = safe_strdup(lbuf);
1426   saveformatDialog(popup_load);
1427 }
1428
1429 static void
1430 popdownLoadPL(Widget w, XtPointer client_data, XtPointer call_data) {
1431   char *p, *p2;
1432   ldPointer ld = (ldPointer)client_data;
1433
1434   p = XawDialogGetValueString(load_d);
1435   if ((p2 = expandDir(p, NULL, basepath)) != NULL) p = p2;
1436   if ( (IsEffectiveFile(p)) && (!readPlaylist(p)) ) {
1437 #ifdef CLEARVALUE
1438     clearValue(load_d);
1439 #endif /* CLEARVALUE */
1440     XtVaSetValues(load_d, XtNvalue,"", NULL);
1441     XtPopdown(popup_load);
1442   } else {
1443     char *s = strrchr(p, '/');
1444
1445     if (s == NULL) return;
1446     else s++;
1447     p2 = s;
1448     while ((*s) != '\0') {
1449       if ((*s == '*') || (*s == '?')) {
1450         strlcpy(filter, p2, sizeof(filter));
1451         XtVaSetValues(load_f, XtNstate,True, NULL);
1452         filterDirList(ld, True);
1453         return;
1454       }
1455       s++;
1456     }
1457   }
1458 }
1459
1460 static void
1461 popdownSavePL(Widget w, XtPointer client_data, XtPointer call_data) {
1462   char *p, *p2;
1463   struct stat st;
1464   ldPointer ld = (ldPointer)client_data;
1465
1466   p = XawDialogGetValueString(XtParent(w));
1467   if ((p2 = expandDir(p, NULL, basepath)) != NULL) p = p2;
1468   if (stat(p, &st) != -1) {
1469     if (st.st_mode & S_IFMT & (S_IFREG|S_IFLNK)) {
1470       if (confirmCB(popup_load, "warnoverwrite", True) != OK) return;
1471     }
1472     else return;
1473   }
1474   a_pipe_write("%c%s", S_SAVE_PLAYLIST, p);
1475 #ifdef CLEARVALUE
1476   clearValue(XtParent(w));
1477 #endif /* CLEARVALUE */
1478   XtVaSetValues(XtParent(w), XtNvalue,"", NULL);
1479   XtPopdown(popup_load);
1480 }
1481
1482 static void 
1483 saveformatDialog(Widget parent) {
1484   Widget popup_sform, popup_sformat, popup_slabel, sbox_rbox, sbox_ratelabel,
1485          sbox_ratetext, popup_sbuttons, popup_sok, popup_scancel, lowBox;
1486
1487   if ((recording == True) ||
1488       ((popup_sformat = XtNameToWidget(parent, "popup_sformat")) != NULL)) {
1489     warnCB(parent, "warnrecording", True);
1490     free(record->lbuf);
1491     return;
1492   }
1493
1494   popup_sformat = XtVaCreatePopupShell("popup_sformat",
1495             transientShellWidgetClass,parent, NULL);
1496   popup_sform = XtVaCreateManagedWidget("popup_sform",formWidgetClass,
1497             popup_sformat, XtNbackground,bgcolor, XtNwidth,200, NULL);
1498   popup_slabel = XtVaCreateManagedWidget("popup_slabel",labelWidgetClass,
1499             popup_sform, XtNbackground,menubcolor, NULL);
1500
1501   lowBox = createOutputSelectionWidgets(popup_sformat, popup_sform,
1502                                              popup_slabel, record, False);
1503
1504   sbox_rbox = XtVaCreateManagedWidget("sbox_rbox",boxWidgetClass,popup_sform,
1505                                            XtNorientation,XtorientVertical,
1506                                            XtNbackground,bgcolor,
1507                                            XtNfromVert,lowBox,
1508                                            XtNborderWidth,0, NULL);
1509   sbox_ratelabel = XtVaCreateManagedWidget("sbox_ratelabel",labelWidgetClass,
1510                                               sbox_rbox, XtNborderWidth,0,
1511                                               XtNforeground,textcolor,
1512                                               XtNbackground,bgcolor, NULL);
1513   sbox_ratetext = XtVaCreateManagedWidget("sbox_ratetext",asciiTextWidgetClass,
1514                                               sbox_rbox,
1515                                               XtNdisplayNonprinting,False,
1516                                               XtNfromHoriz,sbox_ratelabel,
1517                                               XtNstring,(String)S(DEFAULT_RATE),
1518                                               XtNbackground,textbgcolor,
1519                                               XtNforeground,textcolor,
1520                                               XtNeditType,XawtextEdit, NULL);
1521   XtCallActionProc(sbox_ratetext, (String)"end-of-line", NULL, NULL, ZERO);
1522   XtInstallAccelerators(sbox_ratetext, record->formatGroup);
1523
1524   popup_sbuttons = XtVaCreateManagedWidget("popup_sbuttons",boxWidgetClass,
1525                                            popup_sform, XtNbackground,bgcolor,
1526                                            XtNorientation,XtorientHorizontal,
1527                                            XtNfromVert,sbox_rbox,
1528                                            XtNborderWidth,0, NULL);
1529   popup_sok = XtVaCreateManagedWidget("OK",commandWidgetClass,popup_sbuttons,
1530                     XtNbackground,buttonbgcolor, XtNresize,False,
1531                     XtNfromVert,sbox_rbox, XtNwidth,90, NULL);
1532   popup_scancel = XtVaCreateManagedWidget("Cancel",commandWidgetClass,
1533                     popup_sbuttons, XtNbackground,buttonbgcolor,
1534                     XtNresize,False, XtNfromVert,sbox_rbox,
1535                     XtNfromHoriz,popup_sok, XtNwidth,90, NULL);
1536
1537   XtAddCallback(popup_sok, XtNcallback,recordCB, (XtPointer)sbox_ratetext);
1538   XtAddCallback(popup_scancel, XtNcallback,closeWidgetCB,
1539                 (XtPointer)popup_sformat);
1540
1541   setupWindow(popup_sformat, "do-closeparent()", False, True);
1542   XtSetKeyboardFocus(popup_sformat, sbox_ratetext);
1543 }
1544
1545 static void
1546 recordCB(Widget w, XtPointer client_data, XtPointer call_data) {
1547   String rate;
1548   Widget warning;
1549   id_list *result;
1550   int i;
1551
1552   if (client_data != NULL) w = (Widget)client_data;
1553   result = (id_list *)XawToggleGetCurrent(record->formatGroup);
1554   XtVaGetValues(w, XtNstring,&rate, NULL);
1555   i = atoi(rate);
1556   if ((i < MIN_OUTPUT_RATE) || (i > MAX_OUTPUT_RATE)) return;
1557   if (recording == True) {
1558     warnCB(toplevel, "warnrecording", True);
1559     return;
1560   }
1561   recording = True;
1562   snprintf(local_buf, sizeof(local_buf), "%c%c%d %s", S_SET_RECORDING,
1563            result->id_char, i, record->lbuf);
1564   w = seekTransientShell(w);
1565   XtPopdown(XtParent(w));
1566   XtPopdown(w);
1567
1568   stopCB(NULL, NULL, NULL);
1569   warning = warnCB(toplevel, "waitforwav", False);
1570   a_pipe_write("%s", local_buf);
1571   while (strncmp(local_buf, CHECKPOST "1", 2)) {
1572     XtAppProcessEvent(app_con, XtIMAll);
1573   }
1574   if (*(local_buf + 2) == 'E') goto savend;
1575 #ifdef CLEARVALUE
1576   clearValue(load_d);
1577 #endif /* CLEARVALUE */
1578   XtVaSetValues(load_d, XtNvalue,"", NULL);
1579   a_pipe_write("%c", S_PLAY);
1580   while (strncmp(local_buf, CHECKPOST "2", 2)) {
1581     XtAppProcessEvent(app_con, XtIMAll);
1582   }
1583 savend:
1584   XtDestroyWidget(warning);
1585   a_pipe_write("%c", S_STOP_RECORDING);
1586   nextCB(NULL, NULL, NULL);
1587   stopCB(NULL, NULL, NULL);
1588   recording = False;
1589 }
1590
1591 static void
1592 recordACT(Widget w, XEvent *e, String *v, Cardinal *n) {
1593   recordCB(w, NULL, NULL);
1594 }
1595
1596 static void
1597 scrollListACT(Widget w, XEvent *e, String *v, Cardinal *n) {
1598   int i = atoi(*v);
1599   Widget scrollbar;
1600   int x, y;
1601   Window win;
1602
1603   XTranslateCoordinates(disp, XtWindow(w), XtWindow(XtParent(w)),
1604                         e->xbutton.x, e->xbutton.y, &x, &y, &win);
1605
1606   scrollbar = XtNameToWidget(XtParent(w), "vertical");
1607   if (scrollbar != NULL) {
1608     e->xbutton.y = y;
1609   } else {
1610     scrollbar = XtNameToWidget(XtParent(w), "horizontal");
1611     if (scrollbar == NULL) return;
1612     e->xbutton.x = x;
1613   }
1614
1615   if (i > 0) {
1616     String arg[1];
1617     arg[0] = XtNewString("Forward");
1618     XtCallActionProc(scrollbar, (String)"StartScroll", e, arg, ONE);
1619     XtFree(arg[0]);
1620     if (use_own_start_scroll) {
1621       XtCallActionProc(scrollbar, (String)"NotifyThumb", e, NULL, ZERO);
1622     } else {
1623       arg[0] = XtNewString("Proportional");
1624       XtCallActionProc(scrollbar, (String)"NotifyScroll", e, arg, ONE);
1625       XtFree(arg[0]);
1626     }
1627     XtCallActionProc(scrollbar, (String)"EndScroll", e, NULL, ZERO);
1628   } else {
1629     String arg[1];
1630     arg[0] = XtNewString("Backward");
1631     XtCallActionProc(scrollbar, (String)"StartScroll", e, arg, ONE);
1632     XtFree(arg[0]);
1633     if (use_own_start_scroll) {
1634       XtCallActionProc(scrollbar, (String)"NotifyThumb", e, NULL, ZERO);
1635     } else {
1636       arg[0] = XtNewString("Proportional");
1637       XtCallActionProc(scrollbar, (String)"NotifyScroll", e, arg, ONE);
1638       XtFree(arg[0]);
1639     }
1640     XtCallActionProc(scrollbar, (String)"EndScroll", e, NULL, ZERO);
1641   }
1642 }
1643
1644 static void
1645 toggleMark(Widget w, Boolean value) {
1646   XtVaSetValues(w, XtNleftBitmap,(value == True)?check_mark:None, NULL);
1647 }
1648
1649 static void
1650 filemenuACT(Widget w, XEvent *e, String *v, Cardinal *n) {
1651   int i = atoi(*v);
1652
1653   filemenuCB(file_menu[i-100].widget, (XtPointer)&file_menu[i-100].id, NULL);
1654 }
1655
1656 static void
1657 popupfilemenuACT(Widget w, XEvent *e, String *v, Cardinal *n) {
1658   XtCallActionProc(file_mb, (String)"reset", e, NULL, ZERO);
1659   XtCallActionProc(file_mb, (String)"PopupMenu", e, NULL, ZERO);
1660 }
1661
1662 static void
1663 popdownfilemenuACT(Widget w, XEvent *e, String *v, Cardinal *n) {
1664   XtCallActionProc(file_mb, (String)"reset", e, NULL, ZERO);
1665   XtCallActionProc(file_sm, (String)"MenuPopdown", e, NULL, ZERO);
1666 }
1667
1668 static void
1669 filemenuCB(Widget w, XtPointer client_data, XtPointer call_data) {
1670   int *id = (int *)client_data;
1671
1672   switch (*id) {
1673     case ID_LOAD:
1674       popupDialog(w, "dialog_lfile", NULL, popdownLoadfile, ldSstart);
1675       break;
1676     case ID_SAVE:
1677       if ((record == NULL) || (max_files == 0)) return;
1678       popupDialog(w, "dialog_sfile", NULL, popdownSavefile, ldSstart);
1679       break;
1680     case ID_LOAD_PLAYLIST:
1681       popupDialog(w, LISTDIALOGBASENAME, 
1682                 &app_resources.load_LISTDIALOGBASENAME_title,
1683                 popdownLoadPL, ldSstart);
1684       break;
1685     case ID_SAVE_PLAYLIST:
1686       popupDialog(w, LISTDIALOGBASENAME, 
1687                  &app_resources.save_LISTDIALOGBASENAME_title,
1688                  popdownSavePL, ldSstart);
1689       break;
1690     case ID_AUTOSTART:
1691       Cfg.autostart ^= True;
1692       toggleMark(w, Cfg.autostart);
1693       break;
1694     case ID_AUTOQUIT:
1695       Cfg.autoexit ^= True;
1696       toggleMark(w, Cfg.autoexit);
1697       a_pipe_write("%c", S_TOGGLE_AUTOQUIT);
1698       break;
1699     case ID_HIDETRACE:
1700       XawFormDoLayout(base_f, False);
1701       if (!ctl->trace_playing) {
1702         Boolean s;
1703
1704         XtVaSetValues(b_box, XtNleft,XawRubber, XtNright,XawRubber, NULL);
1705         createTraceWidgets();
1706        /*
1707         * trace_vport should be unmanaged before calling XResizeWindow, with
1708         * XtNtop set to XawChainTop else xaw tends to place it on the wrong
1709         * place (typically where lyric_t used to be before calling
1710         * XResizeWindow). After the resize, we'll remanage trace_vport, and
1711         * set XtNtop to XawChainBottom (so that resizing won't change height).
1712         */
1713         XtUnmanageChild(trace_vport);
1714         callInitTrace();
1715         ctl->trace_playing = 1;
1716 #ifdef HAVE_TIP
1717         xawTipSet(Cfg.tooltips);
1718 #endif /* HAVE_TIP */
1719        /*
1720         * In the case lyric_t is not managed, the maximum height has been 
1721         * defined to curr_height by setSizeHints. We need to increase it 
1722         * otherwise the trace may not be shown - the WM may cap
1723         * XConfigureEvent->height to
1724         * maximum_height - WINDOW_DECORATIONS_HEIGHT.
1725         */
1726         if (!XtIsManaged(lyric_t)) setSizeHints(root_height);
1727         XResizeWindow(disp, XtWindow(toplevel),
1728                       TRACE_WIDTH+8, curr_height + trace_v_height);
1729         XtVaGetValues(play_b, XtNstate,&s, NULL);
1730         if (s == True) a_pipe_write("%c%c", S_ENABLE_TRACE, ST_RESET);
1731         else a_pipe_write("%c", S_ENABLE_TRACE);
1732         toggleMark(w, True);
1733         return;
1734       }
1735      /*
1736       * We must do this via XResizeWindow, as we are unable to calculate
1737       * lyric_height correctly here in the case
1738       * (trace_v_height + curr_height) is too big.
1739       *
1740       * lyric_height = curr_height - base_height -
1741       * (XtIsManaged(trace_vport))?trace_v_height:0.
1742       *
1743       * curr_height should be capped to max_height - WINDOW_DECORATIONS_HEIGHT
1744       *
1745       * We do not know WDH, so we cannot avoid overflow leading to
1746       * display artifacts when (trace_v_height + curr_height)
1747       * is larger than the cap.
1748       * However, most WMs will not return an XConfigureEvent->
1749       * height greater than that cap, so resizeToplevelAction can
1750       * calculate a correct lyric_height.
1751       */
1752       if (XtIsManaged(trace_vport)) {
1753         XtUnmanageChild(trace_vport);
1754         XtUnmanageChild(fast_b); XtUnmanageChild(slow_b);
1755         XtUnmanageChild(keyup_b); XtUnmanageChild(keydown_b);
1756         XtVaSetValues(b_box, XtNleft,XawChainLeft, XtNright,XawChainLeft, NULL);
1757         XResizeWindow(disp, XtWindow(toplevel), DEFAULT_REG_WIDTH,
1758                       curr_height - trace_v_height);
1759         Cfg.disptrace = False;
1760       } else {
1761         XtVaSetValues(trace_vport, XtNtop,XawChainTop, NULL);
1762         if (!XtIsManaged(lyric_t)) setSizeHints(root_height);
1763         XtVaSetValues(b_box, XtNleft,XawRubber, XtNright,XawRubber, NULL);
1764         XtManageChild(fast_b); XtManageChild(slow_b);
1765         XtManageChild(keyup_b); XtManageChild(keydown_b);
1766         XResizeWindow(disp, XtWindow(toplevel),
1767                       TRACE_WIDTH+8, curr_height + trace_v_height);
1768         Cfg.disptrace = True;
1769       }
1770       toggleMark(w, !Cfg.disptrace);
1771       break;
1772     case ID_HIDETXT:
1773       XawFormDoLayout(base_f, False);
1774       if (Cfg.disptrace == True) {
1775         XtUnmanageChild(trace_vport);
1776         XtVaSetValues(trace_vport, XtNtop,XawChainTop, NULL);
1777       }
1778       if (XtIsManaged(lyric_t)) {
1779         if (ctl->trace_playing)
1780           XtVaSetValues(trace_vport, XtNfromVert,t_box, NULL);
1781         XtUnmanageChild(lyric_t);
1782         XResizeWindow(disp, XtWindow(toplevel),
1783                       curr_width, curr_height - lyric_height);
1784         Cfg.disptext = False;
1785       } else {
1786         setSizeHints(curr_height + lyric_height);
1787         if (ctl->trace_playing)
1788           XtVaSetValues(trace_vport, XtNfromVert,lyric_t, NULL);
1789         XtManageChild(lyric_t);
1790         XResizeWindow(disp, XtWindow(toplevel),
1791                       curr_width, curr_height + lyric_height);
1792         Cfg.disptext = True;
1793       }
1794       toggleMark(w, !Cfg.disptext);
1795       break;
1796     case ID_SAVECONFIG:
1797       a_saveconfig(dotfile, Cfg.save_list);
1798       break;
1799     case ID_SHUFFLE:
1800       Cfg.shuffle ^= True;
1801       randomCB(NULL, (XtPointer)&Cfg.shuffle, NULL);
1802       break;
1803     case ID_REPEAT:
1804       Cfg.repeat ^= True;
1805       repeatCB(NULL, (XtPointer)&Cfg.repeat, NULL);
1806       break;
1807     case ID_OPTIONS:
1808       optionspopupACT(w, NULL, NULL, NULL);
1809       break;
1810     case ID_FILELIST:
1811       flistpopupACT(w, NULL, NULL, NULL);
1812       break;
1813     case ID_ABOUT:
1814       aboutACT(w, NULL, NULL, NULL);
1815       break;
1816     case ID_QUIT:
1817       quitCB(w, NULL, NULL);
1818       break;
1819   }
1820 }
1821
1822 #ifdef WIDGET_IS_LABEL_WIDGET
1823 static void
1824 a_print_msg(Widget w) {
1825   size_t i, msglen;
1826
1827   a_pipe_nread((char *)&msglen, sizeof(size_t));
1828   while (msglen > 0) {
1829     i = msglen;
1830     if (i > sizeof(local_buf)-1) i = sizeof(local_buf)-1;
1831     a_pipe_nread(local_buf, i);
1832     local_buf[i] = '\0';
1833     XtVaSetValues(w, XtNlabel,local_buf, NULL);
1834     msglen -= i;
1835   }
1836 }
1837
1838 static void
1839 a_print_text(Widget w, char *st) {
1840   XtVaSetValues(w, XtNlabel,st, NULL);
1841 }
1842 #else
1843 static void
1844 a_print_msg(Widget w) {
1845   size_t i, msglen;
1846   XawTextPosition pos;
1847   XawTextBlock tb;
1848
1849   tb.firstPos = 0;
1850   tb.ptr = local_buf;
1851   tb.format = XawFmt8Bit;
1852   pos = XawTextGetInsertionPoint(w);
1853
1854   a_pipe_nread((char *)&msglen, sizeof(size_t));
1855   while (msglen > 0) {
1856     i = msglen;
1857     if (i > sizeof(local_buf)) i = sizeof(local_buf);
1858     a_pipe_nread(local_buf, i);
1859     tb.length = i;
1860     XawTextReplace(w, pos, pos, &tb);
1861     pos += i;
1862     XawTextSetInsertionPoint(w, pos+1);
1863     msglen -= i;
1864   }
1865 #ifdef BYPASSTEXTSCROLLBUG
1866   XtCallActionProc(lyric_t, (String)"redraw-display", NULL, NULL, ZERO);
1867 #endif /* BYPASSTEXTSCROLLBUG */
1868 }
1869
1870 static void
1871 a_print_text(Widget w, const char *st) {
1872   XawTextPosition pos;
1873   XawTextBlock tb;
1874   char s[PIPE_LENGTH];
1875
1876   snprintf(s, sizeof(s), "%s\n", st);
1877   pos = XawTextGetInsertionPoint(w);
1878   tb.firstPos = 0;
1879   tb.length = strlen(st);
1880   tb.ptr = s;
1881   tb.format = XawFmt8Bit;
1882   XawTextReplace(w, pos, pos, &tb);
1883   XawTextSetInsertionPoint(w, pos + tb.length);
1884 }
1885 #endif /* WIDGET_IS_LABEL_WIDGET */
1886
1887 static void
1888 free_vars(void) {
1889   Cardinal i = 0, n;
1890   WidgetList wl;
1891   Pixmap bm_Pixmap;
1892
1893   XtUnmapWidget(toplevel);
1894   if (ctl->trace_playing) uninitTrace();
1895   XFreePixmap(disp, check_mark); XFreePixmap(disp, arrow_mark);
1896   XFreePixmap(disp, on_mark); XFreePixmap(disp, off_mark);
1897   XtVaGetValues(b_box, XtNchildren,&wl, XtNnumChildren,&n, NULL);
1898   for (i = 0; i < n; i++) {
1899     XtVaGetValues(wl[i], XtNbitmap,&bm_Pixmap, NULL);
1900     XFreePixmap(disp, bm_Pixmap);
1901   }
1902   XtDestroyApplicationContext(app_con);
1903 }
1904
1905 static void
1906 handle_input(XtPointer data, int *source, XtInputId *id) {
1907   char s[16];
1908   int n; long i;
1909   barfloat thumb;
1910
1911   a_pipe_read(local_buf, sizeof(local_buf));
1912   switch (local_buf[0]) {
1913   case M_CUR_TIME:
1914     curr_time = n = atoi(local_buf+1);
1915     if (halt) break;
1916     i = n % 60; n /= 60;
1917     sprintf(s, "%d:%02ld", n, i);
1918     XtVaSetValues(tune_l0, XtNlabel,s, NULL);
1919     if (total_time > 0) {
1920       thumb.f = (float)curr_time / (float)total_time;
1921       setThumb(tune_bar, thumb);
1922     }
1923     break;
1924   case M_TOTAL_TIME:
1925     n = atoi(local_buf+1);
1926     if (n > 0) {
1927       total_time = n;
1928       snprintf(s, sizeof(s), "/%2d:%02d", n/60, n%60);
1929       XtVaSetValues(tune_l, XtNlabel,s, NULL);
1930     }
1931     break;
1932   case M_LISTITEM:
1933     {
1934       char *name;
1935       name = strchr(local_buf+1, ' ');
1936       current_n_displayed = n = atoi(local_buf+1);
1937       lockevents = False;
1938       if (IsRealized(popup_file))
1939         XawListHighlight(file_list, n-1);
1940       if (name == NULL) break;
1941       name++;
1942       XtVaSetValues(title_mb, XtNlabel,name, NULL);
1943       snprintf(window_title, sizeof(window_title), "%s : %s",
1944                APP_CLASS, local_buf+1);
1945       XtVaSetValues(toplevel, XtNtitle,window_title, NULL);
1946     }
1947     break;
1948   case M_TITLE:
1949     if (app_resources.arrange_title) {
1950       char *p = local_buf+1;
1951       if (!strcmp(p, "(null)")) p = (char *)app_resources.tracecfg.untitled;
1952       snprintf(window_title, sizeof(window_title), "%s : %s", APP_CLASS, p);
1953       XtVaSetValues(toplevel, XtNtitle,window_title, NULL);
1954     }
1955     snprintf(window_title, sizeof(window_title), "%s", local_buf+1);
1956     break;
1957   case M_PLAY_END:
1958     thumb.f = 0;
1959     setThumb(tune_bar, thumb);
1960     XtVaSetValues(tune_l0, XtNlabel,"0:00", NULL);
1961     offPlayButton();
1962     break;
1963   case M_LOADING_DONE:
1964     n = atoi(local_buf+1);
1965     if ((!n) && (ctl->trace_playing)) initStatus();
1966     break;
1967   case M_LYRIC:
1968     a_print_msg(lyric_t);
1969     break;
1970   case M_QUIT:
1971     free_vars();
1972     exit(0);
1973   case M_VOLUME:
1974     if (lockevents == True) return;
1975     amplitude = atoi(local_buf+1);
1976     snprintf(s, sizeof(s), "%d", amplitude);
1977     XtVaSetValues(vol_l, XtNlabel,s, NULL);
1978     thumb.f = (float)amplitude / (float)MAXVOLUME;
1979     setThumb(vol_bar, thumb);
1980     break;
1981   case M_FILE_LIST:
1982     n = max_files;
1983     max_files += atoi(local_buf+1);
1984     if ((max_files > 0) && (record != NULL))
1985       XtVaSetValues(file_menu[ID_SAVE - 100].widget, XtNsensitive,True, NULL);
1986     for (i=n;i<max_files;i++) {
1987       a_pipe_read(local_buf, sizeof(local_buf));
1988       addOneFile(max_files, i, local_buf);
1989       addFlist(local_buf, i);
1990     }
1991     if (IsRealized(popup_file)) {
1992       XawListReturnStruct *lr = XawListShowCurrent(file_list);
1993
1994       XawListChange(file_list, flist, max_files, 0, True);
1995       if ((lr != NULL) && (lr->list_index != XAW_LIST_NONE))
1996          XawListHighlight(file_list, lr->list_index);
1997       else
1998         if (max_files > 0) XawListHighlight(file_list, 0);
1999     }
2000     break;
2001   case M_SET_MODE:
2002     n = atoi(local_buf+1);
2003     switch (n) {
2004     case GM_SYSTEM_MODE:
2005       snprintf(s, sizeof(s), "%d:%02d / GM", total_time/60, total_time%60);
2006       break;
2007     case GS_SYSTEM_MODE:
2008       snprintf(s, sizeof(s), "%d:%02d / GS", total_time/60, total_time%60);
2009       break;
2010     case XG_SYSTEM_MODE:
2011       snprintf(s, sizeof(s), "%d:%02d / XG", total_time/60, total_time%60);
2012       break;
2013     default:
2014       snprintf(s, sizeof(s), "%d:%02d", total_time/60, total_time%60);
2015       break;
2016     }
2017     XtVaSetValues(time_l, XtNlabel,s, NULL);
2018     break;
2019   case M_SAVE_PLAYLIST:
2020     {
2021       const char * filename;
2022       n = atoi(local_buf+1);
2023       if (n <= 0) break;
2024       filename = strchr(local_buf, ' ');
2025       if (filename == NULL) break;
2026       savePlaylist(++filename, n);
2027     }
2028     break;
2029   case MT_PITCH:
2030   case MT_TEMPO:
2031     if (IsTracePlaying()) (void)handleTraceinput(local_buf);
2032     break;
2033   case MT_PITCH_OFFSET:
2034     if (IsTracePlaying()) {
2035       XtCallActionProc(keyup_b, (String)"unset", NULL, NULL, ZERO);
2036       XtCallActionProc(keydown_b, (String)"unset", NULL, NULL, ZERO);
2037 #ifdef XAWPLUS
2038       XtCallActionProc(keyup_b, (String)"unhighlight", NULL, NULL, ZERO);
2039       XtCallActionProc(keydown_b, (String)"unhighlight", NULL, NULL, ZERO);
2040 #endif /* XAWPLUS */
2041       (void)handleTraceinput(local_buf);
2042     }
2043     break;
2044   case MT_RATIO:
2045     if (IsTracePlaying()) {
2046       XtCallActionProc(fast_b, (String)"unset", NULL, NULL, ZERO);
2047       XtCallActionProc(slow_b, (String)"unset", NULL, NULL, ZERO);
2048 #ifdef XAWPLUS
2049       XtCallActionProc(fast_b, (String)"unhighlight", NULL, NULL, ZERO);
2050       XtCallActionProc(slow_b, (String)"unhighlight", NULL, NULL, ZERO);
2051 #endif /* XAWPLUS */
2052       (void)handleTraceinput(local_buf);
2053     }
2054     break;
2055   case M_PAUSE:
2056     n = atoi(local_buf+1);
2057     halt = n;
2058     if (n == 0) XtVaSetValues(pause_b, XtNstate,False, NULL);
2059     else XtVaSetValues(pause_b, XtNstate,True, NULL);
2060     break;
2061   case M_CHECKPOST:
2062   case '\0':
2063     break;
2064   default :
2065     if ((lockevents == True) || (((ctl->trace_playing) &&
2066          (!handleTraceinput(local_buf)))))
2067       return;
2068     fprintf(stderr, "Unknown message '%s' from CONTROL\n", local_buf);
2069   }
2070 }
2071
2072
2073 static int
2074 configcmp(const char *s, int *num) {
2075   int i;
2076   const char *p;
2077
2078   for (i = 0; i < CFGITEMSNUMBER; i++) {
2079     if (strncasecmp(s, cfg_items[i], strlen(cfg_items[i])) == 0) {
2080       p = s + strlen(cfg_items[i]);
2081       while ((*p == ' ') || (*p == '\t')) p++;
2082       if ((i == S_MidiFile) || (i == S_DefaultDirectory))
2083         *num = p - s + SPLEN;
2084       else
2085         *num = atoi(p);
2086       return i;
2087     }
2088   }
2089   return -1;
2090 }
2091
2092 static char *
2093 strmatch(char *s1, const char *s2) {
2094   char *p = s1;
2095
2096   while ((*p != '\0') && (*p == *s2++)) p++;
2097   *p = '\0';
2098   return s1;
2099 }
2100
2101 /* Canonicalize by removing /. and /foo/.. if they appear. */
2102 static char *
2103 canonicalize_path(char *path)
2104 {
2105   char *o, *p, *target;
2106   int abspath;
2107
2108   o = p = path;
2109   while (*p) {
2110     if ((p[0] == '/') && (p[1] == '/')) p++;
2111     else *o++ = *p++;
2112   }
2113   while ((path < o-1) && (path[o - path - 1] == '/')) o--;
2114   path[o - path] = '\0';
2115
2116   if ((p = strchr(path, '/')) == NULL) return path;
2117   abspath = (p == path);
2118
2119   o = target = p;
2120   while (*p) {
2121     if (*p != '/') *o++ = *p++;
2122     else if ((p[0] == '/') && (p[1] == '.') && ((p[2] == '/')||(p[2] == '\0')))
2123     {
2124       /* If "/." is the entire filename, keep the "/".  Otherwise,
2125        *  just delete the whole "/.".
2126        */
2127       if ((o == target) && (p[2] == '\0')) *o++ = *p;
2128       p += 2;
2129     }
2130     else if ((p[0] == '/') && (p[1] == '.') && (p[2] == '.') &&
2131     /* `/../' is the "superroot" on certain file systems.  */
2132              (o != target) && (p[3] == '/' || p[3] == '\0'))
2133     {
2134       while ((o != target) && (--o) && (*o != '/'));
2135       p += 3;
2136       if ((o == target) && (!abspath)) o = target = p;
2137     }
2138     else *o++ = *p++;
2139   }
2140
2141   target[o - target] = '\0';
2142   if (*path == '\0') strcpy(path, "/");
2143   return path;
2144 }
2145
2146 static char *
2147 expandDir(char *path, DirPath *full, const char *bpath) {
2148   static char newfull[PATH_MAX];
2149   char tmp[PATH_MAX];
2150   char *p, *tail;
2151
2152   p = path;
2153   if (path == NULL) {
2154     strcpy(tmp, "/");
2155     strcpy(newfull, "/");
2156     if (full != NULL) {
2157       full->basename = NULL;
2158       full->dirname = newfull;
2159     }
2160     return newfull;
2161   } else 
2162     if ((*p != '~') && ((tail = strrchr(path, '/')) == NULL) 
2163          && (strcmp(p, ".")) && (strcmp(p, "..")) )
2164   {
2165     p = tmp;
2166     strlcpy(p, bpath, PATH_MAX);
2167     if (full != NULL) full->dirname = p;
2168     while (*p++ != '\0') ;
2169     strlcpy(p, path, PATH_MAX - (p - tmp));
2170     snprintf(newfull, sizeof(newfull), "%s/%s", bpath, path);
2171     if (full != NULL) full->basename = p;
2172     return newfull;
2173   }
2174   if (*p  == '/') {
2175     strlcpy(tmp, path, PATH_MAX);
2176   } else {
2177     if (*p == '~') {
2178       struct passwd *pw;
2179
2180       p++;
2181       if ((*p == '/') || (*p == '\0')) {
2182         if (home == NULL) return NULL;
2183         while (*p == '/') p++;
2184         snprintf(tmp, sizeof(tmp), "%s/%s", home, p);
2185       } else {
2186         char buf[80], *bp = buf;
2187
2188         while ((*p != '/') && (*p != '\0')) *bp++ = *p++;
2189         *bp = '\0';
2190         pw = getpwnam(buf);
2191         if (pw == NULL) {
2192           ctl->cmsg(CMSG_WARNING, VERB_NORMAL,
2193                     "I tried to expand a non-existant user's homedir!");
2194           return NULL;
2195         }
2196         else home = pw->pw_dir;
2197         while (*p == '/') p++;
2198         snprintf(tmp, sizeof(tmp), "%s/%s", home, p);
2199       }
2200     } else {    /* *p != '~' */
2201       snprintf(tmp, sizeof(tmp), "%s/%s", bpath, path);
2202     }
2203   }
2204   p = canonicalize_path(tmp);
2205   tail = strrchr(p, '/'); *tail++ = '\0';
2206   if (full != NULL) {
2207     full->dirname = p;
2208     full->basename = tail;
2209   }
2210   snprintf(newfull, sizeof(newfull), "%s/%s", p, tail);
2211   return newfull;
2212 }
2213
2214 static void
2215 setDirACT(Widget w, XEvent *e, String *v, Cardinal *n) {
2216 /* uses global ld */
2217   char *p, *p2;
2218   struct stat st;
2219
2220   p = XawDialogGetValueString(load_d);
2221   if ((p2 = expandDir(p, NULL, basepath)) != NULL) p = p2;
2222   if (stat(p, &st) == -1) XtCallCallbacks(load_ok, XtNcallback, (XtPointer)ld);
2223   else if (S_ISDIR(st.st_mode)) {
2224     p2 = strrchr(p, '/');
2225     if ((*(p2+1) == '\0') && (p2 != p)) *p2 = '\0';
2226     if (!setDirList(ld, p) ) {
2227       strlcpy(basepath, p, sizeof(basepath));
2228       XtVaSetValues(cwd_l, XtNlabel,basepath, NULL);
2229 #ifdef CLEARVALUE
2230       clearValue(load_d);
2231 #endif /* CLEARVALUE */
2232       XtVaSetValues(load_d, XtNvalue,"", NULL);
2233     }
2234   }
2235   else XtCallCallbacks(load_ok, XtNcallback,(XtPointer)ld);
2236 }
2237
2238 static void
2239 callFilterDirList(Widget w, XtPointer client_data, XtPointer call_data) {
2240   Boolean toggle;
2241
2242   ldPointer ld = (ldPointer)client_data;
2243   XtVaGetValues(load_f, XtNstate,&toggle, NULL);
2244   filterDirList(ld, toggle);
2245 }
2246
2247 static void
2248 filterDirList(ldPointer ld, Boolean toggle) {
2249 /* can use global ld when called from SetDirAction via SetDirList */
2250   String *fulllist = fulldirlist, *filelist;
2251   StringTable strtab;
2252   char *filename;
2253   char mbuf[35];
2254   unsigned int f_num = 0;
2255
2256   if (toggle == False) {
2257     XawListChange(load_flist, fulldirlist, fullfilenum, 0, True);
2258     XtVaSetValues(load_flist, XtNwidth,0, XtNheight,0, NULL);
2259     snprintf(mbuf, sizeof(mbuf), "%d Directories, %d Files",
2260              dirnum, fullfilenum);
2261     XtVaSetValues(load_info, XtNlabel,mbuf, NULL);
2262     return;
2263   }
2264   else if ( (fdirlist != NULL) &&
2265             (!(strncmp(cur_filter, filter, sizeof(cur_filter)))) )
2266   {
2267     XawListChange(load_flist, fdirlist, filenum, 0, True);
2268     XtVaSetValues(load_flist, XtNwidth,0, XtNheight,0, NULL);
2269     snprintf(mbuf, sizeof(mbuf), "%d Directories, %d Files", dirnum, filenum);
2270     XtVaSetValues(load_info, XtNlabel,mbuf, NULL);
2271     return;
2272   }
2273   if (!strcmp(filter, "SetDirList")) strcpy(filter, cur_filter);
2274   init_string_table(&strtab);
2275   while ((filename = *(fulllist++)) != NULL) {
2276     if (!(arc_case_wildmat(filename, filter))) continue;
2277     f_num++;
2278     put_string_table(&strtab, filename, strlen(filename));
2279   }
2280   filenum = f_num;
2281   if (f_num > 0)
2282     filelist = (String *)make_string_array(&strtab);
2283   else {
2284     filelist = (String *)safe_malloc(sizeof(String));
2285     *filelist = '\0';
2286   }
2287   XawListChange(load_flist, filelist, f_num, 0, True);
2288   free(fdirlist);
2289   fdirlist = filelist;
2290   XtVaSetValues(load_flist, XtNwidth,0, XtNheight,0, NULL);
2291   strlcpy(cur_filter, filter, sizeof(cur_filter));
2292
2293   snprintf(mbuf, sizeof(mbuf), "%d Directories, %d Files", dirnum, filenum);
2294   XtVaSetValues(load_info, XtNlabel,mbuf, NULL);
2295 }
2296
2297 static int
2298 cmpstringp(const void *p1, const void *p2) {
2299   return strcmp(* (char * const *) p1, * (char * const *) p2);
2300 }
2301
2302 static int
2303 setDirList(ldPointer ld, char *curr_dir) {
2304 /* uses global ld when called from SetDirAction */
2305   URL dirp;
2306   struct stat st;
2307   char filename[PATH_MAX];
2308   unsigned int d_num = 0, f_num = 0;
2309   Boolean toggle;
2310
2311   if ((dirp = url_dir_open(curr_dir)) != NULL) {
2312     char *fullpath;
2313     MBlockList pool;
2314     StringTable strftab, strdtab;
2315     String *olddirlist = ddirlist, *oldfullfilelist = fulldirlist;
2316     char lbuf[50];
2317
2318     init_mblock(&pool);
2319     XtVaGetValues(load_f, XtNstate,&toggle, NULL);
2320
2321     init_string_table(&strftab); init_string_table(&strdtab);
2322     while (url_gets(dirp, filename, sizeof(filename)) != NULL) {
2323       fullpath = (char *)new_segment(&pool, strlen(curr_dir) + 
2324                                      strlen(filename) + 2);
2325       sprintf(fullpath, "%s/%s", curr_dir, filename);
2326       if (filename[0] == '.') {
2327         if (filename[1] == '\0') continue;
2328         if ((filename[1] == '.') && (filename[2] == '\0')) {
2329           if ((curr_dir[0] == '/') && (curr_dir[1] == '\0')) continue;
2330         }
2331         else if (!Cfg.showdotfiles) continue;
2332       }
2333       if (stat(fullpath, &st) == -1) continue;
2334       if (S_ISDIR(st.st_mode)) {
2335         strcat(filename, "/"); d_num++;
2336         put_string_table(&strdtab, filename, strlen(filename));
2337       } else {
2338         f_num++;
2339         put_string_table(&strftab, filename, strlen(filename));
2340       }
2341     }
2342     if (d_num > 0) {
2343       ddirlist = (String *)make_string_array(&strdtab);
2344       qsort (ddirlist, d_num, sizeof (char *), cmpstringp);
2345     } else {
2346       ddirlist = (String *)safe_malloc(sizeof(String));
2347       *ddirlist = '\0';
2348     }
2349     if (f_num > 0) {
2350       fulldirlist = (String *)make_string_array(&strftab);
2351       qsort (fulldirlist, f_num, sizeof (char *), cmpstringp);
2352     } else {
2353       fulldirlist = (String *)safe_malloc(sizeof(String));
2354       *fulldirlist = '\0';
2355     }
2356     fullfilenum = f_num; dirnum = d_num;
2357
2358     XawListChange(load_dlist, ddirlist, d_num, 0, True);
2359     XtVaSetValues(load_dlist, XtNwidth,0, XtNheight,0, NULL);
2360     free(olddirlist);
2361     /* According to Xt CLI p. 49, we must keep the list usable
2362      * until it is replaced, so we use a local pointer first,
2363      * and free the previous list only after it has been replaced.
2364      */
2365     if (toggle == True) {
2366       strcpy(filter, "SetDirList");
2367       filterDirList(ld, True);
2368       if (oldfullfilelist) free(oldfullfilelist);
2369       return 0;
2370     }
2371     XawListChange(load_flist, fulldirlist, f_num, 0, True);
2372     XtVaSetValues(load_flist, XtNwidth,0, XtNheight,0, NULL);
2373     /* Same reason as in popupDialog */
2374     free(fdirlist);
2375     fdirlist = NULL;
2376     free(oldfullfilelist);
2377     snprintf(lbuf, sizeof(lbuf), "%d Directories, %d Files",
2378              d_num, f_num);
2379     XtVaSetValues(load_info, XtNlabel,lbuf, NULL);
2380     return 0;
2381   } else {
2382     fprintf(stderr, "Can't read directory\n");
2383     return 1;
2384   }
2385 }
2386
2387 static void
2388 setFileLoadCB(Widget list, XtPointer client_data, XawListReturnStruct *lrs) {
2389   ldPointer ld = (ldPointer)client_data;
2390   Widget Text = XtNameToWidget(load_d, "value");
2391
2392 #ifdef CLEARVALUE
2393   clearValue(load_d);
2394 #endif /* CLEARVALUE */
2395   XtVaSetValues(Text, XtNstring,lrs->string, NULL);
2396   XtVaSetValues(Text, XtNinsertPosition,strlen(lrs->string), NULL);
2397   return;
2398 }
2399
2400 static void
2401 setDirLoadCB(Widget list, XtPointer client_data, XawListReturnStruct *lrs) {
2402   ldPointer ld = (ldPointer)client_data;
2403   struct stat st;
2404   char curr_dir[PATH_MAX];
2405
2406   snprintf(curr_dir, sizeof(curr_dir)-1, "%s/%s", basepath, lrs->string);
2407   canonicalize_path(curr_dir);
2408   if (stat(curr_dir, &st) == -1) return;
2409   if (!setDirList(ld, curr_dir) ) {
2410     strcpy(basepath, curr_dir);
2411     XtVaSetValues(cwd_l, XtNlabel,basepath, NULL);
2412   }
2413   return;
2414 }
2415
2416 static void
2417 toggleTraceACT(Widget w, XEvent *e, String *v, Cardinal *n) {
2418   if (ctl->trace_playing && ((e->xbutton.button == 1) || (e->type == KeyPress)))
2419     toggleTracePlane(IsTracePlaying());
2420 }
2421
2422 static int
2423 getClickedChan(XEvent *e) {
2424   int c;
2425
2426   if (e->xbutton.y <= TRACE_HEADER) return -1;
2427   c = (e->xbutton.y - TRACE_FOOT - BAR_SPACE + BAR_HEIGHT)/BAR_SPACE;
2428   if ((c > getVisibleChanNum()-1) || (c < 0)) return -1;
2429   return c+getLowestVisibleChan();
2430 }
2431
2432 static void
2433 muteChanACT(Widget w, XEvent *e, String *v, Cardinal *n) {
2434   int c;
2435
2436   c = getClickedChan(e);
2437   if (c != -1) a_pipe_write("%c%d", S_SET_MUTE, c);
2438 }
2439
2440 static void
2441 soloChanACT(Widget w, XEvent *e, String *v, Cardinal *n) {
2442   int c;
2443
2444   c = getClickedChan(e);
2445   if (c != -1) a_pipe_write("%c%d", S_SET_SOLO, c);
2446 }
2447
2448 static void
2449 scrollTraceACT(Widget w, XEvent *e, String *v, Cardinal *n) {
2450   int i = atoi(*v);
2451
2452   if (!ctl->trace_playing) return;
2453   if (i>0) scrollTrace(1);
2454   else scrollTrace(-1);
2455 }
2456
2457 static void
2458 exchgWidthACT(Widget w, XEvent *e, String *v, Cardinal *n) {
2459 #define MEDIAN (TRACE_WIDTH+8 + DEFAULT_REG_WIDTH)/2
2460   if (curr_width < DEFAULT_REG_WIDTH)
2461     XResizeWindow(disp, XtWindow(toplevel), DEFAULT_REG_WIDTH, curr_height);
2462   else if (curr_width < MEDIAN)
2463     XResizeWindow(disp, XtWindow(toplevel), MEDIAN, curr_height);
2464   else if (curr_width < TRACE_WIDTH+8)
2465     XResizeWindow(disp, XtWindow(toplevel), TRACE_WIDTH+8, curr_height);
2466   else
2467     XResizeWindow(disp, XtWindow(toplevel), DEFAULT_REG_WIDTH, curr_height);
2468 #undef MEDIAN
2469 }
2470
2471 static void
2472 redrawACT(Widget w, XEvent *e, String *v, Cardinal *n) {
2473   if (e->xexpose.count == 0) callRedrawTrace(IsTracePlaying());
2474 }
2475
2476 static void
2477 redrawCaptionACT(Widget w, XEvent *e, String *v, Cardinal *n) {
2478   if (e->type == EnterNotify) redrawCaption(True);
2479   else redrawCaption(False);
2480 }
2481
2482 static void
2483 completeDirACT(Widget w, XEvent *e, String *v, Cardinal *n) {
2484   char *p;
2485   DirPath full;
2486   Widget load_dialog_widget = XtParent(w);  /* XtParent = ld->ld_load_d */
2487
2488   p = XawDialogGetValueString(load_dialog_widget);
2489   if (!expandDir(p, &full, basepath)) { /* uses global ld */
2490     ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "something wrong with getting path.");
2491     return;
2492   }
2493   if (full.basename != NULL) {
2494     int lenb, lend, match = 0;
2495     char filename[PATH_MAX], matchstr[PATH_MAX], *path = "/";
2496     char *fullpath;
2497     URL dirp;
2498
2499     lenb = strlen(full.basename);
2500     lend = strlen(full.dirname);
2501     if (lend != 0) path = full.dirname;
2502     if ((dirp = url_dir_open(path)) != NULL) {
2503       MBlockList pool;
2504       struct stat st;
2505       init_mblock(&pool);
2506
2507       while (url_gets(dirp, filename, sizeof(filename)) != NULL) {
2508         if (!strncmp(full.basename, filename, lenb)) {
2509
2510           fullpath = (char *)new_segment(&pool,
2511                             lend + strlen(filename) + 2);
2512           sprintf(fullpath, "%s/%s", full.dirname, filename);
2513
2514           if (stat(fullpath, &st) == -1)
2515             continue;
2516           if (!match)
2517             strlcpy(matchstr, filename, PATH_MAX);
2518           else
2519             strmatch(matchstr, filename);
2520           match++;
2521           if (S_ISDIR(st.st_mode) && (!strcmp(filename, full.basename))) {
2522             lenb = strlcpy(matchstr, filename, PATH_MAX);
2523             if (lenb >= PATH_MAX) lenb = PATH_MAX - 1;
2524             strncat(matchstr, "/", PATH_MAX - 1 - lenb);
2525             match = 1;
2526             break;
2527           }
2528         }
2529       }
2530       url_close(dirp);
2531       reuse_mblock(&pool);
2532
2533       if (match) {
2534 #ifdef CLEARVALUE
2535         clearValue(XtParent(w));
2536 #endif /* CLEARVALUE */
2537         snprintf(filename, sizeof(filename), "%s/%s", full.dirname, matchstr);
2538         XtVaSetValues(load_dialog_widget, XtNvalue,filename, NULL); 
2539       }
2540     }
2541   }
2542 }
2543
2544 static int
2545 readPlaylist(const char *file) {
2546   FILE *Playlist;
2547   char fname[SLINELEN], *pp;
2548   int ret = 1;
2549
2550   if ((Playlist = fopen(file, "r")) == NULL) {
2551      fprintf(stderr, "Can't open %s for reading.\n", file);
2552      return 2;
2553   }
2554   if ((pp = fgets(fname, SLINELEN, Playlist)) == NULL) goto out;
2555   if (memcmp(fname, "\0timidity playlist:\n", 20)) goto out;
2556   while (fgets(fname, SLINELEN, Playlist) != NULL) {
2557     if ((pp = strchr(fname, '\n')) != NULL) *pp = '\0';
2558     a_pipe_write("%c%s", S_ADD_TO_PLAYLIST, fname);
2559   }
2560   ret = 0;
2561 out:
2562   fclose(Playlist);
2563   return ret;
2564 }
2565
2566 static void
2567 savePlaylist(const char *file, int n) {
2568   int i;
2569   FILE *fp;
2570
2571   if (!strcmp(file, dotfile)) {
2572     char prefix[10];
2573
2574     snprintf(prefix, sizeof(prefix), SPREFIX "%s ", cfg_items[S_MidiFile]);
2575     if ((fp = fopen(dotfile, "a")) != NULL) {
2576       for(i=0; i<n; i++) {
2577         a_pipe_read(local_buf, sizeof(local_buf));
2578         if (fprintf(fp,"%s%s\n", prefix, local_buf) < 0) goto error;
2579       }
2580       fclose(fp);
2581     }
2582     else goto error;
2583   } else {
2584     if ((fp = fopen(file, "w")) != NULL) {
2585       if (fputc('\0', fp) == EOF) goto error;
2586       if (fprintf(fp, "timidity playlist:\n") < 0) goto error;
2587       for(i=0; i<n; i++) {
2588         a_pipe_read(local_buf, sizeof(local_buf));
2589         if (fprintf(fp,"%s\n", local_buf) < 0) goto error;
2590       }
2591       fclose(fp);
2592     }
2593     else goto error;
2594   }
2595   return;
2596 error:
2597   if (fp != NULL) fclose(fp);
2598   for(i=0; i<n; i++) a_pipe_read(local_buf, sizeof(local_buf));
2599   warnCB(toplevel, "saveplaylisterror", True);
2600   return;
2601 }
2602
2603 static int
2604 a_readconfig (Config *Cfg, char ***dotfile_flist) {
2605   char s[SLINELEN];
2606   char *p, *pp;
2607   int dot_nfile = 0, k;
2608   struct stat st;
2609   FILE *fp;
2610
2611   if (home != NULL) {
2612     dotfile = (char *)safe_malloc(sizeof(char) * PATH_MAX);
2613     snprintf(dotfile, PATH_MAX, "%s/%s", home, INITIAL_CONFIG);
2614     if ( (fp = fopen(dotfile, "r")) != NULL) {
2615       while ((p = fgets(s, SLINELEN, fp)) != NULL) {
2616         if ((pp = strchr(p, '\n')) != NULL) *pp = '\0';
2617         if (strncasecmp(s, SPREFIX, SPLEN) != 0) continue;
2618         switch (configcmp(s+SPLEN, &k)) {
2619         case S_ConfirmExit:
2620           Cfg->confirmexit = (Boolean)k; break;
2621         case S_RepeatPlay:
2622           Cfg->repeat = (Boolean)k; break;
2623         case S_AutoStart:
2624           Cfg->autostart = (Boolean)k; break;
2625         case S_AutoExit:
2626           Cfg->autoexit = (Boolean)k; break;
2627         case S_DispText:
2628           Cfg->disptext = (Boolean)k;
2629           break;
2630         case S_ShufflePlay:
2631           Cfg->shuffle = (Boolean)k; break;
2632         case S_DispTrace:
2633           Cfg->disptrace = (Boolean)k; break;
2634         case S_CurVol:
2635           Cfg->amplitude = (int)k;
2636           if (Cfg->amplitude > MAXVOLUME) Cfg->amplitude = MAXVOLUME;
2637           else if (Cfg->amplitude < 0) Cfg->amplitude = 0;
2638           break;
2639         case S_ExtOptions:
2640           Cfg->extendopt = (int)k; break;
2641         case S_ChorusOption:
2642           Cfg->chorusopt = (int)k; break;
2643         case S_Tooltips:
2644           Cfg->tooltips = (Boolean)k; break;
2645         case S_Showdotfiles:
2646           Cfg->showdotfiles = (Boolean)k; break;
2647         case S_SaveList:
2648           Cfg->save_list = (Boolean)k; break;
2649         case S_SaveConfig:
2650           Cfg->save_config = (Boolean)k; break;
2651         case S_DefaultDirectory:
2652           p = s+k;
2653           pp = expandDir(p, NULL, "/");
2654           if ((stat(pp, &st) == -1) || (!(S_ISDIR(st.st_mode)))) {
2655             fprintf(stderr, "Default directory %s doesn't exist!\n", p);
2656             Cfg->DefaultDir = NULL;
2657           } else {
2658             Cfg->DefaultDir = safe_strdup(pp);
2659           }
2660           break;
2661         case S_MidiFile:
2662           if (dotfile_flist == NULL) break;
2663           if (*dotfile_flist == NULL)
2664             *dotfile_flist = (char **)safe_malloc(sizeof(char *) *
2665                                                   INIT_FLISTNUM);
2666           p = s+k;
2667           if (dot_nfile < INIT_FLISTNUM) {
2668             (*dotfile_flist)[dot_nfile] = safe_strdup(p);
2669             dot_nfile++;
2670           }
2671           (*dotfile_flist)[dot_nfile] = NULL;
2672           break;
2673         }
2674       }
2675       fclose(fp);
2676       if (Cfg->DefaultDir == NULL) Cfg->DefaultDir = safe_strdup(home);
2677     } else {
2678       Cfg->DefaultDir = safe_strdup(home);
2679       a_saveconfig(dotfile, False);
2680     }
2681   } else {
2682     Cfg->DefaultDir = safe_strdup("/");
2683   }
2684
2685   if (ctl->flags & CTLF_AUTOSTART) Cfg->autostart = True;
2686   if (ctl->flags & CTLF_AUTOEXIT) Cfg->autoexit = True;
2687   if (ctl->flags & CTLF_LIST_LOOP) Cfg->repeat = True;
2688   if (ctl->flags & CTLF_LIST_RANDOM) Cfg->shuffle = True;
2689
2690   return dot_nfile;
2691 }
2692
2693 static void
2694 a_saveconfig(const char *file, Boolean save_list) {
2695   FILE *fp;
2696
2697   if (*file == '\0') return;
2698   if ((fp = fopen(file, "w")) == NULL) {
2699     fprintf(stderr, "cannot open initializing file '%s'.\n", file);
2700     return;
2701   }
2702   fprintf(fp, SPREFIX "%s %d\n", cfg_items[S_RepeatPlay], Cfg.repeat?1:0);
2703   fprintf(fp, SPREFIX "%s %d\n", cfg_items[S_ShufflePlay], Cfg.shuffle?1:0);
2704   fprintf(fp, SPREFIX "%s %d\n", cfg_items[S_ExtOptions], init_options);
2705   fprintf(fp, SPREFIX "%s %d\n", cfg_items[S_ChorusOption], init_chorus);
2706   fprintf(fp, SPREFIX "%s %d\n", cfg_items[S_CurVol], amplitude);
2707   fprintf(fp, SPREFIX "%s %d\n", cfg_items[S_Showdotfiles],
2708           Cfg.showdotfiles?1:0);
2709   fprintf(fp, SPREFIX "%s %s\n", cfg_items[S_DefaultDirectory], Cfg.DefaultDir);
2710   fprintf(fp, SPREFIX "%s %d\n", cfg_items[S_DispTrace], Cfg.disptrace?1:0);
2711   fprintf(fp, SPREFIX "%s %d\n", cfg_items[S_DispText], Cfg.disptext?1:0);
2712   fprintf(fp, SPREFIX "%s %d\n", cfg_items[S_Tooltips], Cfg.tooltips?1:0);
2713   fprintf(fp, SPREFIX "%s %d\n", cfg_items[S_AutoStart], Cfg.autostart?1:0);
2714   fprintf(fp, SPREFIX "%s %d\n", cfg_items[S_AutoExit], Cfg.autoexit?1:0);
2715   fprintf(fp, SPREFIX "%s %d\n", cfg_items[S_ConfirmExit], Cfg.confirmexit?1:0);
2716   fprintf(fp, SPREFIX "%s %d\n", cfg_items[S_SaveList], Cfg.save_list?1:0);
2717   fprintf(fp, SPREFIX "%s %d\n", cfg_items[S_SaveConfig], Cfg.save_config?1:0);
2718   fclose(fp);
2719   if (save_list) {
2720     /* TODO: We're doing this dance via the pipe because no structure
2721      * in xaw_i.c contains full filenames (including paths).
2722      * Changing this would require changing xaw_c.c as well.
2723      */
2724     a_pipe_write("%c%s", S_SAVE_PLAYLIST, dotfile);
2725   }
2726 }
2727
2728 #ifdef OFFIX
2729 static void
2730 FileDropedHandler(Widget widget, XtPointer data, XEvent *event, Boolean *b) {
2731   char *filename;
2732   unsigned char *Data;
2733   unsigned long Size;
2734   char local_buffer[PATH_MAX];
2735   int i;
2736   static const int AcceptType[] = {DndFile, DndFiles, DndDir, DndLink,
2737                                    DndExe, DndURL, DndNotDnd};
2738   int Type;
2739
2740   Type = DndDataType(event);
2741   for(i=0;AcceptType[i] != DndNotDnd;i++) {
2742     if (AcceptType[i] == Type)
2743       goto OK;
2744   }
2745   fprintf(stderr, "NOT ACCEPT\n");
2746   /*Not Acceptable,so Do Nothing*/
2747   return;
2748 OK:
2749   DndGetData(&Data, &Size);
2750   if (Type == DndFiles) {
2751     filename = Data;
2752     while (filename[0] != '\0') {
2753       a_pipe_write("%c%s", S_ADD_TO_PLAYLIST, filename);
2754       filename = filename + strlen(filename) + 1;
2755     }
2756   } else {
2757     a_pipe_write("%c%s%s", S_ADD_TO_PLAYLIST, Data, (Type == DndDir)?"/":"");
2758   }
2759   return;
2760 }
2761 #endif /* OFFIX */
2762
2763 static void
2764 leaveSubmenuACT(Widget w, XEvent *e, String *v, Cardinal *n) {
2765   XLeaveWindowEvent *leave_event = (XLeaveWindowEvent *)e;
2766   Dimension height;
2767
2768   XtVaGetValues(w, XtNheight,&height, NULL);
2769   if ((leave_event->x <= 0) || (leave_event->y <= 0) ||
2770       (leave_event->y >= height))
2771     XtPopdown(w);
2772 }
2773
2774 #ifdef TimNmenu
2775 static void
2776 checkRightAndPopupSubmenuACT(Widget w, XEvent *e, String *v, Cardinal *n) {
2777   XLeaveWindowEvent *leave_ev = (XLeaveWindowEvent *)e;
2778   Dimension nheight, height, width;
2779   Position x, y;
2780   int i;
2781
2782   if (maxentry_on_a_menu == 0) return;
2783
2784   if (e == NULL) i = *(int *)n;
2785   else i = atoi(*v);
2786   if (w != title_sm) {
2787     if ((leave_ev->x <= 0) || (leave_ev->y < 0)) {
2788       XtPopdown(w);
2789       return;
2790     }
2791   } else {
2792     if ((leave_ev->x <= 0) || (leave_ev->y <= 0)) return;
2793   }
2794   if (psmenu[i] == NULL) return;
2795   XtVaGetValues(psmenu[i], XtNheight,&height, NULL);
2796
2797   /* neighbor menu height */
2798   XtVaGetValues((i > 0)? psmenu[i-1]:title_sm, XtNwidth,&width,
2799                          XtNheight,&nheight, XtNx,&x, XtNy,&y, NULL);
2800   if ((leave_ev->x > 0) && (leave_ev->y > nheight - 22)) {
2801     XtVaSetValues(psmenu[i], XtNx,x+80, NULL);
2802     XtPopup(psmenu[i], XtGrabNone);
2803     XtVaGetValues(psmenu[i], XtNheight,&height, NULL);
2804     XtVaSetValues(psmenu[i], XtNy,y +((height)? nheight-height:0), NULL);
2805   }
2806 }
2807
2808 static void
2809 popdownSubmenuCB(Widget w, XtPointer client_data, XtPointer call_data) {
2810   long i = (long)client_data;
2811
2812   if (i < 0) i = submenu_n -1;
2813   while (i >= 0) XtPopdown(psmenu[i--]);
2814 }
2815
2816 static void
2817 popdownSubmenuACT(Widget w, XEvent *e, String *v, Cardinal *n) {
2818   int i = atoi(*v);
2819
2820   while (i >= 0) XtPopdown(psmenu[i--]);
2821 }
2822 #endif /* TimNmenu */
2823
2824 static void
2825 closeParentACT(Widget w, XEvent *e, String *v, Cardinal *n) {
2826   XtPopdown(seekTransientShell(w));
2827 }
2828
2829 static void
2830 flistMoveACT(Widget w, XEvent *e, String *v, Cardinal *n) {
2831   int i = atoi(*v);
2832   XawListReturnStruct *lr;
2833
2834   if (max_files == 0) return;
2835   lr = XawListShowCurrent(file_list);
2836   if (XtIsRealized(popup_file)) {
2837     if ((lr != NULL) && (lr->list_index != XAW_LIST_NONE)) {
2838       Dimension listheight, vportheight;
2839       Widget file_vport = XtParent(file_list);
2840       int perpage;
2841
2842       XtVaGetValues(file_list, XtNheight,&listheight, NULL);
2843       XtVaGetValues(file_vport, XtNheight,&vportheight, NULL);
2844       perpage = ceil((max_files * vportheight) / listheight - 0.5);
2845       if (*(int *)n == 1) {
2846         i += lr->list_index;
2847       } else if (*(int *)n == 2) {
2848         i = lr->list_index + i*perpage;
2849       } else {
2850         if (i > 0) i = max_files-1;
2851         else i = 0;
2852       }
2853       if (i < 0) i = 0;
2854       else if (i >= max_files) i = max_files-1;
2855       if (listheight > vportheight) {
2856         Widget scrollbar; barfloat thumb; int covered;
2857
2858         scrollbar = XtNameToWidget(file_vport, "vertical");
2859         if (scrollbar == NULL) return;
2860         XtVaGetValues(scrollbar, XtNtopOfThumb,&thumb.f, NULL);
2861         covered = thumb.f*max_files;
2862
2863         if ( ((i - 1) < covered) || ((i + 1) > (covered + perpage)) ) {
2864           String arg[1];
2865
2866           if (((i - 1) < covered) && (i <= perpage/2)) thumb.f = 0;
2867           else thumb.f = (float)(i - perpage/2) / (float)max_files;
2868           arg[0] = XtNewString("Continuous");
2869           XtCallActionProc(scrollbar, (String)"StartScroll", e, arg, ONE);
2870           XtFree(arg[0]);
2871           setThumb(scrollbar, thumb);
2872           XtCallActionProc(scrollbar, (String)"NotifyThumb", e, NULL, ZERO);
2873           XtCallActionProc(scrollbar, (String)"EndScroll", e, NULL, ZERO);
2874         }
2875       }
2876       XawListHighlight(file_list, i);
2877     } else {
2878 /* should never be reached */
2879       XawListHighlight(file_list, (i<0)?max_files-1:0);
2880     }
2881   }
2882 }
2883
2884 static void
2885 addFlist(const char *fname, long current_n) {
2886   if (max_num < current_n+1) {
2887     max_num += 64;
2888     flist = (String *)safe_realloc(flist, (max_num+1)*sizeof(String));
2889   }
2890   free(flist[current_n]);
2891   flist[current_n] = safe_strdup(fname);
2892   flist[current_n+1] = NULL;
2893 }
2894
2895 static void
2896 addOneFile(int max_files, long curr_num, const char *fname) {
2897   static Dimension tmpi;
2898   static int menu_height;
2899   static Widget tmpw;
2900   static int jjj;
2901   Widget pbox;
2902   char sbuf[256];
2903
2904   if (curr_num == 0) {
2905     jjj = 0; tmpi = 0; menu_height = 0; tmpw = title_sm;
2906   }
2907   if (menu_height + tmpi*2 > root_height) {
2908     if (maxentry_on_a_menu == 0) {
2909       jjj = curr_num;
2910       maxentry_on_a_menu = jjj;
2911 #ifdef TimNmenu
2912       XtAddCallback(title_sm, XtNpopdownCallback,popdownSubmenuCB,
2913                          (XtPointer)(submenu_n -1));
2914 #endif
2915     }
2916     if (jjj >= maxentry_on_a_menu) {
2917       if (!psmenu) {
2918         psmenu = (Widget *)safe_malloc(sizeof(Widget)
2919                               * ((int)(max_files / curr_num) + 2));
2920 #ifndef TimNmenu
2921        sb = (String *)safe_malloc(sizeof(String));
2922 #endif
2923       } else {
2924         psmenu = (Widget *)safe_realloc((char *)psmenu,
2925                     sizeof(Widget)*(submenu_n + 2));
2926 #ifndef TimNmenu
2927         sb = (String *)safe_realloc(sb, sizeof(String)*(submenu_n + 2));
2928 #endif
2929       }
2930       snprintf(sbuf, sizeof(sbuf), "morebox%ld", submenu_n);
2931       pbox = XtVaCreateManagedWidget(sbuf,smeBSBObjectClass,tmpw,
2932                XtNlabel,app_resources.more_text,
2933                XtNbackground,textbgcolor, XtNforeground,capcolor,
2934                XtNrightBitmap,arrow_mark,
2935                XtNfontSet,app_resources.label_font, NULL);
2936
2937       snprintf(sbuf, sizeof(sbuf), "psmenu%ld", submenu_n);
2938       psmenu[submenu_n] = XtVaCreatePopupShell(sbuf,simpleMenuWidgetClass,
2939                                  title_sm, XtNforeground,textcolor,
2940                                  XtNbackingStore,NotUseful, XtNsaveUnder,False,
2941                                  XtNwidth,app_resources.menu_width,
2942                                  XtNbackground,textbgcolor, NULL);
2943 #ifndef TimNmenu
2944       sb[submenu_n] = safe_strdup(sbuf);
2945       XtVaSetValues(pbox, XtNmenuName,sb[submenu_n], NULL);
2946 #else
2947       snprintf(sbuf, sizeof(sbuf),
2948               "<LeaveWindow>: unhighlight() \
2949                   checkRightAndPopupSubmenu(%ld)", submenu_n);
2950       XtOverrideTranslations(tmpw, XtParseTranslationTable(sbuf));
2951       snprintf(sbuf, sizeof(sbuf), "<BtnUp>: popdownSubmenu(%ld) \
2952                                       notify() unhighlight()\n\
2953         <EnterWindow>: unhighlight()\n\
2954         <LeaveWindow>: leaveSubmenu(%ld) unhighlight()", submenu_n, submenu_n);
2955       XtOverrideTranslations(psmenu[submenu_n], XtParseTranslationTable(sbuf));
2956 #endif /* !TimNmenu */
2957       tmpw = psmenu[submenu_n++]; psmenu[submenu_n] = NULL;
2958       jjj = 0;
2959     }
2960   }
2961   if (maxentry_on_a_menu != 0) jjj++;
2962   bsb = XtVaCreateManagedWidget(fname,smeBSBObjectClass,tmpw, NULL);
2963   XtAddCallback(bsb, XtNcallback,menuCB, (XtPointer)curr_num);
2964   XtVaGetValues(bsb, XtNheight,&tmpi, NULL);
2965   if (maxentry_on_a_menu == 0) menu_height += tmpi;
2966   else psmenu[submenu_n] = NULL;
2967 }
2968
2969 static void
2970 createOptions(void) {
2971   Widget modul_b, modul_bb, porta_b, porta_bb, nrpnv_b,
2972          nrpnv_bb, reverb_b, reverb_bb, chorus_bb,
2973          chpressure_b, chpressure_bb, overlapv_b, overlapv_bb,
2974          txtmeta_b, txtmeta_bb,
2975          popup_optform, lowBox, popup_olabel, popup_ook, popup_ocancel;
2976   Dimension x, y;
2977
2978   popup_opt = XtVaCreatePopupShell("popup_option",transientShellWidgetClass,
2979                        toplevel, NULL);
2980   XtVaGetValues(toplevel, XtNx,&x, XtNy,&y, NULL);
2981   XtVaSetValues(popup_opt, XtNx,x+DEFAULT_REG_WIDTH, XtNy,y, NULL);
2982
2983   popup_optform = XtVaCreateManagedWidget("popup_optform",formWidgetClass,
2984                        popup_opt, XtNorientation,XtorientVertical,
2985                        XtNbackground,bgcolor, NULL);
2986   modul_bb = XtVaCreateManagedWidget("modul_box",boxWidgetClass,popup_optform,
2987                        XtNbackground,bgcolor,
2988                        XtNorientation,XtorientHorizontal, NULL);
2989   modul_b = XtVaCreateManagedWidget("modul_button",toggleWidgetClass,modul_bb,
2990                        XtNbitmap,off_mark, XtNforeground,togglecolor,
2991                        XtNbackground,buttonbgcolor, NULL);
2992   XtVaCreateManagedWidget("modul_lbl",labelWidgetClass,modul_bb,
2993                        XtNforeground,textcolor, XtNbackground,bgcolor, NULL);
2994   porta_bb = XtVaCreateManagedWidget("porta_box",boxWidgetClass,popup_optform,
2995                        XtNfromVert,modul_bb, 
2996                        XtNorientation,XtorientHorizontal,
2997                        XtNbackground,bgcolor, NULL);
2998   porta_b = XtVaCreateManagedWidget("porta_button",toggleWidgetClass,porta_bb,
2999                        XtNforeground,togglecolor, XtNbackground,buttonbgcolor,
3000                        XtNbitmap,off_mark, XtNfromVert,modul_b, NULL);
3001   XtVaCreateManagedWidget("porta_lbl",labelWidgetClass,porta_bb,
3002                        XtNforeground,textcolor, XtNbackground,bgcolor, NULL);
3003   nrpnv_bb = XtVaCreateManagedWidget("nrpnv_box",boxWidgetClass,popup_optform,
3004                        XtNfromVert,porta_bb, 
3005                        XtNorientation,XtorientHorizontal,
3006                        XtNbackground,bgcolor, NULL);
3007   nrpnv_b = XtVaCreateManagedWidget("nrpnv_button",toggleWidgetClass,nrpnv_bb,
3008                        XtNforeground,togglecolor, XtNbackground,buttonbgcolor,
3009                        XtNbitmap,off_mark, XtNfromVert,porta_b, NULL);
3010   XtVaCreateManagedWidget("nrpnv_lbl",labelWidgetClass,nrpnv_bb,
3011                        XtNforeground,textcolor, XtNbackground,bgcolor, NULL);
3012   reverb_bb = XtVaCreateManagedWidget("reverb_box",boxWidgetClass,
3013                        popup_optform, XtNfromVert,nrpnv_bb,
3014                        XtNorientation,XtorientHorizontal,
3015                        XtNbackground,bgcolor, NULL);
3016   reverb_b = XtVaCreateManagedWidget("reverb_button",toggleWidgetClass,
3017                        reverb_bb, XtNbitmap,off_mark, XtNfromVert,nrpnv_b,
3018                        XtNforeground,togglecolor, XtNbackground,buttonbgcolor,
3019                        NULL);
3020   XtVaCreateManagedWidget("reverb_lbl",labelWidgetClass,reverb_bb,
3021                        XtNforeground,textcolor, XtNbackground,bgcolor, NULL);
3022   chorus_bb = XtVaCreateManagedWidget("chorus_box",boxWidgetClass,
3023                        popup_optform, XtNorientation,XtorientHorizontal,
3024                        XtNfromVert,reverb_bb, 
3025                        XtNbackground,bgcolor, NULL);
3026   chorus_b = XtVaCreateManagedWidget("chorus_button",toggleWidgetClass,
3027                        chorus_bb, XtNbitmap,off_mark, XtNfromVert,reverb_b,
3028                        XtNforeground,togglecolor, XtNbackground,buttonbgcolor,
3029                        NULL);
3030   XtVaCreateManagedWidget("chorus_lbl",labelWidgetClass,chorus_bb,
3031                        XtNforeground,textcolor, XtNbackground,bgcolor, NULL);
3032   chpressure_bb = XtVaCreateManagedWidget("chpressure_box",boxWidgetClass,
3033                        popup_optform, XtNorientation,XtorientHorizontal,
3034                        XtNfromVert,chorus_bb, 
3035                        XtNbackground,bgcolor, NULL);
3036   chpressure_b = XtVaCreateManagedWidget("chpressure_button",
3037                        toggleWidgetClass,chpressure_bb, XtNbitmap,off_mark,
3038                        XtNfromVert,chorus_b, XtNforeground,togglecolor,
3039                        XtNbackground,buttonbgcolor, NULL);
3040   XtVaCreateManagedWidget("chpressure_lbl",labelWidgetClass,
3041                        chpressure_bb, XtNforeground,textcolor,
3042                        XtNbackground,bgcolor, NULL);
3043   overlapv_bb = XtVaCreateManagedWidget("overlapvoice_box",boxWidgetClass,
3044                        popup_optform, XtNorientation,XtorientHorizontal,
3045                        XtNfromVert,chpressure_bb, 
3046                        XtNbackground,bgcolor, NULL);
3047   overlapv_b = XtVaCreateManagedWidget("overlapvoice_button",
3048                        toggleWidgetClass,overlapv_bb, XtNbitmap,off_mark, 
3049                        XtNfromVert,chpressure_b, XtNforeground,togglecolor,
3050                        XtNbackground,buttonbgcolor, NULL);
3051   XtVaCreateManagedWidget("overlapv_lbl",labelWidgetClass,
3052                        overlapv_bb, XtNforeground,textcolor,
3053                        XtNbackground,bgcolor, NULL);
3054   txtmeta_bb = XtVaCreateManagedWidget("txtmeta_box",boxWidgetClass,
3055                        popup_optform, XtNorientation,XtorientHorizontal,
3056                        XtNfromVert,overlapv_bb, 
3057                        XtNbackground,bgcolor, NULL);
3058   txtmeta_b = XtVaCreateManagedWidget("txtmeta_button",toggleWidgetClass,
3059                        txtmeta_bb, XtNbitmap,off_mark, XtNfromVert,overlapv_b,
3060                        XtNforeground,togglecolor, XtNbackground,buttonbgcolor,
3061                        NULL);
3062   XtVaCreateManagedWidget("txtmeta_lbl",labelWidgetClass,
3063                        txtmeta_bb, XtNforeground,textcolor,
3064                        XtNbackground,bgcolor, NULL);
3065
3066
3067   popup_olabel = XtVaCreateManagedWidget("popup_olabel",labelWidgetClass,
3068             popup_optform, XtNbackground,menubcolor, XtNfromVert,txtmeta_bb,
3069             NULL);
3070   lowBox = createOutputSelectionWidgets(popup_opt, popup_optform,
3071                                         popup_olabel, play, True);
3072
3073   popup_ook = XtVaCreateManagedWidget("closebutton",commandWidgetClass,
3074                                       popup_optform, XtNfromVert,lowBox,
3075                                       XtNwidth,80, NULL);
3076   popup_ocancel = XtVaCreateManagedWidget("Cancel",commandWidgetClass,
3077                                           popup_optform, XtNfromVert,lowBox,
3078                                           XtNfromHoriz,popup_ook, XtNwidth,80,
3079                                           NULL);
3080   XtAddCallback(popup_ook, XtNcallback,optionscloseCB, NULL);
3081   XtAddCallback(popup_ocancel, XtNcallback,closeWidgetCB, (XtPointer)popup_opt);
3082   XtAddCallback(modul_b, XtNcallback,optionsCB, NULL);
3083   XtAddCallback(porta_b, XtNcallback,optionsCB, NULL);
3084   XtAddCallback(nrpnv_b, XtNcallback,optionsCB, NULL);
3085   XtAddCallback(reverb_b, XtNcallback,optionsCB, NULL);
3086   XtAddCallback(chpressure_b, XtNcallback,optionsCB, NULL);
3087   XtAddCallback(overlapv_b, XtNcallback,optionsCB, NULL);
3088   XtAddCallback(txtmeta_b, XtNcallback,optionsCB, NULL);
3089   XtAddCallback(chorus_b, XtNcallback,optionsCB, NULL);
3090   option_num[MODUL_N].widget = modul_b;
3091   option_num[PORTA_N].widget = porta_b;
3092   option_num[NRPNV_N].widget = nrpnv_b;
3093   option_num[REVERB_N].widget = reverb_b;
3094   option_num[CHPRESSURE_N].widget = chpressure_b;
3095   option_num[OVERLAPV_N].widget = overlapv_b;
3096   option_num[TXTMETA_N].widget = txtmeta_b;
3097   XtSetKeyboardFocus(popup_opt, popup_optform);
3098   if (init_options != 0) {
3099     int i;
3100
3101     for(i=0; i<MAX_OPTION_N; i++) {
3102       if (init_options & option_num[i].bit)
3103         XtVaSetValues(option_num[i].widget, XtNstate,True,
3104                       XtNbitmap,on_mark, NULL);
3105     }
3106   }
3107   if (init_chorus != 0)
3108     XtVaSetValues(chorus_b, XtNstate,True, XtNbitmap,on_mark, NULL);
3109 }
3110
3111 static void
3112 fselectCB(Widget w, XtPointer client_data, XtPointer call_data) {
3113   XawListReturnStruct *lr = XawListShowCurrent(file_list);
3114
3115   if ((lr != NULL) && (lr->list_index != XAW_LIST_NONE)) {
3116     onPlayOffPause();
3117     a_pipe_write("%c%d", S_PLAY_FILE, lr->list_index + 1);
3118   }
3119 }
3120
3121 static void
3122 fdeleteCB(Widget w, XtPointer client_data, XtPointer call_data) {
3123   XawListReturnStruct *lr = XawListShowCurrent(file_list);
3124   int n; long i;
3125   const char *p;
3126
3127   if ((lr == NULL) || (lr->list_index == XAW_LIST_NONE)) return;
3128   if (max_files == 1) {
3129     fdelallCB(w, NULL, NULL);
3130     return;
3131   }
3132   n = lr->list_index;
3133   if (n+1 < current_n_displayed) current_n_displayed--;
3134   else if (n+1 == current_n_displayed) {
3135     stopCB(w, NULL, NULL);
3136     XtVaSetValues(tune_l, XtNlabel,"/ 00:00", NULL);
3137     if (n+1<max_files) p = strchr(flist[n+1], ' ');
3138     else {
3139       p = strchr(flist[n-1], ' ');
3140       current_n_displayed--;
3141     }
3142     if (p != NULL) XtVaSetValues(title_mb, XtNlabel,p+1, NULL);
3143     else fprintf(stderr, "No space character in flist!\n"); 
3144          /* Should never happen */
3145   }
3146   a_pipe_write("%c%d", S_DEL_FROM_PLAYLIST, n);
3147   --max_files;
3148   free(flist[n]);
3149   for(i=n; i<max_files; i++) {
3150     p = strchr(flist[i+1], '.');
3151     snprintf(flist[i+1], strlen(flist[i+1])+1, "%ld%s", i+1, p);
3152     flist[i] = flist[i+1];
3153   }
3154   flist[max_files] = NULL;
3155   if (XtIsRealized(popup_file)) {
3156     XawListChange(file_list, flist, max_files, 0, True);
3157     if (n >= max_files) --n;
3158     XawListHighlight(file_list, n);
3159   }
3160   if (psmenu != NULL) { 
3161     free(psmenu);
3162     psmenu = NULL;
3163 #ifndef TimNmenu
3164     if (sb != NULL) {
3165       free(sb);
3166       sb = NULL;
3167     }
3168 #endif /* !TimNmenu */
3169   }
3170   XtDestroyWidget(title_sm);
3171   maxentry_on_a_menu = 0;
3172   submenu_n = 0;
3173   title_sm = XtVaCreatePopupShell("title_simplemenu",simpleMenuWidgetClass,
3174                                 title_mb, XtNforeground,textcolor,
3175                                 XtNbackground,textbgcolor, XtNsaveUnder,False,
3176                                 XtNbackingStore,NotUseful, NULL);
3177   for(i=0; i<max_files; i++)
3178     addOneFile(max_files, i, flist[i]);
3179 }
3180
3181 static void
3182 fdelallCB(Widget w, XtPointer client_data, XtPointer call_data) {
3183   int i; char lbuf[50];
3184
3185   stopCB(w, NULL, NULL);
3186   a_pipe_write("%c", S_DEL_CUR_PLAYLIST);
3187   for(i=1; i<max_files; i++) free(flist[i]);
3188   /* We keep a single member in flist. Otherwise, Xaw will display the
3189    * widget's name as a member, also letting the user "delete" it (with a
3190    * crash to follow).
3191    */
3192   max_files = 0;
3193   current_n_displayed = 0;
3194   if (*flist == NULL) *flist = (String)safe_malloc(sizeof(char *));
3195   **flist = '\0';
3196   if (XtIsRealized(popup_file))
3197     XawListChange(file_list, flist, max_files?max_files:1, 0, True);
3198   XtVaSetValues(file_menu[ID_SAVE - 100].widget, XtNsensitive,False, NULL);
3199   if (psmenu != NULL) {
3200     free(psmenu);
3201     psmenu = NULL;
3202 #ifndef TimNmenu
3203     if (sb != NULL) {
3204       free(sb);
3205       sb = NULL;
3206     }
3207 #endif /* !TimNmenu */
3208   }
3209   XtDestroyWidget(title_sm);
3210   maxentry_on_a_menu = 0; submenu_n = 0;
3211   title_sm = XtVaCreatePopupShell("title_simplemenu",simpleMenuWidgetClass,
3212                                 title_mb, XtNforeground,textcolor,
3213                                 XtNbackground,textbgcolor, XtNsaveUnder,False,
3214                                 XtNbackingStore,NotUseful, NULL);
3215   bsb = XtVaCreateManagedWidget("dummyfile",smeLineObjectClass,title_sm, NULL);
3216   snprintf(lbuf, sizeof(lbuf), "TiMidity++ %s", timidity_version);
3217   XtVaSetValues(title_mb, XtNlabel,lbuf, NULL);
3218   snprintf(window_title, sizeof(window_title), "%s : %s",
3219            APP_CLASS, app_resources.no_playing);
3220   XtVaSetValues(toplevel, XtNtitle,window_title, NULL);
3221   XtVaSetValues(tune_l, XtNlabel,"/ ----", NULL);
3222 #ifndef WIDGET_IS_LABEL_WIDGET
3223   deleteTextACT(w, NULL, NULL, NULL);
3224 #endif
3225 }
3226
3227 static void
3228 backspaceACT(Widget w, XEvent *e, String *v, Cardinal *n) {
3229   XawTextPosition begin, end;
3230   XawTextBlock tb;
3231
3232   XawTextGetSelectionPos(w, &begin, &end);
3233   if (begin == end) return;
3234   tb.firstPos = 0;
3235   tb.ptr = ".";
3236   tb.format = XawFmt8Bit;
3237   tb.length = strlen(tb.ptr);
3238   XawTextReplace(w, begin, end, &tb);
3239   XawTextSetInsertionPoint(w, begin+1);
3240 }
3241
3242 #ifndef WIDGET_IS_LABEL_WIDGET
3243 static void
3244 deleteTextACT(Widget w, XEvent *e, String *v, Cardinal *n) {
3245 #ifdef CLEARVALUE
3246   Widget TextSrc;
3247
3248   XtVaGetValues(lyric_t, XtNtextSource,&TextSrc, NULL); 
3249   XawAsciiSourceFreeString(TextSrc);
3250 #endif /* CLEARVALUE */
3251   XtVaSetValues(lyric_t, XtNstring,(String)"<< TiMidity Messages >>\n", NULL);
3252 }
3253 #endif
3254
3255 static void
3256 scrollTextACT(Widget w, XEvent *e, String *v, Cardinal *n) {
3257   int i, l = atoi(*v);
3258
3259   for (i=0; i<l; i++)
3260     XtCallActionProc(lyric_t, "scroll-one-line-up", NULL, NULL, ZERO);
3261   for (i=0; i>l; i--)
3262     XtCallActionProc(lyric_t, "scroll-one-line-down", NULL, NULL, ZERO);
3263 }
3264
3265 static void
3266 createFlist(void) {
3267
3268   if (popup_file == NULL) {
3269     Widget popup_fform, flist_cmdbox, popup_fplay, popup_fdelete,
3270            popup_fdelall, popup_fclose;
3271
3272     popup_file = XtVaCreatePopupShell("popup_file",transientShellWidgetClass,
3273                     toplevel, NULL);
3274     popup_fform = XtVaCreateManagedWidget("popup_fform",formWidgetClass,
3275                     popup_file, XtNbackground,bgcolor,
3276                     XtNorientation,XtorientVertical, NULL);
3277     file_vport = XtVaCreateManagedWidget("file_vport",viewportWidgetClass,
3278                     popup_fform, XtNallowHoriz,True, XtNallowVert,True,
3279                     XtNleft,XawChainLeft, XtNright,XawChainRight,
3280                     XtNbottom,XawChainBottom, XtNbackground,textbgcolor, NULL);
3281     file_list = XtVaCreateManagedWidget("filelist",listWidgetClass,file_vport,
3282                     XtNbackground,textbgcolor, XtNverticalList,True,
3283                     XtNdefaultColumns,1, XtNforceColumns,True, NULL);
3284     flist_cmdbox = XtVaCreateManagedWidget("flist_cmdbox",boxWidgetClass,
3285                     popup_fform, XtNfromVert,file_vport, XtNright,XawChainLeft,
3286                     XtNbottom,XawChainBottom, XtNtop,XawChainBottom,
3287                     XtNorientation,XtorientHorizontal, XtNbackground,bgcolor,
3288                     NULL);
3289     popup_fplay = XtVaCreateManagedWidget("fplaybutton",commandWidgetClass,
3290                     flist_cmdbox, XtNfontSet,app_resources.volume_font, NULL);
3291     popup_fdelete = XtVaCreateManagedWidget("fdeletebutton",commandWidgetClass,
3292                     flist_cmdbox, XtNfontSet,app_resources.volume_font, NULL);
3293     popup_fdelall = XtVaCreateManagedWidget("fdelallbutton",commandWidgetClass,
3294                     flist_cmdbox, XtNfontSet,app_resources.volume_font, NULL);
3295     popup_fclose = XtVaCreateManagedWidget("closebutton",commandWidgetClass,
3296                     flist_cmdbox, XtNfontSet,app_resources.volume_font, NULL);
3297     XtAddCallback(popup_fclose, XtNcallback,closeWidgetCB,
3298                   (XtPointer)popup_file);
3299     XtAddCallback(popup_fplay, XtNcallback,fselectCB, NULL);
3300     XtAddCallback(popup_fdelete, XtNcallback,fdeleteCB, NULL);
3301     XtAddCallback(popup_fdelall, XtNcallback,fdelallCB, NULL);
3302     XtSetKeyboardFocus(popup_file, popup_fform);
3303 #ifdef XawTraversal
3304     XtSetKeyboardFocus(file_list, popup_fform);
3305 #endif /* XawTraversal */
3306     XawListChange(file_list, flist, 0, 0, True);
3307     if (max_files != 0) XawListHighlight(file_list, 0);
3308   }
3309 }
3310
3311 #ifdef XDND
3312 static void
3313 xdnd_file_drop_handler(const char *filename) {
3314   char local_buffer[PIPE_LENGTH];
3315   const char *fp;
3316   struct stat st;
3317
3318   fp = filename;
3319   if (!strncmp(fp, "file:", 5)) {
3320     fp += 5;
3321     if (!strncmp(fp, "//", 2)) {
3322       fp += 2;
3323       if (*fp == '\0') return; /* path given was file :// */
3324       if (*fp != '/') {
3325         if (!strncmp(fp, "localhost/", 10)) {
3326           fp += 10;
3327         } else return;
3328        /*
3329         * This is either a remote URL (which we don't support)
3330         * or a malformed file://text URL
3331         */
3332       }
3333     }
3334   }
3335
3336   if ((*fp == '~') && ((*(fp+1) == '/') || (*(fp+1) == '\0'))) {
3337     if (home == NULL) return;
3338     fp++;
3339     snprintf(local_buffer, sizeof(local_buffer), "%c%s%s",
3340              S_ADD_TO_PLAYLIST, home, fp);
3341   }
3342   else if ( (*fp == '/') && (*(fp+1) == '~') &&
3343             ((*(fp+2) == '/') || (*(fp+2) == '\0')) ) {
3344     if (home == NULL) return;
3345     fp += 2;
3346     snprintf(local_buffer, sizeof(local_buffer), "%c%s%s",
3347              S_ADD_TO_PLAYLIST, home, fp);
3348   }
3349   else
3350     snprintf(local_buffer, sizeof(local_buffer), "%c%s",
3351              S_ADD_TO_PLAYLIST, fp);
3352
3353   if (stat(local_buffer + 1, &st) == -1) return;
3354   if (S_ISDIR(st.st_mode))
3355      strlcat(local_buffer, "/", sizeof(local_buffer));
3356   a_pipe_write("%s", local_buffer);
3357 }
3358
3359 static void
3360 a_dnd_init(void) {
3361   init_dnd(disp, dnd);
3362   enable_dnd_for_widget(dnd, toplevel, xdnd_file_drop_handler);
3363 }
3364
3365 static void
3366 enable_dnd_for_widget(DndClass *dnd, Widget widget, dnd_callback_t cb) {
3367   make_window_dnd_aware(dnd, XtWindow(widget), cb);
3368   XtAddEventHandler(widget, ClientMessage, True, 
3369                      xdnd_listener, (XtPointer)dnd);
3370   XtAddEventHandler(widget, SelectionNotify, True, 
3371                      xdnd_listener, (XtPointer)dnd);
3372 }
3373
3374 static void
3375 xdnd_listener(Widget w, XtPointer client_data, XEvent *ev, Boolean *dummy) {
3376   DndClass *dnd = (DndClass *)client_data;
3377   dnd->win = XtWindow(w);
3378   process_client_dnd_message(dnd, ev); 
3379 }
3380 #endif /* XDND */
3381
3382 static void
3383 destroyWidgetCB(Widget w, XtPointer client_data, XtPointer call_data) {
3384   w = (Widget)client_data;
3385   if (XtIsRealized(XtParent(w))) {
3386     XWindowAttributes war;
3387     Window win;
3388
3389     win = XtWindow(XtParent(w));
3390     XGetWindowAttributes(disp, win, &war);
3391     if (war.map_state == IsViewable)
3392       XSetInputFocus(disp, win, RevertToParent, CurrentTime);
3393   }
3394 #ifdef RECFMTGROUPDESTHACK
3395   if (seekTransientShell(record->formatGroup) == w) {
3396     XtDestroyWidget(XtParent(XtParent(record->formatGroup)));
3397     record->formatGroup = NULL;
3398   }
3399 #endif /* RECFMTGROUPDESTHACK */
3400   XtDestroyWidget(w);
3401 }
3402
3403 static void
3404 setupWindow(Widget w, String action, Boolean xdnd,
3405             Boolean destroyWidgetOnPopdown) {
3406   char s[255];
3407
3408   snprintf(s, sizeof(s), "<Message>WM_PROTOCOLS: %s", action);
3409   XtOverrideTranslations(w, XtParseTranslationTable(s));
3410   if (destroyWidgetOnPopdown == True)
3411     XtAddCallback(w, XtNpopdownCallback,destroyWidgetCB, (XtPointer)w);
3412   XtPopup(w, XtGrabNone);
3413   XSetWMProtocols(disp, XtWindow(w), &wm_delete_window, 1);
3414   XChangeProperty(disp, XtWindow(w), net_wm_pid, XA_CARDINAL, 32,
3415                     PropModeReplace, (unsigned char *)&pid, 1);
3416   /* The WM spec requires setting up WM_CLIENT_MACHINE along with
3417    * _NET_WM_PID. Xt sets it up automatically for us.
3418    */
3419 #ifdef XDND
3420   if (xdnd == True) enable_dnd_for_widget(dnd, w, xdnd_file_drop_handler);
3421 #endif /* XDND */
3422 }
3423
3424 static void
3425 callRedrawTrace(Boolean draw) {
3426   if ((ctl->trace_playing) && (XtIsRealized(trace))) redrawTrace(draw);
3427 }
3428
3429 static void
3430 createTraceWidgets(void) {
3431
3432   if ((app_resources.tracecfg.trace_height > TRACE_HEIGHT_WITH_FOOTER) ||
3433       (app_resources.tracecfg.trace_height < BAR_SPACE+TRACE_FOOT+TRACE_HEADER))
3434     trace_v_height = TRACE_HEIGHT_WITH_FOOTER;
3435   else
3436     trace_v_height = app_resources.tracecfg.trace_height;
3437   trace_vport = XtVaCreateManagedWidget("trace_vport",viewportWidgetClass,
3438           base_f, XtNbottom,XawChainBottom, XtNtop,XawChainTop,
3439           XtNleft,XawChainLeft, XtNright,XawChainLeft,
3440           XtNfromVert,(XtIsManaged(lyric_t))?lyric_t:t_box,
3441           XtNallowHoriz,True, XtNallowVert,True,
3442           XtNwidth,TRACE_WIDTH+8, XtNheight,trace_v_height, NULL);
3443   trace = XtVaCreateManagedWidget("trace",widgetClass,trace_vport,
3444           XtNheight,app_resources.tracecfg.trace_height,
3445           XtNwidth,app_resources.tracecfg.trace_width, NULL);
3446   Cfg.disptrace = True;
3447
3448   XtSetKeyboardFocus(trace, base_f);
3449
3450   fast_b = XtVaCreateManagedWidget("fast_button",commandWidgetClass,b_box,
3451               XtNforeground,togglecolor, XtNbackground,buttonbgcolor,
3452               XtNbitmap,GET_BITMAP(fast), XtNfromHoriz,repeat_b, NULL);
3453   slow_b = XtVaCreateManagedWidget("slow_button",commandWidgetClass,b_box,
3454                 XtNforeground,togglecolor, XtNbackground,buttonbgcolor,
3455                 XtNbitmap,GET_BITMAP(slow), XtNfromHoriz,fast_b, NULL);
3456   keyup_b = XtVaCreateManagedWidget("keyup_button",commandWidgetClass,b_box,
3457               XtNforeground,togglecolor, XtNbackground,buttonbgcolor,
3458               XtNbitmap,GET_BITMAP(keyup), XtNfromHoriz,slow_b, NULL);
3459   keydown_b = XtVaCreateManagedWidget("keydown_button",commandWidgetClass,b_box,
3460                 XtNforeground,togglecolor, XtNbackground,buttonbgcolor,
3461                 XtNbitmap,GET_BITMAP(keydown), XtNfromHoriz,keyup_b, NULL);
3462
3463   XtAddCallback(fast_b, XtNcallback,tempoCB, (XtPointer)TRUE);
3464   XtAddCallback(slow_b, XtNcallback,tempoCB, (XtPointer)FALSE);
3465   XtAddCallback(keyup_b, XtNcallback,pitchCB, (XtPointer)TRUE);
3466   XtAddCallback(keydown_b, XtNcallback,pitchCB, (XtPointer)FALSE);
3467
3468 #ifndef XawTraversal
3469   XtSetKeyboardFocus(fast_b, base_f);
3470   XtSetKeyboardFocus(slow_b, base_f);
3471   XtSetKeyboardFocus(keyup_b, base_f);
3472   XtSetKeyboardFocus(keydown_b, base_f);
3473 #endif /* !XawTraversal */
3474 }
3475
3476 static void
3477 callInitTrace(void) {
3478   initTrace(disp, XtWindow(trace), window_title, &(app_resources.tracecfg));
3479 }
3480
3481 static void
3482 createBars(void) {
3483   int i, j, k, l, vol_hd, tune_hd;
3484 #ifdef SCROLLBARLENGTHBUG
3485   int m, m2;
3486 #endif /* !SCROLLBARLENGTHBUG */
3487   barfloat thumb;
3488
3489   Cardinal num_actions;
3490   XtActionList action_list;
3491   Widget vol_l0;
3492   static XtActionsRec startscroll_act[] = {
3493     {"StartScroll", StartScrollACT}
3494   };
3495
3496   v_box = XtVaCreateManagedWidget("volume_box",formWidgetClass,base_f,
3497             XtNorientation,XtorientHorizontal, XtNheight,36,
3498             XtNtop,XawChainTop, XtNbottom,XawChainTop,
3499             XtNleft,XawChainLeft, XtNright,XawChainLeft,
3500             XtNfromVert,b_box, XtNbackground,bgcolor, NULL);
3501   t_box = XtVaCreateManagedWidget("tune_box",formWidgetClass,base_f,
3502             XtNorientation,XtorientHorizontal,
3503             XtNtop,XawChainTop, XtNbottom,XawChainTop,
3504             XtNleft,XawChainLeft, XtNright,XawChainLeft,
3505             XtNheight,36, XtNfromVert,v_box, XtNbackground,bgcolor, NULL);
3506   i = XmbTextEscapement(app_resources.volume_font, "Volume ", 7)+8;
3507   j = snprintf(local_buf, sizeof(local_buf), "%3d  ", amplitude);
3508   j = XmbTextEscapement(app_resources.volume_font, local_buf, j)+8;
3509   k = XmbTextEscapement(app_resources.volume_font, " 0:00", 5)+8;
3510   l = XmbTextEscapement(app_resources.volume_font, "/ 00:00", 7)+8;
3511   if (k+l > i+j) {
3512     vol_hd = k+l-i-j;
3513     tune_hd = 0;
3514   } else {
3515     tune_hd = i+j-k-l;
3516     vol_hd = 0;
3517   }
3518   vol_l0 = XtVaCreateManagedWidget("volume_label0",labelWidgetClass,v_box,
3519             XtNwidth,i, XtNfontSet,app_resources.volume_font,
3520             XtNlabel,"Volume", XtNborderWidth,0, XtNforeground,textcolor,
3521             XtNleft,XawChainLeft, XtNright,XawChainLeft,
3522             XtNbackground,bgcolor, NULL);
3523   vol_l = XtVaCreateManagedWidget("volume_label",labelWidgetClass,v_box,
3524             XtNwidth,j, XtNborderWidth,0, XtNfromHoriz,vol_l0,
3525             XtNfontSet,app_resources.volume_font,
3526             XtNorientation,XtorientHorizontal, XtNforeground,textcolor,
3527             XtNleft,XawChainLeft, XtNright,XawChainLeft,
3528             XtNbackground,bgcolor, XtNlabel,local_buf, NULL);
3529   /* VOLUME_LABEL_WIDTH = i+30+j */
3530   vol_bar = XtVaCreateManagedWidget("volume_bar",scrollbarWidgetClass,v_box,
3531             XtNorientation,XtorientHorizontal, XtNfromHoriz,vol_l,
3532             XtNwidth,DEFAULT_REG_WIDTH - (i+30+j+vol_hd),
3533             XtNhorizDistance,vol_hd,
3534             XtNleft,XawChainLeft, XtNright,XawChainLeft,
3535             XtNbackground,textbgcolor, NULL);
3536   thumb.f = (float)amplitude / (float)MAXVOLUME;
3537   setThumb(vol_bar, thumb);
3538   tune_l0 = XtVaCreateManagedWidget("tune_label0",labelWidgetClass,t_box,
3539             XtNwidth,k, XtNlabel,"0:00",
3540             XtNfontSet,app_resources.volume_font,
3541             XtNborderWidth,0, XtNforeground,textcolor,
3542             XtNleft,XawChainLeft, XtNright,XawChainLeft,
3543             XtNbackground,bgcolor, NULL);
3544   tune_l = XtVaCreateManagedWidget("tune_label",labelWidgetClass,t_box,
3545             XtNwidth,l, XtNfontSet,app_resources.volume_font,
3546             XtNfromHoriz,tune_l0, XtNborderWidth,0, XtNforeground,textcolor,
3547             XtNleft,XawChainLeft, XtNright,XawChainLeft,
3548             XtNbackground,bgcolor, NULL);
3549   tune_bar = XtVaCreateManagedWidget("tune_bar",scrollbarWidgetClass,t_box,
3550             XtNwidth,DEFAULT_REG_WIDTH-(k+l+30+tune_hd),
3551             XtNbackground,textbgcolor,
3552             XtNhorizDistance,tune_hd, XtNfromHoriz,tune_l,
3553             XtNleft,XawChainLeft, XtNright,XawChainLeft,
3554             XtNorientation,XtorientHorizontal, NULL);
3555 #ifdef SCROLLBARLENGTHBUG
3556   XtVaGetValues(vol_bar, XtNminimumThumb,&m, NULL);
3557   XtVaGetValues(tune_bar, XtNminimumThumb,&m2, NULL);
3558   XtVaSetValues(vol_bar,
3559                   XtNlength,DEFAULT_REG_WIDTH-(i+j+30+vol_hd)-m, NULL);
3560   XtVaSetValues(tune_bar,
3561                   XtNlength,DEFAULT_REG_WIDTH-(k+l+30+tune_hd)-m2, NULL);
3562 #endif /* SCROLLBARLENGTHBUG */
3563
3564  /*
3565   * StartScroll does not exist when Xaw3d is compiled with XAW_ARROW_SCROLLBARS,
3566   * or when neXtaw or XawPlus is used. Thus, a runtime check sees if it exists.
3567   * If it does not, A replacement is defined to avoid warnings, and to allow
3568   * for scrolling with the wheel buttons.
3569   * Note that this check could work only after the scrollbar class is inited.
3570   */
3571   XtGetActionList(scrollbarWidgetClass, &action_list, &num_actions);
3572   j = (int)num_actions;
3573   for (i = 0; i < j; i++)
3574     if (!strcasecmp(action_list[i].string, "StartScroll")) {
3575       XtFree((char *)action_list);
3576       return;
3577     }
3578   XtAppAddActions(app_con, startscroll_act, XtNumber(startscroll_act));
3579   use_own_start_scroll = True;
3580   XtFree((char *)action_list);
3581 }
3582
3583 static void
3584 createButtons(void) {
3585   play_b = XtVaCreateManagedWidget("play_button",toggleWidgetClass,b_box,
3586             XtNbitmap,GET_BITMAP(play), XtNforeground,buttoncolor,
3587             XtNbackground,buttonbgcolor, NULL);
3588   pause_b = XtVaCreateManagedWidget("pause_button",toggleWidgetClass,b_box,
3589             XtNbitmap,GET_BITMAP(pause), XtNfromHoriz,play_b,
3590             XtNforeground,togglecolor, XtNbackground,buttonbgcolor, NULL);
3591   stop_b = XtVaCreateManagedWidget("stop_button",commandWidgetClass,b_box,
3592             XtNbitmap,GET_BITMAP(stop), XtNforeground,buttoncolor,
3593             XtNbackground,buttonbgcolor, XtNfromHoriz,pause_b, NULL);
3594   prev_b = XtVaCreateManagedWidget("prev_button",commandWidgetClass,b_box,
3595             XtNbitmap,GET_BITMAP(prev), XtNforeground,buttoncolor,
3596             XtNbackground,buttonbgcolor, XtNfromHoriz,stop_b, NULL);
3597   back_b = XtVaCreateManagedWidget("back_button",commandWidgetClass,b_box,
3598             XtNbitmap,GET_BITMAP(back), XtNforeground,buttoncolor,
3599             XtNbackground,buttonbgcolor, XtNfromHoriz,prev_b, NULL);
3600   fwd_b = XtVaCreateManagedWidget("fwd_button",commandWidgetClass,b_box,
3601             XtNbitmap,GET_BITMAP(fwrd), XtNforeground,buttoncolor,
3602             XtNbackground,buttonbgcolor, XtNfromHoriz,back_b, NULL);
3603   next_b = XtVaCreateManagedWidget("next_button",commandWidgetClass,b_box,
3604             XtNbitmap,GET_BITMAP(next), XtNforeground,buttoncolor,
3605             XtNbackground,buttonbgcolor, XtNfromHoriz,fwd_b, NULL);
3606   quit_b = XtVaCreateManagedWidget("quit_button",commandWidgetClass,b_box,
3607             XtNbitmap,GET_BITMAP(quit), XtNforeground,buttoncolor,
3608             XtNbackground,buttonbgcolor, XtNfromHoriz,next_b, NULL);
3609   random_b = XtVaCreateManagedWidget("random_button",toggleWidgetClass,b_box,
3610             XtNbitmap,GET_BITMAP(random), XtNfromHoriz,quit_b,
3611             XtNforeground,togglecolor, XtNbackground,buttonbgcolor, NULL);
3612   repeat_b = XtVaCreateManagedWidget("repeat_button",toggleWidgetClass,b_box,
3613             XtNbitmap,GET_BITMAP(repeat2), XtNfromHoriz,random_b,
3614             XtNforeground,togglecolor, XtNbackground,buttonbgcolor, NULL);
3615
3616   XtAddCallback(quit_b, XtNcallback,quitCB, NULL);
3617   XtAddCallback(play_b, XtNcallback,playCB, NULL);
3618   XtAddCallback(pause_b, XtNcallback,pauseCB, NULL);
3619   XtAddCallback(stop_b, XtNcallback,stopCB, NULL);
3620   XtAddCallback(prev_b, XtNcallback,prevCB, NULL);
3621   XtAddCallback(next_b, XtNcallback,nextCB, NULL);
3622   XtAddCallback(fwd_b, XtNcallback,forwardCB, NULL);
3623   XtAddCallback(back_b, XtNcallback,backCB, NULL);
3624   XtAddCallback(random_b, XtNcallback,randomCB, NULL);
3625   XtAddCallback(repeat_b, XtNcallback,repeatCB, NULL);
3626
3627 #ifndef XawTraversal
3628   XtSetKeyboardFocus(play_b, base_f);
3629   XtSetKeyboardFocus(stop_b, base_f);
3630   XtSetKeyboardFocus(prev_b, base_f);
3631   XtSetKeyboardFocus(back_b, base_f);
3632   XtSetKeyboardFocus(fwd_b, base_f);
3633   XtSetKeyboardFocus(next_b, base_f);
3634   XtSetKeyboardFocus(quit_b, base_f);
3635   XtSetKeyboardFocus(random_b, base_f);
3636   XtSetKeyboardFocus(repeat_b, base_f);
3637 #endif /* !XawTraversal */
3638 }
3639
3640 static void
3641 init_output_lists(void) {
3642   int i = 0, j = 0;
3643
3644   play = (outputs *)safe_malloc(sizeof(outputs));
3645   record = (outputs *)safe_malloc(sizeof(outputs));
3646   play->output_list = (id_list *)safe_malloc(sizeof(id_list) * 7);
3647   record->output_list = (id_list *)safe_malloc(sizeof(id_list) * 7);
3648   play->current = play->def = 0; play->formatGroup = NULL;
3649   record->current = record->def = 0; record->formatGroup = NULL;
3650   while (strcmp(local_buf, CHECKPOST "0")) {
3651     a_pipe_read(local_buf, sizeof(local_buf));
3652     if ((*local_buf == M_FILE_OUTPUT) || (*local_buf == M_FILE_CUR_OUTPUT)) {
3653       record->output_list[i].id_char = *(local_buf + 1);
3654       record->output_list[i].id_name = safe_strdup(local_buf + 3);
3655       if (((i+1) % 7) == 0) record->output_list = (id_list *)safe_realloc(
3656                                                           record->output_list,
3657                                                           sizeof(id_list) *
3658                                                           (7 * ((i+1)/7 + 1)));
3659       i++;
3660     } else if ((*local_buf == M_DEVICE_OUTPUT) ||
3661                (*local_buf == M_DEVICE_CUR_OUTPUT)) {
3662       play->output_list[j].id_char = *(local_buf + 1);
3663       play->output_list[j].id_name = safe_strdup(local_buf + 3);
3664       if (((j+1) % 7) == 0) play->output_list = (id_list *)safe_realloc(
3665                                                          play->output_list,
3666                                                          sizeof(id_list) *
3667                                                          (7 * ((j+1)/7 + 1)));
3668       if (*local_buf == M_DEVICE_CUR_OUTPUT) play->def = play->current = j;
3669       j++;
3670     }
3671   }
3672   if (i == 0) {
3673     free(record->output_list);
3674     free(record);
3675     record = NULL;
3676     XtVaSetValues(file_menu[ID_SAVE - 100].widget, XtNsensitive,False, NULL);
3677   } else {
3678     record->output_list = (id_list *)safe_realloc(record->output_list,
3679                                                 sizeof(id_list) * i);
3680     record->max = i;
3681     record->lbuf = NULL;
3682   }
3683   if (j == 0) {
3684     free(play->output_list);
3685     free(play);
3686     play = NULL;
3687   } else {
3688     play->output_list = (id_list *)safe_realloc(play->output_list,
3689                                                sizeof(id_list) * j);
3690     play->max = j;
3691     play->lbuf = NULL;
3692   }
3693 }
3694
3695 static void
3696 a_init_interface(int pipe_in) {
3697   static XtActionsRec actions[] = {
3698     {"do-quit", (XtActionProc)quitCB},
3699     {"show-menu", popupfilemenuACT},
3700     {"hide-menu", popdownfilemenuACT},
3701 #ifdef OLDXAW
3702     {"fix-menu", (XtActionProc)filemenuCB},
3703 #endif
3704     {"do-menu", filemenuACT},
3705     {"do-addall", popdownAddALLACT},
3706     {"do-complete", completeDirACT},
3707     {"do-chgdir", setDirACT},
3708     {"draw-trace", redrawACT},
3709     {"do-exchange", exchgWidthACT},
3710     {"do-toggletrace", toggleTraceACT},
3711     {"do-mutechan", muteChanACT},
3712     {"do-solochan", soloChanACT},
3713     {"do-revcaption", redrawCaptionACT},
3714     {"do-popdown", (XtActionProc)popdownCB},
3715     {"do-play", (XtActionProc)playCB},
3716     {"do-sndspec", sndspecACT},
3717     {"do-pause", (XtActionProc)pauseCB},
3718     {"do-stop", (XtActionProc)stopCB},
3719     {"do-next", (XtActionProc)nextCB},
3720     {"do-prev", (XtActionProc)prevCB},
3721     {"do-forward", (XtActionProc)forwardCB},
3722     {"do-back", (XtActionProc)backCB},
3723     {"do-key", soundkeyACT},
3724     {"do-speed", speedACT},
3725     {"do-voice", voiceACT},
3726     {"do-volupdown", volupdownACT},
3727     {"do-tuneset", tunesetACT},
3728     {"do-resize", resizeToplevelACT},
3729     {"do-scroll", scrollListACT},
3730 #ifndef WIDGET_IS_LABEL_WIDGET
3731     {"do-deltext", deleteTextACT},
3732 #endif
3733     {"do-scroll-lyrics", scrollTextACT},
3734 #ifdef TimNmenu
3735     {"checkRightAndPopupSubmenu", checkRightAndPopupSubmenuACT},
3736     {"popdownSubmenu", popdownSubmenuACT},
3737 #endif
3738     {"leaveSubmenu", leaveSubmenuACT},
3739     {"do-options", optionspopupACT},
3740     {"do-optionsclose", (XtActionProc)optionscloseCB},
3741     {"do-filelist", flistpopupACT},
3742     {"do-about", aboutACT},
3743     {"do-toggle-tooltips", xawtipsetACT},
3744     {"do-closeparent", closeParentACT},
3745     {"do-flistmove", flistMoveACT},
3746     {"do-fselect", (XtActionProc)fselectCB},
3747     {"do-fdelete", (XtActionProc)fdeleteCB},
3748     {"do-fdelall", (XtActionProc)fdelallCB},
3749     {"do-backspace", backspaceACT},
3750     {"do-cancel", cancelACT},
3751     {"do-ok", okACT},
3752     {"do-up", upACT},
3753     {"do-down", downACT},
3754     {"do-record", recordACT},
3755     {"changetrace", scrollTraceACT}
3756   };
3757
3758   XtResource xaw_resources[] = {
3759 #define offset(entry) XtOffset(struct _app_resources*, entry)
3760 #define toffset(entry) XtOffset(struct _app_resources*, tracecfg.entry)
3761   {"arrangeTitle", "ArrangeTitle", XtRBoolean, sizeof(Boolean),
3762    offset(arrange_title), XtRImmediate, (XtPointer)False},
3763   {"gradientBar", "GradientBar", XtRBoolean, sizeof(Boolean),
3764    toffset(gradient_bar), XtRImmediate, (XtPointer)False},
3765 #ifdef WIDGET_IS_LABEL_WIDGET
3766   {"textLHeight", "TextLHeight", XtRShort, sizeof(short),
3767    offset(text_height), XtRImmediate, (XtPointer)30},
3768 #else
3769   {"textHeight", "TextHeight", XtRShort, sizeof(short),
3770    offset(text_height), XtRImmediate, (XtPointer)120},
3771 #endif /* WIDGET_IS_LABEL_WIDGET */
3772   {"traceWidth", "TraceWidth", XtRShort, sizeof(short),
3773    toffset(trace_width), XtRImmediate, (XtPointer)TRACE_WIDTH},
3774   {"traceHeight", "TraceHeight", XtRShort, sizeof(short),
3775    toffset(trace_height), XtRImmediate, (XtPointer)TRACE_HEIGHT_WITH_FOOTER},
3776   {"menuWidth", "MenuWidth", XtRShort, sizeof(Dimension),
3777    offset(menu_width), XtRImmediate, (XtPointer)200},
3778   {"foreground", XtCForeground, XtRPixel, sizeof(Pixel),
3779    toffset(common_fgcolor), XtRString, "black"},
3780   {"background", XtCBackground, XtRPixel, sizeof(Pixel),
3781    offset(common_bgcolor), XtRString, COMMON_BGCOLOR},
3782   {"menubutton", "MenuButtonBackground", XtRPixel, sizeof(Pixel),
3783    offset(menub_bgcolor), XtRString, "#CCFF33"},
3784   {"textbackground", "TextBackground", XtRPixel, sizeof(Pixel),
3785    toffset(text_bgcolor), XtRString, TEXTBG_COLOR},
3786   {"text2background", "Text2Background", XtRPixel, sizeof(Pixel),
3787    offset(text2_bgcolor), XtRString, "gray80"},
3788   {"toggleforeground", "ToggleForeground", XtRPixel, sizeof(Pixel),
3789    offset(toggle_fgcolor), XtRString, "MediumBlue"},
3790   {"buttonforeground", "ButtonForeground", XtRPixel, sizeof(Pixel),
3791    offset(button_fgcolor), XtRString, "blue"},
3792   {"buttonbackground", "ButtonBackground", XtRPixel, sizeof(Pixel),
3793    offset(button_bgcolor), XtRString, COMMANDBUTTON_COLOR},
3794   {"velforeground", "VelForeground", XtRPixel, sizeof(Pixel),
3795    toffset(velocity_color), XtRString, "orange"},
3796   {"veldrumforeground", "VelDrumForeground", XtRPixel, sizeof(Pixel),
3797    toffset(drumvelocity_color), XtRString, "red"},
3798   {"volforeground", "VolForeground", XtRPixel, sizeof(Pixel),
3799    toffset(volume_color), XtRString, "LightPink"},
3800   {"expforeground", "ExpForeground", XtRPixel, sizeof(Pixel),
3801    toffset(expr_color), XtRString, "aquamarine"},
3802   {"panforeground", "PanForeground", XtRPixel, sizeof(Pixel),
3803    toffset(pan_color), XtRString, "blue"},
3804   {"tracebackground", "TraceBackground", XtRPixel, sizeof(Pixel),
3805    toffset(trace_bgcolor), XtRString, "gray90"},
3806   {"rimcolor", "RimColor", XtRPixel, sizeof(Pixel),
3807    toffset(rim_color), XtRString, "gray20"},
3808   {"boxcolor", "BoxColor", XtRPixel, sizeof(Pixel),
3809    toffset(box_color), XtRString, "gray76"},
3810   {"captioncolor", "CaptionColor", XtRPixel, sizeof(Pixel),
3811    toffset(caption_color), XtRString, "DarkSlateGrey"},
3812   {"sustainedkeycolor", "SustainedKeyColor", XtRPixel, sizeof(Pixel),
3813    toffset(sus_color), XtRString, "red4"},
3814   {"whitekeycolor", "WhiteKeyColor", XtRPixel, sizeof(Pixel),
3815    toffset(white_key_color), XtRString, "white"},
3816   {"blackkeycolor", "BlackKeyColor", XtRPixel, sizeof(Pixel),
3817    toffset(black_key_color), XtRString, "black"},
3818   {"playingkeycolor", "PlayingKeyColor", XtRPixel, sizeof(Pixel),
3819    toffset(play_color), XtRString, "maroon1"},
3820   {"reverbcolor", "ReverbColor", XtRPixel, sizeof(Pixel),
3821    toffset(rev_color), XtRString, "PaleGoldenrod"},
3822   {"choruscolor", "ChorusColor", XtRPixel, sizeof(Pixel),
3823    toffset(cho_color), XtRString, "yellow"},
3824   {"labelfont", XtCFontSet, XtRFontSet, sizeof(XFontSet),
3825    offset(label_font), XtRString,
3826        "-adobe-helvetica-bold-r-*-*-14-*-75-75-*-*-*-*,*"},
3827   {"volumefont", XtCFontSet, XtRFontSet, sizeof(XFontSet),
3828    offset(volume_font), XtRString,
3829        "-adobe-helvetica-bold-r-*-*-12-*-75-75-*-*-*-*,*"},
3830   {"textfontset", XtCFontSet, XtRFontSet, sizeof(XFontSet),
3831    offset(text_font), XtRString, "-*-*-medium-r-normal--14-*-*-*-*-*-*-*,*"},
3832   {"ttitlefont", XtCFontSet, XtRFontSet, sizeof(XFontSet),
3833    toffset(c_title_font), XtRString,
3834        "-*-fixed-medium-r-normal--14-*-*-*-*-*-*-*,*"},
3835   {"tracefont", XtCFontSet, XtRFontSet, sizeof(XFontSet),
3836    toffset(c_trace_font), XtRString, "7x14,*"},
3837   {"labelfile", "LabelFile", XtRString, sizeof(String),
3838    offset(file_text), XtRString, "file..."},
3839   {"popup_confirm_title", XtCString, XtRString, sizeof(String),
3840    offset(popup_confirm), XtRString, "Dialog"},
3841   {"moreString", XtCString, XtRString, sizeof(String),
3842    offset(more_text), XtRString, "More..."},
3843   {"noplaying", XtCString, XtRString, sizeof(String),
3844    offset(no_playing), XtRString, "[ No Playing File ]"},
3845   {"untitled", XtCString, XtRString, sizeof(String),
3846    toffset(untitled), XtRString, "<No Title>"},
3847   {"load_" LISTDIALOGBASENAME ".title", XtCString, XtRString,
3848    sizeof(String), offset(load_LISTDIALOGBASENAME_title), XtRString,
3849    "TiMidity <Load Playlist>"},
3850   {"save_" LISTDIALOGBASENAME ".title", XtCString, XtRString,
3851    sizeof(String), offset(save_LISTDIALOGBASENAME_title), XtRString,
3852    "TiMidity <Save Playlist>"}
3853 #undef offset
3854 #undef toffset
3855   };
3856
3857   String fallback_resources[] = {
3858     "*international: True",
3859     "*Label*fontSet: -adobe-helvetica-bold-o-*-*-14-*-*-*-*-*-*-*,*",
3860     "*MenuButton*fontSet: -adobe-helvetica-bold-r-*-*-14-*-*-*-*-*-*-*,*",
3861     "*Command*fontSet: -adobe-helvetica-bold-r-*-*-12-*-*-*-*-*-*-*,*",
3862     "*List*fontSet: -adobe-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*,*",
3863     "*Dialog*List*fontSet: -adobe-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*,*",
3864     "*Dialog*fontSet: -adobe-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*,*",
3865     "*Text*fontSet: -misc-fixed-medium-r-normal--14-*-*-*-*-*-*-*,*",
3866     "*Text*background: " TEXTBG_COLOR "",
3867     "*Text*scrollbar*background: " TEXTBG_COLOR "",
3868     "*Scrollbar*background: " TEXTBG_COLOR "",
3869     "*Label.foreground: black",
3870     "*Label.background: #CCFF33",
3871     "*Command.background: " COMMANDBUTTON_COLOR "",
3872     "*Tip.fontSet: -misc-fixed-medium-r-normal-*-10-*-*-*-*-*-*-*,*",
3873     "*Tip.background: white",
3874     "*Tip.foreground: black",
3875     "*Tip.borderColor: black",
3876     "*Dialog.Command.background: " COMMANDBUTTON_COLOR "",
3877     "*Dialog.Text.background: " TEXTBG_COLOR "",
3878     "*fontSet: -*--14-*,*",
3879     "*load_dialog.label.background: " COMMON_BGCOLOR "",
3880     "*Command.fontSet: -adobe-helvetica-bold-r-*-*-12-*-*-*-*-*-*-*,*",
3881     "*Toggle.fontSet: -adobe-helvetica-medium-o-*-*-12-*-*-*-*-*-*-*,*",
3882 #ifdef OLDXAW
3883     "*MenuButton.translations:<EnterWindow>:    highlight()\\n\
3884         <LeaveWindow>:  reset()\\n\
3885         Any<BtnDown>:   reset() fix-menu() PopupMenu()",
3886 #endif
3887     "*menu_box.borderWidth: 0",
3888     "*button_box.borderWidth: 0",
3889     "*button_box.horizDistance: 4",
3890     "*file_menubutton.menuName: file_simplemenu",
3891     "*file_menubutton.width: 60",
3892     "*file_menubutton.height: 28",
3893     "*file_menubutton.horizDistance: 6",
3894     "*file_menubutton.vertDistance: 4",
3895     "*file_menubutton.file_simplemenu*fontSet: -*--14-*,*",
3896     "*title_menubutton.title_simplemenu*fontSet: \
3897          -adobe-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*,*",
3898     "*title_menubutton*SmeBSB.fontSet: \
3899          -adobe-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*,*",
3900     "*title_menubutton.menuName: title_simplemenu",
3901     "*OK.label: OK",
3902     "*Cancel.label: Cancel",
3903     "*title_menubutton.width: 210",
3904     "*title_menubutton.height: 28",
3905     "*title_menubutton.resize: false",
3906     "*title_menubutton.horizDistance: 6",
3907     "*title_menubutton.vertDistance: 4",
3908     "*title_menubutton.fromHoriz: file_menubutton",
3909     "*time_label.width: 92",
3910     "*time_label.height: 26",
3911     "*time_label.resize: false",
3912     "*time_label.fromHoriz: title_menubutton",
3913     "*time_label.horizDistance: 1",
3914     "*time_label.vertDistance: 4",
3915     "*time_label.label: time / mode",
3916     "*button_box.height: 40",
3917     "*button_box*Command.width: 32",
3918     "*button_box*Command.height: 32",
3919     "*button_box*Toggle.width: 32",
3920     "*button_box*Toggle.height: 32",
3921     "*button_box*Command.horizDistance: 1",
3922     "*button_box*Command.vertDistance: 1",
3923     "*button_box*Toggle.horizDistance: 1",
3924     "*button_box*Toggle.vertDistance: 1",
3925     "*random_button.horizDistance: 4",
3926     "*play_button.vertDistance: 9",
3927     "*play_button.tip: Play",
3928     "*pause_button.tip: Pause",
3929     "*stop_button.tip: Stop",
3930     "*prev_button.tip: Previous",
3931     "*back_button.tip: Back",
3932     "*fwd_button.tip: Forward",
3933     "*next_button.tip: Next",
3934     "*quit_button.tip: Quit",
3935     "*random_button.tip: Shuffle",
3936     "*repeat_button.tip: Repeat",
3937     "*fast_b.tip: Increase tempo",
3938     "*slow_b.tip: Decrease Tempo",
3939     "*keyup_b.tip: Raise pitch",
3940     "*keydown_b.tip: Lower pitch",
3941     "*repeat_button.tip: Repeat",
3942     "*repeat_button.tip: Repeat",
3943     "*repeat_button.tip: Repeat",
3944     "*repeat_button.tip: Repeat",
3945     "*lyric_text.fromVert: tune_box",
3946     "*lyric_text.borderWidth: 1" ,
3947     "*lyric_text.vertDistance: 4",
3948     "*lyric_text.horizDistance: 6",
3949 #ifndef WIDGET_IS_LABEL_WIDGET
3950     "*lyric_text.height: 120",
3951     "*lyric_text.scrollVertical: Always",
3952     "*lyric_text.translations: #override\\n\
3953         <Btn2Down>:     do-deltext()\\n\
3954         <Btn4Down>:     do-scroll-lyrics(-1)\\n\
3955         <Btn5Down>:     do-scroll-lyrics(1)",
3956 #else
3957     "*lyric_text.height: 30",
3958     "*lyric_text.label: MessageWindow",
3959     "*lyric_text.resize: true",
3960 #endif
3961     "*volume_box*fontSet: -adobe-helvetica-bold-r-*-*-12-*-*-*-*-*-*-*,*",
3962     "*tune_box*fontSet: -adobe-helvetica-bold-r-*-*-12-*-*-*-*-*-*-*,*",
3963     "*volume_box*horizDistance: 0",
3964     "*volume_box*vertDistance: 0",
3965     "*volume_box.vertDistance: 2",
3966     "*volume_box.borderWidth: 0",
3967     "*volume_label.borderWidth: 0",
3968     "*tune_box.borderWidth: 0",
3969     "*tune_label.label: / ----",
3970     "*tune_box*horizDistance: 0",
3971     "*tune_box*vertDistance: 0",
3972     "*tune_box.vertDistance: 2",
3973     "*popup_option.title: TiMidity <Extend Modes>",
3974     "*popup_file.title: TiMidity <File List>",
3975     "*dialog_lfile.title: TiMidity <Load File>",
3976     "*dialog_sfile.title: TiMidity <Save File>",
3977     "*popup_about.title: Information",
3978     "*popup_warning.title: Information",
3979     "*popup_sformat.title: Dialog",
3980     "*popup_slabel.label: Select output format",
3981     "*popup_olabel.label: Output device",
3982     "*load_dialog.label: File Name",
3983     "*load_dialog.borderWidth: 0",
3984     "*load_dialog.height: 400",
3985     "*trace.vertDistance: 2",
3986     "*trace.borderWidth: 1",
3987     "*trace_vport.borderWidth: 1",
3988     "*trace_vport.useRight: True",
3989     "*popup_optform*Box*borderWidth: 0",
3990     "*load_dialog.label.fontSet: -*--14-*,*",
3991     "*popup_abox*fontSet: -adobe-helvetica-bold-o-*-*-14-*-*-*-*-*-*-*,*",
3992     "*popup_cform*fontSet: -adobe-helvetica-bold-o-*-*-14-*-*-*-*-*-*-*,*",
3993     "*popup_optform*fontSet: -adobe-helvetica-bold-o-*-*-14-*-*-*-*-*-*-*,*",
3994     "*popup_sform*fontSet: -adobe-helvetica-bold-o-*-*-14-*-*-*-*-*-*-*,*",
3995     "*popup_wbox*fontSet: -adobe-helvetica-bold-o-*-*-14-*-*-*-*-*-*-*,*",
3996     "*cwd_label.fontSet: -adobe-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*,*",
3997     "*time_label*cwd_info.fontSet: \
3998            -adobe-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*,*",
3999     "*time_label.fontSet: -adobe-helvetica-bold-r-*-*-14-*-*-*-*-*-*-*,*",
4000     "*volume_bar.translations: #override\\n\
4001         ~Ctrl Shift<Btn1Down>: do-volupdown(-50)\\n\
4002         ~Ctrl Shift<Btn3Down>: do-volupdown(50)\\n\
4003         ~Ctrl Shift<Btn2Down>: do-volupdown(1)\\n\
4004         Ctrl ~Shift<Btn2Down>: do-volupdown(-1)\\n\
4005         Ctrl ~Shift<Btn1Down>: do-volupdown(-5)\\n\
4006         Ctrl ~Shift<Btn3Down>: do-volupdown(5)\\n\
4007         <BtnDown>: StartScroll(Continuous) MoveThumb() NotifyThumb()\\n\
4008         <BtnUp>: NotifyScroll(FullLength) EndScroll()",
4009     "*tune_bar.translations: #override\\n\
4010         <BtnDown>:      StartScroll(Continuous) MoveThumb() NotifyThumb()\\n\
4011         <BtnMotion>:    MoveThumb() NotifyThumb()\\n\
4012         <BtnUp>:        do-tuneset() NotifyScroll(FullLength) EndScroll()",
4013     "*file_simplemenu.load.label: Load (Meta-N)",
4014     "*file_simplemenu.load.underline: 0",
4015     "*file_simplemenu.save.label: Save (Ctrl-V)",
4016     "*file_simplemenu.save.underline: 2",
4017     "*file_simplemenu.load_playlist.label: Load Playlist (Meta-L)",
4018     "*file_simplemenu.load_playlist.underline: 3",
4019     "*file_simplemenu.save_playlist.label: Save Playlist (Meta-P)",
4020     "*file_simplemenu.save_playlist.underline: 5",
4021     "*file_simplemenu.saveconfig.label: Save Config (Meta-S)",
4022     "*file_simplemenu.saveconfig.underline: 0",
4023     "*file_simplemenu.hidetext.label: (Un)Hide Messages (Ctrl-M)",
4024     "*file_simplemenu.hidetext.underline: 9",
4025     "*file_simplemenu.hidetrace.label: (Un)Hide Trace (Ctrl-T)",
4026     "*file_simplemenu.hidetrace.underline: 9",
4027     "*file_simplemenu.shuffle.label: Shuffle (Ctrl-S)",
4028     "*file_simplemenu.shuffle.underline: 1",
4029     "*file_simplemenu.repeat.label: Repeat (Ctrl-R)",
4030     "*file_simplemenu.repeat.underline: 0",
4031     "*file_simplemenu.autostart.label: Auto Start",
4032     "*file_simplemenu.autostart.underline: 1",
4033     "*file_simplemenu.autoquit.label: Auto Exit",
4034     "*file_simplemenu.autoquit.underline: 5",
4035     "*file_simplemenu.filelist.label: File List (Ctrl-F)",
4036     "*file_simplemenu.filelist.underline: 0",
4037     "*file_simplemenu.modes.label: Extend Modes (Ctrl-O)",
4038     "*file_simplemenu.modes.underline: 8",
4039     "*file_simplemenu.about.label: About",
4040     "*file_simplemenu.about.underline: 0",
4041     "*file_simplemenu.quit.label: Quit (Meta-Q, Q)",
4042     "*file_simplemenu.quit.underline: 0",
4043     "*file_simplemenu.translations: #override\\n\
4044         <Key>n:         MenuPopdown() do-menu(" S(ID_LOAD) ")\\n\
4045         ~Meta<Key>l:    MenuPopdown() do-menu(" S(ID_LOAD) ")\\n\
4046         <Key>v:         MenuPopdown() do-menu(" S(ID_SAVE) ")\\n\
4047         Meta<Key>l:     MenuPopdown() do-menu(" S(ID_LOAD_PLAYLIST) ")\\n\
4048         <Key>d:         MenuPopdown() do-menu(" S(ID_LOAD_PLAYLIST) ")\\n\
4049         <Key>p:         MenuPopdown() do-menu(" S(ID_SAVE_PLAYLIST) ")\\n\
4050         ~Ctrl<Key>s:    MenuPopdown() do-menu(" S(ID_SAVECONFIG) ")\\n\
4051         <Key>h:         MenuPopdown() do-menu(" S(ID_SHUFFLE) ")\\n\
4052         Ctrl<Key>s:     MenuPopdown() do-menu(" S(ID_SHUFFLE) ")\\n\
4053         <Key>r:         MenuPopdown() do-menu(" S(ID_REPEAT) ")\\n\
4054         <Key>m:         MenuPopdown() do-menu(" S(ID_HIDETXT) ")\\n\
4055         <Key>t:         MenuPopdown() do-menu(" S(ID_HIDETRACE) ")\\n\
4056         <Key>u:         MenuPopdown() do-menu(" S(ID_AUTOSTART) ")\\n\
4057         <Key>e:         MenuPopdown() do-menu(" S(ID_AUTOQUIT) ")\\n\
4058         ~Meta<Key>f:    MenuPopdown() do-filelist()\\n\
4059         <Key>o:         MenuPopdown() do-options()\\n\
4060         <Key>a:         MenuPopdown() do-about()\\n\
4061         <Key>q:         MenuPopdown() do-quit()\\n\
4062         <Key>Escape:    MenuPopdown()\\n\
4063         <Motion>:       highlight()",
4064     "*load_dialog.add.label: Add ALL",
4065     "*load_dialog.filter.label: Filter",
4066     "*flist_cmdbox.fplaybutton.label: Play",
4067     "*flist_cmdbox.fdeletebutton.label: Delete",
4068     "*flist_cmdbox.fdelallbutton.label: Delete ALL",
4069     "*closebutton.label: Close",
4070     "*modul_box.modul_lbl.label: Modulation control",
4071     "*porta_box.porta_lbl.label: Portamento control",
4072     "*nrpnv_box.nrpnv_lbl.label: NRPN Vibration",
4073     "*reverb_box.reverb_lbl.label: Reverb control",
4074     "*chorus_box.chorus_lbl.label: Chorus control",
4075     "*chpressure_box.chpressure_lbl.label: Channel Pressure control",
4076     "*overlapvoice_box.overlapv_lbl.label: Allow Multiple Same Notes",
4077     "*txtmeta_box.txtmeta_lbl.label: Tracing All Text Meta Events",
4078     "*sbox_ratelabel.label: Rate",
4079     "*base_form.translations: #override\\n\
4080         ~Ctrl Meta<Key>n:       do-menu(" S(ID_LOAD) ")\\n\
4081         Ctrl ~Shift<Key>v:      do-menu(" S(ID_SAVE) ")\\n\
4082         Meta<Key>l:             do-menu(" S(ID_LOAD_PLAYLIST) ")\\n\
4083         Meta<Key>p:             do-menu(" S(ID_SAVE_PLAYLIST) ")\\n\
4084         ~Ctrl Meta<Key>s:       do-menu(" S(ID_SAVECONFIG) ")\\n\
4085         Ctrl<Key>r:             do-menu(" S(ID_REPEAT) ")\\n\
4086         Ctrl<Key>s:             do-menu(" S(ID_SHUFFLE) ")\\n\
4087         Ctrl<Key>t:             do-menu(" S(ID_HIDETRACE) ")\\n\
4088         Ctrl<Key>m:             do-menu(" S(ID_HIDETXT) ")\\n\
4089         ~Ctrl<Key>q:            do-quit()\\n\
4090         ~Ctrl<Key>r:            do-play()\\n\
4091         <Key>Return:            do-play()\\n\
4092         <Key>KP_Enter:          do-play()\\n\
4093         ~Ctrl<Key>g:            do-sndspec()\\n\
4094         ~Ctrl<Key>space:        do-pause()\\n\
4095         ~Ctrl<Key>s:            do-stop()\\n\
4096         ~Meta<Key>p:            do-prev()\\n\
4097         <Key>Left:              do-prev()\\n\
4098         ~Meta<Key>n:            do-next()\\n\
4099         <Key>Right:             do-next()\\n\
4100         ~Ctrl ~Meta<Key>f:      do-forward()\\n\
4101         ~Ctrl<Key>b:            do-back()\\n\
4102         ~Ctrl<Key>plus:         do-key()\\n\
4103         ~Shift<Key>-:           do-key(1)\\n\
4104         <Key>KP_Add:            do-key()\\n\
4105         <Key>KP_Subtract:       do-key(1)\\n\
4106         ~Ctrl<Key>greater:      do-speed()\\n\
4107         ~Ctrl<Key>less:         do-speed(1)\\n\
4108         ~Ctrl ~Shift<Key>o:     do-voice()\\n\
4109         ~Ctrl Shift<Key>o:      do-voice(1)\\n\
4110         Ctrl<Key>o:             do-options()\\n\
4111         ~Meta Ctrl<Key>f:       do-filelist()\\n\
4112         ~Meta<Key>l:            do-filelist()\\n\
4113         <Key>a:                 do-about()\\n\
4114         Ctrl<Key>d:             do-toggle-tooltips(-1)\\n\
4115         ~Ctrl ~Shift<Key>v:     do-volupdown(-10)\\n\
4116         ~Ctrl Shift<Key>v:      do-volupdown(10)\\n\
4117         <Key>Down:              do-volupdown(-10)\\n\
4118         <Key>Up:                do-volupdown(10)\\n\
4119         ~Ctrl<Key>x:            do-exchange()\\n\
4120         ~Ctrl<Key>t:            do-toggletrace()\\n\
4121         ~Ctrl Meta <Key>f:      show-menu()\\n\
4122         <Key>z:                 show-menu()\\n\
4123         <Key>j:                 changetrace(1)\\n\
4124         <BtnDown>:              hide-menu()\\n\
4125         <ConfigureNotify>:      do-resize()",
4126
4127     "*Viewport.useBottom: True",
4128     "*List.baseTranslations: #override\\n\
4129         <Btn4Down>:   do-scroll(-1)\\n\
4130         <Btn5Down>:   do-scroll(1)",
4131     "*Scrollbar.baseTranslations: #override\\n\
4132         <Btn4Down>:   StartScroll(Backward)\\n\
4133         <Btn5Down>:   StartScroll(Forward)",
4134     "*Text.baseTranslations: #override\\n\
4135         ~Shift<Key>Delete:      delete-next-character()\\n\
4136         Ctrl<Key>V:             insert-selection(CLIPBOARD)",
4137     "*TransientShell.Box.baseTranslations: #override\\n\
4138         ~Ctrl<Key>c:    do-closeparent()\\n\
4139         <Key>Escape:    do-closeparent()\\n\
4140         <Key>KP_Enter:  do-closeparent()\\n\
4141         <Key>Return:    do-closeparent()",
4142     "*load_dialog.value.translations: #override\\n\
4143         ~Ctrl Meta<Key>KP_Enter:        do-addall()\\n\
4144         ~Ctrl Meta<Key>Return:          do-addall()\\n\
4145         ~Ctrl ~Meta<Key>KP_Enter:       do-chgdir()\\n\
4146         ~Ctrl ~Meta<Key>Return:         do-chgdir()\\n\
4147         ~Ctrl ~Meta<Key>Tab:            do-complete() end-of-line()\\n\
4148         Ctrl ~Shift<Key>g:              do-popdown()\\n\
4149         <Key>BackSpace:         do-backspace() delete-previous-character()\\n\
4150         Ctrl<Key>H:             do-backspace() delete-previous-character()\\n\
4151         <Key>Escape:            do-popdown()",
4152     "*load_dialog.filter.accelerators: #override\\n\
4153         Ctrl<KeyPress>`: toggle() notify()",
4154     "*dialog_sfile*load_dialog.add.Sensitive: False",
4155     "*" LISTDIALOGBASENAME "*load_dialog.add.Sensitive: False",
4156     "*trace.translations: #override\\n\
4157         <Btn1Down>:     do-toggletrace()\\n\
4158         <Btn2Down>:     do-solochan()\\n\
4159         <Btn3Down>:     do-mutechan()\\n\
4160         <Btn4Down>:     changetrace(-1)\\n\
4161         <Btn5Down>:     changetrace(1)\\n\
4162         <EnterNotify>:  do-revcaption()\\n\
4163         <LeaveNotify>:  do-revcaption()\\n\
4164         <Expose>:       draw-trace()",
4165     "*time_label.translations: #override\\n\
4166         <Btn2Down>:     do-menu(" S(ID_HIDETRACE) ")\\n\
4167         <Btn3Down>:     do-exchange()",
4168     "*popup_optform.translations: #override\\n\
4169         ~Ctrl<Key>c:    do-closeparent()\\n\
4170         ~Ctrl<Key>q:    do-quit()\\n\
4171         <Key>Escape:    do-closeparent()\\n\
4172         <Key>KP_Enter:  do-optionsclose()\\n\
4173         <Key>Return:    do-optionsclose()",
4174     "*popup_file*filelist.translations: #override\\n\
4175         <Btn1Up>(2+):   do-fselect()\\n\
4176         <Btn3Up>:       do-stop()",
4177     "*flist_cmdbox.width: 272",
4178     "*flist_cmdbox.height: 24",
4179     "*flist_cmdbox.borderWidth: 0",
4180     "*file_vport.width: 272",
4181     "*file_vport.height: 336",
4182     "*file_vport.borderWidth: 1",
4183     "*popup_fform.translations: #override\\n\
4184         ~Ctrl<Key>c:    do-closeparent()\\n\
4185         <Key>Escape:    do-closeparent()\\n\
4186         <Key>Home:      do-flistmove(-1, 0, 0)\\n\
4187         <Key>Prior:     do-flistmove(-1, 0)\\n\
4188         <Key>Right:     do-flistmove(-5)\\n\
4189         <Key>Up:        do-flistmove(-1)\\n\
4190         <Key>p:         do-flistmove(-1)\\n\
4191         ~Ctrl<Key>r:    do-fselect()\\n\
4192         <Key>Return:    do-fselect()\\n\
4193         <Key>KP_Enter:  do-fselect()\\n\
4194         Ctrl<Key>m:     do-fselect()\\n\
4195         <Key>space:     do-pause()\\n\
4196         <Key>s:         do-stop()\\n\
4197         <Key>Down:      do-flistmove(1)\\n\
4198         <Key>n:         do-flistmove(1)\\n\
4199         <Key>Left:      do-flistmove(5)\\n\
4200         <Key>Next:      do-flistmove(1, 0)\\n\
4201         <Key>End:       do-flistmove(1, 0, 0)\\n\
4202         <Key>d:         do-fdelete()\\n\
4203         :<Key>A:        do-fdelall()\\n\
4204         ~Shift<Key>v:   do-volupdown(-10)\\n\
4205         Shift<Key>v:    do-volupdown(10)\\n\
4206         ~Ctrl<Key>f:    do-forward()\\n\
4207         ~Ctrl<Key>b:    do-back()\\n\
4208         ~Ctrl<Key>q:    do-quit()",
4209     "*popup_cform.translations: #override\\n\
4210         ~Ctrl<Key>c:    do-cancel()\\n\
4211         <Key>Escape:    do-cancel()\\n\
4212         <Key>KP_Enter:  do-ok()\\n\
4213         <Key>Return:    do-ok()",
4214     "*sbox_ratetext.translations: #override\\n\
4215         <Key>Escape:    do-closeparent()\\n\
4216         <Key>KP_Enter:  do-record()\\n\
4217         <Key>Return:    do-record()\\n\
4218         <Key>BackSpace: delete-previous-character()\\n\
4219         Shift<Key>:     no-op()\\n\
4220         ~Ctrl<Key>0:    insert-char()\\n\
4221         ~Ctrl<Key>KP_0: insert-char()\\n\
4222         ~Ctrl<Key>1:    insert-char()\\n\
4223         ~Ctrl<Key>KP_1: insert-char()\\n\
4224         ~Ctrl<Key>2:    insert-char()\\n\
4225         ~Ctrl<Key>KP_2: insert-char()\\n\
4226         ~Ctrl<Key>3:    insert-char()\\n\
4227         ~Ctrl<Key>KP_3: insert-char()\\n\
4228         ~Ctrl<Key>4:    insert-char()\\n\
4229         ~Ctrl<Key>KP_4: insert-char()\\n\
4230         ~Ctrl<Key>5:    insert-char()\\n\
4231         ~Ctrl<Key>KP_5: insert-char()\\n\
4232         ~Ctrl<Key>6:    insert-char()\\n\
4233         ~Ctrl<Key>KP_6: insert-char()\\n\
4234         ~Ctrl<Key>7:    insert-char()\\n\
4235         ~Ctrl<Key>KP_7: insert-char()\\n\
4236         ~Ctrl<Key>8:    insert-char()\\n\
4237         ~Ctrl<Key>KP_8: insert-char()\\n\
4238         ~Ctrl<Key>9:    insert-char()\\n\
4239         ~Ctrl<Key>KP_9: insert-char()\\n\
4240         <Key>Home:      beginning-of-file()\\n\
4241         :<Key>KP_Home:  beginning-of-file()\\n\
4242         <Key>End:       end-of-file()\\n\
4243         :<Key>KP_End:   end-of-file()\\n\
4244         <Key>Right:     forward-character()\\n\
4245         :<Key>KP_Right: forward-character()\\n\
4246         <Key>Left:      backward-character()\\n\
4247         :<Key>KP_Left:  backward-character()\\n\
4248         Hyper<Key>:     no-op()\\n\
4249         Super<Key>:     no-op()\\n\
4250         None<Key>:      no-op()\\n\
4251         Alt<Key>:       no-op()\\n\
4252         Meta<Key>:      no-op()\\n\
4253         Lock<Key>:      no-op()",
4254     "*fbox_toggle0.accelerators: #override\\n\
4255         <Key>Up:        do-up()\\n\
4256         <Key>Down:      do-down()\\n\
4257         <Btn4Down>:     do-up()\\n\
4258         <Btn5Down>:     do-down()",
4259     "*confirmexit.label: Do you wish to exit?",
4260     "*warnoverwrite.label: Do you wish to overfile this file?",
4261     "*saveplaylisterror.label: Could not save playlist!",
4262     "*waitforwav.label: Please wait. This may take several minutes.",
4263     "*warnrecording.label: Cannot record - a file is already being recorded",
4264     NULL
4265   };
4266   int argc = 1, dot_nfile = 0, i;
4267   char *argv = APP_NAME, **dotfile_flist = NULL;
4268
4269   xaw_vendor_setup();
4270
4271   XtSetLanguageProc(NULL, NULL, NULL);
4272   toplevel = XtVaAppInitialize(&app_con, APP_CLASS, NULL, ZERO, &argc, &argv,
4273                          fallback_resources, NULL);
4274   XtGetApplicationResources(toplevel, (XtPointer)&app_resources,
4275                             xaw_resources, XtNumber(xaw_resources), NULL, 0);
4276   umask(022);
4277   home = get_user_home_dir();
4278   dot_nfile = a_readconfig(&Cfg, &dotfile_flist);
4279   if (Cfg.disptrace) ctl->trace_playing = 1;
4280   amplitude =
4281     (amplification == DEFAULT_AMPLIFICATION)?Cfg.amplitude:amplification;
4282   disp = XtDisplay(toplevel);
4283   root_height = DisplayHeight(disp, DefaultScreen(disp));
4284   root_width = DisplayWidth(disp, DefaultScreen(disp));
4285   XtVaSetValues(toplevel, XtNiconPixmap,GET_BITMAP(timidity), NULL);
4286
4287   check_mark = GET_BITMAP(check);
4288   arrow_mark = GET_BITMAP(arrow);
4289   on_mark = GET_BITMAP(on);
4290   off_mark = GET_BITMAP(off);
4291
4292   ldSstart = init_ldS();
4293
4294 #ifdef OFFIX
4295   DndInitialize(toplevel);
4296   DndRegisterOtherDrop(FileDropedHandler);
4297   DndRegisterIconDrop(FileDropedHandler);
4298 #endif /* OFFIX */
4299   XtAppAddActions(app_con, actions, XtNumber(actions));
4300
4301   base_f = XtVaCreateManagedWidget("base_form",formWidgetClass,toplevel,
4302             XtNbackground,bgcolor, NULL);
4303 #ifdef XawTraversal
4304   XawFocusInstallActions(app_con);
4305   XawFocusInstall(base_f, False);
4306 #endif /* XawTraversal */
4307   m_box = XtVaCreateManagedWidget("menu_box",boxWidgetClass,base_f,
4308             XtNtop,XawChainTop, XtNbottom,XawChainTop,
4309             XtNleft,XawChainLeft, XtNright,XawChainLeft,
4310             XtNorientation,XtorientHorizontal, XtNbackground,bgcolor, NULL);
4311   file_mb = XtVaCreateManagedWidget("file_menubutton",menuButtonWidgetClass,
4312             m_box, XtNbackground,menubcolor,
4313             XtNfontSet,app_resources.label_font,
4314             XtNlabel,app_resources.file_text, NULL);
4315   file_sm = XtVaCreatePopupShell("file_simplemenu",simpleMenuWidgetClass,
4316             file_mb, XtNforeground,textcolor, XtNbackground,textbgcolor,
4317             XtNresize,False, XtNbackingStore,NotUseful, XtNsaveUnder,False,
4318             XtNwidth,app_resources.menu_width+100, NULL);
4319   for (i = 0; i < (int)XtNumber(file_menu); i++) {
4320     bsb = XtVaCreateManagedWidget(file_menu[i].name,
4321             *(file_menu[i].wclass), file_sm,XtNleftBitmap,None,
4322              XtNleftMargin,24, NULL);
4323     XtAddCallback(bsb, XtNcallback,filemenuCB, (XtPointer)&file_menu[i].id);
4324     file_menu[i].widget = bsb;
4325   }
4326   snprintf(local_buf, sizeof(local_buf), "TiMidity++ %s", timidity_version);
4327   title_mb = XtVaCreateManagedWidget("title_menubutton",menuButtonWidgetClass,
4328             m_box, XtNbackground,menubcolor, XtNlabel,local_buf,
4329             XtNfontSet,app_resources.label_font, NULL);
4330   title_sm = XtVaCreatePopupShell("title_simplemenu",simpleMenuWidgetClass,
4331             title_mb, XtNforeground,textcolor, XtNbackground,textbgcolor,
4332             XtNbackingStore,NotUseful, XtNsaveUnder,False, NULL);
4333   time_l = XtVaCreateManagedWidget("time_label",commandWidgetClass,m_box,
4334             XtNfontSet,app_resources.label_font,
4335             XtNbackground,menubcolor, NULL);
4336   b_box = XtVaCreateManagedWidget("button_box",boxWidgetClass,base_f,
4337             XtNorientation,XtorientHorizontal,
4338             XtNtop,XawChainTop, XtNbottom,XawChainTop,
4339             XtNleft,XawChainLeft, XtNright,XawChainLeft,
4340             XtNbackground,bgcolor, XtNfromVert,m_box, NULL);
4341
4342   createButtons();
4343
4344   createBars();
4345
4346 #ifndef WIDGET_IS_LABEL_WIDGET
4347   lyric_t = XtVaCreateWidget("lyric_text",asciiTextWidgetClass,base_f,
4348             XtNwrap,XawtextWrapWord, XtNeditType,XawtextAppend,
4349             XtNwidth,(ctl->trace_playing)?TRACE_WIDTH+8:DEFAULT_REG_WIDTH,
4350 #else
4351   lyric_t = XtVaCreateWidget("lyric_text",labelWidgetClass,base_f,
4352             XtNforeground,textcolor, XtNbackground,menubcolor,
4353 #endif
4354             XtNborderWidth,1, XtNfontSet,app_resources.text_font,
4355             XtNtop,XawChainTop, XtNright,XawChainRight,
4356             XtNheight,app_resources.text_height, XtNfromVert,t_box, NULL);
4357   if (Cfg.disptext == True) XtManageChild(lyric_t);
4358
4359   if (ctl->trace_playing) createTraceWidgets();
4360
4361   XtAddCallback(vol_bar, XtNjumpProc,volsetCB, NULL);
4362   XtAddCallback(tune_bar, XtNjumpProc,tuneslideCB, NULL);
4363   XtAddCallback(time_l, XtNcallback,filemenuCB,
4364                 (XtPointer)&file_menu[ID_HIDETXT-100].id);
4365   XtAppAddInput(app_con, pipe_in,
4366                 (XtPointer)XtInputReadMask, handle_input, NULL);
4367
4368   pid = getpid();
4369   wm_delete_window = XInternAtom(disp, "WM_DELETE_WINDOW", False);
4370   net_wm_pid = XInternAtom(disp, "_NET_WM_PID", False);
4371   setupWindow(toplevel, "do-quit()", False, False);
4372
4373   XtVaGetValues(toplevel, XtNheight,&curr_height,
4374                           XtNwidth,&curr_width, NULL);
4375   XtVaGetValues(lyric_t, XtNheight,&lyric_height, NULL);
4376   base_height = curr_height;
4377
4378   XtSetKeyboardFocus(base_f, base_f);
4379   XtSetKeyboardFocus(lyric_t, base_f);
4380 #ifdef XDND
4381   a_dnd_init();
4382 #endif /* XDND */
4383   snprintf(window_title, sizeof(window_title), "%s : %s",
4384            APP_CLASS, app_resources.no_playing);
4385   XtVaSetValues(toplevel, XtNtitle,window_title, NULL);
4386
4387   a_print_text(lyric_t, strcpy(local_buf, "<< TiMidity Messages >>"));
4388   a_pipe_write("READY");
4389
4390   while (1) {
4391     a_pipe_read(local_buf, sizeof(local_buf));
4392     if (local_buf[0] != M_CHECKPOST) break;
4393     a_print_text(lyric_t, local_buf+2);
4394   }
4395   bsb = XtVaCreateManagedWidget("dummyfile",smeLineObjectClass,title_sm,
4396                                  XtNforeground,textbgcolor, NULL);
4397   init_options = atoi(local_buf);
4398   a_pipe_read(local_buf, sizeof(local_buf));
4399   init_chorus = atoi(local_buf);
4400
4401   init_output_lists();
4402   a_pipe_read(local_buf, sizeof(local_buf));
4403   max_files = atoi(local_buf);
4404   flist = (String *)safe_malloc((INIT_FLISTNUM+1)*sizeof(char *));
4405   *flist = NULL;
4406   for (i=0; i<max_files; i++) {
4407     a_pipe_read(local_buf, sizeof(local_buf));
4408     addOneFile(max_files, i, local_buf);
4409     addFlist(local_buf, i);
4410   }
4411   for (i=0; i<dot_nfile; i++) {
4412     a_pipe_write("%c%s", S_ADD_TO_PLAYLIST, dotfile_flist[i]);
4413     free(dotfile_flist[i]);
4414   }
4415   if (dotfile_flist) free(dotfile_flist);
4416
4417   if (Cfg.disptext == False)
4418     XtVaSetValues(file_menu[ID_HIDETXT - 100].widget,
4419                   XtNleftBitmap,check_mark, NULL);
4420   else base_height -= lyric_height;
4421
4422   if (ctl->trace_playing) {
4423     callInitTrace();
4424     a_pipe_write("%c", S_ENABLE_TRACE);
4425     base_height -= trace_v_height;
4426     toggleMark(file_menu[ID_HIDETRACE-100].widget, False);
4427     resizeToplevelACT(toplevel, NULL, NULL, NULL);
4428   } else {
4429     toggleMark(file_menu[ID_HIDETRACE-100].widget, True);
4430 #ifdef XAWPLUS
4431     resizeToplevelACT(toplevel, NULL, NULL, NULL);
4432 #endif /* XAWPLUS */
4433   }
4434 #ifdef HAVE_TIP
4435   if (Cfg.tooltips == True) xawTipSet(True);
4436 #endif /* HAVE_TIP */
4437
4438   a_pipe_write("%c%d", S_SET_VOL, amplitude);
4439   if (init_options == DEFAULT_OPTIONS) init_options = Cfg.extendopt;
4440   if (init_chorus == DEFAULT_CHORUS) init_chorus = Cfg.chorusopt;
4441   else Cfg.chorusopt = init_chorus;
4442   a_pipe_write("%c%03d", S_SET_OPTIONS, init_options);
4443   a_pipe_write("%c%03d", S_SET_CHORUS, init_chorus);
4444
4445   if (Cfg.autostart)
4446     XtVaSetValues(file_menu[ID_AUTOSTART - 100].widget,
4447                   XtNleftBitmap,check_mark, NULL);
4448   if (Cfg.autoexit) {
4449     XtVaSetValues(file_menu[ID_AUTOQUIT - 100].widget,
4450                   XtNleftBitmap,check_mark, NULL);
4451     a_pipe_write("%c", S_TOGGLE_AUTOQUIT);
4452   }
4453
4454   if (Cfg.repeat) {
4455     XtVaSetValues(file_menu[ID_REPEAT - 100].widget,
4456                   XtNleftBitmap,check_mark, NULL);
4457     repeatCB(NULL, &Cfg.repeat, NULL);
4458   }
4459   if (Cfg.shuffle) {
4460     XtVaSetValues(file_menu[ID_SHUFFLE - 100].widget,
4461                   XtNleftBitmap,check_mark, NULL);
4462     randomCB(NULL, &Cfg.shuffle, NULL);
4463   }
4464   if (Cfg.autostart) {
4465     if (max_files != 0) playCB(NULL, NULL, NULL);
4466     else if (dot_nfile != 0) {
4467       onPlayOffPause();
4468       a_pipe_write("%c", S_PREV);
4469     }
4470   }
4471   else stopCB(NULL, NULL, NULL);
4472   if ((max_files == 0) && (dot_nfile == 0))
4473     XtVaSetValues(file_menu[ID_SAVE - 100].widget, XtNsensitive,False, NULL);
4474 }
4475
4476 void a_start_interface(int pipe_in) {
4477   a_init_interface(pipe_in);
4478   XtAppMainLoop(app_con);
4479 }
4480
4481 static char *
4482 get_user_home_dir(void) {
4483   char *home, *p;
4484   struct passwd *pw;
4485
4486   home = getenv("HOME");
4487   if (home == NULL) home = getenv("home");
4488   if (home == NULL) {
4489     pw = getpwuid(getuid());
4490     if (pw == NULL) {
4491       ctl->cmsg(CMSG_WARNING, VERB_NORMAL,
4492                  "I cannot find the current user's home directory!");
4493       return NULL;
4494     }
4495     home = pw->pw_dir;
4496   }
4497   p = safe_strdup(home);
4498   return p;
4499 }
4500
4501 #include "interface.h"
4502 #if defined(IA_MOTIF)
4503 /*
4504  * Switch -lXm's vendorShellWidgetClass to -lXaw's vendorShellWidgetClass
4505  */
4506 #define vendorShellClassRec xaw_vendorShellClassRec
4507 #define vendorShellWidgetClass xaw_vendorShellWidgetClass
4508 #include "xaw_redef.c"
4509 #undef vendorShellClassRec
4510 #undef vendorShellWidgetClass
4511 extern WidgetClass vendorShellWidgetClass;
4512 extern VendorShellClassRec vendorShellClassRec;
4513 static void
4514 xaw_vendor_setup(void) {
4515   memcpy(&vendorShellClassRec, &xaw_vendorShellClassRec,
4516          sizeof(VendorShellClassRec));
4517   vendorShellWidgetClass = (WidgetClass)&xaw_vendorShellWidgetClass;
4518 }
4519 #else
4520 static void
4521 xaw_vendor_setup(void) { }
4522 #endif
4523
4524 #ifdef CLEARVALUE
4525 static void
4526 clearValue(Widget w) {
4527   Widget TextSrc;
4528
4529   XtVaGetValues(XtNameToWidget(w, "value"), XtNtextSource, &TextSrc, NULL); 
4530   XawAsciiSourceFreeString(TextSrc);
4531 }
4532 #endif /* CLEARVALUE */
4533
4534 static void
4535 simulateArrowsCB(Widget w, XtPointer client_data, XtPointer call_data) {
4536   long offset = (long)call_data;
4537   XEvent *e = (XEvent *)client_data;
4538   barfloat thumb;
4539   Dimension len;
4540
4541   XtVaGetValues(w, XtNtopOfThumb,&thumb.f, XtNlength,&len, NULL);
4542   if (abs(offset) >= len) return;
4543   thumb.f += (float)offset/(float)len;
4544   if (thumb.f < 0) thumb.f = 0;
4545   else if (thumb.f > 1) thumb.f = 1;
4546   setThumb(w, thumb);
4547   XtCallActionProc(w, (String)"NotifyThumb", e, NULL, ZERO);
4548   e->xmotion.same_screen = 0;
4549 }
4550
4551 static void
4552 StartScrollACT(Widget w, XEvent *e, String *v, Cardinal *n) {
4553   XtOrientation Orientation;
4554   long call_data;
4555
4556   if ((e->type != ButtonPress) && (e->type != ButtonRelease)) return;
4557   XtVaGetValues(w, XtNorientation,&Orientation, NULL);
4558   if (Orientation == XtorientHorizontal) call_data = e->xbutton.x;
4559   else call_data = e->xbutton.y;
4560   if (!strcasecmp("Continuous", *v)) {
4561     XtAddCallback(w, XtNscrollProc,simulateArrowsCB, (XtPointer)e);
4562     XtCallActionProc(w, (String)"NotifyScroll", e, NULL, ZERO);
4563     XtRemoveCallback(w, XtNscrollProc,simulateArrowsCB, (XtPointer)e);
4564     return;
4565   } else if (!strcasecmp("Backward", *v)) {
4566     call_data = -call_data;
4567   }
4568   XtCallCallbacks(w, XtNscrollProc, (XtPointer)call_data);
4569 }
4570
4571 /* XawScrollbarSetThumb is buggy. */
4572 static void
4573 setThumb(Widget w, barfloat u)
4574 {
4575   if (sizeof(float) > sizeof(XtArgVal)) {
4576     XtVaSetValues(w, XtNtopOfThumb,&u.f, NULL);
4577   } else {
4578     XtVaSetValues(w, XtNtopOfThumb,u.x, NULL);
4579   }
4580 }
4581
4582 static Widget seekTransientShell(Widget w) {
4583   if (w == NULL) return NULL;
4584   while (w != toplevel) {
4585     if (XtIsTransientShell(w)) return w;
4586     w = XtParent(w);
4587   }
4588   return toplevel;
4589 }
4590
4591 /* The following implements a series of toggles, to be used for output
4592  * selection either when saving a file, or changing output in options.
4593  */
4594
4595 static void
4596 freevarCB(Widget w, XtPointer client_data, XtPointer call_data) {
4597   outputs *out = (outputs *)client_data;
4598
4599   free(out->lbuf);
4600   free(out->toggleGroup);
4601 }
4602
4603 static void
4604 restoreDefaultOSelectionCB(Widget w, XtPointer client_data,
4605                            XtPointer call_data) {
4606   outputs *out = (outputs *)client_data;
4607
4608   XawToggleSetCurrent(out->formatGroup,
4609                       (XtPointer)(out->output_list + out->def));
4610 }
4611
4612 static void
4613 tnotifyCB(Widget w, XtPointer client_data, XtPointer call_data) {
4614   outputs *out;
4615   id_list *result;
4616   int i;
4617   Boolean s;
4618
4619   XtVaGetValues(w, XtNstate,&s, NULL);
4620   if (s == False) return;
4621   if ((Widget)client_data == play->formatGroup) out = play;
4622   else out = record;
4623   result = (id_list *)XawToggleGetCurrent(out->formatGroup);
4624   for (i=0; i<out->max; i++)
4625     if (result->id_char == (out->output_list[i].id_char)) break;
4626   out->current = i;
4627 }
4628
4629 static void
4630 upACT(Widget w, XEvent *e, String *v, Cardinal *n) {
4631   char s[20];
4632   Widget w1, w2;
4633   outputs *out;
4634   id_list *result;
4635   int i;
4636
4637   if (w == play->formatGroup) out = play;
4638   else out = record;
4639   result = (id_list *)XawToggleGetCurrent(out->formatGroup);
4640   for (i=0; i<out->max; i++)
4641     if (result->id_char == (out->output_list[i].id_char)) break;
4642   if (i == 0) i = out->max-1;
4643   else i--;
4644   snprintf(s, sizeof(s), "sbox_fbox%d", i);
4645   w1 = XtNameToWidget(XtParent(XtParent(w)), s);
4646   snprintf(s, sizeof(s), "fbox_toggle%d", i);
4647   w2 = XtNameToWidget(w1, s);
4648   XtVaSetValues(w2, XtNstate,True, NULL);
4649   out->current = i;
4650 }
4651
4652 static void
4653 downACT(Widget w, XEvent *e, String *v, Cardinal *n) {
4654   char s[20];
4655   Widget w1, w2;
4656   outputs *out;
4657   id_list *result;
4658   int i;
4659
4660   if (w == play->formatGroup) out = play;
4661   else out = record;
4662   result = (id_list *)XawToggleGetCurrent(out->formatGroup);
4663   for (i=0; i<out->max; i++)
4664     if (result->id_char == (out->output_list[i].id_char)) break;
4665   if (i >= out->max-1) i = 0;
4666   else i++;
4667   snprintf(s, sizeof(s), "sbox_fbox%d", i);
4668   w1 = XtNameToWidget(XtParent(XtParent(w)), s);
4669   snprintf(s, sizeof(s), "fbox_toggle%d", i);
4670   w2 = XtNameToWidget(w1, s);
4671   XtVaSetValues(w2, XtNstate,True, NULL);
4672   out->current = i;
4673 }
4674
4675 static Widget
4676 createOutputSelectionWidgets(Widget popup, Widget parent,
4677                              Widget fromVert, outputs *out,
4678                              Boolean restoreDefault) {
4679   Widget *sbox_fbox, *fbox_toggle, *fbox_label, *pw, formatGroup;
4680   char s[20];
4681   int i = out->max, j;
4682   id_list *list;
4683   char defaultToggleTranslations[] =
4684     "<EnterWindow>:         highlight(Always)\n\
4685     <LeaveWindow>:         unhighlight()\n\
4686     <Btn1Down>,<Btn1Up>:   set() notify()";
4687   XtTranslations ToggleTrans;
4688
4689   if (out == NULL) return None;
4690   list = out->output_list;
4691   pw = (Widget *)safe_malloc(sizeof(Widget) * 3 * i);
4692   out->toggleGroup = pw;
4693
4694   sbox_fbox = pw;
4695   fbox_toggle = pw + i;
4696   fbox_label = pw + 2*i;
4697   ToggleTrans = XtParseTranslationTable(defaultToggleTranslations);
4698
4699   sbox_fbox[0] = XtVaCreateManagedWidget("sbox_fbox0",boxWidgetClass,parent,
4700                                          XtNorientation,XtorientHorizontal,
4701                                          XtNbackground,bgcolor,
4702                                          XtNfromVert,fromVert,
4703                                          XtNborderWidth,0, NULL);
4704   fbox_toggle[0] = XtVaCreateManagedWidget("fbox_toggle0",toggleWidgetClass,
4705                                       sbox_fbox[0], XtNlabel,"",
4706                                       XtNtranslations,ToggleTrans,
4707                                       XtNbackground,buttonbgcolor,
4708                                       XtNforeground,togglecolor,
4709                                       XtNradioGroup,NULL, XtNborderWidth,1,
4710                                       XtNradioData,(XtPointer)list,
4711 #ifndef DONTUSEOVALTOGGLES
4712                                       XtNshapeStyle,XmuShapeOval,
4713 #endif /* !DONTUSEOVALTOGGLES */
4714                                       XtNborderColor,togglecolor,
4715                                       XtNinternalWidth,3, XtNinternalHeight,1,
4716                                       XtNwidth,17, XtNheight,17, NULL);
4717   fbox_label[0] = XtVaCreateManagedWidget("fbox_label0",labelWidgetClass,
4718                                             sbox_fbox[0], XtNbackground,bgcolor,
4719                                             XtNlabel,list[0].id_name,
4720                                             XtNforeground,textcolor,
4721                                             XtNfromHoriz,fbox_toggle[0],
4722                                             XtNborderWidth,0, NULL);
4723   out->formatGroup = formatGroup = fbox_toggle[0];
4724   XtAddCallback(fbox_toggle[0], XtNcallback,tnotifyCB,
4725                 (XtPointer)formatGroup);
4726
4727   for (j = 1; j < i; j++) {
4728     snprintf(s, sizeof(s), "sbox_fbox%d", j);
4729     sbox_fbox[j] = XtVaCreateManagedWidget(s,boxWidgetClass,parent,
4730                                            XtNorientation,XtorientHorizontal,
4731                                            XtNfromVert,sbox_fbox[j-1],
4732                                            XtNbackground,bgcolor,
4733                                            XtNborderWidth,0, NULL);
4734     snprintf(s, sizeof(s), "fbox_toggle%d", j);
4735     fbox_toggle[j] = XtVaCreateManagedWidget(s,toggleWidgetClass,sbox_fbox[j],
4736                                         XtNbackground,buttonbgcolor,
4737                                         XtNforeground,togglecolor,
4738                                         XtNradioData,(XtPointer)(list + j),
4739                                         XtNradioGroup,formatGroup,
4740                                         XtNfromVert,fbox_toggle[j-1],
4741 #ifndef DONTUSEOVALTOGGLES
4742                                         XtNshapeStyle,XmuShapeOval,
4743 #endif /* !DONTUSEOVALTOGGLES */
4744                                         XtNinternalWidth,3, XtNinternalHeight,1,
4745                                         XtNwidth,17, XtNheight,17, XtNlabel,"",
4746                                         XtNtranslations,ToggleTrans,
4747                                         XtNborderColor,togglecolor,
4748                                         XtNborderWidth,1, NULL);
4749     XtAddCallback(fbox_toggle[j], XtNcallback,tnotifyCB,
4750                   (XtPointer)formatGroup);
4751     snprintf(s, sizeof(s), "fbox_label%d", j);
4752     fbox_label[j] = XtVaCreateManagedWidget(s,labelWidgetClass,sbox_fbox[j],
4753                                               XtNfromHoriz,fbox_toggle[j],
4754                                               XtNlabel,list[j].id_name,
4755                                               XtNforeground,textcolor,
4756                                               XtNbackground,bgcolor,
4757                                               XtNjustify,XtJustifyLeft,
4758                                               XtNborderWidth,0, NULL);
4759   }
4760   XtCallActionProc(fbox_toggle[out->def], (String)"set", NULL, NULL, ZERO);
4761
4762   XtAddCallback(popup, XtNdestroyCallback,freevarCB,
4763                 (XtPointer)out);
4764   if (restoreDefault == True)
4765     XtAddCallback(popup, XtNpopdownCallback,restoreDefaultOSelectionCB,
4766                   (XtPointer)out);
4767   XtInstallAccelerators(parent, formatGroup);
4768   XtInstallAccelerators(popup, formatGroup);
4769
4770   return sbox_fbox[i-1];
4771 }
4772
4773 /* End output selection routines */
4774
4775 #ifdef HAVE_TIP
4776 static void
4777 TipEnable(Widget w, String s) {
4778 #ifdef XAW3D
4779   XawTipEnable(w, s);
4780 #elif defined(XAWPLUS)
4781   XtVaSetValues(w, XtNhelpText,s, XtNuseHelp,True, NULL);
4782 #else
4783   XawTipEnable(w);
4784 #endif /* !XAW3D */
4785 }
4786
4787 static void
4788 TipDisable(Widget w) {
4789 #ifdef XAWPLUS
4790   XtVaSetValues(w, XtNuseHelp,False, NULL);
4791 #else
4792   XawTipDisable(w);
4793 #endif /* XAWPLUS */
4794 }
4795
4796 static void
4797 xawtipsetACT(Widget w, XEvent *e, String *v, Cardinal *n) {
4798   int state = atoi(*v);
4799
4800   if (state == -1) Cfg.tooltips ^= True;
4801   else Cfg.tooltips = (Boolean)state;
4802   xawTipSet(Cfg.tooltips);
4803 }
4804
4805 static void
4806 xawTipSet(Boolean tooltips) {
4807   if (tooltips == True) {
4808     TipEnable(play_b, "Play");
4809     TipEnable(pause_b, "Pause");
4810     TipEnable(stop_b, "Stop");
4811     TipEnable(prev_b, "Previous");
4812     TipEnable(back_b, "Back");
4813     TipEnable(fwd_b, "Forward");
4814     TipEnable(next_b, "Next");
4815     TipEnable(quit_b, "Quit");
4816     TipEnable(random_b, "Shuffle");
4817     TipEnable(repeat_b, "Repeat");
4818     if (ctl->trace_playing) {
4819       TipEnable(fast_b, "Increase tempo");
4820       TipEnable(slow_b, "Decrease Tempo");
4821       TipEnable(keyup_b, "Raise pitch");
4822       TipEnable(keydown_b, "Lower pitch");
4823     }
4824   } else {
4825     TipDisable(play_b);
4826     TipDisable(pause_b);
4827     TipDisable(stop_b);
4828     TipDisable(prev_b);
4829     TipDisable(back_b);
4830     TipDisable(fwd_b);
4831     TipDisable(next_b);
4832     TipDisable(quit_b);
4833     TipDisable(random_b);
4834     TipDisable(repeat_b);
4835     if (ctl->trace_playing) {
4836       TipDisable(fast_b);
4837       TipDisable(slow_b);
4838       TipDisable(keyup_b);
4839       TipDisable(keydown_b);
4840     }
4841   }
4842 }
4843 #else
4844 static void
4845 xawtipsetACT(Widget w, XEvent *e, String *v, Cardinal *n) { }
4846 #endif /* HAVE_TIP */