1 #include "snd.h"
2 
3 #include <X11/IntrinsicP.h>
4 #include <stdint.h>
5 #include <inttypes.h>
6 
7 #if __GNUC__
8 #ifdef LESSTIF_VERSION
9   /* moved the warning here so it only is displayed once */
10   #warning You appear to be using Lesstif: this is not recommended!  Expect bugs...
11 #endif
12 #if (XmVERSION == 1)
13   #warning Motif 1 is no longer supported -- this has little chance of working...
14 #endif
15 #endif
16 
17 
18 /* In case of X error that simply exits without any stack trace, first
19  *
20  *     XSynchronize(dpy, true);
21  *     XSync(dpy, true);
22  *
23  * around line 30817 (where ss->mainapp gets set)
24  * then if still trouble, make an X error handler:
25  *
26  *    static XErrorHandler old_handler = (XErrorHandler) 0;
27  *    static int ApplicationErrorHandler(Display *display, XErrorEvent *theEvent)
28  *    {
29  *      (void) fprintf(stderr, "Xlib error: error code %d request code %d\n", theEvent->error_code, theEvent->request_code);
30  *      abort();
31  *      return 0;
32  *    }
33  *
34  * and at the same point as before
35  *
36  *      old_handler = XSetErrorHandler(ApplicationErrorHandler);
37  *
38  * code 8 seems to mean a newly created window is unhappy (tooltip for example)
39  */
40 
41 
get_xm_font(XFontStruct * ignore,const char * font,const char * tag)42 static XmRenderTable get_xm_font(XFontStruct *ignore, const char *font, const char *tag)
43 {
44   XmRendition tmp;
45   XmRenderTable tabl;
46   int n;
47   Arg args[12];
48 
49   n = 0;
50   XtSetArg(args[n], XmNfontName, font); n++;
51   XtSetArg(args[n], XmNfontType, XmFONT_IS_FONT); n++;
52   XtSetArg(args[n], XmNloadModel, XmLOAD_IMMEDIATE); n++;
53   tmp = XmRenditionCreate(main_shell(ss), (char *)tag, args, n);
54   tabl = XmRenderTableAddRenditions(NULL, &tmp, 1, XmMERGE_NEW);
55 
56   /* XmRenditionFree(tmp); */ /* valgrind thinks this is a bad idea */
57   return(tabl);
58 }
59 
60 
61 /* to see all fonts: (format #f "~{~A~%~}" (XListFonts (XtDisplay (cadr (main-widgets))) "*" 10000))
62  */
63 
set_tiny_font(const char * font)64 bool set_tiny_font(const char *font)
65 {
66   XFontStruct *fs = NULL;
67   fs = XLoadQueryFont(main_display(ss), font);
68   if (fs)
69     {
70       /* it's not clear to me whether this is safe -- what if two fontstructs are pointing to the same font? */
71       if (TINY_FONT(ss)) XFreeFont(main_display(ss), TINY_FONT(ss));
72       if (tiny_font(ss)) free(tiny_font(ss));
73       in_set_tiny_font(mus_strdup(font));
74       TINY_FONT(ss) = fs;
75       if (ss->tiny_fontlist) XM_FONT_FREE(ss->tiny_fontlist);
76       ss->tiny_fontlist = get_xm_font(TINY_FONT(ss), font, "tiny_font");
77       return(true);
78     }
79   return(false);
80 }
81 
82 
set_listener_font(const char * font)83 bool set_listener_font(const char *font)
84 {
85   XFontStruct *fs = NULL;
86   fs = XLoadQueryFont(main_display(ss), font);
87   if (fs)
88     {
89       if (LISTENER_FONT(ss)) XFreeFont(main_display(ss), LISTENER_FONT(ss));
90       if (listener_font(ss)) free(listener_font(ss));
91       in_set_listener_font(mus_strdup(font));
92       LISTENER_FONT(ss) = fs;
93       if (ss->listener_fontlist) XM_FONT_FREE(ss->listener_fontlist);
94       ss->listener_fontlist = get_xm_font(LISTENER_FONT(ss), font, "listener_font");
95       set_listener_text_font();
96       return(true);
97     }
98   return(false);
99 }
100 
101 
set_peaks_font(const char * font)102 bool set_peaks_font(const char *font)
103 {
104   XFontStruct *fs = NULL;
105   fs = XLoadQueryFont(main_display(ss), font);
106   if (fs)
107     {
108       if (PEAKS_FONT(ss)) XFreeFont(main_display(ss), PEAKS_FONT(ss));
109       if (peaks_font(ss)) free(peaks_font(ss));
110       in_set_peaks_font(mus_strdup(font));
111       PEAKS_FONT(ss) = fs;
112       if (ss->peaks_fontlist) XM_FONT_FREE(ss->peaks_fontlist);
113       ss->peaks_fontlist = get_xm_font(PEAKS_FONT(ss), font, "peaks_font");
114       return(true);
115     }
116   return(false);
117 }
118 
119 
set_bold_peaks_font(const char * font)120 bool set_bold_peaks_font(const char *font)
121 {
122   XFontStruct *fs = NULL;
123   fs = XLoadQueryFont(main_display(ss), font);
124   if (fs)
125     {
126       if (BOLD_PEAKS_FONT(ss)) XFreeFont(main_display(ss), BOLD_PEAKS_FONT(ss));
127       if (bold_peaks_font(ss)) free(bold_peaks_font(ss));
128       in_set_bold_peaks_font(mus_strdup(font));
129       BOLD_PEAKS_FONT(ss) = fs;
130       if (ss->bold_peaks_fontlist) XM_FONT_FREE(ss->bold_peaks_fontlist);
131       ss->bold_peaks_fontlist = get_xm_font(BOLD_PEAKS_FONT(ss), font, "bold_peaks_font");
132       return(true);
133     }
134   return(false);
135 }
136 
137 
set_axis_label_font(const char * font)138 bool set_axis_label_font(const char *font)
139 {
140   XFontStruct *fs = NULL;
141   fs = XLoadQueryFont(main_display(ss), font);
142   if (fs)
143     {
144       if (AXIS_LABEL_FONT(ss)) XFreeFont(main_display(ss), AXIS_LABEL_FONT(ss));
145       if (axis_label_font(ss)) free(axis_label_font(ss));
146       in_set_axis_label_font(mus_strdup(font));
147       AXIS_LABEL_FONT(ss) = fs;
148 #if HAVE_GL
149       reload_label_font();
150 #endif
151       return(true);
152     }
153   return(false);
154 }
155 
156 
set_axis_numbers_font(const char * font)157 bool set_axis_numbers_font(const char *font)
158 {
159   XFontStruct *fs = NULL;
160   fs = XLoadQueryFont(main_display(ss), font);
161   if (fs)
162     {
163       if (AXIS_NUMBERS_FONT(ss)) XFreeFont(main_display(ss), AXIS_NUMBERS_FONT(ss));
164       if (axis_numbers_font(ss)) free(axis_numbers_font(ss));
165       in_set_axis_numbers_font(mus_strdup(font));
166       AXIS_NUMBERS_FONT(ss) = fs;
167 #if HAVE_GL
168       reload_number_font();
169 #endif
170       return(true);
171     }
172   return(false);
173 }
174 
175 
mark_name_width(const char * txt)176 int mark_name_width(const char *txt)
177 {
178   if (txt)
179     return(XTextWidth(PEAKS_FONT(ss), txt, strlen(txt)));
180   return(0);
181 }
182 
183 
label_width(const char * txt,bool use_tiny_font)184 int label_width(const char *txt, bool use_tiny_font)
185 {
186   if (txt)
187     return(XTextWidth((use_tiny_font) ? TINY_FONT(ss) : AXIS_LABEL_FONT(ss), txt, strlen(txt)));
188   else return(0);
189 }
190 
191 
number_width(const char * num,bool use_tiny_font)192 int number_width(const char *num, bool use_tiny_font)
193 {
194   if (num)
195     return(XTextWidth((use_tiny_font) ? TINY_FONT(ss) : AXIS_NUMBERS_FONT(ss), num, strlen(num)));
196   return(0);
197 }
198 
199 
number_height(XFontStruct * numbers_font)200 int number_height(XFontStruct *numbers_font)
201 {
202   return(numbers_font->ascent);
203 }
204 
205 
label_height(bool use_tiny_font)206 int label_height(bool use_tiny_font)
207 {
208   XFontStruct *label_font;
209   if (use_tiny_font)
210     label_font = TINY_FONT(ss);
211   else label_font = AXIS_LABEL_FONT(ss);
212   return(label_font->ascent + label_font->descent);
213 }
214 
215 
clear_window(graphics_context * ax)216 void clear_window(graphics_context *ax)
217 {
218   if ((ax) && (ax->dp) && (ax->wn))
219     XClearWindow(ax->dp, ax->wn);
220 }
221 
222 
map_over_children(Widget w,void (* func)(Widget uw))223 static void map_over_children(Widget w, void (*func)(Widget uw))
224 {
225   /* apply func to each child in entire tree beneath top widget */
226   /* taken from Douglas Young, "Motif Debugging and Performance Tuning" Prentice-Hall 1995 */
227   /* used mostly to get colors right in environments with "convenience" widgets */
228   if (w)
229     {
230       uint32_t i;
231       (*func)(w);
232       if (XtIsComposite(w))
233 	{
234 	  CompositeWidget cw = (CompositeWidget)w;
235 	  for (i = 0; i < cw->composite.num_children; i++)
236 	    map_over_children(cw->composite.children[i], func);
237 	}
238 
239       if (XtIsWidget(w))
240 	for (i = 0; i < w->core.num_popups; i++)
241 	  map_over_children(w->core.popup_list[i], func);
242     }
243 }
244 
245 
map_over_children_with_color(Widget w,void (* func)(Widget uw,color_t color),color_t color)246 void map_over_children_with_color(Widget w, void (*func)(Widget uw, color_t color), color_t color)
247 {
248   if (w)
249     {
250       uint32_t i;
251       (*func)(w, color);
252       if (XtIsComposite(w))
253 	{
254 	  CompositeWidget cw = (CompositeWidget)w;
255 	  for (i = 0; i < cw->composite.num_children; i++)
256 	    map_over_children_with_color(cw->composite.children[i], func, color);
257 	}
258 
259       if (XtIsWidget(w))
260 	for (i = 0; i < w->core.num_popups; i++)
261 	  map_over_children_with_color(w->core.popup_list[i], func, color);
262     }
263 }
264 
265 
raise_dialog(Widget w)266 static void raise_dialog(Widget w)
267 {
268   /* since we're using non-transient message dialogs, the dialog window can become completely
269    * hidden behind other windows, with no easy way to raise it back to the top, so...
270    */
271   if ((w) && (XtIsManaged(w)))
272     {
273       Widget parent;
274       parent = XtParent(w);
275       if ((parent) &&
276 	  (XtIsSubclass(parent, xmDialogShellWidgetClass)))
277 	XtPopup(parent, XtGrabNone);
278       /* XtGrabNone means don't lock out events to rest of App (i.e. modeless dialog) */
279     }
280 }
281 
282 
set_main_color_of_widget(Widget w)283 static void set_main_color_of_widget(Widget w)
284 {
285   if (XtIsWidget(w))
286     {
287       if (XmIsScrollBar(w))
288 	XmChangeColor(w, (Pixel)ss->position_color);
289       else
290 	{
291 	  Pixel cur_color;
292 	  XtVaGetValues(w, XmNbackground, &cur_color, NULL);
293 	  if ((cur_color != ss->highlight_color) &&
294 	      (cur_color != ss->white))
295 	    XmChangeColor(w, (Pixel)ss->basic_color);
296 	}
297     }
298 }
299 
300 
set_label(Widget label,const char * str)301 void set_label(Widget label, const char *str)
302 {
303   XmString s1;
304   s1 = XmStringCreateLocalized((char *)str);
305   XtVaSetValues(label, XmNlabelString, s1, NULL);
306   XmStringFree(s1);
307 }
308 
309 
get_label(Widget label)310 static char *get_label(Widget label)
311 {
312   char *text;
313   XmString str = NULL;
314   XtVaGetValues(label, XmNlabelString, &str, NULL);
315   if (XmStringEmpty(str)) return(NULL);
316   text = (char *)XmStringUnparse(str, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
317   XmStringFree(str);
318   return(text);
319 }
320 
321 
set_button_label(Widget label,const char * str)322 void set_button_label(Widget label, const char *str)
323 {
324   set_label(label, str);
325 }
326 
327 
set_title(const char * title)328 void set_title(const char *title)
329 {
330   XtVaSetValues(main_shell(ss), XmNtitle, (char *)title, NULL);
331 }
332 
333 
goto_window(Widget text)334 void goto_window(Widget text)
335 {
336   if (XmIsTraversable(text))
337     XmProcessTraversal(text, XmTRAVERSE_CURRENT);
338 }
339 
340 
make_callback_list(XtCallbackProc callback,XtPointer closure)341 static XtCallbackList make_callback_list(XtCallbackProc callback, XtPointer closure)
342 {
343   XtCallbackList nlist;
344   nlist = (XtCallbackList)calloc(2, sizeof(XtCallbackRec));
345   nlist[0].callback = callback;
346   nlist[0].closure = closure;
347   nlist[1].callback = NULL;
348   nlist[1].closure = NULL;
349   return(nlist);
350 }
351 
352 
353 #include <Xm/SashP.h>
color_sashes(Widget w)354 static void color_sashes(Widget w)
355 {
356   if ((XtIsWidget(w)) &&
357       (XtIsSubclass(w, xmSashWidgetClass)))
358     XmChangeColor(w, (Pixel)ss->sash_color);
359 }
360 
361 
check_for_event(void)362 void check_for_event(void)
363 {
364   /* this is needed to force label updates and provide interrupts from long computations */
365   XEvent event;
366   XtInputMask msk = 0;
367   XtAppContext app;
368 
369   if (ss->checking_explicitly) return;
370   ss->checking_explicitly = true;
371 
372   app = main_app(ss);
373   while (true)
374     {
375       msk = XtAppPending(app);
376       /* if (msk & (XtIMXEvent | XtIMAlternateInput)) */
377       /* if (msk & XtIMXEvent) */
378 	/* was also tracking alternate input events, but these are problematic if libfam is in use (even with check)
379 	 *   but libfam is now long-since forgotten; new form below is thanks to Tito Latini
380 	 */
381       if ((msk & (XtIMXEvent | XtIMAlternateInput)) == XtIMXEvent)
382 	{
383 	  XtAppNextEvent(app, &event);
384 	  XtDispatchEvent(&event);
385 	  /* widget = XtWindowToWidget(event.xany.display, event.xany.window); */
386 	}
387       else break;
388     }
389   ss->checking_explicitly = false;
390 }
391 
392 
color_cursor(Pixel color)393 void color_cursor(Pixel color)
394 {
395   ss->cursor_color = color;
396 #if HAVE_SCHEME
397   s7_symbol_set_value(s7, ss->cursor_color_symbol, Xen_wrap_pixel(color));
398 #endif
399   XSetForeground(main_display(ss), ss->cursor_gc, (Pixel)(XOR(color, ss->graph_color)));
400   XSetForeground(main_display(ss), ss->selected_cursor_gc, (Pixel)(XOR(color, ss->selected_graph_color)));
401 }
402 
403 
color_marks(Pixel color)404 void color_marks(Pixel color)
405 {
406   ss->mark_color = color;
407 #if HAVE_SCHEME
408   s7_symbol_set_value(s7, ss->mark_color_symbol, Xen_wrap_pixel(color));
409 #endif
410   XSetForeground(main_display(ss), ss->mark_gc, (Pixel)(XOR(color, ss->graph_color)));
411   XSetForeground(main_display(ss), ss->selected_mark_gc, (Pixel)(XOR(color, ss->selected_graph_color)));
412 }
413 
414 
color_selection(Pixel color)415 void color_selection(Pixel color)
416 {
417   ss->selection_color = color;
418 #if HAVE_SCHEME
419   s7_symbol_set_value(s7, ss->selection_color_symbol, Xen_wrap_pixel(color));
420 #endif
421   XSetForeground(main_display(ss), ss->selection_gc, (Pixel)(XOR(color, ss->graph_color)));
422   XSetForeground(main_display(ss), ss->selected_selection_gc, (Pixel)(XOR(color, ss->selected_graph_color)));
423 }
424 
425 
color_graph(Pixel color)426 void color_graph(Pixel color)
427 {
428   Display *dpy;
429   dpy = main_display(ss);
430   XSetBackground(dpy, ss->basic_gc, color);
431   XSetForeground(dpy, ss->erase_gc, color);
432   XSetForeground(dpy, ss->selection_gc, (Pixel)(XOR(ss->selection_color, color)));
433   XSetForeground(dpy, ss->cursor_gc, (Pixel)(XOR(ss->cursor_color, color)));
434   XSetForeground(dpy, ss->mark_gc, (Pixel)(XOR(ss->mark_color, color)));
435 }
436 
437 
color_selected_graph(Pixel color)438 void color_selected_graph(Pixel color)
439 {
440   Display *dpy;
441   dpy = main_display(ss);
442   XSetBackground(dpy, ss->selected_basic_gc, color);
443   XSetForeground(dpy, ss->selected_erase_gc, color);
444   XSetForeground(dpy, ss->selected_selection_gc, (Pixel)(XOR(ss->selection_color, color)));
445   XSetForeground(dpy, ss->selected_cursor_gc, (Pixel)(XOR(ss->cursor_color, color)));
446   XSetForeground(dpy, ss->selected_mark_gc, (Pixel)(XOR(ss->mark_color, color)));
447 }
448 
449 
color_data(Pixel color)450 void color_data(Pixel color)
451 {
452   Display *dpy;
453   dpy = main_display(ss);
454   XSetForeground(dpy, ss->basic_gc, color);
455   XSetBackground(dpy, ss->erase_gc, color);
456 }
457 
458 
color_selected_data(Pixel color)459 void color_selected_data(Pixel color)
460 {
461   Display *dpy;
462   dpy = main_display(ss);
463   XSetForeground(dpy, ss->selected_basic_gc, color);
464   XSetBackground(dpy, ss->selected_erase_gc, color);
465 }
466 
467 
recolor_graph(chan_info * cp,bool selected)468 void recolor_graph(chan_info *cp, bool selected)
469 {
470   XtVaSetValues(channel_graph(cp), XmNbackground, (selected) ? ss->selected_graph_color : ss->graph_color, NULL);
471 }
472 
473 
set_mix_color(Pixel color)474 void set_mix_color(Pixel color)
475 {
476   Display *dpy;
477   dpy = main_display(ss);
478   ss->mix_color = color;
479 #if HAVE_SCHEME
480   s7_symbol_set_value(s7, ss->mix_color_symbol, Xen_wrap_pixel(color));
481 #endif
482   XSetForeground(dpy, ss->mix_gc, color);
483 
484 }
485 
486 
set_sensitive(Widget wid,bool val)487 void set_sensitive(Widget wid, bool val)
488 {
489   if (wid) XtSetSensitive(wid, val);
490 }
491 
492 
set_toggle_button(Widget wid,bool val,bool passed,void * ignore)493 void set_toggle_button(Widget wid, bool val, bool passed, void *ignore)
494 {
495   XmToggleButtonSetState(wid, (Boolean)val, (Boolean)passed);
496 }
497 
498 
widget_height(Widget w)499 Dimension widget_height(Widget w)
500 {
501   Dimension height;
502   XtVaGetValues(w, XmNheight, &height, NULL);
503   return(height);
504 }
505 
506 
widget_width(Widget w)507 Dimension widget_width(Widget w)
508 {
509   Dimension width;
510   XtVaGetValues(w, XmNwidth, &width, NULL);
511   return(width);
512 }
513 
514 
set_widget_height(Widget w,Dimension height)515 void set_widget_height(Widget w, Dimension height)
516 {
517   XtVaSetValues(w, XmNheight, height, NULL);
518 }
519 
520 
set_widget_width(Widget w,Dimension width)521 void set_widget_width(Widget w, Dimension width)
522 {
523   XtVaSetValues(w, XmNwidth, width, NULL);
524 }
525 
526 
set_widget_size(Widget w,Dimension width,Dimension height)527 void set_widget_size(Widget w, Dimension width, Dimension height)
528 {
529   XtVaSetValues(w, XmNwidth, width, XmNheight, height, NULL);
530 }
531 
532 
widget_x(Widget w)533 Position widget_x(Widget w)
534 {
535   Position x;
536   XtVaGetValues(w, XmNx, &x, NULL);
537   return(x);
538 }
539 
540 
widget_y(Widget w)541 Position widget_y(Widget w)
542 {
543   Position y;
544   XtVaGetValues(w, XmNy, &y, NULL);
545   return(y);
546 }
547 
548 
set_widget_x(Widget w,Position x)549 void set_widget_x(Widget w, Position x)
550 {
551   XtVaSetValues(w, XmNx, x, NULL);
552 }
553 
554 
set_widget_y(Widget w,Position y)555 void set_widget_y(Widget w, Position y)
556 {
557   XtVaSetValues(w, XmNy, y, NULL);
558 }
559 
560 
set_widget_position(Widget w,Position x,Position y)561 void set_widget_position(Widget w, Position x, Position y)
562 {
563   XtVaSetValues(w, XmNx, x, XmNy, y, NULL);
564 }
565 
566 
add_work_proc(XtWorkProc func,XtPointer data)567 idle_t add_work_proc(XtWorkProc func, XtPointer data)
568 {
569   /* during auto-testing I need to force the background procs to run to completion */
570   if (with_background_processes(ss))
571     return(XtAppAddWorkProc(main_app(ss), func, data));
572   else
573     {
574       while (((*func)(data)) == BACKGROUND_CONTINUE) ;
575       return((idle_t)0);
576     }
577 }
578 
579 
attach_all_sides(Arg * args,int n)580 static int attach_all_sides(Arg *args, int n)
581 {
582   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
583   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
584   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
585   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
586   return(n);
587 }
588 
589 
widget_int_to_text(Widget w,int val)590 static void widget_int_to_text(Widget w, int val)
591 {
592   char *str;
593   str = (char *)calloc(16, sizeof(char));
594   snprintf(str, 16, "%d", val);
595   XmTextFieldSetString(w, str);
596   free(str);
597 }
598 
599 
widget_mus_long_t_to_text(Widget w,mus_long_t val)600 static void widget_mus_long_t_to_text(Widget w, mus_long_t val)
601 {
602   char *str;
603   str = (char *)calloc(32, sizeof(char));
604   snprintf(str, 32, "%" print_mus_long, val);
605   XmTextFieldSetString(w, str);
606   free(str);
607 }
608 
609 
rotate_text(Widget w,const char * str,XFontStruct * font,mus_float_t angle_in_degrees,int * nw,int * nh,Pixel bg,Pixel fg,GC d_gc)610 static Pixmap rotate_text(Widget w, const char *str, XFontStruct *font, mus_float_t angle_in_degrees, int *nw, int *nh, Pixel bg, Pixel fg, GC d_gc)
611 {
612   /* rotate clockwise by angle_in_degrees degrees (i.e. 45 points text south-east),
613    * new bounding box (text centered in it) returned in nw and nh
614    * bg = background color, fg = foreground (text) color)
615    */
616   mus_float_t matrix[4];
617   mus_float_t angle_in_radians;
618   XImage *before, *after;
619   Pixmap pix, rotpix;
620   uint32_t width, height, depth, nwidth, nheight, x, y, nx, ny, tx, ty, depth_bytes;
621   char *data;
622   unsigned long px;
623   Display *dp;
624   Drawable wn;
625   Visual *vis;
626   int scr;
627   int bx0 = 0, bx1 = 0, by0 = 0, by1 = 0, b;
628   if (!str) return(BadPixmap);
629 
630   angle_in_radians = mus_degrees_to_radians(angle_in_degrees);
631   matrix[0] = cos(angle_in_radians);
632   matrix[1] = sin(angle_in_radians);
633   matrix[2] = -sin(angle_in_radians);
634   matrix[3] = cos(angle_in_radians);
635 
636   dp = XtDisplay(w);
637   wn = XtWindow(w);
638   scr = DefaultScreen(dp);
639   vis = DefaultVisual(dp, scr);
640 
641   XtVaGetValues(w, XmNdepth, &depth, NULL);
642   depth_bytes = (depth >> 3);
643   if (depth_bytes == 0) depth_bytes = 1; /* unsigned so can't be negative */
644 
645   /* find extent of original text, expand out to byte boundaries */
646   XSetFont(dp, d_gc, font->fid);
647   width = XTextWidth(font, str, strlen(str)) + 8;
648   height = (font->ascent + font->descent) + 8;
649   if (width % 8) width = 8 * (1 + (int)(width / 8));
650   if (height % 8) height = 8 * (1 + (int)(height / 8));
651 
652   /* get bounding box of rotated text (this could be simplfied -- used to involve scaling) */
653   b = (int)(width * matrix[0]);
654   if (b < 0) bx0 = b; else bx1 = b;
655   b = (int)(height * matrix[2]);
656   if (b < 0) bx0 += b; else bx1 += b;
657   b = (int)(width * matrix[1]);
658   if (b < 0) by0 = b; else by1 = b;
659   b = (int)(height * matrix[3]);
660   if (b < 0) by0 += b; else by1 += b;
661 
662   /* set translation vector so we're centered in the resultant pixmap */
663   if (bx0 < 0) tx = -bx0; else tx = 0;
664   if (by0 < 0) ty = -by0; else ty = 0;
665   nx = bx1 - bx0;
666   ny = by1 - by0;
667 
668   /* expand result bounds to byte boundaries */
669   if (nx % 8) nwidth = 8 * (1 + (int)(nx / 8)); else nwidth = nx;
670   if (ny % 8) nheight = 8 * (1 + (int)(ny / 8)); else nheight = ny;
671   (*nw) = nwidth;
672   (*nh) = nheight;
673 
674   XSetBackground(dp, d_gc, bg);
675   XSetForeground(dp, d_gc, bg);
676 
677   /* create pixmaps, fill with background color, write string to pix */
678   pix = XCreatePixmap(dp, wn, width, height, depth);
679   rotpix= XCreatePixmap(dp, wn, nwidth, nheight, depth);
680   XFillRectangle(dp, pix, d_gc, 0, 0, width, height);
681   XFillRectangle(dp, rotpix, d_gc, 0, 0, nwidth, nheight);
682 #if HAVE_SUN
683   XSync(dp, 0);
684   /* needed to get the numbers drawn at all */
685 #endif
686   XSetForeground(dp, d_gc, fg);
687   XDrawImageString(dp, pix, d_gc, 4, height - 4, str, strlen(str));
688 
689   /* dump pixmap bits into an image; image data will be freed automatically later */
690   data = (char *)calloc((width + 1) * (height + 1) * depth_bytes, sizeof(char)); /* not calloc since X will free this */
691   before = XCreateImage(dp, vis, depth, XYPixmap, 0, data, width, height, 8, 0);
692   XGetSubImage(dp, pix, 0, 0, width, height, AllPlanes, XYPixmap, before, 0, 0);
693   data = (char *)calloc((nwidth + 1) * (nheight + 1) * depth_bytes, sizeof(char));
694   after = XCreateImage(dp, vis, depth, XYPixmap, 0, data, nwidth, nheight, 8, 0);
695 
696   /* clear background of result image */
697   for (x = 0; x < nwidth; x++)
698     for (y = 0; y < nheight; y++)
699       XPutPixel(after, x, y, bg);
700 
701   /* write rotated pixels to result image */
702   for (x = 0; x < width; x++)
703     for (y = 0; y < height; y++)
704       {
705 	px = XGetPixel(before, x, y);
706 	if (px != bg)
707 	  XPutPixel(after,
708 		    mus_iclamp(0, (int)snd_round(tx + x * matrix[0] + y * matrix[2]), nwidth - 1),
709 		    mus_iclamp(0, (int)snd_round(ty + x * matrix[1] + y * matrix[3]), nheight - 1),
710 		    px);
711       }
712 
713   /* dump image into result pixmap (needed for later display) */
714   XPutImage(dp, rotpix, d_gc, after, 0, 0, 0, 0, nwidth, nheight);
715 
716   /* cleanup */
717   XDestroyImage(before);  /* frees data as well */
718   XDestroyImage(after);
719   XFreePixmap(dp, pix);
720   return(rotpix);
721 }
722 
723 
draw_rotated_axis_label(chan_info * cp,graphics_context * ax,const char * text,int x0,int y0)724 void draw_rotated_axis_label(chan_info *cp, graphics_context *ax, const char *text, int x0, int y0)
725 {
726   Pixmap pix;
727   int h = 0, w = 0;
728   XGCValues gv;
729   Display *dp;
730   Widget widget;
731 
732   if ((cp->chan > 0) && (cp->sound->channel_style == CHANNELS_COMBINED))
733     widget = channel_graph(cp->sound->chans[0]);
734   else widget = channel_graph(cp);
735   dp = XtDisplay(widget);
736   XGetGCValues(main_display(ss), ax->gc, GCForeground | GCBackground, &gv);
737 
738   pix = rotate_text(widget, text, AXIS_LABEL_FONT(ss), -90.0, &w, &h, gv.background, gv.foreground, ax->gc);
739 
740   XCopyArea(dp, pix, XtWindow(widget), ax->gc, 0, 0, w, h, x0, y0); /* XtWindow?? */
741   XFreePixmap(dp, pix);
742 }
743 
744 
ensure_list_row_visible(widget_t list,int pos)745 static void ensure_list_row_visible(widget_t list, int pos)
746 {
747   if (pos >= 0)
748     {
749       int top, visible, num_rows;
750       XtVaGetValues(list,
751 		    XmNtopItemPosition, &top,
752 		    XmNvisibleItemCount, &visible,
753 		    XmNitemCount, &num_rows,
754 		    NULL);
755       if (pos <= top)
756 	XmListSetPos(list, pos); /* was pos+1?? (new file dialog sample type list off by 1 in that case) */
757       else
758 	{
759 	  if (pos >= (top + visible))
760 	    {
761 	      if ((pos + visible) > num_rows)
762 		XmListSetBottomPos(list, num_rows);
763 	      else XmListSetPos(list, pos);
764 	    }
765 	}
766     }
767 }
768 
769 
ensure_scrolled_window_row_visible(widget_t list,int row,int num_rows)770 static void ensure_scrolled_window_row_visible(widget_t list, int row, int num_rows)
771 {
772   int minimum, maximum, value, size, new_value, increment, page_increment;
773   Widget scrollbar, work_window;
774 
775   XtVaGetValues(list,
776 		XmNverticalScrollBar, &scrollbar,
777 		XmNworkWindow, &work_window,
778 		NULL);
779 
780   XtVaGetValues(scrollbar,
781 		XmNminimum, &minimum,
782 		XmNmaximum, &maximum,
783 		XmNvalue, &value,
784 		XmNsliderSize, &size,
785 		XmNincrement, &increment, /* needed for XmScrollBarSetValues which is needed to force list display update */
786 		XmNpageIncrement, &page_increment,
787 		NULL);
788 
789   maximum -= size;
790   if (row == 0)
791     new_value = 0;
792   else
793     {
794       if (row >= (num_rows - 1))
795 	new_value = maximum;
796       else new_value = (int)((row + 0.5) * ((double)(maximum - minimum) / (double)(num_rows - 1)));
797     }
798   XmScrollBarSetValues(scrollbar, new_value, size, increment, page_increment, true);
799 }
800 
801 
multi_line_label(const char * s,int * lines)802 static XmString multi_line_label(const char *s, int *lines)
803 {
804   /* taken from the Motif FAQ */
805   XmString xms1, xms2, line, separator;
806   char *p, *tmp;
807 
808   (*lines) = 1;
809   tmp = mus_strdup(s);
810   separator = XmStringSeparatorCreate();
811   p = strtok(tmp, "\n");
812   xms1 = XmStringCreateLocalized(p);
813 
814   p = strtok(NULL, "\n");
815   while (p)
816     {
817       (*lines)++;
818       line = XmStringCreateLocalized(p);
819       xms2 = XmStringConcat(xms1, separator);
820       XmStringFree(xms1);
821       xms1 = XmStringConcat(xms2, line);
822       XmStringFree(xms2);
823       XmStringFree(line);
824       p = strtok(NULL, "\n");
825     }
826 
827   XmStringFree(separator);
828   free(tmp);
829   return(xms1);
830 }
831 
832 #include <Xm/ScaleP.h>
833 /* needed to set the scale title background */
834 
835 
draw_line(graphics_context * ax,int x0,int y0,int x1,int y1)836 void draw_line(graphics_context *ax, int x0, int y0, int x1, int y1)
837 {
838   XDrawLine(ax->dp, ax->wn, ax->gc, x0, y0, x1, y1);
839 }
840 
841 
fill_rectangle(graphics_context * ax,int x0,int y0,int width,int height)842 void fill_rectangle(graphics_context *ax, int x0, int y0, int width, int height)
843 {
844   XFillRectangle(ax->dp, ax->wn, ax->gc, x0, y0, width, height);
845 }
846 
847 
erase_rectangle(chan_info * cp,graphics_context * ax,int x0,int y0,int width,int height)848 void erase_rectangle(chan_info *cp, graphics_context *ax, int x0, int y0, int width, int height)
849 {
850   XFillRectangle(ax->dp, ax->wn, erase_GC(cp), x0, y0, width, height);
851 }
852 
853 
draw_string(graphics_context * ax,int x0,int y0,const char * str,int len)854 void draw_string(graphics_context *ax, int x0, int y0, const char *str, int len)
855 {
856   if ((str) && (*str))
857     XDrawString(ax->dp, ax->wn, ax->gc, x0, y0, str, len);
858 }
859 
860 
gtk_style_draw_string(graphics_context * ax,int x0,int y0,const char * str,int len)861 void gtk_style_draw_string(graphics_context *ax, int x0, int y0, const char *str, int len)
862 {
863   /* for callers of Scheme-level draw-string, the Motif and (now removed Gtk) versions should agree on where "y0" is */
864   XGCValues gv;
865   static XFontStruct *fs = NULL;
866 
867   XGetGCValues(main_display(ss), ax->gc, GCFont, &gv);
868 
869   /* now gv.font is the default font */
870   if (fs) XFree(fs);
871   /*  this doesn't free all the space */
872   /* but this: */
873   /* if (fs) XFreeFont(main_display(ss), fs); */
874   /* gets:
875      X Error of failed request:  BadFont (invalid Font parameter)
876      Major opcode of failed request:  56 (X_ChangeGC)
877      Resource id in failed request:  0x4e0035c
878      Serial number of failed request:  8479111
879      Current serial number in output stream:  8479240
880   */
881 
882   fs = XQueryFont(main_display(ss), gv.font);
883   if (fs)
884     XDrawString(ax->dp, ax->wn, ax->gc, x0, y0 + fs->ascent, str, len);
885   else XDrawString(ax->dp, ax->wn, ax->gc, x0, y0, str, len); /* not sure why this happens... */
886 
887   /* XFreeFont here is trouble, but handling it as above seems ok -- Font.c in xlib does allocate new space */
888 }
889 
890 
draw_polygon_va(graphics_context * ax,bool filled,int points,va_list ap)891 static void draw_polygon_va(graphics_context *ax, bool filled, int points, va_list ap)
892 {
893   int i;
894   XPoint *pts;
895   pts = (XPoint *)calloc(points, sizeof(XPoint));
896   for (i = 0; i < points; i++)
897     {
898       pts[i].x = va_arg(ap, int);
899       pts[i].y = va_arg(ap, int);
900     }
901   if (filled)
902     XFillPolygon(ax->dp, ax->wn, ax->gc, pts, points, Convex, CoordModeOrigin);
903   else XDrawLines(ax->dp, ax->wn, ax->gc, pts, points, CoordModeOrigin);
904   free(pts);
905 }
906 
907 
fill_polygon(graphics_context * ax,int points,...)908 void fill_polygon(graphics_context *ax, int points, ...)
909 { /* currently used only in snd-marks.c */
910   va_list ap;
911   if (points == 0) return;
912   va_start(ap, points);
913   draw_polygon_va(ax, true, points, ap);
914   va_end(ap);
915 }
916 
917 #if 0
918 void draw_polygon(graphics_context *ax, int points, ...)
919 {
920   va_list ap;
921   if (points == 0) return;
922   va_start(ap, points);
923   draw_polygon_va(ax, false, points, ap);
924   va_end(ap);
925 }
926 #endif
927 
draw_lines(graphics_context * ax,point_t * points,int num)928 void draw_lines(graphics_context *ax, point_t *points, int num)
929 {
930   if (num == 0) return;
931   XDrawLines(ax->dp, ax->wn, ax->gc, points, num, CoordModeOrigin);
932 }
933 
934 
draw_points(graphics_context * ax,point_t * points,int num,int size)935 void draw_points(graphics_context *ax, point_t *points, int num, int size)
936 {
937   if (num == 0) return;
938   if (size == 1)
939     XDrawPoints(ax->dp, ax->wn, ax->gc, points, num, CoordModeOrigin);
940   else
941     {
942       int i, size2;
943       XArc *rs;
944       /* create squares or whatever centered on each point */
945       size2 = size / 2;
946       rs = (XArc *)calloc(num, sizeof(XArc));
947       for (i = 0; i < num; i++)
948 	{
949 	  rs[i].x = points[i].x - size2;
950 	  rs[i].y = points[i].y - size2;
951 	  rs[i].angle1 = 0;
952 	  rs[i].angle2 = 360 * 64;
953 	  rs[i].width = size;
954 	  rs[i].height = size;
955 	}
956       XFillArcs(ax->dp, ax->wn, ax->gc, rs, num);
957       free(rs);
958     }
959 }
960 
961 
962 #if 0
963 void draw_point(graphics_context *ax, point_t point, int size)
964 {
965   if (size == 1)
966     XDrawPoint(ax->dp, ax->wn, ax->gc, point.x, point.y);
967   else
968     XFillArc(ax->dp, ax->wn, ax->gc,
969 	     point.x - size / 2,
970 	     point.y - size / 2,
971 	     size, size, 0,
972 	     360 * 64);
973 }
974 #endif
975 
976 
draw_dot(graphics_context * ax,int x,int y,int size)977 void draw_dot(graphics_context *ax, int x, int y, int size)
978 {
979   XFillArc(ax->dp, ax->wn, ax->gc,
980 	   x - size / 2,
981 	   y - size / 2,
982 	   size, size, 0,
983 	   360 * 64);
984 }
985 
986 
fill_polygons(graphics_context * ax,point_t * points,int num,int y0)987 void fill_polygons(graphics_context *ax, point_t *points, int num, int y0)
988 {
989   XPoint polypts[4];
990   int i;
991   for (i = 1; i < num; i++)
992     {
993       polypts[0].x = points[i - 1].x;
994       polypts[0].y = points[i - 1].y;
995       polypts[1].x = points[i].x;
996       polypts[1].y = points[i].y;
997       polypts[2].x = polypts[1].x;
998       polypts[2].y = y0;
999       polypts[3].x = points[i - 1].x;
1000       polypts[3].y = y0;
1001       XFillPolygon(ax->dp, ax->wn, ax->gc, polypts, 4, Convex, CoordModeOrigin);
1002     }
1003 }
1004 
1005 
fill_two_sided_polygons(graphics_context * ax,point_t * points,point_t * points1,int num)1006 void fill_two_sided_polygons(graphics_context *ax, point_t *points, point_t *points1, int num)
1007 {
1008   XPoint polypts[4];
1009   int i;
1010   for (i = 1; i < num; i++)
1011     {
1012       polypts[0].x = points[i - 1].x;
1013       polypts[0].y = points[i - 1].y;
1014       polypts[1].x = points[i].x;
1015       polypts[1].y = points[i].y;
1016       polypts[2].x = points1[i].x;
1017       polypts[2].y = points1[i].y;
1018       polypts[3].x = points1[i - 1].x;
1019       polypts[3].y = points1[i - 1].y;
1020       XFillPolygon(ax->dp, ax->wn, ax->gc, polypts, 4, Convex, CoordModeOrigin);
1021     }
1022 }
1023 
1024 
setup_graphics_context(chan_info * cp,graphics_context * ax)1025 void setup_graphics_context(chan_info *cp, graphics_context *ax)
1026 {
1027   Widget w;
1028   w = channel_to_widget(cp);
1029   ax->dp = XtDisplay(w);
1030   ax->gc = copy_GC(cp);
1031   ax->wn = XtWindow(w);
1032 }
1033 
1034 
1035 /* colormaps */
1036 
1037 static int sono_bins = 0;             /* tracks total_bins -- each sono_data[i] is an array of total_bins rectangles */
1038 static Pixel *current_colors = NULL;
1039 static int current_colors_size = 0;
1040 static int current_colormap = BLACK_AND_WHITE_COLORMAP;
1041 static XRectangle **sono_data = NULL; /* each entry in sono_data is an array of colormap_size arrays: sono_data[colormap_size][total_bins] */
1042 static int sono_colors = 0;           /* tracks colormap_size */
1043 static GC colormap_GC;
1044 
1045 
check_colormap_sizes(int colors)1046 void check_colormap_sizes(int colors)
1047 {
1048   int i, old_size;
1049   if (current_colors_size > 0)
1050     {
1051       if (current_colormap != BLACK_AND_WHITE_COLORMAP)
1052 	{
1053 	  int scr;
1054 	  Colormap cmap;
1055 	  Display *dpy;
1056 	  dpy = XtDisplay(main_shell(ss));
1057 	  scr = DefaultScreen(dpy);
1058 	  cmap = DefaultColormap(dpy, scr);
1059 	  XFreeColors(dpy, cmap, current_colors, current_colors_size, 0);
1060 	  current_colormap = BLACK_AND_WHITE_COLORMAP;
1061 	}
1062       if ((current_colors) && (current_colors_size < colors))
1063 	{
1064 	  old_size = current_colors_size;
1065 	  current_colors_size = colors;
1066 	  current_colors = (Pixel *)realloc(current_colors, current_colors_size * sizeof(Pixel));
1067 	  for (i = old_size; i < current_colors_size; i++) current_colors[i] = 0;
1068 	}
1069     }
1070   if ((sono_data) && (sono_colors < colors) && (sono_bins > 0))
1071     {
1072       old_size = sono_colors;
1073       sono_colors = colors;
1074       sono_data = (XRectangle **)realloc(sono_data, sono_colors * sizeof(XRectangle *));
1075       for (i = old_size; i < sono_colors; i++) sono_data[i] = (XRectangle *)calloc(sono_bins, sizeof(XRectangle));
1076     }
1077 }
1078 
1079 
initialize_colormap(void)1080 static void initialize_colormap(void)
1081 {
1082   XGCValues gv;
1083   gv.background = ss->white;
1084   gv.foreground = ss->data_color;
1085   colormap_GC = XCreateGC(main_display(ss), XtWindow(main_shell(ss)), GCForeground | GCBackground, &gv);
1086   sono_colors = color_map_size(ss);
1087   sono_data = (XRectangle **)calloc(sono_colors, sizeof(XRectangle *));
1088   current_colors_size = color_map_size(ss);
1089   current_colors = (Pixel *)calloc(current_colors_size, sizeof(Pixel));
1090 }
1091 
1092 
draw_spectro_line(graphics_context * ax,int color,int x0,int y0,int x1,int y1)1093 void draw_spectro_line(graphics_context *ax, int color, int x0, int y0, int x1, int y1)
1094 {
1095   XSetForeground(ax->dp, colormap_GC, current_colors[color]);
1096   XDrawLine(ax->dp, ax->wn, colormap_GC, x0, y0, x1, y1);
1097 }
1098 
1099 
draw_sono_rectangles(graphics_context * ax,int color,int jmax)1100 void draw_sono_rectangles(graphics_context *ax, int color, int jmax)
1101 {
1102   XSetForeground(ax->dp, colormap_GC, current_colors[color]);
1103   XFillRectangles(ax->dp, ax->wn, colormap_GC, sono_data[color], jmax);
1104 }
1105 
1106 
set_sono_rectangle(int j,int color,int x,int y,int width,int height)1107 void set_sono_rectangle(int j, int color, int x, int y, int width, int height)
1108 {
1109   XRectangle *r;
1110   r = sono_data[color];
1111   r[j].x = x;
1112   r[j].y = y;
1113   r[j].width = width;
1114   r[j].height = height;
1115 }
1116 
1117 
allocate_sono_rects(int bins)1118 void allocate_sono_rects(int bins)
1119 {
1120   if (bins != sono_bins)
1121     {
1122       int i;
1123       for (i = 0; i < sono_colors; i++)
1124 	{
1125 	  if ((sono_bins > 0) && (sono_data[i]))
1126 	    free(sono_data[i]); /* each is array of XRectangle structs, but it's the wrong size */
1127 	  sono_data[i] = (XRectangle *)calloc(bins, sizeof(XRectangle));
1128 	}
1129       sono_bins = bins;
1130     }
1131 }
1132 
1133 
allocate_color_map(int colormap)1134 void allocate_color_map(int colormap)
1135 {
1136   static bool warned_color = false;
1137   if (current_colormap != colormap)
1138     {
1139       int i;
1140       Colormap cmap;
1141       XColor tmp_color;
1142       Display *dpy;
1143       int scr;
1144       tmp_color.flags = DoRed | DoGreen | DoBlue;
1145 
1146       dpy = XtDisplay(main_shell(ss));
1147       scr = DefaultScreen(dpy);
1148       cmap = DefaultColormap(dpy, scr);
1149 
1150       /* 8-bit color displays can't handle all these colors, apparently, so we have to check status */
1151       if (current_colormap != BLACK_AND_WHITE_COLORMAP)
1152 	XFreeColors(dpy, cmap, current_colors, current_colors_size, 0);
1153 
1154       for (i = 0; i < current_colors_size; i++)
1155 	{
1156 	  get_current_color(colormap, i, &(tmp_color.red), &(tmp_color.green), &(tmp_color.blue));
1157 	  if ((XAllocColor(dpy, cmap, &tmp_color)) == 0) /* 0 = failure -- try black as a fallback */
1158 	    {
1159 	      tmp_color.red = 0;
1160 	      tmp_color.green = 0;
1161 	      tmp_color.blue = 0;
1162 	      if ((XAllocColor(dpy, cmap, &tmp_color)) == 0)
1163 		{
1164 		  if (!warned_color)
1165 		    snd_error_without_format("can't even allocate black?!?");
1166 		  warned_color = true;
1167 		}
1168 	    }
1169 	  current_colors[i] = tmp_color.pixel;
1170 	}
1171       current_colormap = colormap;
1172     }
1173 }
1174 
1175 
draw_colored_lines(chan_info * cp,graphics_context * ax,point_t * points,int num,int * colors,int axis_y0,color_t default_color)1176 void draw_colored_lines(chan_info *cp, graphics_context *ax, point_t *points, int num, int *colors, int axis_y0, color_t default_color)
1177 {
1178   int i, x0, y0, y2 = 0, y00 = -1, cur, prev;
1179   color_t old_color;
1180 
1181   if (num <= 0) return;
1182 
1183   old_color = get_foreground_color(ax);
1184 
1185   x0 = points[0].x;
1186   y0 = points[0].y;
1187 
1188   if (abs(y0 - axis_y0) < 5)
1189     prev = -1;
1190   else prev = colors[0];
1191 
1192   set_foreground_color(ax, (prev == -1) ? default_color : current_colors[prev]);
1193 
1194   for (i = 1; i < num; i++)
1195     {
1196       int x1, y1;
1197       x1 = points[i].x;
1198       y1 = points[i].y;
1199       if (i < num - 1)
1200 	y2 = points[i + 1].y;
1201       else y2 = y1;
1202 
1203       if ((abs(y0 - axis_y0) < 5) &&
1204 	  (abs(y1 - axis_y0) < 5))
1205 	cur = -1;
1206       else
1207 	{
1208 	  if ((y00 > y0) &&
1209 	      (y00 > y1) &&
1210 	      (i > 1))
1211 	    cur = colors[i - 2];
1212 	  else
1213 	    {
1214 	      if ((y2 > y1) &&
1215 		  (y2 > y0))
1216 		cur = colors[i + 1];
1217 	      else
1218 		{
1219 		  if (y0 > y1)
1220 		    cur = colors[i];
1221 		  else cur = colors[i - 1]; /* coords are upside down */
1222 		}
1223 	    }
1224 	}
1225 
1226       if (cur != prev)
1227 	{
1228 	  set_foreground_color(ax, (cur == -1) ? default_color : current_colors[cur]);
1229 	  prev = cur;
1230 	}
1231 
1232       if (cp->transform_graph_style == GRAPH_DOTS)
1233 	draw_dot(ax, x0, y0, cp->dot_size);
1234       else draw_line(ax, x0, y0, x1, y1);
1235 
1236       y00 = y0;
1237       x0 = x1;
1238       y0 = y1;
1239     }
1240 
1241   set_foreground_color(ax, old_color);
1242 }
1243 
1244 
1245 
1246 /* -------- color/orientation browser -------- */
1247 
1248 static Xen color_hook;
1249 
check_color_hook(void)1250 static void check_color_hook(void)
1251 {
1252   if (Xen_hook_has_list(color_hook))
1253     run_hook(color_hook, Xen_empty_list, S_color_hook);
1254 }
1255 
1256 
1257 static Widget ccd_dialog = NULL, ccd_list, ccd_scale, ccd_invert, ccd_cutoff;
1258 
update_graph_setting_fft_changed(chan_info * cp)1259 static void update_graph_setting_fft_changed(chan_info *cp)
1260 {
1261   cp->fft_changed = FFT_CHANGE_LOCKED;
1262   update_graph(cp);
1263 }
1264 
1265 
invert_color_callback(Widget w,XtPointer context,XtPointer info)1266 static void invert_color_callback(Widget w, XtPointer context, XtPointer info)
1267 {
1268   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
1269   in_set_color_inverted(cb->set);
1270   check_color_hook();
1271   for_each_chan(update_graph_setting_fft_changed);
1272 }
1273 
1274 
set_color_inverted(bool val)1275 void set_color_inverted(bool val)
1276 {
1277   in_set_color_inverted(val);
1278   if (ccd_dialog)
1279     XmToggleButtonSetState(ccd_invert, (Boolean)val, false);
1280   check_color_hook();
1281   if (!(ss->graph_hook_active))
1282     for_each_chan(update_graph_setting_fft_changed);
1283 }
1284 
1285 
scale_color_callback(Widget w,XtPointer context,XtPointer info)1286 static void scale_color_callback(Widget w, XtPointer context, XtPointer info)
1287 {
1288   mus_float_t val;
1289   int scale_val;
1290   XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info;
1291   scale_val = cbs->value;
1292   if (scale_val <= 50)
1293     val = (mus_float_t)(scale_val + 1) / 51.0;
1294   else val = 1.0 + (mus_float_t)((scale_val - 50) * (scale_val - 50)) / 12.5;
1295   in_set_color_scale(val);
1296   check_color_hook();
1297   for_each_chan(update_graph_setting_fft_changed);
1298 }
1299 
1300 
reflect_color_scale(mus_float_t val)1301 static void reflect_color_scale(mus_float_t val)
1302 {
1303   if (val < 0.02)
1304     XmScaleSetValue(ccd_scale, 0);
1305   else
1306     {
1307       if (val <= 1.0)
1308 	XmScaleSetValue(ccd_scale, mus_iclamp(0, (int)(val * 51.0 - 1), 100));
1309       else XmScaleSetValue(ccd_scale, mus_iclamp(0, 50 + (int)sqrt((val - 1.0) * 12.5), 100));
1310     }
1311 }
1312 
1313 
set_color_scale(mus_float_t val)1314 void set_color_scale(mus_float_t val)
1315 {
1316   in_set_color_scale(val);
1317   if (ccd_dialog)
1318     reflect_color_scale(color_scale(ss));
1319   if (!(ss->graph_hook_active))
1320     for_each_chan(update_graph_setting_fft_changed);
1321 }
1322 
1323 
list_color_callback(Widget w,XtPointer context,XtPointer info)1324 static void list_color_callback(Widget w, XtPointer context, XtPointer info)
1325 {
1326   XmListCallbackStruct *cbs = (XmListCallbackStruct *)info;
1327   if (is_colormap(cbs->item_position - 1))
1328     {
1329       in_set_color_map(cbs->item_position - 1);
1330       check_color_hook();
1331       for_each_chan(update_graph_setting_fft_changed);
1332     }
1333 }
1334 
1335 
set_color_map(int val)1336 void set_color_map(int val)
1337 {
1338   in_set_color_map(val);
1339   if ((ccd_dialog) && (val >= 0))
1340     XmListSelectPos(ccd_list, val + 1, false);
1341   check_color_hook();
1342   if (!(ss->graph_hook_active))
1343     for_each_chan(update_graph_setting_fft_changed);
1344 }
1345 
1346 
fscale_label(const char * orig_label,mus_float_t value)1347 static XmString fscale_label(const char *orig_label, mus_float_t value)
1348 {
1349   XmString x;
1350   char *lab;
1351   lab = mus_format("%s: %.3f", orig_label, value);
1352   x = XmStringCreateLocalized(lab);
1353   free(lab);
1354   return(x);
1355 }
1356 
1357 
fscale_set_label(const char * orig_label,Widget w,mus_float_t value)1358 static void fscale_set_label(const char *orig_label, Widget w, mus_float_t value)
1359 {
1360   XmString x;
1361   char *lab;
1362   lab = mus_format("%s: %.3f", orig_label, value);
1363   x = XmStringCreateLocalized(lab);
1364   XtVaSetValues(w, XmNtitleString, x, NULL);
1365   free(lab);
1366   XmStringFree(x);
1367 }
1368 
1369 
cutoff_color_callback(Widget w,XtPointer context,XtPointer info)1370 static void cutoff_color_callback(Widget w, XtPointer context, XtPointer info) /* cutoff point */
1371 {
1372   /* cutoff point for color chooser */
1373   XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info;
1374   in_set_color_cutoff((mus_float_t)(cbs->value) / 1000.0);
1375   fscale_set_label("data cutoff", w, color_cutoff(ss));
1376   check_color_hook();
1377   for_each_chan(update_graph_setting_fft_changed);
1378 }
1379 
1380 
set_color_cutoff(mus_float_t val)1381 void set_color_cutoff(mus_float_t val)
1382 {
1383   in_set_color_cutoff(val);
1384   if (ccd_dialog)
1385     XmScaleSetValue(ccd_cutoff, (int)(val * 1000.0));
1386   if (!(ss->graph_hook_active))
1387     for_each_chan(update_graph_setting_fft_changed);
1388 }
1389 
1390 
dismiss_color_orientation_callback(Widget w,XtPointer context,XtPointer info)1391 static void dismiss_color_orientation_callback(Widget w, XtPointer context, XtPointer info)
1392 {
1393   XtUnmanageChild(ccd_dialog);
1394 }
1395 
1396 
help_color_orientation_callback(Widget w,XtPointer context,XtPointer info)1397 static void help_color_orientation_callback(Widget w, XtPointer context, XtPointer info)
1398 {
1399   color_orientation_dialog_help();
1400 }
1401 
1402 
reflect_color_list(bool setup_time)1403 void reflect_color_list(bool setup_time)
1404 {
1405   if ((ccd_dialog) && (ccd_list))
1406     {
1407       int i, size;
1408       XmString *cmaps;
1409       size = num_colormaps();
1410       cmaps = (XmString *)calloc(size, sizeof(XmString));
1411       for (i = 0; i < size; i++)
1412 	cmaps[i] = XmStringCreateLocalized(colormap_name(i));
1413       XtVaSetValues(ccd_list,
1414 		    XmNitems, cmaps,
1415 		    XmNitemCount, size,
1416 		    NULL);
1417       if (setup_time)
1418 	XtVaSetValues(ccd_list,
1419 		      XmNvisibleItemCount, 6,
1420 		      NULL);
1421       for (i = 0; i < size; i++) XmStringFree(cmaps[i]);
1422       free(cmaps);
1423     }
1424 }
1425 
1426 
1427 static Xen orientation_hook;
1428 
check_orientation_hook(void)1429 static void check_orientation_hook(void)
1430 {
1431   if (Xen_hook_has_list(orientation_hook))
1432     run_hook(orientation_hook, Xen_empty_list, S_orientation_hook);
1433 }
1434 
1435 
1436 static Widget oid_ax, oid_ay, oid_az, oid_sx, oid_sy, oid_sz, oid_hop;
1437 #if HAVE_GL
1438   static Widget oid_glbutton;
1439 #endif
1440 
1441 #define HOP_MAX 20
1442 
scale_label(const char * orig_label,int value,bool dec)1443 static XmString scale_label(const char *orig_label, int value, bool dec)
1444 {
1445   XmString x;
1446   char *lab;
1447   if (!dec)
1448     lab = mus_format("%s: %d", orig_label, value);
1449   else lab = mus_format("%s: %.2f", orig_label, value * 0.01);
1450   x = XmStringCreateLocalized(lab);
1451   free(lab);
1452   return(x);
1453 }
1454 
1455 
scale_set_label(const char * orig_label,Widget w,int value,bool dec)1456 static void scale_set_label(const char *orig_label, Widget w, int value, bool dec)
1457 {
1458   /* in new motif (after version 2.1), showValue not XmNONE (= 0) clobbers XmScale title!
1459    *   also XmNEAR_BORDER has no effect -- same as XmNEAR_SLIDER
1460    * so...
1461    *   we create the full label by hand here.
1462    */
1463 
1464   XmString x;
1465   char *lab;
1466   if (!dec)
1467     lab = mus_format("%s: %d", orig_label, value);
1468   else lab = mus_format("%s: %.2f", orig_label, value * 0.01);
1469   x = XmStringCreateLocalized(lab);
1470   XtVaSetValues(w, XmNtitleString, x, NULL);
1471   free(lab);
1472   XmStringFree(x);
1473 }
1474 
1475 
ax_orientation_callback(Widget w,XtPointer context,XtPointer info)1476 static void ax_orientation_callback(Widget w, XtPointer context, XtPointer info)
1477 {
1478   XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info;
1479   scale_set_label("x angle", w, cbs->value, false);
1480   in_set_spectro_x_angle((mus_float_t)(cbs->value));
1481   chans_field(FCP_X_ANGLE, (mus_float_t)(cbs->value));
1482   check_orientation_hook();
1483   for_each_chan(update_graph);
1484 }
1485 
1486 
set_spectro_x_angle(mus_float_t val)1487 void set_spectro_x_angle(mus_float_t val)
1488 {
1489   if (val < 0.0) val += 360.0; else if (val >= 360.0) val = fmod(val, 360.0);
1490   in_set_spectro_x_angle(val);
1491   if (ccd_dialog)
1492     {
1493       XmScaleSetValue(oid_ax, (int)val);
1494       scale_set_label("x angle", oid_ax, (int)val, false);
1495     }
1496   chans_field(FCP_X_ANGLE, val);
1497   check_orientation_hook();
1498   if (!(ss->graph_hook_active))
1499     for_each_chan(update_graph);
1500 }
1501 
1502 
ay_orientation_callback(Widget w,XtPointer context,XtPointer info)1503 static void ay_orientation_callback(Widget w, XtPointer context, XtPointer info)
1504 {
1505   XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info;
1506   scale_set_label("y angle", w, cbs->value, false);
1507   in_set_spectro_y_angle((mus_float_t)(cbs->value));
1508   chans_field(FCP_Y_ANGLE, (mus_float_t)(cbs->value));
1509   check_orientation_hook();
1510   for_each_chan(update_graph);
1511 }
1512 
1513 
set_spectro_y_angle(mus_float_t val)1514 void set_spectro_y_angle(mus_float_t val)
1515 {
1516   if (val < 0.0) val += 360.0; else if (val >= 360.0) val = fmod(val, 360.0);
1517   in_set_spectro_y_angle(val);
1518   if (ccd_dialog)
1519     {
1520       XmScaleSetValue(oid_ay, (int)val);
1521       scale_set_label("y angle", oid_ay, (int)val, false);
1522     }
1523   chans_field(FCP_Y_ANGLE, val);
1524   check_orientation_hook();
1525   if (!(ss->graph_hook_active))
1526     for_each_chan(update_graph);
1527 }
1528 
1529 
az_orientation_callback(Widget w,XtPointer context,XtPointer info)1530 static void az_orientation_callback(Widget w, XtPointer context, XtPointer info)
1531 {
1532   XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info;
1533   scale_set_label("z angle", w, cbs->value, false);
1534   in_set_spectro_z_angle((mus_float_t)(cbs->value));
1535   chans_field(FCP_Z_ANGLE, (mus_float_t)(cbs->value));
1536   check_orientation_hook();
1537   for_each_chan(update_graph);
1538 }
1539 
1540 
set_spectro_z_angle(mus_float_t val)1541 void set_spectro_z_angle(mus_float_t val)
1542 {
1543   if (val < 0.0) val += 360.0; else if (val >= 360.0) val = fmod(val, 360.0);
1544   in_set_spectro_z_angle(val);
1545   if (ccd_dialog)
1546     {
1547       XmScaleSetValue(oid_az, (int)val);
1548       scale_set_label("z angle", oid_az, (int)val, false);
1549     }
1550   chans_field(FCP_Z_ANGLE, val);
1551   check_orientation_hook();
1552   if (!(ss->graph_hook_active))
1553     for_each_chan(update_graph);
1554 }
1555 
1556 
sx_orientation_callback(Widget w,XtPointer context,XtPointer info)1557 static void sx_orientation_callback(Widget w, XtPointer context, XtPointer info)
1558 {
1559   XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info;
1560   scale_set_label("x scale", w, cbs->value, true);
1561   in_set_spectro_x_scale((mus_float_t)(cbs->value) * 0.01);
1562   chans_field(FCP_X_SCALE, (mus_float_t)(cbs->value) * 0.01);
1563   check_orientation_hook();
1564   for_each_chan(update_graph);
1565 }
1566 
1567 
set_spectro_x_scale(mus_float_t val)1568 void set_spectro_x_scale(mus_float_t val)
1569 {
1570   in_set_spectro_x_scale(val);
1571   if (ccd_dialog)
1572     {
1573       int value;
1574       value = mus_iclamp(0, (int)(val * 100), (int)(100 * SPECTRO_X_SCALE_MAX));
1575       XmScaleSetValue(oid_sx, value);
1576       scale_set_label("x scale", oid_sx, value, true);
1577     }
1578   chans_field(FCP_X_SCALE, val);
1579   check_orientation_hook();
1580   if (!(ss->graph_hook_active))
1581     for_each_chan(update_graph);
1582 }
1583 
1584 
sy_orientation_callback(Widget w,XtPointer context,XtPointer info)1585 static void sy_orientation_callback(Widget w, XtPointer context, XtPointer info)
1586 {
1587   XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info;
1588   scale_set_label("y scale", w, cbs->value, true);
1589   in_set_spectro_y_scale((mus_float_t)(cbs->value) * 0.01);
1590   chans_field(FCP_Y_SCALE, (mus_float_t)(cbs->value) * 0.01);
1591   check_orientation_hook();
1592   for_each_chan(update_graph);
1593 }
1594 
1595 
set_spectro_y_scale(mus_float_t val)1596 void set_spectro_y_scale(mus_float_t val)
1597 {
1598   in_set_spectro_y_scale(val);
1599   if (ccd_dialog)
1600     {
1601       int value;
1602       value = mus_iclamp(0, (int)(val * 100), (int)(100 * SPECTRO_Y_SCALE_MAX));
1603       XmScaleSetValue(oid_sy, value);
1604       scale_set_label("y scale", oid_sy, value, true);
1605     }
1606   chans_field(FCP_Y_SCALE, val);
1607   check_orientation_hook();
1608   if (!(ss->graph_hook_active))
1609     for_each_chan(update_graph);
1610 }
1611 
1612 
sz_orientation_callback(Widget w,XtPointer context,XtPointer info)1613 static void sz_orientation_callback(Widget w, XtPointer context, XtPointer info)
1614 {
1615   XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info;
1616   scale_set_label("z scale", w, cbs->value, true);
1617   in_set_spectro_z_scale((mus_float_t)(cbs->value) * 0.01);
1618   chans_field(FCP_Z_SCALE, (mus_float_t)(cbs->value) * 0.01);
1619   check_orientation_hook();
1620   for_each_chan(update_graph);
1621 }
1622 
1623 
set_spectro_z_scale(mus_float_t val)1624 void set_spectro_z_scale(mus_float_t val)
1625 {
1626   in_set_spectro_z_scale(val);
1627   if (ccd_dialog)
1628     {
1629       int value;
1630       value = mus_iclamp(0, (int)(val * 100), (int)(100 * SPECTRO_Z_SCALE_MAX));
1631       XmScaleSetValue(oid_sz, value);
1632       scale_set_label("z scale", oid_sz, value, true);
1633     }
1634   chans_field(FCP_Z_SCALE, val);
1635   check_orientation_hook();
1636   if (!(ss->graph_hook_active))
1637     for_each_chan(update_graph);
1638 }
1639 
1640 
chans_spectro_hop(chan_info * cp,int value)1641 static void chans_spectro_hop(chan_info *cp, int value)
1642 {
1643   cp->spectro_hop = value;
1644 }
1645 
1646 
hop_orientation_callback(Widget w,XtPointer context,XtPointer info)1647 static void hop_orientation_callback(Widget w, XtPointer context, XtPointer info)
1648 {
1649   int val;
1650   XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info;
1651   scale_set_label("hop", w, cbs->value, false);
1652   val = mus_iclamp(1, cbs->value, HOP_MAX);
1653   in_set_spectro_hop(val);
1654   for_each_chan_with_int(chans_spectro_hop,val);
1655   check_orientation_hook();
1656   for_each_chan(update_graph);
1657 }
1658 
1659 
set_spectro_hop(int val)1660 void set_spectro_hop(int val)
1661 {
1662   if (val > 0)
1663     {
1664       in_set_spectro_hop(val);
1665       if (ccd_dialog)
1666 	{
1667 	  int value;
1668 	  value = mus_iclamp(1, val, HOP_MAX);
1669 	  XmScaleSetValue(oid_hop, value);
1670 	  scale_set_label("hop", oid_hop, value, false);
1671 	}
1672       for_each_chan_with_int(chans_spectro_hop, val);
1673       check_orientation_hook();
1674       if (!(ss->graph_hook_active))
1675 	for_each_chan(update_graph);
1676     }
1677 }
1678 
1679 
fixup_angle(mus_float_t ang)1680 static int fixup_angle(mus_float_t ang)
1681 {
1682   int na;
1683   na = (int)ang;
1684   if (na < 0) na += 360;
1685   na = na % 360;
1686   return(na);
1687 }
1688 
1689 
reflect_spectro(void)1690 void reflect_spectro(void)
1691 {
1692   /* set color/orientaton widget values */
1693   if (ccd_dialog)
1694     {
1695       XmToggleButtonSetState(ccd_invert, (Boolean)(color_inverted(ss)), false);
1696       XtVaSetValues(ccd_cutoff, XmNvalue, (int)((color_cutoff(ss)) * 1000), NULL);
1697       reflect_color_scale(color_scale(ss));
1698 
1699       XtVaSetValues(oid_ax, XmNvalue, fixup_angle(spectro_x_angle(ss)), NULL);
1700       XtVaSetValues(oid_ay, XmNvalue, fixup_angle(spectro_y_angle(ss)), NULL);
1701       XtVaSetValues(oid_az, XmNvalue, fixup_angle(spectro_z_angle(ss)), NULL);
1702       XtVaSetValues(oid_sx, XmNvalue, mus_iclamp(0, (int)(spectro_x_scale(ss) * 100), 100), NULL);
1703       XtVaSetValues(oid_sy, XmNvalue, mus_iclamp(0, (int)(spectro_y_scale(ss) * 100), 100), NULL);
1704       XtVaSetValues(oid_sz, XmNvalue, mus_iclamp(0, (int)(spectro_z_scale(ss) * 100), 100), NULL);
1705       XtVaSetValues(oid_hop, XmNvalue, mus_iclamp(1, spectro_hop(ss), HOP_MAX), NULL);
1706       check_orientation_hook();
1707     }
1708 }
1709 
1710 
set_with_gl(bool val,bool with_dialogs)1711 void set_with_gl(bool val, bool with_dialogs)
1712 {
1713 #if HAVE_GL
1714   sgl_save_currents();
1715 #endif
1716   in_set_with_gl(val);
1717 #if HAVE_GL
1718   sgl_set_currents(with_dialogs);
1719   if ((ccd_dialog) && (with_dialogs))
1720     XmToggleButtonSetState(oid_glbutton, val, false);
1721 #endif
1722 }
1723 
1724 
1725 #if HAVE_GL
with_gl_callback(Widget w,XtPointer context,XtPointer info)1726 static void with_gl_callback(Widget w, XtPointer context, XtPointer info)
1727 {
1728   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
1729   sgl_save_currents();
1730   in_set_with_gl(cb->set);
1731   sgl_set_currents(true);
1732   /* this only sets the slider positions -- it doesn't update the labels! */
1733   /*   and  reflect_spectro() doesn't help! */
1734   if (ccd_dialog)
1735     {
1736       scale_set_label("x angle", oid_ax, spectro_x_angle(ss), false);
1737       scale_set_label("y angle", oid_ay, spectro_y_angle(ss), false);
1738       scale_set_label("z angle", oid_az, spectro_z_angle(ss), false);
1739       scale_set_label("x scale", oid_sx, spectro_x_scale(ss), false);
1740       scale_set_label("y scale", oid_sy, spectro_y_scale(ss), false);
1741       scale_set_label("z scale", oid_sz, spectro_z_scale(ss), false);
1742     }
1743   for_each_chan(update_graph);
1744 }
1745 #endif
1746 
1747 
reset_color_orientation_callback(Widget w,XtPointer context,XtPointer info)1748 static void reset_color_orientation_callback(Widget w, XtPointer context, XtPointer info)
1749 {
1750   /* put everything back the way it was at the start.
1751    *     this sets everything to the startup defaults -- should they be the dialog startup values instead?
1752    */
1753   set_color_cutoff(DEFAULT_COLOR_CUTOFF);
1754   set_color_inverted(DEFAULT_COLOR_INVERTED);
1755   set_color_scale(DEFAULT_COLOR_SCALE);
1756   set_color_map(DEFAULT_COLOR_MAP);
1757 
1758   reset_spectro();
1759   reflect_spectro();
1760   for_each_chan(update_graph);
1761 }
1762 
1763 
1764 
1765 /* I tried a scrolled window with each colormap name in an appropriate color, but it looked kinda dumb */
1766 
make_color_orientation_dialog(bool managed)1767 Widget make_color_orientation_dialog(bool managed)
1768 {
1769   if (!ccd_dialog)
1770     {
1771       Arg args[32];
1772       int n, initial_value;
1773       XmString xhelp, xdismiss, xinvert, titlestr, xreset, xstr;
1774       Widget mainform, light_label, lsep, rsep, sep1, tsep, color_frame, orientation_frame, color_form, orientation_form;
1775       Widget color_title, orientation_title;
1776 #if HAVE_GL
1777       XmString glstr;
1778 #endif
1779 
1780       xdismiss = XmStringCreateLocalized((char *)I_GO_AWAY); /* needed by template dialog */
1781       xhelp = XmStringCreateLocalized((char *)I_HELP);
1782       xreset = XmStringCreateLocalized((char *)"Reset");
1783       titlestr = XmStringCreateLocalized((char *)"Color and Orientation");
1784 
1785       n = 0;
1786       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
1787       XtSetArg(args[n], XmNcancelLabelString, xdismiss); n++;
1788       XtSetArg(args[n], XmNhelpLabelString, xhelp); n++;
1789       XtSetArg(args[n], XmNokLabelString, xreset); n++;
1790       XtSetArg(args[n], XmNautoUnmanage, false); n++;
1791       XtSetArg(args[n], XmNdialogTitle, titlestr); n++;
1792       XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
1793       XtSetArg(args[n], XmNnoResize, false); n++;
1794       XtSetArg(args[n], XmNtransient, false); n++;
1795       ccd_dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"Color and Orientation", args, n);
1796 
1797       XtAddCallback(ccd_dialog, XmNcancelCallback, dismiss_color_orientation_callback, NULL);
1798       XtAddCallback(ccd_dialog, XmNhelpCallback, help_color_orientation_callback, NULL);
1799       XtAddCallback(ccd_dialog, XmNokCallback, reset_color_orientation_callback, NULL);
1800 
1801       XmStringFree(xhelp);
1802       XmStringFree(xdismiss);
1803       XmStringFree(titlestr);
1804       XmStringFree(xreset);
1805 
1806       XtVaSetValues(XmMessageBoxGetChild(ccd_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL);
1807       XtVaSetValues(XmMessageBoxGetChild(ccd_dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL);
1808       XtVaSetValues(XmMessageBoxGetChild(ccd_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL);
1809       XtVaSetValues(XmMessageBoxGetChild(ccd_dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL);
1810       XtVaSetValues(XmMessageBoxGetChild(ccd_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL);
1811       XtVaSetValues(XmMessageBoxGetChild(ccd_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL);
1812 
1813       n = 0;
1814       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
1815       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1816       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1817       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1818       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
1819       XtSetArg(args[n], XmNbottomWidget, XmMessageBoxGetChild(ccd_dialog, XmDIALOG_SEPARATOR)); n++;
1820       mainform = XtCreateManagedWidget("formd", xmFormWidgetClass, ccd_dialog, args, n);
1821 
1822       /* color section */
1823       n = 0;
1824       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
1825       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1826       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1827       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1828       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
1829       XtSetArg(args[n], XmNborderWidth, 10); n++;
1830       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
1831       color_frame = XtCreateManagedWidget("color", xmFrameWidgetClass, mainform, args, n);
1832 
1833       n = 0;
1834       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
1835       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1836       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1837       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1838       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1839       color_form = XtCreateManagedWidget("cform", xmFormWidgetClass, color_frame, args, n);
1840 
1841       n = 0;
1842       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
1843       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1844       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
1845       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1846       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1847       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
1848       color_title = XtCreateManagedWidget("colors", xmLabelWidgetClass, color_form, args, n);
1849 
1850       n = 0;
1851       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
1852       XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
1853       XtSetArg(args[n], XmNleftPosition, 60); n++;
1854       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
1855       XtSetArg(args[n], XmNtopWidget, color_title); n++;
1856       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1857       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1858       XtSetArg(args[n], XmNlistMarginWidth, 3); n++;
1859       ccd_list = XmCreateScrolledList(color_form, (char *)"colormap-list", args, n);
1860 
1861       XtVaSetValues(ccd_list,
1862 		    XmNbackground, ss->white,
1863 		    XmNforeground, ss->black,
1864 		    NULL);
1865       reflect_color_list(true);
1866       XtAddCallback(ccd_list, XmNbrowseSelectionCallback, list_color_callback, NULL);
1867       XtManageChild(ccd_list);
1868       XmListSelectPos(ccd_list, color_map(ss) + 1, false);
1869 
1870       n = 0;
1871       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
1872       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1873       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
1874       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
1875       XtSetArg(args[n], XmNtopWidget, color_title); n++;
1876       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1877       XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
1878       XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
1879       XtSetArg(args[n], XmNwidth, 10); n++;
1880       lsep = XtCreateManagedWidget("sep", xmSeparatorWidgetClass, color_form, args, n);
1881 
1882       n = 0;
1883       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
1884       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
1885       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
1886       XtSetArg(args[n], XmNrightWidget, ccd_list); n++;
1887       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
1888       XtSetArg(args[n], XmNtopWidget, color_title); n++;
1889       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1890       XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
1891       XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
1892       XtSetArg(args[n], XmNwidth, 10); n++;
1893       rsep = XtCreateManagedWidget("sep", xmSeparatorWidgetClass, color_form, args, n);
1894 
1895       /* this horizontal separator exists solely to keep the "light" label from clobbering the "dark" label! */
1896       n = 0;
1897       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
1898       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
1899       XtSetArg(args[n], XmNleftWidget, lsep); n++;
1900       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
1901       XtSetArg(args[n], XmNrightWidget, rsep); n++;
1902       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
1903       XtSetArg(args[n], XmNtopWidget, color_title); n++;
1904       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
1905       XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
1906       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
1907       XtSetArg(args[n], XmNwidth, 250); n++;
1908       XtSetArg(args[n], XmNheight, 10); n++;
1909       sep1 = XtCreateManagedWidget("sep1", xmSeparatorWidgetClass, color_form, args, n);
1910 
1911       n = 0;
1912       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
1913       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
1914       XtSetArg(args[n], XmNleftWidget, lsep); n++;
1915       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
1916       XtSetArg(args[n], XmNrightWidget, rsep); n++;
1917       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
1918       XtSetArg(args[n], XmNtopWidget, sep1); n++;
1919       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
1920       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
1921       XtSetArg(args[n], XmNshowValue, XmNEAR_SLIDER); n++;
1922       XtSetArg(args[n], XmNvalue, 50); n++;
1923       ccd_scale = XtCreateManagedWidget("ccdscl", xmScaleWidgetClass, color_form, args, n);
1924       XtAddCallback(ccd_scale, XmNvalueChangedCallback, scale_color_callback, NULL);
1925       XtAddCallback(ccd_scale, XmNdragCallback, scale_color_callback, NULL);
1926 
1927       n = 0;
1928       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
1929       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
1930       XtSetArg(args[n], XmNleftWidget, lsep); n++;
1931       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
1932       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
1933       XtSetArg(args[n], XmNtopWidget, ccd_scale); n++;
1934       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
1935       light_label = XtCreateManagedWidget("light", xmLabelWidgetClass, color_form, args, n);
1936 
1937       n = 0;
1938       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
1939       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
1940       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
1941       XtSetArg(args[n], XmNrightWidget, rsep); n++;
1942       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
1943       XtSetArg(args[n], XmNtopWidget, ccd_scale); n++;
1944       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
1945       XtCreateManagedWidget("dark", xmLabelWidgetClass, color_form, args, n);
1946 
1947       n = 0;
1948       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
1949       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
1950       XtSetArg(args[n], XmNleftWidget, lsep); n++;
1951       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
1952       XtSetArg(args[n], XmNrightWidget, rsep); n++;
1953       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
1954       XtSetArg(args[n], XmNtopWidget, light_label); n++;
1955       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
1956       XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
1957       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
1958       XtSetArg(args[n], XmNwidth, 250); n++;
1959       XtSetArg(args[n], XmNheight, 10); n++;
1960       tsep = XtCreateManagedWidget("tsep", xmSeparatorWidgetClass, color_form, args, n);
1961 
1962       n = 0;
1963       xstr = fscale_label("data cutoff", color_cutoff(ss));
1964       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
1965       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
1966       XtSetArg(args[n], XmNleftWidget, lsep); n++;
1967       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
1968       XtSetArg(args[n], XmNrightWidget, rsep); n++;
1969       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
1970       XtSetArg(args[n], XmNtopWidget, tsep); n++;
1971       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
1972       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
1973       XtSetArg(args[n], XmNshowValue, XmNONE); n++;
1974       XtSetArg(args[n], XmNmaximum, 250); n++;
1975       XtSetArg(args[n], XmNdecimalPoints, 3); n++;
1976       XtSetArg(args[n], XmNtitleString, xstr); n++;
1977       XtSetArg(args[n], XmNvalue, (int)(color_cutoff(ss) * 1000)); n++;
1978       ccd_cutoff = XtCreateManagedWidget("cutoff", xmScaleWidgetClass, color_form, args, n);
1979       XtAddCallback(ccd_cutoff, XmNvalueChangedCallback, cutoff_color_callback, NULL);
1980       XtAddCallback(ccd_cutoff, XmNdragCallback, cutoff_color_callback, NULL);
1981       XmStringFree(xstr);
1982 
1983       XtVaSetValues(((XmScaleWidget)ccd_cutoff)->composite.children[0], XmNbackground, ss->basic_color, NULL);
1984 
1985       n = 0;
1986       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
1987       XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
1988       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
1989       XtSetArg(args[n], XmNleftWidget, lsep); n++;
1990       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
1991       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
1992       XtSetArg(args[n], XmNtopWidget, ccd_cutoff); n++;
1993       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1994       XtSetArg(args[n], XmNset, color_inverted(ss)); n++;
1995       xinvert = XmStringCreateLocalized((char *)"invert");
1996       XtSetArg(args[n], XmNlabelString, xinvert); n++;
1997       ccd_invert = make_togglebutton_widget("invert", color_form, args, n);
1998       XtAddCallback(ccd_invert, XmNvalueChangedCallback, invert_color_callback, NULL);
1999       XmStringFree(xinvert);
2000 
2001 
2002       /* orientation section */
2003       n = 0;
2004       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
2005       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2006       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2007       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2008       XtSetArg(args[n], XmNtopWidget, color_frame); n++;
2009       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2010       XtSetArg(args[n], XmNborderWidth, 10); n++;
2011       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
2012       orientation_frame = XtCreateManagedWidget("color", xmFrameWidgetClass, mainform, args, n);
2013 
2014       n = 0;
2015       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
2016       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2017       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2018       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2019       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2020       orientation_form = XtCreateManagedWidget("oform", xmFormWidgetClass, orientation_frame, args, n);
2021 
2022       n = 0;
2023       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
2024       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2025       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
2026       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2027       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2028       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
2029       orientation_title = XtCreateManagedWidget("orientation", xmLabelWidgetClass, orientation_form, args, n);
2030 
2031       #define SCALE_BORDER_WIDTH 6
2032 
2033       n = 0;
2034       initial_value = fixup_angle(spectro_x_angle(ss));
2035       xstr = scale_label("x angle", initial_value, false);
2036       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
2037       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
2038       XtSetArg(args[n], XmNshowValue, XmNONE); n++;
2039       XtSetArg(args[n], XmNvalue, initial_value); n++;
2040       XtSetArg(args[n], XmNmaximum, 360); n++;
2041       XtSetArg(args[n], XmNtitleString, xstr); n++;
2042       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2043       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
2044       XtSetArg(args[n], XmNrightPosition, 48); n++;
2045       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2046       XtSetArg(args[n], XmNtopWidget, orientation_title); n++;
2047       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
2048       XtSetArg(args[n], XmNborderWidth, SCALE_BORDER_WIDTH); n++;
2049       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
2050       oid_ax = XtCreateManagedWidget("ax", xmScaleWidgetClass, orientation_form, args, n);
2051       XtAddCallback(oid_ax, XmNvalueChangedCallback, ax_orientation_callback, NULL);
2052       XtAddCallback(oid_ax, XmNdragCallback, ax_orientation_callback, NULL);
2053       XmStringFree(xstr);
2054 
2055       XtVaSetValues(((XmScaleWidget)oid_ax)->composite.children[0], XmNbackground, ss->basic_color, NULL);
2056 
2057       n = 0;
2058       initial_value = mus_iclamp(0, (int)(spectro_x_scale(ss) * 100), (int)(100 * SPECTRO_X_SCALE_MAX));
2059       xstr = scale_label("x scale", initial_value, true);
2060       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
2061       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
2062       XtSetArg(args[n], XmNshowValue, XmNONE); n++;
2063       XtSetArg(args[n], XmNmaximum, (int)(100 * SPECTRO_X_SCALE_MAX)); n++;
2064       XtSetArg(args[n], XmNvalue, initial_value); n++;
2065       XtSetArg(args[n], XmNtitleString, xstr); n++;
2066       XtSetArg(args[n], XmNdecimalPoints, 2); n++;
2067       XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
2068       XtSetArg(args[n], XmNleftPosition, 52); n++;
2069       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2070       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
2071       XtSetArg(args[n], XmNtopWidget, oid_ax); n++;
2072       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
2073       XtSetArg(args[n], XmNborderWidth, SCALE_BORDER_WIDTH); n++;
2074       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
2075       oid_sx = XtCreateManagedWidget("xs", xmScaleWidgetClass, orientation_form, args, n);
2076       XtAddCallback(oid_sx, XmNvalueChangedCallback, sx_orientation_callback, NULL);
2077       XtAddCallback(oid_sx, XmNdragCallback, sx_orientation_callback, NULL);
2078       XmStringFree(xstr);
2079 
2080       XtVaSetValues(((XmScaleWidget)oid_sx)->composite.children[0], XmNbackground, ss->basic_color, NULL);
2081 
2082       n = 0;
2083       initial_value = fixup_angle(spectro_y_angle(ss));
2084       xstr = scale_label("y angle", initial_value, false);
2085       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
2086       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
2087       XtSetArg(args[n], XmNshowValue, XmNONE); n++;
2088       XtSetArg(args[n], XmNvalue, initial_value); n++;
2089       XtSetArg(args[n], XmNmaximum, 360); n++;
2090       XtSetArg(args[n], XmNtitleString, xstr); n++;
2091       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2092       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
2093       XtSetArg(args[n], XmNrightPosition, 48); n++;
2094       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2095       XtSetArg(args[n], XmNtopWidget, oid_ax); n++;
2096       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
2097       XtSetArg(args[n], XmNborderWidth, SCALE_BORDER_WIDTH); n++;
2098       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
2099       oid_ay = XtCreateManagedWidget("ay", xmScaleWidgetClass, orientation_form, args, n);
2100       XtAddCallback(oid_ay, XmNvalueChangedCallback, ay_orientation_callback, NULL);
2101       XtAddCallback(oid_ay, XmNdragCallback, ay_orientation_callback, NULL);
2102       XmStringFree(xstr);
2103 
2104       XtVaSetValues(((XmScaleWidget)oid_ay)->composite.children[0], XmNbackground, ss->basic_color, NULL);
2105 
2106       n = 0;
2107       initial_value = mus_iclamp(0, (int)(spectro_y_scale(ss) * 100), (int)(100 * SPECTRO_Y_SCALE_MAX));
2108       xstr = scale_label("y scale", initial_value, true);
2109       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
2110       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
2111       XtSetArg(args[n], XmNshowValue, XmNONE); n++;
2112       XtSetArg(args[n], XmNmaximum, (int)(100 * SPECTRO_Y_SCALE_MAX)); n++;
2113       XtSetArg(args[n], XmNvalue, initial_value); n++;
2114       XtSetArg(args[n], XmNtitleString, xstr); n++;
2115       XtSetArg(args[n], XmNdecimalPoints, 2); n++;
2116       XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
2117       XtSetArg(args[n], XmNleftPosition, 52); n++;
2118       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2119       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2120       XtSetArg(args[n], XmNtopWidget, oid_sx); n++;
2121       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
2122       XtSetArg(args[n], XmNborderWidth, SCALE_BORDER_WIDTH); n++;
2123       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
2124       oid_sy = XtCreateManagedWidget("ys", xmScaleWidgetClass, orientation_form, args, n);
2125       XtAddCallback(oid_sy, XmNvalueChangedCallback, sy_orientation_callback, NULL);
2126       XtAddCallback(oid_sy, XmNdragCallback, sy_orientation_callback, NULL);
2127       XmStringFree(xstr);
2128 
2129       XtVaSetValues(((XmScaleWidget)oid_sy)->composite.children[0], XmNbackground, ss->basic_color, NULL);
2130 
2131       n = 0;
2132       initial_value = fixup_angle(spectro_z_angle(ss));
2133       xstr = scale_label("z angle", initial_value, false);
2134       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
2135       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
2136       XtSetArg(args[n], XmNtitleString, xstr); n++;
2137       XtSetArg(args[n], XmNshowValue, XmNONE); n++;
2138       XtSetArg(args[n], XmNvalue, initial_value); n++;
2139       XtSetArg(args[n], XmNmaximum, 360); n++;
2140       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2141       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
2142       XtSetArg(args[n], XmNrightPosition, 48); n++;
2143       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2144       XtSetArg(args[n], XmNtopWidget, oid_ay); n++;
2145       XtSetArg(args[n], XmNborderWidth, SCALE_BORDER_WIDTH); n++;
2146       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
2147       oid_az = XtCreateManagedWidget("az", xmScaleWidgetClass, orientation_form, args, n);
2148       XtAddCallback(oid_az, XmNvalueChangedCallback, az_orientation_callback, NULL);
2149       XtAddCallback(oid_az, XmNdragCallback, az_orientation_callback, NULL);
2150       XmStringFree(xstr);
2151 
2152       XtVaSetValues(((XmScaleWidget)oid_az)->composite.children[0], XmNbackground, ss->basic_color, NULL);
2153 
2154       n = 0;
2155       initial_value = mus_iclamp(0, (int)(spectro_z_scale(ss) * 100), (int)(100 * SPECTRO_Z_SCALE_MAX));
2156       xstr = scale_label("z scale", initial_value, true);
2157       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
2158       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
2159       XtSetArg(args[n], XmNshowValue, XmNONE); n++;
2160       XtSetArg(args[n], XmNdecimalPoints, 2); n++;
2161       XtSetArg(args[n], XmNmaximum, (int)(100 * SPECTRO_Z_SCALE_MAX)); n++;
2162       XtSetArg(args[n], XmNvalue, initial_value); n++;
2163       XtSetArg(args[n], XmNtitleString, xstr); n++;
2164       XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
2165       XtSetArg(args[n], XmNleftPosition, 52); n++;
2166       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2167       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2168       XtSetArg(args[n], XmNtopWidget, oid_sy); n++;
2169       XtSetArg(args[n], XmNborderWidth, SCALE_BORDER_WIDTH); n++;
2170       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
2171       oid_sz = XtCreateManagedWidget("zs", xmScaleWidgetClass, orientation_form, args, n);
2172       XtAddCallback(oid_sz, XmNvalueChangedCallback, sz_orientation_callback, NULL);
2173       XtAddCallback(oid_sz, XmNdragCallback, sz_orientation_callback, NULL);
2174       XmStringFree(xstr);
2175 
2176       XtVaSetValues(((XmScaleWidget)oid_sz)->composite.children[0], XmNbackground, ss->basic_color, NULL);
2177 
2178       n = 0;
2179       initial_value = mus_iclamp(1, spectro_hop(ss), HOP_MAX);
2180       xstr = scale_label("hop", initial_value, false);
2181       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
2182       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
2183       XtSetArg(args[n], XmNshowValue, XmNONE); n++;
2184       XtSetArg(args[n], XmNvalue, initial_value); n++;
2185       XtSetArg(args[n], XmNmaximum, HOP_MAX); n++;
2186       XtSetArg(args[n], XmNtitleString, xstr); n++;
2187       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2188       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
2189       XtSetArg(args[n], XmNrightPosition, 48); n++;
2190       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2191       XtSetArg(args[n], XmNtopWidget, oid_az); n++;
2192 #if HAVE_GL
2193       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
2194 #else
2195       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2196 #endif
2197       XtSetArg(args[n], XmNborderWidth, SCALE_BORDER_WIDTH); n++;
2198       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
2199       oid_hop = XtCreateManagedWidget("hop", xmScaleWidgetClass, orientation_form, args, n);
2200       XtAddCallback(oid_hop, XmNvalueChangedCallback, hop_orientation_callback, NULL);
2201       XtAddCallback(oid_hop, XmNdragCallback, hop_orientation_callback, NULL);
2202       XmStringFree(xstr);
2203 
2204       XtVaSetValues(((XmScaleWidget)oid_hop)->composite.children[0], XmNbackground, ss->basic_color, NULL);
2205 
2206 #if HAVE_GL
2207       n = 0;
2208       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
2209       XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
2210       XtSetArg(args[n], XmNset, with_gl(ss)); n++;
2211       glstr = XmStringCreateLocalized((char *)"use OpenGL");
2212       XtSetArg(args[n], XmNlabelString, glstr); n++;
2213       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2214       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
2215       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2216       XtSetArg(args[n], XmNtopWidget, oid_hop); n++;
2217       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2218       oid_glbutton = make_togglebutton_widget("use OpenGL", orientation_form, args, n);
2219       XtAddCallback(oid_glbutton, XmNvalueChangedCallback, with_gl_callback, NULL);
2220       XmStringFree(glstr);
2221 #endif
2222 
2223       if (color_scale(ss) != 1.0)
2224 	reflect_color_scale(color_scale(ss));
2225 
2226       map_over_children(ccd_dialog, set_main_color_of_widget);
2227       set_dialog_widget(COLOR_ORIENTATION_DIALOG, ccd_dialog);
2228       if (managed) XtManageChild(ccd_dialog);
2229     }
2230   else
2231     {
2232       if (managed)
2233 	{
2234 	  if (!XtIsManaged(ccd_dialog)) XtManageChild(ccd_dialog);
2235 	  raise_dialog(ccd_dialog);
2236 	}
2237     }
2238   return(ccd_dialog);
2239 }
2240 
2241 
view_color_orientation_callback(Widget w,XtPointer context,XtPointer info)2242 static void view_color_orientation_callback(Widget w, XtPointer context, XtPointer info)
2243 {
2244   make_color_orientation_dialog(true);
2245 }
2246 
2247 
color_orientation_dialog_is_active(void)2248 bool color_orientation_dialog_is_active(void)
2249 {
2250   return((ccd_dialog) && (XtIsManaged(ccd_dialog)));
2251 }
2252 
2253 
2254 
2255 #define HELP_ROWS 10
2256 #define HELP_XREFS 8
2257 #define HELP_COLUMNS 72
2258 /* these set the initial size of the help dialog text area */
2259 
2260 static Widget help_dialog = NULL;
2261 static Widget help_text = NULL;
2262 static char *original_help_text = NULL;
2263 static with_word_wrap_t outer_with_wrap = WITHOUT_WORD_WRAP;
2264 static const char **help_urls = NULL; /* shouldn't this be static char* const char*? */
2265 
2266 static int old_help_text_width = 0;
2267 
help_expose(Widget w,XtPointer context,XEvent * event,Boolean * cont)2268 static void help_expose(Widget w, XtPointer context, XEvent *event, Boolean *cont)
2269 {
2270   int curwid;
2271   curwid = widget_width(help_text);
2272   if (old_help_text_width == 0)
2273     old_help_text_width = curwid;
2274   else
2275     {
2276       if ((outer_with_wrap == WITH_WORD_WRAP) &&
2277 	  (abs(curwid - old_help_text_width) > 10))
2278 	{
2279 	  char *cur_help_str, *new_help_str = NULL;
2280 	  cur_help_str = XmTextGetString(help_text);
2281 	  new_help_str = word_wrap(original_help_text, curwid);
2282 	  XmTextSetString(help_text, new_help_str);
2283 	  if (new_help_str) free(new_help_str);
2284 	  if (cur_help_str) XtFree(cur_help_str);
2285 	  old_help_text_width = curwid;
2286 	}
2287     }
2288 }
2289 
2290 
parse_crossref(const char * xref)2291 static XmString parse_crossref(const char *xref)
2292 {
2293   XmString xs = NULL, tmp;
2294   int i, len, start = 0, j, k;
2295   char *str;
2296   /* crossref has text for scrolled list entry, but url is in '{}'.  It is displayed via the texts rendition */
2297   len = strlen(xref);
2298   for (i = 0; i < len; i++)
2299     {
2300       if (xref[i] == '{')
2301 	{
2302 	  if (i > 0)
2303 	    {
2304 	      str = (char *)calloc(i - start + 1, sizeof(char));
2305 	      for (k = 0, j = start; j < i; k++, j++) str[k] = xref[j];
2306 	      tmp = XmStringGenerate(str, NULL, XmCHARSET_TEXT, (char *)"normal_text");
2307 	      free(str);
2308 	      if (xs)
2309 		xs = XmStringConcatAndFree(xs, tmp);
2310 	      else xs = tmp;
2311 	    }
2312 	  start = i + 1;
2313 	}
2314       else
2315 	{
2316 	  if (xref[i] == '}')
2317 	    {
2318 	      str = (char *)calloc(i - start + 1, sizeof(char));
2319 	      for (k = 0, j = start; j < i; k++, j++) str[k] = xref[j];
2320 	      if (xs)
2321 		xs = XmStringConcatAndFree(xs, XmStringGenerate(str, NULL, XmCHARSET_TEXT, (char *)"url_text"));
2322 	      else xs = XmStringGenerate(str, NULL, XmCHARSET_TEXT, (char *)"url_text");
2323 	      free(str);
2324 	      start = i + 1;
2325 	    }
2326 	}
2327     }
2328   if (start < len)
2329     {
2330       str = (char *)calloc(len - start + 1, sizeof(char));
2331       for (k = 0, j = start; j < len; k++, j++) str[k] = xref[j];
2332       if (xs)
2333 	xs = XmStringConcatAndFree(xs, XmStringGenerate(str, NULL, XmCHARSET_TEXT, (char *)"normal_text"));
2334       else xs = XmStringGenerate(str, NULL, XmCHARSET_TEXT, (char *)"normal_text");
2335       free(str);
2336     }
2337   return(xs);
2338 }
2339 
2340 
find_highlighted_text(XmString xs)2341 static char *find_highlighted_text(XmString xs)
2342 {
2343   /* search xs for text in "url_text" rendition, returning first such portion */
2344   XtPointer text;
2345   bool in_red_text = false;
2346   uint32_t len;
2347   char *result;
2348   XmStringComponentType type;
2349   XmStringContext ctx;
2350 
2351   XmStringInitContext(&ctx, xs);
2352 
2353   while ((type = XmStringGetNextTriple(ctx, &len, &text)) != XmSTRING_COMPONENT_END)
2354     {
2355       switch (type)
2356 	{
2357 	case XmSTRING_COMPONENT_RENDITION_BEGIN:
2358 	  in_red_text = mus_strcmp((char *)text, "url_text");
2359 	  break;
2360 
2361 	case XmSTRING_COMPONENT_RENDITION_END:
2362 	  in_red_text = false;
2363 	  break;
2364 
2365 	case XmSTRING_COMPONENT_TEXT:
2366 	  if (in_red_text)
2367 	    {
2368 	      result = mus_strdup((char *)text);
2369 	      XtFree((char *)text);
2370 	      XmStringFreeContext(ctx);
2371 	      return(result);
2372 	    }
2373 	}
2374 
2375       /* this from the Motif docs, though it looks odd to me */
2376       if (text) XtFree((char *)text);
2377       text = NULL;
2378     }
2379 
2380   XmStringFreeContext(ctx);
2381   return(NULL);
2382 }
2383 
2384 
2385 static Widget related_items = NULL;
2386 
help_completer(widget_t w,const char * text,void * data)2387 static char *help_completer(widget_t w, const char *text, void *data)
2388 {
2389   return(expression_completer(w, text, data));
2390   /* might want to look at help topics too */
2391 }
2392 
2393 
new_help(const char * pattern,bool complain)2394 static bool new_help(const char *pattern, bool complain)
2395 {
2396   const char *url = NULL;
2397   const char **xrefs;
2398 
2399   url = snd_url(pattern);
2400   if (url)
2401     {
2402       /* given name, find doc string, if any */
2403       Xen xstr;
2404       xstr = g_snd_help(C_string_to_Xen_string(pattern), 0);
2405       if (Xen_is_string(xstr))
2406 	{
2407 	  int gc_loc;
2408 	  gc_loc = snd_protect(xstr);
2409 	  xrefs = help_name_to_xrefs(pattern);
2410 	  snd_help_with_xrefs(pattern, Xen_string_to_C_string(xstr), WITH_WORD_WRAP, xrefs, NULL);
2411 	  snd_unprotect_at(gc_loc);
2412 	  if (xrefs) free(xrefs);
2413 	  return(true);
2414 	}
2415       url_to_html_viewer(url);
2416       return(true);
2417     }
2418 
2419   if ((!(snd_topic_help(pattern))) && (complain))
2420     {
2421       xrefs = help_name_to_xrefs(pattern);
2422       if (xrefs)
2423 	{
2424 	  snd_help_with_xrefs(pattern, "(no help found)", WITH_WORD_WRAP, xrefs, NULL);
2425 	  free(xrefs);
2426 	  return(true);
2427 	}
2428       else snd_help_with_xrefs(pattern, "(no help found)", WITH_WORD_WRAP, NULL, NULL);
2429     }
2430 
2431   return(false);
2432 }
2433 
2434 
help_browse_callback(Widget w,XtPointer context,XtPointer info)2435 static void help_browse_callback(Widget w, XtPointer context, XtPointer info)
2436 {
2437   /* single-click to select item in "related items" list */
2438   XmListCallbackStruct *cbs = (XmListCallbackStruct *)info;
2439   if ((help_urls) && (help_urls[cbs->item_position - 1]))
2440     url_to_html_viewer(help_urls[cbs->item_position - 1]);
2441   else
2442     {
2443       char *red_text;
2444       red_text = find_highlighted_text(cbs->item);
2445       if (red_text)
2446 	{
2447 	  name_to_html_viewer(red_text);
2448 	  free(red_text);
2449 	}
2450       else
2451 	{
2452 	  red_text = (char *)XmStringUnparse(cbs->item, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
2453 	  if (red_text)
2454 	    {
2455 	      new_help(red_text, true);
2456 	      XtFree(red_text);
2457 	    }
2458 	}
2459     }
2460 }
2461 
2462 
help_double_click_callback(Widget w,XtPointer context,XtPointer info)2463 static void help_double_click_callback(Widget w, XtPointer context, XtPointer info)
2464 {
2465   /* double-click item in "related items" list */
2466   XmListCallbackStruct *cbs = (XmListCallbackStruct *)info;
2467   if ((help_urls) && (help_urls[cbs->item_position - 1]))
2468     url_to_html_viewer(help_urls[cbs->item_position - 1]);
2469   else
2470     {
2471       char *red_text;
2472       red_text = find_highlighted_text(cbs->selected_items[0]);
2473       if (red_text)
2474 	{
2475 	  name_to_html_viewer(red_text);
2476 	  free(red_text);
2477 	}
2478       else
2479 	{
2480 	  red_text = (char *)XmStringUnparse(cbs->selected_items[0], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
2481 	  if (red_text)
2482 	    {
2483 	      name_to_html_viewer(red_text);
2484 	      XtFree(red_text);
2485 	    }
2486 	}
2487     }
2488 }
2489 
2490 
2491 static Widget help_search = NULL;
2492 
help_quit_callback(Widget w,XtPointer context,XtPointer info)2493 static void help_quit_callback(Widget w, XtPointer context, XtPointer info)
2494 {
2495   /* this focus widget check is actually needed! */
2496   if (XmGetFocusWidget(help_dialog) == XmMessageBoxGetChild(help_dialog, XmDIALOG_CANCEL_BUTTON))
2497     XtUnmanageChild(help_dialog);
2498 }
2499 
2500 
text_release_callback(Widget w,XtPointer context,XEvent * event,Boolean * flag)2501 static void text_release_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag)
2502 {
2503   char *help_str;
2504   help_str = XmTextGetSelection(w);
2505   if (help_str)
2506     {
2507       int i, len;
2508       bool one_word = true;
2509       len = mus_strlen(help_str);
2510       for (i = 0; i < len; i++)
2511 	if (isspace(help_str[i]))
2512 	  {
2513 	    one_word = false;
2514 	    break;
2515 	  }
2516       if (one_word) new_help(help_str, false);
2517       XtFree(help_str);
2518     }
2519 }
2520 
2521 
help_search_callback(Widget w,XtPointer context,XtPointer info)2522 static void help_search_callback(Widget w, XtPointer context, XtPointer info)
2523 {
2524   char *pattern = NULL;
2525   pattern = XmTextFieldGetString(w);
2526   if (new_help(pattern, true))
2527     XmTextFieldSetString(w, (char *)"");
2528   if (pattern) XtFree(pattern);
2529 }
2530 
2531 
2532 static XmRendition texts[2];
2533 
create_help_monolog(void)2534 static void create_help_monolog(void)
2535 {
2536   /* create scrollable but not editable text window */
2537   Arg args[20];
2538   int n;
2539   XmString titlestr, go_away;
2540   Widget holder, xref_label; /* documentation says this isn't needed, but it is */
2541   Widget frame, label, inner_holder, sep, parent;
2542   XmRenderTable rs = NULL;
2543 
2544   titlestr = XmStringCreateLocalized((char *)I_HELP);
2545   go_away = XmStringCreateLocalized((char *)I_GO_AWAY);
2546 
2547   n = 0;
2548   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
2549   XtSetArg(args[n], XmNdialogTitle, titlestr); n++;
2550   /* this window should be resizable by the user (i.e. have the resize bars), but not resize itself */
2551   XtSetArg(args[n], XmNautoUnmanage, false); n++;
2552   XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
2553   XtSetArg(args[n], XmNnoResize, false); n++;
2554   XtSetArg(args[n], XmNtransient, false); n++;
2555   XtSetArg(args[n], XmNcancelLabelString, go_away); n++;
2556 
2557   help_dialog = XmCreateMessageDialog(main_pane(ss), (char *)"snd-help", args, n);
2558   XtAddEventHandler(help_dialog, ExposureMask, false, help_expose, NULL);
2559 
2560   XtAddCallback(help_dialog, XmNcancelCallback, help_quit_callback, NULL);
2561 
2562   XtUnmanageChild(XmMessageBoxGetChild(help_dialog, XmDIALOG_OK_BUTTON));
2563   XtUnmanageChild(XmMessageBoxGetChild(help_dialog, XmDIALOG_HELP_BUTTON));
2564   XtUnmanageChild(XmMessageBoxGetChild(help_dialog, XmDIALOG_SYMBOL_LABEL));
2565 
2566   XtVaSetValues(XmMessageBoxGetChild(help_dialog, XmDIALOG_MESSAGE_LABEL), XmNbackground, ss->highlight_color, NULL);
2567 
2568   XmStringFree(titlestr);
2569   holder = XtCreateManagedWidget("holder", xmFormWidgetClass, help_dialog, NULL, 0);
2570 
2571   n = 0;
2572   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2573   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
2574   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2575   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2576   XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
2577   XtSetArg(args[n], XmNeditable, false); n++;
2578   XtSetArg(args[n], XmNcolumns, HELP_COLUMNS); n++;
2579   XtSetArg(args[n], XmNrows, HELP_ROWS); n++;
2580   XtSetArg(args[n], XmNforeground, ss->black); n++; /* needed if color allocation fails completely */
2581   XtSetArg(args[n], XmNbackground, ss->white); n++;
2582   help_text = XmCreateScrolledText(holder, (char *)"help-text", args, n);
2583   XtAddEventHandler(help_text, ButtonReleaseMask, false, text_release_callback, NULL);
2584   XtManageChild(help_text);
2585 
2586   /* to display the url-related portion of the text in red, we need a rendition for it in the rendertable */
2587   /* try to find the current default render table. */
2588   parent = help_text;
2589   while ((parent) && (!rs))
2590     {
2591       XtVaGetValues(parent, XmNrenderTable, &rs, NULL);
2592       parent = XtParent(parent);
2593     }
2594   n = 0;
2595   if (!rs)
2596     {
2597       /* failed to find a rendertable to specialize, so we need an explicit font */
2598       XtSetArg(args[n], XmNfontName, listener_font(ss)); n++;
2599       XtSetArg(args[n], XmNfontType, XmFONT_IS_FONT); n++;
2600       XtSetArg(args[n], XmNloadModel, XmLOAD_IMMEDIATE); n++;
2601     }
2602   XtSetArg(args[n], XmNrenditionBackground, ss->white); n++;
2603   XtSetArg(args[n], XmNrenditionForeground, ss->red); n++;
2604   texts[0] = XmRenditionCreate(help_text, (char *)"url_text", args, n);
2605   XtSetArg(args[n - 1], XmNrenditionForeground, ss->black);
2606   texts[1] = XmRenditionCreate(help_text, (char *)"normal_text", args, n);
2607   rs = XmRenderTableCopy(XmRenderTableAddRenditions(rs, texts, 2, XmMERGE_NEW), NULL, 0);
2608   /*
2609    * valgrind says this data is used later
2610    * XmRenditionFree(texts[0]);
2611    * XmRenditionFree(texts[1]);
2612   */
2613 
2614   n = 0;
2615   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2616   XtSetArg(args[n], XmNtopWidget, XtParent(help_text)); n++;
2617   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
2618   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2619   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2620   XtSetArg(args[n], XmNheight, 6); n++;
2621   XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
2622   XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
2623   sep = XtCreateManagedWidget("sep", xmSeparatorWidgetClass, holder, args, n);
2624 
2625   n = 0;
2626   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
2627   XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
2628   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2629   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2630   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
2631   XtSetArg(args[n], XmNheight, 24); n++;
2632   /* XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; */
2633   label = XtCreateManagedWidget("help topic:", xmLabelWidgetClass, holder, args, n);
2634 
2635   n = 0;
2636   XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
2637   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2638   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
2639   XtSetArg(args[n], XmNleftWidget, label); n++;
2640   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2641   help_search = make_textfield_widget("help-search", holder, args, n, ACTIVATABLE, add_completer_func(help_completer, NULL));
2642   XtAddCallback(help_search, XmNactivateCallback, help_search_callback, NULL);
2643 
2644   n = 0;
2645   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2646   XtSetArg(args[n], XmNtopWidget, sep); n++;
2647   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2648   XtSetArg(args[n], XmNbottomWidget, help_search); n++;
2649   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2650   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2651   XtSetArg(args[n], XmNshadowThickness, 4); n++;
2652   frame = XtCreateManagedWidget("frame", xmFrameWidgetClass, holder, args, n);
2653 
2654   inner_holder = XtCreateManagedWidget("inner-holder", xmFormWidgetClass, frame, NULL, 0);
2655 
2656   n = 0;
2657   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2658   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
2659   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2660   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2661   XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
2662   xref_label = XtCreateManagedWidget("related topics:", xmLabelWidgetClass, inner_holder, args, n);
2663 
2664   n = 0;
2665   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2666   XtSetArg(args[n], XmNtopWidget, xref_label); n++;
2667   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2668   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2669   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2670 
2671   /* in operton-based solaris 10 this (next) line causes an X server error (with no stack...):
2672    *   complaint is X_ChangeGC got an invalid font.
2673    *   Do I need a configure test program for this?  Is there some other way to force the render table to take effect?
2674    */
2675 #if (!HAVE_SUN) || (!MUS_LITTLE_ENDIAN)
2676   XtSetArg(args[n], XmNfontList, 0); n++; /* needed or new rendertable doesn't take effect! */
2677                                           /* also, 0, not NULL so types match */
2678   XtSetArg(args[n], XmNrenderTable, rs); n++;
2679 #endif
2680 
2681   XtSetArg(args[n], XmNvisibleItemCount, HELP_XREFS); n++; /* appears to be a no-op */
2682   XtSetArg(args[n], XmNheight, 150); n++;
2683 
2684   XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmAS_NEEDED); n++;
2685   related_items = XmCreateScrolledList(inner_holder, (char *)"help-list", args, n);
2686   XtManageChild(related_items);
2687   XtAddCallback(related_items, XmNbrowseSelectionCallback, help_browse_callback, NULL);
2688   XtAddCallback(related_items, XmNdefaultActionCallback, help_double_click_callback, NULL);
2689 
2690   XtManageChild(help_dialog);
2691 
2692   map_over_children(help_dialog, set_main_color_of_widget);
2693   XtVaSetValues(help_text, XmNbackground, ss->white, XmNforeground, ss->black, NULL);
2694   XtVaSetValues(related_items, XmNbackground, ss->highlight_color, XmNforeground, ss->black, NULL);
2695   XtVaSetValues(xref_label, XmNbackground, ss->highlight_color, XmNforeground, ss->black, NULL);
2696 
2697   XtVaSetValues(XmMessageBoxGetChild(help_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL);
2698   XtVaSetValues(XmMessageBoxGetChild(help_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL);
2699 
2700   set_dialog_widget(HELP_DIALOG, help_dialog);
2701 }
2702 
2703 
help_text_width(const char * txt,int start,int end)2704 int help_text_width(const char *txt, int start, int end)
2705 {
2706 #if 0
2707   /* this is full of problems... -- adding renditions below makes everything else flakey */
2708   if ((help_text) && (end > start))
2709     {
2710       char *msg;
2711       int i, j;
2712       XmString s1;
2713       Dimension text_wid = 0;
2714       XmFontList fonts;
2715       XtVaGetValues(help_text, XmNfontList, &fonts, NULL);
2716       msg = (char *)calloc(end - start + 1, sizeof(char));
2717       for (i = start, j = 0; i < end; i++, j++) msg[j] = txt[i];
2718       s1 = XmStringCreateLocalized(msg);
2719       text_wid = XmStringWidth(fonts, s1);
2720       XmStringFree(s1);
2721       free(msg);
2722       return((int)text_wid);
2723     }
2724 #endif
2725   return((end - start) * 8);
2726 }
2727 
2728 
snd_help(const char * subject,const char * helpstr,with_word_wrap_t with_wrap)2729 Widget snd_help(const char *subject, const char *helpstr, with_word_wrap_t with_wrap)
2730 {
2731   /* place help string in scrollable help window */
2732   /* if window is already active, add this help at the top and reposition */
2733   XmString xstr1;
2734 
2735   outer_with_wrap = with_wrap;
2736   if (!(help_dialog))
2737     create_help_monolog();
2738   else raise_dialog(help_dialog);
2739 
2740   xstr1 = XmStringCreateLocalized((char *)subject);
2741   XtVaSetValues(help_dialog, XmNmessageString, xstr1, NULL);
2742   original_help_text = (char *)helpstr;
2743 
2744   if (with_wrap == WITH_WORD_WRAP)
2745     {
2746       char *new_help_str = NULL;
2747       new_help_str = word_wrap(helpstr, widget_width(help_text));
2748       XmTextSetString(help_text, new_help_str);
2749       if (new_help_str) free(new_help_str);
2750     }
2751   else XmTextSetString(help_text, (char *)helpstr);
2752 
2753   if (!XtIsManaged(help_dialog))
2754     XtManageChild(help_dialog);
2755 
2756   XmStringFree(xstr1);
2757   XtVaSetValues(related_items, XmNitems, NULL, XmNitemCount, 0, NULL);
2758   return(help_dialog);
2759 }
2760 
2761 
snd_help_with_xrefs(const char * subject,const char * helpstr,with_word_wrap_t with_wrap,const char ** xrefs,const char ** urls)2762 Widget snd_help_with_xrefs(const char *subject, const char *helpstr, with_word_wrap_t with_wrap, const char **xrefs, const char **urls)
2763 {
2764   Widget w;
2765   w = snd_help(subject, helpstr, with_wrap);
2766   help_urls = urls; /* can't associate the url with the help item in any "natural" way in Motif (no user-data per item) */
2767   if (xrefs)
2768     {
2769       int i, len;
2770 
2771       for (i = 0; ; i++)
2772 	if (!xrefs[i])
2773 	  {
2774 	    len = i;
2775 	    break;
2776 	  }
2777 
2778       if (len > 0)
2779 	{
2780 	  XmString *strs;
2781 	  strs = (XmString *)calloc(len, sizeof(XmString));
2782 
2783 	  for (i = 0; i < len; i++)
2784 	    strs[i] = parse_crossref((const char *)(xrefs[i]));
2785 	  XtVaSetValues(related_items, XmNitems, strs, XmNitemCount, len, NULL);
2786 
2787 	  for (i = 0; i < len; i++)
2788 	    XmStringFree(strs[i]);
2789 	  free(strs);
2790 	}
2791     }
2792   return(w);
2793 }
2794 
2795 
snd_help_append(const char * text)2796 void snd_help_append(const char *text)
2797 {
2798   if (help_text)
2799     XmTextInsert(help_text,
2800 		 XmTextGetLastPosition(help_text),
2801 		 (char *)text);
2802 }
2803 
2804 
snd_help_back_to_top(void)2805 void snd_help_back_to_top(void)
2806 {
2807   if (help_text) XmTextShowPosition(help_text, 0);
2808 }
2809 
2810 
2811 static Widget edit_find_dialog, edit_find_text, cancelB, edit_find_label, previousB;
2812 static Widget find_error_frame = NULL, find_error_label = NULL;
2813 static chan_info *find_channel = NULL; /* sigh */
2814 
2815 
2816 static void clear_find_error(void);
edit_find_modify_callback(Widget w,XtPointer context,XtPointer info)2817 static void edit_find_modify_callback(Widget w, XtPointer context, XtPointer info)
2818 {
2819   clear_find_error();
2820 }
2821 
2822 
clear_find_error(void)2823 static void clear_find_error(void)
2824 {
2825   if ((find_error_frame) && (XtIsManaged(find_error_frame)))
2826     XtUnmanageChild(find_error_frame);
2827   XtRemoveCallback(edit_find_text, XmNmodifyVerifyCallback, edit_find_modify_callback, NULL);
2828   /* squeezing out the error label room here moves the text widget, which is irritating since it
2829    *   means the text we're typing gets lost
2830    */
2831 }
2832 
2833 
find_dialog_stop_label(bool show_stop)2834 void find_dialog_stop_label(bool show_stop)
2835 {
2836   XmString s1;
2837   if (show_stop)
2838     s1 = XmStringCreateLocalized((char *)I_STOP);
2839   else s1 = XmStringCreateLocalized((char *)I_GO_AWAY);
2840   XtVaSetValues(cancelB, XmNlabelString, s1, NULL);
2841   XmStringFree(s1);
2842 }
2843 
2844 
errors_to_find_text(const char * msg,void * data)2845 void errors_to_find_text(const char *msg, void *data)
2846 {
2847   Dimension find_height = 0;
2848   int lines = 0;
2849   XmString label;
2850   find_dialog_set_label("error");
2851   label = multi_line_label(msg, &lines);
2852   XtVaSetValues(find_error_label,
2853 		XmNlabelString, label,
2854 		XmNheight, lines * 20,
2855 		NULL);
2856   XtVaSetValues(find_error_frame, XmNheight, lines * 20, NULL);
2857   XtVaGetValues(edit_find_dialog, XmNheight, &find_height, NULL);
2858   if (find_height < (lines * 20 + 140))
2859     {
2860       XtUnmanageChild(edit_find_dialog);
2861       XtVaSetValues(edit_find_dialog, XmNheight, 140 + 20 * lines, NULL);
2862       XtManageChild(edit_find_dialog);
2863     }
2864   XmStringFree(label);
2865   XtManageChild(find_error_frame);
2866   XtAddCallback(edit_find_text, XmNmodifyVerifyCallback, edit_find_modify_callback, NULL);
2867 }
2868 
2869 
stop_search_if_error(const char * msg,void * data)2870 void stop_search_if_error(const char *msg, void *data)
2871 {
2872   errors_to_find_text(msg, data);
2873   ss->stopped_explicitly = true; /* should be noticed in global_search in snd-find.c */
2874 }
2875 
2876 
edit_find_help_callback(Widget w,XtPointer context,XtPointer info)2877 static void edit_find_help_callback(Widget w, XtPointer context, XtPointer info)
2878 {
2879   find_dialog_help();
2880 }
2881 
2882 
edit_find_ok_callback(read_direction_t direction,Widget w,XtPointer context,XtPointer info)2883 static void edit_find_ok_callback(read_direction_t direction, Widget w, XtPointer context, XtPointer info)
2884 {
2885   char *str;
2886   str = XmTextGetString(edit_find_text);
2887 #if HAVE_EXTENSION_LANGUAGE
2888   find_dialog_find(str, direction, find_channel);
2889 #endif
2890   if (str) free(str);
2891 }
2892 
2893 
find_dialog_set_label(const char * str)2894 void find_dialog_set_label(const char *str)
2895 {
2896   if (edit_find_label)
2897     set_label(edit_find_label, str);
2898 }
2899 
2900 
edit_find_next_callback(Widget w,XtPointer context,XtPointer info)2901 static void edit_find_next_callback(Widget w, XtPointer context, XtPointer info)
2902 {
2903   edit_find_ok_callback(READ_FORWARD, w, context, info);
2904 }
2905 
2906 
edit_find_previous_callback(Widget w,XtPointer context,XtPointer info)2907 static void edit_find_previous_callback(Widget w, XtPointer context, XtPointer info)
2908 {
2909   edit_find_ok_callback(READ_BACKWARD, w, context, info);
2910 }
2911 
2912 
find_dialog_close(Widget w,XtPointer context,XtPointer info)2913 static void find_dialog_close(Widget w, XtPointer context, XtPointer info)
2914 {
2915   clear_find_error();
2916 }
2917 
2918 
edit_find_cancel_callback(Widget w,XtPointer context,XtPointer info)2919 static void edit_find_cancel_callback(Widget w, XtPointer context, XtPointer info)
2920 {
2921   if (ss->checking_explicitly)
2922     ss->stopped_explicitly = true;
2923   else
2924     {
2925       XtUnmanageChild(edit_find_dialog);
2926       clear_find_error();
2927     }
2928 }
2929 
2930 
make_edit_find_dialog(bool managed,chan_info * cp)2931 static void make_edit_find_dialog(bool managed, chan_info *cp)
2932 {
2933   find_channel = cp;
2934 
2935   if (!edit_find_dialog)
2936     {
2937       Widget dl, rc;
2938       Arg args[20];
2939       int n;
2940       XmString go_away, next;
2941 
2942       n = 0;
2943       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
2944 
2945       go_away = XmStringCreateLocalized((char *)I_GO_AWAY);
2946       next = XmStringCreateLocalized((char *)I_NEXT);
2947 
2948       XtSetArg(args[n], XmNokLabelString, next); n++;
2949       XtSetArg(args[n], XmNcancelLabelString, go_away); n++;
2950       XtSetArg(args[n], XmNautoUnmanage, false); n++;
2951       XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
2952       XtSetArg(args[n], XmNnoResize, false); n++;
2953       XtSetArg(args[n], XmNtransient, false); n++;
2954       edit_find_dialog = XmCreateMessageDialog(main_shell(ss), (char *)I_FIND, args, n);
2955 
2956       XmStringFree(go_away);
2957       XmStringFree(next);
2958 
2959       XtUnmanageChild(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_SYMBOL_LABEL));
2960       XtUnmanageChild(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_MESSAGE_LABEL));
2961 
2962       XtAddCallback(edit_find_dialog, XmNhelpCallback, edit_find_help_callback, NULL);
2963       XtAddCallback(edit_find_dialog, XmNcancelCallback, edit_find_cancel_callback, NULL);
2964       XtAddCallback(edit_find_dialog, XmNokCallback, edit_find_next_callback, NULL);
2965 
2966       n = 0;
2967       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
2968       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
2969       previousB = XtCreateManagedWidget(I_PREVIOUS, xmPushButtonGadgetClass, edit_find_dialog, args, n);
2970       XtAddCallback(previousB, XmNactivateCallback, edit_find_previous_callback, NULL);
2971 
2972       rc = XtCreateManagedWidget("row", xmFormWidgetClass, edit_find_dialog, NULL, 0);
2973 
2974       n = 0;
2975       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2976       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
2977       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2978       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
2979       dl = XtCreateManagedWidget(I_find, xmLabelWidgetClass, rc, args, n);
2980 
2981       n = 0;
2982       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
2983       XtSetArg(args[n], XmNleftWidget, dl); n++;
2984       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
2985       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2986       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2987       edit_find_text = make_textfield_widget("text", rc, args, n, ACTIVATABLE, add_completer_func(expression_completer, NULL));
2988 
2989       n = 0;
2990       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2991       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
2992       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2993       XtSetArg(args[n], XmNtopWidget, edit_find_text); n++;
2994       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2995       XtSetArg(args[n], XmNmarginHeight, 10); n++;
2996       edit_find_label = XtCreateManagedWidget("    ", xmLabelWidgetClass, rc, args, n);
2997 
2998       n = 0;
2999       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
3000       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
3001       XtSetArg(args[n], XmNtopWidget, edit_find_label); n++;
3002       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
3003       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
3004       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
3005       XtSetArg(args[n], XmNallowResize, true); n++;
3006       XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++;
3007       XtSetArg(args[n], XmNshadowThickness, 2); n++;
3008       find_error_frame = XtCreateManagedWidget("find-error-frame", xmFrameWidgetClass, rc, args, n);
3009 
3010       n = 0;
3011       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
3012       find_error_label = XtCreateManagedWidget("", xmLabelWidgetClass, find_error_frame, args, n);
3013 
3014       map_over_children(edit_find_dialog, set_main_color_of_widget);
3015       XtVaSetValues(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL);
3016       XtVaSetValues(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL);
3017       XtVaSetValues(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL);
3018       XtVaSetValues(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL);
3019       XtVaSetValues(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL);
3020       XtVaSetValues(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL);
3021 
3022       cancelB = XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_CANCEL_BUTTON);
3023       set_dialog_widget(FIND_DIALOG, edit_find_dialog);
3024 
3025       XtUnmanageChild(find_error_frame);
3026       if (managed) XtManageChild(edit_find_dialog);
3027       {
3028 	Atom wm_delete_window;
3029 	wm_delete_window = XmInternAtom(main_display(ss), (char *)"WM_DELETE_WINDOW", false);
3030 	XmAddWMProtocolCallback(XtParent(edit_find_dialog), wm_delete_window, find_dialog_close, NULL);
3031       }
3032     }
3033   else
3034     {
3035       if (managed)
3036 	{
3037 	  if (!XtIsManaged(edit_find_dialog)) XtManageChild(edit_find_dialog);
3038 	  raise_dialog(edit_find_dialog);
3039 	}
3040     }
3041 
3042   {
3043     XmString titlestr;
3044     if (cp)
3045       titlestr = XmStringCreateLocalized(mus_format("%s in %s channel %d", (char *)I_FIND, cp->sound->short_filename, cp->chan));
3046     else titlestr = XmStringCreateLocalized((char *)I_FIND);
3047     XtVaSetValues(edit_find_dialog, XmNdialogTitle, titlestr, NULL);
3048     XmStringFree(titlestr);
3049   }
3050 }
3051 
3052 
edit_find_callback(Widget w,XtPointer context,XtPointer info)3053 static void edit_find_callback(Widget w, XtPointer context, XtPointer info)
3054 {
3055   make_edit_find_dialog(true, NULL);
3056 }
3057 
3058 
find_dialog(chan_info * cp)3059 void find_dialog(chan_info *cp)
3060 {
3061   make_edit_find_dialog(true, cp);
3062 }
3063 
3064 
find_dialog_is_active(void)3065 bool find_dialog_is_active(void)
3066 {
3067   return((edit_find_dialog) && (XtIsManaged(edit_find_dialog)));
3068 }
3069 
3070 
save_find_dialog_state(FILE * fd)3071 void save_find_dialog_state(FILE *fd)
3072 {
3073   if (find_dialog_is_active())
3074     {
3075       char *text = NULL;
3076       text = XmTextGetString(edit_find_text);
3077       if ((text) && (*text))
3078 	{
3079 #if HAVE_SCHEME
3080 	  fprintf(fd, "(%s #t \"%s\")\n", S_find_dialog, text);
3081 #endif
3082 #if HAVE_RUBY
3083 	  fprintf(fd, "%s(true, \"%s\")\n", to_proc_name(S_find_dialog), text);
3084 #endif
3085 #if HAVE_FORTH
3086 	  fprintf(fd, "#t \"%s\" %s drop\n", text, S_find_dialog);
3087 #endif
3088 	  XtFree(text);
3089 	}
3090       else
3091 	{
3092 #if HAVE_SCHEME
3093 	  if (ss->search_expr)
3094 	    fprintf(fd, "(%s #t \"%s\")\n", S_find_dialog, ss->search_expr);
3095 	  else fprintf(fd, "(%s #t)\n", S_find_dialog);
3096 #endif
3097 #if HAVE_RUBY
3098 	  if (ss->search_expr)
3099 	    fprintf(fd, "%s(true, \"%s\")\n", to_proc_name(S_find_dialog), ss->search_expr);
3100 	  else fprintf(fd, "%s(true)\n", to_proc_name(S_find_dialog));
3101 #endif
3102 #if HAVE_FORTH
3103 	  if (ss->search_expr)
3104 	    fprintf(fd, "#t \"%s\" %s drop\n", ss->search_expr, S_find_dialog);
3105 	  else fprintf(fd, "#t %s drop\n", S_find_dialog);
3106 #endif
3107 	}
3108     }
3109 }
3110 
3111 
g_find_dialog(Xen managed,Xen text)3112 static Xen g_find_dialog(Xen managed, Xen text)
3113 {
3114   #define H_find_dialog "(" S_find_dialog " :optional managed text): create and activate the Edit:Find dialog, return the dialog widget. \
3115 If 'text' is included, it is preloaded into the find dialog text widget."
3116 
3117   Xen_check_type(Xen_is_boolean_or_unbound(managed), managed, 1, S_find_dialog, "a boolean");
3118   Xen_check_type(Xen_is_string_or_unbound(text), text, 2, S_find_dialog, "a string");
3119 
3120   make_edit_find_dialog(Xen_boolean_to_C_bool(managed), NULL);
3121   if ((edit_find_text) && (Xen_is_string(text)))
3122     XmTextSetString(edit_find_text, (char *)Xen_string_to_C_string(text));
3123 
3124   return(Xen_wrap_widget(edit_find_dialog));
3125 }
3126 
3127 
g_find_dialog_widgets(void)3128 static Xen g_find_dialog_widgets(void)
3129 {
3130   if (edit_find_dialog)
3131     return(Xen_cons(Xen_wrap_widget(edit_find_dialog),
3132 	     Xen_cons(Xen_wrap_widget(edit_find_text),
3133   	       Xen_cons(Xen_wrap_widget(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_OK_BUTTON)),           /* find next */
3134 		 Xen_cons(Xen_wrap_widget(previousB),                                                          /* find previous */
3135 		   Xen_cons(Xen_wrap_widget(XmMessageBoxGetChild(edit_find_dialog, XmDIALOG_CANCEL_BUTTON)),   /* go away */
3136 		     Xen_empty_list))))));
3137   return(Xen_empty_list);
3138 }
3139 
3140 
3141 
3142 #define NAME_COLUMNS 8
3143 
3144 /* ---------------- mix dialog ---------------- */
3145 
3146 static Widget mix_dialog = NULL;
3147 static int mix_dialog_id = INVALID_MIX_ID, old_mix_dialog_id = INVALID_MIX_ID;
3148 static env *dialog_env = NULL;
3149 
3150 static bool dragging = false;
3151 static int edpos_before_drag;
3152 static with_hook_t hookable_before_drag;
3153 static mus_long_t drag_beg = 0, drag_end = 0;
3154 
start_dragging(int mix_id)3155 static void start_dragging(int mix_id)
3156 {
3157   chan_info *cp;
3158   cp = mix_chan_info_from_id(mix_id);
3159   edpos_before_drag = cp->edit_ctr;
3160   hookable_before_drag = cp->hookable;
3161   cp->hookable = WITHOUT_HOOK;
3162   dragging = true;
3163   drag_beg = mix_position_from_id(mix_id);
3164   drag_end = drag_beg + mix_length_from_id(mix_id);
3165   start_dragging_syncd_mixes(mix_id);
3166 }
3167 
3168 
keep_dragging(int mix_id)3169 static void keep_dragging(int mix_id)
3170 {
3171   chan_info *cp;
3172   cp = mix_chan_info_from_id(mix_id);
3173   cp->edit_ctr = edpos_before_drag;
3174   keep_dragging_syncd_mixes(mix_id);
3175 }
3176 
3177 
stop_dragging(int mix_id)3178 static void stop_dragging(int mix_id)
3179 {
3180   chan_info *cp;
3181   cp = mix_chan_info_from_id(mix_id);
3182   undo_edit(cp, 1);
3183   cp->hookable = hookable_before_drag;
3184   dragging = false;
3185   stop_dragging_syncd_mixes(mix_id);
3186 }
3187 
3188 
3189 /* -------- speed -------- */
3190 
3191 static Widget w_speed_number, w_speed_label, w_speed;
3192 static speed_style_t xmix_speed_control_style = SPEED_CONTROL_AS_FLOAT;
3193 
speed_to_scrollbar(mus_float_t minval,mus_float_t val,mus_float_t maxval)3194 static int speed_to_scrollbar(mus_float_t minval, mus_float_t val, mus_float_t maxval)
3195 {
3196   if (val <= minval) return(0);
3197   if (val >= maxval) return((int)(0.9 * SCROLLBAR_MAX));
3198   return(snd_round(0.9 * SCROLLBAR_MAX * ((log(val) - log(minval)) / (log(maxval) - log(minval)))));
3199 }
3200 
3201 
set_speed_label(Widget speed_number,int ival)3202 static mus_float_t set_speed_label(Widget speed_number, int ival)
3203 {
3204   char speed_number_buffer[6];
3205   mus_float_t speed;
3206   speed = speed_changed(exp((ival * (log(speed_control_max(ss)) - log(speed_control_min(ss))) / (0.9 * SCROLLBAR_MAX)) + log(speed_control_min(ss))),
3207 			speed_number_buffer,
3208 			xmix_speed_control_style,
3209 			speed_control_tones(ss),
3210 			6);
3211   set_label(speed_number, speed_number_buffer);
3212   return(speed);
3213 }
3214 
3215 
mix_speed_click_callback(Widget w,XtPointer context,XtPointer info)3216 static void mix_speed_click_callback(Widget w, XtPointer context, XtPointer info)
3217 {
3218   char speed_number_buffer[6];
3219   mus_float_t speed;
3220 
3221   if (!(mix_is_active(mix_dialog_id))) return;
3222   speed = speed_changed(1.0,
3223 			speed_number_buffer,
3224 			xmix_speed_control_style,
3225 			speed_control_tones(ss),
3226 			6);
3227 
3228   drag_beg = mix_position_from_id(mix_dialog_id);
3229   drag_end = drag_beg + mix_length_from_id(mix_dialog_id);
3230 
3231   mix_set_speed_edit(mix_dialog_id, speed);
3232   syncd_mix_set_speed(mix_dialog_id, speed);
3233   after_mix_edit(mix_dialog_id);
3234   set_label(w_speed_number, speed_number_buffer);
3235   XtVaSetValues(w_speed, XmNvalue, speed_to_scrollbar(speed_control_min(ss), 1.0, speed_control_max(ss)), NULL);
3236 }
3237 
3238 
mix_speed_label_click_callback(Widget w,XtPointer context,XtPointer info)3239 static void mix_speed_label_click_callback(Widget w, XtPointer context, XtPointer info)
3240 {
3241   char speed_number_buffer[6];
3242   if (!(mix_is_active(mix_dialog_id))) return;
3243   switch (xmix_speed_control_style)
3244     {
3245     default:
3246     case SPEED_CONTROL_AS_FLOAT:    xmix_speed_control_style = SPEED_CONTROL_AS_RATIO;    break;
3247     case SPEED_CONTROL_AS_RATIO:    xmix_speed_control_style = SPEED_CONTROL_AS_SEMITONE; break;
3248     case SPEED_CONTROL_AS_SEMITONE: xmix_speed_control_style = SPEED_CONTROL_AS_FLOAT;    break;
3249     }
3250   speed_changed(mix_speed_from_id(mix_dialog_id),
3251 		speed_number_buffer,
3252 		xmix_speed_control_style,
3253 		speed_control_tones(ss),
3254 		6);
3255   set_label(w_speed_number, speed_number_buffer);
3256 }
3257 
3258 
mix_speed_drag_callback(Widget w,XtPointer context,XtPointer info)3259 static void mix_speed_drag_callback(Widget w, XtPointer context, XtPointer info)
3260 {
3261   int ival;
3262   mus_float_t speed;
3263   mus_long_t beg, end;
3264 
3265   if (!(mix_is_active(mix_dialog_id))) return;
3266 
3267   ival = ((XmScrollBarCallbackStruct *)info)->value;
3268   if (!dragging)
3269     start_dragging(mix_dialog_id);
3270   else keep_dragging(mix_dialog_id);
3271 
3272   speed = set_speed_label(w_speed_number, ival);
3273   mix_set_speed_edit(mix_dialog_id, speed);
3274 
3275   beg = mix_position_from_id(mix_dialog_id);
3276   end = beg + mix_length_from_id(mix_dialog_id);
3277   if (drag_beg > beg) drag_beg = beg;
3278   if (drag_end < end) drag_end = end;
3279 
3280   mix_display_during_drag(mix_dialog_id, drag_beg, drag_end);
3281   syncd_mix_set_speed(mix_dialog_id, speed);
3282 }
3283 
3284 
mix_speed_valuechanged_callback(Widget w,XtPointer context,XtPointer info)3285 static void mix_speed_valuechanged_callback(Widget w, XtPointer context, XtPointer info)
3286 {
3287   XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info;
3288   mus_float_t speed;
3289 
3290   if (!(mix_is_active(mix_dialog_id))) return;
3291   if (dragging)
3292     stop_dragging(mix_dialog_id);
3293 
3294   speed = set_speed_label(w_speed_number, cb->value);
3295   mix_set_speed_edit(mix_dialog_id, speed);
3296   syncd_mix_set_speed(mix_dialog_id, speed);
3297   after_mix_edit(mix_dialog_id);
3298   after_syncd_mix_edit(mix_dialog_id);
3299 }
3300 
3301 
3302 /* -------- amp -------- */
3303 
3304 static Widget w_amp_number, w_amp_label, w_amp;
3305 
scrollbar_to_amp(int val)3306 static mus_float_t scrollbar_to_amp(int val)
3307 {
3308   if (val <= 0)
3309     return(amp_control_min(ss));
3310   if (val >= (0.9 * SCROLLBAR_MAX))
3311     return(amp_control_max(ss));
3312   if (val > (0.5 * 0.9 * SCROLLBAR_MAX))
3313     return((((val / (0.5 * 0.9 * SCROLLBAR_MAX)) - 1.0) * (amp_control_max(ss) - 1.0)) + 1.0);
3314   else return((val * (1.0 - amp_control_min(ss)) / (0.5 * 0.9 * SCROLLBAR_MAX)) + amp_control_min(ss));
3315 }
3316 
3317 
amp_to_scrollbar(Widget amp_number,mus_float_t amp)3318 static int amp_to_scrollbar(Widget amp_number, mus_float_t amp)
3319 {
3320   char sfs[6];
3321   snprintf(sfs, 6, "%.2f", amp);
3322   set_label(amp_number, sfs);
3323   return(amp_to_scroll(amp_control_min(ss), amp, amp_control_max(ss)));
3324 }
3325 
3326 
change_mix_amp(int mix_id,mus_float_t val)3327 static void change_mix_amp(int mix_id, mus_float_t val)
3328 {
3329   char sfs[6];
3330   mix_set_amp_edit(mix_id, val);
3331   syncd_mix_set_amp(mix_id, val);
3332   snprintf(sfs, 6, "%.2f", val);
3333   set_label(w_amp_number, sfs);
3334 }
3335 
3336 
mix_amp_click_callback(Widget w,XtPointer context,XtPointer info)3337 static void mix_amp_click_callback(Widget w, XtPointer context, XtPointer info)
3338 {
3339   if (!(mix_is_active(mix_dialog_id))) return;
3340   change_mix_amp(mix_dialog_id, 1.0);
3341   after_mix_edit(mix_dialog_id);
3342   XtVaSetValues(w_amp, XmNvalue, amp_to_scroll(amp_control_min(ss), 1.0, amp_control_max(ss)), NULL);
3343 }
3344 
3345 
mix_amp_drag_callback(Widget w,XtPointer context,XtPointer info)3346 static void mix_amp_drag_callback(Widget w, XtPointer context, XtPointer info)
3347 {
3348   int ival;
3349   if (!(mix_is_active(mix_dialog_id))) return;
3350   ival = ((XmScrollBarCallbackStruct *)info)->value;
3351   if (!dragging)
3352     start_dragging(mix_dialog_id);
3353   else keep_dragging(mix_dialog_id);
3354   change_mix_amp(mix_dialog_id, scrollbar_to_amp(ival));
3355   mix_display_during_drag(mix_dialog_id, drag_beg, drag_end);
3356 }
3357 
3358 
mix_amp_valuechanged_callback(Widget w,XtPointer context,XtPointer info)3359 static void mix_amp_valuechanged_callback(Widget w, XtPointer context, XtPointer info)
3360 {
3361   int ival;
3362   if (!(mix_is_active(mix_dialog_id))) return;
3363   ival = ((XmScrollBarCallbackStruct *)info)->value;
3364   if (dragging)
3365     stop_dragging(mix_dialog_id);
3366   change_mix_amp(mix_dialog_id, scrollbar_to_amp(ival));
3367   after_mix_edit(mix_dialog_id);
3368   after_syncd_mix_edit(mix_dialog_id);
3369 }
3370 
3371 
3372 /* -------- amp-env -------- */
3373 
3374 static Widget w_env_frame, w_env;
3375 static graphics_context *ax = NULL;
3376 static GC cur_gc;
3377 static env_editor *spf = NULL;
3378 static bool with_mix_background_wave = false;
3379 
show_mix_background_wave(int mix_id)3380 static void show_mix_background_wave(int mix_id)
3381 {
3382   int pts;
3383   bool two_sided = false;
3384   if (!spf) return;
3385   pts = prepare_mix_dialog_waveform(mix_id, spf->axis, &two_sided);
3386   if (pts > 0)
3387     {
3388       XSetForeground(main_display(ss), ax->gc, ss->enved_waveform_color);
3389       if (two_sided)
3390 	draw_both_grf_points(1, ax, pts, GRAPH_LINES);
3391       else draw_grf_points(1, ax, pts, spf->axis, ungrf_y(spf->axis, 0.0), GRAPH_LINES);
3392       XSetForeground(main_display(ss), ax->gc, ss->black);
3393     }
3394 }
3395 
3396 
mix_amp_env_resize(Widget w,XtPointer context,XtPointer info)3397 static void mix_amp_env_resize(Widget w, XtPointer context, XtPointer info)
3398 {
3399   env *cur_env;
3400   if (!(mix_is_active(mix_dialog_id))) return;
3401 
3402   if (!ax)
3403     {
3404       XGCValues gv;
3405       gv.function = GXcopy;
3406       XtVaGetValues(w_env, XmNbackground, &gv.background, XmNforeground, &gv.foreground, NULL);
3407       cur_gc = XtGetGC(w_env, GCForeground | GCFunction, &gv);
3408       ax = (graphics_context *)calloc(1, sizeof(graphics_context));
3409       ax->wn = XtWindow(w_env);
3410       ax->dp = XtDisplay(w_env);
3411       ax->gc = cur_gc;
3412     }
3413   else clear_window(ax);
3414 
3415   cur_env = dialog_env;
3416   spf->with_dots = true;
3417   env_editor_display_env(spf, cur_env, ax, "mix env", 0, 0, widget_width(w), widget_height(w), NOT_PRINTING);
3418   if (with_mix_background_wave)
3419     show_mix_background_wave(mix_dialog_id);
3420 }
3421 
3422 
3423 #ifdef __APPLE__
3424 static int press_x, press_y;
3425 #endif
3426 
mix_drawer_button_motion(Widget w,XtPointer context,XEvent * event,Boolean * cont)3427 static void mix_drawer_button_motion(Widget w, XtPointer context, XEvent *event, Boolean *cont)
3428 {
3429   XMotionEvent *ev = (XMotionEvent *)event;
3430   if (!(mix_is_active(mix_dialog_id))) return;
3431 #ifdef __APPLE__
3432   if ((press_x == ev->x) && (press_y == ev->y)) return;
3433 #endif
3434   env_editor_button_motion(spf, ev->x, ev->y, ev->time, dialog_env);
3435   mix_amp_env_resize(w, NULL, NULL);
3436 }
3437 
3438 
mix_drawer_button_press(Widget w,XtPointer context,XEvent * event,Boolean * cont)3439 static void mix_drawer_button_press(Widget w, XtPointer context, XEvent *event, Boolean *cont)
3440 {
3441   XButtonEvent *ev = (XButtonEvent *)event;
3442   if (!(mix_is_active(mix_dialog_id))) return;
3443 #ifdef __APPLE__
3444   press_x = ev->x;
3445   press_y = ev->y;
3446 #endif
3447   if (env_editor_button_press(spf, ev->x, ev->y, ev->time, dialog_env))
3448     mix_amp_env_resize(w, NULL, NULL);
3449 }
3450 
3451 
mix_drawer_button_release(Widget w,XtPointer context,XEvent * event,Boolean * cont)3452 static void mix_drawer_button_release(Widget w, XtPointer context, XEvent *event, Boolean *cont)
3453 {
3454   if (!(mix_is_active(mix_dialog_id))) return;
3455   env_editor_button_release(spf, dialog_env);
3456   mix_amp_env_resize(w, NULL, NULL);
3457 }
3458 
3459 
3460 static Widget w_id = NULL, w_beg = NULL;
3461 #if WITH_AUDIO
3462   static Widget mix_play = NULL;
3463 #endif
3464 static Widget error_frame = NULL, error_label = NULL;
3465 
clear_mix_error(void)3466 static void clear_mix_error(void)
3467 {
3468   if ((error_frame) && (XtIsManaged(error_frame)))
3469     XtUnmanageChild(error_frame);
3470 }
3471 
3472 
unpost_mix_error(XtPointer data,XtIntervalId * id)3473 static void unpost_mix_error(XtPointer data, XtIntervalId *id)
3474 {
3475   clear_mix_error();
3476 }
3477 
3478 
errors_to_mix_text(const char * msg,void * data)3479 static void errors_to_mix_text(const char *msg, void *data)
3480 {
3481   int lines = 0;
3482   XmString label;
3483   label = multi_line_label(msg, &lines);
3484   XtVaSetValues(error_label,
3485 		XmNlabelString, label,
3486 		XmNheight, lines * 20,
3487 		NULL);
3488   XtVaSetValues(error_frame, XmNheight, lines * 20, NULL);
3489   XmStringFree(label);
3490   XtManageChild(error_frame);
3491   /* since the offending text is automatically overwritten, we can't depend on subsequent text modify callbacks
3492    *   to clear things, so we'll just use a timer
3493    */
3494   XtAppAddTimeOut(main_app(ss),
3495 		  5000,
3496 		  (XtTimerCallbackProc)unpost_mix_error,
3497 		  NULL);
3498 }
3499 
3500 
widget_mix_to_text(Widget w,int id)3501 static void widget_mix_to_text(Widget w, int id)
3502 {
3503   if (mix_name(id))
3504     XmTextFieldSetString(w, (char *)mix_name(id));
3505   else widget_int_to_text(w, id);
3506 }
3507 
3508 
3509 static bool id_changed = false;
3510 
id_activated(void)3511 static void id_activated(void)
3512 {
3513   char *val;
3514   id_changed = false;
3515   val = XmTextGetString(w_id);
3516   if (val)
3517     {
3518       int id;
3519       /* look for a mix name first, then a number */
3520       id = mix_name_to_id(val);
3521       if (id < 0)
3522 	{
3523 	  redirect_errors_to(errors_to_mix_text, NULL);
3524 	  id = string_to_int(val, 0, "id");
3525 	  redirect_errors_to(NULL, NULL);
3526 	}
3527       if (mix_is_active(id))
3528 	{
3529 	  mix_dialog_id = id;
3530 	  reflect_mix_change(id);
3531 	}
3532       XtFree(val);
3533     }
3534 }
3535 
3536 
id_modify_callback(Widget w,XtPointer context,XtPointer info)3537 static void id_modify_callback(Widget w, XtPointer context, XtPointer info)
3538 {
3539   id_changed = true;
3540 }
3541 
3542 
id_check_callback(Widget w,XtPointer context,XtPointer info)3543 static void id_check_callback(Widget w, XtPointer context, XtPointer info)
3544 {
3545   if (id_changed) id_activated();
3546 }
3547 
3548 
beg_activated(void)3549 static void beg_activated(void)
3550 {
3551   char *val;
3552   if (!(mix_is_active(mix_dialog_id))) return;
3553   val = XmTextGetString(w_beg);
3554   if (val)
3555     {
3556       chan_info *cp;
3557       char *up_to_colon;
3558       mus_float_t beg;
3559       cp = mix_chan_info_from_id(mix_dialog_id);
3560       up_to_colon = string_to_colon(val);
3561       redirect_errors_to(errors_to_mix_text, NULL);
3562       beg = string_to_mus_float_t(up_to_colon, 0.0, "begin time");
3563       redirect_errors_to(NULL, NULL);
3564       if (beg >= 0.0)
3565 	{
3566 	  mus_long_t pos, old_pos;
3567 	  old_pos = mix_position_from_id(mix_dialog_id);
3568 	  pos = (mus_long_t)(beg * snd_srate(cp->sound));
3569 	  mix_set_position_edit(mix_dialog_id, pos);
3570 	  syncd_mix_change_position(mix_dialog_id, pos - old_pos);
3571 	}
3572       after_mix_edit(mix_dialog_id);
3573       free(up_to_colon);
3574       XtFree(val);
3575     }
3576 }
3577 
3578 
apply_mix_dialog_callback(Widget w,XtPointer context,XtPointer info)3579 static void apply_mix_dialog_callback(Widget w, XtPointer context, XtPointer info)
3580 {
3581   if (!(mix_is_active(mix_dialog_id))) return;
3582   if ((dialog_env) &&
3583       (!(is_default_env(dialog_env))))
3584     {
3585       mix_set_amp_env_edit(mix_dialog_id, dialog_env);
3586       syncd_mix_set_amp_env(mix_dialog_id, dialog_env);
3587     }
3588   else
3589     {
3590       mix_set_amp_env_edit(mix_dialog_id, NULL);
3591       syncd_mix_set_amp_env(mix_dialog_id, NULL);
3592     }
3593   mix_amp_env_resize(w_env, NULL, NULL);
3594   after_mix_edit(mix_dialog_id);
3595 }
3596 
3597 
copy_mix_dialog_callback(Widget w,XtPointer context,XtPointer info)3598 static void copy_mix_dialog_callback(Widget w, XtPointer context, XtPointer info)
3599 {
3600   Widget active_widget;
3601   active_widget = XmGetFocusWidget(mix_dialog);
3602   if (active_widget == XmMessageBoxGetChild(mix_dialog, XmDIALOG_OK_BUTTON))
3603     {
3604       copy_mix(mix_dialog_id);
3605       after_mix_edit(mix_dialog_id);
3606     }
3607   else
3608     {
3609       if (active_widget == w_id)
3610 	id_activated();
3611       else
3612 	{
3613 	  if (active_widget == w_beg)
3614 	    beg_activated();
3615 	}
3616     }
3617 }
3618 
3619 
quit_mix_dialog_callback(Widget w,XtPointer context,XtPointer info)3620 static void quit_mix_dialog_callback(Widget w, XtPointer context, XtPointer info)
3621 {
3622   clear_mix_error();
3623   XtUnmanageChild(mix_dialog);
3624 }
3625 
3626 
help_mix_dialog_callback(Widget w,XtPointer context,XtPointer info)3627 static void help_mix_dialog_callback(Widget w, XtPointer context, XtPointer info)
3628 {
3629   mix_dialog_help();
3630 }
3631 
3632 
3633 /* -------- play -------- */
3634 
3635 #if WITH_AUDIO
3636   static bool mix_playing = false;
3637 #endif
3638 
reflect_mix_play_stop(void)3639 void reflect_mix_play_stop(void)
3640 {
3641 #if WITH_AUDIO
3642   if (mix_play)
3643     XmChangeColor(mix_play, ss->basic_color);
3644   mix_playing = false;
3645 #endif
3646 }
3647 
3648 
3649 #if WITH_AUDIO
mix_dialog_play_callback(Widget w,XtPointer context,XtPointer info)3650 static void mix_dialog_play_callback(Widget w, XtPointer context, XtPointer info)
3651 {
3652   if (mix_playing)
3653     reflect_mix_play_stop();
3654   else
3655     {
3656       if (!(mix_exists(mix_dialog_id))) return;
3657       if (mix_play)
3658 	XmChangeColor(mix_play, ss->selection_color); /* this needs to happen before trying to play */
3659       syncd_mix_play(mix_dialog_id);
3660       mix_playing = true;                                      /* don't use the return value here */
3661       play_mix_from_id(mix_dialog_id);
3662     }
3663 }
3664 #endif
3665 
3666 
3667 /* -------- dB -------- */
3668 
mix_dB_callback(Widget w,XtPointer context,XtPointer info)3669 static void mix_dB_callback(Widget w, XtPointer context, XtPointer info)
3670 {
3671   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
3672   spf->in_dB = cb->set;
3673   mix_amp_env_resize(w_env, NULL, NULL);
3674 }
3675 
3676 
3677 /* -------- sync -------- */
3678 
mix_sync_callback(Widget w,XtPointer context,XtPointer info)3679 static void mix_sync_callback(Widget w, XtPointer context, XtPointer info)
3680 {
3681   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
3682   if ((cb->set) &&
3683       (mix_sync_from_id(mix_dialog_id) == 0))
3684     {
3685       mix_set_sync_from_id(mix_dialog_id, GET_ORIGINAL_SYNC);  /* choose a new sync val or return to previous */
3686       /* check for resync */
3687       syncd_mix_set_color(mix_dialog_id, ss->red);
3688     }
3689   else
3690     {
3691       if ((!(cb->set)) &&
3692 	  (mix_sync_from_id(mix_dialog_id) != 0))
3693 	{
3694 	  syncd_mix_unset_color(mix_dialog_id); /* unset colors of any syncd mixes */
3695 	  mix_set_sync_from_id(mix_dialog_id, 0);
3696 	}
3697     }
3698   for_each_normal_chan(display_channel_mixes);
3699 }
3700 
3701 
3702 /* -------- clip -------- */
3703 
mix_clip_callback(Widget w,XtPointer context,XtPointer info)3704 static void mix_clip_callback(Widget w, XtPointer context, XtPointer info)
3705 {
3706   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
3707   spf->clipping = cb->set;
3708   mix_amp_env_resize(w_env, NULL, NULL);
3709 }
3710 
3711 
3712 /* -------- wave -------- */
3713 
mix_wave_callback(Widget w,XtPointer context,XtPointer info)3714 static void mix_wave_callback(Widget w, XtPointer context, XtPointer info)
3715 {
3716   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
3717   with_mix_background_wave = cb->set;
3718   mix_amp_env_resize(w_env, NULL, NULL);
3719 }
3720 
3721 
3722 /* -------- next/previous -------- */
3723 
3724 static Widget mix_next_button, mix_previous_button;
3725 
mix_next_callback(Widget w,XtPointer context,XtPointer info)3726 static void mix_next_callback(Widget w, XtPointer context, XtPointer info)
3727 {
3728   int id;
3729   clear_mix_error();
3730   id = next_mix_id(mix_dialog_id);
3731   if (id != INVALID_MIX_ID)
3732     {
3733       mix_dialog_id = id;
3734       reflect_mix_change(id);
3735       if (next_mix_id(id) == INVALID_MIX_ID)
3736 	set_sensitive(mix_next_button, false);
3737     }
3738 }
3739 
3740 
mix_previous_callback(Widget w,XtPointer context,XtPointer info)3741 static void mix_previous_callback(Widget w, XtPointer context, XtPointer info)
3742 {
3743   int id;
3744   clear_mix_error();
3745   id = previous_mix_id(mix_dialog_id);
3746   if (id != INVALID_MIX_ID)
3747     {
3748       mix_dialog_id = id;
3749       reflect_mix_change(id);
3750       if (previous_mix_id(id) == INVALID_MIX_ID)
3751 	set_sensitive(mix_previous_button, false);
3752     }
3753 }
3754 
3755 
make_pixmap(unsigned char * bits,int width,int height,int depth,GC gc)3756 static Pixmap make_pixmap(unsigned char *bits, int width, int height, int depth, GC gc)
3757 {
3758   Pixmap rb, nr;
3759   rb = XCreateBitmapFromData(main_display(ss),
3760 			     RootWindowOfScreen(XtScreen(main_pane(ss))),
3761 			     (const char *)bits,
3762 			     width, height);
3763   nr = XCreatePixmap(main_display(ss),
3764 		     RootWindowOfScreen(XtScreen(main_pane(ss))),
3765 		     width, height, depth);
3766   XCopyPlane(main_display(ss), rb, nr, gc, 0, 0, width, height, 0, 0, 1);
3767   XFreePixmap(main_display(ss), rb);
3768   return(nr);
3769 }
3770 
3771 
3772 
3773 #define p_speaker_width 12
3774 #define p_speaker_height 12
3775 static unsigned char p_speaker_bits[] = {
3776    0x00, 0x07, 0xc0, 0x04, 0x30, 0x04, 0x0e, 0x04, 0x06, 0x04, 0x06, 0x04,
3777    0x06, 0x04, 0x06, 0x04, 0x0e, 0x04, 0x30, 0x04, 0xc0, 0x04, 0x00, 0x07};
3778 
3779 static int mixer_depth;
3780 static GC gc;
3781 static Pixmap speaker_r;
3782 
make_mixer_icons_transparent_again(Pixel old_color,Pixel new_color)3783 void make_mixer_icons_transparent_again(Pixel old_color, Pixel new_color)
3784 {
3785   if (mix_dialog)
3786     {
3787       XFreePixmap(XtDisplay(mix_dialog), speaker_r);
3788       XSetBackground(XtDisplay(mix_dialog), gc, new_color);
3789       speaker_r = make_pixmap(p_speaker_bits, p_speaker_width, p_speaker_height, mixer_depth, gc);
3790 #if WITH_AUDIO
3791       XtVaSetValues(mix_play, XmNlabelPixmap, speaker_r, NULL);
3792 #endif
3793     }
3794 }
3795 
3796 static Widget w_sync;
3797 
make_mix_dialog(void)3798 Widget make_mix_dialog(void)
3799 {
3800   if (!mix_dialog)
3801     {
3802       Widget mainform, mix_row, mix_frame, sep, w_sep1;
3803       Widget w_dB_frame, w_dB, w_clip, w_wave, w_dB_row, env_button, copy_button;
3804       XmString xgo_away, xhelp, xtitle, s1, xcopy;
3805       int n;
3806       Arg args[20];
3807       XtCallbackList n1, n2;
3808       XGCValues v;
3809       char amplab[LABEL_BUFFER_SIZE];
3810 
3811       xmix_speed_control_style = speed_control_style(ss);
3812 
3813       mix_dialog_id = any_mix_id();
3814       xgo_away = XmStringCreateLocalized((char *)I_GO_AWAY);
3815       xcopy = XmStringCreateLocalized((char *)"Copy mix");
3816       xhelp = XmStringCreateLocalized((char *)I_HELP);
3817       xtitle = XmStringCreateLocalized((char *)"Mixes");
3818 
3819       n = 0;
3820       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
3821       XtSetArg(args[n], XmNokLabelString, xcopy); n++;
3822       XtSetArg(args[n], XmNcancelLabelString, xgo_away); n++;
3823       XtSetArg(args[n], XmNhelpLabelString, xhelp); n++;
3824       XtSetArg(args[n], XmNautoUnmanage, false); n++;
3825       XtSetArg(args[n], XmNdialogTitle, xtitle); n++;
3826       XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
3827       XtSetArg(args[n], XmNnoResize, false); n++;
3828       XtSetArg(args[n], XmNtransient, false); n++;
3829       mix_dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"Mixes", args, n);
3830       copy_button = XmMessageBoxGetChild(mix_dialog, XmDIALOG_OK_BUTTON);
3831 
3832       /* XtAddCallback(mix_dialog, XmNokCallback, copy_mix_dialog_callback, NULL); */
3833       XtAddCallback(copy_button, XmNactivateCallback, copy_mix_dialog_callback, NULL);
3834       XtAddCallback(mix_dialog, XmNcancelCallback, quit_mix_dialog_callback, NULL);
3835       XtAddCallback(mix_dialog, XmNhelpCallback, help_mix_dialog_callback, NULL);
3836 
3837       XmStringFree(xhelp);
3838       XmStringFree(xcopy);
3839       XmStringFree(xgo_away);
3840       XmStringFree(xtitle);
3841 
3842       XtVaSetValues(XmMessageBoxGetChild(mix_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL);
3843       XtVaSetValues(XmMessageBoxGetChild(mix_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL);
3844       XtVaSetValues(XmMessageBoxGetChild(mix_dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL);
3845       XtVaSetValues(XmMessageBoxGetChild(mix_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL);
3846       XtVaSetValues(XmMessageBoxGetChild(mix_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL);
3847       XtVaSetValues(XmMessageBoxGetChild(mix_dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL);
3848 
3849       n = 0;
3850       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
3851       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
3852       env_button = XtCreateManagedWidget("Apply env", xmPushButtonGadgetClass, mix_dialog, args, n);
3853       XtAddCallback(env_button, XmNactivateCallback, apply_mix_dialog_callback, NULL);
3854 
3855       n = 0;
3856       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
3857       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
3858       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
3859       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
3860       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
3861       XtSetArg(args[n], XmNbottomWidget, XmMessageBoxGetChild(mix_dialog, XmDIALOG_SEPARATOR)); n++;
3862       mainform = XtCreateManagedWidget("formd", xmFormWidgetClass, mix_dialog, args, n);
3863 
3864       n = 0;
3865       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
3866       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
3867       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
3868       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
3869       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
3870       XtSetArg(args[n], XmNallowResize, true); n++;
3871       XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++;
3872       XtSetArg(args[n], XmNshadowThickness, 2); n++;
3873       mix_frame = XtCreateManagedWidget("mix-frame", xmFrameWidgetClass, mainform, args, n);
3874 
3875       n = 0;
3876       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
3877       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
3878       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
3879       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
3880       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
3881       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
3882       mix_row = XtCreateManagedWidget("mix-dialog-row", xmRowColumnWidgetClass, mix_frame, args, n);
3883 
3884       n = 0;
3885       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
3886       XtCreateManagedWidget("mix:", xmLabelWidgetClass, mix_row, args, n);
3887 
3888       n = 0;
3889       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
3890       XtSetArg(args[n], XmNresizeWidth, false); n++;
3891       XtSetArg(args[n], XmNcolumns, NAME_COLUMNS); n++;
3892       XtSetArg(args[n], XmNrecomputeSize, false); n++;
3893       w_id = make_textfield_widget("mix-id", mix_row, args, n, ACTIVATABLE, NO_COMPLETER);
3894       XtAddCallback(w_id, XmNlosingFocusCallback, id_check_callback, NULL);
3895       XtAddCallback(w_id, XmNmodifyVerifyCallback, id_modify_callback, NULL);
3896       XmTextSetString(w_id, (char *)"0");
3897 
3898       n = 0;
3899       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
3900       w_beg = make_textfield_widget("mix-times", mix_row, args, n, ACTIVATABLE, NO_COMPLETER);
3901       XmTextSetString(w_beg, (char *)"0.000 : 1.000");
3902 
3903       XtVaGetValues(mix_row, XmNforeground, &v.foreground, XmNbackground, &v.background, XmNdepth, &mixer_depth, NULL);
3904       gc = XtGetGC(mix_row, GCForeground | GCBackground, &v);
3905       speaker_r = make_pixmap(p_speaker_bits, p_speaker_width, p_speaker_height, mixer_depth, gc);
3906 
3907 #if WITH_AUDIO
3908       n = 0;
3909       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
3910       XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++;
3911       XtSetArg(args[n], XmNlabelPixmap, speaker_r); n++;
3912       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
3913       mix_play = XtCreateManagedWidget("mix-play", xmPushButtonWidgetClass, mix_row, args, n);
3914       XtAddCallback(mix_play, XmNactivateCallback, mix_dialog_play_callback, NULL);
3915 #endif
3916 
3917       n = 0;
3918       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
3919       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
3920       mix_previous_button = XtCreateManagedWidget(I_PREVIOUS, xmPushButtonWidgetClass, mix_row, args, n);
3921       if (previous_mix_id(mix_dialog_id) == INVALID_MIX_ID)
3922 	set_sensitive(mix_previous_button, false);
3923       XtAddCallback(mix_previous_button, XmNactivateCallback, mix_previous_callback, NULL);
3924 
3925       n = 0;
3926       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
3927       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
3928       mix_next_button = XtCreateManagedWidget(I_NEXT, xmPushButtonWidgetClass, mix_row, args, n);
3929       if (next_mix_id(mix_dialog_id) == INVALID_MIX_ID)
3930 	set_sensitive(mix_next_button, false);
3931       XtAddCallback(mix_next_button, XmNactivateCallback, mix_next_callback, NULL);
3932 
3933 
3934 
3935       /* separator before sliders */
3936       n = 0;
3937       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
3938       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
3939       XtSetArg(args[n], XmNtopWidget, mix_row); n++;
3940       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
3941       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
3942       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
3943       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
3944       XtSetArg(args[n], XmNheight, 10); n++;
3945       XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
3946       sep = XtCreateManagedWidget("mix-dialog-sep", xmSeparatorWidgetClass, mainform, args, n);
3947 
3948       /* SPEED */
3949       n = 0;
3950       s1 = XmStringCreateLocalized((char *)"speed:");
3951       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
3952       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
3953       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
3954       XtSetArg(args[n], XmNtopWidget, sep); n++;
3955       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
3956       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
3957       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
3958       XtSetArg(args[n], XmNlabelString, s1); n++;
3959       XtSetArg(args[n], XmNrecomputeSize, false); n++;
3960       XtSetArg(args[n], XmNshadowThickness, 0); n++;
3961       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
3962       XtSetArg(args[n], XmNfillOnArm, false); n++;
3963       w_speed_label = make_pushbutton_widget("mix-speed-label", mainform, args, n);
3964       XtAddCallback(w_speed_label, XmNactivateCallback, mix_speed_click_callback, NULL);
3965       XmStringFree(s1);
3966 
3967       n = 0;
3968       s1 = initial_speed_label(xmix_speed_control_style);
3969       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
3970       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
3971       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
3972       XtSetArg(args[n], XmNtopWidget, w_speed_label); n++;
3973       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
3974       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
3975       XtSetArg(args[n], XmNleftWidget, w_speed_label); n++;
3976       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
3977       XtSetArg(args[n], XmNlabelString, s1); n++;
3978       XtSetArg(args[n], XmNrecomputeSize, false); n++;
3979       XtSetArg(args[n], XmNshadowThickness, 0); n++;
3980       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
3981       XtSetArg(args[n], XmNfillOnArm, false); n++;
3982       w_speed_number = make_pushbutton_widget("mix-speed-number", mainform, args, n);
3983       XtAddCallback(w_speed_number, XmNactivateCallback, mix_speed_label_click_callback, NULL);
3984       XmStringFree(s1);
3985 
3986       n = 0;
3987       XtSetArg(args[n], XmNbackground, ss->position_color); n++;
3988       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
3989       XtSetArg(args[n], XmNtopWidget, w_speed_number); n++;
3990       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
3991       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
3992       XtSetArg(args[n], XmNleftWidget, w_speed_number); n++;
3993       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
3994       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
3995       XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++;
3996       XtSetArg(args[n], XmNvalue, speed_to_scrollbar(speed_control_min(ss), 1.0, speed_control_max(ss))); n++;
3997       XtSetArg(args[n], XmNheight, 16); n++;
3998       XtSetArg(args[n], XmNdragCallback, n1 = make_callback_list(mix_speed_drag_callback, NULL)); n++;
3999       XtSetArg(args[n], XmNvalueChangedCallback, n2 = make_callback_list(mix_speed_valuechanged_callback, NULL)); n++;
4000       w_speed = XtCreateManagedWidget("mix-speed", xmScrollBarWidgetClass, mainform, args, n);
4001 
4002       free(n1);
4003       free(n2);
4004 
4005       n = 0;
4006       snprintf(amplab, LABEL_BUFFER_SIZE, "%s", "amp:");
4007       s1 = XmStringCreateLocalized(amplab);
4008       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
4009       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
4010       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
4011       XtSetArg(args[n], XmNtopWidget, w_speed_label); n++;
4012       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
4013       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
4014       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
4015       XtSetArg(args[n], XmNlabelString, s1); n++;
4016       XtSetArg(args[n], XmNrecomputeSize, false); n++;
4017       XtSetArg(args[n], XmNshadowThickness, 0); n++;
4018       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
4019       XtSetArg(args[n], XmNfillOnArm, false); n++;
4020       w_amp_label = make_pushbutton_widget("mix-amp-label", mainform, args, n);
4021       XtAddCallback(w_amp_label, XmNactivateCallback, mix_amp_click_callback, NULL);
4022       XmStringFree(s1);
4023 
4024       n = 0;
4025       s1 = XmStringCreateLocalized((char *)"1.00");
4026       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
4027       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
4028       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
4029       XtSetArg(args[n], XmNtopWidget, w_speed_number); n++;
4030       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
4031       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
4032       XtSetArg(args[n], XmNleftWidget, w_amp_label); n++;
4033       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
4034       XtSetArg(args[n], XmNlabelString, s1); n++;
4035       XtSetArg(args[n], XmNrecomputeSize, false); n++;
4036       w_amp_number = XtCreateManagedWidget("mix-amp-number", xmLabelWidgetClass, mainform, args, n);
4037       XmStringFree(s1);
4038 
4039       n = 0;
4040       XtSetArg(args[n], XmNbackground, ss->position_color); n++;
4041       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
4042       XtSetArg(args[n], XmNtopWidget, w_amp_number); n++;
4043       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
4044       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
4045       XtSetArg(args[n], XmNleftWidget, w_amp_number); n++;
4046       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
4047       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
4048       XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++;
4049       XtSetArg(args[n], XmNvalue, 0); n++;
4050       XtSetArg(args[n], XmNdragCallback, n1 = make_callback_list(mix_amp_drag_callback, NULL)); n++;
4051       XtSetArg(args[n], XmNvalueChangedCallback, n2 = make_callback_list(mix_amp_valuechanged_callback, NULL)); n++;
4052       w_amp = XtCreateManagedWidget("mix-amp", xmScrollBarWidgetClass, mainform, args, n);
4053       free(n1);
4054       free(n2);
4055 
4056       /* separator before envelopes */
4057       n = 0;
4058       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
4059       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
4060       XtSetArg(args[n], XmNtopWidget, w_amp_label); n++;
4061       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
4062       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
4063       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
4064       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
4065       XtSetArg(args[n], XmNheight, 8); n++;
4066       XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
4067       w_sep1 = XtCreateManagedWidget("mix-dialog-sep1", xmSeparatorWidgetClass, mainform, args, n);
4068 
4069       /* button box for dB clip wave sync */
4070       n = 0;
4071       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
4072       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
4073       XtSetArg(args[n], XmNtopWidget, w_sep1); n++;
4074       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
4075       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
4076       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
4077       XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++;
4078       XtSetArg(args[n], XmNshadowThickness, 4); n++;
4079       w_dB_frame = XtCreateManagedWidget("mix-dB-frame", xmFrameWidgetClass, mainform, args, n);
4080 
4081       n = 0;
4082       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
4083       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
4084       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
4085       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
4086       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
4087       w_dB_row = XtCreateManagedWidget("mix-dB-row", xmRowColumnWidgetClass, w_dB_frame, args, n);
4088 
4089       n = 0;
4090       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
4091       XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
4092       if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;}
4093 
4094       w_clip = make_togglebutton_widget("clip", w_dB_row, args, n);
4095       XtAddCallback(w_clip, XmNvalueChangedCallback, mix_clip_callback, NULL);
4096       XmToggleButtonSetState(w_clip, true, false);
4097 
4098       w_wave = make_togglebutton_widget("wave", w_dB_row, args, n);
4099       XtAddCallback(w_wave, XmNvalueChangedCallback, mix_wave_callback, NULL);
4100 
4101       w_dB = make_togglebutton_widget("dB", w_dB_row, args, n);
4102       XtAddCallback(w_dB, XmNvalueChangedCallback, mix_dB_callback, NULL);
4103 
4104       if (mix_sync_from_id(mix_dialog_id) != 0)
4105 	{XtSetArg(args[n], XmNset, true); n++;}
4106       w_sync = make_togglebutton_widget("sync", w_dB_row, args, n);
4107       XtAddCallback(w_sync, XmNvalueChangedCallback, mix_sync_callback, NULL);
4108 
4109 
4110       n = 0;
4111       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
4112       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
4113       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
4114       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
4115       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
4116       XtSetArg(args[n], XmNallowResize, true); n++;
4117       XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++;
4118       XtSetArg(args[n], XmNshadowThickness, 2); n++;
4119       error_frame = XtCreateManagedWidget("error-frame", xmFrameWidgetClass, mainform, args, n);
4120 
4121       n = 0;
4122       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
4123       error_label = XtCreateManagedWidget("", xmLabelWidgetClass, error_frame, args, n);
4124 
4125 
4126       /* amp env */
4127       n = 0;
4128       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
4129       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
4130       XtSetArg(args[n], XmNtopWidget, w_sep1); n++;
4131       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
4132       XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
4133       XtSetArg(args[n], XmNleftPosition, 4); n++;
4134       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
4135       XtSetArg(args[n], XmNrightWidget, w_dB_frame); n++;
4136       XtSetArg(args[n], XmNallowResize, true); n++;
4137       XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++;
4138       XtSetArg(args[n], XmNshadowThickness, 4); n++;
4139       w_env_frame = XtCreateManagedWidget("mix-amp-env-frame", xmFrameWidgetClass, mainform, args, n);
4140 
4141       n = 0;
4142       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
4143       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
4144       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
4145       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
4146       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
4147       XtSetArg(args[n], XmNallowResize, true); n++;
4148       w_env = XtCreateManagedWidget("mix-amp-env-window", xmDrawingAreaWidgetClass, w_env_frame, args, n);
4149 
4150       XtManageChild(mix_dialog);
4151 
4152       XtAddCallback(w_env, XmNresizeCallback, mix_amp_env_resize, NULL);
4153       XtAddCallback(w_env, XmNexposeCallback, mix_amp_env_resize, NULL);
4154 
4155       spf = new_env_editor();
4156 
4157       XtAddEventHandler(w_env, ButtonPressMask, false, mix_drawer_button_press, NULL);
4158       XtAddEventHandler(w_env, ButtonMotionMask, false, mix_drawer_button_motion, NULL);
4159       XtAddEventHandler(w_env, ButtonReleaseMask, false, mix_drawer_button_release, NULL);
4160 
4161       set_dialog_widget(MIX_DIALOG, mix_dialog);
4162 
4163       XtUnmanageChild(error_frame);
4164     }
4165   else
4166     {
4167       if (!(XtIsManaged(mix_dialog))) XtManageChild(mix_dialog);
4168       raise_dialog(mix_dialog);
4169     }
4170   reflect_mix_change(mix_dialog_id);
4171   return(mix_dialog);
4172 }
4173 
4174 
reflect_mix_change(int mix_id)4175 void reflect_mix_change(int mix_id)
4176 {
4177   if ((mix_dialog) &&
4178       (XtIsManaged(mix_dialog)))
4179     {
4180       if (mix_id != ANY_MIX_ID)
4181 	mix_dialog_id = mix_id;
4182 
4183       if (!(mix_exists(mix_dialog_id)))
4184 	{
4185 	  mix_dialog_id = any_mix_id();
4186 	  mix_id = mix_dialog_id;
4187 	}
4188 
4189       if ((mix_id == mix_dialog_id) || (mix_id == ANY_MIX_ID))
4190 	{
4191 	  mus_float_t val;
4192 	  set_sensitive(mix_next_button, (next_mix_id(mix_dialog_id) != INVALID_MIX_ID));
4193 	  set_sensitive(mix_previous_button, (previous_mix_id(mix_dialog_id) != INVALID_MIX_ID));
4194 
4195 	  /* now reflect current mix state in mix dialog controls */
4196 	  if (mix_exists(mix_dialog_id))
4197 	    {
4198 	      chan_info *cp = NULL;
4199 	      mus_long_t beg, len;
4200 	      char lab[LABEL_BUFFER_SIZE];
4201 
4202 	      /* syncd mixes have the same color (red) reverting to old color when sync changes */
4203 	      cp = mix_chan_info_from_id(mix_dialog_id);
4204 	      if (old_mix_dialog_id != INVALID_MIX_ID)
4205 		{
4206 		  mix_unset_color_from_id(old_mix_dialog_id);
4207 		  syncd_mix_unset_color(old_mix_dialog_id);
4208 		}
4209 	      old_mix_dialog_id = mix_dialog_id;
4210 	      mix_set_color_from_id(mix_dialog_id, ss->red);
4211 	      syncd_mix_set_color(mix_dialog_id, ss->red);
4212 
4213 	      for_each_normal_chan(display_channel_mixes);
4214 
4215 	      if (!dragging)
4216 		{
4217 		  val = mix_speed_from_id(mix_dialog_id);
4218 		  XtVaSetValues(w_speed, XmNvalue, speed_to_scrollbar(speed_control_min(ss), val, speed_control_max(ss)), NULL);
4219 		  speed_changed(val, lab, xmix_speed_control_style, speed_control_tones(ss), 6);
4220 		  set_label(w_speed_number, lab);
4221 		}
4222 	      widget_mix_to_text(w_id, mix_dialog_id);
4223 
4224 	      beg = mix_position_from_id(mix_dialog_id);
4225 	      len = mix_length_from_id(mix_dialog_id);
4226 	      snprintf(lab, LABEL_BUFFER_SIZE, "%.3f : %.3f%s",
4227 			   ((double)beg / (double)snd_srate(cp->sound)),
4228 			   ((double)(beg + len) / (double)snd_srate(cp->sound)),
4229 			   (mix_is_active(mix_dialog_id)) ? "" : " (locked)");
4230 	      XmTextSetString(w_beg, lab);
4231 
4232 	      set_sensitive(XmMessageBoxGetChild(mix_dialog, XmDIALOG_OK_BUTTON), true);
4233 	    }
4234 	  else
4235 	    {
4236 	      XmTextSetString(w_id, (char *)"-1");
4237 	      XmTextSetString(w_beg, (char *)"no active mixes");
4238 	      set_sensitive(XmMessageBoxGetChild(mix_dialog, XmDIALOG_OK_BUTTON), false);
4239 	    }
4240 	  if (!dragging)
4241 	    {
4242 	      if (mix_is_active(mix_dialog_id))
4243 		val = mix_amp_from_id(mix_dialog_id);
4244 	      else val = 1.0;
4245 	      XtVaSetValues(w_amp, XmNvalue, amp_to_scrollbar(w_amp_number, val), NULL);
4246 	    }
4247 
4248 	  if (mix_amp_env_from_id(mix_dialog_id))
4249 	    {
4250 	      if (dialog_env) free_env(dialog_env);
4251 	      dialog_env = copy_env(mix_amp_env_from_id(mix_dialog_id));
4252 	    }
4253 	  /* copy here else we're editing it directly afterwards (and we free old in mix_set_amp_env_edit) */
4254 	  if (!dialog_env)
4255 	    dialog_env = default_env(1.0, 1.0);
4256 	  mix_amp_env_resize(w_env, NULL, NULL);
4257 
4258 	  set_toggle_button(w_sync, (mix_sync_from_id(mix_dialog_id) != 0), false, NULL);
4259 	}
4260     }
4261 }
4262 
4263 
mix_dialog_mix(void)4264 int mix_dialog_mix(void)
4265 {
4266   return(mix_dialog_id);
4267 }
4268 
4269 
mix_dialog_set_mix(int id)4270 void mix_dialog_set_mix(int id)
4271 {
4272   mix_dialog_id = id;
4273   reflect_mix_change(mix_dialog_id);
4274 }
4275 
4276 
4277 
4278 /* envelope editor and viewer */
4279 
4280 
4281 static Widget enved_dialog = NULL;
4282 static Widget apply_button, apply2_button, cancel_button, drawer, show_button, save_button, revert_button, undo_button, redo_button;
4283 static Widget brkptL, graph_button, flt_button, amp_button, src_button, clip_button;
4284 static Widget nameL, textL, screnvlst, dB_button, orderL, reset_button, fir_button = NULL;
4285 static Widget baseScale, baseValue, selection_button;
4286 static GC gc1, rgc, ggc;
4287 
4288 static const char *env_names[3] = {"amp env:", "flt env:", "src env:"};
4289 
4290 static bool showing_all_envs = false; /* edit one env (0), or view all currently defined envs (1) */
4291 static bool apply_to_selection = false, we_turned_selection_off = false;
4292 
4293 static int env_window_width = 0;
4294 static int env_window_height = 0;
4295 
4296 static chan_info *active_channel = NULL, *last_active_channel = NULL;
4297 
4298 static env* selected_env = NULL; /* if during view, one env is clicked, it is "selected" and can be pasted elsewhere */
4299 static env* active_env = NULL;   /* env currently being edited */
4300 
4301 static axis_info *axis = NULL;
4302 static axis_info *gray_ap = NULL;
4303 static bool is_FIR = true;
4304 static bool old_clipping = false;
4305 static bool ignore_button_release = false;
4306 static bool cancelling = true;
4307 
4308 
fixup_graphics_context(graphics_context * ax,Widget w,GC gc)4309 static void fixup_graphics_context(graphics_context *ax, Widget w, GC gc)
4310 {
4311   ax->dp = XtDisplay(w);
4312   ax->wn = XtWindow(w);
4313   if (gc) ax->gc = gc;
4314 }
4315 
4316 
enved_make_axis(const char * name,graphics_context * ax,int ex0,int ey0,int width,int height,mus_float_t xmin,mus_float_t xmax,mus_float_t ymin,mus_float_t ymax,printing_t printing)4317 axis_info *enved_make_axis(const char *name, graphics_context *ax,
4318 			   int ex0, int ey0, int width, int height,
4319 			   mus_float_t xmin, mus_float_t xmax, mus_float_t ymin, mus_float_t ymax,
4320 			   printing_t printing)
4321 {
4322   /* conjure up minimal context for axis drawer in snd-axis.c */
4323   if (!axis)
4324     {
4325       axis = (axis_info *)calloc(1, sizeof(axis_info));
4326       axis->ax = (graphics_context *)calloc(1, sizeof(graphics_context));
4327       fixup_graphics_context(axis->ax, drawer, ax->gc);
4328     }
4329   if (!gray_ap)
4330     {
4331       gray_ap = (axis_info *)calloc(1, sizeof(axis_info));
4332       gray_ap->ax = (graphics_context *)calloc(1, sizeof(graphics_context));
4333       gray_ap->graph_active = true;
4334       fixup_graphics_context(gray_ap->ax, drawer, ggc);
4335     }
4336   init_env_axes(axis, name, ex0, ey0, width, height, xmin, xmax, ymin, ymax, printing);
4337   return(axis);
4338 }
4339 
4340 
display_env(env * e,const char * name,GC cur_gc,int x0,int y0,int width,int height,bool dots,printing_t printing)4341 static void display_env(env *e, const char *name, GC cur_gc, int x0, int y0, int width, int height, bool dots, printing_t printing)
4342 {
4343   graphics_context *ax = NULL;
4344   ax = (graphics_context *)calloc(1, sizeof(graphics_context));
4345   ax->wn = XtWindow(drawer);
4346   if (!(ax->wn)) {free(ax); return;}
4347   ax->dp = XtDisplay(drawer);
4348   ax->gc = cur_gc;
4349   ss->enved->with_dots = dots;
4350   env_editor_display_env(ss->enved, e, ax, name, x0, y0, width, height, printing);
4351   free(ax);
4352 }
4353 
4354 
display_enved_env_with_selection(env * e,const char * name,int x0,int y0,int width,int height,bool dots,printing_t printing)4355 void display_enved_env_with_selection(env *e, const char *name, int x0, int y0, int width, int height, bool dots, printing_t printing)
4356 {
4357   display_env(e, name, (selected_env == e) ? rgc : gc1, x0, y0, width, height, dots, printing);
4358 }
4359 
4360 
reflect_segment_state(void)4361 static void reflect_segment_state(void)
4362 {
4363   if ((enved_dialog) &&
4364       (active_env) &&
4365       (!(showing_all_envs)))
4366     env_redisplay();
4367 }
4368 
4369 
prepare_env_edit(env * new_env)4370 static void prepare_env_edit(env *new_env)
4371 {
4372   prepare_enved_edit(new_env);
4373   if (new_env->base == 1.0)
4374     set_enved_style(ENVELOPE_LINEAR);
4375   else
4376     {
4377       set_enved_base(new_env->base);
4378       set_enved_style(ENVELOPE_EXPONENTIAL);
4379     }
4380   reflect_segment_state();
4381 }
4382 
4383 
set_enved_redo_sensitive(bool val)4384 void set_enved_redo_sensitive(bool val) {set_sensitive(redo_button, val);}
set_enved_revert_sensitive(bool val)4385 void set_enved_revert_sensitive(bool val) {set_sensitive(revert_button, val);}
set_enved_undo_sensitive(bool val)4386 void set_enved_undo_sensitive(bool val) {set_sensitive(undo_button, val);}
set_enved_save_sensitive(bool val)4387 void set_enved_save_sensitive(bool val) {set_sensitive(save_button, val);}
set_enved_show_sensitive(bool val)4388 void set_enved_show_sensitive(bool val) {set_sensitive(show_button, val);}
4389 
4390 
4391 static bool use_listener_font = false;
4392 
make_scrolled_env_list(void)4393 void make_scrolled_env_list(void)
4394 {
4395   XmString *strs;
4396   int n, size;
4397   size = enved_all_envs_top();
4398   XtVaSetValues(screnvlst, XmNbackground, ss->highlight_color, NULL);
4399   strs = (XmString *)calloc(size, sizeof(XmString));
4400   for (n = 0; n < size; n++)
4401     strs[n] = XmStringCreate(enved_all_names(n), (char *)((use_listener_font) ? "listener_font" : XmFONTLIST_DEFAULT_TAG));
4402   XtVaSetValues(screnvlst,
4403 		XmNitems, strs,
4404 		XmNitemCount, size,
4405 		NULL);
4406   for (n = 0; n < size; n++)
4407     XmStringFree(strs[n]);
4408   free(strs);
4409 }
4410 
4411 
enved_reflect_peak_env_completion(snd_info * sp)4412 void enved_reflect_peak_env_completion(snd_info *sp)
4413 {
4414   if ((enved_dialog) && (active_channel) && (enved_with_wave(ss)))
4415     if (active_channel->sound == sp)
4416       env_redisplay();
4417 }
4418 
4419 
new_active_channel_alert(void)4420 void new_active_channel_alert(void)
4421 {
4422   if (enved_dialog)
4423     {
4424       /* if showing current active channel in gray, update */
4425       active_channel = current_channel();
4426       env_redisplay();
4427     }
4428 }
4429 
4430 
dismiss_enved_callback(Widget w,XtPointer context,XtPointer info)4431 static void dismiss_enved_callback(Widget w, XtPointer context, XtPointer info)
4432 {
4433   if (!cancelling)
4434     {
4435       if (ss->checking_explicitly)
4436 	ss->stopped_explicitly = true;
4437     }
4438   else XtUnmanageChild(enved_dialog);
4439 }
4440 
4441 
help_enved_callback(Widget w,XtPointer context,XtPointer info)4442 static void help_enved_callback(Widget w, XtPointer context, XtPointer info)
4443 {
4444   envelope_editor_dialog_help();
4445 }
4446 
4447 
4448 static bool within_selection_src = false;
4449 
apply_enved(void)4450 static void apply_enved(void)
4451 {
4452   if (active_env)
4453     {
4454       active_channel = current_channel();
4455       if (active_channel)
4456 	{
4457 	  int i, j;
4458 	  char *origin = NULL, *estr = NULL;
4459 	  env *max_env = NULL;
4460 
4461 	  set_sensitive(apply_button, false);
4462 	  set_sensitive(apply2_button, false);
4463 	  set_button_label(cancel_button, I_STOP);
4464 	  cancelling = false;
4465 	  check_for_event();
4466 
4467 	  switch (enved_target(ss))
4468 	    {
4469 	    case ENVED_AMPLITUDE:
4470 #if HAVE_FORTH
4471 	      origin = mus_format("%s%s %s drop",
4472 				  estr = env_to_string(active_env),
4473 				  (apply_to_selection) ? "" : " 0 " PROC_FALSE,
4474 				  (apply_to_selection) ? S_env_selection : S_env_channel);
4475 #else
4476 	      origin = mus_format("%s" PROC_OPEN "%s%s",
4477 				  to_proc_name((apply_to_selection) ? S_env_selection : S_env_channel),
4478 				  estr = env_to_string(active_env),
4479 				  (apply_to_selection) ? "" : PROC_SEP "0" PROC_SEP PROC_FALSE);
4480 #endif
4481 	      apply_env(active_channel, active_env, 0,
4482 			current_samples(active_channel),
4483 			apply_to_selection,
4484 			origin, NULL,
4485 			C_int_to_Xen_integer(AT_CURRENT_EDIT_POSITION), 0);
4486 	      /* calls update_graph, I think, but in short files that doesn't update the amp-env */
4487 	      if (estr) free(estr);
4488 	      if (origin) free(origin);
4489 	      break;
4490 	    case ENVED_SPECTRUM:
4491 #if HAVE_FORTH
4492 	      origin = mus_format("%s %d%s %s drop",
4493 				  estr = env_to_string(active_env),
4494 				  enved_filter_order(ss),
4495 				  (apply_to_selection) ? "" : " 0 " PROC_FALSE,
4496 				  (apply_to_selection) ? S_filter_selection : S_filter_channel);
4497 #else
4498 	      origin = mus_format("%s" PROC_OPEN "%s" PROC_SEP "%d%s",
4499 				  to_proc_name((apply_to_selection) ? S_filter_selection : S_filter_channel),
4500 				  estr = env_to_string(active_env),
4501 				  enved_filter_order(ss),
4502 				  (apply_to_selection) ? "" : PROC_SEP "0" PROC_SEP PROC_FALSE);
4503 #endif
4504 	      apply_filter(active_channel,
4505 			   (is_FIR) ? enved_filter_order(ss) : 0,
4506 			   active_env,
4507 			   origin, NULL, apply_to_selection,
4508 			   NULL, NULL,
4509 			   C_int_to_Xen_integer(AT_CURRENT_EDIT_POSITION), 0, false);
4510 	      if (estr) free(estr);
4511 	      if (origin) free(origin);
4512 	      break;
4513 	    case ENVED_SRATE:
4514 	      /* mus_src no longer protects against 0 srate */
4515 	      max_env = copy_env(active_env);
4516 	      for (i = 0, j = 1; i < max_env->pts; i++, j += 2)
4517 		if (max_env->data[j] < .01)
4518 		  max_env->data[j] = .01;
4519 	      within_selection_src = true;
4520 	      src_env_or_num(active_channel, max_env, 0.0,
4521 			     false, "Enved: src",
4522 			     apply_to_selection, NULL,
4523 			     C_int_to_Xen_integer(AT_CURRENT_EDIT_POSITION), 0);
4524 	      within_selection_src = false;
4525 	      max_env = free_env(max_env);
4526 	      break;
4527 	    }
4528 	  if (enved_with_wave(ss)) env_redisplay();
4529 	  set_sensitive(apply_button, true);
4530 	  set_sensitive(apply2_button, true);
4531 	  set_button_label(cancel_button, I_GO_AWAY);
4532 	  cancelling = true;
4533 	}
4534     }
4535 }
4536 
4537 
env_redisplay_1(printing_t printing)4538 static void env_redisplay_1(printing_t printing)
4539 {
4540   if (enved_dialog_is_active())
4541     {
4542       XClearWindow(XtDisplay(drawer), XtWindow(drawer));
4543       if (showing_all_envs)
4544 	view_envs(env_window_width, env_window_height, printing);
4545       else
4546 	{
4547 	  char *name = NULL;
4548 	  name = XmTextGetString(textL);
4549 	  if (!name) name = mus_strdup("noname");
4550 	  /* active_env can be null here if just showing axes (empty initial graph) */
4551 
4552 	  if ((enved_with_wave(ss)) &&
4553 	      (active_channel) &&
4554 	      (!(active_channel->squelch_update)))
4555 	    {
4556 	      if ((enved_target(ss) == ENVED_SPECTRUM) && (active_env) && (is_FIR) && (printing == NOT_PRINTING))
4557 		display_frequency_response(active_env, axis, gray_ap->ax, enved_filter_order(ss), enved_in_dB(ss));
4558 	      enved_show_background_waveform(axis, gray_ap, apply_to_selection, (enved_target(ss) == ENVED_SPECTRUM), printing);
4559 	    }
4560 
4561 	  display_env(active_env, name, gc1, 0, 0, env_window_width, env_window_height, true, printing);
4562 	  if (name) XtFree(name);
4563 	}
4564     }
4565 }
4566 
4567 
env_redisplay(void)4568 void env_redisplay(void)
4569 {
4570   env_redisplay_1(NOT_PRINTING);
4571 }
4572 
env_redisplay_with_print(void)4573 void env_redisplay_with_print(void)
4574 {
4575   env_redisplay_1(PRINTING);
4576 }
4577 
4578 
update_enved_background_waveform(chan_info * cp)4579 void update_enved_background_waveform(chan_info *cp)
4580 {
4581   if ((enved_dialog_is_active()) &&
4582       (enved_with_wave(ss)) &&
4583       (enved_target(ss) == ENVED_AMPLITUDE) &&
4584       (cp == active_channel) &&
4585       ((!apply_to_selection) || (selection_is_active_in_channel(cp))))
4586     env_redisplay();
4587 }
4588 
4589 
enved_reset(void)4590 static void enved_reset(void)
4591 {
4592   set_enved_clipping(DEFAULT_ENVED_CLIPPING);
4593   set_enved_style(ENVELOPE_LINEAR);
4594   set_enved_power(DEFAULT_ENVED_POWER);
4595   set_enved_base(DEFAULT_ENVED_BASE);
4596   set_enved_target(DEFAULT_ENVED_TARGET);
4597   set_enved_with_wave(DEFAULT_ENVED_WITH_WAVE);
4598   set_enved_in_dB(DEFAULT_ENVED_IN_DB);
4599   XmTextSetString(textL, NULL);
4600   set_enved_filter_order(DEFAULT_ENVED_FILTER_ORDER);
4601   if (active_env) active_env = free_env(active_env);
4602 #if HAVE_SCHEME
4603   active_env = string_to_env("'(0 0 1 0)");
4604 #endif
4605 #if HAVE_FORTH
4606   active_env = string_to_env("'( 0 0 1 0 )");
4607 #endif
4608 #if HAVE_RUBY
4609   active_env = string_to_env("[0, 0, 1, 0]");
4610 #endif
4611   set_enved_env_list_top(0);
4612   prepare_env_edit(active_env);
4613   set_sensitive(save_button, true);
4614   reflect_enved_style();
4615   env_redisplay();
4616 }
4617 
4618 
4619 static void clear_point_label(void);
4620 
clear_xenv_error(void)4621 static void clear_xenv_error(void)
4622 {
4623   if (brkptL)
4624     clear_point_label();
4625 }
4626 
4627 
unpost_xenv_error(XtPointer data,XtIntervalId * id)4628 static void unpost_xenv_error(XtPointer data, XtIntervalId *id)
4629 {
4630   clear_xenv_error();
4631 }
4632 
4633 
errors_to_xenv_text(const char * msg,void * data)4634 static void errors_to_xenv_text(const char *msg, void *data)
4635 {
4636   set_button_label(brkptL, msg);
4637   XtAppAddTimeOut(main_app(ss),
4638 		  5000,
4639 		  (XtTimerCallbackProc)unpost_xenv_error,
4640 		  NULL);
4641 }
4642 
4643 
order_field_activated(void)4644 static void order_field_activated(void)
4645 {
4646   /* return in order text field */
4647   char *str = NULL;
4648   str = XmTextGetString(orderL);
4649   if ((str) && (*str))
4650     {
4651       int order;
4652       redirect_errors_to(errors_to_xenv_text, NULL);
4653       order = string_to_int(str, 1, "order");
4654       redirect_errors_to(NULL, NULL);
4655       if (order & 1) order++;
4656       if ((order > 0) &&
4657 	  (order < 2000))
4658 	set_enved_filter_order(order);
4659       else widget_int_to_text(orderL, enved_filter_order(ss));
4660     }
4661   if (str) XtFree(str);
4662 }
4663 
4664 
text_field_activated(void)4665 static void text_field_activated(void)
4666 { /* might be breakpoints to load or an envelope name (<cr> in enved text field) */
4667   char *name = NULL;
4668   name = XmTextGetString(textL);
4669   if ((name) && (*name))
4670     {
4671       char *str;
4672       env *e = NULL;
4673       str = name;
4674       while (isspace((int)(*str))) str++;
4675       e = name_to_env(str);
4676       if (!e)
4677 	{
4678 	  if (isalpha((int)(str[0])))
4679 	    {
4680 	      alert_envelope_editor(str, copy_env(active_env));
4681 	      add_or_edit_symbol(str, active_env);
4682 	      set_sensitive(save_button, false);
4683 	      env_redisplay(); /* updates label */
4684 	      /* e is null here */
4685 	    }
4686 	  else
4687 	    {
4688 	      redirect_errors_to(errors_to_xenv_text, NULL);
4689 	      e = string_to_env(str);
4690 	      redirect_errors_to(NULL, NULL);
4691 	    }
4692 	}
4693       if (e)
4694 	{
4695 	  if (active_env)
4696 	    {
4697 	      #define ENVED_TEMP_NAME "enved-backup"
4698 	      /* save current under a temp name!  -- user might have mistakenly reused a name */
4699 	      alert_envelope_editor((char *)ENVED_TEMP_NAME, copy_env(active_env));
4700 	      add_or_edit_symbol(ENVED_TEMP_NAME, active_env);
4701 	      active_env = free_env(active_env);
4702 	    }
4703 	  active_env = copy_env(e);
4704 	  set_enved_env_list_top(0);
4705 	  prepare_env_edit(active_env);
4706 	  set_sensitive(save_button, true);
4707 	  set_sensitive(undo_button, false);
4708 	  set_sensitive(revert_button, false);
4709 	  env_redisplay();
4710 	  e = free_env(e);
4711 	}
4712     }
4713   if (name) XtFree(name);
4714 }
4715 
enved_text_activate_callback(Widget w,XtPointer context,XtPointer info)4716 static void enved_text_activate_callback(Widget w, XtPointer context, XtPointer info)
4717 {
4718   text_field_activated();
4719 }
4720 
4721 
order_activate_callback(Widget w,XtPointer context,XtPointer info)4722 static void order_activate_callback(Widget w, XtPointer context, XtPointer info)
4723 {
4724   order_field_activated();
4725 }
4726 
4727 
save_button_pressed(Widget w,XtPointer context,XtPointer info)4728 static void save_button_pressed(Widget w, XtPointer context, XtPointer info)
4729 {
4730   char *name = NULL;
4731   if (!active_env) return;
4732   name = XmTextGetString(textL);
4733   if ((!name) || (!(*name)))
4734     name = mus_strdup("unnamed");
4735   alert_envelope_editor(name, copy_env(active_env));
4736   add_or_edit_symbol(name, active_env);
4737   set_sensitive(save_button, false);
4738   env_redisplay();
4739   if (name) XtFree(name);
4740 }
4741 
4742 
apply_enved_callback(Widget w,XtPointer context,XtPointer info)4743 static void apply_enved_callback(Widget w, XtPointer context, XtPointer info)
4744 {
4745   /* apply current envs to currently sync'd channels */
4746   Widget active_widget;
4747   active_widget = XmGetFocusWidget(enved_dialog);
4748   if (active_widget == XmMessageBoxGetChild(enved_dialog, XmDIALOG_OK_BUTTON))
4749     {
4750       apply_enved();
4751       last_active_channel = active_channel;
4752     }
4753 }
4754 
4755 
undo_and_apply_enved_callback(Widget w,XtPointer context,XtPointer info)4756 static void undo_and_apply_enved_callback(Widget w, XtPointer context, XtPointer info)
4757 {
4758   /* undo previous amp env, then apply */
4759   /* this blindly undoes the previous edit (assumed to be an envelope) -- if the user made some other change in the meantime, too bad */
4760   if ((active_channel) && (active_channel == last_active_channel))
4761     {
4762       active_channel->squelch_update = true;
4763       undo_edit_with_sync(active_channel, 1);
4764       active_channel->squelch_update = false;
4765       clear_status_area(active_channel->sound);
4766     }
4767   apply_enved();
4768   last_active_channel = active_channel;
4769 }
4770 
4771 
select_or_edit_env(int pos)4772 static void select_or_edit_env(int pos)
4773 {
4774   if (showing_all_envs)
4775     {
4776       showing_all_envs = false;
4777       set_button_label(show_button, "view envs");
4778     }
4779   if (active_env) active_env = free_env(active_env);
4780   selected_env = position_to_env(pos);
4781   if (!selected_env) return;
4782   active_env = selected_env;
4783   XmTextSetString(textL, enved_all_names(pos));
4784   set_enved_env_list_top(0);
4785   prepare_env_edit(active_env);
4786   set_sensitive(undo_button, false);
4787   set_sensitive(revert_button, false);
4788   set_sensitive(save_button, false);
4789   env_redisplay();
4790 }
4791 
4792 
clear_point_label(void)4793 static void clear_point_label(void)
4794 {
4795   XtVaSetValues(brkptL, XmNlabelType, XmSTRING, XmNlabelString, NULL, NULL);
4796 }
4797 
4798 
enved_display_point_label(mus_float_t x,mus_float_t y)4799 static void enved_display_point_label(mus_float_t x, mus_float_t y)
4800 {
4801   char brkpt_buf[LABEL_BUFFER_SIZE];
4802   if ((enved_in_dB(ss)) && (min_dB(ss) < -60))
4803     snprintf(brkpt_buf, LABEL_BUFFER_SIZE, "%.3f : %.5f", x, y);
4804   else snprintf(brkpt_buf, LABEL_BUFFER_SIZE, "%.3f : %.3f", x, y);
4805   set_button_label(brkptL, brkpt_buf);
4806 }
4807 
4808 
drawer_button_motion(Widget w,XtPointer context,XEvent * event,Boolean * cont)4809 static void drawer_button_motion(Widget w, XtPointer context, XEvent *event, Boolean *cont)
4810 {
4811   XMotionEvent *ev = (XMotionEvent *)event;
4812   ignore_button_release = false;
4813 
4814   if (!showing_all_envs)
4815     {
4816       mus_float_t x, y;
4817 #ifdef __APPLE__
4818       if ((ev->x == press_x) && (ev->y == press_y)) return;
4819 #endif
4820       env_editor_button_motion_with_xy(ss->enved, ev->x, ev->y, ev->time, active_env, &x, &y);
4821       enved_display_point_label(x, y);
4822       env_redisplay();
4823     }
4824 }
4825 
4826 
drawer_button_press(Widget w,XtPointer context,XEvent * event,Boolean * cont)4827 static void drawer_button_press(Widget w, XtPointer context, XEvent *event, Boolean *cont)
4828 {
4829   XButtonEvent *ev = (XButtonEvent *)event;
4830 #ifdef __APPLE__
4831   press_x = ev->x;
4832   press_y = ev->y;
4833 #endif
4834   ss->enved->down_time = ev->time;
4835   ss->enved->env_dragged = false;
4836   if (showing_all_envs)
4837     {
4838       int pos;
4839       pos = hit_env(ev->x, ev->y, env_window_width, env_window_height);
4840       XmListSelectPos(screnvlst, pos + 1, false);
4841       if ((pos >= 0) &&
4842 	  (pos < enved_all_envs_top()))
4843 	{
4844 	  select_or_edit_env(pos);
4845 	  ignore_button_release = true;
4846 	}
4847     }
4848   else
4849     {
4850       if (!active_env)
4851 	{
4852 	  active_env = default_env(1.0, 0.0);
4853 	  active_env->base = enved_base(ss);
4854 	  env_redisplay(); /* needed to get current_xs set up correctly */
4855 	}
4856       if (env_editor_button_press(ss->enved, ev->x, ev->y, ev->time, active_env))
4857 	env_redisplay();
4858       enved_display_point_label(ungrf_x(ss->enved->axis, ev->x), env_editor_ungrf_y_dB(ss->enved, ev->y));
4859       set_sensitive(save_button, true);
4860       set_sensitive(undo_button, true);
4861       set_sensitive(revert_button, true);
4862     }
4863 }
4864 
4865 
drawer_button_release(Widget w,XtPointer context,XEvent * event,Boolean * cont)4866 static void drawer_button_release(Widget w, XtPointer context, XEvent *event, Boolean *cont)
4867 {
4868   if (ignore_button_release)
4869     ignore_button_release = false;
4870   else
4871     {
4872       if ((active_env) && (!showing_all_envs))
4873 	{
4874 	  env_editor_button_release(ss->enved, active_env);
4875 	  env_redisplay();
4876 	  clear_point_label();
4877 	}
4878     }
4879 }
4880 
4881 
drawer_resize(Widget w,XtPointer context,XtPointer info)4882 static void drawer_resize(Widget w, XtPointer context, XtPointer info)
4883 {
4884   /* update display, can be either view of all envs or sequence of current envs */
4885   env_window_width = widget_width(w);
4886   env_window_height = widget_height(w);
4887   env_redisplay();
4888 }
4889 
4890 
show_button_pressed(Widget w,XtPointer context,XtPointer info)4891 static void show_button_pressed(Widget w, XtPointer context, XtPointer info)
4892 {
4893   /* if show all (as opposed to show current), loop through loaded LV_LISTs */
4894   showing_all_envs = (!showing_all_envs);
4895   set_button_label(show_button, (showing_all_envs) ? "edit env" : "view envs");
4896   env_redisplay();
4897 }
4898 
4899 
selection_button_pressed(Widget s,XtPointer context,XtPointer info)4900 static void selection_button_pressed(Widget s, XtPointer context, XtPointer info)
4901 {
4902   we_turned_selection_off = false;
4903   apply_to_selection = (!apply_to_selection);
4904   XmChangeColor(selection_button, (apply_to_selection) ? ((Pixel)ss->yellow) : ((Pixel)ss->highlight_color));
4905   set_sensitive(apply2_button, true);
4906   if ((enved_with_wave(ss)) &&
4907       (!showing_all_envs))
4908     env_redisplay();
4909 }
4910 
4911 
revert_button_pressed(Widget w,XtPointer context,XtPointer info)4912 static void revert_button_pressed(Widget w, XtPointer context, XtPointer info)
4913 {
4914   revert_env_edit();
4915   if (active_env) active_env = free_env(active_env);
4916   active_env = enved_next_env();
4917   if (!active_env)
4918     text_field_activated();
4919   env_redisplay();
4920 }
4921 
4922 
undo_button_pressed(Widget w,XtPointer context,XtPointer info)4923 static void undo_button_pressed(Widget w, XtPointer context, XtPointer info)
4924 {
4925   undo_env_edit();
4926   if (active_env) active_env = free_env(active_env);
4927   active_env = enved_next_env();
4928   env_redisplay();
4929 }
4930 
4931 
redo_button_pressed(Widget w,XtPointer context,XtPointer info)4932 static void redo_button_pressed(Widget w, XtPointer context, XtPointer info)
4933 {
4934   redo_env_edit();
4935   if (active_env) active_env = free_env(active_env);
4936   active_env = enved_next_env();
4937   env_redisplay();
4938 }
4939 
4940 
reflect_apply_state(void)4941 static void reflect_apply_state(void)
4942 {
4943   set_label(nameL, env_names[enved_target(ss)]);
4944   XmChangeColor(amp_button, (enved_target(ss) == ENVED_AMPLITUDE) ? ((Pixel)ss->yellow) : ((Pixel)ss->highlight_color));
4945   XmChangeColor(flt_button, (enved_target(ss) == ENVED_SPECTRUM) ? ((Pixel)ss->yellow) : ((Pixel)ss->highlight_color));
4946   XmChangeColor(src_button, (enved_target(ss) == ENVED_SRATE) ? ((Pixel)ss->yellow) : ((Pixel)ss->highlight_color));
4947   if ((!showing_all_envs) &&
4948       (enved_with_wave(ss)))
4949     env_redisplay();
4950 }
4951 
4952 
freq_button_callback(Widget w,XtPointer context,XtPointer info)4953 static void freq_button_callback(Widget w, XtPointer context, XtPointer info)
4954 {
4955   in_set_enved_target(ENVED_SPECTRUM);
4956   old_clipping = enved_clipping(ss);
4957   set_enved_clipping(true);
4958   reflect_apply_state();
4959 }
4960 
4961 
amp_button_callback(Widget w,XtPointer context,XtPointer info)4962 static void amp_button_callback(Widget w, XtPointer context, XtPointer info)
4963 {
4964   if (enved_target(ss) == ENVED_SPECTRUM)
4965     set_enved_clipping(old_clipping);
4966   in_set_enved_target(ENVED_AMPLITUDE);
4967   reflect_apply_state();
4968 }
4969 
4970 
src_button_callback(Widget w,XtPointer context,XtPointer info)4971 static void src_button_callback(Widget w, XtPointer context, XtPointer info)
4972 {
4973   if (enved_target(ss) == ENVED_SPECTRUM)
4974     set_enved_clipping(old_clipping);
4975   in_set_enved_target(ENVED_SRATE);
4976   reflect_apply_state();
4977 }
4978 
4979 
reset_button_callback(Widget w,XtPointer context,XtPointer info)4980 static void reset_button_callback(Widget w, XtPointer context, XtPointer info)
4981 {
4982   enved_reset();
4983 }
4984 
4985 
enved_print(char * name)4986 static void enved_print(char *name)
4987 {
4988   print_enved(name, env_window_height);
4989 }
4990 
4991 
env_browse_callback(Widget w,XtPointer context,XtPointer info)4992 static void env_browse_callback(Widget w, XtPointer context, XtPointer info)
4993 {
4994   XmListCallbackStruct *cb = (XmListCallbackStruct *)info;
4995   select_or_edit_env(cb->item_position - 1);
4996 }
4997 
4998 
graph_button_callback(Widget w,XtPointer context,XtPointer info)4999 static void graph_button_callback(Widget w, XtPointer context, XtPointer info)
5000 {
5001   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
5002   in_set_enved_with_wave(cb->set);
5003   env_redisplay();
5004 }
5005 
5006 
dB_button_callback(Widget w,XtPointer context,XtPointer info)5007 static void dB_button_callback(Widget w, XtPointer context, XtPointer info)
5008 {
5009   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
5010   in_set_enved_in_dB(cb->set);
5011   env_redisplay();
5012 }
5013 
5014 
clip_button_callback(Widget w,XtPointer context,XtPointer info)5015 static void clip_button_callback(Widget w, XtPointer context, XtPointer info)
5016 {
5017   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
5018   in_set_enved_clipping(cb->set);
5019 }
5020 
5021 
5022 
5023 #define BASE_MAX 400
5024 #define BASE_MID 200
5025 /* these two just set the granularity of the scale widget, not the user-visible bounds */
5026 
make_base_label(mus_float_t bval)5027 static void make_base_label(mus_float_t bval)
5028 {
5029   char *sfs, *buf;
5030   int i, len, scale_len;
5031   len = (int)(enved_power(ss) * 4);
5032   if (len < 32) len = 32;
5033   sfs = (char *)calloc(len, sizeof(char));
5034   snprintf(sfs, len, "%.3f", bval);
5035   scale_len = (int)(enved_power(ss) + 3);
5036   if (scale_len < 32) scale_len = 32;
5037   buf = (char *)calloc(scale_len, sizeof(char));
5038   for (i = 0; i < scale_len - 1; i++)
5039     buf[i] = sfs[i];
5040   set_button_label(baseValue, buf);
5041   free(sfs);
5042   free(buf);
5043   in_set_enved_base(bval);
5044   if ((active_env) &&
5045       (!(showing_all_envs)))
5046     {
5047       active_env->base = enved_base(ss);
5048       if (active_env->base == 1.0)
5049 	set_enved_style(ENVELOPE_LINEAR);
5050       else set_enved_style(ENVELOPE_EXPONENTIAL);
5051       env_redisplay();
5052     }
5053 }
5054 
5055 
base_changed(int val)5056 static void base_changed(int val)
5057 {
5058   mus_float_t bval;
5059   if (val == 0)
5060     bval = 0.0;
5061   else
5062     {
5063       if (val == BASE_MID)
5064 	bval = 1.0;
5065       else
5066 	{
5067 	  if (val > BASE_MID)
5068 	    bval = pow(1.0 + (10.0 * ((mus_float_t)(val - BASE_MID) / (mus_float_t)BASE_MID)), enved_power(ss));
5069 	  else
5070 	    bval = pow(((mus_float_t)val / (mus_float_t)BASE_MID), enved_power(ss) - 1.0);
5071 	}
5072     }
5073   make_base_label(bval);
5074   if (active_env)
5075     set_sensitive(save_button, true); /* what about undo/redo here? */
5076 }
5077 
5078 
reflect_changed_base(mus_float_t val)5079 static void reflect_changed_base(mus_float_t val)
5080 {
5081   int ival;
5082   if (val <= 0.0)
5083     ival = 0;
5084   else
5085     {
5086       if (val == 1.0)
5087 	ival = BASE_MID;
5088       else
5089 	{
5090 	  if (val <= 1.0)
5091 	    ival = (int)(pow(val, 1.0 / (enved_power(ss) - 1.0)) * BASE_MID);
5092 	  else ival = (int)(BASE_MID + ((BASE_MID * (pow(val, (1.0 / (enved_power(ss)))) - 1)) / 10.0));
5093 	}
5094     }
5095   XtVaSetValues(baseScale, XmNvalue, mus_iclamp(0, ival, (int)(BASE_MAX * .9)), NULL);
5096   make_base_label(val);
5097 }
5098 
5099 
base_drag_callback(Widget w,XtPointer context,XtPointer info)5100 static void base_drag_callback(Widget w, XtPointer context, XtPointer info)
5101 {
5102   XmScrollBarCallbackStruct *sb = (XmScrollBarCallbackStruct *)info;
5103   base_changed(sb->value);
5104 }
5105 
5106 
5107 static int base_last_value = BASE_MID;
5108 
base_valuechanged_callback(Widget w,XtPointer context,XtPointer info)5109 static void base_valuechanged_callback(Widget w, XtPointer context, XtPointer info)
5110 {
5111   XmScrollBarCallbackStruct *sb = (XmScrollBarCallbackStruct *)info;
5112   base_last_value = sb->value;
5113   base_changed(sb->value);
5114 }
5115 
5116 
base_click_callback(Widget w,XtPointer context,XtPointer info)5117 static void base_click_callback(Widget w, XtPointer context, XtPointer info)
5118 {
5119   XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info;
5120   XButtonEvent *ev;
5121   int val;
5122   ev = (XButtonEvent *)(cb->event);
5123   if (ev->state & (ControlMask | MetaMask))
5124     val = base_last_value;
5125   else val = BASE_MID; /* this is supposedly 1.0 */
5126   base_changed(val);
5127   XtVaSetValues(baseScale, XmNvalue, val, NULL);
5128 }
5129 
5130 
FIR_click_callback(Widget w,XtPointer context,XtPointer info)5131 static void FIR_click_callback(Widget w, XtPointer context, XtPointer info)
5132 {
5133   is_FIR = (!is_FIR);
5134   set_label(w, (is_FIR) ? "fir" : "fft");
5135   if (enved_with_wave(ss)) env_redisplay();
5136 }
5137 
5138 
reflect_sound_state(void)5139 static void reflect_sound_state(void)
5140 {
5141   bool file_on;
5142   file_on = (bool)(any_selected_sound());
5143   set_sensitive(apply_button, file_on);
5144   set_sensitive(apply2_button, file_on);
5145 }
5146 
5147 
reflect_file_in_enved(Xen hook_or_reason)5148 static Xen reflect_file_in_enved(Xen hook_or_reason)
5149 {
5150   if (enved_dialog) reflect_sound_state();
5151   return(Xen_false);
5152 }
5153 
5154 static void add_reflect_enved_hook(void);
5155 
create_envelope_editor(void)5156 Widget create_envelope_editor(void)
5157 {
5158   if (!enved_dialog)
5159     {
5160       int n;
5161       Arg args[32];
5162       Widget colE, colD, colB, colF;
5163       Widget spacer, spacer1, aform, mainform, screnvname, baseSep, baseLabel;
5164       XmString xhelp, xdismiss, xapply, titlestr, s1;
5165       XGCValues gv;
5166       XtCallbackList n1, n2;
5167       char str[LABEL_BUFFER_SIZE];
5168 
5169       /* -------- DIALOG -------- */
5170       xdismiss = XmStringCreateLocalized((char *)I_GO_AWAY);
5171       xhelp = XmStringCreateLocalized((char *)I_HELP);
5172       titlestr = XmStringCreateLocalized((char *)"Edit Envelope");
5173       xapply = XmStringCreateLocalized((char *)"Apply");
5174 
5175       n = 0;
5176       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5177       XtSetArg(args[n], XmNautoUnmanage, false); n++;
5178       XtSetArg(args[n], XmNcancelLabelString, xdismiss); n++;
5179       XtSetArg(args[n], XmNhelpLabelString, xhelp); n++;
5180       XtSetArg(args[n], XmNokLabelString, xapply); n++;
5181       XtSetArg(args[n], XmNdialogTitle, titlestr); n++;
5182       XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
5183       XtSetArg(args[n], XmNnoResize, false); n++;
5184       XtSetArg(args[n], XmNtransient, false); n++;
5185       enved_dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"envelope editor", args, n);
5186 
5187       XtAddCallback(enved_dialog, XmNcancelCallback, dismiss_enved_callback, NULL);
5188       XtAddCallback(enved_dialog, XmNhelpCallback, help_enved_callback, NULL);
5189       XtAddCallback(enved_dialog, XmNokCallback, apply_enved_callback, NULL);
5190 
5191       XmStringFree(xhelp);
5192       XmStringFree(xdismiss);
5193       XmStringFree(titlestr);
5194       XmStringFree(xapply);
5195 
5196       XtVaSetValues(XmMessageBoxGetChild(enved_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL);
5197       XtVaSetValues(XmMessageBoxGetChild(enved_dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL);
5198       XtVaSetValues(XmMessageBoxGetChild(enved_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL);
5199       XtVaSetValues(XmMessageBoxGetChild(enved_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL);
5200       XtVaSetValues(XmMessageBoxGetChild(enved_dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL);
5201       XtVaSetValues(XmMessageBoxGetChild(enved_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL);
5202 
5203       n = 0;
5204       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
5205       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
5206       apply2_button = XtCreateManagedWidget("Undo&Apply", xmPushButtonGadgetClass, enved_dialog, args, n);
5207       XtAddCallback(apply2_button, XmNactivateCallback, undo_and_apply_enved_callback, NULL);
5208 
5209       n = 0;
5210       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
5211       XtSetArg(args[n], XmNforeground, ss->black); n++;
5212       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
5213       reset_button = XtCreateManagedWidget("Clear graph", xmPushButtonGadgetClass, enved_dialog, args, n);
5214       XtAddCallback(reset_button, XmNactivateCallback, reset_button_callback, NULL);
5215 
5216 
5217       /* -------- MAIN WIDGET -------- */
5218       n = 0;
5219       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5220       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5221       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5222       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
5223       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
5224       XtSetArg(args[n], XmNbottomWidget, XmMessageBoxGetChild(enved_dialog, XmDIALOG_SEPARATOR)); n++;
5225       mainform = XtCreateManagedWidget("formd", xmFormWidgetClass, enved_dialog, args, n);
5226 
5227       /* the order in which widgets are defined matters a lot here:
5228        * we need to build from the bottom up so that the graph portion expands
5229        * when the window is resized (if top-down, the slider at the bottom expands!)
5230        */
5231 
5232       /* -------- EXP SLIDER AT BOTTOM -------- */
5233       n = 0;
5234       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5235       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
5236       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
5237       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
5238       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5239       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
5240       XtSetArg(args[n], XmNrecomputeSize, false); n++;
5241       XtSetArg(args[n], XmNshadowThickness, 0); n++;
5242       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
5243       XtSetArg(args[n], XmNfillOnArm, false); n++;
5244       baseLabel = make_pushbutton_widget("exp:", mainform, args, n);
5245       XtAddCallback(baseLabel, XmNactivateCallback, base_click_callback, NULL);
5246 
5247       n = 0;
5248       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5249       s1 = XmStringCreateLocalized((char *)"1.000");
5250       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
5251       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
5252       XtSetArg(args[n], XmNtopWidget, baseLabel); n++;
5253       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
5254       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
5255       XtSetArg(args[n], XmNleftWidget, baseLabel); n++;
5256       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
5257       /*      XtSetArg(args[n], XmNrecomputeSize, false); n++; */
5258       XtSetArg(args[n], XmNlabelString, s1); n++;
5259       baseValue = XtCreateManagedWidget("base-label", xmLabelWidgetClass, mainform, args, n);
5260       XmStringFree(s1);
5261 
5262       /* -------- filter order -------- */
5263       n = 0;
5264       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5265       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
5266       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
5267       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
5268       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5269       XtSetArg(args[n], XmNcolumns, 3); n++;
5270       XtSetArg(args[n], XmNrecomputeSize, false); n++;
5271       XtSetArg(args[n], XmNheight, 24); n++;
5272       XtSetArg(args[n], XmNresizeWidth, false); n++;
5273       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
5274       XtSetArg(args[n], XmNmarginHeight, 0); n++;
5275       XtSetArg(args[n], XmNmarginBottom, 0); n++;
5276       snprintf(str, LABEL_BUFFER_SIZE, "%d", enved_filter_order(ss));
5277       XtSetArg(args[n], XmNvalue, str); n++;
5278       orderL = make_textfield_widget("orderL", mainform, args, n, ACTIVATABLE, NO_COMPLETER);
5279       XtAddCallback(orderL, XmNactivateCallback, order_activate_callback, NULL);
5280 
5281       /* -------- fft/fir choice -------- */
5282       n = 0;
5283       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5284       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
5285       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
5286       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
5287       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
5288       XtSetArg(args[n], XmNrightWidget, orderL); n++;
5289       XtSetArg(args[n], XmNrecomputeSize, false); n++;
5290       XtSetArg(args[n], XmNshadowThickness, 0); n++;
5291       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
5292       XtSetArg(args[n], XmNfillOnArm, false); n++;
5293       fir_button = make_pushbutton_widget((char *)((is_FIR) ? "fir" : "fft"), mainform, args, n);
5294       XtAddCallback(fir_button, XmNactivateCallback, FIR_click_callback, NULL);
5295 
5296       /* -------- exp base scale -------- */
5297       n = 0;
5298       XtSetArg(args[n], XmNbackground, ss->position_color); n++;
5299       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
5300       XtSetArg(args[n], XmNtopWidget, baseLabel); n++;
5301       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
5302       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
5303       XtSetArg(args[n], XmNleftWidget, baseValue); n++;
5304       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
5305       XtSetArg(args[n], XmNrightWidget, fir_button); n++;
5306       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
5307       XtSetArg(args[n], XmNmaximum, BASE_MAX); n++;
5308       XtSetArg(args[n], XmNvalue, BASE_MID); n++;
5309       XtSetArg(args[n], XmNincrement, 1); n++;
5310       XtSetArg(args[n], XmNpageIncrement, 1); n++;
5311       XtSetArg(args[n], XmNdragCallback, n1 = make_callback_list(base_drag_callback, NULL)); n++;
5312       XtSetArg(args[n], XmNvalueChangedCallback, n2 = make_callback_list(base_valuechanged_callback, NULL)); n++;
5313       baseScale = XtCreateManagedWidget("expscl", xmScrollBarWidgetClass, mainform, args, n);
5314 
5315       n = 0;
5316       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5317       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
5318       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
5319       XtSetArg(args[n], XmNbottomWidget, baseScale); n++;
5320       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5321       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5322       XtSetArg(args[n], XmNmargin, LINE_MARGIN); n++;
5323       XtSetArg(args[n], XmNheight, LINE_MARGIN); n++;
5324       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
5325       XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
5326       XtSetArg(args[n], XmNheight, 5); n++;
5327       baseSep = XtCreateManagedWidget("snd-rec-sep", xmSeparatorWidgetClass, mainform, args, n);
5328 
5329       /* -------- AMP ENV NAME -------- */
5330       n = 0;
5331       s1 = XmStringCreateLocalized((char *)"amp env:");
5332       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5333       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
5334       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
5335       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
5336       XtSetArg(args[n], XmNbottomWidget, baseSep); n++;
5337       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5338       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
5339       XtSetArg(args[n], XmNlabelString, s1); n++;
5340       XtSetArg(args[n], XmNshadowThickness, 0); n++;
5341       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
5342       nameL = XtCreateManagedWidget("nameL", xmLabelWidgetClass, mainform, args, n);
5343       XmStringFree(s1);
5344 
5345       n = 0;
5346       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5347       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
5348       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
5349       XtSetArg(args[n], XmNbottomWidget, baseSep); n++;
5350       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
5351       XtSetArg(args[n], XmNleftWidget, nameL); n++;
5352       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
5353       textL = make_textfield_widget("textL", mainform, args, n, ACTIVATABLE, add_completer_func(env_name_completer, NULL));
5354       XtAddCallback(textL, XmNactivateCallback, enved_text_activate_callback, NULL);
5355 
5356 
5357       /* -------- dB, GRAPH ('wave') AND CLIP BUTTONS -------- */
5358       n = 0;
5359       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5360       XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
5361       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
5362       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
5363       XtSetArg(args[n], XmNbottomWidget, baseSep); n++;
5364       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
5365       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5366       if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;}
5367       dB_button = make_togglebutton_widget("dB", mainform, args, n);
5368       XtAddCallback(dB_button, XmNvalueChangedCallback, dB_button_callback, NULL);
5369 
5370       n = 0;
5371       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5372       XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
5373       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
5374       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
5375       XtSetArg(args[n], XmNbottomWidget, baseSep); n++;
5376       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
5377       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
5378       XtSetArg(args[n], XmNrightWidget, dB_button); n++;
5379       if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;}
5380       graph_button = make_togglebutton_widget("wave", mainform, args, n);
5381       XtAddCallback(graph_button, XmNvalueChangedCallback, graph_button_callback, NULL);
5382 
5383       n = 0;
5384       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5385       XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
5386       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
5387       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
5388       XtSetArg(args[n], XmNbottomWidget, baseSep); n++;
5389       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
5390       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
5391       XtSetArg(args[n], XmNrightWidget, graph_button); n++;
5392       if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;}
5393       clip_button = make_togglebutton_widget("clip", mainform, args, n);
5394       XtAddCallback(clip_button, XmNvalueChangedCallback, clip_button_callback, NULL);
5395 
5396       /* -------- BREAKPOINT DATA DISPLAY LABEL -------- */
5397       n = 0;
5398       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5399       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
5400       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
5401       XtSetArg(args[n], XmNbottomWidget, baseSep); n++;
5402       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
5403       XtSetArg(args[n], XmNleftWidget, textL); n++;
5404       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
5405       XtSetArg(args[n], XmNrightWidget, clip_button); n++;
5406       XtSetArg(args[n], XmNrecomputeSize, false); n++;
5407       XtSetArg(args[n], XmNlabelType, XmSTRING); n++;
5408       brkptL = XtCreateManagedWidget("         ", xmLabelWidgetClass, mainform, args, n);
5409 
5410       /* -------- SPACERS TO DIVIDE WINDOW IN TWO -------- */
5411       n = 0;
5412       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5413       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
5414       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
5415       XtSetArg(args[n], XmNbottomWidget, textL); n++;
5416       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5417       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5418       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
5419       XtSetArg(args[n], XmNheight, 4); n++;
5420       XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
5421       spacer = XtCreateManagedWidget("spacer", xmSeparatorWidgetClass, mainform, args, n);
5422 
5423       n = 0;
5424       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5425       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
5426       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
5427       XtSetArg(args[n], XmNbottomWidget, spacer); n++;
5428       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5429       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5430       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
5431       XtSetArg(args[n], XmNseparatorType, XmSHADOW_ETCHED_IN); n++;
5432       spacer1 = XtCreateManagedWidget("spacer1", xmSeparatorWidgetClass, mainform, args, n);
5433       /* second separator needed because marginTop seems to be broken or non-existent for these widgets */
5434 
5435       /* -------- WINDOW LEFT WIDGET HOLDER -------- */
5436       n = 0;
5437       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5438       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
5439       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
5440       XtSetArg(args[n], XmNbottomWidget, spacer1); n++;
5441       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5442       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
5443       aform = XtCreateManagedWidget("aform", xmFormWidgetClass, mainform, args, n);
5444 
5445       /* -------- BUTTON BOX AT TOP LEFT -------- */
5446       n = 0;
5447       XtSetArg(args[n], XmNbackground, ss->zoom_color); n++;
5448       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
5449       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
5450       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5451       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5452       XtSetArg(args[n], XmNshadowThickness, 4); n++;
5453       XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++;
5454       colF = XtCreateManagedWidget("env-button-frame", xmFrameWidgetClass, aform, args, n);
5455 
5456       n = 0;
5457       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
5458       colB = XtCreateManagedWidget("env-button-holder", xmFormWidgetClass, colF, args, n);
5459 
5460       /* VIEW ENVS */
5461       n = 0;
5462       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
5463       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
5464       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
5465       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
5466       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5467       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5468       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
5469       show_button = XtCreateManagedWidget("view envs", xmPushButtonWidgetClass, colB, args, n);
5470       XtAddCallback(show_button, XmNactivateCallback, show_button_pressed, NULL);
5471 
5472       /* SAVE PRINT */
5473       n = 0;
5474       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
5475       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
5476       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
5477       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
5478       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
5479       XtSetArg(args[n], XmNtopWidget, show_button); n++;
5480       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5481       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5482       save_button = XtCreateManagedWidget("define it", xmPushButtonWidgetClass, colB, args, n);
5483 
5484       XtAddCallback(save_button, XmNactivateCallback, save_button_pressed, NULL);
5485 
5486       /* REVERT */
5487       n = 0;
5488       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
5489       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
5490       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
5491       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
5492       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
5493       XtSetArg(args[n], XmNtopWidget, save_button); n++;
5494       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5495       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5496       revert_button = XtCreateManagedWidget("revert", xmPushButtonWidgetClass, colB, args, n);
5497 
5498       XtAddCallback(revert_button, XmNactivateCallback, revert_button_pressed, NULL);
5499 
5500 
5501       /* UNDO REDO */
5502       n = 0;
5503       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
5504       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
5505       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
5506       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
5507       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
5508       XtSetArg(args[n], XmNtopWidget, revert_button); n++;
5509       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5510       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
5511       XtSetArg(args[n], XmNrightPosition, 50); n++;
5512       undo_button = XtCreateManagedWidget("undo", xmPushButtonWidgetClass, colB, args, n);
5513 
5514       n = 0;
5515       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
5516       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
5517       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
5518       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
5519       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
5520       XtSetArg(args[n], XmNtopWidget, undo_button); n++;
5521       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
5522       XtSetArg(args[n], XmNleftWidget, undo_button); n++;
5523       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5524       redo_button = XtCreateManagedWidget("redo", xmPushButtonWidgetClass, colB, args, n);
5525 
5526       XtAddCallback(undo_button, XmNactivateCallback, undo_button_pressed, NULL);
5527       XtAddCallback(redo_button, XmNactivateCallback, redo_button_pressed, NULL);
5528 
5529 
5530       /* AMP FLT SRC */
5531       /* enved_function (target) choice (a row of three push buttons that acts like a "radio box") */
5532       n = 0;
5533       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
5534       XtSetArg(args[n], XmNarmColor, ss->yellow); n++;
5535       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
5536       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
5537       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
5538       XtSetArg(args[n], XmNtopWidget, undo_button); n++;
5539       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5540       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
5541       XtSetArg(args[n], XmNrightPosition, 33); n++;
5542       amp_button = XtCreateManagedWidget("amp", xmPushButtonWidgetClass, colB, args, n);
5543 
5544       n = 0;
5545       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
5546       XtSetArg(args[n], XmNarmColor, ss->yellow); n++;
5547       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
5548       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
5549       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
5550       XtSetArg(args[n], XmNtopWidget, amp_button); n++;
5551       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
5552       XtSetArg(args[n], XmNleftWidget, amp_button); n++;
5553       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
5554       XtSetArg(args[n], XmNrightPosition, 67); n++;
5555       flt_button = XtCreateManagedWidget("flt", xmPushButtonWidgetClass, colB, args, n);
5556 
5557       n = 0;
5558       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
5559       XtSetArg(args[n], XmNarmColor, ss->yellow); n++;
5560       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
5561       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
5562       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
5563       XtSetArg(args[n], XmNtopWidget, flt_button); n++;
5564       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
5565       XtSetArg(args[n], XmNleftWidget, flt_button); n++;
5566       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5567       src_button = XtCreateManagedWidget("src", xmPushButtonWidgetClass, colB, args, n);
5568 
5569       XtAddCallback(flt_button, XmNactivateCallback, freq_button_callback, NULL);
5570       XtAddCallback(amp_button, XmNactivateCallback, amp_button_callback, NULL);
5571       XtAddCallback(src_button, XmNactivateCallback, src_button_callback, NULL);
5572 
5573       /* SELECTION */
5574       n = 0;
5575       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
5576       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
5577       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
5578       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
5579       XtSetArg(args[n], XmNtopWidget, amp_button); n++;
5580       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
5581       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5582       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5583       selection_button = make_pushbutton_widget("selection", colB, args, n);
5584 
5585       XtAddCallback(selection_button, XmNactivateCallback, selection_button_pressed, NULL);
5586 
5587 
5588       /* -------- ENV LIST AT LEFT UNDER BUTTONS -------- */
5589       n = 0;
5590       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
5591       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
5592       XtSetArg(args[n], XmNtopWidget, colF); n++;
5593       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
5594       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5595       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5596       XtSetArg(args[n], XmNshadowThickness, 4); n++;
5597       XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++;
5598       colE = XtCreateManagedWidget("env-list-frame", xmFrameWidgetClass, aform, args, n);
5599 
5600       n = 0;
5601       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
5602       colD = XtCreateManagedWidget("env-list-holder", xmFormWidgetClass, colE, args, n);
5603 
5604       n = 0;
5605       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5606       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5607       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
5608       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
5609       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5610       screnvname = XtCreateManagedWidget("envs:", xmLabelWidgetClass, colD, args, n);
5611 
5612       n = 0;
5613       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
5614       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
5615       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
5616       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
5617       XtSetArg(args[n], XmNtopWidget, screnvname); n++;
5618       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5619       if (ss->listener_fontlist)
5620 	{
5621 	  XtSetArg(args[n], XmNfontList, 0); n++;
5622 	  XtSetArg(args[n], XM_FONT_RESOURCE, ss->listener_fontlist); n++;
5623 	  use_listener_font = true;
5624 	}
5625       screnvlst = XmCreateScrolledList(colD, (char *)"scrolled-env-list", args, n);
5626       XtManageChild(screnvlst);
5627       XtAddCallback(screnvlst, XmNbrowseSelectionCallback, env_browse_callback, NULL);
5628       map_over_children(screnvlst, set_main_color_of_widget);
5629       if (enved_all_envs_top() > 0) make_scrolled_env_list();
5630 
5631       /* -------- MAIN GRAPH -------- */
5632 
5633       n = 0;
5634       XtSetArg(args[n], XmNbackground, ss->graph_color); n++;
5635       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
5636       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
5637       XtSetArg(args[n], XmNbottomWidget, spacer1 /* textL */); n++;
5638       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
5639       XtSetArg(args[n], XmNleftWidget, aform); n++;
5640       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
5641       XtSetArg(args[n], XmNheight, 350); n++;
5642       XtSetArg(args[n], XmNallowResize, true); n++;
5643       drawer = XtCreateManagedWidget("drawer", xmDrawingAreaWidgetClass, mainform, args, n);
5644 
5645       gv.function = GXcopy;
5646       XtVaGetValues(drawer, XmNbackground, &gv.background, XmNforeground, &gv.foreground, NULL);
5647       gc1 = XtGetGC(drawer, GCForeground | GCFunction, &gv);
5648       gv.foreground = ss->red;
5649       rgc = XtGetGC(drawer, GCBackground | GCForeground | GCFunction, &gv);
5650       gv.foreground = ss->enved_waveform_color;
5651       ggc = XtGetGC(drawer, GCBackground | GCForeground | GCFunction, &gv);
5652 
5653       XtManageChild(enved_dialog); /* needed so that window is valid when resize callback is invoked */
5654       apply_button = XmMessageBoxGetChild(enved_dialog, XmDIALOG_OK_BUTTON);
5655       cancel_button = XmMessageBoxGetChild(enved_dialog, XmDIALOG_CANCEL_BUTTON);
5656       cancelling = true;
5657 
5658       XtAddCallback(drawer, XmNresizeCallback, drawer_resize, NULL);
5659       XtAddCallback(drawer, XmNexposeCallback, drawer_resize, NULL);
5660 
5661       XtAddEventHandler(drawer, ButtonPressMask, false, drawer_button_press, NULL);
5662       XtAddEventHandler(drawer, ButtonMotionMask, false, drawer_button_motion, NULL);
5663       XtAddEventHandler(drawer, ButtonReleaseMask, false, drawer_button_release, NULL);
5664 
5665       if (enved_all_envs_top() == 0)
5666 	set_sensitive(show_button, false);
5667       set_sensitive(revert_button, false);
5668       set_sensitive(undo_button, false);
5669       set_sensitive(redo_button, false);
5670       set_sensitive(save_button, false);
5671       if (!(selection_is_active()))
5672 	set_sensitive(selection_button, false);
5673 
5674       XmToggleButtonSetState(clip_button, (Boolean)(enved_clipping(ss)), false);
5675       XmToggleButtonSetState(graph_button, (Boolean)(enved_with_wave(ss)), false);
5676       XmToggleButtonSetState(dB_button, (Boolean)(enved_in_dB(ss)), false);
5677 
5678       free(n1);
5679       free(n2);
5680 
5681       reflect_apply_state();
5682       reflect_segment_state();
5683       reflect_sound_state();
5684 
5685       set_dialog_widget(ENVED_DIALOG, enved_dialog);
5686 
5687       add_reflect_enved_hook();
5688     }
5689   else raise_dialog(enved_dialog);
5690   if (!XtIsManaged(enved_dialog))
5691     XtManageChild(enved_dialog);
5692   active_channel = current_channel();
5693   return(enved_dialog);
5694 }
5695 
5696 
set_enved_clipping(bool val)5697 void set_enved_clipping(bool val)
5698 {
5699   in_set_enved_clipping(val);
5700   if (enved_dialog)
5701     XmToggleButtonSetState(clip_button, (Boolean)val, false);
5702 }
5703 
5704 
reflect_enved_style(void)5705 void reflect_enved_style(void)
5706 {
5707   reflect_segment_state();
5708 }
5709 
5710 
set_enved_target(enved_target_t val)5711 void set_enved_target(enved_target_t val)
5712 {
5713   in_set_enved_target(val);
5714   if (enved_dialog)
5715     reflect_apply_state();
5716 }
5717 
5718 
set_enved_with_wave(bool val)5719 void set_enved_with_wave(bool val)
5720 {
5721   in_set_enved_with_wave(val);
5722   if (enved_dialog)
5723     XmToggleButtonSetState(graph_button, (Boolean)val, false);
5724 }
5725 
5726 
set_enved_in_dB(bool val)5727 void set_enved_in_dB(bool val)
5728 {
5729   in_set_enved_in_dB(val);
5730   if (enved_dialog)
5731     XmToggleButtonSetState(dB_button, (Boolean)val, false);
5732 }
5733 
5734 
set_enved_base(mus_float_t val)5735 void set_enved_base(mus_float_t val)
5736 {
5737   in_set_enved_base(val);
5738   if (enved_dialog)
5739     reflect_changed_base(val);
5740 }
5741 
5742 
enved_dialog_is_active(void)5743 bool enved_dialog_is_active(void)
5744 {
5745   return((enved_dialog) &&
5746 	 (XtIsManaged(enved_dialog)));
5747 }
5748 
5749 
set_enved_filter_order(int order)5750 void set_enved_filter_order(int order)
5751 {
5752   if ((order > 0) && (order < 2000))
5753     {
5754       if (order & 1)
5755 	{in_set_enved_filter_order(order + 1);}
5756       else {in_set_enved_filter_order(order);}
5757       if (enved_dialog)
5758 	{
5759 	  widget_int_to_text(orderL, enved_filter_order(ss));
5760 	  if ((enved_dialog) &&
5761 	      (enved_target(ss) == ENVED_SPECTRUM) &&
5762 	      (enved_with_wave(ss)) && (!showing_all_envs))
5763 	    env_redisplay();
5764 	}
5765     }
5766 }
5767 
5768 
enved_reflect_selection(bool on)5769 void enved_reflect_selection(bool on)
5770 {
5771   if ((enved_dialog) && (!within_selection_src))
5772     {
5773       set_sensitive(selection_button, on);
5774       if ((apply_to_selection) && (!on))
5775 	{
5776 	  apply_to_selection = false;
5777 	  we_turned_selection_off = true;
5778 	}
5779       if ((on) && (we_turned_selection_off))
5780 	{
5781 	  apply_to_selection = true;
5782 	}
5783       XmChangeColor(selection_button, (apply_to_selection) ? ((Pixel)ss->yellow) : ((Pixel)ss->highlight_color));
5784       if ((enved_target(ss) != ENVED_SPECTRUM) &&
5785 	  (enved_with_wave(ss)) &&
5786 	  (!showing_all_envs))
5787 	env_redisplay();
5788     }
5789 }
5790 
5791 
5792 
color_enved_waveform(Pixel pix)5793 void color_enved_waveform(Pixel pix)
5794 {
5795   if (enved_dialog)
5796     {
5797       XSetForeground(main_display(ss), ggc, pix);
5798       if ((enved_with_wave(ss)) &&
5799 	  (enved_dialog))
5800 	env_redisplay();
5801     }
5802 }
5803 
5804 
g_enved_envelope(void)5805 static Xen g_enved_envelope(void)
5806 {
5807   #define H_enved_envelope "(" S_enved_envelope "): current envelope editor displayed (active) envelope"
5808   return(env_to_xen(active_env));
5809 }
5810 
5811 
g_set_enved_envelope(Xen e)5812 static Xen g_set_enved_envelope(Xen e)
5813 {
5814   Xen_check_type(Xen_is_list(e) || Xen_is_string(e) || Xen_is_symbol(e), e, 1, S_set S_enved_envelope, "a list, symbol, or string");
5815   if (active_env) active_env = free_env(active_env);
5816   if ((Xen_is_string(e)) || (Xen_is_symbol(e)))
5817     active_env = name_to_env((Xen_is_string(e)) ? Xen_string_to_C_string(e) : Xen_symbol_to_C_string(e)); /* xen_to_env in name_to_env, so no copy */
5818   else active_env = xen_to_env(e);
5819   if ((!active_env) && (!(Xen_is_list(e))))
5820     Xen_error(Xen_make_error_type("no-such-envelope"),
5821 	      Xen_list_2(C_string_to_Xen_string(S_set S_enved_envelope ": bad envelope arg: ~A"),
5822 			 e));
5823   if (enved_dialog)
5824     env_redisplay();
5825   return(e);
5826 }
5827 
5828 
g_enved_filter(void)5829 static Xen g_enved_filter(void)
5830 {
5831   #define H_enved_filter "(" S_enved_filter "): envelope editor FIR/FFT filter choice (" PROC_TRUE ": FIR)"
5832   return(C_bool_to_Xen_boolean(is_FIR));
5833 }
5834 
5835 
g_set_enved_filter(Xen type)5836 static Xen g_set_enved_filter(Xen type)
5837 {
5838   Xen_check_type(Xen_is_boolean(type), type, 1, S_set S_enved_filter, "boolean");
5839   is_FIR = Xen_boolean_to_C_bool(type);
5840   if (fir_button)
5841     set_label(fir_button, (is_FIR) ? "fir" : "fft");
5842   return(type);
5843 }
5844 
5845 
5846 /* Transform settings dialog */
5847 
5848 
5849 static Widget transform_dialog = NULL; /* main dialog shell */
5850 static Widget type_list, size_list, wavelet_list, window_list;
5851 static Widget beta_scale, alpha_scale, start_scale, end_scale, alpha_number, beta_number, start_number, end_number;
5852 static Widget db_button, peaks_button, logfreq_button, sono_button, spectro_button, normo_button, normalize_button, selection_button1, phases_button;
5853 static Widget graph_label, graph_drawer;
5854 static Widget peak_txt, db_txt, freq_base_txt;
5855 static Widget error_frame1, error_label1;
5856 
5857 #define NUM_TRANSFORM_SIZES 15
5858 static const char *transform_size_names[NUM_TRANSFORM_SIZES] =
5859   {"32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384", "65536", "262144", "1048576", "4194304    ", "16777216"};
5860 static mus_long_t transform_sizes[NUM_TRANSFORM_SIZES] =
5861   {32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 65536, 262144, 1048576, 4194304, 16777216};
5862 
5863 
5864 
5865 /* ---------------- fft window graph ---------------- */
5866 
5867 static GC gc2, fgc;
5868 
5869 #define GRAPH_SIZE 128
5870 static mus_float_t graph_data[GRAPH_SIZE]; /* fft window graph in transform options dialog */
5871 static mus_float_t graph_fftr[GRAPH_SIZE * 2];
5872 static mus_float_t graph_ffti[GRAPH_SIZE * 2];
5873 /* I goofed around with making the graph size dependent on the drawer's width, but there's really nothing gained */
5874 /*   also tried linear/db+min-dB distinction, but linear looks dumb and min-dB is a bother */
5875 
fp_dB(mus_float_t py)5876 static mus_float_t fp_dB(mus_float_t py)
5877 {
5878   return((py <= ss->lin_dB) ? 0.0 : (1.0 - (20.0 * log10(py) / min_dB(ss))));
5879 }
5880 
5881 
local_grf_x(double val,axis_info * ap)5882 static int local_grf_x(double val, axis_info *ap)
5883 {
5884   if (val >= ap->x1) return(ap->x_axis_x1);
5885   if (val <= ap->x0) return(ap->x_axis_x0);
5886   return((int)(ap->x_base + val * ap->x_scale));
5887 }
5888 
5889 
local_grf_y(mus_float_t val,axis_info * ap)5890 static int local_grf_y(mus_float_t val, axis_info *ap)
5891 {
5892   if (val >= ap->y1) return(ap->y_axis_y1);
5893   if (val <= ap->y0) return(ap->y_axis_y0);
5894   return((int)(ap->y_base + val * ap->y_scale));
5895 }
5896 
5897 
5898 static axis_info *axis_ap = NULL;
5899 
graph_redisplay(void)5900 static void graph_redisplay(void)
5901 {
5902   /* fft_window(ss) is the current choice */
5903   int ix0, iy0, ix1, iy1, i;
5904   mus_float_t xincr, x;
5905   graphics_context *ax;
5906 
5907   if (!axis_ap)
5908     {
5909       axis_ap = (axis_info *)calloc(1, sizeof(axis_info));
5910       ax = (graphics_context *)calloc(1, sizeof(graphics_context));
5911       axis_ap->ax = ax;
5912       ax->dp = XtDisplay(graph_drawer);
5913       ax->wn = XtWindow(graph_drawer);
5914     }
5915   else ax = axis_ap->ax;
5916 
5917   axis_ap->xmin = 0.0;
5918   axis_ap->xmax = 1.0;
5919   axis_ap->x_ambit = 1.0;
5920   axis_ap->x0 = 0.0;
5921   axis_ap->x1 = 1.0;
5922 
5923   if (axis_ap->xlabel) free(axis_ap->xlabel);
5924   if (fft_beta_max(fft_window(ss)) != 1.0)
5925     axis_ap->xlabel = mus_format("(%d, beta: %.2f)", GRAPH_SIZE, fft_beta_max(fft_window(ss)) * fft_window_beta(ss));
5926   else axis_ap->xlabel = mus_format("(%d)", GRAPH_SIZE);
5927 
5928   if (fft_window(ss) == MUS_FLAT_TOP_WINDOW)
5929     {
5930       axis_ap->ymin = -0.1;
5931       axis_ap->ymax = 1.0;
5932       axis_ap->y_ambit = 1.1;
5933       axis_ap->y0 = -0.1;
5934       axis_ap->y1 = 1.0;
5935     }
5936   else
5937     {
5938       axis_ap->ymin = 0.0;
5939       axis_ap->ymax = 1.0;
5940       axis_ap->y_ambit = 1.0;
5941       axis_ap->y0 = 0.0;
5942       axis_ap->y1 = 1.0;
5943     }
5944 
5945   axis_ap->width = widget_width(graph_drawer);
5946   axis_ap->window_width = axis_ap->width;
5947   axis_ap->y_offset = 0;
5948   axis_ap->height = widget_height(graph_drawer);
5949   axis_ap->graph_x0 = 0;
5950 
5951   clear_window(ax);
5952   ax->gc = gc2;
5953   make_axes_1(axis_ap, X_AXIS_IN_SECONDS, 1 /* "srate" */, SHOW_ALL_AXES, NOT_PRINTING, WITH_X_AXIS, NO_GRID, WITH_LINEAR_AXES, grid_density(ss));
5954 
5955   ix1 = local_grf_x(0.0, axis_ap);
5956   iy1 = local_grf_y(graph_data[0], axis_ap);
5957   xincr = 1.0 / (mus_float_t)GRAPH_SIZE;
5958 
5959   for (i = 1, x = xincr; i < GRAPH_SIZE; i++, x += xincr)
5960     {
5961       ix0 = ix1;
5962       iy0 = iy1;
5963       ix1 = local_grf_x(x, axis_ap);
5964       iy1 = local_grf_y(graph_data[i], axis_ap);
5965       XDrawLine(ax->dp, ax->wn, gc2, ix0, iy0, ix1, iy1);
5966     }
5967 
5968   ax->gc = fgc;
5969   ix1 = local_grf_x(0.0, axis_ap);
5970   iy1 = local_grf_y(graph_fftr[0], axis_ap);
5971   xincr = 1.0 / (mus_float_t)GRAPH_SIZE;
5972 
5973   for (i = 1, x = xincr; i < GRAPH_SIZE; i++, x += xincr)
5974     {
5975       ix0 = ix1;
5976       iy0 = iy1;
5977       ix1 = local_grf_x(x, axis_ap);
5978       if (fft_log_magnitude(ss))
5979 	iy1 = local_grf_y(fp_dB(graph_fftr[i]), axis_ap);
5980       else iy1 = local_grf_y(graph_fftr[i], axis_ap);
5981       XDrawLine(ax->dp, ax->wn, fgc, ix0, iy0, ix1, iy1);
5982     }
5983 }
5984 
5985 
get_fft_window_data(void)5986 static void get_fft_window_data(void)
5987 {
5988   int i;
5989   mus_make_fft_window_with_window(fft_window(ss), GRAPH_SIZE,
5990 				  fft_window_beta(ss) * fft_beta_max(fft_window(ss)),
5991 				  fft_window_alpha(ss), graph_data);
5992   mus_clear_floats(graph_fftr, GRAPH_SIZE * 2);
5993   mus_clear_floats(graph_ffti, GRAPH_SIZE * 2);
5994   mus_copy_floats(graph_fftr, graph_data, GRAPH_SIZE);
5995   mus_spectrum(graph_fftr, graph_ffti, NULL, GRAPH_SIZE * 2, MUS_SPECTRUM_IN_DB);
5996   for (i = 0; i < GRAPH_SIZE; i++)
5997     graph_fftr[i] = (graph_fftr[i] + 80.0) / 80.0; /* min dB here is -80 */
5998 }
5999 
6000 
widget_float_to_text(Widget w,mus_float_t val)6001 static void widget_float_to_text(Widget w, mus_float_t val)
6002 {
6003   char *str;
6004   str = (char *)calloc(16, sizeof(char));
6005   snprintf(str, 16, "%.2f", val);
6006   XmTextFieldSetString(w, str);
6007   free(str);
6008 }
6009 
6010 
6011 
6012 /* ---------------- errors ---------------- */
6013 
clear_fft_error(void)6014 static void clear_fft_error(void)
6015 {
6016   if ((error_frame1) && (XtIsManaged(error_frame1)))
6017     XtUnmanageChild(error_frame1);
6018 }
6019 
6020 
unpost_fft_error(XtPointer data,XtIntervalId * id)6021 static void unpost_fft_error(XtPointer data, XtIntervalId *id)
6022 {
6023   clear_fft_error();
6024 }
6025 
6026 
errors_to_fft_text(const char * msg,void * data)6027 static void errors_to_fft_text(const char *msg, void *data)
6028 {
6029   int lines = 0;
6030   XmString label;
6031   label = multi_line_label(msg, &lines);
6032   XtVaSetValues(error_label1,
6033 		XmNlabelString, label,
6034 		XmNheight, lines * 20,
6035 		NULL);
6036   XtVaSetValues(error_frame1, XmNheight, lines * 20, NULL);
6037   XmStringFree(label);
6038   XtManageChild(error_frame1);
6039   /* since the offending text is automatically overwritten, we can't depend on subsequent text modify callbacks
6040    *   to clear things, so we'll just use a timer
6041    */
6042   XtAppAddTimeOut(main_app(ss),
6043 		  5000,
6044 		  (XtTimerCallbackProc)unpost_fft_error,
6045 		  NULL);
6046 }
6047 
6048 
6049 
6050 /* ---------------- transform size ---------------- */
6051 
chans_transform_size(chan_info * cp,mus_long_t size)6052 static void chans_transform_size(chan_info *cp, mus_long_t size)
6053 {
6054   cp->transform_size = size;
6055   if (cp->fft)
6056     cp->fft->size = size;
6057 }
6058 
6059 
set_transform_size(mus_long_t val)6060 void set_transform_size(mus_long_t val)
6061 {
6062   for_each_chan(force_fft_clear);
6063   in_set_transform_size(val);
6064   for_each_chan_with_mus_long_t(chans_transform_size, val);
6065   if (transform_dialog)
6066     {
6067       int i;
6068       for (i = 0; i < NUM_TRANSFORM_SIZES; i++)
6069 	if (transform_sizes[i] == val)
6070 	  {
6071 	    XmListSelectPos(size_list, i + 1, false);
6072 	    break;
6073 	  }
6074     }
6075   if (!(ss->graph_hook_active)) for_each_chan(calculate_fft);
6076 }
6077 
6078 
size_browse_callback(Widget w,XtPointer context,XtPointer info)6079 static void size_browse_callback(Widget w, XtPointer context, XtPointer info)
6080 {
6081   XmListCallbackStruct *cbs = (XmListCallbackStruct *)info;
6082   for_each_chan(force_fft_clear);
6083   in_set_transform_size(transform_sizes[cbs->item_position - 1]);
6084   for_each_chan_with_mus_long_t(chans_transform_size, transform_size(ss));
6085   for_each_chan(calculate_fft);
6086   set_label(graph_label, mus_fft_window_name(fft_window(ss)));
6087 }
6088 
6089 
6090 /* ---------------- wavelet choice ---------------- */
6091 
chans_wavelet_type(chan_info * cp,int value)6092 static void chans_wavelet_type(chan_info *cp, int value)
6093 {
6094   cp->wavelet_type = value;
6095 }
6096 
6097 
set_wavelet_type(int val)6098 void set_wavelet_type(int val)
6099 {
6100   if (transform_dialog) XmListSelectPos(wavelet_list, val, false);
6101   in_set_wavelet_type(val);
6102   for_each_chan_with_int(chans_wavelet_type, val);
6103   if ((transform_type(ss) == WAVELET) &&
6104       (!(ss->graph_hook_active)))
6105     for_each_chan(calculate_fft);
6106 }
6107 
6108 
wavelet_browse_callback(Widget w,XtPointer context,XtPointer info)6109 static void wavelet_browse_callback(Widget w, XtPointer context, XtPointer info)
6110 {
6111   int val;
6112   XmListCallbackStruct *cbs = (XmListCallbackStruct *)info;
6113   in_set_wavelet_type(val = (cbs->item_position - 1)); /* make these numbers 0-based as in mus.lisp */
6114   for_each_chan_with_int(chans_wavelet_type, val);
6115   if (transform_type(ss) == WAVELET)
6116     for_each_chan(calculate_fft);
6117 }
6118 
6119 
6120 /* ---------------- fft window choice ---------------- */
6121 
highlight_alpha_beta_scales(mus_fft_window_t val)6122 static void highlight_alpha_beta_scales(mus_fft_window_t val)
6123 {
6124   if (fft_window_beta_in_use(val))
6125     {
6126       XtVaSetValues(beta_scale, XmNbackground, ss->highlight_color, NULL);
6127       XtVaSetValues(beta_number, XmNbackground, ss->highlight_color, NULL);
6128     }
6129   else
6130     {
6131       XtVaSetValues(beta_scale, XmNbackground, ss->basic_color, NULL);
6132       XtVaSetValues(beta_number, XmNbackground, ss->basic_color, NULL);
6133     }
6134 
6135   if (fft_window_alpha_in_use(val))
6136     {
6137       XtVaSetValues(alpha_scale, XmNbackground, ss->highlight_color, NULL);
6138       XtVaSetValues(alpha_number, XmNbackground, ss->highlight_color, NULL);
6139     }
6140   else
6141     {
6142       XtVaSetValues(alpha_scale, XmNbackground, ss->basic_color, NULL);
6143       XtVaSetValues(alpha_number, XmNbackground, ss->basic_color, NULL);
6144     }
6145 }
6146 
6147 
set_fft_window(mus_fft_window_t val)6148 void set_fft_window(mus_fft_window_t val)
6149 {
6150   in_set_fft_window(val);
6151   if (!(ss->graph_hook_active)) for_each_chan(calculate_fft);
6152   if (transform_dialog)
6153     {
6154       XmListSelectPos(window_list, (int)val + 1, false);
6155       set_label(graph_label, mus_fft_window_name(val));
6156       get_fft_window_data();
6157       if (XtIsManaged(transform_dialog))
6158 	graph_redisplay();
6159       highlight_alpha_beta_scales(val);
6160     }
6161 }
6162 
6163 
window_browse_callback(Widget w,XtPointer context,XtPointer info)6164 static void window_browse_callback(Widget w, XtPointer context, XtPointer info)
6165 {
6166   XmListCallbackStruct *cbs = (XmListCallbackStruct *)info;
6167   mus_fft_window_t fft_window_choice;
6168 
6169   fft_window_choice = (mus_fft_window_t)(cbs->item_position - 1); /* make these numbers 0-based as in mus.lisp */
6170 
6171   in_set_fft_window(fft_window_choice);
6172   for_each_chan(calculate_fft);
6173   set_label(graph_label, mus_fft_window_name(fft_window(ss)));
6174   get_fft_window_data();
6175   graph_redisplay();
6176   highlight_alpha_beta_scales(fft_window_choice);
6177 }
6178 
6179 
6180 
6181 /* ---------------- transform choice ---------------- */
6182 
chans_transform_type(chan_info * cp,int value)6183 static void chans_transform_type(chan_info *cp, int value)
6184 {
6185   cp->transform_type = value;
6186 }
6187 
6188 
set_transform_type(int val)6189 void set_transform_type(int val)
6190 {
6191   if (is_transform(val))
6192     {
6193       if (!(ss->graph_hook_active)) for_each_chan(force_fft_clear);
6194       in_set_transform_type(val);
6195       for_each_chan_with_int(chans_transform_type, val);
6196       if (!(ss->graph_hook_active))
6197 	for_each_chan(calculate_fft);
6198       if (transform_dialog) XmListSelectPos(type_list, transform_type_to_position(val) + 1, false);
6199     }
6200 }
6201 
6202 
transform_type_browse_callback(Widget w,XtPointer context,XtPointer info)6203 static void transform_type_browse_callback(Widget w, XtPointer context, XtPointer info)
6204 {
6205   int type;
6206   XmListCallbackStruct *cbs = (XmListCallbackStruct *)info;
6207   type = transform_position_to_type(cbs->item_position - 1);
6208   for_each_chan(force_fft_clear);
6209   in_set_transform_type(type);
6210   for_each_chan_with_int(chans_transform_type, type);
6211   for_each_chan(calculate_fft);
6212 }
6213 
6214 
make_transform_type_list(void)6215 void make_transform_type_list(void)
6216 {
6217   int num;
6218   num = max_transform_type();
6219   if (transform_dialog)
6220     {
6221       XmString *types;
6222       int i, j;
6223       types = (XmString *)calloc(num, sizeof(XmString));
6224       for (i = 0, j = 0; i < num; i++)
6225 	if (is_transform(i))
6226 	  {
6227 	    set_transform_position(i, j);
6228 	    types[j++] = XmStringCreateLocalized((char *)transform_name(i));
6229 	  }
6230       XtVaSetValues(type_list,
6231 		    XmNitems, types,
6232 		    XmNitemCount, j,
6233 		    XmNvisibleItemCount, 6,
6234 		    NULL);
6235       for (i = 0; i < j; i++)
6236 	XmStringFree(types[i]);
6237       free(types);
6238     }
6239 }
6240 
6241 
6242 
6243 /* ---------------- transform "graph type" (i.e. sonogram etc) ---------------- */
6244 
set_transform_graph_type(graph_type_t val)6245 void set_transform_graph_type(graph_type_t val)
6246 {
6247   in_set_transform_graph_type(val);
6248   if (transform_dialog)
6249     switch (val)
6250       {
6251       case GRAPH_ONCE:
6252 	XmToggleButtonSetState(normo_button, true, false);
6253 	XmToggleButtonSetState(spectro_button, false, false);
6254 	XmToggleButtonSetState(sono_button, false, false);
6255 	break;
6256       case GRAPH_AS_SONOGRAM:
6257 	XmToggleButtonSetState(normo_button, false, false);
6258 	XmToggleButtonSetState(spectro_button, false, false);
6259 	XmToggleButtonSetState(sono_button, true, false);
6260 	break;
6261       case GRAPH_AS_SPECTROGRAM:
6262 	XmToggleButtonSetState(normo_button, false, false);
6263 	XmToggleButtonSetState(spectro_button, true, false);
6264 	XmToggleButtonSetState(sono_button, false, false);
6265 	break;
6266       case GRAPH_AS_WAVOGRAM:
6267 	break;
6268       }
6269   if (!(ss->graph_hook_active))
6270     for_each_chan(calculate_fft);
6271 }
6272 
6273 
graph_transform_once_callback(Widget w,XtPointer context,XtPointer info)6274 static void graph_transform_once_callback(Widget w, XtPointer context, XtPointer info)
6275 {
6276   graph_type_t old_type;
6277   old_type = transform_graph_type(ss);
6278   XmToggleButtonSetState(normo_button, true, false);
6279   XmToggleButtonSetState(sono_button, false, false);
6280   XmToggleButtonSetState(spectro_button, false, false);
6281   in_set_transform_graph_type(GRAPH_ONCE);
6282   if (old_type != GRAPH_ONCE)
6283     for_each_chan(calculate_fft);
6284 }
6285 
6286 
sonogram_callback(Widget w,XtPointer context,XtPointer info)6287 static void sonogram_callback(Widget w, XtPointer context, XtPointer info)
6288 {
6289   graph_type_t old_type;
6290   old_type = transform_graph_type(ss);
6291   XmToggleButtonSetState(sono_button, true, false);
6292   XmToggleButtonSetState(normo_button, false, false);
6293   XmToggleButtonSetState(spectro_button, false, false);
6294   in_set_transform_graph_type(GRAPH_AS_SONOGRAM);
6295   if (old_type != GRAPH_AS_SONOGRAM)
6296     for_each_chan(calculate_fft);
6297 }
6298 
6299 
spectrogram_callback(Widget w,XtPointer context,XtPointer info)6300 static void spectrogram_callback(Widget w, XtPointer context, XtPointer info)
6301 {
6302   graph_type_t old_type;
6303   old_type = transform_graph_type(ss);
6304   XmToggleButtonSetState(spectro_button, true, false);
6305   XmToggleButtonSetState(normo_button, false, false);
6306   XmToggleButtonSetState(sono_button, false, false);
6307   in_set_transform_graph_type(GRAPH_AS_SPECTROGRAM);
6308   if (old_type != GRAPH_AS_SPECTROGRAM)
6309     for_each_chan(calculate_fft);
6310 }
6311 
6312 
6313 
6314 /* ---------------- show peaks ---------------- */
6315 
map_show_transform_peaks(chan_info * cp,bool value)6316 static void map_show_transform_peaks(chan_info *cp, bool value)
6317 {
6318   cp->show_transform_peaks = value;
6319 }
6320 
6321 
peaks_callback(Widget w,XtPointer context,XtPointer info)6322 static void peaks_callback(Widget w, XtPointer context, XtPointer info)
6323 {
6324   bool val;
6325   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
6326   val = (cb->set);
6327   in_set_show_transform_peaks(val);
6328   for_each_chan_with_bool(map_show_transform_peaks, val);
6329   for_each_chan(calculate_fft);
6330 }
6331 
6332 
set_show_transform_peaks(bool val)6333 void set_show_transform_peaks(bool val)
6334 {
6335   in_set_show_transform_peaks(val);
6336   for_each_chan_with_bool(map_show_transform_peaks, val);
6337   if (transform_dialog)
6338     set_toggle_button(peaks_button, val, false, NULL);
6339   if (!(ss->graph_hook_active))
6340     for_each_chan(calculate_fft);
6341 }
6342 
6343 
reflect_peaks_in_transform_dialog(void)6344 void reflect_peaks_in_transform_dialog(void)
6345 {
6346   if (transform_dialog)
6347     widget_int_to_text(peak_txt, max_transform_peaks(ss));
6348 }
6349 
6350 
peaks_activate_callback(Widget w,XtPointer context,XtPointer info)6351 static void peaks_activate_callback(Widget w, XtPointer context, XtPointer info)
6352 {
6353   char *str;
6354   str = XmTextFieldGetString(w);
6355   if ((str) && (*str))
6356     {
6357       int new_peaks;
6358       redirect_errors_to(errors_to_fft_text, NULL);
6359       new_peaks = string_to_int(str, 1, "peaks");
6360       redirect_errors_to(NULL, NULL);
6361       if (new_peaks >= 1)
6362 	{
6363 	  set_max_transform_peaks(new_peaks);
6364 	  for_each_chan(calculate_fft);
6365 	}
6366       else widget_int_to_text(w, max_transform_peaks(ss));
6367       XtFree(str);
6368     }
6369 }
6370 
6371 
6372 
6373 /* ---------------- log magnitude ---------------- */
6374 
chans_fft_log_magnitude(chan_info * cp,bool value)6375 static void chans_fft_log_magnitude(chan_info *cp, bool value)
6376 {
6377   cp->fft_log_magnitude = value;
6378   cp->fft_changed = FFT_CHANGE_LOCKED;
6379 }
6380 
6381 
set_fft_log_magnitude(bool val)6382 void set_fft_log_magnitude(bool val)
6383 {
6384   in_set_fft_log_magnitude(val);
6385   for_each_chan_with_bool(chans_fft_log_magnitude, val);
6386   if (transform_dialog)
6387     set_toggle_button(db_button, val, false, NULL);
6388   if (!(ss->graph_hook_active))
6389     for_each_chan(calculate_fft);
6390 }
6391 
6392 
6393 
6394 /* ---------------- dB ---------------- */
6395 
fft_db_callback(Widget w,XtPointer context,XtPointer info)6396 static void fft_db_callback(Widget w, XtPointer context, XtPointer info)
6397 {
6398   bool val;
6399   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
6400   val = cb->set;
6401   in_set_fft_log_magnitude(val);
6402   graph_redisplay();
6403   for_each_chan_with_bool(chans_fft_log_magnitude, val);
6404   for_each_chan(calculate_fft);
6405 }
6406 
6407 
reflect_min_db_in_transform_dialog(void)6408 void reflect_min_db_in_transform_dialog(void)
6409 {
6410   if (transform_dialog)
6411     widget_float_to_text(db_txt, min_dB(ss));
6412 }
6413 
6414 
min_db_activate_callback(Widget w,XtPointer context,XtPointer info)6415 static void min_db_activate_callback(Widget w, XtPointer context, XtPointer info)
6416 {
6417   char *str;
6418   str = XmTextFieldGetString(w);
6419   if ((str) && (*str))
6420     {
6421       mus_float_t new_db;
6422       redirect_errors_to(errors_to_fft_text, NULL);
6423       new_db = string_to_mus_float_t(str, -10000.0, "dB");
6424       redirect_errors_to(NULL, NULL);
6425       if (new_db < 0.0)
6426 	set_min_db(new_db);
6427       else widget_float_to_text(w, min_dB(ss));
6428       XtFree(str);
6429     }
6430 }
6431 
6432 
6433 
6434 /* ---------------- log frequency ---------------- */
6435 
chans_fft_log_frequency(chan_info * cp,bool value)6436 static void chans_fft_log_frequency(chan_info *cp, bool value)
6437 {
6438   cp->fft_log_frequency = value;
6439   cp->fft_changed = FFT_CHANGE_LOCKED;
6440 }
6441 
6442 
logfreq_callback(Widget w,XtPointer context,XtPointer info)6443 static void logfreq_callback(Widget w, XtPointer context, XtPointer info)
6444 {
6445   bool val;
6446   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
6447   val = cb->set;
6448   in_set_fft_log_frequency(val);
6449   for_each_chan_with_bool(chans_fft_log_frequency, val);
6450   for_each_chan(calculate_fft);
6451 }
6452 
6453 
set_fft_log_frequency(bool val)6454 void set_fft_log_frequency(bool val)
6455 {
6456   in_set_fft_log_frequency(val);
6457   for_each_chan_with_bool(chans_fft_log_frequency, val);
6458   if (transform_dialog)
6459     set_toggle_button(logfreq_button, val, false, NULL);
6460   if (!(ss->graph_hook_active))
6461     for_each_chan(calculate_fft);
6462 }
6463 
6464 
reflect_log_freq_start_in_transform_dialog(void)6465 void reflect_log_freq_start_in_transform_dialog(void)
6466 {
6467   if (transform_dialog)
6468     widget_float_to_text(freq_base_txt, log_freq_start(ss));
6469 }
6470 
6471 
log_freq_start_activate_callback(Widget w,XtPointer context,XtPointer info)6472 static void log_freq_start_activate_callback(Widget w, XtPointer context, XtPointer info)
6473 {
6474   char *str;
6475   str = XmTextFieldGetString(w);
6476   if ((str) && (*str))
6477     {
6478       mus_float_t new_lfb;
6479       redirect_errors_to(errors_to_fft_text, NULL);
6480       new_lfb = string_to_mus_float_t(str, 0.0, "log freq start");
6481       redirect_errors_to(NULL, NULL);
6482       if (new_lfb > 0.0)
6483 	set_log_freq_start(new_lfb);
6484       else widget_float_to_text(w, log_freq_start(ss));
6485       XtFree(str);
6486     }
6487 }
6488 
6489 
6490 
6491 
6492 /* ---------------- normalization choice ---------------- */
6493 
chans_transform_normalization(chan_info * cp,int value)6494 static void chans_transform_normalization(chan_info *cp, int value)
6495 {
6496   cp->transform_normalization = (fft_normalize_t)value;
6497   cp->fft_changed = FFT_CHANGE_LOCKED;
6498 }
6499 
6500 
normalize_callback(Widget w,XtPointer context,XtPointer info)6501 static void normalize_callback(Widget w, XtPointer context, XtPointer info)
6502 {
6503   fft_normalize_t choice;
6504   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
6505   choice = (cb->set) ? NORMALIZE_BY_CHANNEL : DONT_NORMALIZE;
6506   in_set_transform_normalization(choice);
6507   for_each_chan_with_int(chans_transform_normalization, (int)choice);
6508   for_each_chan(calculate_fft);
6509 }
6510 
6511 
set_transform_normalization(fft_normalize_t val)6512 void set_transform_normalization(fft_normalize_t val)
6513 {
6514   in_set_transform_normalization(val);
6515   for_each_chan_with_int(chans_transform_normalization, (int)val);
6516   if (transform_dialog)
6517     set_toggle_button(normalize_button, (val != DONT_NORMALIZE), false, NULL);
6518   if (!(ss->graph_hook_active))
6519     for_each_chan(calculate_fft);
6520 }
6521 
6522 
6523 
6524 /* ---------------- show selection transform ---------------- */
6525 
selection_callback(Widget w,XtPointer context,XtPointer info)6526 static void selection_callback(Widget w, XtPointer context, XtPointer info)
6527 {
6528   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
6529   in_set_show_selection_transform(cb->set);
6530   for_each_chan(calculate_fft);
6531 }
6532 
6533 
set_show_selection_transform(bool show)6534 void set_show_selection_transform(bool show)
6535 {
6536   in_set_show_selection_transform(show);
6537   if (transform_dialog)
6538     set_toggle_button(selection_button1, show, false, NULL);
6539   if (!(ss->graph_hook_active))
6540     for_each_chan(calculate_fft);
6541 }
6542 
6543 
6544 
6545 /* ---------------- show phases (via color) ---------------- */
6546 
chans_fft_with_phases(chan_info * cp,bool value)6547 static void chans_fft_with_phases(chan_info *cp, bool value)
6548 {
6549   cp->fft_with_phases = value;
6550   cp->fft_changed = FFT_CHANGE_LOCKED;
6551 }
6552 
6553 
phases_callback(Widget w,XtPointer context,XtPointer info)6554 static void phases_callback(Widget w, XtPointer context, XtPointer info)
6555 {
6556   bool val;
6557   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
6558   val = cb->set;
6559   in_set_fft_with_phases(val);
6560   graph_redisplay();
6561   for_each_chan_with_bool(chans_fft_with_phases, val);
6562   for_each_chan(calculate_fft);
6563 }
6564 
6565 
set_fft_with_phases(bool val)6566 void set_fft_with_phases(bool val)
6567 {
6568   in_set_fft_with_phases(val);
6569   for_each_chan_with_bool(chans_fft_with_phases, val);
6570   if (!(ss->graph_hook_active))
6571     for_each_chan(calculate_fft);
6572 }
6573 
6574 
6575 
6576 /* ---------------- window alpha parameter ---------------- */
6577 
alpha_drag_callback(Widget w,XtPointer context,XtPointer info)6578 static void alpha_drag_callback(Widget w, XtPointer context, XtPointer info)
6579 {
6580   char alpha_number_buffer[512]; /* 11 before gcc 7.1 */
6581   mus_float_t alpha;
6582 
6583   alpha = (((XmScrollBarCallbackStruct *)info)->value) / 90.0;
6584   in_set_fft_window_alpha(alpha);
6585   chans_field(FCP_ALPHA, alpha);
6586 
6587   snprintf(alpha_number_buffer, 512, "alpha:%.3f", alpha);
6588   set_label(alpha_number, alpha_number_buffer);
6589 
6590   if (fft_window_alpha_in_use(fft_window(ss)))
6591     {
6592       get_fft_window_data();
6593       graph_redisplay();
6594       if (transform_type(ss) == FOURIER)
6595 	for_each_chan(calculate_fft);
6596     }
6597 }
6598 
set_alpha_scale(mus_float_t val)6599 static void set_alpha_scale(mus_float_t val)
6600 {
6601   char alpha_number_buffer[512];
6602   XtVaSetValues(alpha_scale, XmNvalue, (int)(val * 90), NULL);
6603   snprintf(alpha_number_buffer, 512, "alpha:%.3f", val);
6604   set_label(alpha_number, alpha_number_buffer);
6605 }
6606 
6607 
set_fft_window_alpha(mus_float_t val)6608 void set_fft_window_alpha(mus_float_t val)
6609 {
6610   in_set_fft_window_alpha(val);
6611   chans_field(FCP_ALPHA, val);
6612   if (transform_dialog)
6613     {
6614       set_alpha_scale(val);
6615       get_fft_window_data();
6616       if (XtIsManaged(transform_dialog))
6617 	graph_redisplay();
6618     }
6619   if (!(ss->graph_hook_active))
6620     for_each_chan(calculate_fft);
6621 }
6622 
6623 
6624 
6625 /* ---------------- window beta parameter ---------------- */
6626 
beta_drag_callback(Widget w,XtPointer context,XtPointer info)6627 static void beta_drag_callback(Widget w, XtPointer context, XtPointer info)
6628 {
6629   char beta_number_buffer[12];
6630   mus_float_t beta;
6631 
6632   beta = (((XmScrollBarCallbackStruct *)info)->value) / 90.0;
6633   in_set_fft_window_beta(beta);
6634   chans_field(FCP_BETA, beta);
6635 
6636   snprintf(beta_number_buffer, 12, "beta: %.3f", beta);
6637   set_label(beta_number, beta_number_buffer);
6638 
6639   if (fft_window_beta_in_use(fft_window(ss)))
6640     {
6641       get_fft_window_data();
6642       graph_redisplay();
6643       if (transform_type(ss) == FOURIER)
6644 	for_each_chan(calculate_fft);
6645     }
6646 }
6647 
6648 
set_beta_scale(mus_float_t val)6649 static void set_beta_scale(mus_float_t val)
6650 {
6651   char beta_number_buffer[12];
6652   XtVaSetValues(beta_scale, XmNvalue, (int)(val * 90), NULL);
6653   snprintf(beta_number_buffer, 12, "beta: %.3f", val);
6654   set_label(beta_number, beta_number_buffer);
6655 }
6656 
6657 
set_fft_window_beta(mus_float_t val)6658 void set_fft_window_beta(mus_float_t val)
6659 {
6660   in_set_fft_window_beta(val);
6661   chans_field(FCP_BETA, val);
6662   if (transform_dialog)
6663     {
6664       set_beta_scale(val);
6665       get_fft_window_data();
6666       if (XtIsManaged(transform_dialog))
6667 	graph_redisplay();
6668     }
6669   if (!(ss->graph_hook_active))
6670     for_each_chan(calculate_fft);
6671 }
6672 
6673 
6674 
6675 /* ---------------- spectrum start/end ---------------- */
6676 
chans_spectrum_changed(chan_info * cp)6677 static void chans_spectrum_changed(chan_info *cp)
6678 {
6679   cp->fft_changed = FFT_CHANGE_LOCKED;
6680   update_graph(cp);
6681 }
6682 
set_spectrum_start_scale(mus_float_t val)6683 static void set_spectrum_start_scale(mus_float_t val)
6684 {
6685   char start_number_buffer[12];
6686   XtVaSetValues(start_scale, XmNvalue, (int)(val * 90), NULL);
6687   snprintf(start_number_buffer, 12, "start:%.3f", val);
6688   set_label(start_number, start_number_buffer);
6689 }
6690 
6691 
check_spectrum_start(mus_float_t end)6692 static void check_spectrum_start(mus_float_t end)
6693 {
6694   /* don't display chans, but do reset if necessary */
6695   if (spectrum_start(ss) > end)
6696     {
6697       in_set_spectrum_start(end);
6698       if (transform_dialog)
6699 	set_spectrum_start_scale(end);
6700       chans_field(FCP_SPECTRUM_START, end);
6701     }
6702 }
6703 
6704 static void check_spectrum_end(mus_float_t start);
6705 
set_spectrum_start(mus_float_t val)6706 void set_spectrum_start(mus_float_t val)
6707 {
6708   if (transform_dialog)
6709     set_spectrum_start_scale(val);
6710   in_set_spectrum_start(val);
6711   check_spectrum_end(val);
6712   chans_field(FCP_SPECTRUM_START, val);
6713   for_each_chan(chans_spectrum_changed);
6714 }
6715 
6716 
start_drag_callback(Widget w,XtPointer context,XtPointer info)6717 static void start_drag_callback(Widget w, XtPointer context, XtPointer info)
6718 {
6719   char start_number_buffer[12];
6720   mus_float_t start;
6721 
6722   start = (((XmScrollBarCallbackStruct *)info)->value) / 90.0;
6723   snprintf(start_number_buffer, 12, "start:%.3f", start);
6724   set_label(start_number, start_number_buffer);
6725 
6726   in_set_spectrum_start(start);
6727   check_spectrum_end(start);
6728   chans_field(FCP_SPECTRUM_START, start);
6729   for_each_chan(chans_spectrum_changed);
6730 }
6731 
6732 
set_spectrum_end_scale(mus_float_t val)6733 static void set_spectrum_end_scale(mus_float_t val)
6734 {
6735   char end_number_buffer[12];
6736   XtVaSetValues(end_scale, XmNvalue, (int)(val * 90), NULL);
6737   snprintf(end_number_buffer, 12, "end:  %.3f", val);
6738   set_label(end_number, end_number_buffer);
6739 }
6740 
check_spectrum_end(mus_float_t start)6741 static void check_spectrum_end(mus_float_t start)
6742 {
6743   /* don't display chans, but do reset if necessary */
6744   if (spectrum_end(ss) < start)
6745     {
6746       in_set_spectrum_end(start);
6747       if (transform_dialog)
6748 	set_spectrum_end_scale(start);
6749       chans_field(FCP_SPECTRUM_END, start);
6750     }
6751 }
6752 
6753 
set_spectrum_end(mus_float_t val)6754 void set_spectrum_end(mus_float_t val)
6755 {
6756   if (transform_dialog)
6757     set_spectrum_end_scale(val);
6758   in_set_spectrum_end(val);
6759   check_spectrum_start(val);
6760   chans_field(FCP_SPECTRUM_END, val);
6761   for_each_chan(chans_spectrum_changed);
6762 }
6763 
6764 
end_drag_callback(Widget w,XtPointer context,XtPointer info)6765 static void end_drag_callback(Widget w, XtPointer context, XtPointer info)
6766 {
6767   char end_number_buffer[12];
6768   mus_float_t end;
6769 
6770   end = (((XmScrollBarCallbackStruct *)info)->value) / 90.0;
6771   snprintf(end_number_buffer, 12, "end:  %.3f", end);
6772   set_label(end_number, end_number_buffer);
6773 
6774   in_set_spectrum_end(end);
6775   check_spectrum_start(end);
6776   chans_field(FCP_SPECTRUM_END, end);
6777   for_each_chan(chans_spectrum_changed);
6778 }
6779 
6780 
6781 
6782 /* ---------------- dialog buttons etc ---------------- */
6783 
graph_resize_callback(Widget w,XtPointer context,XtPointer info)6784 static void graph_resize_callback(Widget w, XtPointer context, XtPointer info)
6785 {
6786   graph_redisplay();
6787 }
6788 
6789 
dismiss_transform_callback(Widget w,XtPointer context,XtPointer info)6790 static void dismiss_transform_callback(Widget w, XtPointer context, XtPointer info)
6791 {
6792   if (XmGetFocusWidget(transform_dialog) == XmMessageBoxGetChild(transform_dialog, XmDIALOG_CANCEL_BUTTON))
6793     XtUnmanageChild(transform_dialog);
6794 }
6795 
6796 
color_orientation_callback(Widget w,XtPointer context,XtPointer info)6797 static void color_orientation_callback(Widget w, XtPointer context, XtPointer info)
6798 {
6799   make_color_orientation_dialog(true);
6800 }
6801 
6802 
help_transform_callback(Widget w,XtPointer context,XtPointer info)6803 static void help_transform_callback(Widget w, XtPointer context, XtPointer info)
6804 {
6805   transform_dialog_help();
6806 }
6807 
6808 
fft_blue_textfield_unfocus_callback(Widget w,XtPointer context,XtPointer info)6809 static void fft_blue_textfield_unfocus_callback(Widget w, XtPointer context, XtPointer info)
6810 {
6811   XtVaSetValues(w, XmNbackground, ss->lighter_blue, NULL);
6812   XtVaSetValues(w, XmNcursorPositionVisible, false, NULL);
6813 }
6814 
6815 
fft_blue_mouse_leave_text_callback(Widget w,XtPointer context,XEvent * event,Boolean * flag)6816 static void fft_blue_mouse_leave_text_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag)
6817 {
6818   XtVaSetValues(w, XmNbackground, ss->lighter_blue, NULL);
6819   XtVaSetValues(w, XmNcursorPositionVisible, false, NULL);
6820 }
6821 
6822 
fft_white_mouse_enter_text_callback(Widget w,XtPointer context,XEvent * event,Boolean * flag)6823 static void fft_white_mouse_enter_text_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag)
6824 {
6825   XtVaSetValues(w, XmNbackground, ss->text_focus_color, NULL);
6826   XtVaSetValues(w, XmNcursorPositionVisible, true, NULL);
6827 }
6828 
6829 
6830 
6831 /* ---------------- transform options dialog ---------------- */
6832 
6833 #define FRAME_BORDER_WIDTH 6
6834 
6835 static bool need_callback = true;
6836 
make_transform_dialog(bool managed)6837 Widget make_transform_dialog(bool managed)
6838 {
6839   if (!transform_dialog)
6840     {
6841       Widget mainform, type_frame, type_form, type_label, size_frame, size_form, size_label, display_frame, display_form, display_label;
6842       Widget window_frame, window_form, window_label, wavelet_frame, wavelet_form, wavelet_label, graph_frame, graph_form, gsep;
6843       Widget ab_form, ab_frame, ab_title, ab_sep;
6844       Widget se_form, se_frame, se_title, se_sep, ok_button;
6845       XmString s1;
6846       XmString xhelp, xgo_away, xtitle, bstr, xorient;
6847       Arg args[32];
6848       XmString sizes[NUM_TRANSFORM_SIZES];
6849       XmString wavelets[NUM_WAVELETS];
6850       XmString windows[MUS_NUM_FFT_WINDOWS];
6851       XGCValues gv;
6852       XtCallbackList n1, n2, n3, n4;
6853       int size_pos = 1;
6854       int n, i;
6855 
6856       for (i = 0; i < NUM_TRANSFORM_SIZES; i++)
6857 	if (transform_sizes[i] == transform_size(ss))
6858 	  {
6859 	    size_pos = i + 1;
6860 	    break;
6861 	  }
6862       xgo_away = XmStringCreateLocalized((char *)I_GO_AWAY); /* needed by template dialog */
6863       xhelp = XmStringCreateLocalized((char *)I_HELP);
6864       xtitle = XmStringCreateLocalized((char *)"Transform Options");
6865       xorient = XmStringCreateLocalized((char *)"Color/Orientation");
6866 
6867       n = 0;
6868       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
6869       XtSetArg(args[n], XmNcancelLabelString, xgo_away); n++;
6870       XtSetArg(args[n], XmNokLabelString, xorient); n++;
6871       XtSetArg(args[n], XmNhelpLabelString, xhelp); n++;
6872       XtSetArg(args[n], XmNautoUnmanage, false); n++;
6873       XtSetArg(args[n], XmNdialogTitle, xtitle); n++;
6874       XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
6875       XtSetArg(args[n], XmNnoResize, false); n++;
6876       XtSetArg(args[n], XmNtransient, false); n++;
6877       transform_dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"Transform Options", args, n);
6878       ok_button = XmMessageBoxGetChild(transform_dialog, XmDIALOG_OK_BUTTON);
6879 
6880       XtAddCallback(transform_dialog, XmNcancelCallback, dismiss_transform_callback, NULL);
6881       /* XtAddCallback(transform_dialog, XmNokCallback, color_orientation_callback, NULL); */ /* <cr> in dialog calls this! */
6882       XtAddCallback(ok_button, XmNactivateCallback, color_orientation_callback, NULL);
6883       XtAddCallback(transform_dialog, XmNhelpCallback, help_transform_callback, NULL);
6884       XmStringFree(xhelp);
6885       XmStringFree(xgo_away);
6886       XmStringFree(xtitle);
6887       XmStringFree(xorient);
6888 
6889       XtVaSetValues(XmMessageBoxGetChild(transform_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL);
6890       XtVaSetValues(XmMessageBoxGetChild(transform_dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL);
6891       XtVaSetValues(XmMessageBoxGetChild(transform_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL);
6892       XtVaSetValues(XmMessageBoxGetChild(transform_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL);
6893       XtVaSetValues(XmMessageBoxGetChild(transform_dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL);
6894       XtVaSetValues(XmMessageBoxGetChild(transform_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL);
6895 
6896       n = 0;
6897       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
6898       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
6899       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
6900       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
6901       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
6902       XtSetArg(args[n], XmNbottomWidget, XmMessageBoxGetChild(transform_dialog, XmDIALOG_SEPARATOR)); n++;
6903       mainform = XtCreateManagedWidget("mainform", xmFormWidgetClass, transform_dialog, args, n);
6904 
6905 
6906       n = 0;
6907       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
6908       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
6909       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
6910       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
6911       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
6912       XtSetArg(args[n], XmNallowResize, true); n++;
6913       XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++;
6914       XtSetArg(args[n], XmNshadowThickness, 2); n++;
6915       error_frame1 = XtCreateManagedWidget("error-frame", xmFrameWidgetClass, mainform, args, n);
6916 
6917       n = 0;
6918       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
6919       error_label1 = XtCreateManagedWidget("", xmLabelWidgetClass, error_frame1, args, n);
6920 
6921 
6922       /* now 7 or 8 boxes within the main box:
6923 
6924 	 type (list)    |  size (list)        |  display (button column)
6925 	 wavelet (list) |  window (list)      |  graph (fft?) of current window
6926          alpha/beta ------------------------  |
6927          start/end -------------------------  |
6928 
6929 	 each box has a frame, label, and contents
6930       */
6931 
6932       /* -------- SPECTRUM START/END -------- */
6933       n = 0;
6934       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
6935       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
6936       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
6937       XtSetArg(args[n], XmNrightPosition, 60); n++;
6938       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
6939       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
6940       XtSetArg(args[n], XmNborderWidth, FRAME_BORDER_WIDTH); n++;
6941       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
6942       se_frame = XtCreateManagedWidget("se-frame", xmFrameWidgetClass, mainform, args, n);
6943 
6944       n = 0;
6945       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
6946       n = attach_all_sides(args, n);
6947       se_form = XtCreateManagedWidget("se-form", xmFormWidgetClass, se_frame, args, n);
6948       /* needed because XmFrame only accepts one child */
6949 
6950       n = 0;
6951       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
6952       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
6953       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
6954       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
6955       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
6956       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
6957       se_title = XtCreateManagedWidget("spectrum start/end", xmLabelWidgetClass, se_form, args, n);
6958 
6959       n = 0;
6960       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
6961       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
6962       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
6963       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
6964       XtSetArg(args[n], XmNtopWidget, se_title); n++;
6965       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
6966       XtSetArg(args[n], XmNseparatorType, XmSHADOW_ETCHED_IN); n++;
6967       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
6968       se_sep = XtCreateManagedWidget("se_sep", xmSeparatorWidgetClass, se_form, args, n);
6969 
6970       n = 0;
6971       s1 = XmStringCreateLocalized((char *)"start:0.0  ");
6972       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
6973       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
6974       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
6975       XtSetArg(args[n], XmNtopWidget, se_sep); n++;
6976       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
6977       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
6978       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
6979       XtSetArg(args[n], XmNlabelString, s1); n++;
6980       XtSetArg(args[n], XmNrecomputeSize, false); n++;
6981       XtSetArg(args[n], XmNshadowThickness, 0); n++;
6982       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
6983       start_number = XtCreateManagedWidget("start-number", xmLabelWidgetClass, se_form, args, n);
6984       XmStringFree(s1);
6985 
6986       n = 0;
6987       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
6988       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
6989       XtSetArg(args[n], XmNtopWidget, start_number); n++;
6990       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
6991       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
6992       XtSetArg(args[n], XmNleftWidget, start_number); n++;
6993       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
6994       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
6995       XtSetArg(args[n], XmNmaximum, 100); n++;
6996       XtSetArg(args[n], XmNvalue, 0); n++;
6997       XtSetArg(args[n], XmNheight, 16); n++;
6998       XtSetArg(args[n], XmNdragCallback, n3 = make_callback_list(start_drag_callback, NULL)); n++;
6999       XtSetArg(args[n], XmNvalueChangedCallback, n3); n++;
7000       start_scale = XtCreateManagedWidget("start-scale", xmScrollBarWidgetClass, se_form, args, n);
7001 
7002       n = 0;
7003       s1 = XmStringCreateLocalized((char *)"end:  1.0  ");
7004       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7005       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
7006       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7007       XtSetArg(args[n], XmNtopWidget, start_number); n++;
7008       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
7009       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7010       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
7011       XtSetArg(args[n], XmNlabelString, s1); n++;
7012       XtSetArg(args[n], XmNrecomputeSize, false); n++;
7013       XtSetArg(args[n], XmNshadowThickness, 0); n++;
7014       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
7015       end_number = XtCreateManagedWidget("end-number", xmLabelWidgetClass, se_form, args, n);
7016       XmStringFree(s1);
7017 
7018       n = 0;
7019       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7020       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
7021       XtSetArg(args[n], XmNtopWidget, end_number); n++;
7022       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7023       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
7024       XtSetArg(args[n], XmNleftWidget, end_number); n++;
7025       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7026       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
7027       XtSetArg(args[n], XmNmaximum, 100); n++;
7028       XtSetArg(args[n], XmNvalue, 90); n++;
7029       XtSetArg(args[n], XmNheight, 16); n++;
7030       XtSetArg(args[n], XmNdragCallback, n4 = make_callback_list(end_drag_callback, NULL)); n++;
7031       XtSetArg(args[n], XmNvalueChangedCallback, n4); n++;
7032       end_scale = XtCreateManagedWidget("end-scale", xmScrollBarWidgetClass, se_form, args, n);
7033 
7034 
7035 
7036       /* -------- WINDOW ALPHA/BETA -------- */
7037       n = 0;
7038       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7039       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7040       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
7041       XtSetArg(args[n], XmNrightPosition, 60); n++;
7042       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
7043       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
7044       XtSetArg(args[n], XmNbottomWidget, se_frame); n++;
7045       XtSetArg(args[n], XmNborderWidth, FRAME_BORDER_WIDTH); n++;
7046       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
7047       ab_frame = XtCreateManagedWidget("ab-frame", xmFrameWidgetClass, mainform, args, n);
7048 
7049       n = 0;
7050       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7051       n = attach_all_sides(args, n);
7052       ab_form = XtCreateManagedWidget("ab-form", xmFormWidgetClass, ab_frame, args, n);
7053       /* needed because XmFrame only accepts one child */
7054 
7055       n = 0;
7056       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
7057       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7058       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7059       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
7060       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7061       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
7062       ab_title = XtCreateManagedWidget("window parameter", xmLabelWidgetClass, ab_form, args, n);
7063 
7064       n = 0;
7065       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7066       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7067       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7068       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7069       XtSetArg(args[n], XmNtopWidget, ab_title); n++;
7070       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7071       XtSetArg(args[n], XmNseparatorType, XmSHADOW_ETCHED_IN); n++;
7072       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
7073       ab_sep = XtCreateManagedWidget("ab_sep", xmSeparatorWidgetClass, ab_form, args, n);
7074 
7075       n = 0;
7076       s1 = XmStringCreateLocalized((char *)"alpha:0.0  ");
7077       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7078       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
7079       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7080       XtSetArg(args[n], XmNtopWidget, ab_sep); n++;
7081       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7082       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7083       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
7084       XtSetArg(args[n], XmNlabelString, s1); n++;
7085       XtSetArg(args[n], XmNrecomputeSize, false); n++;
7086       XtSetArg(args[n], XmNshadowThickness, 0); n++;
7087       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
7088       alpha_number = XtCreateManagedWidget("alpha-number", xmLabelWidgetClass, ab_form, args, n);
7089       XmStringFree(s1);
7090 
7091       n = 0;
7092       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7093       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
7094       XtSetArg(args[n], XmNtopWidget, alpha_number); n++;
7095       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7096       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
7097       XtSetArg(args[n], XmNleftWidget, alpha_number); n++;
7098       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7099       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
7100       XtSetArg(args[n], XmNmaximum, 100); n++;
7101       XtSetArg(args[n], XmNvalue, 0); n++;
7102       XtSetArg(args[n], XmNheight, 16); n++;
7103 
7104       XtSetArg(args[n], XmNdragCallback, n1 = make_callback_list(alpha_drag_callback, NULL)); n++;
7105       XtSetArg(args[n], XmNvalueChangedCallback, n1); n++;
7106       alpha_scale = XtCreateManagedWidget("alpha-scale", xmScrollBarWidgetClass, ab_form, args, n);
7107 
7108 
7109       n = 0;
7110       s1 = XmStringCreateLocalized((char *)"beta: 0.0  ");
7111       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7112       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
7113       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7114       XtSetArg(args[n], XmNtopWidget, alpha_number); n++;
7115       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
7116       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7117       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
7118       XtSetArg(args[n], XmNlabelString, s1); n++;
7119       XtSetArg(args[n], XmNrecomputeSize, false); n++;
7120       XtSetArg(args[n], XmNshadowThickness, 0); n++;
7121       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
7122       beta_number = XtCreateManagedWidget("beta-number", xmLabelWidgetClass, ab_form, args, n);
7123       XmStringFree(s1);
7124 
7125       n = 0;
7126       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7127       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
7128       XtSetArg(args[n], XmNtopWidget, beta_number); n++;
7129       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7130       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
7131       XtSetArg(args[n], XmNleftWidget, beta_number); n++;
7132       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7133       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
7134       XtSetArg(args[n], XmNmaximum, 100); n++;
7135       XtSetArg(args[n], XmNvalue, 0); n++;
7136       XtSetArg(args[n], XmNheight, 16); n++;
7137 
7138       XtSetArg(args[n], XmNdragCallback, n2 = make_callback_list(beta_drag_callback, NULL)); n++;
7139       XtSetArg(args[n], XmNvalueChangedCallback, n2); n++;
7140       beta_scale = XtCreateManagedWidget("beta-scale", xmScrollBarWidgetClass, ab_form, args, n);
7141 
7142 
7143       /* -------- WINDOW -------- */
7144       n = 0;
7145       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7146       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7147       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
7148       XtSetArg(args[n], XmNrightPosition, 30); n++;
7149       XtSetArg(args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
7150       XtSetArg(args[n], XmNtopPosition, 35); n++;
7151       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
7152       XtSetArg(args[n], XmNbottomWidget, ab_frame); n++;
7153       XtSetArg(args[n], XmNborderWidth, FRAME_BORDER_WIDTH); n++;
7154       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
7155       window_frame = XtCreateManagedWidget("window-frame", xmFrameWidgetClass, mainform, args, n);
7156 
7157       n = 0;
7158       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7159       n = attach_all_sides(args, n);
7160       window_form = XtCreateManagedWidget("window-form", xmFormWidgetClass, window_frame, args, n);
7161 
7162       n = 0;
7163       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
7164       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7165       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7166       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
7167       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7168       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
7169       window_label = XtCreateManagedWidget("window", xmLabelWidgetClass, window_form, args, n);
7170 
7171       n = 0;
7172       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7173       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7174       XtSetArg(args[n], XmNbottomWidget, XmATTACH_FORM); n++;
7175       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7176       XtSetArg(args[n], XmNtopWidget, window_label); n++;
7177       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7178       XtSetArg(args[n], XmNtopItemPosition, ((int)fft_window(ss) > 2) ? ((int)fft_window(ss) - 1) : ((int)fft_window(ss) + 1)); n++;
7179       window_list = XmCreateScrolledList(window_form, (char *)"window-list", args, n);
7180 
7181       XtVaSetValues(window_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL);
7182       for (i = 0; i < MUS_NUM_FFT_WINDOWS; i++)
7183 	windows[i] = XmStringCreateLocalized((char *)mus_fft_window_name((mus_fft_window_t)i));
7184 
7185       XtVaSetValues(window_list,
7186 		    XmNitems, windows,
7187 		    XmNitemCount, MUS_NUM_FFT_WINDOWS,
7188 		    XmNvisibleItemCount, 8,
7189 		    NULL);
7190       for (i = 0; i < MUS_NUM_FFT_WINDOWS; i++)
7191 	XmStringFree(windows[i]);
7192 
7193       XtManageChild(window_list);
7194       XtAddCallback(window_list, XmNbrowseSelectionCallback, window_browse_callback, NULL);
7195 
7196 
7197       /* -------- WAVELET -------- */
7198       n = 0;
7199       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7200       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
7201       XtSetArg(args[n], XmNleftWidget, window_frame); n++;
7202 
7203       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
7204       XtSetArg(args[n], XmNrightPosition, 60); n++;
7205       XtSetArg(args[n], XmNtopAttachment, XmATTACH_POSITION); n++;
7206       XtSetArg(args[n], XmNtopPosition, 35); n++;
7207       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
7208       XtSetArg(args[n], XmNbottomWidget, ab_frame); n++;
7209       XtSetArg(args[n], XmNborderWidth, FRAME_BORDER_WIDTH); n++;
7210       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
7211       wavelet_frame = XtCreateManagedWidget("wavelet-frame", xmFrameWidgetClass, mainform, args, n);
7212 
7213       n = 0;
7214       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7215       n = attach_all_sides(args, n);
7216       wavelet_form = XtCreateManagedWidget("wavelet-form", xmFormWidgetClass, wavelet_frame, args, n);
7217 
7218       n = 0;
7219       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
7220       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7221       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7222       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
7223       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7224       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
7225       wavelet_label = XtCreateManagedWidget("wavelet", xmLabelWidgetClass, wavelet_form, args, n);
7226 
7227       n = 0;
7228       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7229       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7230       XtSetArg(args[n], XmNbottomWidget, XmATTACH_FORM); n++;
7231       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7232       XtSetArg(args[n], XmNtopWidget, wavelet_label); n++;
7233       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7234       wavelet_list = XmCreateScrolledList(wavelet_form, (char *)"wavelet-list", args, n);
7235 
7236       XtVaSetValues(wavelet_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL);
7237       for (i = 0; i < NUM_WAVELETS; i++)
7238 	wavelets[i] = XmStringCreateLocalized((char *)wavelet_name(i));
7239 
7240       XtVaSetValues(wavelet_list,
7241 		    XmNitems, wavelets,
7242 		    XmNitemCount, NUM_WAVELETS,
7243 		    XmNvisibleItemCount, 8,
7244 		    NULL);
7245       for (i = 0; i < NUM_WAVELETS; i++)
7246 	XmStringFree(wavelets[i]);
7247 
7248       XtManageChild(wavelet_list);
7249       XtAddCallback(wavelet_list, XmNbrowseSelectionCallback, wavelet_browse_callback, NULL);
7250 
7251 
7252       /* -------- TRANSFORM TYPE -------- */
7253       n = 0;
7254       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7255       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7256       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
7257       XtSetArg(args[n], XmNrightPosition, 30); n++;
7258       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
7259       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_POSITION); n++;
7260       XtSetArg(args[n], XmNbottomPosition, 35); n++;
7261       XtSetArg(args[n], XmNborderWidth, FRAME_BORDER_WIDTH); n++;
7262       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
7263       type_frame = XtCreateManagedWidget("type-frame", xmFrameWidgetClass, mainform, args, n);
7264 
7265       n = 0;
7266       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7267       n = attach_all_sides(args, n);
7268       type_form = XtCreateManagedWidget("type-form", xmFormWidgetClass, type_frame, args, n);
7269       /* needed because XmFrame only accepts one child */
7270 
7271       n = 0;
7272       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
7273       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7274       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7275       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
7276       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7277       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
7278       type_label = XtCreateManagedWidget("type", xmLabelWidgetClass, type_form, args, n);
7279 
7280       n = 0;
7281       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7282       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7283       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
7284       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7285       XtSetArg(args[n], XmNtopWidget, type_label); n++;
7286       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7287       type_list = XmCreateScrolledList(type_form, (char *)"type-list", args, n);
7288 
7289       XtVaSetValues(type_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL);
7290       make_transform_type_list();
7291 
7292       XtManageChild(type_list);
7293       XtAddCallback(type_list, XmNbrowseSelectionCallback, transform_type_browse_callback, NULL);
7294 
7295 
7296       /* -------- SIZE -------- */
7297       n = 0;
7298       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7299       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
7300       XtSetArg(args[n], XmNleftWidget, type_frame); n++;
7301       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
7302       XtSetArg(args[n], XmNrightPosition, 60); n++;
7303       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
7304       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
7305       XtSetArg(args[n], XmNbottomWidget, type_frame); n++;
7306       XtSetArg(args[n], XmNborderWidth, FRAME_BORDER_WIDTH); n++;
7307       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
7308       size_frame = XtCreateManagedWidget("size-frame", xmFrameWidgetClass, mainform, args, n);
7309 
7310       n = 0;
7311       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7312       n = attach_all_sides(args, n);
7313       size_form = XtCreateManagedWidget("size-form", xmFormWidgetClass, size_frame, args, n);
7314 
7315       n = 0;
7316       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
7317       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7318       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7319       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
7320       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7321       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
7322       size_label = XtCreateManagedWidget("size", xmLabelWidgetClass, size_form, args, n);
7323 
7324       n = 0;
7325       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7326       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7327       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
7328       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7329       XtSetArg(args[n], XmNtopWidget, size_label); n++;
7330       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7331       XtSetArg(args[n], XmNtopItemPosition, (size_pos > 2) ? (size_pos - 2) : size_pos); n++;
7332       size_list = XmCreateScrolledList(size_form, (char *)"size-list", args, n);
7333 
7334       XtVaSetValues(size_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL);
7335       for (i = 0; i < NUM_TRANSFORM_SIZES; i++)
7336 	sizes[i] = XmStringCreateLocalized((char *)transform_size_names[i]);
7337 
7338       XtVaSetValues(size_list,
7339 		    XmNitems, sizes,
7340 		    XmNitemCount, NUM_TRANSFORM_SIZES,
7341 		    XmNvisibleItemCount, 6,
7342 		    NULL);
7343       for (i = 0; i < NUM_TRANSFORM_SIZES; i++)
7344 	XmStringFree(sizes[i]);
7345 
7346       XtManageChild(size_list);
7347       XtAddCallback(size_list, XmNbrowseSelectionCallback, size_browse_callback, NULL);
7348 
7349 
7350       /* -------- DISPLAY BOX BUTTONS -------- */
7351       n = 0;
7352       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7353       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
7354       XtSetArg(args[n], XmNleftWidget, size_frame); n++;
7355       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7356       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
7357       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7358       XtSetArg(args[n], XmNborderWidth, FRAME_BORDER_WIDTH); n++;
7359       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
7360       display_frame = XtCreateManagedWidget("display-frame", xmFrameWidgetClass, mainform, args, n);
7361 
7362       n = 0;
7363       XtSetArg(args[n], XmNbackground, ss->zoom_color); n++;
7364       n = attach_all_sides(args, n);
7365       display_form = XtCreateManagedWidget("display-form", xmFormWidgetClass, display_frame, args, n);
7366 
7367       n = 0;
7368       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
7369       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7370       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7371       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
7372       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7373       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
7374       display_label = XtCreateManagedWidget("display", xmLabelWidgetClass, display_form, args, n);
7375 
7376       n = 0;
7377       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
7378       XtSetArg(args[n], XmNselectColor, ss->red); n++;
7379       bstr = XmStringCreateLocalized((char *)"single transform");
7380       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7381       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7382       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7383       XtSetArg(args[n], XmNtopWidget, display_label); n++;
7384       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7385       XtSetArg(args[n], XmNlabelString, bstr); n++;
7386       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
7387       XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++;
7388       normo_button = make_togglebutton_widget("normo-button", display_form, args, n);
7389       XtAddCallback(normo_button, XmNdisarmCallback, graph_transform_once_callback, NULL);
7390       XmStringFree(bstr);
7391 
7392       n = 0;
7393       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
7394       XtSetArg(args[n], XmNselectColor, ss->red); n++;
7395       bstr = XmStringCreateLocalized((char *)"sonogram");
7396       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7397       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7398       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7399       XtSetArg(args[n], XmNtopWidget, normo_button); n++;
7400       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7401       XtSetArg(args[n], XmNlabelString, bstr); n++;
7402       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
7403       XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++;
7404       sono_button = make_togglebutton_widget("sono-button", display_form, args, n);
7405       XtAddCallback(sono_button, XmNdisarmCallback, sonogram_callback, NULL);
7406       XmStringFree(bstr);
7407 
7408       n = 0;
7409       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
7410       XtSetArg(args[n], XmNselectColor, ss->red); n++;
7411       bstr = XmStringCreateLocalized((char *)"spectrogram");
7412       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7413       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7414       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7415       XtSetArg(args[n], XmNtopWidget, sono_button); n++;
7416       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7417       XtSetArg(args[n], XmNlabelString, bstr); n++;
7418       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
7419       XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++;
7420       spectro_button = make_togglebutton_widget("spectro-button", display_form, args, n);
7421       XtAddCallback(spectro_button, XmNdisarmCallback, spectrogram_callback, NULL);
7422       XmStringFree(bstr);
7423 
7424       n = 0;
7425       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
7426       XtSetArg(args[n], XmNselectColor, ss->red); n++;
7427       bstr = XmStringCreateLocalized((char *)"peaks");
7428       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7429       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
7430       XtSetArg(args[n], XmNrightPosition, 67); n++;
7431       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7432       XtSetArg(args[n], XmNtopWidget, spectro_button); n++;
7433       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7434       XtSetArg(args[n], XmNlabelString, bstr); n++;
7435       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
7436       peaks_button = make_togglebutton_widget("peaks-button", display_form, args, n);
7437       XtAddCallback(peaks_button, XmNvalueChangedCallback, peaks_callback, NULL);
7438       XmStringFree(bstr);
7439 
7440       n = 0;
7441       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
7442       XtSetArg(args[n], XmNresizeWidth, false); n++;
7443       XtSetArg(args[n], XmNcolumns, 6); n++;
7444       XtSetArg(args[n], XmNrecomputeSize, false); n++;
7445       /* XtSetArg(args[n], XmNmarginHeight, 1); n++; */
7446       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
7447       XtSetArg(args[n], XmNleftWidget, peaks_button); n++;
7448       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7449       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
7450       XtSetArg(args[n], XmNtopWidget, peaks_button); n++;
7451       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
7452       XtSetArg(args[n], XmNbottomWidget, peaks_button); n++;
7453       XtSetArg(args[n], XmNborderWidth, 0); n++;
7454       XtSetArg(args[n], XmNshadowThickness, 0); n++;
7455       peak_txt = make_textfield_widget("max-peaks", display_form, args, n, ACTIVATABLE, NO_COMPLETER);
7456       XtRemoveCallback(peak_txt, XmNlosingFocusCallback, textfield_unfocus_callback, NULL);
7457       XtAddCallback(peak_txt, XmNlosingFocusCallback, fft_blue_textfield_unfocus_callback, NULL);
7458       XtAddEventHandler(peak_txt, LeaveWindowMask, false, fft_blue_mouse_leave_text_callback, NULL);
7459       XtAddEventHandler(peak_txt, EnterWindowMask, false, fft_white_mouse_enter_text_callback, NULL);
7460       widget_int_to_text(peak_txt, max_transform_peaks(ss));
7461       XtAddCallback(peak_txt, XmNactivateCallback, peaks_activate_callback, NULL);
7462 
7463       n = 0;
7464       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
7465       XtSetArg(args[n], XmNselectColor, ss->red); n++;
7466       bstr = XmStringCreateLocalized((char *)"dB");
7467       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7468       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
7469       XtSetArg(args[n], XmNrightPosition, 67); n++;
7470       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7471       XtSetArg(args[n], XmNtopWidget, peaks_button); n++;
7472       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7473       XtSetArg(args[n], XmNlabelString, bstr); n++;
7474       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
7475       db_button = make_togglebutton_widget("db-button", display_form, args, n);
7476       XtAddCallback(db_button, XmNvalueChangedCallback, fft_db_callback, NULL);
7477       XmStringFree(bstr);
7478 
7479       n = 0;
7480       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
7481       XtSetArg(args[n], XmNresizeWidth, false); n++;
7482       XtSetArg(args[n], XmNcolumns, 6); n++;
7483       XtSetArg(args[n], XmNrecomputeSize, false); n++;
7484       /* XtSetArg(args[n], XmNmarginHeight, 1); n++; */
7485       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
7486       XtSetArg(args[n], XmNleftWidget, db_button); n++;
7487       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7488       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
7489       XtSetArg(args[n], XmNtopWidget, db_button); n++;
7490       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
7491       XtSetArg(args[n], XmNbottomWidget, db_button); n++;
7492       XtSetArg(args[n], XmNborderWidth, 0); n++;
7493       XtSetArg(args[n], XmNshadowThickness, 0); n++;
7494       db_txt = make_textfield_widget("db", display_form, args, n, ACTIVATABLE, NO_COMPLETER);
7495       XtRemoveCallback(db_txt, XmNlosingFocusCallback, textfield_unfocus_callback, NULL);
7496       XtAddCallback(db_txt, XmNlosingFocusCallback, fft_blue_textfield_unfocus_callback, NULL);
7497       XtAddEventHandler(db_txt, LeaveWindowMask, false, fft_blue_mouse_leave_text_callback, NULL);
7498       XtAddEventHandler(db_txt, EnterWindowMask, false, fft_white_mouse_enter_text_callback, NULL);
7499       widget_float_to_text(db_txt, min_dB(ss));
7500       XtAddCallback(db_txt, XmNactivateCallback, min_db_activate_callback, NULL);
7501 
7502       n = 0;
7503       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
7504       XtSetArg(args[n], XmNselectColor, ss->red); n++;
7505       bstr = XmStringCreateLocalized((char *)"log freq");
7506       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7507       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
7508       XtSetArg(args[n], XmNrightPosition, 67); n++;
7509       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7510       XtSetArg(args[n], XmNtopWidget, db_button); n++;
7511       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7512       XtSetArg(args[n], XmNlabelString, bstr); n++;
7513       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
7514       logfreq_button = make_togglebutton_widget("logfreq-button", display_form, args, n);
7515       XtAddCallback(logfreq_button, XmNvalueChangedCallback, logfreq_callback, NULL);
7516       XmStringFree(bstr);
7517 
7518       n = 0;
7519       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
7520       XtSetArg(args[n], XmNresizeWidth, false); n++;
7521       XtSetArg(args[n], XmNcolumns, 6); n++;
7522       XtSetArg(args[n], XmNrecomputeSize, false); n++;
7523       /* XtSetArg(args[n], XmNmarginHeight, 1); n++; */
7524       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
7525       XtSetArg(args[n], XmNleftWidget, logfreq_button); n++;
7526       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7527       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
7528       XtSetArg(args[n], XmNtopWidget, logfreq_button); n++;
7529       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
7530       XtSetArg(args[n], XmNbottomWidget, logfreq_button); n++;
7531       XtSetArg(args[n], XmNborderWidth, 0); n++;
7532       XtSetArg(args[n], XmNshadowThickness, 0); n++;
7533       freq_base_txt = make_textfield_widget("lfb", display_form, args, n, ACTIVATABLE, NO_COMPLETER);
7534       XtRemoveCallback(freq_base_txt, XmNlosingFocusCallback, textfield_unfocus_callback, NULL);
7535       XtAddCallback(freq_base_txt, XmNlosingFocusCallback, fft_blue_textfield_unfocus_callback, NULL);
7536       XtAddEventHandler(freq_base_txt, LeaveWindowMask, false, fft_blue_mouse_leave_text_callback, NULL);
7537       XtAddEventHandler(freq_base_txt, EnterWindowMask, false, fft_white_mouse_enter_text_callback, NULL);
7538       widget_float_to_text(freq_base_txt, log_freq_start(ss));
7539       XtAddCallback(freq_base_txt, XmNactivateCallback, log_freq_start_activate_callback, NULL);
7540 
7541       n = 0;
7542       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
7543       XtSetArg(args[n], XmNselectColor, ss->red); n++;
7544       bstr = XmStringCreateLocalized((char *)"normalize");
7545       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7546       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7547       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7548       XtSetArg(args[n], XmNtopWidget, logfreq_button); n++;
7549       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7550       XtSetArg(args[n], XmNlabelString, bstr); n++;
7551       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
7552       normalize_button = make_togglebutton_widget("normalize-button", display_form, args, n);
7553       XtAddCallback(normalize_button, XmNvalueChangedCallback, normalize_callback, NULL);
7554       XmStringFree(bstr);
7555 
7556       n = 0;
7557       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
7558       XtSetArg(args[n], XmNselectColor, ss->red); n++;
7559       bstr = XmStringCreateLocalized((char *)"selection");
7560       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7561       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7562       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7563       XtSetArg(args[n], XmNtopWidget, normalize_button); n++;
7564       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7565       XtSetArg(args[n], XmNlabelString, bstr); n++;
7566       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
7567       selection_button1 = make_togglebutton_widget("selection-button", display_form, args, n);
7568       XtAddCallback(selection_button1, XmNvalueChangedCallback, selection_callback, NULL);
7569       XmStringFree(bstr);
7570 
7571 
7572       n = 0;
7573       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
7574       XtSetArg(args[n], XmNselectColor, ss->red); n++;
7575       bstr = XmStringCreateLocalized((char *)"with phases");
7576       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7577       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7578       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7579       XtSetArg(args[n], XmNtopWidget, selection_button1); n++;
7580       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
7581       XtSetArg(args[n], XmNlabelString, bstr); n++;
7582       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
7583       phases_button = make_togglebutton_widget("phases-button", display_form, args, n);
7584       XtAddCallback(phases_button, XmNvalueChangedCallback, phases_callback, NULL);
7585       XmStringFree(bstr);
7586 
7587 
7588 
7589       /* -------- GRAPH -------- */
7590       n = 0;
7591       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7592       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
7593       XtSetArg(args[n], XmNleftWidget, wavelet_frame); n++;
7594       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7595       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7596       XtSetArg(args[n], XmNtopWidget, display_frame); n++;
7597       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
7598       XtSetArg(args[n], XmNborderWidth, FRAME_BORDER_WIDTH); n++;
7599       XtSetArg(args[n], XmNborderColor, ss->basic_color); n++;
7600       graph_frame = XtCreateManagedWidget("graph-frame", xmFrameWidgetClass, mainform, args, n);
7601 
7602       n = 0;
7603       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7604       n = attach_all_sides(args, n);
7605       graph_form = XtCreateManagedWidget("graph-form", xmFormWidgetClass, graph_frame, args, n);
7606 
7607       n = 0;
7608       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
7609       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7610       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7611       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
7612       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7613       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
7614       graph_label = XtCreateManagedWidget("window", xmLabelWidgetClass, graph_form, args, n);
7615       /* label should change according to what is being displayed */
7616 
7617       n = 0;
7618       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
7619       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7620       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7621       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7622       XtSetArg(args[n], XmNtopWidget, graph_label); n++;
7623       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
7624       XtSetArg(args[n], XmNseparatorType, XmSHADOW_ETCHED_IN); n++;
7625       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
7626       gsep = XtCreateManagedWidget("gsep", xmSeparatorWidgetClass, graph_form, args, n);
7627 
7628       n = 0;
7629       XtSetArg(args[n], XmNbackground, ss->graph_color); n++;
7630       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
7631       XtSetArg(args[n], XmNtopWidget, gsep); n++;
7632       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
7633       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
7634       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
7635       XtSetArg(args[n], XmNallowResize, true); n++;
7636       graph_drawer = XtCreateManagedWidget("graph-drawer", xmDrawingAreaWidgetClass, graph_form, args, n);
7637 
7638       gv.function = GXcopy;
7639       XtVaGetValues(graph_drawer, XmNbackground, &gv.background, XmNforeground, &gv.foreground, NULL);
7640       gc2 = XtGetGC(graph_drawer, GCForeground | GCFunction, &gv);
7641 
7642       gv.foreground = ss->enved_waveform_color;
7643       fgc = XtGetGC(graph_drawer, GCForeground | GCFunction, &gv);
7644 
7645       XmToggleButtonSetState(normo_button, (Boolean)(transform_graph_type(ss) == GRAPH_ONCE), false);
7646       XmToggleButtonSetState(sono_button, (Boolean)(transform_graph_type(ss) == GRAPH_AS_SONOGRAM), false);
7647       XmToggleButtonSetState(spectro_button, (Boolean)(transform_graph_type(ss) == GRAPH_AS_SPECTROGRAM), false);
7648       XmToggleButtonSetState(peaks_button, (Boolean)(show_transform_peaks(ss)), false);
7649       XmToggleButtonSetState(db_button, (Boolean)(fft_log_magnitude(ss)), false);
7650       XmToggleButtonSetState(logfreq_button, (Boolean)(fft_log_frequency(ss)), false);
7651       XmToggleButtonSetState(normalize_button, (Boolean)(transform_normalization(ss) != DONT_NORMALIZE), false);
7652       XmToggleButtonSetState(selection_button1, (Boolean)(show_selection_transform(ss)), false);
7653       XmToggleButtonSetState(phases_button, (Boolean)(fft_with_phases(ss)), false);
7654 
7655       /* select current list choices */
7656       /* display current windowing choice unless wavelet in force */
7657 
7658       XmListSelectPos(type_list, transform_type_to_position(transform_type(ss)) + 1, false);
7659       XmListSelectPos(wavelet_list, wavelet_type(ss) + 1, false);
7660       XmListSelectPos(size_list, size_pos, false);
7661       XmListSelectPos(window_list, (int)fft_window(ss) + 1, false);
7662 
7663       if (spectrum_start(ss) != 0.0) set_spectrum_start_scale(spectrum_start(ss));
7664       if (spectrum_end(ss) != 1.0) set_spectrum_end_scale(spectrum_end(ss));
7665       if (fft_window_alpha(ss) != 0.0) set_alpha_scale(fft_window_alpha(ss));
7666       if (fft_window_beta(ss) != 0.0) set_beta_scale(fft_window_beta(ss));
7667 
7668       highlight_alpha_beta_scales(fft_window(ss));
7669 
7670       free(n1);
7671       free(n2);
7672       free(n3);
7673       free(n4);
7674 
7675       set_dialog_widget(TRANSFORM_DIALOG, transform_dialog);
7676 
7677       XtUnmanageChild(error_frame1);
7678     }
7679   else
7680     {
7681       if (managed)
7682 	raise_dialog(transform_dialog);
7683     }
7684   if (managed)
7685     {
7686       if (!XtIsManaged(transform_dialog))
7687 	XtManageChild(transform_dialog);
7688     }
7689   else XtUnmanageChild(transform_dialog);
7690   if ((need_callback) && (XtIsManaged(transform_dialog)))
7691     {
7692       set_label(graph_label, mus_fft_window_name(fft_window(ss)));
7693       get_fft_window_data();
7694       XtAddCallback(graph_drawer, XmNresizeCallback, graph_resize_callback, NULL);
7695       XtAddCallback(graph_drawer, XmNexposeCallback, graph_resize_callback, NULL);
7696       need_callback = false;
7697     }
7698   return(transform_dialog);
7699 }
7700 
7701 
transform_dialog_is_active(void)7702 bool transform_dialog_is_active(void)
7703 {
7704   return((transform_dialog) &&
7705 	 (XtIsManaged(transform_dialog)));
7706 }
7707 
7708 
7709 /* -------- region browser -------- */
7710 
7711 typedef struct {
7712   Widget rw, nm, pl;
7713   int pos;
7714 } regrow;
7715 
7716 static Widget region_dialog = NULL, region_list, region_grf;
7717 static regrow **region_rows = NULL;
7718 static int region_rows_size = 0;
7719 static snd_info *rsp = NULL;
7720 static int current_region = -1;
7721 static Widget reg_srtxt, reg_lentxt, reg_chntxt, reg_maxtxt;
7722 static Widget region_ww = NULL;
7723 static Widget mix_button = NULL, save_as_button = NULL, insert_button = NULL;
7724 static regrow *region_row(int n);
7725 
7726 
set_current_region(int rg)7727 static void set_current_region(int rg)
7728 {
7729   bool reg_ok = false;
7730   current_region = rg;
7731   reflect_region_in_save_as_dialog();
7732   if (rg >= 0)
7733     reg_ok = region_ok(region_list_position_to_id(rg));
7734   if (save_as_button) XtSetSensitive(save_as_button, reg_ok);
7735   if (mix_button) XtSetSensitive(mix_button, reg_ok);
7736   if (insert_button) XtSetSensitive(insert_button, reg_ok);
7737 }
7738 
7739 
reflect_regions_in_region_browser(void)7740 void reflect_regions_in_region_browser(void)
7741 {
7742   if (rsp)
7743     {
7744       uint32_t i;
7745       rsp->active = true;
7746       if (rsp->chans)
7747 	for (i = 0; i < rsp->nchans; i++)
7748 	  rsp->chans[i]->active = CHANNEL_HAS_AXES;
7749     }
7750 }
7751 
7752 
reflect_no_regions_in_region_browser(void)7753 void reflect_no_regions_in_region_browser(void)
7754 {
7755   if (rsp)
7756     {
7757       uint32_t i;
7758       rsp->active = false;
7759       if (rsp->chans)
7760 	for (i = 0; i < rsp->nchans; i++)
7761 	  rsp->chans[i]->active = CHANNEL_INACTIVE;
7762     }
7763 }
7764 
7765 
region_update_graph(chan_info * cp)7766 static void region_update_graph(chan_info *cp)
7767 {
7768   if (current_region == -1) return;
7769   rsp->nchans = region_chans(region_list_position_to_id(current_region));
7770   if (rsp->nchans == 0) return;
7771   update_graph(cp);
7772   rsp->nchans = 1;
7773 }
7774 
7775 
reflect_region_graph_style(void)7776 void reflect_region_graph_style(void)
7777 {
7778   if (current_region == -1) return;
7779   if ((rsp) &&
7780       (rsp->chans) &&
7781       (rsp->chans[0]) &&
7782       (region_dialog_is_active()))
7783     {
7784       rsp->chans[0]->time_graph_style = region_graph_style(ss);
7785       rsp->chans[0]->dot_size = dot_size(ss);
7786       /* update_graph(rsp->chans[0]); */
7787       update_region_browser(true);
7788     }
7789 }
7790 
7791 
unhighlight_region(void)7792 static void unhighlight_region(void)
7793 {
7794   if (current_region != -1)
7795     {
7796       regrow *oldr;
7797       oldr = region_row(current_region);
7798       XtVaSetValues(oldr->rw, XmNbackground, ss->highlight_color, NULL);
7799       XtVaSetValues(oldr->nm, XmNbackground, ss->highlight_color, NULL);
7800     }
7801 }
7802 
7803 
highlight_region(void)7804 static void highlight_region(void)
7805 {
7806   if (current_region != -1)
7807     {
7808       regrow *oldr;
7809       oldr = region_row(current_region);
7810       XtVaSetValues(oldr->rw, XmNbackground, ss->zoom_color, NULL);
7811       XtVaSetValues(oldr->nm, XmNbackground, ss->zoom_color, NULL);
7812     }
7813 }
7814 
7815 
make_region_labels(file_info * hdr)7816 static void make_region_labels(file_info *hdr)
7817 {
7818   char *str;
7819   if (!hdr) return;
7820   str = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char));
7821   snprintf(str, PRINT_BUFFER_SIZE, "srate: %d", hdr->srate);
7822   set_label(reg_srtxt, str);
7823   snprintf(str, PRINT_BUFFER_SIZE, "chans: %d", hdr->chans);
7824   set_label(reg_chntxt, str);
7825   snprintf(str, PRINT_BUFFER_SIZE, "length: %.3f", ((double)(hdr->samples) / (double)(hdr->chans * hdr->srate)));
7826   set_label(reg_lentxt, str);
7827   snprintf(str, PRINT_BUFFER_SIZE, "maxamp: %.3f", region_maxamp(region_list_position_to_id(current_region)));
7828   set_label(reg_maxtxt, str);
7829   free(str);
7830 }
7831 
7832 
update_region_browser(bool grf_too)7833 int update_region_browser(bool grf_too)
7834 {
7835   int i, len;
7836   region_state *rs;
7837 
7838   rs = region_report();
7839   len = rs->len;
7840 
7841   for (i = 0; i < len; i++)
7842     {
7843       regrow *r;
7844       r = region_row(i);
7845       set_button_label(r->nm, rs->name[i]);
7846 #if WITH_AUDIO
7847       XmToggleButtonSetState(r->pl, false, false);
7848 #endif
7849       XtManageChild(r->rw);
7850     }
7851 
7852   for (i = len; i < max_regions(ss); i++)
7853     if (region_rows[i])
7854       XtUnmanageChild(region_rows[i]->rw);
7855 
7856   free_region_state(rs);
7857   if (len == 0) return(0);
7858 
7859   XtManageChild(region_list);
7860   if (grf_too)
7861     {
7862       chan_info *cp;
7863       unhighlight_region();
7864       set_current_region(0);
7865       highlight_region();
7866       goto_window(region_rows[0]->nm);
7867       cp = rsp->chans[0];
7868       if (cp)
7869 	{
7870 	  cp->sound = rsp;
7871 	  cp->chan = 0;
7872 	  set_sensitive(channel_f(cp), false);
7873 	  set_sensitive(channel_w(cp), (region_chans(region_list_position_to_id(0)) > 1));
7874 	  rsp->hdr = fixup_region_data(cp, 0, 0);
7875 	  make_region_labels(rsp->hdr);
7876 	  region_update_graph(cp);
7877 	}
7878     }
7879   return(len);
7880 }
7881 
7882 
region_quit_callback(Widget w,XtPointer context,XtPointer info)7883 static void region_quit_callback(Widget w, XtPointer context, XtPointer info)
7884 {
7885   XtUnmanageChild(region_dialog);
7886 }
7887 
7888 
region_browser_is_active(void)7889 bool region_browser_is_active(void)
7890 {
7891   return((region_dialog) && (XtIsRealized(region_dialog)));
7892 }
7893 
7894 
region_resize_callback(Widget w,XtPointer context,XtPointer info)7895 static void region_resize_callback(Widget w, XtPointer context, XtPointer info)
7896 {
7897   region_update_graph((chan_info *)context);
7898 }
7899 
7900 
delete_region_and_update_browser(int pos)7901 void delete_region_and_update_browser(int pos)
7902 {
7903   int act;
7904   unhighlight_region();
7905   act = remove_region_from_list(pos);
7906   if (act == INVALID_REGION) return;
7907   if (region_dialog)
7908     {
7909       if (act != NO_REGIONS)
7910 	{
7911 	  set_current_region(0);
7912 	  highlight_region();
7913 	  goto_window(region_rows[0]->nm);
7914 	}
7915       else set_current_region(-1);
7916       update_region_browser(1);
7917     }
7918 }
7919 
7920 
region_help_callback(Widget w,XtPointer context,XtPointer info)7921 static void region_help_callback(Widget w, XtPointer context, XtPointer info)
7922 {
7923   region_dialog_help();
7924 }
7925 
7926 
region_insert_callback(Widget w,XtPointer context,XtPointer info)7927 static void region_insert_callback(Widget w, XtPointer context, XtPointer info)
7928 {
7929   if ((current_region != -1) &&
7930       (selected_channel()))
7931     paste_region(region_list_position_to_id(current_region), selected_channel());
7932 }
7933 
7934 
region_mix_callback(Widget w,XtPointer context,XtPointer info)7935 static void region_mix_callback(Widget w, XtPointer context, XtPointer info)
7936 {
7937   if ((current_region != -1) &&
7938       (selected_channel()))
7939     add_region(region_list_position_to_id(current_region), selected_channel());
7940 }
7941 
7942 
region_save_callback(Widget w,XtPointer context,XtPointer info)7943 static void region_save_callback(Widget w, XtPointer context, XtPointer info)
7944 {
7945   if ((current_region != -1) &&
7946       (XmGetFocusWidget(region_dialog) == XmMessageBoxGetChild(region_dialog, XmDIALOG_OK_BUTTON)))
7947     make_region_save_as_dialog(true);
7948 }
7949 
7950 
region_up_arrow_callback(Widget w,XtPointer context,XtPointer info)7951 static void region_up_arrow_callback(Widget w, XtPointer context, XtPointer info)
7952 {
7953   chan_info *cp;
7954   cp = rsp->chans[0];
7955   cp->sound = rsp;
7956   if (cp->chan > 0)
7957     {
7958       cp->chan--;
7959       set_sensitive(channel_f(cp), (cp->chan > 0));
7960       set_sensitive(channel_w(cp), true);
7961       fixup_region_data(cp, cp->chan, current_region);
7962       region_update_graph(cp);
7963     }
7964 }
7965 
7966 
region_down_arrow_callback(Widget w,XtPointer context,XtPointer info)7967 static void region_down_arrow_callback(Widget w, XtPointer context, XtPointer info)
7968 {
7969   chan_info *cp;
7970   cp = rsp->chans[0];
7971   cp->sound = rsp;
7972   if ((cp->chan + 1) < region_chans(region_list_position_to_id(current_region)))
7973     {
7974       cp->chan++;
7975       set_sensitive(channel_f(cp), true);
7976       set_sensitive(channel_w(cp), (region_chans(region_list_position_to_id(current_region)) > (cp->chan + 1)));
7977       fixup_region_data(cp, cp->chan, current_region);
7978       region_update_graph(cp);
7979     }
7980 }
7981 
7982 
region_focus_callback(Widget w,XtPointer context,XtPointer info)7983 static void region_focus_callback(Widget w, XtPointer context, XtPointer info)
7984 {
7985   static oclock_t mouse_down_time = 0;
7986   XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info;
7987   XButtonEvent *ev;
7988   chan_info *cp;
7989   regrow *r = (regrow *)context;
7990 
7991   ev = (XButtonEvent *)(cb->event);
7992   if (mouse_down_time != 0)
7993     {
7994       if ((ev->time - mouse_down_time) < ss->click_time) /* edit region if double clicked */
7995 	{
7996 	  mouse_down_time = ev->time;
7997 	  if (current_region != -1)
7998 	    region_edit(current_region);
7999 	  return;
8000 	}
8001     }
8002   mouse_down_time = ev->time;
8003 
8004   unhighlight_region();
8005   if (region_list_position_to_id(r->pos) == INVALID_REGION) return; /* needed by auto-tester */
8006   set_current_region(r->pos);
8007   cp = rsp->chans[0];
8008   cp->sound = rsp;
8009   cp->chan  = 0;
8010   highlight_region();
8011   set_sensitive(channel_f(cp), false);
8012   set_sensitive(channel_w(cp), (region_chans(region_list_position_to_id(current_region)) > 1));
8013   rsp->hdr = fixup_region_data(cp, 0, current_region);
8014   if (!rsp->hdr) return;
8015   make_region_labels(rsp->hdr);
8016   region_update_graph(cp);
8017 }
8018 
8019 
reflect_play_region_stop(int n)8020 void reflect_play_region_stop(int n)
8021 {
8022 #if WITH_AUDIO
8023   if (region_rows)
8024     {
8025       regrow *rg;
8026       rg = region_row(region_id_to_list_position(n));
8027       if (rg) XmToggleButtonSetState(rg->pl, false, false);
8028     }
8029 #endif
8030 }
8031 
8032 
region_play_callback(Widget w,XtPointer context,XtPointer info)8033 static void region_play_callback(Widget w, XtPointer context, XtPointer info)
8034 {
8035 #if WITH_AUDIO
8036   regrow *r = (regrow *)context;
8037   if (XmToggleButtonGetState(r->pl))
8038     play_region(region_list_position_to_id(r->pos), IN_BACKGROUND);
8039   else stop_playing_region(region_list_position_to_id(r->pos), PLAY_BUTTON_UNSET);
8040 #endif
8041 }
8042 
8043 
reflect_file_in_region_browser(Xen hook_or_reason)8044 static Xen reflect_file_in_region_browser(Xen hook_or_reason)
8045 {
8046   if (region_dialog)
8047     {
8048       bool file_on;
8049       file_on = (bool)(any_selected_sound());
8050       set_sensitive(mix_button, file_on);
8051       set_sensitive(insert_button, file_on);
8052     }
8053   return(Xen_false);
8054 }
8055 
8056 
regrow_get_label(void * ur)8057 static char *regrow_get_label(void *ur)
8058 {
8059   regrow *r = (regrow *)ur;
8060   return(get_label(r->nm));
8061 }
8062 
8063 
regrow_get_pos(void * ur)8064 static int regrow_get_pos(void *ur)
8065 {
8066   regrow *r = (regrow *)ur;
8067   return(r->pos);
8068 }
8069 
8070 
regrow_mouse_enter_label(Widget w,XtPointer context,XEvent * event,Boolean * flag)8071 static void regrow_mouse_enter_label(Widget w, XtPointer context, XEvent *event, Boolean *flag)
8072 {
8073   mouse_enter_label(context, REGION_VIEWER);
8074 }
8075 
8076 
regrow_mouse_leave_label(Widget w,XtPointer context,XEvent * event,Boolean * flag)8077 static void regrow_mouse_leave_label(Widget w, XtPointer context, XEvent *event, Boolean *flag)
8078 {
8079   mouse_leave_label(context, REGION_VIEWER);
8080 }
8081 
8082 
make_regrow(Widget ww,Widget last_row,XtCallbackProc play_callback,XtCallbackProc name_callback)8083 static regrow *make_regrow(Widget ww, Widget last_row, XtCallbackProc play_callback, XtCallbackProc name_callback)
8084 {
8085   int n;
8086   Arg args[32];
8087   regrow *r;
8088   XmString s1;
8089 #if WITH_AUDIO
8090   XtCallbackList n1;
8091 #endif
8092   XtCallbackList n3;
8093 
8094   s1 = XmStringCreateLocalized((char *)"");
8095   r = (regrow *)calloc(1, sizeof(regrow));
8096 
8097   n = 0;
8098   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
8099   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
8100   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
8101   XtSetArg(args[n], XmNtopAttachment, (last_row) ? XmATTACH_WIDGET : XmATTACH_FORM); n++;
8102   if (last_row) {XtSetArg(args[n], XmNtopWidget, last_row); n++;}
8103   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
8104   XtSetArg(args[n], XmNheight, 18); n++;
8105   r->rw = XtCreateWidget("rw", xmFormWidgetClass, ww, args, n);
8106 
8107 #if WITH_AUDIO
8108   n = 0;
8109   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
8110   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
8111   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
8112   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
8113   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
8114   XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
8115   XtSetArg(args[n], XmNlabelString, s1); n++;
8116   XtSetArg(args[n], XmNvalueChangedCallback, n1 = make_callback_list(play_callback, (XtPointer)r)); n++;
8117   if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;}
8118   XtSetArg(args[n], XmNmarginWidth, 8); n++;
8119   r->pl = make_togglebutton_widget("pl", r->rw, args, n);
8120 #endif
8121 
8122   n = 0;
8123   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
8124 #if WITH_AUDIO
8125   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
8126   XtSetArg(args[n], XmNleftWidget, r->pl); n++;
8127 #else
8128   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
8129 #endif
8130   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
8131   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
8132   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
8133   XtSetArg(args[n], XmNshadowThickness, 0); n++;
8134   XtSetArg(args[n], XmNhighlightThickness, 0); n++;
8135   XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
8136   XtSetArg(args[n], XmNfillOnArm, false); n++;
8137   XtSetArg(args[n], XmNrecomputeSize, false); n++;
8138   XtSetArg(args[n], XmNwidth, 300); n++;
8139   XtSetArg(args[n], XmNactivateCallback, n3 = make_callback_list(name_callback, (XtPointer)r)); n++;
8140   r->nm = XtCreateManagedWidget("nm", xmPushButtonWidgetClass, r->rw, args, n);
8141   XmStringFree(s1);
8142 
8143   XtAddEventHandler(r->nm, EnterWindowMask, false, regrow_mouse_enter_label, (XtPointer)r);
8144   XtAddEventHandler(r->nm, LeaveWindowMask, false, regrow_mouse_leave_label, (XtPointer)r);
8145 
8146 #if WITH_AUDIO
8147   free(n1);
8148 #endif
8149   free(n3);
8150   return(r);
8151 }
8152 
8153 static void add_reflect_region_hook(void);
8154 
make_region_dialog(void)8155 static void make_region_dialog(void)
8156 {
8157   int n, i, id;
8158   Arg args[32];
8159   Widget formw, last_row, infosep;
8160   Widget panes, toppane, sep1 = NULL, sep2;
8161 #if WITH_AUDIO
8162   Widget plw;
8163 #endif
8164   XmString xgo_away, xhelp, titlestr, xsave_as;
8165   regrow *r;
8166   chan_info *cp;
8167 
8168   xgo_away = XmStringCreateLocalized((char *)I_GO_AWAY);
8169   xhelp = XmStringCreateLocalized((char *)I_HELP);
8170   titlestr = XmStringCreateLocalized((char *)"Regions");
8171   xsave_as = XmStringCreateLocalized((char *)"Save as");
8172 
8173   n = 0;
8174   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
8175   XtSetArg(args[n], XmNcancelLabelString, xgo_away); n++;
8176   XtSetArg(args[n], XmNhelpLabelString, xhelp); n++;
8177   XtSetArg(args[n], XmNokLabelString, xsave_as); n++;
8178   XtSetArg(args[n], XmNautoUnmanage, false); n++;
8179   XtSetArg(args[n], XmNdialogTitle, titlestr); n++;
8180   XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
8181   XtSetArg(args[n], XmNnoResize, false); n++;
8182   XtSetArg(args[n], XmNtransient, false); n++;
8183   region_dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"Regions", args, n);
8184   save_as_button = XmMessageBoxGetChild(region_dialog, XmDIALOG_OK_BUTTON);
8185 
8186   n = 0;
8187   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
8188   XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
8189   insert_button = XtCreateManagedWidget("Insert", xmPushButtonGadgetClass, region_dialog, args, n);
8190 
8191   n = 0;
8192   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
8193   XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
8194   mix_button = XtCreateManagedWidget("Mix", xmPushButtonGadgetClass, region_dialog, args, n);
8195 
8196   /* XtAddCallback(region_dialog,  XmNokCallback,       region_save_callback,   NULL); */
8197   XtAddCallback(save_as_button, XmNactivateCallback, region_save_callback,   NULL);
8198   XtAddCallback(region_dialog,  XmNcancelCallback,   region_quit_callback,   NULL);
8199   XtAddCallback(region_dialog,  XmNhelpCallback,     region_help_callback,   NULL);
8200   XtAddCallback(mix_button,     XmNactivateCallback, region_mix_callback,    NULL);
8201   XtAddCallback(insert_button,  XmNactivateCallback, region_insert_callback, NULL);
8202 
8203   XmStringFree(xhelp);
8204   XmStringFree(xgo_away);
8205   XmStringFree(xsave_as);
8206   XmStringFree(titlestr);
8207 
8208   XtVaSetValues(XmMessageBoxGetChild(region_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL);
8209   XtVaSetValues(XmMessageBoxGetChild(region_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL);
8210   XtVaSetValues(XmMessageBoxGetChild(region_dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL);
8211   XtVaSetValues(XmMessageBoxGetChild(region_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL);
8212   XtVaSetValues(XmMessageBoxGetChild(region_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL);
8213   XtVaSetValues(XmMessageBoxGetChild(region_dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL);
8214 
8215   insert_button = XmMessageBoxGetChild(region_dialog, XmDIALOG_CANCEL_BUTTON);
8216 
8217   n = 0;
8218   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
8219   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
8220   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
8221   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
8222   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
8223   XtSetArg(args[n], XmNbottomWidget, XmMessageBoxGetChild(region_dialog, XmDIALOG_SEPARATOR)); n++;
8224   formw = XtCreateManagedWidget("formw", xmFormWidgetClass, region_dialog, args, n);
8225 
8226   n = 0;
8227   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
8228   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
8229   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
8230   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
8231   XtSetArg(args[n], XmNtopWidget, sep1); n++;
8232   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
8233   XtSetArg(args[n], XmNallowResize, true); n++;
8234   XtSetArg(args[n], XmNpaneMaximum, LOTSA_PIXELS); n++;
8235   panes = XtCreateManagedWidget("panes", xmPanedWindowWidgetClass, formw, args, n);
8236 
8237   n = 0;
8238   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
8239   n = attach_all_sides(args, n);
8240   XtSetArg(args[n], XmNpaneMinimum, 40); n++;
8241   toppane = XtCreateManagedWidget("toppane", xmFormWidgetClass, panes, args, n);
8242 
8243 #if WITH_AUDIO
8244   n = 0;
8245   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
8246   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
8247   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
8248   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
8249   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
8250   XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
8251   plw = XtCreateManagedWidget("play", xmLabelWidgetClass, toppane, args, n);
8252 #endif
8253 
8254   n = 0;
8255   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
8256   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
8257   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
8258   XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
8259   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
8260   XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
8261   XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
8262   XtSetArg(args[n], XmNheight, 8); n++;
8263   sep2 = XtCreateManagedWidget("sep2", xmSeparatorWidgetClass, toppane, args, n);
8264 
8265   n = 0;
8266   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
8267   XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
8268   XtSetArg(args[n], XmNrightPosition, 70); n++;
8269 #if WITH_AUDIO
8270   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
8271   XtSetArg(args[n], XmNtopWidget, plw); n++;
8272 #else
8273   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
8274 #endif
8275   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
8276   XtSetArg(args[n], XmNbottomWidget, sep2); n++;
8277   XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); n++;
8278   XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); n++;
8279   region_list = XmCreateScrolledWindow(toppane, (char *)"reglist", args, n);
8280 
8281   n = attach_all_sides(args, 0);
8282   region_ww = XtCreateManagedWidget("ww", xmFormWidgetClass, region_list, args, n);
8283   XtVaSetValues(region_list,
8284 		XmNworkWindow, region_ww,
8285 		NULL);
8286 
8287   map_over_children(region_list, set_main_color_of_widget);
8288   last_row = NULL;
8289 
8290   region_rows = (regrow **)calloc(max_regions(ss), sizeof(regrow *));
8291   region_rows_size = max_regions(ss);
8292   for (i = 0; i < max_regions(ss); i++)
8293     {
8294       r = make_regrow(region_ww, last_row, region_play_callback, region_focus_callback);
8295       region_rows[i] = r;
8296       r->pos = i;
8297       last_row = r->rw;
8298     }
8299 
8300   update_region_browser(0);
8301 
8302   n = 0;
8303   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
8304   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
8305   XtSetArg(args[n], XmNleftWidget, region_list); n++;
8306   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
8307 #if WITH_AUDIO
8308   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
8309   XtSetArg(args[n], XmNtopWidget, plw); n++;
8310 #else
8311   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
8312 #endif
8313   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
8314   XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
8315   XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
8316   XtSetArg(args[n], XmNwidth, 8); n++;
8317   infosep = XtCreateManagedWidget("infosep", xmSeparatorWidgetClass, toppane, args, n);
8318 
8319   n = 0;
8320   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
8321   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
8322   XtSetArg(args[n], XmNleftWidget, infosep); n++;
8323   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
8324 #if WITH_AUDIO
8325   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
8326   XtSetArg(args[n], XmNtopWidget, plw); n++;
8327 #else
8328   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
8329 #endif
8330   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
8331   XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
8332   reg_srtxt = XtCreateManagedWidget("srate:", xmLabelWidgetClass, toppane, args, n);
8333 
8334   n = 0;
8335   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
8336   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
8337   XtSetArg(args[n], XmNleftWidget, infosep); n++;
8338   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
8339   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
8340   XtSetArg(args[n], XmNtopWidget, reg_srtxt); n++;
8341   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
8342   XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
8343   reg_chntxt = XtCreateManagedWidget("chans:", xmLabelWidgetClass, toppane, args, n);
8344 
8345   n = 0;
8346   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
8347   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
8348   XtSetArg(args[n], XmNleftWidget, infosep); n++;
8349   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
8350   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
8351   XtSetArg(args[n], XmNtopWidget, reg_chntxt); n++;
8352   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
8353   XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
8354   reg_lentxt = XtCreateManagedWidget("length:", xmLabelWidgetClass, toppane, args, n);
8355 
8356   n = 0;
8357   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
8358   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
8359   XtSetArg(args[n], XmNleftWidget, infosep); n++;
8360   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
8361   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
8362   XtSetArg(args[n], XmNtopWidget, reg_lentxt); n++;
8363   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
8364   XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
8365   reg_maxtxt = XtCreateManagedWidget("maxamp:", xmLabelWidgetClass, toppane, args, n);
8366 
8367 
8368   n = 0;
8369   XtSetArg(args[n], XmNbackground, ss->white); n++;
8370   n = attach_all_sides(args, n);
8371   XtSetArg(args[n], XmNpaneMinimum, 150); n++;
8372   region_grf = XtCreateManagedWidget("grf", xmFormWidgetClass, panes, args, n);
8373 
8374   XtManageChild(region_dialog);
8375   if (widget_width(region_dialog) < 400) set_widget_width(region_dialog, 400);
8376 
8377   id = region_list_position_to_id(0);
8378   rsp = make_simple_channel_display(region_srate(id), region_len(id), WITH_ARROWS, region_graph_style(ss), region_grf, WITHOUT_EVENTS);
8379   rsp->inuse = SOUND_REGION;
8380   set_current_region(0);
8381   cp = rsp->chans[0];
8382   XtVaSetValues(region_rows[0]->nm, XmNbackground, ss->white, XmNforeground, ss->black, NULL);
8383   map_over_children(panes, color_sashes);
8384   XtVaSetValues(toppane, XmNpaneMinimum, 1, NULL);
8385   XtVaSetValues(region_grf, XmNpaneMinimum, 1, NULL);
8386 
8387   XtAddCallback(channel_graph(cp), XmNresizeCallback, region_resize_callback, (XtPointer)cp);
8388   XtAddCallback(channel_graph(cp), XmNexposeCallback, region_resize_callback, (XtPointer)cp);
8389 
8390   /* channel_f is up arrow, channel_w is down arrow */
8391   XtAddCallback(channel_f(cp), XmNactivateCallback, region_up_arrow_callback, NULL);
8392   XtAddCallback(channel_w(cp), XmNactivateCallback, region_down_arrow_callback, NULL);
8393 
8394   set_sensitive(channel_f(cp), false);
8395   set_sensitive(channel_w(cp), (region_chans(region_list_position_to_id(0)) > 1));
8396 
8397   cp->chan = 0;
8398   rsp->hdr = fixup_region_data(cp, 0, 0);
8399   make_region_labels(rsp->hdr);
8400   highlight_region();
8401   region_update_graph(cp);
8402 
8403   add_reflect_region_hook();
8404 
8405   set_dialog_widget(REGION_DIALOG, region_dialog);
8406 }
8407 
8408 
view_region_callback(Widget w,XtPointer context,XtPointer info)8409 static void view_region_callback(Widget w, XtPointer context, XtPointer info)
8410 {
8411   /* put up scrollable dialog describing/playing/editing the region list */
8412   if (!region_dialog)
8413     make_region_dialog();
8414   else raise_dialog(region_dialog);
8415   if (!XtIsManaged(region_dialog))
8416     {
8417       set_current_region(0);
8418       XtManageChild(region_dialog);
8419     }
8420 }
8421 
8422 
region_dialog_is_active(void)8423 bool region_dialog_is_active(void)
8424 {
8425   return((region_dialog) &&
8426 	 (XtIsManaged(region_dialog)));
8427 }
8428 
8429 
allocate_region_rows(int n)8430 void allocate_region_rows(int n)
8431 {
8432   if ((region_dialog) &&
8433       (n > region_rows_size))
8434     {
8435       int i;
8436       region_rows = (regrow **)realloc(region_rows, n * sizeof(regrow *));
8437       for (i = region_rows_size; i < n; i++) region_rows[i] = NULL;
8438       region_rows_size = n;
8439     }
8440 }
8441 
8442 
region_row(int n)8443 static regrow *region_row(int n)
8444 {
8445   if (n < region_rows_size)
8446     {
8447       regrow *r;
8448       if (!region_rows[n])
8449 	{
8450 	  r = make_regrow(region_ww,
8451 			  (n > 0) ? (region_rows[n - 1]->rw) : NULL,
8452 			  region_play_callback, region_focus_callback);
8453 	  region_rows[n] = r;
8454 	  r->pos = n;
8455 	}
8456       return(region_rows[n]);
8457     }
8458   return(NULL);
8459 }
8460 
8461 
region_dialog_region(void)8462 static int region_dialog_region(void)
8463 {
8464   return(region_list_position_to_id(current_region));
8465 }
8466 
8467 
g_view_regions_dialog(void)8468 static Xen g_view_regions_dialog(void)
8469 {
8470   #define H_view_regions_dialog "(" S_view_regions_dialog "): start the region dialog"
8471   if (snd_regions() > 0)
8472     view_region_callback(main_pane(ss), NULL, NULL);
8473   return(Xen_wrap_widget(region_dialog));
8474 }
8475 
8476 
8477 #include "snd-file.h"
8478 
8479 /* various file-related dialogs:
8480    File|Edit:Save-as
8481    File:Open|View
8482    File|Edit:Mix
8483    File:Insert
8484    File:Edit-Header
8485    File:New
8486    Info and Raw
8487    View:Files
8488 */
8489 
8490 static void snd_sort(int sorter, sort_info **data, int len);
8491 
8492 
8493 /* -------------------------------- sorters -------------------------------- */
8494 
8495 
file_bytes(const char * filename)8496 static mus_long_t file_bytes(const char *filename)
8497 {
8498 #ifndef _MSC_VER
8499   struct stat statbuf;
8500   if (stat(filename, &statbuf) >= 0)
8501     return(statbuf.st_size);
8502   return(0);
8503 #else
8504   int chan;
8505   mus_long_t bytes;
8506   chan = mus_file_open_read(filename);
8507   if (chan == -1) return(0);
8508   bytes = lseek(chan, 0L, SEEK_END);
8509   snd_close(chan, filename);
8510   return(bytes);
8511 #endif
8512 }
8513 
8514 /* sort files list by name (aphabetical), or some number (date written, size), or by xen proc */
8515 
sort_a_to_z(const void * a,const void * b)8516 static int sort_a_to_z(const void *a, const void *b)
8517 {
8518   sort_info *d1 = *(sort_info **)a;
8519   sort_info *d2 = *(sort_info **)b;
8520   return(strcmp(d1->filename, d2->filename));
8521 }
8522 
8523 
sort_z_to_a(const void * a,const void * b)8524 static int sort_z_to_a(const void *a, const void *b)
8525 {
8526   return(-sort_a_to_z(a, b));
8527 }
8528 
8529 
sort_small_to_big(const void * a,const void * b)8530 static int sort_small_to_big(const void *a, const void *b)
8531 {
8532   sort_info *d1 = *(sort_info **)a;
8533   sort_info *d2 = *(sort_info **)b;
8534   if (d1->samps > d2->samps)
8535     return(1);
8536   else
8537     {
8538       if (d1->samps == d2->samps)
8539 	return(0);
8540       else return(-1);
8541     }
8542 }
8543 
8544 
sort_big_to_small(const void * a,const void * b)8545 static int sort_big_to_small(const void *a, const void *b)
8546 {
8547   return(-sort_small_to_big(a, b));
8548 }
8549 
8550 
sort_new_to_old(const void * a,const void * b)8551 static int sort_new_to_old(const void *a, const void *b)
8552 {
8553   sort_info *d1 = *(sort_info **)a;
8554   sort_info *d2 = *(sort_info **)b;
8555   if (d1->time < d2->time)
8556     return(1);
8557   else
8558     {
8559       if (d1->time == d2->time)
8560 	return(0);
8561       else return(-1);
8562     }
8563 }
8564 
8565 
sort_old_to_new(const void * a,const void * b)8566 static int sort_old_to_new(const void *a, const void *b)
8567 {
8568   return(-sort_new_to_old(a, b));
8569 }
8570 
8571 
8572 static Xen sorter_func;
8573 
sort_xen(const void * a,const void * b)8574 static int sort_xen(const void *a, const void *b)
8575 {
8576   /* sorter function gets two names, returns -1, 0, or 1 just like the other comparators */
8577   sort_info *d1 = *(sort_info **)a;
8578   sort_info *d2 = *(sort_info **)b;
8579   return(Xen_integer_to_C_int(Xen_call_with_2_args(sorter_func, C_string_to_Xen_string(d1->full_filename), C_string_to_Xen_string(d2->full_filename), "sort func")));
8580 }
8581 
8582 
snd_sort(int sorter,sort_info ** data,int len)8583 static void snd_sort(int sorter, sort_info **data, int len)
8584 {
8585   int i, sorter_pos;
8586   switch (sorter)
8587     {
8588     case SORT_A_TO_Z:
8589       qsort((void *)data, len, sizeof(sort_info *), sort_a_to_z);
8590       break;
8591 
8592     case SORT_Z_TO_A:
8593       qsort((void *)data, len, sizeof(sort_info *), sort_z_to_a);
8594       break;
8595 
8596     case SORT_NEW_TO_OLD:
8597       for (i = 0; i < len; i++)
8598 	data[i]->time = file_write_date(data[i]->full_filename);
8599       qsort((void *)data, len, sizeof(sort_info *), sort_new_to_old);
8600       break;
8601 
8602     case SORT_OLD_TO_NEW:
8603       for (i = 0; i < len; i++)
8604 	data[i]->time = file_write_date(data[i]->full_filename);
8605       qsort((void *)data, len, sizeof(sort_info *), sort_old_to_new);
8606       break;
8607 
8608     case SORT_SMALL_TO_BIG:
8609       for (i = 0; i < len; i++)
8610 	data[i]->samps = file_bytes(data[i]->full_filename);
8611       qsort((void *)data, len, sizeof(sort_info *), sort_small_to_big);
8612       break;
8613 
8614     case SORT_BIG_TO_SMALL:
8615       for (i = 0; i < len; i++)
8616 	data[i]->samps = file_bytes(data[i]->full_filename);
8617       qsort((void *)data, len, sizeof(sort_info *), sort_big_to_small);
8618       break;
8619 
8620     default:
8621     case SORT_XEN:
8622       /* sorter is SORT_XEN + index into file_sorters list */
8623       /*   that list is a vector of pairs (name proc) */
8624       sorter_pos = sorter - SORT_XEN;
8625       if ((sorter_pos >= 0) &&
8626 	  (sorter_pos < ss->file_sorters_size))
8627 	{
8628 	  if (Xen_is_list(Xen_vector_ref(ss->file_sorters, sorter_pos)))
8629 	    {
8630 	      sorter_func = Xen_cadr(Xen_vector_ref(ss->file_sorters, sorter_pos));
8631 	      qsort((void *)data, len, sizeof(sort_info *), sort_xen);
8632 	      return;
8633 	    }
8634 	}
8635       snd_warning("no such file-sorter (%d)", sorter_pos);
8636       break;
8637     }
8638 }
8639 
8640 
8641 
dialog_set_title(widget_t dialog,const char * titlestr)8642 static void dialog_set_title(widget_t dialog, const char *titlestr)
8643 {
8644   XmString title;
8645   title = XmStringCreateLocalized((char *)titlestr);
8646   XtVaSetValues(dialog, XmNdialogTitle, title, NULL);
8647   XmStringFree(title);
8648 }
8649 
8650 
cleanup_file_monitor(void)8651 void cleanup_file_monitor(void) {}
initialize_file_monitor(void)8652 static bool initialize_file_monitor(void) {return(false);}
unmonitor_file(void * watcher)8653 void *unmonitor_file(void *watcher) {return(NULL);}
monitor_sound(snd_info * sp)8654 void monitor_sound(snd_info *sp) {}
8655 
8656 /* -------------------------------------------------------------------------------- */
8657 
8658 
8659 
8660 #define FSB_BOX(Dialog, Child) XmFileSelectionBoxGetChild(Dialog, Child)
8661 #define MSG_BOX(Dialog, Child) XmMessageBoxGetChild(Dialog, Child)
8662 
8663 
8664 /* ---------------- open/mix/insert/save-as dialogs ---------------- */
8665 
color_file_selection_box(Widget w)8666 static void color_file_selection_box(Widget w)
8667 {
8668   /* overwrite most Motif-default colors */
8669   Widget wtmp;
8670 
8671   map_over_children(w, set_main_color_of_widget);
8672   XtVaSetValues(FSB_BOX(w, XmDIALOG_DIR_LIST),
8673 		XmNbackground, ss->white,
8674 		XmNforeground, ss->black,
8675 		NULL);
8676   XtVaSetValues(FSB_BOX(w, XmDIALOG_LIST),
8677 		XmNbackground, ss->white,
8678 		XmNforeground, ss->black,
8679 		NULL);
8680 
8681   XtVaSetValues(FSB_BOX(w, XmDIALOG_CANCEL_BUTTON), XmNarmColor,   ss->selection_color, NULL);
8682   XtVaSetValues(FSB_BOX(w, XmDIALOG_HELP_BUTTON),   XmNarmColor,   ss->selection_color, NULL);
8683   XtVaSetValues(FSB_BOX(w, XmDIALOG_OK_BUTTON),     XmNarmColor,   ss->selection_color, NULL);
8684   XtVaSetValues(FSB_BOX(w, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL);
8685   XtVaSetValues(FSB_BOX(w, XmDIALOG_HELP_BUTTON),   XmNbackground, ss->highlight_color, NULL);
8686   XtVaSetValues(FSB_BOX(w, XmDIALOG_OK_BUTTON),     XmNbackground, ss->highlight_color, NULL);
8687 
8688   wtmp = FSB_BOX(w, XmDIALOG_TEXT);
8689   if (wtmp)
8690     {
8691       XtVaSetValues(wtmp,     XmNhighlightThickness,  1,                          NULL);
8692       XtAddCallback(wtmp,     XmNfocusCallback,       textfield_focus_callback,   NULL);
8693       XtAddCallback(wtmp,     XmNlosingFocusCallback, textfield_unfocus_callback, NULL);
8694       XtAddEventHandler(wtmp, EnterWindowMask, false, mouse_enter_text_callback,  NULL);
8695       XtAddEventHandler(wtmp, LeaveWindowMask, false, mouse_leave_text_callback,  NULL);
8696     }
8697 
8698   wtmp = FSB_BOX(w, XmDIALOG_FILTER_TEXT);
8699   if (wtmp)
8700     {
8701       XtVaSetValues(wtmp,     XmNhighlightThickness,  1,                          NULL);
8702       XtAddCallback(wtmp,     XmNfocusCallback,       textfield_focus_callback,   NULL);
8703       XtAddCallback(wtmp,     XmNlosingFocusCallback, textfield_unfocus_callback, NULL);
8704       XtAddEventHandler(wtmp, EnterWindowMask, false, mouse_enter_text_callback,  NULL);
8705       XtAddEventHandler(wtmp, LeaveWindowMask, false, mouse_leave_text_callback,  NULL);
8706     }
8707 }
8708 
8709 
force_directory_reread(Widget dialog)8710 static void force_directory_reread(Widget dialog)
8711 {
8712   /* force update, but make sure the filename is not reset to its (dumb) default */
8713   XmString dirmask;
8714   Widget name_field;
8715   char *filename = NULL;
8716   name_field = FSB_BOX(dialog, XmDIALOG_TEXT);
8717   filename = XmTextGetString(name_field);
8718   XtVaGetValues(dialog, XmNdirMask, &dirmask, NULL);
8719   XmFileSelectionDoSearch(dialog, dirmask);
8720   XmStringFree(dirmask);
8721   XmTextSetString(name_field, filename);
8722   if (filename)
8723     {
8724       XmTextSetCursorPosition(name_field, mus_strlen(filename));
8725       XtFree(filename);
8726     }
8727 }
8728 
8729 
force_directory_reread_and_let_filename_change(Widget dialog)8730 static void force_directory_reread_and_let_filename_change(Widget dialog)
8731 {
8732   XmString dirmask;
8733   XtVaGetValues(dialog, XmNdirMask, &dirmask, NULL);
8734   XmFileSelectionDoSearch(dialog, dirmask);
8735   XmStringFree(dirmask);
8736 }
8737 
8738 
8739 
8740 
8741 /* -------------------------------- file list positioning -------------------------------- */
8742 
8743 typedef struct {
8744   char *directory_name;
8745   position_t list_top;
8746 } dirpos_info;
8747 
8748 typedef struct {
8749   dirpos_info **dirs;
8750   int size, top;
8751 } dirpos_list;
8752 
8753 void dirpos_update(dirpos_list *dl, const char *dir, position_t pos);
8754 position_t dirpos_list_top(dirpos_list *dl, const char *dirname);
8755 dirpos_list *make_dirpos_list(void);
8756 
8757 
make_dirpos_info(const char * dir,position_t pos)8758 static dirpos_info *make_dirpos_info(const char *dir, position_t pos)
8759 {
8760   dirpos_info *dp;
8761   dp = (dirpos_info *)calloc(1, sizeof(dirpos_info));
8762   dp->directory_name = mus_strdup(dir);
8763   dp->list_top = pos;
8764   return(dp);
8765 }
8766 
8767 
make_dirpos_list(void)8768 dirpos_list *make_dirpos_list(void)
8769 {
8770   dirpos_list *dl;
8771   dl = (dirpos_list *)calloc(1, sizeof(dirpos_list));
8772   dl->size = 8;
8773   dl->top = 0;
8774   dl->dirs = (dirpos_info **)calloc(dl->size, sizeof(dirpos_info *));
8775   return(dl);
8776 }
8777 
8778 
dirpos_update(dirpos_list * dl,const char * dir,position_t pos)8779 void dirpos_update(dirpos_list *dl, const char *dir, position_t pos)
8780 {
8781   int i;
8782   if (!dl) return;
8783   for (i = 0; i < dl->top; i++)
8784     {
8785       if ((dl->dirs[i]) &&
8786 	  (mus_strcmp(dir, dl->dirs[i]->directory_name)))
8787 	{
8788 	  dirpos_info *dp;
8789 	  dp = dl->dirs[i];
8790 	  dp->list_top = pos;
8791 	  return;
8792 	}
8793     }
8794   if (dl->top >= dl->size)
8795     {
8796       int old_size;
8797       old_size = dl->size;
8798       dl->size += 8;
8799       dl->dirs = (dirpos_info **)realloc(dl->dirs, dl->size * sizeof(dirpos_info *));
8800       for (i = old_size; i < dl->size; i++) dl->dirs[i] = NULL;
8801     }
8802   dl->dirs[dl->top++] = make_dirpos_info(dir, pos);
8803 }
8804 
8805 
dirpos_list_top(dirpos_list * dl,const char * dirname)8806 position_t dirpos_list_top(dirpos_list *dl, const char *dirname)
8807 {
8808   int i;
8809   if (dl)
8810     for (i = 0; i < dl->top; i++)
8811       if ((dl->dirs[i]) &&
8812 	  (mus_strcmp(dirname, dl->dirs[i]->directory_name)))
8813 	return(dl->dirs[i]->list_top);
8814   return(POSITION_UNKNOWN);
8815 }
8816 
8817 
8818 /* -------- popups -------- */
8819 
8820 /* I think there is no way to get a key action to popup one of these menus -- Xm/RowColumn.c
8821  *   appears to insist on a button event, and any change to that via XmNmenuPost gets an
8822  *   error.  Perhaps we should notice the POPUP_BUTTON setting however?
8823  */
8824 
8825 typedef struct file_pattern_info {
8826   /* just-sounds file lists */
8827   bool reread_directory;
8828   bool in_just_sounds_update;
8829   Widget dialog, just_sounds_button;
8830   char *last_dir;
8831   dir_info *current_files;
8832   void *directory_watcher;
8833   int filter_choice, sorter_choice;
8834   dirpos_list *dir_list;
8835 } file_pattern_info;
8836 
8837 /* popups:
8838  *   text:    history of previous choices,
8839  *   list:    sort and filter choices
8840  *   dir:     higher level dir choices
8841  *   filter:  history of previous choices
8842  */
8843 
8844 typedef struct file_popup_info {
8845   Widget dialog;
8846   Widget file_text_popup, file_list_popup, file_dir_popup, file_filter_popup;
8847   Widget file_text_popup_label, file_filter_popup_label, file_dir_popup_label, file_list_popup_label;
8848   /* file_filter here refers to the dialog filter field, not file-filters */
8849   char **file_text_names, **file_filter_names;                   /* history of choices as array of strings */
8850   Widget *file_text_items, *file_filter_items, *file_dir_items, *file_list_items;  /* menu items */
8851   int file_list_items_size;
8852   file_pattern_info *fp;
8853 } file_popup_info;
8854 
8855 
8856 /* file popup */
file_text_item_activate_callback(Widget w,XtPointer context,XtPointer info)8857 static void file_text_item_activate_callback(Widget w, XtPointer context, XtPointer info)
8858 {
8859   file_popup_info *fd = (file_popup_info *)context;
8860   char *filename;
8861   snd_info *sp;
8862   filename = get_label(w);
8863   XmTextFieldSetString(FSB_BOX(fd->dialog, XmDIALOG_TEXT), filename);
8864 
8865   ss->open_requestor = FROM_OPEN_DIALOG_POPUP;
8866   ss->open_requestor_data = NULL;
8867   sp = snd_open_file(filename, FILE_READ_WRITE);
8868   if (sp) select_channel(sp, 0);
8869 
8870   XtUnmanageChild(fd->dialog);
8871   if (filename) XtFree(filename);
8872 }
8873 
8874 
8875 #define FILE_TEXT_POPUP_LABEL "previous files"
8876 
file_text_popup_callback(Widget w,XtPointer context,XtPointer info)8877 static void file_text_popup_callback(Widget w, XtPointer context, XtPointer info)
8878 {
8879   file_popup_info *fd = (file_popup_info *)context;
8880   XmPopupHandlerCallbackStruct *cb = (XmPopupHandlerCallbackStruct *)info;
8881   XEvent *e;
8882   e = cb->event;
8883   if (e->type == ButtonPress)
8884     {
8885       /* position menu to match current text widget, show previous choices, if any else "[no previous choices]" */
8886       /*     XmMenuPosition(popup_menu, event) happens automatically */
8887 
8888       char *current_filename;
8889       int i, filenames_to_display = 0;
8890 
8891       if (!fd->file_text_items)
8892 	{
8893 	  int n = 0;
8894 	  Arg args[12];
8895 	  fd->file_text_items = (Widget *)calloc(FILENAME_LIST_SIZE, sizeof(Widget));
8896 	  XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
8897 	  for (i = 0; i < FILENAME_LIST_SIZE; i++)
8898 	    {
8899 	      fd->file_text_items[i] = XtCreateWidget("", xmPushButtonWidgetClass, fd->file_text_popup, args, n);
8900 	      XtAddCallback(fd->file_text_items[i], XmNactivateCallback, file_text_item_activate_callback, (void *)fd);
8901 	    }
8902 	}
8903 
8904       current_filename = XmTextFieldGetString(FSB_BOX(fd->dialog, XmDIALOG_TEXT));
8905       /* w is probably ok here (assumes only text triggers this) */
8906 
8907       for (i = 0; i < FILENAME_LIST_SIZE; i++)
8908 	if ((fd->file_text_names[i]) &&
8909 	    (mus_file_probe(fd->file_text_names[i])) &&
8910 	    (!(mus_strcmp(fd->file_text_names[i], current_filename))))
8911 	  {
8912 	    set_label(fd->file_text_items[filenames_to_display], fd->file_text_names[i]);
8913 	    XtManageChild(fd->file_text_items[filenames_to_display]);
8914 	    filenames_to_display++;
8915 	  }
8916 
8917       for (i = filenames_to_display; i < FILENAME_LIST_SIZE; i++)
8918 	if ((fd->file_text_items[i]) &&
8919 	    (XtIsManaged(fd->file_text_items[i])))
8920 	  XtUnmanageChild(fd->file_text_items[i]);
8921       XtFree(current_filename);
8922 
8923       /* why was this commented out? */
8924       if (filenames_to_display == 0)
8925 	set_label(fd->file_text_popup_label, "no " FILE_TEXT_POPUP_LABEL);
8926       else set_label(fd->file_text_popup_label, FILE_TEXT_POPUP_LABEL);
8927 
8928       cb->menuToPost = fd->file_text_popup;
8929     }
8930 }
8931 
8932 
8933 /* filter popup */
file_filter_text_activate_callback(Widget w,XtPointer context,XtPointer info)8934 static void file_filter_text_activate_callback(Widget w, XtPointer context, XtPointer info)
8935 {
8936   file_popup_info *fd = (file_popup_info *)context;
8937   char *filter;
8938   filter = XmTextFieldGetString(w);
8939   if (filter)
8940     {
8941       remember_filename(filter, fd->file_filter_names);
8942       XtFree(filter);
8943       force_directory_reread_and_let_filename_change(fd->dialog);
8944     }
8945 }
8946 
8947 
file_filter_item_activate_callback(Widget w,XtPointer context,XtPointer info)8948 static void file_filter_item_activate_callback(Widget w, XtPointer context, XtPointer info)
8949 {
8950   file_popup_info *fd = (file_popup_info *)context;
8951   Widget text;
8952   char *filtername;
8953   filtername = get_label(w);
8954   text = FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT);
8955   XmTextFieldSetString(text, filtername);
8956   force_directory_reread(fd->dialog);
8957   if (filtername) XtFree(filtername);
8958 }
8959 
8960 
8961 #define FILE_FILTER_POPUP_LABEL "previous filters"
8962 
file_filter_popup_callback(Widget w,XtPointer context,XtPointer info)8963 static void file_filter_popup_callback(Widget w, XtPointer context, XtPointer info)
8964 {
8965   file_popup_info *fd = (file_popup_info *)context;
8966   XmPopupHandlerCallbackStruct *cb = (XmPopupHandlerCallbackStruct *)info;
8967   XEvent *e;
8968   e = cb->event;
8969   if (e->type == ButtonPress)
8970     {
8971       char *current_filtername;
8972       int i, filternames_to_display = 0;
8973 
8974       if (!fd->file_filter_items)
8975 	{
8976 	  int n = 0;
8977 	  Arg args[12];
8978 	  fd->file_filter_items = (Widget *)calloc(FILENAME_LIST_SIZE, sizeof(Widget));
8979 	  XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
8980 	  for (i = 0; i < FILENAME_LIST_SIZE; i++)
8981 	    {
8982 	      fd->file_filter_items[i] = XtCreateWidget("", xmPushButtonWidgetClass, fd->file_filter_popup, args, n);
8983 	      XtAddCallback(fd->file_filter_items[i], XmNactivateCallback, file_filter_item_activate_callback, (void *)fd);
8984 	    }
8985 	}
8986 
8987       current_filtername = XmTextFieldGetString(FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT));
8988 
8989       for (i = 0; i < FILENAME_LIST_SIZE; i++)
8990 	if ((fd->file_filter_names[i]) &&
8991 	    (!(mus_strcmp(fd->file_filter_names[i], current_filtername))))
8992 	  {
8993 	    set_label(fd->file_filter_items[filternames_to_display], fd->file_filter_names[i]);
8994 	    XtManageChild(fd->file_filter_items[filternames_to_display]);
8995 	    filternames_to_display++;
8996 	  }
8997 
8998       for (i = filternames_to_display; i < FILENAME_LIST_SIZE; i++)
8999 	if ((fd->file_filter_items[i]) &&
9000 	    (XtIsManaged(fd->file_filter_items[i])))
9001 	  XtUnmanageChild(fd->file_filter_items[i]);
9002       XtFree(current_filtername);
9003       /*
9004       if (filternames_to_display == 0)
9005 	set_label(fd->file_filter_popup_label, "no " FILE_FILTER_POPUP_LABEL);
9006       else set_label(fd->file_filter_popup_label, FILE_FILTER_POPUP_LABEL);
9007       */
9008       cb->menuToPost = fd->file_filter_popup;
9009     }
9010 }
9011 
9012 
9013 /* dir list popup */
9014 
update_dir_list(Widget dialog,char * filter)9015 static void update_dir_list(Widget dialog, char *filter)
9016 {
9017   Widget text;
9018   text = FSB_BOX(dialog, XmDIALOG_FILTER_TEXT);
9019   XmTextFieldSetString(text, filter);
9020   force_directory_reread(dialog);
9021 }
9022 
9023 
file_dir_item_activate_callback(Widget w,XtPointer context,XtPointer info)9024 static void file_dir_item_activate_callback(Widget w, XtPointer context, XtPointer info)
9025 {
9026   char *name;
9027   name = get_label(w);
9028   if (name)
9029     {
9030       file_popup_info *fd = (file_popup_info *)context;
9031       char *filter;
9032       filter = mus_format("%s/*", name);
9033       update_dir_list(fd->dialog, filter);
9034       XtFree(name);
9035       free(filter);
9036     }
9037 }
9038 
9039 
9040 #define FILE_DIR_POPUP_LABEL "dirs"
9041 
9042 /* dir_items, but strs generated on the fly, current in filter text */
9043 
file_dir_popup_callback(Widget w,XtPointer context,XtPointer info)9044 static void file_dir_popup_callback(Widget w, XtPointer context, XtPointer info)
9045 {
9046   file_popup_info *fd = (file_popup_info *)context;
9047   XmPopupHandlerCallbackStruct *cb = (XmPopupHandlerCallbackStruct *)info;
9048   XEvent *e;
9049   e = cb->event;
9050   if (e->type == ButtonPress)
9051     {
9052       char *current_filename = NULL;
9053       int i, dirs_to_display = 0;
9054 
9055       if (!fd->file_dir_items)
9056 	{
9057 	  int n = 0;
9058 	  Arg args[12];
9059 	  fd->file_dir_items = (Widget *)calloc(FILENAME_LIST_SIZE, sizeof(Widget));
9060 	  XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
9061 	  for (i = 0; i < FILENAME_LIST_SIZE; i++)
9062 	    {
9063 	      fd->file_dir_items[i] = XtCreateWidget("", xmPushButtonWidgetClass, fd->file_dir_popup, args, n);
9064 	      XtAddCallback(fd->file_dir_items[i], XmNactivateCallback, file_dir_item_activate_callback, (void *)fd);
9065 	    }
9066 	}
9067 
9068       {
9069 	XmStringTable items;
9070 	int num_dirs;
9071 	XtVaGetValues(fd->dialog, XmNdirListItems, &items, XmNdirListItemCount, &num_dirs, NULL);
9072 	if (num_dirs > 0)
9073 	  current_filename = (char *)XmStringUnparse(items[0], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
9074       }
9075       if (!current_filename)
9076 	{
9077 	  current_filename = XmTextFieldGetString(FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT));
9078 	  if (!current_filename)
9079 	    current_filename = XmTextFieldGetString(FSB_BOX(fd->dialog, XmDIALOG_TEXT));
9080 	}
9081 
9082       if (current_filename)
9083 	{
9084 	  int len;
9085 	  len = strlen(current_filename);
9086 	  for (i = 0; i < len; i++)
9087 	    if (current_filename[i] == '/')
9088 	      dirs_to_display++;
9089 
9090 	  if (dirs_to_display > FILENAME_LIST_SIZE)
9091 	    dirs_to_display = FILENAME_LIST_SIZE;
9092 
9093 	  if (dirs_to_display > 0)
9094 	    {
9095 	      char **dirs;
9096 	      int j = 1;
9097 	      dirs = (char **)calloc(dirs_to_display, sizeof(char *));
9098 	      dirs[0] = mus_strdup("/");
9099 	      for (i = 1; i < len; i++)
9100 		if (current_filename[i] == '/')
9101 		  {
9102 		    dirs[j] = (char *)calloc(i + 1, sizeof(char));
9103 		    memcpy(dirs[j], (const char *)current_filename, i);
9104 		    j++;
9105 		  }
9106 
9107 	      for (i = 0; i < dirs_to_display; i++)
9108 		{
9109 		  set_label(fd->file_dir_items[i], dirs[i]);
9110 		  XtManageChild(fd->file_dir_items[i]);
9111 		  free(dirs[i]);
9112 		}
9113 	      free(dirs);
9114 	    }
9115 	}
9116 
9117       for (i = dirs_to_display; i < FILENAME_LIST_SIZE; i++)
9118 	if ((fd->file_dir_items[i]) &&
9119 	    (XtIsManaged(fd->file_dir_items[i])))
9120 	  XtUnmanageChild(fd->file_dir_items[i]);
9121       XtFree(current_filename);
9122 
9123       cb->menuToPost = fd->file_dir_popup;
9124     }
9125 }
9126 
9127 
9128 #define FILE_LIST_POPUP_LABEL "sort/filter"
9129 #define NO_FILTER_LABEL "no filter"
9130 
9131 #define FILE_FILTER_OFFSET 1024
9132 #define NO_FILE_FILTER_OFFSET 2048
9133 
9134 static void sort_files_and_redisplay(file_pattern_info *fp);
9135 
9136 
file_list_item_activate_callback(Widget w,XtPointer context,XtPointer info)9137 static void file_list_item_activate_callback(Widget w, XtPointer context, XtPointer info)
9138 {
9139   file_popup_info *fd = (file_popup_info *)context;
9140   intptr_t data;
9141   int choice;
9142   XtVaGetValues(w, XmNuserData, &data, NULL);
9143   choice = (int)data;
9144   if (choice >= FILE_FILTER_OFFSET)
9145     {
9146       XmToggleButtonSetState(fd->fp->just_sounds_button, false, false);
9147       if (choice == NO_FILE_FILTER_OFFSET)
9148 	fd->fp->filter_choice = NO_FILE_FILTER;
9149       else fd->fp->filter_choice = choice - FILE_FILTER_OFFSET + 2;
9150       fd->fp->in_just_sounds_update = true;
9151       force_directory_reread(fd->fp->dialog);
9152       fd->fp->in_just_sounds_update = false;
9153     }
9154   else
9155     {
9156       fd->fp->sorter_choice = choice;
9157       sort_files_and_redisplay(fd->fp);
9158     }
9159 }
9160 
9161 
make_file_list_item(file_popup_info * fd,int choice)9162 static Widget make_file_list_item(file_popup_info *fd, int choice)
9163 {
9164   int n;
9165   Arg args[12];
9166   const char *item_label;
9167   Widget w;
9168 
9169   n = 0;
9170   XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
9171 
9172   switch (choice)
9173     {
9174     case 0: item_label = "a..z";       break;
9175     case 1: item_label = "z..a";       break;
9176     case 2: item_label = "new..old";   break;
9177     case 3: item_label = "old..new";   break;
9178     case 4: item_label = "small..big"; break;
9179     case 5: item_label = "big..small"; break;
9180     default: item_label = "unused";    break;
9181     }
9182 
9183   XtSetArg(args[n], XmNuserData, choice);           /* userData is index into sorters list */
9184   w = XtCreateManagedWidget(item_label, xmPushButtonWidgetClass, fd->file_list_popup, args, n + 1);
9185   XtAddCallback(w, XmNactivateCallback, file_list_item_activate_callback, (void *)fd);
9186   return(w);
9187 }
9188 
9189 
file_list_popup_callback(Widget w,XtPointer context,XtPointer info)9190 static void file_list_popup_callback(Widget w, XtPointer context, XtPointer info)
9191 {
9192   file_popup_info *fd = (file_popup_info *)context;
9193   XmPopupHandlerCallbackStruct *cb = (XmPopupHandlerCallbackStruct *)info;
9194   XEvent *e;
9195   e = cb->event;
9196   if (e->type == ButtonPress)
9197     {
9198       int i;
9199       if (!fd->file_list_items)
9200 	{
9201 	  /* set up the default menu items */
9202 
9203 	  fd->file_list_items = (Widget *)calloc(SORT_XEN, sizeof(Widget));
9204 	  fd->file_list_items_size = SORT_XEN;
9205 
9206 	  for (i = 0; i < SORT_XEN; i++)
9207 	    fd->file_list_items[i] = make_file_list_item(fd, i);
9208 	}
9209 
9210       /* clear any trailers just in case */
9211       if (fd->file_list_items_size > SORT_XEN)
9212 	for (i = SORT_XEN; i < fd->file_list_items_size; i++)
9213 	  XtUnmanageChild(fd->file_list_items[i]);
9214 
9215       /* check for added sort and filter functions (allocate more items if needed) */
9216       {
9217 	int extra_sorters = 0, extra_filters = 0, items_len;
9218 	for (i = 0; i < ss->file_sorters_size; i++)
9219 	  if (!(Xen_is_false(Xen_vector_ref(ss->file_sorters, i))))
9220 	    extra_sorters++;
9221 	for (i = 0; i < ss->file_filters_size; i++)
9222 	  if (!(Xen_is_false(Xen_vector_ref(ss->file_filters, i))))
9223 	    extra_filters++;
9224 
9225 	items_len = SORT_XEN + extra_sorters + extra_filters;
9226 	if (fd->fp->filter_choice != NO_FILE_FILTER) items_len++;
9227 
9228 	if (items_len > fd->file_list_items_size)
9229 	  {
9230 	    fd->file_list_items = (Widget *)realloc(fd->file_list_items, items_len * sizeof(Widget));
9231 	    for (i = fd->file_list_items_size; i < items_len; i++)
9232 	      fd->file_list_items[i] = make_file_list_item(fd, i);
9233 	    fd->file_list_items_size = items_len;
9234 	  }
9235       }
9236 
9237       /* make sure all the added sorter labels are correct, bg blue, and items active */
9238       if (fd->file_list_items_size > SORT_XEN)
9239 	{
9240 	  int k = SORT_XEN;
9241 
9242 	  /* sorters */
9243 	  for (i = 0; i < ss->file_sorters_size; i++)
9244 	    {
9245 	      if (!(Xen_is_false(Xen_vector_ref(ss->file_sorters, i))))
9246 		{
9247 		  set_label(fd->file_list_items[k], Xen_string_to_C_string(Xen_car(Xen_vector_ref(ss->file_sorters, i))));
9248 		  XtVaSetValues(fd->file_list_items[k],
9249 				XmNbackground, ss->lighter_blue,
9250 				XmNuserData, SORT_XEN + i,
9251 				NULL);
9252 		  if (!(XtIsManaged(fd->file_list_items[k])))
9253 		    XtManageChild(fd->file_list_items[k]);
9254 		  k++;
9255 		}
9256 	    }
9257 
9258 	  for (i = 0; i < ss->file_filters_size; i++)
9259 	    {
9260 	      if (!(Xen_is_false(Xen_vector_ref(ss->file_filters, i))))
9261 		{
9262 		  set_label(fd->file_list_items[k], Xen_string_to_C_string(Xen_car(Xen_vector_ref(ss->file_filters, i))));
9263 		  XtVaSetValues(fd->file_list_items[k], XmNbackground, ss->light_blue,
9264 				XmNuserData, i + FILE_FILTER_OFFSET,
9265 				NULL);
9266 		  if (!(XtIsManaged(fd->file_list_items[k])))
9267 		    XtManageChild(fd->file_list_items[k]);
9268 		  k++;
9269 		}
9270 	    }
9271 
9272 	  /* add "no filter" item if currently filtered */
9273 	  if (fd->fp->filter_choice != NO_FILE_FILTER)
9274 	    {
9275 	      set_label(fd->file_list_items[k], NO_FILTER_LABEL);
9276 	      XtVaSetValues(fd->file_list_items[k], XmNbackground, ss->light_blue,
9277 			    XmNuserData, NO_FILE_FILTER_OFFSET,
9278 			    NULL);
9279 	      if (!(XtIsManaged(fd->file_list_items[k])))
9280 		XtManageChild(fd->file_list_items[k]);
9281 	    }
9282 
9283 	}
9284       cb->menuToPost = fd->file_list_popup;
9285     }
9286 }
9287 
9288 
add_file_popups(file_popup_info * fd)9289 static void add_file_popups(file_popup_info *fd)
9290 {
9291   int n;
9292   Arg args[20];
9293 
9294   /* from lib/Xm.RCPopup.c:
9295    * When a user creates a new popup menu then we will install a particular
9296    * event handler on the menu's widget parent. Along with this we install
9297    * a grab on the button specified in XmNmenuPost or XmNwhichButton.   [XmNmenuPost is a string = translation table syntax, <Btn3Down> is default]
9298    *                                                                    [XmNwhichButton is obsolete]
9299    * The posting algorithm is as follows:
9300    *
9301    * 1. On receipt of a posting event, the handler will search the child
9302    * list for a candidate widget or gadget, and track the most specific
9303    * popup menu available (these can be found in the popup list). The
9304    * criteria for a match includes matching the XmNmenuPost information.
9305    *
9306    * 2. Matching criteria include:
9307    *
9308    *    * The menu must have XmNpopupEnabled set to either
9309    *      XmPOPUP_AUTOMATIC or XmPOPUP_AUTOMATIC_RECURSIVE.
9310    *
9311    *    * The popup menu is chosen according to creation order. If there is
9312    *      more than one, the first correct match is chosen.
9313    *
9314    *    * If the popup menu is found in a parent of the target widget, and
9315    *      the popup menu must also have XmNpopupEnabled set to
9316    *      XmPOPUP_AUTOMATIC_RECURSIVE to match.                         [sigh -- no one actually reads comments...]
9317    *
9318    * 3. Once a selection is made, if the menu's parent widget has a
9319    * popupHandlerCallback, it is invoked. The callback allows the user to
9320    * determine if a more specific menu is necessary, such as would be the
9321    * case in a graphical manipulation environment, and includes all the
9322    * necessary information.
9323    *
9324    */
9325 
9326   n = 0;
9327   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
9328   XtSetArg(args[n], XmNpopupEnabled, XmPOPUP_AUTOMATIC); n++;
9329 
9330   /* file text */
9331   XtAddCallback(FSB_BOX(fd->dialog, XmDIALOG_TEXT), XmNpopupHandlerCallback, file_text_popup_callback, (void *)fd);
9332   fd->file_text_popup = XmCreatePopupMenu(FSB_BOX(fd->dialog, XmDIALOG_TEXT), (char *)"file-text-popup", args, n);
9333   fd->file_text_names = make_filename_list();
9334   fd->file_text_popup_label = XtCreateManagedWidget(FILE_TEXT_POPUP_LABEL, xmLabelWidgetClass, fd->file_text_popup, args, n);
9335   XtCreateManagedWidget("sep", xmSeparatorWidgetClass, fd->file_text_popup, args, n);
9336 
9337   /* filter text */
9338   XtAddCallback(FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT), XmNpopupHandlerCallback, file_filter_popup_callback, (void *)fd);
9339   fd->file_filter_popup = XmCreatePopupMenu(FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT), (char *)"file-filter-popup", args, n);
9340   fd->file_filter_names = make_filename_list();
9341   fd->file_filter_popup_label = XtCreateManagedWidget(FILE_FILTER_POPUP_LABEL, xmLabelWidgetClass, fd->file_filter_popup, args, n);
9342   XtCreateManagedWidget("sep", xmSeparatorWidgetClass, fd->file_filter_popup, args, n);
9343   {
9344     char *startup_filter;
9345     startup_filter = XmTextFieldGetString(FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT));
9346     if (startup_filter)
9347       {
9348 	remember_filename(startup_filter, fd->file_filter_names);
9349 	XtFree(startup_filter);
9350       }
9351   }
9352   XtAddCallback(FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT), XmNactivateCallback, file_filter_text_activate_callback, (void *)fd);
9353 
9354   /* file directory */
9355   XtAddCallback(FSB_BOX(fd->dialog, XmDIALOG_DIR_LIST), XmNpopupHandlerCallback, file_dir_popup_callback, (void *)fd);
9356   fd->file_dir_popup = XmCreatePopupMenu(FSB_BOX(fd->dialog, XmDIALOG_DIR_LIST), (char *)"file-dir-popup", args, n);
9357   fd->file_dir_popup_label = XtCreateManagedWidget(FILE_DIR_POPUP_LABEL, xmLabelWidgetClass, fd->file_dir_popup, args, n);
9358   XtCreateManagedWidget("sep", xmSeparatorWidgetClass, fd->file_dir_popup, args, n);
9359 
9360   /* file list */
9361   XtAddCallback(FSB_BOX(fd->dialog, XmDIALOG_LIST), XmNpopupHandlerCallback, file_list_popup_callback, (void *)fd);
9362   fd->file_list_popup = XmCreatePopupMenu(FSB_BOX(fd->dialog, XmDIALOG_LIST), (char *)"file-list-popup", args, n);
9363   fd->file_list_popup_label = XtCreateManagedWidget(FILE_LIST_POPUP_LABEL, xmLabelWidgetClass, fd->file_list_popup, args, n);
9364   XtCreateManagedWidget("sep", xmSeparatorWidgetClass, fd->file_list_popup, args, n);
9365 }
9366 
9367 
9368 
9369 /* ---------------- just-sounds (file-filters) ---------------- */
9370 
file_change_directory_callback(Widget w,XtPointer context,XtPointer info)9371 static void file_change_directory_callback(Widget w, XtPointer context, XtPointer info)
9372 {
9373   /* click in directory list */
9374   file_pattern_info *fp = (file_pattern_info *)context;
9375   char *leaving_dir;
9376 
9377   {
9378     /* save current directory list position */
9379     position_t position = 0;
9380     XmString *strs = NULL;
9381     XtVaGetValues(w,
9382 		  XmNtopItemPosition, &position,
9383 		  XmNselectedItems, &strs,
9384 		  NULL);
9385     if ((strs) && (position > 1)) /* 1 = .. */
9386       {
9387 	char *filename = NULL;
9388 	filename = (char *)XmStringUnparse(strs[0], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
9389 	dirpos_update(fp->dir_list, filename, position);
9390 	XtFree(filename);
9391       }
9392   }
9393 
9394   leaving_dir = mus_strdup(fp->last_dir);
9395   if ((leaving_dir) &&
9396       (leaving_dir[strlen(leaving_dir) - 1] == '/'))
9397     leaving_dir[strlen(leaving_dir) - 1] = 0;
9398 
9399   fp->reread_directory = true;
9400   force_directory_reread_and_let_filename_change(fp->dialog);
9401   fp->reread_directory = false;
9402 
9403   if (leaving_dir)
9404     {
9405       position_t pos;
9406       pos = dirpos_list_top(fp->dir_list, leaving_dir);
9407       if (pos != POSITION_UNKNOWN)
9408 	XmListSetPos(w, pos);
9409       free(leaving_dir);
9410     }
9411 }
9412 
9413 
sort_files_and_redisplay(file_pattern_info * fp)9414 static void sort_files_and_redisplay(file_pattern_info *fp)
9415 {
9416   /* if just sorting, no need to read the directory */
9417   dir_info *cur_dir;
9418 
9419   cur_dir = fp->current_files;
9420   if (cur_dir->len > 0)
9421     {
9422       XmString *names;
9423       int i, new_selected_position = -1;
9424       char *selected_filename = NULL;
9425 
9426       {
9427 	XmString *strs = NULL;
9428 	int selections = 0;
9429 	XtVaGetValues(XmFileSelectionBoxGetChild(fp->dialog, XmDIALOG_LIST),
9430 		      XmNselectedItems, &strs,
9431 		      XmNselectedItemCount, &selections,
9432 		      NULL);
9433 	if ((selections > 0) && (strs) && (strs[0]))
9434 	  selected_filename = (char *)XmStringUnparse(strs[0], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
9435       }
9436 
9437       snd_sort(fp->sorter_choice, cur_dir->files, cur_dir->len);
9438 
9439       /* here we could use colored text to mark sound files, perhaps different colors for
9440        *   different chans (as in install-searcher-with-colors), but I would rather have
9441        *   used different background colors (less intrusive I think).  As far as I can tell,
9442        *   this is impossible given the current XmList widget -- each item is an internal
9443        *   "Element", not a label widget or whatever, and the selection color, for example,
9444        *   is done by hand.
9445        */
9446 
9447       names = (XmString *)calloc(cur_dir->len, sizeof(XmString));
9448       for (i = 0; i < cur_dir->len; i++)
9449 	{
9450 	  names[i] = XmStringCreateLocalized(cur_dir->files[i]->full_filename);
9451 	  if ((new_selected_position == -1) &&
9452 	      (mus_strcmp(selected_filename, cur_dir->files[i]->full_filename)))
9453 	    new_selected_position = i;
9454 	}
9455 
9456       XtVaSetValues(fp->dialog,
9457 		    XmNfileListItems, names,
9458 		    XmNfileListItemCount, cur_dir->len,
9459 		    XmNlistUpdated, true,
9460 		    NULL);
9461 
9462       if (new_selected_position >= 0)
9463 	ensure_list_row_visible(XmFileSelectionBoxGetChild(fp->dialog, XmDIALOG_LIST), new_selected_position);
9464 
9465       for (i = 0; i < cur_dir->len; i++)
9466 	if (names[i])
9467 	  XmStringFree(names[i]);
9468       free(names);
9469     }
9470   else
9471     {
9472       /* nothing to sort, but make sure the files list is actually empty */
9473       XtVaSetValues(fp->dialog,
9474 		    XmNfileListItems, NULL,
9475 		    XmNfileListItemCount, 0,
9476 		    XmNlistUpdated, true,
9477 		    NULL);
9478     }
9479 }
9480 
9481 
snd_directory_reader(Widget dialog,XmFileSelectionBoxCallbackStruct * info)9482 static void snd_directory_reader(Widget dialog, XmFileSelectionBoxCallbackStruct *info)
9483 {
9484   /* replaces the FSB searchProc */
9485   file_pattern_info *fp;
9486   dir_info *cur_dir = NULL;
9487   char *pattern = NULL, *our_dir = NULL;
9488 
9489   XtVaGetValues(dialog, XmNuserData, &fp, NULL);
9490   if (!(fp->dialog)) fp->dialog = dialog; /* can be null at initialization */
9491 
9492   pattern = (char *)XmStringUnparse(info->pattern, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
9493   our_dir = (char *)XmStringUnparse(info->dir,     NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
9494 
9495   /* get current directory contents, given filter and pattern */
9496   if (mus_strcmp(pattern, "*"))
9497     {
9498       if (fp->filter_choice == NO_FILE_FILTER)
9499 	cur_dir = find_files_in_dir(our_dir);
9500       else cur_dir = find_filtered_files_in_dir(our_dir, fp->filter_choice);
9501     }
9502   else cur_dir = find_filtered_files_in_dir_with_pattern(our_dir, fp->filter_choice, pattern);
9503 
9504   if (fp->current_files) free_dir_info(fp->current_files);
9505   fp->current_files = cur_dir;
9506   if (pattern) XtFree(pattern);
9507 
9508   /* set file_pattern_info->selected_filename list_slider_position from history */
9509   {
9510     position_t list_pos;
9511     Widget file_list;
9512     file_list = XmFileSelectionBoxGetChild(dialog, XmDIALOG_LIST);
9513     list_pos = dirpos_list_top(fp->dir_list, our_dir);
9514 
9515     /* post the sorted list in the dialog -- alphabetize by default */
9516     sort_files_and_redisplay(fp);
9517 
9518     if (list_pos != POSITION_UNKNOWN)
9519       XmListSetPos(file_list, list_pos);
9520   }
9521 
9522   if ((!fp->last_dir) ||
9523       (!mus_strcmp(our_dir, fp->last_dir)))
9524     {
9525       if (fp->directory_watcher)
9526 	unmonitor_file(fp->directory_watcher);
9527       fp->directory_watcher = NULL;
9528       if (fp->last_dir) free(fp->last_dir);
9529       fp->last_dir = mus_strdup(our_dir);
9530       fp->reread_directory = false;
9531     }
9532 
9533   if (our_dir) XtFree(our_dir);
9534 }
9535 
9536 
just_sounds_callback(Widget w,XtPointer context,XtPointer info)9537 static void just_sounds_callback(Widget w, XtPointer context, XtPointer info)
9538 {
9539   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
9540   file_pattern_info *fp = (file_pattern_info *)context;
9541   if (cb->set)
9542     fp->filter_choice = JUST_SOUNDS_FILTER;
9543   else fp->filter_choice = NO_FILE_FILTER;
9544   fp->in_just_sounds_update = true;
9545   force_directory_reread(fp->dialog);
9546   fp->in_just_sounds_update = false;
9547 }
9548 
9549 
9550 /* -------- play selected file handlers -------- */
9551 
9552 typedef struct {
9553   Widget dialog, play_button;
9554   snd_info *player;
9555 } dialog_play_info;
9556 
9557 
file_dialog_stop_playing(dialog_play_info * dp)9558 static void file_dialog_stop_playing(dialog_play_info *dp)
9559 {
9560 #if WITH_AUDIO
9561   if ((dp->player) &&
9562       (dp->player->playing))
9563     {
9564       stop_playing_sound(dp->player, PLAY_BUTTON_UNSET);
9565       dp->player = NULL;
9566     }
9567 #endif
9568 }
9569 
9570 
clear_deleted_snd_info(void * udp)9571 void clear_deleted_snd_info(void *udp)
9572 {
9573   dialog_play_info *dp = (dialog_play_info *)udp;
9574 #if WITH_AUDIO
9575   dp->player = NULL;
9576 #endif
9577 }
9578 
9579 
9580 #if WITH_AUDIO
play_selected_callback(Widget w,XtPointer context,XtPointer info)9581 static void play_selected_callback(Widget w, XtPointer context, XtPointer info)
9582 {
9583   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
9584   dialog_play_info *dp = (dialog_play_info *)context;
9585   if (cb->set)
9586     {
9587       Widget wtmp;
9588       char *filename = NULL;
9589       if ((dp->player) &&
9590 	  (dp->player->playing))
9591 	stop_playing_sound(dp->player, PLAY_BUTTON_UNSET);
9592       wtmp = FSB_BOX(dp->dialog, XmDIALOG_TEXT);
9593       filename = XmTextGetString(wtmp);
9594       if (filename)
9595 	{
9596 	  if (mus_file_probe(filename))
9597 	    {
9598 	      dp->player = make_sound_readable(filename, false);
9599 	      dp->player->delete_me = (void *)dp;
9600 	      if (dp->player)
9601 		play_sound(dp->player, 0, NO_END_SPECIFIED);
9602 	    }
9603 	  XtFree(filename);
9604 	}
9605     }
9606   else file_dialog_stop_playing(dp);
9607 }
9608 #endif
9609 
9610 
add_play_and_just_sounds_buttons(Widget dialog,Widget parent,file_pattern_info * fp,dialog_play_info * dp)9611 static void add_play_and_just_sounds_buttons(Widget dialog, Widget parent, file_pattern_info *fp, dialog_play_info *dp)
9612 {
9613   Widget rc;
9614   int n;
9615   Arg args[12];
9616 
9617   n = 0;
9618   XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
9619   rc = XtCreateManagedWidget("filebuttons-rc", xmRowColumnWidgetClass, parent, args, n);
9620 
9621   n = 0;
9622   XtSetArg(args[n], XmNset, just_sounds(ss)); n++;
9623   XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
9624   fp->just_sounds_button = XtCreateManagedWidget("sound files only", xmToggleButtonWidgetClass, rc, args, n);
9625   XtAddCallback(fp->just_sounds_button, XmNvalueChangedCallback, just_sounds_callback, (XtPointer)fp);
9626 
9627 #if WITH_AUDIO
9628   n = 0;
9629   XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
9630   XtSetArg(args[n], XmNwidth, 20); n++;
9631   XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
9632   XtCreateManagedWidget("sep1", xmSeparatorWidgetClass, rc, args, n);
9633 
9634   n = 0;
9635   /* XmNmarginLeft here refers to the space between the button and its label! */
9636   XtSetArg(args[n], XmNalignment, XmALIGNMENT_END); n++;
9637   dp->play_button = XtCreateWidget("play selected sound", xmToggleButtonWidgetClass, rc, args, n);
9638 
9639   XtAddCallback(dp->play_button, XmNvalueChangedCallback, play_selected_callback, (XtPointer)dp);
9640 #endif
9641 }
9642 
9643 
9644 
9645 /* -------- File Open/View/Mix Dialogs -------- */
9646 
9647 typedef struct file_dialog_info {
9648   read_only_t file_dialog_read_only;
9649   Widget dialog;
9650   Widget info_frame, info1, info2;     /* labels giving info on selected file, or an error message */
9651   file_pattern_info *fp;
9652   dialog_play_info *dp;
9653   void *unsound_directory_watcher; /* started if file doesn't exist, not a sound file, bogus header, etc (clears error msg if problem changed) */
9654   void *info_filename_watcher;     /* watch for change in selected file and repost info */
9655   char *unsound_dirname, *unsound_filename;
9656   char *info_filename;
9657   file_popup_info *fpop;
9658 } file_dialog_info;
9659 
9660 
open_file_help_callback(Widget w,XtPointer context,XtPointer info)9661 static void open_file_help_callback(Widget w, XtPointer context, XtPointer info)
9662 {
9663   open_file_dialog_help();
9664 }
9665 
9666 
file_cancel_callback(Widget w,XtPointer context,XtPointer info)9667 static void file_cancel_callback(Widget w, XtPointer context, XtPointer info)
9668 {
9669   file_dialog_stop_playing((dialog_play_info *)context);
9670   XtUnmanageChild (w);
9671 }
9672 
9673 
file_wm_delete_callback(Widget w,XtPointer context,XtPointer info)9674 static void file_wm_delete_callback(Widget w, XtPointer context, XtPointer info)
9675 {
9676   file_dialog_stop_playing((dialog_play_info *)context);
9677 }
9678 
9679 
post_sound_info(Widget info1,Widget info2,const char * filename,bool with_filename)9680 static void post_sound_info(Widget info1, Widget info2, const char *filename, bool with_filename)
9681 {
9682   /* filename is known[strongly believed] to be a sound file, etc */
9683   XmString label;
9684   char *buf;
9685   buf = (char *)calloc(LABEL_BUFFER_SIZE, sizeof(char));
9686   snprintf(buf, LABEL_BUFFER_SIZE, "%s%s%d chan%s, %d Hz, %.3f secs",
9687 	       (with_filename) ? filename_without_directory(filename) : "",
9688 	       (with_filename) ? ": " : "",
9689 	       mus_sound_chans(filename),
9690 	       (mus_sound_chans(filename) > 1) ? "s" : "",
9691 	       mus_sound_srate(filename),
9692 	       (double)mus_sound_duration(filename));
9693   label = XmStringCreateLocalized(buf);
9694   XtVaSetValues(info1,
9695 		XmNlabelString, label,
9696 		NULL);
9697   XmStringFree(label);
9698   snprintf(buf, LABEL_BUFFER_SIZE, "%s, %s%s",
9699 	       mus_header_type_name(mus_sound_header_type(filename)),
9700 	       short_sample_type_name(mus_sound_sample_type(filename), filename),
9701 	       snd_strftime(", %d-%b-%Y", mus_sound_write_date(filename)));
9702   label = XmStringCreateLocalized(buf);
9703   XtVaSetValues(info2, XmNlabelString, label, NULL);
9704   XmStringFree(label);
9705   free(buf);
9706 }
9707 
9708 
post_file_info(file_dialog_info * fd,const char * filename)9709 static void post_file_info(file_dialog_info *fd, const char *filename)
9710 {
9711 #if WITH_AUDIO
9712   XtManageChild(fd->dp->play_button);
9713 #endif
9714   post_sound_info(fd->info1, fd->info2, filename, true);
9715   if (!(XtIsManaged(fd->info1)))
9716     XtManageChild(fd->info1);
9717   if (!(XtIsManaged(fd->info2)))
9718     XtManageChild(fd->info2);
9719   if (!(XtIsManaged(fd->info_frame)))
9720     XtManageChild(fd->info_frame);
9721 }
9722 
9723 
unpost_file_info(file_dialog_info * fd)9724 static void unpost_file_info(file_dialog_info *fd)
9725 {
9726 #if WITH_AUDIO
9727   if (XtIsManaged(fd->dp->play_button))
9728     XtUnmanageChild(fd->dp->play_button);
9729 #endif
9730   if (XtIsManaged(fd->info_frame))
9731     XtUnmanageChild(fd->info_frame);
9732 
9733   if (fd->info_filename_watcher)
9734     {
9735       fd->info_filename_watcher = unmonitor_file(fd->info_filename_watcher);
9736       if (fd->info_filename) {free(fd->info_filename); fd->info_filename = NULL;}
9737     }
9738 }
9739 
9740 
is_empty_file(const char * filename)9741 static bool is_empty_file(const char *filename)
9742 {
9743 #ifndef _MSC_VER
9744   struct stat statbuf;
9745   if (stat(filename, &statbuf) >= 0)
9746     return(statbuf.st_size == (mus_long_t)0);
9747 #endif
9748   return(false);
9749 }
9750 
9751 
9752 static int local_error = MUS_NO_ERROR;
9753 static char *local_error_msg = NULL;
9754 static mus_error_handler_t *old_error_handler;
9755 
local_error2snd(int type,char * msg)9756 static void local_error2snd(int type, char *msg)
9757 {
9758   local_error = type;
9759   if (local_error_msg) free(local_error_msg);
9760   if (msg)
9761     local_error_msg = mus_strdup(msg);
9762   else local_error_msg = NULL;
9763 }
9764 
9765 
is_plausible_sound_file(const char * name)9766 static bool is_plausible_sound_file(const char *name)
9767 {
9768   int err = MUS_NO_ERROR;
9769   if (is_empty_file(name)) return(false);
9770   old_error_handler = mus_error_set_handler(local_error2snd);
9771   err = mus_header_read(name);
9772   mus_error_set_handler(old_error_handler);
9773   return((err == MUS_NO_ERROR) &&
9774 	 (mus_header_type() != MUS_RAW));
9775 }
9776 
9777 
file_dialog_select_callback(Widget w,XtPointer context,XtPointer info)9778 static void file_dialog_select_callback(Widget w, XtPointer context, XtPointer info)
9779 {
9780   file_dialog_info *fd = (file_dialog_info *)context;
9781   XmString *strs = NULL;
9782   XtVaGetValues(w, XmNselectedItems, &strs, NULL);
9783   if (strs) /* can be null if click in empty space */
9784     {
9785       char *filename;
9786       position_t position = 0;
9787       filename = (char *)XmStringUnparse(strs[0], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
9788       if (filename)
9789 	{
9790 	  if (is_plausible_sound_file(filename)) /* forces header read to avoid later unwanted error possibility */
9791 	    post_file_info(fd, filename);
9792 	  XtFree(filename);
9793 	}
9794       else unpost_file_info(fd);
9795 
9796       /* save current list position */
9797       XtVaGetValues(w, XmNtopItemPosition, &position, NULL);
9798       dirpos_update(fd->fp->dir_list, fd->fp->current_files->dir_name, position);
9799     }
9800 }
9801 
9802 
unpost_if_filter_changed(Widget w,XtPointer context,XtPointer info)9803 static void unpost_if_filter_changed(Widget w, XtPointer context, XtPointer info)
9804 {
9805   unpost_file_info((file_dialog_info *)context);
9806 }
9807 
9808 
watch_filename_change(Widget w,XtPointer context,XtPointer info)9809 static void watch_filename_change(Widget w, XtPointer context, XtPointer info)
9810 {
9811   /* try to move file list to show possible matches,
9812    *   if a sound file, show info
9813    */
9814   file_dialog_info *fd = (file_dialog_info *)context;
9815   char *filename = NULL;
9816 
9817   filename = XmTextGetString(w);
9818   if ((filename) && (*filename))
9819     {
9820       XmStringTable files;
9821       Widget file_list;
9822       int num_files = 0, pos = -1, l, u;
9823 
9824       file_list = FSB_BOX(fd->dialog, XmDIALOG_LIST);
9825       XtVaGetValues(fd->dialog,
9826 		    XmNfileListItemCount, &num_files,
9827 		    XmNfileListItems, &files, /* do not free */
9828 		    NULL);
9829       l = 0; /* hooray for Knuth... */
9830       u = num_files - 1;
9831       while (true)
9832 	{
9833 	  int i, comp;
9834 	  char *file_list_file = NULL;
9835 
9836 	  if (u < l) break;
9837 	  i = (l + u) / 2;
9838 	  file_list_file = (char *)XmStringUnparse(files[i], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); /* p453 */
9839 	  comp = strcmp(file_list_file, filename);
9840 	  XtFree(file_list_file);
9841 	  pos = i + 1;
9842 	  if (comp == 0)
9843 	    break;
9844 	  if (comp < 0) /* files[i] less than filename */
9845 	    l = i + 1;
9846 	  else u = i - 1;
9847 	}
9848       if (pos > 0)
9849 	ensure_list_row_visible(file_list, pos);
9850 
9851       if ((mus_file_probe(filename)) &&
9852 	  (!is_directory(filename)))
9853 	{
9854 	  if (is_sound_file(filename))
9855 	    post_file_info(fd, filename);
9856 	}
9857     }
9858   if (filename) XtFree(filename);
9859 }
9860 
9861 
focus_filename_text_callback(Widget w,XtPointer context,XtPointer info)9862 static void focus_filename_text_callback(Widget w, XtPointer context, XtPointer info)
9863 {
9864   XtAddCallback(w, XmNvalueChangedCallback, watch_filename_change, context);
9865 }
9866 
9867 
unfocus_filename_text_callback(Widget w,XtPointer context,XtPointer info)9868 static void unfocus_filename_text_callback(Widget w, XtPointer context, XtPointer info)
9869 {
9870   XtRemoveCallback(w, XmNvalueChangedCallback, watch_filename_change, context);
9871 }
9872 
9873 
file_is_directory(Widget dialog)9874 static bool file_is_directory(Widget dialog)
9875 {
9876   char *filename = NULL;
9877   bool is_dir = false;
9878   filename = XmTextGetString(FSB_BOX(dialog, XmDIALOG_TEXT));
9879   if (filename)
9880     {
9881       is_dir = is_directory(filename);
9882       XtFree(filename);
9883     }
9884   return(is_dir);
9885 }
9886 
9887 
file_is_nonexistent_directory(Widget dialog)9888 static bool file_is_nonexistent_directory(Widget dialog)
9889 {
9890   char *filename = NULL;
9891   bool is_nonexistent_dir = false;
9892   filename = XmTextGetString(FSB_BOX(dialog, XmDIALOG_TEXT));
9893   if (filename)
9894     {
9895       int len;
9896       len = strlen(filename);
9897       if ((!mus_file_probe(filename)) &&
9898 	  (filename[len - 1] == '/'))
9899 	{
9900 	  int i;
9901 	  /* check that there's some hope of making this directory */
9902 	  for (i = len - 2; i > 0; i--)
9903 	    if (filename[i] == '/')
9904 	      {
9905 		filename[i] = '\0';
9906 		is_nonexistent_dir = is_directory(filename);
9907 		break;
9908 	      }
9909 	}
9910       XtFree(filename);
9911     }
9912   return(is_nonexistent_dir);
9913 }
9914 
9915 
reflect_text_in_open_button(Widget w,XtPointer context,XtPointer info)9916 static void reflect_text_in_open_button(Widget w, XtPointer context, XtPointer info)
9917 {
9918   file_dialog_info *fd = (file_dialog_info *)context;
9919   /* w here is the text widget, not the button */
9920   XtSetSensitive(FSB_BOX(fd->dialog, XmDIALOG_OK_BUTTON), (!(file_is_directory(fd->dialog))));
9921 }
9922 
9923 
multifile_completer(widget_t w,void * data)9924 static void multifile_completer(widget_t w, void *data)
9925 {
9926   watch_filename_change(w, (XtPointer)data, NULL);
9927 }
9928 
9929 
9930 #define FILE_DIALOG_WIDTH 500
9931 #define FILE_DIALOG_HEIGHT 500
9932 
make_file_dialog(read_only_t read_only,char * title,char * select_title,XtCallbackProc file_ok_proc,XtCallbackProc file_help_proc)9933 static file_dialog_info *make_file_dialog(read_only_t read_only, char *title, char *select_title,
9934 					  XtCallbackProc file_ok_proc, XtCallbackProc file_help_proc)
9935 {
9936   /* file selection dialog box with added "Just Sound Files" and "Play selected" toggle buttons and info area,
9937    *   popups, and so on.  This applies to the Open, Mix, and Insert dialogs.  The save-as
9938    *   dialogs are handled by make_save_as_dialog below
9939    */
9940   Widget w;
9941   file_dialog_info *fd;
9942   Arg args[32];
9943   int n;
9944   XmString s1, s2, ok_label, filter_list_label, cancel_label;
9945   Widget wtmp = NULL, rc1, rc2;
9946 
9947   fd = (file_dialog_info *)calloc(1, sizeof(file_dialog_info));
9948   fd->fp = (file_pattern_info *)calloc(1, sizeof(file_pattern_info));
9949   fd->fp->in_just_sounds_update = false;
9950   if (just_sounds(ss))
9951     fd->fp->filter_choice = JUST_SOUNDS_FILTER;
9952   else fd->fp->filter_choice = NO_FILE_FILTER;
9953 
9954   fd->dp = (dialog_play_info *)calloc(1, sizeof(dialog_play_info));
9955   fd->file_dialog_read_only = read_only;
9956   fd->fpop = (file_popup_info *)calloc(1, sizeof(file_popup_info));
9957   fd->fpop->fp = fd->fp;
9958 
9959   fd->fp->dir_list = make_dirpos_list();
9960 
9961   w = main_shell(ss);
9962 
9963   s1 = XmStringCreateLocalized(select_title);
9964   s2 = XmStringCreateLocalized(title);
9965   ok_label = XmStringCreateLocalized(title);
9966   filter_list_label = XmStringCreateLocalized((char *)"files listed:");
9967   cancel_label = XmStringCreateLocalized((char *)I_GO_AWAY);
9968 
9969   n = 0;
9970   if (open_file_dialog_directory(ss))
9971     {
9972       XmString dirstr;
9973       dirstr = XmStringCreateLocalized(open_file_dialog_directory(ss));
9974       XtSetArg(args[n], XmNdirectory, dirstr); n++;
9975     }
9976   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
9977   XtSetArg(args[n], XmNokLabelString, ok_label); n++;
9978   XtSetArg(args[n], XmNselectionLabelString, s1); n++;                    /* "open", "mix", "insert", "open read-only:" */
9979   XtSetArg(args[n], XmNdialogTitle, s2); n++;
9980   XtSetArg(args[n], XmNfilterLabelString, filter_list_label); n++;        /* default label 'Filter' is confusing in this context */
9981   XtSetArg(args[n], XmNfileFilterStyle, XmFILTER_HIDDEN_FILES); n++;      /* the dot files mostly just get in the way */
9982   XtSetArg(args[n], XmNcancelLabelString, cancel_label); n++;
9983   XtSetArg(args[n], XmNuserData, (XtPointer)(fd->fp)); n++;
9984   XtSetArg(args[n], XmNfileSearchProc, snd_directory_reader); n++;        /* over-ride Motif's directory reader altogether */
9985   XtSetArg(args[n], XmNwidth, FILE_DIALOG_WIDTH); n++;
9986 
9987   XtSetArg(args[n], XmNheight, FILE_DIALOG_HEIGHT); n++;
9988   XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
9989   XtSetArg(args[n], XmNnoResize, false); n++;
9990 
9991   fd->dialog = XmCreateFileSelectionDialog(w, title, args, n);
9992   fd->fp->dialog = fd->dialog;
9993   fd->dp->dialog = fd->dialog;
9994   fd->fpop->dialog = fd->dialog;
9995 
9996   XtUnmanageChild(FSB_BOX(fd->dialog, XmDIALOG_DIR_LIST_LABEL)); /* these are obvious */
9997   XtUnmanageChild(FSB_BOX(fd->dialog, XmDIALOG_LIST_LABEL));
9998   XtUnmanageChild(FSB_BOX(fd->dialog, XmDIALOG_APPLY_BUTTON));   /* "Filter" button is useless */
9999 
10000   XtVaSetValues(FSB_BOX(fd->dialog, XmDIALOG_FILTER_LABEL), XmNbackground, ss->basic_color, NULL);
10001   XtVaSetValues(FSB_BOX(fd->dialog, XmDIALOG_SELECTION_LABEL), XmNbackground, ss->basic_color, NULL);
10002 
10003   XmStringFree(s1);
10004   XmStringFree(s2);
10005   XmStringFree(ok_label);
10006   XmStringFree(filter_list_label);
10007   XmStringFree(cancel_label);
10008 
10009   /* -------- play and just-sounds buttons and info area */
10010   rc1 = XtVaCreateManagedWidget("filebuttons-rc1",
10011 				xmRowColumnWidgetClass, fd->dialog,
10012 				XmNorientation, XmVERTICAL,
10013 				NULL);
10014 
10015   add_play_and_just_sounds_buttons(fd->dialog, rc1, fd->fp, fd->dp);
10016 
10017   fd->info_frame = XtVaCreateWidget("", xmFrameWidgetClass, rc1, NULL);
10018   rc2 = XtVaCreateManagedWidget("info-rc2",
10019 				xmRowColumnWidgetClass, fd->info_frame,
10020 				XmNorientation, XmVERTICAL,
10021 				XmNbackground, ss->highlight_color,
10022 				NULL);
10023   fd->info1 = XtVaCreateManagedWidget("", xmLabelWidgetClass, rc2, XmNbackground, ss->highlight_color, NULL);
10024   fd->info2 = XtVaCreateManagedWidget("", xmLabelWidgetClass, rc2, XmNbackground, ss->highlight_color, NULL);
10025 
10026 
10027   /* -------- Snd-like color schemes */
10028   color_file_selection_box(fd->dialog);
10029   XtVaSetValues(fd->fp->just_sounds_button, XmNselectColor, ss->selection_color, NULL);
10030 #if WITH_AUDIO
10031   XtVaSetValues(fd->dp->play_button, XmNselectColor, ss->selection_color, NULL);
10032 #endif
10033 
10034   /* -------- completions */
10035 
10036   wtmp = FSB_BOX(fd->dialog, XmDIALOG_TEXT);
10037   add_completer_to_builtin_textfield(wtmp, add_completer_func_with_multicompleter(sound_filename_completer, (void *)fd, multifile_completer));
10038 
10039   XtAddCallback(wtmp, XmNfocusCallback, focus_filename_text_callback, (XtPointer)fd);
10040   XtAddCallback(wtmp, XmNlosingFocusCallback, unfocus_filename_text_callback, (XtPointer)fd);
10041 
10042   wtmp = FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT);
10043   add_completer_to_builtin_textfield(wtmp, add_completer_func(filename_completer, NULL));
10044 
10045   XtAddCallback(wtmp, XmNvalueChangedCallback, unpost_if_filter_changed, (XtPointer)fd);
10046 
10047   /* -------- base button callbacks */
10048   XtAddCallback(fd->dialog, XmNokCallback, file_ok_proc, (XtPointer)fd);
10049   XtAddCallback(fd->dialog, XmNcancelCallback, file_cancel_callback, (XtPointer)(fd->dp));
10050   XtAddCallback(fd->dialog, XmNhelpCallback, file_help_proc, NULL);
10051   XtAddCallback(FSB_BOX(fd->dialog, XmDIALOG_LIST), XmNbrowseSelectionCallback, file_dialog_select_callback, (XtPointer)fd);
10052 
10053   /* -------- single click in directory list */
10054   XtAddCallback(FSB_BOX(fd->dialog, XmDIALOG_DIR_LIST), XmNbrowseSelectionCallback, file_change_directory_callback, (XtPointer)(fd->fp));
10055 
10056   /* -------- the WM 'close' button */
10057   {
10058     Atom wm_delete_window;
10059     wm_delete_window = XmInternAtom(main_display(ss), (char *)"WM_DELETE_WINDOW", false);
10060     XmAddWMProtocolCallback(XtParent(fd->dialog), wm_delete_window, file_wm_delete_callback, (XtPointer)(fd->dp));
10061   }
10062 
10063   /* -------- special popups */
10064   add_file_popups(fd->fpop);
10065 
10066   XtSetSensitive(FSB_BOX(fd->dialog, XmDIALOG_OK_BUTTON), (!(file_is_directory(fd->dialog))));
10067   XtAddCallback(FSB_BOX(fd->dialog, XmDIALOG_TEXT), XmNvalueChangedCallback, reflect_text_in_open_button, (void *)fd);
10068 
10069   return(fd);
10070 }
10071 
10072 
10073 /* -------- File:Open/View dialogs -------- */
10074 
10075 
file_open_error(const char * error_msg,file_dialog_info * fd)10076 static void file_open_error(const char *error_msg, file_dialog_info *fd)
10077 {
10078   XmString msg;
10079   msg = XmStringCreateLocalized((char *)error_msg);
10080   XtVaSetValues(fd->info1,
10081 		XmNlabelString, msg,
10082 		NULL);
10083   XmStringFree(msg);
10084 
10085   if (XtIsManaged(fd->info2))
10086     XtUnmanageChild(fd->info2);
10087   if (!(XtIsManaged(fd->info_frame)))
10088     XtManageChild(fd->info_frame);
10089 }
10090 
10091 
redirect_file_open_error(const char * error_msg,void * ufd)10092 static void redirect_file_open_error(const char *error_msg, void *ufd)
10093 {
10094   /* called from snd_error, redirecting error handling to the dialog */
10095   file_open_error(error_msg, (file_dialog_info *)ufd);
10096 }
10097 
10098 
10099 static void open_modify_callback(Widget w, XtPointer context, XtPointer info);
10100 
unpost_open_modify_error(file_dialog_info * fd)10101 static void unpost_open_modify_error(file_dialog_info *fd)
10102 {
10103   Widget dialog_filename_text;
10104   if (XtIsManaged(fd->info_frame))
10105     XtUnmanageChild(fd->info_frame);
10106   dialog_filename_text = FSB_BOX(fd->dialog, XmDIALOG_TEXT);
10107   if (dialog_filename_text)
10108     XtRemoveCallback(dialog_filename_text, XmNmodifyVerifyCallback, open_modify_callback, (XtPointer)fd);
10109 
10110   if (fd->unsound_directory_watcher)
10111     {
10112       fd->unsound_directory_watcher = unmonitor_file(fd->unsound_directory_watcher);
10113       if (fd->unsound_dirname) {free(fd->unsound_dirname); fd->unsound_dirname = NULL;}
10114       if (fd->unsound_filename) {free(fd->unsound_filename); fd->unsound_filename = NULL;}
10115     }
10116 }
10117 
10118 
open_modify_callback(Widget w,XtPointer context,XtPointer info)10119 static void open_modify_callback(Widget w, XtPointer context, XtPointer info)
10120 {
10121   file_dialog_info *fd = (file_dialog_info *)context;
10122   XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info;
10123   if (!(fd->fp->in_just_sounds_update)) /* auto trigger from just_sounds button -- unwanted! */
10124     unpost_open_modify_error(fd);
10125   cbs->doit = true; /* fixup filename elsewhere -- returning false here makes the thing beep! */
10126 }
10127 
10128 
clear_error_if_open_changes(Widget dialog,file_dialog_info * data)10129 static void clear_error_if_open_changes(Widget dialog, file_dialog_info *data)
10130 {
10131   Widget dialog_filename_text;
10132   dialog_filename_text = FSB_BOX(dialog, XmDIALOG_TEXT);
10133   if (dialog_filename_text)
10134     XtAddCallback(dialog_filename_text, XmNmodifyVerifyCallback, open_modify_callback, (XtPointer)data);
10135 }
10136 
10137 
file_open_ok_callback(Widget w,XtPointer context,XtPointer info)10138 static void file_open_ok_callback(Widget w, XtPointer context, XtPointer info)
10139 {
10140   file_dialog_info *fd = (file_dialog_info *)context;
10141   XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *)info;
10142   char *filename = NULL;
10143   if (XmGetFocusWidget(fd->dialog) == FSB_BOX(fd->dialog, XmDIALOG_FILTER_TEXT)) return;
10144 
10145   filename = (char *)XmStringUnparse(cbs->value, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
10146   if ((!filename) || (!(*filename)))
10147     {
10148       file_open_error("no filename given", fd);
10149       clear_error_if_open_changes(fd->dialog, fd);
10150     }
10151   else
10152     {
10153       file_dialog_stop_playing(fd->dp);
10154       if (!(is_directory(filename)))               /* this can be a directory name if the user clicked 'ok' when he meant 'cancel' */
10155 	{
10156 	  snd_info *sp;
10157 	  redirect_snd_error_to(redirect_file_open_error, (void *)fd);
10158 	  ss->requestor_dialog = w;
10159 	  ss->open_requestor = FROM_OPEN_DIALOG;
10160 	  ss->open_requestor_data = NULL;
10161 	  sp = snd_open_file(filename, fd->file_dialog_read_only);
10162 	  redirect_snd_error_to(NULL, NULL);
10163 	  if (sp)
10164 	    {
10165 	      XtUnmanageChild(w);
10166 	      remember_filename(filename, fd->fpop->file_text_names);
10167 	      select_channel(sp, 0);
10168 	    }
10169 	  else
10170 	    {
10171 	      if (ss->open_requestor != FROM_RAW_DATA_DIALOG)
10172 		{
10173 		  clear_error_if_open_changes(fd->dialog, fd);
10174 		  /* whatever the error was, I think it is correct here to unpost the error
10175 		   *   if the underlying file is either changed or created.
10176 		   */
10177 		}
10178 	    }
10179 	  if (filename) XtFree(filename);
10180 	}
10181       else
10182 	{
10183 	  char *str;
10184 	  str = mus_format("%s is a directory", filename);
10185 	  file_open_error(str, fd);
10186 	  clear_error_if_open_changes(fd->dialog, fd);
10187 	  free(str);
10188 	}
10189     }
10190 }
10191 
10192 
10193 static file_dialog_info *odat = NULL;
10194 
make_open_file_dialog(read_only_t read_only,bool managed)10195 widget_t make_open_file_dialog(read_only_t read_only, bool managed)
10196 {
10197   char *title, *select_title;
10198   if (read_only == FILE_READ_ONLY)
10199     {
10200       title = (char *)"View";
10201       select_title = (char *)"open read-only:";
10202     }
10203   else
10204     {
10205       title = (char *)"Open";
10206       select_title = (char *)"open:";
10207     }
10208   if (!odat)
10209     {
10210       XmString cancel_label;
10211       odat = make_file_dialog(read_only, title, select_title, file_open_ok_callback, open_file_help_callback);
10212       set_dialog_widget(FILE_OPEN_DIALOG, odat->dialog);
10213 
10214       /* now preload last n files opened before this point */
10215       preload_filenames(odat->fpop->file_text_names);
10216 
10217       cancel_label = XmStringCreateLocalized((char *)I_GO_AWAY);
10218       XtVaSetValues(odat->dialog, XmNcancelLabelString, cancel_label, NULL);
10219       XmStringFree(cancel_label);
10220     }
10221   else
10222     {
10223       if (odat->file_dialog_read_only != read_only)
10224 	{
10225 	  XmString s1, s2;
10226 	  s1 = XmStringCreateLocalized(select_title);
10227 	  s2 = XmStringCreateLocalized(title);
10228 	  XtVaSetValues(odat->dialog,
10229 			XmNselectionLabelString, s1,
10230 			XmNdialogTitle, s2,
10231 			XmNokLabelString, s2, /* "ok" button label can be either "View" or "Open" */
10232 			NULL);
10233 	  XmStringFree(s1);
10234 	  XmStringFree(s2);
10235 	}
10236       odat->file_dialog_read_only = read_only;
10237       if (odat->fp->reread_directory)
10238 	{
10239 	  force_directory_reread(odat->dialog);
10240 	  odat->fp->reread_directory = false;
10241 	}
10242     }
10243   if ((managed) && (!(XtIsManaged(odat->dialog))))
10244     XtManageChild(odat->dialog);
10245 
10246   return(odat->dialog);
10247 }
10248 
10249 
10250 
10251 /* -------- File:Mix dialog -------- */
10252 
file_mix_ok_callback(Widget w,XtPointer context,XtPointer info)10253 static void file_mix_ok_callback(Widget w, XtPointer context, XtPointer info)
10254 {
10255   XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *)info;
10256   file_dialog_info *fd = (file_dialog_info *)context;
10257   char *filename = NULL;
10258 
10259   filename = (char *)XmStringUnparse(cbs->value, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
10260   if ((!filename) || (!(*filename)))
10261     {
10262       file_open_error("no filename given", fd);
10263       clear_error_if_open_changes(fd->dialog, fd);
10264     }
10265   else
10266     {
10267       file_dialog_stop_playing(fd->dp);
10268       if (!(is_directory(filename)))               /* this can be a directory name if the user clicked 'ok' when he meant 'cancel' */
10269 	{
10270 	  int id_or_error;
10271 	  snd_info *sp;
10272 	  sp = any_selected_sound();
10273 	  redirect_snd_error_to(redirect_file_open_error, (void *)fd);
10274 	  ss->requestor_dialog = w;
10275 	  ss->open_requestor = FROM_MIX_DIALOG;
10276 	  ss->open_requestor_data = NULL;
10277 	  id_or_error = mix_complete_file_at_cursor(sp, filename);
10278 	  /* "id_or_error" here is either one of the mix id's or an error indication such as MIX_FILE_NO_MIX */
10279 	  /*    the possible error conditions have been checked already, or go through snd_error */
10280 	  redirect_snd_error_to(NULL, NULL);
10281 	  if (id_or_error < 0) /* actually -1 .. -3 */
10282 	    {
10283 	      if (ss->open_requestor != FROM_RAW_DATA_DIALOG)
10284 		{
10285 		  clear_error_if_open_changes(fd->dialog, fd);
10286 		}
10287 	    }
10288 	  else
10289 	    {
10290 	      status_report(sp, "%s mixed in at cursor", filename);
10291 	      remember_filename(filename, fd->fpop->file_text_names);
10292 	    }
10293 	  if (filename) XtFree(filename);
10294 	}
10295       else
10296 	{
10297 	  char *str;
10298 	  str = mus_format("%s is a directory", filename);
10299 	  file_open_error(str, fd);
10300 	  clear_error_if_open_changes(fd->dialog, fd);
10301 	  free(str);
10302 	}
10303     }
10304 }
10305 
10306 
mix_file_help_callback(Widget w,XtPointer context,XtPointer info)10307 static void mix_file_help_callback(Widget w, XtPointer context, XtPointer info)
10308 {
10309   mix_file_dialog_help();
10310 }
10311 
10312 
10313 static file_dialog_info *mdat = NULL;
10314 
mix_open_file_watcher(Xen hook_or_reason)10315 static Xen mix_open_file_watcher(Xen hook_or_reason)
10316 {
10317   if ((mdat->dialog) &&
10318       (XtIsManaged(mdat->dialog)))
10319     set_sensitive(FSB_BOX(mdat->dialog, XmDIALOG_OK_BUTTON), (bool)any_selected_sound());
10320   return(Xen_false);
10321 }
10322 
10323 static void add_reflect_mix_hook(void);
10324 
make_mix_file_dialog(bool managed)10325 widget_t make_mix_file_dialog(bool managed)
10326 {
10327   /* called from the menu */
10328   if (!mdat)
10329     {
10330       mdat = make_file_dialog(FILE_READ_ONLY, (char *)"Mix Sound", (char *)"mix in:", file_mix_ok_callback, mix_file_help_callback);
10331       set_dialog_widget(FILE_MIX_DIALOG, mdat->dialog);
10332       add_reflect_mix_hook();
10333     }
10334   else
10335     {
10336       if (mdat->fp->reread_directory)
10337 	{
10338 	  force_directory_reread(mdat->dialog);
10339 	  mdat->fp->reread_directory = false;
10340 	}
10341     }
10342   if ((managed) && (!XtIsManaged(mdat->dialog)))
10343     XtManageChild(mdat->dialog);
10344   return(mdat->dialog);
10345 }
10346 
10347 
10348 /* -------- File:Insert dialog -------- */
10349 
file_insert_ok_callback(Widget w,XtPointer context,XtPointer info)10350 static void file_insert_ok_callback(Widget w, XtPointer context, XtPointer info)
10351 {
10352   XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *)info;
10353   file_dialog_info *fd = (file_dialog_info *)context;
10354   char *filename = NULL;
10355 
10356   filename = (char *)XmStringUnparse(cbs->value, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
10357   if ((!filename) || (!(*filename)))
10358     {
10359       file_open_error("no filename given", fd);
10360       clear_error_if_open_changes(fd->dialog, fd);
10361     }
10362   else
10363     {
10364       file_dialog_stop_playing(fd->dp);
10365       if (!(is_directory(filename)))               /* this can be a directory name if the user clicked 'ok' when he meant 'cancel' */
10366 	{
10367 	  bool ok;
10368 	  snd_info *sp;
10369 	  sp = any_selected_sound();
10370 	  ss->requestor_dialog = w;
10371 	  ss->open_requestor = FROM_INSERT_DIALOG;
10372 	  ss->open_requestor_data = NULL;
10373 	  redirect_snd_error_to(redirect_file_open_error, (void *)fd);
10374 	  ok = insert_complete_file_at_cursor(sp, filename);
10375 	  redirect_snd_error_to(NULL, NULL);
10376 	  if (!ok)
10377 	    {
10378 	      if (ss->open_requestor != FROM_RAW_DATA_DIALOG)
10379 		{
10380 		  clear_error_if_open_changes(fd->dialog, fd);
10381 		  /* ideally insert_complete_file would return an indication of what the error was... */
10382 		}
10383 	    }
10384 	  else
10385 	    {
10386 	      status_report(sp, "%s inserted at cursor", filename);
10387 	      remember_filename(filename, fd->fpop->file_text_names);
10388 	    }
10389 	  if (filename) XtFree(filename);
10390 	}
10391       else
10392 	{
10393 	  char *str;
10394 	  str = mus_format("%s is a directory", filename);
10395 	  file_open_error(str, fd);
10396 	  clear_error_if_open_changes(fd->dialog, fd);
10397 	  free(str);
10398 	}
10399     }
10400 }
10401 
10402 
insert_file_help_callback(Widget w,XtPointer context,XtPointer info)10403 static void insert_file_help_callback(Widget w, XtPointer context, XtPointer info)
10404 {
10405   insert_file_dialog_help();
10406 }
10407 
10408 
10409 static file_dialog_info *idat = NULL;
10410 
insert_open_file_watcher(Xen hook_or_reason)10411 static Xen insert_open_file_watcher(Xen hook_or_reason)
10412 {
10413   if ((idat->dialog) &&
10414       (XtIsManaged(idat->dialog)))
10415     set_sensitive(FSB_BOX(idat->dialog, XmDIALOG_OK_BUTTON), (bool)any_selected_sound());
10416   return(Xen_false);
10417 }
10418 
10419 static void add_reflect_insert_hook(void);
10420 
make_insert_file_dialog(bool managed)10421 widget_t make_insert_file_dialog(bool managed)
10422 {
10423   if (!idat)
10424     {
10425       idat = make_file_dialog(FILE_READ_ONLY, (char *)"Insert Sound", (char *)"insert:", file_insert_ok_callback, insert_file_help_callback);
10426       set_dialog_widget(FILE_INSERT_DIALOG, idat->dialog);
10427       add_reflect_insert_hook();
10428     }
10429   else
10430     {
10431       if (idat->fp->reread_directory)
10432 	{
10433 	  force_directory_reread(idat->dialog);
10434 	  idat->fp->reread_directory = false;
10435 	}
10436     }
10437   if ((managed) && (!XtIsManaged(idat->dialog)))
10438     XtManageChild(idat->dialog);
10439   return(idat->dialog);
10440 }
10441 
10442 
10443 /* -------- reflect outside changes -------- */
10444 
set_open_file_play_button(bool val)10445 void set_open_file_play_button(bool val)
10446 {
10447 #if WITH_AUDIO
10448   if ((odat) && (odat->dp->play_button))
10449     XmToggleButtonSetState(odat->dp->play_button, (Boolean)val, false);
10450   if ((mdat) && (mdat->dp->play_button))
10451     XmToggleButtonSetState(mdat->dp->play_button, (Boolean)val, false);
10452   if ((idat) && (idat->dp->play_button))
10453     XmToggleButtonSetState(idat->dp->play_button, (Boolean)val, false);
10454 #endif
10455 }
10456 
10457 
alert_new_file(void)10458 void alert_new_file(void)
10459 {
10460   if (ss->file_monitor_ok) return;
10461   /* ideally this would include the save-as dialogs */
10462   if (odat)
10463     {
10464       odat->fp->reread_directory = true;
10465       if (XtIsManaged(odat->dialog))
10466 	{
10467 	  force_directory_reread(odat->dialog);
10468 	  odat->fp->reread_directory = false;
10469 	}
10470     }
10471   if (mdat)
10472     {
10473       mdat->fp->reread_directory = true;
10474       if (XtIsManaged(mdat->dialog))
10475 	{
10476 	  force_directory_reread(mdat->dialog);
10477 	  mdat->fp->reread_directory = false;
10478 	}
10479     }
10480   if (idat)
10481     {
10482       idat->fp->reread_directory = true;
10483       if (XtIsManaged(idat->dialog))
10484 	{
10485 	  force_directory_reread(idat->dialog);
10486 	  idat->fp->reread_directory = false;
10487 	}
10488     }
10489 }
10490 
10491 
reflect_just_sounds(void)10492 void reflect_just_sounds(void)
10493 {
10494   if ((odat) && (odat->fp->just_sounds_button))
10495     XmToggleButtonSetState(odat->fp->just_sounds_button, just_sounds(ss), true);
10496   if ((mdat) && (mdat->fp->just_sounds_button))
10497     XmToggleButtonSetState(mdat->fp->just_sounds_button, just_sounds(ss), true);
10498   if ((idat) && (idat->fp->just_sounds_button))
10499     XmToggleButtonSetState(idat->fp->just_sounds_button, just_sounds(ss), true);
10500 }
10501 
10502 
10503 
10504 /* ---------------- file data panel ---------------- */
10505 
10506 #define NUM_VISIBLE_HEADERS 5
10507 
get_file_dialog_sound_attributes(file_data * fdat,int * srate,int * chans,mus_header_t * header_type,mus_sample_t * sample_type,mus_long_t * location,mus_long_t * samples,int min_chan)10508 char *get_file_dialog_sound_attributes(file_data *fdat, int *srate, int *chans, mus_header_t *header_type,
10509 				       mus_sample_t *sample_type, mus_long_t *location, mus_long_t *samples, int min_chan)
10510 {
10511   char *str;
10512   int n;
10513   int res;
10514   int *ns = NULL;
10515   fdat->error_widget = NOT_A_SCANF_WIDGET;
10516   fdat->scanf_widget = NOT_A_SCANF_WIDGET;
10517 
10518   if ((srate) && (fdat->srate_text))
10519     {
10520       str = XmTextGetString(fdat->srate_text);
10521       fdat->scanf_widget = SRATE_WIDGET;
10522       if ((str) && (*str))
10523 	{
10524 	  (*srate) = string_to_int(str, 1, "srate");
10525 	  XtFree(str);
10526 	}
10527       else snd_error_without_format("no srate?");
10528     }
10529 
10530   if ((chans) && (fdat->chans_text))
10531     {
10532       str = XmTextGetString(fdat->chans_text);
10533       fdat->scanf_widget = CHANS_WIDGET;
10534       if ((str) && (*str))
10535 	{
10536 	  (*chans) = string_to_int(str, min_chan, "chans");
10537 	  XtFree(str);
10538 	}
10539       else
10540 	{
10541 	  if (min_chan > 0)
10542 	    snd_error_without_format("no chans?");
10543 	}
10544     }
10545 
10546   if ((location) && (fdat->location_text))
10547     {
10548       str = XmTextGetString(fdat->location_text);
10549       fdat->scanf_widget = DATA_LOCATION_WIDGET;
10550       if ((str) && (*str))
10551 	{
10552 	  (*location) = string_to_mus_long_t(str, 0, "data location");
10553 	  XtFree(str);
10554 	}
10555       else snd_error_without_format("no data location?");
10556     }
10557 
10558   if ((samples) && (fdat->samples_text))
10559     {
10560       str = XmTextGetString(fdat->samples_text);
10561       fdat->scanf_widget = SAMPLES_WIDGET;
10562       if ((str) && (*str))
10563 	{
10564 	  (*samples) = string_to_mus_long_t(str, 0, "samples");
10565 	  XtFree(str);
10566 	}
10567       else snd_error_without_format("no samples?");
10568     }
10569   fdat->scanf_widget = SAMPLES_WIDGET;
10570 
10571   if ((header_type) && (fdat->header_type_list))
10572     {
10573       res = XmListGetSelectedPos(fdat->header_type_list, &ns, &n);
10574       if (res)
10575 	{
10576 	  (*header_type) = position_to_header_type(ns[0] - 1);
10577 	  fdat->current_header_type = (*header_type);
10578 	  free(ns);
10579 	  ns = NULL;
10580 	}
10581     }
10582 
10583   if ((sample_type) && (fdat->sample_type_list))
10584     {
10585       res = XmListGetSelectedPos(fdat->sample_type_list, &ns, &n);
10586       if (res)
10587 	{
10588 	  (*sample_type) = position_to_sample_type(fdat->current_header_type, ns[0] - 1);
10589 	  fdat->current_sample_type = (*sample_type);
10590 	  free(ns);
10591 	  ns = NULL;
10592 	}
10593     }
10594 
10595   if (fdat->comment_text)
10596     {
10597       char *comment = NULL;
10598       comment = XmTextGetString(fdat->comment_text);
10599       if (comment)
10600 	{
10601 	  str = mus_strdup(comment);
10602 	  XtFree(comment);
10603 	  return(str);
10604 	}
10605     }
10606 
10607   return(NULL);
10608 }
10609 
10610 
10611 #define IGNORE_DATA_LOCATION -1
10612 #define IGNORE_SAMPLES MUS_UNKNOWN_SAMPLE
10613 #define IGNORE_CHANS -1
10614 #define IGNORE_SRATE -1
10615 #define IGNORE_HEADER_TYPE MUS_UNKNOWN_HEADER
10616 
set_file_dialog_sound_attributes(file_data * fdat,mus_header_t header_type,mus_sample_t sample_type,int srate,int chans,mus_long_t location,mus_long_t samples,char * comment)10617 static void set_file_dialog_sound_attributes(file_data *fdat, mus_header_t header_type, mus_sample_t sample_type,
10618 					     int srate, int chans, mus_long_t location, mus_long_t samples, char *comment)
10619 {
10620   int i;
10621   const char **fl = NULL;
10622   XmString *strs;
10623 
10624   if (header_type != IGNORE_HEADER_TYPE)
10625     fdat->current_header_type = header_type;
10626   else fdat->current_header_type = MUS_RAW;
10627   fdat->current_sample_type = sample_type;
10628   fl = header_type_and_sample_type_to_position(fdat, fdat->current_header_type, fdat->current_sample_type);
10629   if (!fl) return;
10630 
10631   if ((header_type != IGNORE_HEADER_TYPE) &&
10632       (fdat->header_type_list))
10633     {
10634       XmListSelectPos(fdat->header_type_list, fdat->header_type_pos + 1, false);
10635       ensure_list_row_visible(fdat->header_type_list, fdat->header_type_pos + 1);
10636     }
10637 
10638   strs = (XmString *)malloc(fdat->sample_types * sizeof(XmString));
10639   for (i = 0; i < fdat->sample_types; i++)
10640     strs[i] = XmStringCreateLocalized((char *)fl[i]);
10641   XtVaSetValues(fdat->sample_type_list,
10642 		XmNitems, strs,
10643 		XmNitemCount, fdat->sample_types,
10644 		NULL);
10645   for (i = 0; i < fdat->sample_types; i++)
10646     XmStringFree(strs[i]);
10647   free(strs);
10648   XmListSelectPos(fdat->sample_type_list, fdat->sample_type_pos + 1, false);
10649   ensure_list_row_visible(fdat->sample_type_list, fdat->sample_type_pos + 1);
10650 
10651   if ((srate != IGNORE_SRATE) &&
10652       (fdat->srate_text))
10653     widget_int_to_text(fdat->srate_text, srate);
10654 
10655   if ((chans != IGNORE_CHANS) &&
10656       (fdat->chans_text))
10657     widget_int_to_text(fdat->chans_text, chans);
10658 
10659   if (fdat->comment_text)
10660     XmTextSetString(fdat->comment_text, comment);
10661 
10662   if ((location != IGNORE_DATA_LOCATION) &&
10663       (fdat->location_text))
10664     widget_mus_long_t_to_text(fdat->location_text, location);
10665 
10666   if ((samples != IGNORE_SAMPLES) &&
10667       (fdat->samples_text))
10668     widget_mus_long_t_to_text(fdat->samples_text, samples);
10669 }
10670 
10671 
10672 /* -------- error handling -------- */
10673 
10674 /* if an error occurs, a callback is added to the offending text widget, and an error is
10675  *   posted in the error_text label.  When the user modifies the bad entry, the callback
10676  *   erases the error message, and removes itself from the text widget.
10677  */
10678 
clear_dialog_error(file_data * fd)10679 static void clear_dialog_error(file_data *fd)
10680 {
10681   if (XtIsManaged(fd->error_text))
10682     {
10683       XtUnmanageChild(fd->error_text);
10684       if (fd->comment_text)
10685 	{
10686 	  XtVaSetValues(fd->comment_text,
10687 			XmNbottomAttachment, XmATTACH_FORM,
10688 			NULL);
10689 	}
10690     }
10691 }
10692 
10693 
show_dialog_error(file_data * fd)10694 static void show_dialog_error(file_data *fd)
10695 {
10696   if (!(XtIsManaged(fd->error_text)))
10697     {
10698       if (fd->comment_text)
10699 	{
10700 	  XtVaSetValues(fd->comment_text,
10701 			XmNbottomAttachment, XmATTACH_WIDGET,
10702 			XmNbottomWidget, fd->error_text,
10703 			NULL);
10704 	}
10705       XtManageChild(fd->error_text);
10706     }
10707 }
10708 
10709 
post_file_dialog_error(const char * error_msg,file_data * fd)10710 static void post_file_dialog_error(const char *error_msg, file_data *fd)
10711 {
10712   XmString msg;
10713   msg = XmStringCreateLocalized((char *)error_msg);
10714   XtVaSetValues(fd->error_text,
10715 		XmNbackground, ss->yellow,
10716 		XmNlabelString, msg,
10717 		NULL);
10718   XmStringFree(msg);
10719   show_dialog_error(fd);
10720 }
10721 
10722 
redirect_post_file_dialog_error(const char * error_msg,void * ufd)10723 static void redirect_post_file_dialog_error(const char *error_msg, void *ufd)
10724 {
10725   post_file_dialog_error(error_msg, (file_data *)ufd);
10726 }
10727 
10728 
filename_modify_callback(Widget w,XtPointer context,XtPointer info)10729 static void filename_modify_callback(Widget w, XtPointer context, XtPointer info)
10730 {
10731   file_data *fd = (file_data *)context;
10732   XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info;
10733   Widget dialog_filename_text;
10734   clear_dialog_error(fd);
10735   dialog_filename_text = FSB_BOX(fd->dialog, XmDIALOG_TEXT);
10736   if (dialog_filename_text) XtRemoveCallback(dialog_filename_text, XmNmodifyVerifyCallback, filename_modify_callback, context);
10737   cbs->doit = true;
10738 }
10739 
10740 
clear_error_if_filename_changes(Widget dialog,file_data * data)10741 static void clear_error_if_filename_changes(Widget dialog, file_data *data)
10742 {
10743   Widget dialog_filename_text;
10744   dialog_filename_text = FSB_BOX(dialog, XmDIALOG_TEXT);
10745   if (dialog_filename_text)
10746     XtAddCallback(dialog_filename_text, XmNmodifyVerifyCallback, filename_modify_callback, (XtPointer)data);
10747 }
10748 
10749 
chans_modify_callback(Widget w,XtPointer context,XtPointer info)10750 static void chans_modify_callback(Widget w, XtPointer context, XtPointer info)
10751 {
10752   file_data *fd = (file_data *)context;
10753   XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info;
10754   clear_dialog_error(fd);
10755   XtRemoveCallback(fd->chans_text, XmNmodifyVerifyCallback, chans_modify_callback, context);
10756   cbs->doit = true;
10757 }
10758 
10759 
clear_error_if_chans_changes(Widget dialog,file_data * fd)10760 static void clear_error_if_chans_changes(Widget dialog, file_data *fd)
10761 {
10762   if (fd->chans_text) XtAddCallback(fd->chans_text, XmNmodifyVerifyCallback, chans_modify_callback, (XtPointer)fd);
10763 }
10764 
10765 
panel_modify_callback(Widget w,XtPointer context,XtPointer info)10766 static void panel_modify_callback(Widget w, XtPointer context, XtPointer info)
10767 {
10768   file_data *fd = (file_data *)context;
10769   XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info;
10770   clear_dialog_error(fd);
10771   XtRemoveCallback(w, XmNmodifyVerifyCallback, panel_modify_callback, context);
10772   cbs->doit = true;
10773 }
10774 
10775 
clear_error_if_panel_changes(Widget dialog,file_data * fd)10776 static void clear_error_if_panel_changes(Widget dialog, file_data *fd)
10777 {
10778   Widget baddy;
10779   switch (fd->error_widget)
10780     {
10781     case SRATE_WIDGET:         baddy = fd->srate_text;    break;
10782     case DATA_LOCATION_WIDGET: baddy = fd->location_text; break;
10783     case SAMPLES_WIDGET:       baddy = fd->samples_text;  break;
10784     default:                   baddy = fd->chans_text;    break;
10785     }
10786   if (baddy) XtAddCallback(baddy, XmNmodifyVerifyCallback, panel_modify_callback, (XtPointer)fd);
10787 }
10788 
10789 
post_file_panel_error(const char * error_msg,void * ufd)10790 static void post_file_panel_error(const char *error_msg, void *ufd)
10791 {
10792   file_data *fd = (file_data *)ufd;
10793   fd->error_widget = fd->scanf_widget;
10794   post_file_dialog_error(error_msg, fd);
10795 }
10796 
10797 
file_data_type_callback(Widget w,XtPointer context,XtPointer info)10798 static void file_data_type_callback(Widget w, XtPointer context, XtPointer info)
10799 {
10800   int pos;
10801   XmListCallbackStruct *cbs = (XmListCallbackStruct *)info;
10802   file_data *fd;
10803 
10804   XtVaGetValues(w, XmNuserData, &fd, NULL);
10805   pos = cbs->item_position - 1;
10806   if (position_to_header_type(pos) != fd->current_header_type)
10807     {
10808       position_to_header_type_and_sample_type(fd, pos);
10809       set_file_dialog_sound_attributes(fd,
10810 				       fd->current_header_type,
10811 				       fd->current_sample_type,
10812 				       IGNORE_SRATE, IGNORE_CHANS, IGNORE_DATA_LOCATION, IGNORE_SAMPLES,
10813 				       NULL);
10814     }
10815 }
10816 
10817 
file_sample_type_callback(Widget w,XtPointer context,XtPointer info)10818 static void file_sample_type_callback(Widget w, XtPointer context, XtPointer info)
10819 {
10820   XmListCallbackStruct *cbs = (XmListCallbackStruct *)info;
10821   file_data *fd;
10822   XtVaGetValues(w, XmNuserData, &fd, NULL);
10823   fd->current_sample_type = position_to_sample_type(fd->current_header_type, cbs->item_position - 1);
10824 }
10825 
10826 
file_data_src_callback(Widget w,XtPointer context,XtPointer info)10827 static void file_data_src_callback(Widget w, XtPointer context, XtPointer info)
10828 {
10829   file_data *fd = (file_data *)context;
10830   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
10831   fd->src = cb->set;
10832 }
10833 
10834 
file_data_auto_comment_callback(Widget w,XtPointer context,XtPointer info)10835 static void file_data_auto_comment_callback(Widget w, XtPointer context, XtPointer info)
10836 {
10837   file_data *fd = (file_data *)context;
10838   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
10839   fd->auto_comment = cb->set;
10840 }
10841 
10842 
10843 
10844 /* ---------------- File Data Panel ---------------- */
10845 
10846 
10847 #define PANEL_COMMENT_SPACE 16
10848 #define WITHOUT_AUTO_COMMENT false
10849 #define WITH_SRATE true
10850 #define WITHOUT_SRATE false
10851 
10852 
make_file_data_panel(Widget parent,const char * name,Arg * in_args,int in_n,dialog_channels_t with_chan,mus_header_t header_type,mus_sample_t sample_type,dialog_data_location_t with_loc,dialog_samples_t with_samples,dialog_header_type_t with_header_type,dialog_comment_t with_comment,header_choice_t header_choice,bool with_src,bool with_auto_comment)10853 static file_data *make_file_data_panel(Widget parent, const char *name, Arg *in_args, int in_n,
10854 				       dialog_channels_t with_chan,
10855 				       mus_header_t header_type,
10856 				       mus_sample_t sample_type,
10857 				       dialog_data_location_t with_loc,
10858 				       dialog_samples_t with_samples,
10859 				       dialog_header_type_t with_header_type,
10860 				       dialog_comment_t with_comment,
10861 				       header_choice_t header_choice,
10862 				       bool with_src, bool with_auto_comment)
10863 {
10864   Widget form, header_label, data_label, srate_label, chans_label, sep1, sep2 = NULL, sep3, sep4;
10865   Widget comment_label = NULL, location_label, samples_label;
10866   file_data *fdat;
10867   Arg args[32];
10868   int i, n;
10869   XmString *strs;
10870   int nsample_types = 0, nheaders = 0;
10871   const char **sample_types = NULL, **header_types = NULL;
10872 
10873   switch (header_choice)
10874     {
10875     case WITH_READABLE_HEADERS: header_types = short_readable_headers(&nheaders); break;
10876     case WITH_WRITABLE_HEADERS: header_types = short_writable_headers(&nheaders); break;
10877     case WITH_BUILTIN_HEADERS:  header_types = short_builtin_headers(&nheaders);  break;
10878     }
10879 
10880   fdat = (file_data *)calloc(1, sizeof(file_data));
10881   fdat->src = save_as_dialog_src(ss);
10882   fdat->auto_comment = save_as_dialog_auto_comment(ss);
10883   fdat->saved_comment = NULL;
10884   fdat->current_header_type = header_type;
10885   fdat->current_sample_type = sample_type;
10886   sample_types = header_type_and_sample_type_to_position(fdat, header_type, sample_type);
10887   nsample_types = fdat->sample_types;
10888 
10889   /* pick up all args from caller -- args here are attachment points */
10890   form = XtCreateManagedWidget(name, xmFormWidgetClass, parent, in_args, in_n);
10891 
10892   if (with_header_type == WITH_HEADER_TYPE_FIELD)
10893     {
10894       n = 0;
10895       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
10896       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
10897       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
10898       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
10899       XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
10900       XtSetArg(args[n], XmNwidth, 5); n++;
10901       XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
10902       sep1 = XtCreateManagedWidget("sep1", xmSeparatorWidgetClass, form, args, n);
10903 
10904       n = 0;
10905       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
10906       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
10907       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
10908       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
10909       XtSetArg(args[n], XmNleftWidget, sep1); n++;
10910       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
10911       header_label = XtCreateManagedWidget("header", xmLabelWidgetClass, form, args, n);
10912 
10913       /* what is selected depends on current type */
10914       strs = (XmString *)calloc(nheaders, sizeof(XmString));
10915       for (i = 0; i < nheaders; i++)
10916 	strs[i] = XmStringCreateLocalized((char *)header_types[i]);
10917 
10918       n = 0;
10919       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
10920       XtSetArg(args[n], XmNtopWidget, header_label); n++;
10921       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
10922       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
10923       XtSetArg(args[n], XmNleftWidget, sep1); n++;
10924       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
10925       XtSetArg(args[n], XmNlistMarginWidth, 1); n++;
10926       XtSetArg(args[n], XmNuserData, (XtPointer)fdat); n++;
10927       XtSetArg(args[n], XmNitems, strs); n++;
10928       XtSetArg(args[n], XmNitemCount, nheaders); n++;
10929       XtSetArg(args[n], XmNvisibleItemCount, NUM_VISIBLE_HEADERS); n++;
10930       fdat->header_type_list = XmCreateScrolledList(form, (char *)"header-type", args, n);
10931       XtManageChild(fdat->header_type_list);
10932 
10933       for (i = 0; i < nheaders; i++)
10934 	XmStringFree(strs[i]);
10935       free(strs);
10936       XmListSelectPos(fdat->header_type_list, fdat->header_type_pos + 1, false);
10937       XtAddCallback(fdat->header_type_list, XmNbrowseSelectionCallback, file_data_type_callback, NULL);
10938 
10939       n = 0;
10940       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
10941       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
10942       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
10943       XtSetArg(args[n], XmNleftWidget, fdat->header_type_list); n++;
10944       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
10945       XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
10946       XtSetArg(args[n], XmNwidth, 15); n++;
10947       XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
10948       sep2 = XtCreateManagedWidget("sep2", xmSeparatorWidgetClass, form, args, n);
10949     }
10950 
10951   n = 0;
10952   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
10953   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
10954   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
10955   if (with_header_type == WITH_HEADER_TYPE_FIELD)
10956     {
10957       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
10958       XtSetArg(args[n], XmNleftWidget, sep2); n++;
10959     }
10960   else
10961     {
10962       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
10963     }
10964   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
10965   data_label = XtCreateManagedWidget("data", xmLabelWidgetClass, form, args, n);
10966 
10967   n = 0;
10968   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
10969   XtSetArg(args[n], XmNtopWidget, data_label); n++;
10970   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
10971   if (with_header_type == WITH_HEADER_TYPE_FIELD)
10972     {
10973       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
10974       XtSetArg(args[n], XmNleftWidget, sep2); n++;
10975     }
10976   else
10977     {
10978       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
10979     }
10980   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
10981   XtSetArg(args[n], XmNuserData, (XtPointer)fdat); n++;
10982   fdat->sample_type_list = XmCreateScrolledList(form, (char *)"sample-type", args, n);
10983 
10984   strs = (XmString *)calloc(nsample_types, sizeof(XmString));
10985   for (i = 0; i < nsample_types; i++)
10986     strs[i] = XmStringCreateLocalized((char *)sample_types[i]);
10987   XtVaSetValues(fdat->sample_type_list,
10988 		XmNitems, strs,
10989 		XmNitemCount, nsample_types,
10990 		NULL);
10991   for (i = 0; i < nsample_types; i++)
10992     XmStringFree(strs[i]);
10993   free(strs);
10994 
10995   XmListSelectPos(fdat->sample_type_list, fdat->sample_type_pos + 1, false);
10996   XtManageChild(fdat->sample_type_list);
10997   XtAddCallback(fdat->sample_type_list, XmNbrowseSelectionCallback, file_sample_type_callback, NULL);
10998 
10999   n = 0;
11000   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
11001   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
11002   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
11003   XtSetArg(args[n], XmNleftWidget, fdat->sample_type_list); n++;
11004   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
11005   XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
11006   XtSetArg(args[n], XmNwidth, 15); n++;
11007   XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
11008   sep3 = XtCreateManagedWidget("sep3", xmSeparatorWidgetClass, form, args, n);
11009 
11010 
11011   /* srate */
11012   n = 0;
11013   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
11014   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
11015   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
11016   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
11017   XtSetArg(args[n], XmNleftWidget, sep3); n++;
11018   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
11019   srate_label = XtCreateManagedWidget("srate", xmLabelWidgetClass, form, args, n);
11020 
11021   n = 0;
11022   XtSetArg(args[n], XmNcolumns, 8); n++;
11023   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
11024   XtSetArg(args[n], XmNtopWidget, srate_label); n++;
11025   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
11026   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
11027   XtSetArg(args[n], XmNleftWidget, sep3); n++;
11028   if (with_src)
11029     {
11030       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
11031     }
11032   else
11033     {
11034       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
11035     }
11036   XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
11037   fdat->srate_text = make_textfield_widget("srate-text", form, args, n, NOT_ACTIVATABLE, add_completer_func(srate_completer, NULL));
11038 
11039   if (with_src)
11040     {
11041       n = 0;
11042       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
11043       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
11044       XtSetArg(args[n], XmNtopWidget, srate_label); n++;
11045       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
11046       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
11047       XtSetArg(args[n], XmNleftWidget, fdat->srate_text); n++;
11048       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
11049       XtSetArg(args[n], XmNselectColor, ss->selection_color); n++; /* this is probably clobbered by color_file_selection_box */
11050       fdat->src_button = make_togglebutton_widget("src", form, args, n);
11051       XtAddCallback(fdat->src_button, XmNvalueChangedCallback, file_data_src_callback, (XtPointer)fdat);
11052       XmToggleButtonSetState(fdat->src_button, fdat->src, false);
11053     }
11054 
11055   if (with_chan != WITHOUT_CHANNELS_FIELD)
11056     {
11057       /* chans */
11058       n = 0;
11059       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
11060       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
11061       XtSetArg(args[n], XmNtopWidget, fdat->srate_text); n++;
11062       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
11063       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
11064       XtSetArg(args[n], XmNleftWidget, sep3); n++;
11065       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
11066       chans_label = XtCreateManagedWidget((char *)((with_chan == WITH_CHANNELS_FIELD) ? "channels" : "extract channel"), xmLabelWidgetClass, form, args, n);
11067 
11068       n = 0;
11069       XtSetArg(args[n], XmNcolumns, 6); n++;
11070       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
11071       XtSetArg(args[n], XmNtopWidget, chans_label); n++;
11072       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
11073       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
11074       XtSetArg(args[n], XmNleftWidget, sep3); n++;
11075       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
11076       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
11077       fdat->chans_text = make_textfield_widget("chans-text", form, args, n, NOT_ACTIVATABLE, NO_COMPLETER);
11078       XmTextFieldSetString(fdat->chans_text, (char *)"0");
11079 
11080       if (with_loc == WITH_DATA_LOCATION_FIELD)
11081 	{
11082 	  n = 0;
11083 	  XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
11084 	  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
11085 	  XtSetArg(args[n], XmNtopWidget, fdat->chans_text); n++;
11086 	  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
11087 	  XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
11088 	  XtSetArg(args[n], XmNleftWidget, sep3); n++;
11089 	  XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
11090 	  location_label = XtCreateManagedWidget("data location", xmLabelWidgetClass, form, args, n);
11091 
11092 	  n = 0;
11093 	  XtSetArg(args[n], XmNcolumns, 6); n++;
11094 	  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
11095 	  XtSetArg(args[n], XmNtopWidget, location_label); n++;
11096 	  XtSetArg(args[n], XmNbottomAttachment, (with_samples == WITHOUT_SAMPLES_FIELD) ? XmATTACH_FORM : XmATTACH_NONE); n++;
11097 	  XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
11098 	  XtSetArg(args[n], XmNleftWidget, sep3); n++;
11099 	  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
11100 	  XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
11101 	  fdat->location_text = make_textfield_widget("location-text", form, args, n, NOT_ACTIVATABLE, NO_COMPLETER);
11102 	}
11103     }
11104 
11105   if (with_samples == WITH_SAMPLES_FIELD)
11106     {
11107       n = 0;
11108       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
11109       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
11110       XtSetArg(args[n], XmNtopWidget, ((fdat->location_text) ? fdat->location_text :
11111 				       ((fdat->chans_text) ? fdat->chans_text : fdat->srate_text))); n++;
11112       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
11113       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
11114       XtSetArg(args[n], XmNleftWidget, sep3); n++;
11115       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
11116       samples_label = XtCreateManagedWidget("samples", xmLabelWidgetClass, form, args, n);
11117 
11118       n = 0;
11119       XtSetArg(args[n], XmNcolumns, 8); n++;
11120       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
11121       XtSetArg(args[n], XmNtopWidget, samples_label); n++;
11122       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
11123       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
11124       XtSetArg(args[n], XmNleftWidget, sep3); n++;
11125       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
11126       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
11127       fdat->samples_text = make_textfield_widget("samples-text", form, args, n, NOT_ACTIVATABLE, NO_COMPLETER);
11128     }
11129 
11130   n = 0;
11131   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
11132   XtSetArg(args[n], XmNtopWidget, form); n++; /* form is the internal XmForm widget holding the lists etc */
11133   XtSetArg(args[n], XmNbottomAttachment, (with_comment != WITHOUT_COMMENT_FIELD) ? XmATTACH_NONE : XmATTACH_FORM); n++;
11134   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
11135   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
11136   XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
11137   XtSetArg(args[n], XmNheight, (with_comment != WITHOUT_COMMENT_FIELD) ? PANEL_COMMENT_SPACE : 2); n++;
11138   XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
11139   sep4 = XtCreateManagedWidget("sep4", xmSeparatorWidgetClass, parent, args, n);
11140 
11141   /* try to make the comment field the one that grows */
11142   n = 0;
11143   if (with_comment == WITHOUT_COMMENT_FIELD)
11144     {
11145       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
11146       XtSetArg(args[n], XmNtopWidget, sep4); n++;
11147     }
11148   else
11149     {
11150       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
11151     }
11152   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
11153   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++; /* overridden later -> yellow */
11154   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
11155   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
11156   XtSetArg(args[n], XmNborderColor, ss->black); n++;
11157   XtSetArg(args[n], XmNborderWidth, 2); n++;
11158   XtSetArg(args[n], XmNmarginWidth, 10); n++;
11159   XtSetArg(args[n], XmNmarginHeight, 10); n++;
11160   fdat->error_text = XtCreateWidget("", xmLabelWidgetClass, parent, args, n);
11161   /* XtUnmanageChild(fdat->error_text); */
11162 
11163   if (with_comment != WITHOUT_COMMENT_FIELD)
11164     {
11165       n = 0;
11166       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
11167       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
11168       XtSetArg(args[n], XmNtopWidget, sep4); n++;
11169       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
11170       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
11171       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
11172       comment_label = XtCreateManagedWidget("comment", xmLabelWidgetClass, parent, args, n);
11173 
11174       if (with_auto_comment)
11175 	{
11176 	  n = 0;
11177 	  XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
11178 	  XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
11179 	  XtSetArg(args[n], XmNtopWidget, sep4); n++;
11180 	  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
11181 	  XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
11182 	  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
11183 	  XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
11184 	  fdat->auto_comment_button = make_togglebutton_widget("auto", parent, args, n);
11185 	  XtAddCallback(fdat->auto_comment_button, XmNvalueChangedCallback, file_data_auto_comment_callback, (XtPointer)fdat);
11186 	  XmToggleButtonSetState(fdat->auto_comment_button, fdat->auto_comment, false);
11187 	}
11188 
11189       n = 0;
11190       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
11191       if (with_auto_comment)
11192 	{
11193 	  XtSetArg(args[n], XmNtopWidget, fdat->auto_comment_button); n++;
11194 	}
11195       else
11196 	{
11197 	  XtSetArg(args[n], XmNtopWidget, comment_label); n++;
11198 	}
11199       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
11200       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
11201       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
11202       XtSetArg(args[n], XmNrows, 4); n++;
11203       /* XtSetArg(args[n], XmNcolumns, 16); n++; */ /* this sets the lower size, so we don't want it too big */
11204       fdat->comment_text = make_text_widget("comment-text", parent, args, n);
11205     }
11206   else fdat->comment_text = NULL;
11207 
11208   return(fdat);
11209 }
11210 
11211 
reflect_file_data_panel_change(file_data * fd,void * data,void (* change_action)(Widget w,XtPointer context,XtPointer info))11212 static void reflect_file_data_panel_change(file_data *fd, void *data, void (*change_action)(Widget w, XtPointer context, XtPointer info))
11213 {
11214   if (fd->srate_text)
11215     XtAddCallback(fd->srate_text, XmNvalueChangedCallback, change_action, (XtPointer)data);
11216   if (fd->chans_text)
11217     XtAddCallback(fd->chans_text, XmNvalueChangedCallback, change_action, (XtPointer)data);
11218   if (fd->samples_text)
11219     XtAddCallback(fd->samples_text, XmNvalueChangedCallback, change_action, (XtPointer)data);
11220   if (fd->location_text)
11221     XtAddCallback(fd->location_text, XmNvalueChangedCallback, change_action, (XtPointer)data);
11222   if (fd->comment_text)
11223     XtAddCallback(fd->comment_text, XmNvalueChangedCallback, change_action, (XtPointer)data);
11224   if (fd->sample_type_list)
11225     XtAddCallback(fd->sample_type_list, XmNbrowseSelectionCallback, change_action, (XtPointer)data);
11226   if (fd->header_type_list)
11227     XtAddCallback(fd->header_type_list, XmNbrowseSelectionCallback, change_action, (XtPointer)data);
11228 }
11229 
11230 
unreflect_file_data_panel_change(file_data * fd,void * data,void (* change_action)(Widget w,XtPointer context,XtPointer info))11231 static void unreflect_file_data_panel_change(file_data *fd, void *data, void (*change_action)(Widget w, XtPointer context, XtPointer info))
11232 {
11233   if (fd->srate_text)
11234     XtRemoveCallback(fd->srate_text, XmNvalueChangedCallback, change_action, (XtPointer)data);
11235   if (fd->chans_text)
11236     XtRemoveCallback(fd->chans_text, XmNvalueChangedCallback, change_action, (XtPointer)data);
11237   if (fd->samples_text)
11238     XtRemoveCallback(fd->samples_text, XmNvalueChangedCallback, change_action, (XtPointer)data);
11239   if (fd->location_text)
11240     XtRemoveCallback(fd->location_text, XmNvalueChangedCallback, change_action, (XtPointer)data);
11241   if (fd->comment_text)
11242     XtRemoveCallback(fd->comment_text, XmNvalueChangedCallback, change_action, (XtPointer)data);
11243   if (fd->sample_type_list)
11244     XtRemoveCallback(fd->sample_type_list, XmNbrowseSelectionCallback, change_action, (XtPointer)data);
11245   if (fd->header_type_list)
11246     XtRemoveCallback(fd->header_type_list, XmNbrowseSelectionCallback, change_action, (XtPointer)data);
11247 }
11248 
11249 
11250 /* -------- save as dialog (file and edit menus) -------- */
11251 
11252 typedef struct {
11253   file_data *panel_data;
11254   Widget dialog, filename_widget, extractB, mkdirB;
11255   char *filename; /* output name (?) */
11256   save_dialog_t type;
11257   file_pattern_info *fp;
11258   dialog_play_info *dp;
11259   void *file_watcher;
11260   file_popup_info *fpop;
11261   const char *original_filename;
11262 } save_as_dialog_info;
11263 
11264 static save_as_dialog_info *save_sound_as = NULL, *save_selection_as = NULL, *save_region_as = NULL;
11265 
11266 
new_save_as_dialog_info(save_dialog_t type)11267 static save_as_dialog_info *new_save_as_dialog_info(save_dialog_t type)
11268 {
11269   save_as_dialog_info *sd;
11270   sd = (save_as_dialog_info *)calloc(1, sizeof(save_as_dialog_info));
11271   sd->type = type;
11272   return(sd);
11273 }
11274 
11275 
make_auto_comment(save_as_dialog_info * sd)11276 static void make_auto_comment(save_as_dialog_info *sd)
11277 {
11278   if ((sd == save_sound_as) &&
11279       (XtIsManaged(sd->dialog)))
11280     {
11281       file_data *fd;
11282       fd = sd->panel_data;
11283 
11284       if (!(fd->auto_comment))
11285 	{
11286 	  /* don't erase typed-in comment, if any */
11287 	  XmTextSetString(fd->comment_text, fd->saved_comment);
11288 	}
11289       else
11290 	{
11291 	  snd_info *sp;
11292 	  bool edits = false;
11293 	  int i;
11294 	  char *original_sound_comment, *comment, *orig_comment = NULL;
11295 
11296 	  sp = any_selected_sound();
11297 
11298 	  original_sound_comment = mus_sound_comment(sp->filename);
11299 	  if (original_sound_comment)
11300 	    {
11301 	      if (*original_sound_comment)
11302 		orig_comment = mus_format("\n%s comment:\n%s\n", sp->short_filename, original_sound_comment);
11303 	      free(original_sound_comment);
11304 	      original_sound_comment = NULL;
11305 	    }
11306 
11307 	  if (fd->saved_comment) XtFree(fd->saved_comment);
11308 	  fd->saved_comment = XmTextGetString(fd->comment_text);
11309 	  if ((fd->saved_comment) &&
11310 	      (!(*(fd->saved_comment))))
11311 	    {
11312 	      /* this is the norm in Motif */
11313 	      XtFree(fd->saved_comment);
11314 	      fd->saved_comment = NULL;
11315 	    }
11316 
11317 	  for (i = 0; i < (int)sp->nchans; i++)
11318 	    if (sp->chans[i]->edit_ctr != 0)
11319 	      {
11320 		edits = true;
11321 		break;
11322 	      }
11323 
11324 	  if (!edits)
11325 	    comment = mus_format("%s%ssaved %s from %s (no edits)\n%s",
11326 				 (fd->saved_comment) ? fd->saved_comment : "",
11327 				 (fd->saved_comment) ? "\n" : "",
11328 				 snd_local_time(),
11329 				 sp->filename,
11330 				 (orig_comment) ? orig_comment : "");
11331 	  else
11332 	    {
11333 	      int len;
11334 	      char **edit_strs;
11335 	      char *time;
11336 
11337 	      time = snd_local_time();
11338 	      len = 2 * mus_strlen(sp->filename) +
11339 		    mus_strlen(time) +
11340 		    32 * sp->nchans +
11341 		    mus_strlen(fd->saved_comment) +
11342 		    mus_strlen(original_sound_comment);
11343 
11344 	      edit_strs = (char **)malloc(sp->nchans * sizeof(char *));
11345 	      for (i = 0; i < (int)sp->nchans; i++)
11346 		{
11347 		  edit_strs[i] = edit_list_to_function(sp->chans[i], 1, sp->chans[i]->edit_ctr);
11348 		  len += mus_strlen(edit_strs[i]);
11349 		}
11350 
11351 	      comment = (char *)calloc(len, sizeof(char));
11352 	      snprintf(comment, len, "%s%ssaved %s from %s with edits:\n",
11353 			   (fd->saved_comment) ? fd->saved_comment : "",
11354 			   (fd->saved_comment) ? "\n" : "",
11355 			   snd_local_time(),
11356 			   sp->filename);
11357 
11358 	      for (i = 0; i < (int)sp->nchans; i++)
11359 		{
11360 		  if (sp->nchans > 1)
11361 		    {
11362 		      char buf[64];
11363 		      snprintf(buf, 64, "\n-------- channel %d --------\n", i);
11364 		      strcat(comment, buf);
11365 		    }
11366 		  strcat(comment, edit_strs[i]);
11367 		}
11368 
11369 	      if (orig_comment)
11370 		strcat(comment, orig_comment);
11371 	      free(edit_strs);
11372 	    }
11373 
11374 	  XmTextSetString(fd->comment_text, comment);
11375 	  if (comment) free(comment);
11376 	  if (orig_comment) free(orig_comment);
11377 	}
11378     }
11379 }
11380 
11381 
auto_comment_callback(Widget w,XtPointer context,XtPointer info)11382 static void auto_comment_callback(Widget w, XtPointer context, XtPointer info)
11383 {
11384   save_as_dialog_info *sd = (save_as_dialog_info *)context;
11385   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
11386   sd->panel_data->auto_comment = (cb->set);
11387   make_auto_comment(sd);
11388 }
11389 
11390 
reflect_save_as_src(bool val)11391 void reflect_save_as_src(bool val)
11392 {
11393   if (save_sound_as)
11394     XmToggleButtonSetState(save_sound_as->panel_data->src_button, val, true);
11395   if (save_selection_as)
11396     XmToggleButtonSetState(save_selection_as->panel_data->src_button, val, true);
11397   if (save_region_as)
11398     XmToggleButtonSetState(save_region_as->panel_data->src_button, val, true);
11399 }
11400 
11401 
reflect_save_as_auto_comment(bool val)11402 void reflect_save_as_auto_comment(bool val)
11403 {
11404   if (save_sound_as)
11405     XmToggleButtonSetState(save_sound_as->panel_data->auto_comment_button, val, true);
11406 }
11407 
11408 
reflect_save_as_sound_selection(const char * sound_name)11409 void reflect_save_as_sound_selection(const char *sound_name)
11410 {
11411   if ((save_sound_as) &&
11412       (XtIsManaged(save_sound_as->dialog)))
11413     {
11414       XmString xmstr2;
11415       char *file_string;
11416       file_string = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char));
11417       if (sound_name)
11418 	snprintf(file_string, PRINT_BUFFER_SIZE, "save %s", sound_name);
11419       else
11420 	{
11421 	  snd_info *sp;
11422 	  sp = any_selected_sound();
11423 	  if (sp)
11424 	    snprintf(file_string, PRINT_BUFFER_SIZE, "save %s", sp->short_filename);
11425 	  else snprintf(file_string, PRINT_BUFFER_SIZE, "nothing to save!");
11426 	}
11427       xmstr2 = XmStringCreateLocalized(file_string);
11428       XtVaSetValues(save_sound_as->dialog, XmNdialogTitle, xmstr2, NULL);
11429       XmStringFree(xmstr2);
11430       free(file_string);
11431     }
11432 }
11433 
11434 
reflect_selection_in_save_as_dialog(bool on)11435 void reflect_selection_in_save_as_dialog(bool on)
11436 {
11437   if ((on) &&
11438       (save_selection_as) &&
11439       (save_selection_as->panel_data))
11440     clear_dialog_error(save_selection_as->panel_data);
11441 }
11442 
11443 
reflect_region_in_save_as_dialog(void)11444 void reflect_region_in_save_as_dialog(void)
11445 {
11446   if ((save_region_as) &&
11447       (save_region_as->dialog) &&
11448       (XtIsManaged(save_region_as->dialog)) &&
11449       (region_ok(region_dialog_region())))
11450     clear_dialog_error(save_region_as->panel_data);
11451 }
11452 
11453 
11454 static void save_as_filename_modify_callback(Widget w, XtPointer context, XtPointer info);
11455 
save_as_undoit(save_as_dialog_info * sd)11456 static void save_as_undoit(save_as_dialog_info *sd)
11457 {
11458   XmString ok_label;
11459   ok_label = XmStringCreateLocalized((char *)"Save");
11460   XtVaSetValues(sd->dialog,
11461 		XmNokLabelString, ok_label,
11462 		NULL);
11463   XmStringFree(ok_label);
11464   clear_dialog_error(sd->panel_data);
11465   XtRemoveCallback(sd->filename_widget, XmNmodifyVerifyCallback, save_as_filename_modify_callback, (XtPointer)(sd->panel_data));
11466   sd->file_watcher = unmonitor_file(sd->file_watcher);
11467 }
11468 
11469 
save_as_filename_modify_callback(Widget w,XtPointer context,XtPointer info)11470 static void save_as_filename_modify_callback(Widget w, XtPointer context, XtPointer info)
11471 {
11472   XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info;
11473   save_as_undoit((save_as_dialog_info *)context);
11474   cbs->doit = true;
11475 }
11476 
11477 
clear_error_if_save_as_filename_changes(Widget dialog,save_as_dialog_info * sd)11478 static void clear_error_if_save_as_filename_changes(Widget dialog, save_as_dialog_info *sd)
11479 {
11480   XtAddCallback(sd->filename_widget, XmNmodifyVerifyCallback, save_as_filename_modify_callback, (XtPointer)sd);
11481 }
11482 
11483 
srates_differ(int srate,save_as_dialog_info * sd)11484 static bool srates_differ(int srate, save_as_dialog_info *sd)
11485 {
11486   switch (sd->type)
11487     {
11488     case SOUND_SAVE_AS:
11489       return(snd_srate(any_selected_sound()) != srate);
11490 
11491     case SELECTION_SAVE_AS:
11492       return(selection_srate() != srate);
11493 
11494     case REGION_SAVE_AS:
11495       return(region_srate(region_dialog_region()) != srate);
11496     }
11497 
11498   return(false);
11499 }
11500 
11501 
srate_ratio(int srate,save_as_dialog_info * sd)11502 static double srate_ratio(int srate, save_as_dialog_info *sd)
11503 {
11504   switch (sd->type)
11505     {
11506     case SOUND_SAVE_AS:
11507       return((double)(snd_srate(any_selected_sound())) / (double)srate);
11508 
11509     case SELECTION_SAVE_AS:
11510       return((double)selection_srate() / (double)srate);
11511 
11512     case REGION_SAVE_AS:
11513       return((double)region_srate(region_dialog_region()) / (double)srate);
11514     }
11515 
11516   return(1.0);
11517 }
11518 
11519 
save_or_extract(save_as_dialog_info * sd,bool saving)11520 static void save_or_extract(save_as_dialog_info *sd, bool saving)
11521 {
11522   char *str = NULL, *comment = NULL, *msg = NULL, *fullname = NULL, *tmpfile = NULL;
11523   snd_info *sp = NULL;
11524   mus_header_t header_type = MUS_NEXT, output_type;
11525   mus_sample_t sample_type = DEFAULT_OUTPUT_SAMPLE_TYPE;
11526   int srate = DEFAULT_OUTPUT_SRATE;
11527   int chan = 0, extractable_chans = 0;
11528   bool file_exists = false;
11529   io_error_t io_err = IO_NO_ERROR;
11530 
11531   clear_dialog_error(sd->panel_data);
11532 
11533   if ((sd->type == SELECTION_SAVE_AS) &&
11534       (!(selection_is_active())))
11535     {
11536       if (saving)
11537 	msg = (char *)"no selection to save";
11538       else msg = (char *)"can't extract: no selection";
11539       post_file_dialog_error((const char *)msg, sd->panel_data);
11540       return;
11541     }
11542 
11543   if ((sd->type == REGION_SAVE_AS) &&
11544       (!(region_ok(region_dialog_region()))))
11545     {
11546       post_file_dialog_error("no region to save", sd->panel_data);
11547       return;
11548     }
11549 
11550   sp = any_selected_sound();
11551   if ((!sp) &&
11552       (sd->type != REGION_SAVE_AS))
11553     {
11554       if (saving)
11555 	msg = (char *)"nothing to save";
11556       else msg = (char *)"nothing to extract";
11557       post_file_dialog_error((const char *)msg, sd->panel_data);
11558       clear_error_if_filename_changes(sd->dialog, sd->panel_data);
11559       return;
11560     }
11561 
11562   /* get output filename */
11563   str = XmTextGetString(sd->filename_widget);
11564   if ((!str) || (!*str))
11565     {
11566       if (saving)
11567 	msg = (char *)"can't save: no file name given";
11568       else msg = (char *)"can't extract: no file name given";
11569       post_file_dialog_error((const char *)msg, sd->panel_data);
11570       clear_error_if_filename_changes(sd->dialog, sd->panel_data);
11571       return;
11572     }
11573 
11574   /* get output file attributes */
11575   redirect_snd_error_to(post_file_panel_error, (void *)(sd->panel_data));
11576   {
11577     mus_long_t location = 28, samples = 0;
11578     int chans = 1;
11579     if (saving)
11580       comment = get_file_dialog_sound_attributes(sd->panel_data, &srate, &chans, &header_type, &sample_type, &location, &samples, 0);
11581     else comment = get_file_dialog_sound_attributes(sd->panel_data, &srate, &chan, &header_type, &sample_type, &location, &samples, 0);
11582   }
11583   output_type = header_type;
11584   redirect_snd_error_to(NULL, NULL);
11585 
11586   if (sd->panel_data->error_widget != NOT_A_SCANF_WIDGET)
11587     {
11588       clear_error_if_panel_changes(sd->dialog, sd->panel_data);
11589       if (comment) free(comment);
11590       XtFree(str);
11591       return;
11592     }
11593 
11594   switch (sd->type)
11595     {
11596     case SOUND_SAVE_AS:
11597       clear_status_area(sp);
11598       if (!saving)
11599 	extractable_chans = sp->nchans;
11600       break;
11601 
11602     case SELECTION_SAVE_AS:
11603       if (!saving)
11604 	extractable_chans = selection_chans();
11605       break;
11606 
11607     default:
11608       break;
11609     }
11610 
11611   if (!saving)
11612     {
11613       if ((chan > extractable_chans) ||
11614 	  (((extractable_chans > 1) && (chan == extractable_chans)) ||
11615 	   (chan < 0)))
11616 	{
11617 	  if (chan > extractable_chans)
11618 	    msg = mus_format("can't extract chan %d (%s has %d chan%s)",
11619 			     chan,
11620 			     (sd->type == SOUND_SAVE_AS) ? "sound" : "selection",
11621 			     extractable_chans,
11622 			     (extractable_chans > 1) ? "s" : "");
11623 	  else msg = mus_format("can't extract chan %d (first chan is numbered 0)", chan);
11624 	  post_file_dialog_error((const char *)msg, sd->panel_data);
11625 	  clear_error_if_chans_changes(sd->dialog, sd->panel_data);
11626 	  free(msg);
11627 	  if (comment) free(comment);
11628 	  XtFree(str);
11629 	  return;
11630 	}
11631     }
11632 
11633   fullname = mus_expand_filename(str);
11634   if (run_before_save_as_hook(sp, fullname, sd->type != SOUND_SAVE_AS, srate, sample_type, header_type, comment))
11635     {
11636       msg = mus_format("%s cancelled by %s", (saving) ? "save" : "extract", S_before_save_as_hook);
11637       post_file_dialog_error((const char *)msg, sd->panel_data);
11638       clear_error_if_filename_changes(sd->dialog, sd->panel_data);
11639       free(msg);
11640       free(fullname);
11641       if (comment) free(comment);
11642       XtFree(str);
11643       return;
11644     }
11645 
11646   file_exists = mus_file_probe(fullname);
11647   if ((sd->type == SOUND_SAVE_AS) &&
11648       (mus_strcmp(fullname, sp->filename)))
11649     {
11650       /* save-as here is the same as save */
11651       if ((sp->user_read_only == FILE_READ_ONLY) ||
11652 	  (sp->file_read_only == FILE_READ_ONLY))
11653 	{
11654 	  msg = mus_format("can't overwrite %s (it is write-protected)", sp->short_filename);
11655 	  post_file_dialog_error((const char *)msg, sd->panel_data);
11656 	  clear_error_if_filename_changes(sd->dialog, sd->panel_data);
11657 	  free(msg);
11658 	  free(fullname);
11659 	  if (comment) free(comment);
11660 	  XtFree(str);
11661 	  return;
11662 	}
11663     }
11664   else
11665     {
11666       if (!(sd->file_watcher))
11667 	{
11668 	  /* check for overwrites that are questionable -- DoIt click will return here with sd->file_watcher active */
11669 	  snd_info *parlous_sp = NULL;
11670 	  if ((file_exists) &&
11671 	      ((ask_before_overwrite(ss)) ||
11672 	       ((sd->type == SOUND_SAVE_AS) &&
11673 		(parlous_sp = file_is_open_elsewhere_and_has_unsaved_edits(sp, fullname)))))
11674 	    {
11675 	      XmString ok_label;
11676 	      msg = mus_format("%s exists%s. To overwrite it, click 'DoIt'",
11677 			       str,
11678 			       (parlous_sp) ? ", and has unsaved edits" : "");
11679 	      post_file_dialog_error((const char *)msg, sd->panel_data);
11680 	      clear_error_if_save_as_filename_changes(sd->dialog, sd);
11681 	      ok_label = XmStringCreateLocalized((char *)"DoIt");
11682 	      XtVaSetValues(sd->dialog,
11683 			    XmNokLabelString, ok_label,
11684 			    NULL);
11685 	      XmUpdateDisplay(FSB_BOX(sd->dialog, XmDIALOG_OK_BUTTON));
11686 	      XmStringFree(ok_label);
11687 	      free(msg);
11688 	      free(fullname);
11689 	      if (comment) free(comment);
11690 	      XtFree(str);
11691 	      return;
11692 	    }
11693 	}
11694     }
11695 
11696   /* try to save... if it exists already, first write as temp, then move */
11697   if (sd->file_watcher)
11698     save_as_undoit(sd);
11699   ss->local_errno = 0;
11700 
11701   if (header_is_encoded(header_type))
11702     {
11703       output_type = header_type;
11704       sample_type = MUS_LSHORT;
11705       header_type = MUS_RIFF;
11706       tmpfile = snd_tempnam();
11707     }
11708   else
11709     {
11710       tmpfile = fullname;
11711     }
11712 
11713   redirect_snd_error_to(redirect_post_file_dialog_error, (void *)(sd->panel_data));
11714   switch (sd->type)
11715     {
11716     case SOUND_SAVE_AS:
11717       if (saving)
11718 	io_err = save_edits_without_display(sp, tmpfile, header_type, sample_type, srate, comment, AT_CURRENT_EDIT_POSITION);
11719       else io_err = save_channel_edits(sp->chans[chan], tmpfile, AT_CURRENT_EDIT_POSITION); /* protects if same name */
11720       break;
11721 
11722     case SELECTION_SAVE_AS:
11723       {
11724 	char *ofile;
11725 	if (file_exists) /* file won't exist if we're encoding, so this isn't as wasteful as it looks */
11726 	  ofile = snd_tempnam();
11727 	else ofile = mus_strdup(tmpfile);
11728 	io_err = save_selection(ofile, srate, sample_type, header_type, comment, (saving) ? SAVE_ALL_CHANS : chan);
11729 	if (io_err == IO_NO_ERROR)
11730 	  io_err = move_file(ofile, fullname);
11731 	free(ofile);
11732       }
11733       break;
11734 
11735     case REGION_SAVE_AS:
11736       {
11737 	if (region_ok(region_dialog_region()))
11738 	  {
11739 	    char *ofile;
11740 	    if (file_exists)
11741 	      ofile = snd_tempnam();
11742 	    else ofile = mus_strdup(tmpfile);
11743 	    io_err = save_region(region_dialog_region(), ofile, sample_type, header_type, comment);
11744 	    if (io_err == IO_NO_ERROR)
11745 	      io_err = move_file(ofile, fullname);
11746 	    free(ofile);
11747 	  }
11748       }
11749       break;
11750     }
11751   redirect_snd_error_to(NULL, NULL);
11752 
11753   /* check for possible srate conversion */
11754   if ((sd->panel_data->src) &&
11755       (srates_differ(srate, sd)))
11756     {
11757       /* if src, and srates differ, do the sampling rate conversion.
11758        *    this needs to happen before the snd_encode (->OGG etc) below
11759        *    if we do it before the save-as above, then undo it later, it messes up the user's edit history list
11760        *    so do it here to tmpfile (tmpfile is fullname unless we're doing a translation to something like OGG)
11761        */
11762       src_file(tmpfile, srate_ratio(srate, sd));
11763     }
11764 
11765   if (io_err == IO_NO_ERROR)
11766     {
11767       if (header_is_encoded(output_type))
11768 	{
11769 	  snd_encode(output_type, tmpfile, fullname);
11770 	  snd_remove(tmpfile, REMOVE_FROM_CACHE);
11771 	  free(tmpfile);
11772 	}
11773       remember_filename(fullname, sd->fpop->file_text_names);
11774 
11775       if (!file_exists)
11776 	force_directory_reread(sd->dialog);
11777       if (saving)
11778 	{
11779 	  if (sd->type == SOUND_SAVE_AS)
11780 	    status_report(sp, "%s saved as %s", sp->short_filename, str);
11781 	  else status_report(sp, "%s saved as %s", (sd->type == SELECTION_SAVE_AS) ? "selection" : "region", str);
11782 	}
11783       else
11784 	{
11785 	  if (sd->type == SOUND_SAVE_AS)
11786 	    status_report(sp, "%s chan %d saved as %s", sp->short_filename, chan, str);
11787 	  else status_report(sp, "selection chan %d saved as %s", chan, str);
11788 	}
11789       run_after_save_as_hook(sp, str, true); /* true => from dialog */
11790       XtUnmanageChild(sd->dialog);
11791     }
11792   else
11793     {
11794       msg = mus_format("%s as %s: %s (%s)", (saving) ? "save" : "extract chan", str, io_error_name(io_err), snd_io_strerror());
11795       post_file_dialog_error((const char *)msg, sd->panel_data);
11796       clear_error_if_filename_changes(sd->dialog, sd->panel_data);
11797       free(msg);
11798     }
11799 
11800   free(fullname);
11801   XtFree(str);
11802   if (comment) free(comment);
11803 }
11804 
11805 
save_as_ok_callback(Widget w,XtPointer context,XtPointer info)11806 static void save_as_ok_callback(Widget w, XtPointer context, XtPointer info)
11807 {
11808   save_or_extract((save_as_dialog_info *)context, true);
11809 }
11810 
11811 
save_as_extract_callback(Widget w,XtPointer context,XtPointer info)11812 static void save_as_extract_callback(Widget w, XtPointer context, XtPointer info)
11813 {
11814   save_or_extract((save_as_dialog_info *)context, false);
11815 }
11816 
11817 
save_as_dialog_select_callback(Widget w,XtPointer context,XtPointer info)11818 static void save_as_dialog_select_callback(Widget w, XtPointer context, XtPointer info)
11819 {
11820 #if WITH_AUDIO
11821   dialog_play_info *dp = (dialog_play_info *)context;
11822   XmString *strs = NULL;
11823   XtVaGetValues(w, XmNselectedItems, &strs, NULL);
11824   if (strs)
11825     {
11826       char *filename;
11827       filename = (char *)XmStringUnparse(strs[0], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
11828       if ((filename) && (is_sound_file(filename)))
11829 	XtManageChild(dp->play_button);
11830       else
11831 	{
11832 	  if (XtIsManaged(dp->play_button))
11833 	    XtUnmanageChild(dp->play_button);
11834 	}
11835       if (filename) XtFree(filename);
11836     }
11837 #endif
11838 }
11839 
11840 
save_as_cancel_callback(Widget w,XtPointer context,XtPointer info)11841 static void save_as_cancel_callback(Widget w, XtPointer context, XtPointer info)
11842 {
11843   save_as_dialog_info *sd = (save_as_dialog_info *)context;
11844   XtUnmanageChild(sd->dialog);
11845 }
11846 
11847 
save_as_help_callback(Widget w,XtPointer context,XtPointer info)11848 static void save_as_help_callback(Widget w, XtPointer context, XtPointer info)
11849 {
11850   save_as_dialog_help();
11851 }
11852 
11853 
directory_exists(char * name)11854 static bool directory_exists(char *name)
11855 {
11856   char temp;
11857   bool result;
11858   int i, len, last_slash = -1;
11859   len = strlen(name);
11860   for (i = 0; i < len; i++)
11861     if (name[i] == '/')
11862       last_slash = i;
11863   if (last_slash <= 0)
11864     return(true);
11865   if (last_slash >= len - 1) /* can't be > */
11866     return(is_directory(name));
11867   temp = name[last_slash + 1];
11868   name[last_slash + 1] = '\0';
11869   result = is_directory(name);
11870   name[last_slash + 1] = temp;
11871   return(result);
11872 }
11873 
11874 
save_as_file_exists_check(Widget w,XtPointer context,XtPointer info)11875 static void save_as_file_exists_check(Widget w, XtPointer context, XtPointer info)
11876 {
11877   Widget dialog = (Widget)context;
11878   char *filename = NULL;
11879   XmString s1;
11880   filename = XmTextGetString(w);
11881   if ((filename) && (*filename))
11882     {
11883       if ((mus_file_probe(filename)) &&
11884 	  (!is_directory(filename)))
11885 	{
11886 #ifndef _MSC_VER
11887 	  if (access(filename, W_OK) < 0)
11888 	    s1 = XmStringCreateLocalized((char *)"save as (file write-protected?):");
11889 	  else
11890 #endif
11891 	    s1 = XmStringCreateLocalized((char *)"save as (overwriting):");
11892 	}
11893       else
11894 	{
11895 	  if (!(directory_exists(filename)))
11896 	    s1 = XmStringCreateLocalized((char *)"save as (no such directory?):");
11897 	  else s1 = XmStringCreateLocalized((char *)"save as:");
11898 	}
11899     }
11900   else s1 = XmStringCreateLocalized((char *)"save as:");
11901   XtVaSetValues(dialog,
11902 		XmNselectionLabelString, s1,
11903 		NULL);
11904   if (filename) XtFree(filename);
11905 }
11906 
11907 
snd_mkdir(const char * filename)11908 static int snd_mkdir(const char *filename)
11909 {
11910 #ifdef __MINGW32__
11911   return(mkdir(filename));
11912 #else
11913   return(mkdir(filename, 0777));
11914 #endif
11915 }
11916 
11917 
save_as_mkdir_callback(Widget w,XtPointer context,XtPointer info)11918 static void save_as_mkdir_callback(Widget w, XtPointer context, XtPointer info)
11919 {
11920   save_as_dialog_info *sd = (save_as_dialog_info *)context;
11921   char *filename = NULL;
11922   filename = XmTextGetString(FSB_BOX(sd->dialog, XmDIALOG_TEXT));
11923   if (snd_mkdir(filename) < 0)
11924     {
11925       /* could not make the directory */
11926       char *str;
11927       str = mus_format("can't make %s: %s", filename, strerror(errno));
11928       post_file_dialog_error((const char *)str, sd->panel_data);
11929       clear_error_if_filename_changes(sd->dialog, sd->panel_data);
11930       free(str);
11931     }
11932   else
11933     {
11934       /* set FSB to new dir and force update */
11935       char *filter;
11936       filter = mus_format("%s*", filename); /* already has the "/" at the end */
11937       update_dir_list(sd->dialog, filter);
11938       free(filter);
11939       XtSetSensitive(w, false);
11940     }
11941   XtFree(filename);
11942 }
11943 
11944 
reflect_text_in_save_button(Widget w,XtPointer context,XtPointer info)11945 static void reflect_text_in_save_button(Widget w, XtPointer context, XtPointer info)
11946 {
11947   save_as_dialog_info *sd = (save_as_dialog_info *)context;
11948   /* w here is text widget, not button */
11949   XtSetSensitive(FSB_BOX(sd->dialog, XmDIALOG_OK_BUTTON), (!(file_is_directory(sd->dialog))));
11950   if (sd->mkdirB) XtSetSensitive(sd->mkdirB, file_is_nonexistent_directory(sd->dialog));
11951 }
11952 
11953 
reflect_text_in_extract_button(Widget w,XtPointer context,XtPointer info)11954 static void reflect_text_in_extract_button(Widget w, XtPointer context, XtPointer info)
11955 {
11956   save_as_dialog_info *sd = (save_as_dialog_info *)context;
11957   /* w here is text widget, not button */
11958   XtSetSensitive(sd->extractB, (!(file_is_directory(sd->dialog))));
11959 }
11960 
11961 
save_as_filter_text_activate_callback(Widget w,XtPointer context,XtPointer info)11962 static void save_as_filter_text_activate_callback(Widget w, XtPointer context, XtPointer info)
11963 {
11964   save_as_dialog_info *sd = (save_as_dialog_info *)context;
11965   force_directory_reread_and_let_filename_change(sd->dialog);
11966 }
11967 
11968 
make_save_as_dialog(save_as_dialog_info * sd,char * sound_name,mus_header_t header_type,mus_sample_t sample_type)11969 static void make_save_as_dialog(save_as_dialog_info *sd, char *sound_name, mus_header_t header_type, mus_sample_t sample_type)
11970 {
11971   char *file_string;
11972 
11973   sd->original_filename = sound_name;
11974   if (!(sd->dialog))
11975     {
11976       Arg args[32];
11977       int n;
11978       XmString xmstr1, xmstr2, s1;
11979       XmString filter_list_label, cancel_label;
11980       Widget extractB, mainform;
11981 
11982       n = 0;
11983       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
11984       s1 = XmStringCreateLocalized((char *)"save as:");
11985       XtSetArg(args[n], XmNselectionLabelString, s1); n++;
11986 
11987       xmstr1 = XmStringCreateLocalized((char *)"Save");
11988       XtSetArg(args[n], XmNokLabelString, xmstr1); n++;
11989 
11990       file_string = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char));
11991       snprintf(file_string, PRINT_BUFFER_SIZE, "save %s", sound_name);
11992 
11993       xmstr2 = XmStringCreateLocalized(file_string);
11994       XtSetArg(args[n], XmNdialogTitle, xmstr2); n++;
11995 
11996       filter_list_label = XmStringCreateLocalized((char *)"files listed:");
11997       XtSetArg(args[n], XmNfilterLabelString, filter_list_label); n++;
11998 
11999       cancel_label = XmStringCreateLocalized((char *)I_GO_AWAY);
12000       XtSetArg(args[n], XmNcancelLabelString, cancel_label); n++;
12001 
12002       sd->fp = (file_pattern_info *)calloc(1, sizeof(file_pattern_info));
12003       sd->fp->in_just_sounds_update = false;
12004       if (just_sounds(ss))
12005 	sd->fp->filter_choice = JUST_SOUNDS_FILTER;
12006       else sd->fp->filter_choice = NO_FILE_FILTER;
12007 
12008       sd->dp = (dialog_play_info *)calloc(1, sizeof(dialog_play_info));
12009       sd->fpop = (file_popup_info *)calloc(1, sizeof(file_popup_info));
12010       sd->fpop->fp = sd->fp;
12011 
12012       XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
12013       XtSetArg(args[n], XmNnoResize, false); n++;
12014       XtSetArg(args[n], XmNautoUnmanage, false); n++;
12015       XtSetArg(args[n], XmNchildPlacement, XmPLACE_ABOVE_SELECTION); n++;
12016       XtSetArg(args[n], XmNallowOverlap, false); n++;
12017       XtSetArg(args[n], XmNheight, 600); n++;
12018       XtSetArg(args[n], XmNuserData, (XtPointer)sd->fp); n++;
12019       XtSetArg(args[n], XmNfileFilterStyle, XmFILTER_HIDDEN_FILES); n++;
12020       XtSetArg(args[n], XmNfileSearchProc, snd_directory_reader); n++;        /* over-ride Motif's directory reader altogether */
12021 
12022       sd->dialog = XmCreateFileSelectionDialog(main_shell(ss), (char *)"save-as", args, n);
12023       sd->fp->dialog = sd->dialog;
12024       sd->dp->dialog = sd->dialog;
12025       sd->fpop->dialog = sd->dialog;
12026 
12027       free(file_string);
12028 
12029       XtUnmanageChild(FSB_BOX(sd->dialog, XmDIALOG_DIR_LIST_LABEL));
12030       XtUnmanageChild(FSB_BOX(sd->dialog, XmDIALOG_LIST_LABEL));
12031       XtUnmanageChild(FSB_BOX(sd->dialog, XmDIALOG_APPLY_BUTTON));
12032 
12033       XtVaSetValues(FSB_BOX(sd->dialog, XmDIALOG_FILTER_LABEL), XmNbackground, ss->basic_color, NULL);
12034       XtVaSetValues(FSB_BOX(sd->dialog, XmDIALOG_SELECTION_LABEL), XmNbackground, ss->basic_color, NULL);
12035 
12036       XmStringFree(s1);
12037       XmStringFree(xmstr1);
12038       XmStringFree(xmstr2);
12039       XmStringFree(filter_list_label);
12040       XmStringFree(cancel_label);
12041 
12042       sd->filename_widget = FSB_BOX(sd->dialog, XmDIALOG_TEXT);
12043       XtAddCallback(sd->dialog, XmNhelpCallback, save_as_help_callback, (XtPointer)sd);
12044       XtAddCallback(sd->dialog, XmNcancelCallback, save_as_cancel_callback, (XtPointer)sd);
12045       XtAddCallback(sd->dialog, XmNokCallback, save_as_ok_callback, (XtPointer)sd);
12046 
12047       mainform = XtVaCreateManagedWidget("filebuttons-mainform", xmFormWidgetClass, sd->dialog, NULL);
12048       add_play_and_just_sounds_buttons(sd->dialog, mainform, sd->fp, sd->dp);
12049 
12050       n = 0;
12051       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
12052       XtSetArg(args[n], XmNtopWidget, sd->fp->just_sounds_button); n++;
12053       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
12054       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
12055       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
12056       sd->panel_data = make_file_data_panel(mainform, "data-form", args, n,
12057 					    (sd->type == REGION_SAVE_AS) ? WITHOUT_CHANNELS_FIELD : WITH_EXTRACT_CHANNELS_FIELD,
12058 					    header_type, sample_type,
12059 					    WITHOUT_DATA_LOCATION_FIELD,
12060 					    WITHOUT_SAMPLES_FIELD,
12061 					    WITH_HEADER_TYPE_FIELD,
12062 					    WITH_COMMENT_FIELD,
12063 					    WITH_WRITABLE_HEADERS,
12064 					    WITH_SRATE,
12065 					    sd->type == SOUND_SAVE_AS); /* auto comment */
12066 
12067       sd->panel_data->dialog = sd->dialog;
12068 
12069       color_file_selection_box(sd->dialog);
12070 
12071       XtVaSetValues(sd->panel_data->sample_type_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL);
12072       XtVaSetValues(sd->panel_data->header_type_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL);
12073       XtVaSetValues(sd->fp->just_sounds_button, XmNselectColor, ss->selection_color, NULL);
12074 #if WITH_AUDIO
12075       XtVaSetValues(sd->dp->play_button, XmNselectColor, ss->selection_color, NULL);
12076 #endif
12077 
12078       XtVaSetValues(sd->panel_data->src_button, XmNselectColor, ss->selection_color, NULL);
12079       if (sd->type == SOUND_SAVE_AS)
12080 	{
12081 	  XtVaSetValues(sd->panel_data->auto_comment_button, XmNselectColor, ss->selection_color, NULL);
12082 	  XtAddCallback(sd->panel_data->auto_comment_button, XmNvalueChangedCallback, auto_comment_callback, (XtPointer)sd);
12083 	}
12084       XtAddCallback(FSB_BOX(sd->dialog, XmDIALOG_LIST),
12085 		    XmNbrowseSelectionCallback, save_as_dialog_select_callback, (XtPointer)(sd->dp));
12086       XtAddCallback(sd->filename_widget, XmNvalueChangedCallback, save_as_file_exists_check, (XtPointer)(sd->dialog));
12087       XtAddCallback(FSB_BOX(sd->dialog, XmDIALOG_FILTER_TEXT), XmNactivateCallback, save_as_filter_text_activate_callback, (void *)sd);
12088 
12089       {
12090 	Widget wtmp;
12091 	wtmp = FSB_BOX(sd->dialog, XmDIALOG_DIR_LIST);
12092 	if (wtmp) XtAddCallback(wtmp, XmNbrowseSelectionCallback, file_change_directory_callback, (XtPointer)(sd->fp));
12093       }
12094 
12095       add_file_popups(sd->fpop);
12096 
12097       /* this must come after the file data panel so that Motif puts it in the button box, not the main work area */
12098       if (sd->type != REGION_SAVE_AS)
12099 	{
12100 	  /* add "Extract" button */
12101 	  n = 0;
12102 	  XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
12103 	  XtSetArg(args[n], XmNarmColor,   ss->selection_color); n++;
12104 	  extractB = XtCreateManagedWidget("Extract", xmPushButtonGadgetClass, sd->dialog, args, n);
12105 	  XtAddCallback(extractB, XmNactivateCallback, save_as_extract_callback, (XtPointer)sd);
12106 	  sd->extractB = extractB;
12107 
12108 	  XtSetSensitive(extractB, (!(file_is_directory(sd->dialog))));
12109 	  XtAddCallback(FSB_BOX(sd->dialog, XmDIALOG_TEXT), XmNvalueChangedCallback, reflect_text_in_extract_button, (void *)sd);
12110 	}
12111 
12112       /* add "Mkdir" button */
12113       n = 0;
12114       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
12115       XtSetArg(args[n], XmNarmColor,   ss->selection_color); n++;
12116       sd->mkdirB = XtCreateManagedWidget("Mkdir", xmPushButtonGadgetClass, sd->dialog, args, n);
12117       XtAddCallback(sd->mkdirB, XmNactivateCallback, save_as_mkdir_callback, (XtPointer)sd);
12118       XtSetSensitive(sd->mkdirB, false);
12119 
12120       XtSetSensitive(FSB_BOX(sd->dialog, XmDIALOG_OK_BUTTON), (!(file_is_directory(sd->dialog))));
12121       XtAddCallback(FSB_BOX(sd->dialog, XmDIALOG_TEXT), XmNvalueChangedCallback, reflect_text_in_save_button, (void *)sd);
12122 
12123       XtManageChild(sd->dialog);
12124       switch (sd->type)
12125 	{
12126 	case SOUND_SAVE_AS:
12127 	  set_dialog_widget(SOUND_SAVE_AS_DIALOG, sd->dialog);
12128 	  break;
12129 
12130 	case SELECTION_SAVE_AS:
12131 	  set_dialog_widget(SELECTION_SAVE_AS_DIALOG, sd->dialog);
12132 	  break;
12133 
12134 	case REGION_SAVE_AS:
12135 	  set_dialog_widget(REGION_SAVE_AS_DIALOG, sd->dialog);
12136 	  break;
12137 
12138 	default:
12139 	  snd_error("internal screw up");
12140 	  break;
12141 	}
12142     }
12143   else
12144     {
12145       XmString xmstr2;
12146       file_string = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char));
12147       snprintf(file_string, PRINT_BUFFER_SIZE, "save %s", sound_name);
12148       xmstr2 = XmStringCreateLocalized(file_string);
12149       XtVaSetValues(sd->dialog,
12150 		    XmNdialogTitle, xmstr2,
12151 		    NULL);
12152       XmStringFree(xmstr2);
12153       free(file_string);
12154     }
12155 }
12156 
12157 
make_sound_save_as_dialog_1(bool managed,int chan)12158 static save_as_dialog_info *make_sound_save_as_dialog_1(bool managed, int chan)
12159 {
12160   /* should the save-as dialog, at least in the file case, reflect the current file attributes/comment?
12161    *          or should we have a save-as-hook that can set up the dialog fields?
12162    */
12163 
12164   snd_info *sp = NULL;
12165   char *com = NULL;
12166   file_info *hdr = NULL;
12167   save_as_dialog_info *sd;
12168 
12169   if (!save_sound_as)
12170     save_sound_as = new_save_as_dialog_info(SOUND_SAVE_AS);
12171   sd = save_sound_as;
12172 
12173   sp = any_selected_sound();
12174   if (sp) hdr = sp->hdr;
12175 
12176   make_save_as_dialog(sd,
12177 		      (char *)((sp) ? sp->short_filename : ""),
12178 		      default_output_header_type(ss),
12179 		      default_output_sample_type(ss));
12180 
12181   set_file_dialog_sound_attributes(sd->panel_data,
12182 				   sd->panel_data->current_header_type,
12183 				   sd->panel_data->current_sample_type,
12184 				   (hdr) ? hdr->srate : selection_srate(),
12185 				   IGNORE_CHANS, IGNORE_DATA_LOCATION, IGNORE_SAMPLES,
12186 				   com = output_comment(hdr));
12187   if (com) free(com);
12188 
12189   if (chan >= 0)
12190     {
12191       char *chan_str;
12192       chan_str = (char *)calloc(16, sizeof(char));
12193       snprintf(chan_str, 16, "%d", chan);
12194       XmTextFieldSetString(sd->panel_data->chans_text, chan_str);
12195       free(chan_str);
12196     }
12197 
12198   if (sd->fp->reread_directory)
12199     {
12200       force_directory_reread(sd->dialog);
12201       sd->fp->reread_directory = false;
12202     }
12203 
12204   if ((managed) && (!XtIsManaged(sd->dialog)))
12205     XtManageChild(sd->dialog);
12206 
12207   make_auto_comment(sd);
12208   return(sd);
12209 }
12210 
12211 
make_sound_save_as_dialog(bool managed)12212 widget_t make_sound_save_as_dialog(bool managed)
12213 {
12214   save_as_dialog_info *sd;
12215   sd = make_sound_save_as_dialog_1(managed, -1);
12216   return(sd->dialog);
12217 }
12218 
12219 
make_channel_extract_dialog(int chan)12220 void make_channel_extract_dialog(int chan)
12221 {
12222   make_sound_save_as_dialog_1(true, chan);
12223 }
12224 
12225 
make_selection_save_as_dialog(bool managed)12226 widget_t make_selection_save_as_dialog(bool managed)
12227 {
12228   save_as_dialog_info *sd;
12229 
12230   if (!save_selection_as)
12231     save_selection_as = new_save_as_dialog_info(SELECTION_SAVE_AS);
12232   sd = save_selection_as;
12233 
12234   make_save_as_dialog(sd,
12235 		      (char *)"current selection",
12236 		      default_output_header_type(ss),
12237 		      default_output_sample_type(ss));
12238   set_file_dialog_sound_attributes(sd->panel_data,
12239 				   sd->panel_data->current_header_type,
12240 				   sd->panel_data->current_sample_type,
12241 				   selection_srate(),
12242 				   IGNORE_CHANS, IGNORE_DATA_LOCATION, IGNORE_SAMPLES,
12243 				   NULL);
12244   if (sd->fp->reread_directory)
12245     {
12246       force_directory_reread(sd->dialog);
12247       sd->fp->reread_directory = false;
12248     }
12249   if ((managed) && (!XtIsManaged(sd->dialog)))
12250     XtManageChild(sd->dialog);
12251   return(sd->dialog);
12252 }
12253 
12254 
make_region_save_as_dialog(bool managed)12255 widget_t make_region_save_as_dialog(bool managed)
12256 {
12257   save_as_dialog_info *sd;
12258   char *comment = NULL;
12259 
12260   if (!save_region_as)
12261     save_region_as = new_save_as_dialog_info(REGION_SAVE_AS);
12262   sd = save_region_as;
12263 
12264   make_save_as_dialog(sd,
12265 		      (char *)"selected region",
12266 		      default_output_header_type(ss),
12267 		      default_output_sample_type(ss));
12268   comment = region_description(region_dialog_region());
12269   set_file_dialog_sound_attributes(sd->panel_data,
12270 				   sd->panel_data->current_header_type,
12271 				   sd->panel_data->current_sample_type,
12272 				   region_srate(region_dialog_region()),
12273 				   IGNORE_CHANS, IGNORE_DATA_LOCATION, IGNORE_SAMPLES,
12274 				   comment);
12275   if (sd->fp->reread_directory)
12276     {
12277       force_directory_reread(sd->dialog);
12278       sd->fp->reread_directory = false;
12279     }
12280   if ((managed) && (!XtIsManaged(sd->dialog)))
12281     XtManageChild(sd->dialog);
12282   if (comment) free(comment);
12283   return(sd->dialog);
12284 }
12285 
12286 
12287 
12288 /* -------- save/restore for all these dialogs -------- */
12289 
save_file_dialog_state(FILE * fd)12290 void save_file_dialog_state(FILE *fd)
12291 {
12292   if ((odat) && (XtIsManaged(odat->dialog)))
12293     {
12294       /* odat->file_dialog_read_only -> "view-sound" dialog -- this distinction currently ignored */
12295 #if HAVE_SCHEME
12296       fprintf(fd, "(%s #t)\n", S_open_file_dialog);
12297 #endif
12298 #if HAVE_RUBY
12299       fprintf(fd, "%s(true)\n", to_proc_name(S_open_file_dialog));
12300 #endif
12301 #if HAVE_FORTH
12302       fprintf(fd, "#t %s drop\n", S_open_file_dialog);
12303 #endif
12304     }
12305   if ((mdat) && (XtIsManaged(mdat->dialog)))
12306     {
12307 #if HAVE_SCHEME
12308       fprintf(fd, "(%s #t)\n", S_mix_file_dialog);
12309 #endif
12310 #if HAVE_RUBY
12311       fprintf(fd, "%s(true)\n", to_proc_name(S_mix_file_dialog));
12312 #endif
12313 #if HAVE_FORTH
12314       fprintf(fd, "#t %s drop\n", S_mix_file_dialog);
12315 #endif
12316     }
12317   if ((idat) && (XtIsManaged(idat->dialog)))
12318     {
12319 #if HAVE_SCHEME
12320       fprintf(fd, "(%s #t)\n", S_insert_file_dialog);
12321 #endif
12322 #if HAVE_RUBY
12323       fprintf(fd, "%s(true)\n", to_proc_name(S_insert_file_dialog));
12324 #endif
12325 #if HAVE_FORTH
12326       fprintf(fd, "#t %s drop\n", S_insert_file_dialog);
12327 #endif
12328     }
12329   if ((save_sound_as) && (XtIsManaged(save_sound_as->dialog)))
12330     {
12331 #if HAVE_SCHEME
12332       fprintf(fd, "(%s #t)\n", S_save_sound_dialog);
12333 #endif
12334 #if HAVE_RUBY
12335       fprintf(fd, "%s(true)\n", to_proc_name(S_save_sound_dialog));
12336 #endif
12337 #if HAVE_FORTH
12338       fprintf(fd, "#t %s drop\n", S_save_sound_dialog);
12339 #endif
12340     }
12341   if ((save_selection_as) && (XtIsManaged(save_selection_as->dialog)))
12342     {
12343 #if HAVE_SCHEME
12344       fprintf(fd, "(%s #t)\n", S_save_selection_dialog);
12345 #endif
12346 #if HAVE_RUBY
12347       fprintf(fd, "%s(true)\n", to_proc_name(S_save_selection_dialog));
12348 #endif
12349 #if HAVE_FORTH
12350       fprintf(fd, "#t %s drop\n", S_save_selection_dialog);
12351 #endif
12352     }
12353   if ((save_region_as) && (XtIsManaged(save_region_as->dialog)))
12354     {
12355 #if HAVE_SCHEME
12356       fprintf(fd, "(%s #t)\n", S_save_region_dialog);
12357 #endif
12358 #if HAVE_RUBY
12359       fprintf(fd, "%s(true)\n", to_proc_name(S_save_region_dialog));
12360 #endif
12361 #if HAVE_FORTH
12362       fprintf(fd, "#t %s drop\n", S_save_region_dialog);
12363 #endif
12364     }
12365 }
12366 
12367 
12368 
12369 /* -------------------------------- New File -------------------------------- */
12370 
12371 static Widget new_file_dialog = NULL;
12372 static file_data *ndat = NULL;
12373 static mus_long_t initial_samples = 1;
12374 static Widget new_file_text = NULL;
12375 static char *new_file_filename = NULL;
12376 static void *new_file_watcher = NULL;
12377 
12378 
12379 static void new_filename_modify_callback(Widget w, XtPointer context, XtPointer info);
12380 
new_file_undoit(void)12381 static void new_file_undoit(void)
12382 {
12383   XmString ok_label;
12384   ok_label = XmStringCreateLocalized((char *)"Ok");
12385   XtVaSetValues(new_file_dialog,
12386 		XmNokLabelString, ok_label,
12387 		NULL);
12388   XmStringFree(ok_label);
12389   clear_dialog_error(ndat);
12390   XtRemoveCallback(new_file_text, XmNmodifyVerifyCallback, new_filename_modify_callback, NULL);
12391   new_file_watcher = unmonitor_file(new_file_watcher);
12392 }
12393 
12394 
new_filename_modify_callback(Widget w,XtPointer context,XtPointer info)12395 static void new_filename_modify_callback(Widget w, XtPointer context, XtPointer info)
12396 {
12397   XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info;
12398   new_file_undoit();
12399   cbs->doit = true;
12400 }
12401 
12402 
clear_error_if_new_filename_changes(Widget dialog)12403 static void clear_error_if_new_filename_changes(Widget dialog)
12404 {
12405   XtAddCallback(new_file_text, XmNmodifyVerifyCallback, new_filename_modify_callback, NULL);
12406 }
12407 
12408 
new_file_ok_callback(Widget w,XtPointer context,XtPointer info)12409 static void new_file_ok_callback(Widget w, XtPointer context, XtPointer info)
12410 {
12411   mus_long_t loc;
12412   char *newer_name = NULL, *msg;
12413   mus_header_t header_type;
12414   mus_sample_t sample_type;
12415   int srate, chans;
12416   newer_name = XmTextGetString(new_file_text);
12417   if ((!newer_name) || (!(*newer_name)))
12418     {
12419       msg = (char *)"new sound needs a file name ('New file:' field is empty)";
12420       post_file_dialog_error((const char *)msg, ndat);
12421       clear_error_if_new_filename_changes(new_file_dialog);
12422     }
12423   else
12424     {
12425       char *comment;
12426       redirect_snd_error_to(post_file_panel_error, (void *)ndat);
12427       comment = get_file_dialog_sound_attributes(ndat, &srate, &chans, &header_type, &sample_type, &loc, &initial_samples, 1);
12428       redirect_snd_error_to(NULL, NULL);
12429       if (ndat->error_widget != NOT_A_SCANF_WIDGET)
12430 	{
12431 	  clear_error_if_panel_changes(new_file_dialog, ndat);
12432 	}
12433       else
12434 	{
12435 	  /* handle the overwrite hook directly */
12436 	  if (new_file_filename) free(new_file_filename);
12437 	  new_file_filename = mus_expand_filename(newer_name);
12438 	  if ((!new_file_watcher) &&
12439 	      (ask_before_overwrite(ss)) &&
12440 	      (mus_file_probe(new_file_filename)))
12441 	    {
12442 	      XmString ok_label;
12443 	      msg = mus_format("%s exists. If you want to overwrite it, click 'DoIt'", newer_name);
12444 	      post_file_dialog_error((const char *)msg, ndat);
12445 	      clear_error_if_new_filename_changes(new_file_dialog);
12446 	      ok_label = XmStringCreateLocalized((char *)"DoIt");
12447 	      XtVaSetValues(new_file_dialog,
12448 			    XmNokLabelString, ok_label,
12449 			    NULL);
12450 	      XmUpdateDisplay(MSG_BOX(new_file_dialog, XmDIALOG_OK_BUTTON));
12451 	      XmStringFree(ok_label);
12452 	      free(msg);
12453 	    }
12454 	  else
12455 	    {
12456 	      snd_info *sp;
12457 	      if (new_file_watcher)
12458 		new_file_undoit();
12459 
12460 	      ss->local_errno = 0;
12461 	      redirect_snd_error_to(redirect_post_file_dialog_error, (void *)ndat);
12462 	      sp = snd_new_file(new_file_filename, chans, srate, sample_type, header_type, comment, initial_samples);
12463 	      redirect_snd_error_to(NULL, NULL);
12464 	      if (!sp)
12465 		{
12466 		  clear_error_if_new_filename_changes(new_file_dialog);
12467 		}
12468 	      else
12469 		{
12470 		  XtUnmanageChild(new_file_dialog);
12471 		}
12472 	    }
12473 	}
12474       XtFree(newer_name);
12475       if (comment) free(comment);
12476     }
12477 }
12478 
12479 
new_file_dialog_filename(mus_header_t header_type)12480 static char *new_file_dialog_filename(mus_header_t header_type)
12481 {
12482   static int new_file_dialog_file_ctr = 1;
12483   char *filename = NULL;
12484   const char *extension = NULL;
12485   filename = (char *)calloc(64, sizeof(char));
12486   switch (header_type)
12487     {
12488     case MUS_AIFC: extension = "aiff"; break;
12489     case MUS_AIFF: extension = "aiff"; break;
12490     case MUS_RIFF: extension = "wav";  break;
12491     case MUS_RF64: extension = "wav";  break;
12492     case MUS_CAFF: extension = "caf";  break;
12493     default:       extension = "snd";  break;
12494     }
12495   snprintf(filename, 64, "new-%d.%s", new_file_dialog_file_ctr++, extension);
12496   return(filename);
12497 }
12498 
12499 
load_new_file_defaults(char * newname)12500 static void load_new_file_defaults(char *newname)
12501 {
12502   char *new_comment = NULL;
12503   mus_header_t header_type;
12504   mus_sample_t sample_type;
12505   int chans, srate;
12506 
12507   header_type = default_output_header_type(ss);
12508   chans =       default_output_chans(ss);
12509   sample_type = default_output_sample_type(ss);
12510   srate =       default_output_srate(ss);
12511   new_comment = output_comment(NULL);
12512 
12513   if ((!newname) || (!(*newname)))
12514     newname = new_file_dialog_filename(header_type);
12515   mus_sound_forget(newname);
12516 
12517   set_file_dialog_sound_attributes(ndat, header_type, sample_type, srate, chans, IGNORE_DATA_LOCATION, initial_samples, new_comment);
12518   if (new_comment) free(new_comment);
12519 }
12520 
12521 
new_file_reset_callback(Widget w,XtPointer context,XtPointer info)12522 static void new_file_reset_callback(Widget w, XtPointer context, XtPointer info)
12523 {
12524   char *current_name;
12525   current_name = XmTextGetString(new_file_text);
12526   load_new_file_defaults(current_name);
12527   if (current_name) XtFree(current_name);
12528   if (new_file_watcher)
12529     new_file_undoit();
12530 }
12531 
12532 
new_file_cancel_callback(Widget w,XtPointer context,XtPointer info)12533 static void new_file_cancel_callback(Widget w, XtPointer context, XtPointer info)
12534 {
12535   XtUnmanageChild(w);
12536 }
12537 
12538 
new_file_help_callback(Widget w,XtPointer context,XtPointer info)12539 static void new_file_help_callback(Widget w, XtPointer context, XtPointer info)
12540 {
12541   new_file_dialog_help();
12542 }
12543 
12544 
make_new_file_dialog(bool managed)12545 widget_t make_new_file_dialog(bool managed)
12546 {
12547   if (!new_file_dialog)
12548     {
12549       Arg args[20];
12550       int n;
12551       XmString xok, xcancel, xhelp;
12552       Widget name_label, form;
12553       XmString titlestr;
12554       Widget sep, reset_button;
12555 
12556       titlestr = XmStringCreateLocalized((char *)"New file");
12557       xhelp = XmStringCreateLocalized((char *)I_HELP);
12558       xcancel = XmStringCreateLocalized((char *)I_GO_AWAY);
12559       xok = XmStringCreateLocalized((char *)"Ok");
12560 
12561       n = 0;
12562       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
12563       XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
12564       XtSetArg(args[n], XmNcancelLabelString, xcancel); n++;
12565       XtSetArg(args[n], XmNhelpLabelString, xhelp); n++;
12566       XtSetArg(args[n], XmNokLabelString, xok); n++;
12567       XtSetArg(args[n], XmNdialogTitle, titlestr); n++;
12568       XtSetArg(args[n], XmNnoResize, false); n++;
12569       XtSetArg(args[n], XmNautoUnmanage, false); n++;
12570       new_file_dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"new", args, n);
12571 
12572       XmStringFree(titlestr);
12573       XmStringFree(xok);
12574       XmStringFree(xcancel);
12575       XmStringFree(xhelp);
12576 
12577       XtAddCallback(new_file_dialog, XmNhelpCallback,   new_file_help_callback,   NULL);
12578       XtAddCallback(new_file_dialog, XmNcancelCallback, new_file_cancel_callback, NULL);
12579       XtAddCallback(new_file_dialog, XmNokCallback,     new_file_ok_callback,     NULL);
12580 
12581       n = 0;
12582       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
12583       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
12584       reset_button = XtCreateManagedWidget("Reset", xmPushButtonGadgetClass, new_file_dialog, args, n);
12585       XtAddCallback(reset_button, XmNactivateCallback, new_file_reset_callback, NULL);
12586 
12587       n = 0;
12588       form = XtCreateManagedWidget("newfile", xmFormWidgetClass, new_file_dialog, args, n);
12589 
12590       n = 0;
12591       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
12592       XtSetArg(args[n], XmNforeground, ss->black); n++;
12593       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
12594       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
12595       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
12596       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
12597       name_label = XtCreateManagedWidget("New file:", xmLabelWidgetClass, form, args, n);
12598 
12599       n = 0;
12600       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
12601       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
12602       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
12603       XtSetArg(args[n], XmNleftWidget, name_label); n++;
12604       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
12605       new_file_text = make_textfield_widget("newtext", form, args, n, ACTIVATABLE, add_completer_func(filename_completer, NULL));
12606 
12607       n = 0;
12608       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
12609       XtSetArg(args[n], XmNtopWidget, new_file_text); n++;
12610       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
12611       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
12612       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
12613       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
12614       XtSetArg(args[n], XmNheight, 8); n++;
12615       XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
12616       sep = XtCreateManagedWidget("sep", xmSeparatorWidgetClass, form, args, n);
12617 
12618       n = 0;
12619       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
12620       XtSetArg(args[n], XmNtopWidget, sep); n++;
12621       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
12622       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
12623       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
12624       ndat = make_file_data_panel(form, "data-form", args, n,
12625 				  WITH_CHANNELS_FIELD,
12626 				  default_output_header_type(ss),
12627 				  default_output_sample_type(ss),
12628 				  WITHOUT_DATA_LOCATION_FIELD,
12629 				  WITH_SAMPLES_FIELD,
12630 				  WITH_HEADER_TYPE_FIELD,
12631 				  WITH_COMMENT_FIELD,
12632 				  WITH_BUILTIN_HEADERS,
12633 				  WITHOUT_SRATE,
12634 				  WITHOUT_AUTO_COMMENT);
12635       ndat->dialog = new_file_dialog;
12636       XtManageChild(ndat->error_text);
12637       XtManageChild(new_file_dialog);
12638 
12639       map_over_children(new_file_dialog, set_main_color_of_widget);
12640       XtVaSetValues(ndat->sample_type_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL);
12641       XtVaSetValues(ndat->header_type_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL);
12642 
12643       XtVaSetValues(MSG_BOX(new_file_dialog, XmDIALOG_OK_BUTTON),     XmNarmColor,   ss->selection_color, NULL);
12644       XtVaSetValues(MSG_BOX(new_file_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor,   ss->selection_color, NULL);
12645       XtVaSetValues(MSG_BOX(new_file_dialog, XmDIALOG_HELP_BUTTON),   XmNarmColor,   ss->selection_color, NULL);
12646       XtVaSetValues(MSG_BOX(new_file_dialog, XmDIALOG_OK_BUTTON),     XmNbackground, ss->highlight_color,   NULL);
12647       XtVaSetValues(MSG_BOX(new_file_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color,   NULL);
12648       XtVaSetValues(MSG_BOX(new_file_dialog, XmDIALOG_HELP_BUTTON),   XmNbackground, ss->highlight_color,   NULL);
12649 
12650       set_dialog_widget(NEW_FILE_DIALOG, new_file_dialog);
12651       XtUnmanageChild(ndat->error_text);
12652 
12653       load_new_file_defaults(NULL);
12654     }
12655   else
12656     {
12657       char *new_name;
12658       new_name = XmTextGetString(new_file_text);
12659 
12660       if (new_file_watcher)
12661 	{
12662 	  /* if overwrite question pends, but file has been deleted in the meantime, go back to normal state */
12663 	  if ((!new_name) || (!(*new_name)) ||
12664 	      (!(mus_file_probe(new_name))))
12665 	    new_file_undoit();
12666 	}
12667 
12668       if (strncmp(new_name, "new-", 4) == 0)
12669 	{
12670 	  /* if file is open with currently posted new-file dialog name, and it's our name (new-%d), then tick the counter */
12671 	  snd_info *sp;
12672 	  sp = find_sound(new_name, 0);
12673 	  if (sp)
12674 	    {
12675 	      char *filename;
12676 	      filename = new_file_dialog_filename(default_output_header_type(ss));
12677 	      XmTextSetString(new_file_text, filename);
12678 	      mus_sound_forget(filename);
12679 	      free(filename);
12680 	    }
12681 	}
12682       if (new_name) XtFree(new_name);
12683     }
12684   if ((managed) &&
12685       (!(XtIsManaged(new_file_dialog))))
12686     XtManageChild(new_file_dialog);
12687   return(new_file_dialog);
12688 }
12689 
12690 
12691 
12692 /* ---------------- Edit Header ---------------- */
12693 
12694 typedef struct edhead_info {
12695   Widget dialog;
12696   file_data *edat;
12697   snd_info *sp;
12698   bool panel_changed;
12699   void *file_ro_watcher;
12700   int sp_ro_watcher_loc;
12701 } edhead_info;
12702 
12703 static int edhead_info_size = 0;
12704 static edhead_info **edhead_infos = NULL;
12705 
12706 
new_edhead_dialog(void)12707 static edhead_info *new_edhead_dialog(void)
12708 {
12709   int loc = -1;
12710   if (edhead_info_size == 0)
12711     {
12712       loc = 0;
12713       edhead_info_size = 4;
12714       edhead_infos = (edhead_info **)calloc(edhead_info_size, sizeof(edhead_info *));
12715     }
12716   else
12717     {
12718       int i;
12719       for (i = 0; i < edhead_info_size; i++)
12720 	if ((!edhead_infos[i]) ||
12721 	    (!(XtIsManaged(edhead_infos[i]->dialog))))
12722 	  {
12723 	    loc = i;
12724 	    break;
12725 	  }
12726       if (loc == -1)
12727 	{
12728 	  loc = edhead_info_size;
12729 	  edhead_info_size += 4;
12730 	  edhead_infos = (edhead_info **)realloc(edhead_infos, edhead_info_size * sizeof(edhead_info *));
12731 	  for (i = loc; i < edhead_info_size; i++) edhead_infos[i] = NULL;
12732 	}
12733     }
12734   if (!edhead_infos[loc])
12735     {
12736       edhead_infos[loc] = (edhead_info *)calloc(1, sizeof(edhead_info));
12737       edhead_infos[loc]->dialog = NULL;
12738       edhead_infos[loc]->panel_changed = false;
12739     }
12740   edhead_infos[loc]->sp = NULL;
12741   edhead_infos[loc]->file_ro_watcher = NULL;
12742   return(edhead_infos[loc]);
12743 }
12744 
12745 
make_header_dialog_title(edhead_info * ep,snd_info * sp)12746 static XmString make_header_dialog_title(edhead_info *ep, snd_info *sp)
12747 {
12748   /* dialog may not yet exist */
12749   char *str;
12750   XmString xstr;
12751   str = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char));
12752   if ((sp->user_read_only == FILE_READ_ONLY) ||
12753       (sp->file_read_only == FILE_READ_ONLY))
12754     {
12755       if (sp->hdr->type == MUS_RAW)
12756 	snprintf(str, PRINT_BUFFER_SIZE, "Add header to (write-protected) %s", sp->short_filename);
12757       else snprintf(str, PRINT_BUFFER_SIZE, "Edit header of (write-protected) %s", sp->short_filename);
12758       if (ep->dialog)
12759 	set_sensitive(MSG_BOX(ep->dialog, XmDIALOG_OK_BUTTON), (sp->hdr->type == MUS_RAW));
12760     }
12761   else
12762     {
12763       if (sp->hdr->type == MUS_RAW)
12764 	snprintf(str, PRINT_BUFFER_SIZE, "Add header to %s", sp->short_filename);
12765       else snprintf(str, PRINT_BUFFER_SIZE, "Edit header of %s", sp->short_filename);
12766       if (ep->dialog)
12767 	set_sensitive(MSG_BOX(ep->dialog, XmDIALOG_OK_BUTTON), ep->panel_changed);
12768     }
12769   xstr = XmStringCreateLocalized(str);
12770   free(str);
12771   return(xstr);
12772 }
12773 
12774 
edit_header_help_callback(Widget w,XtPointer context,XtPointer info)12775 static void edit_header_help_callback(Widget w, XtPointer context, XtPointer info)
12776 {
12777   edit_header_dialog_help();
12778 }
12779 
12780 
edit_header_set_ok_sensitive(Widget w,XtPointer context,XtPointer info)12781 static void edit_header_set_ok_sensitive(Widget w, XtPointer context, XtPointer info)
12782 {
12783   edhead_info *ep = (edhead_info *)context;
12784   if (ep->sp->file_read_only == FILE_READ_WRITE)
12785     set_sensitive(MSG_BOX(ep->dialog, XmDIALOG_OK_BUTTON), true);
12786   ep->panel_changed = true;
12787 }
12788 
12789 
eh_cancel(edhead_info * ep)12790 static void eh_cancel(edhead_info *ep)
12791 {
12792   unreflect_file_data_panel_change(ep->edat, (void *)ep, edit_header_set_ok_sensitive);
12793   ep->panel_changed = false;
12794   if ((ep->file_ro_watcher) &&
12795       (ep->sp) &&
12796       (ep->sp->active) &&
12797       (ep->sp->filename))
12798     ep->file_ro_watcher = unmonitor_file(ep->file_ro_watcher);
12799 }
12800 
12801 
edit_header_cancel_callback(Widget w,XtPointer context,XtPointer info)12802 static void edit_header_cancel_callback(Widget w, XtPointer context, XtPointer info)
12803 {
12804   edhead_info *ep = (edhead_info *)context;
12805   XtUnmanageChild(ep->dialog);
12806   eh_cancel(ep);
12807 }
12808 
12809 
edit_header_wm_delete_callback(Widget w,XtPointer context,XtPointer info)12810 static void edit_header_wm_delete_callback(Widget w, XtPointer context, XtPointer info)
12811 {
12812   eh_cancel((edhead_info *)context);
12813 }
12814 
12815 
edit_header_ok_callback(Widget w,XtPointer context,XtPointer info)12816 static void edit_header_ok_callback(Widget w, XtPointer context, XtPointer info)
12817 {
12818   edhead_info *ep = (edhead_info *)context;
12819   if ((ep->sp) && (ep->sp->active))
12820     {
12821       if (XmGetFocusWidget(ep->dialog) == MSG_BOX(ep->dialog, XmDIALOG_OK_BUTTON))
12822 	{
12823 	  bool ok;
12824 	  redirect_snd_error_to(redirect_post_file_dialog_error, (void *)(ep->edat));
12825 	  ok = edit_header_callback(ep->sp, ep->edat, redirect_post_file_dialog_error, post_file_panel_error);
12826 	  /* edit_header_callback, if all goes well, writes the header, recopies the data,
12827 	   *   then calls snd_update which closes the sound and reopens it, to force the
12828 	   *   new_header to take effect.  The read-only watcher is disabled during that
12829 	   *   process to keep it from getting a SOUND_IS_CLOSING message from close.
12830 	   */
12831 	  redirect_snd_error_to(NULL, NULL);
12832 	  if (ep->edat->error_widget != NOT_A_SCANF_WIDGET)
12833 	    {
12834 	      clear_error_if_panel_changes(ep->dialog, ep->edat);
12835 	      return;
12836 	    }
12837 	  else
12838 	    {
12839 	      if (!ok)
12840 		{
12841 		  set_sensitive(MSG_BOX(ep->dialog, XmDIALOG_OK_BUTTON), false);
12842 		  return;
12843 		}
12844 	    }
12845 	  ep->file_ro_watcher = unmonitor_file(ep->file_ro_watcher);
12846 	  XtUnmanageChild(ep->dialog);
12847 	  unreflect_file_data_panel_change(ep->edat, (void *)ep, edit_header_set_ok_sensitive);
12848 	}
12849     }
12850 }
12851 
12852 
edit_header(snd_info * sp)12853 Widget edit_header(snd_info *sp)
12854 {
12855   file_info *hdr;
12856   XmString xstr4;
12857   Widget main_w;
12858   edhead_info *ep = NULL;
12859 
12860   if (!sp) return(NULL);
12861 
12862   /* look for a dialog already editing this sound, raise if found, else make a new one */
12863   if (edhead_info_size > 0)
12864     {
12865       int i;
12866       for (i = 0; i < edhead_info_size; i++)
12867 	if ((edhead_infos[i]) &&
12868 	    ((edhead_infos[i]->sp == sp) ||
12869 	     ((edhead_infos[i]->sp) && /* maybe same sound open twice -- only one edit header dialog for it */
12870 	      (edhead_infos[i]->sp->inuse == SOUND_NORMAL) &&
12871 	      (mus_strcmp(sp->filename, edhead_infos[i]->sp->filename)))))
12872 	  {
12873 	    ep = edhead_infos[i];
12874 	    break;
12875 	  }
12876     }
12877   if (!ep)
12878     ep = new_edhead_dialog();
12879 
12880   ep->sp = sp;
12881   hdr = sp->hdr;
12882   ep->panel_changed = (hdr->type == MUS_RAW);
12883   xstr4 = make_header_dialog_title(ep, sp);
12884 
12885   if (!ep->dialog)
12886     {
12887       int n;
12888       Arg args[20];
12889       XmString xstr1, xstr2, xstr3, titlestr;
12890 
12891       n = 0;
12892       xstr1 = XmStringCreateLocalized((char *)I_GO_AWAY); /* needed by template dialog */
12893       xstr2 = XmStringCreateLocalized((char *)I_HELP);
12894       xstr3 = XmStringCreateLocalized((char *)"Save");
12895       titlestr = XmStringCreateLocalized((char *)"Edit Header");
12896 
12897       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
12898       XtSetArg(args[n], XmNcancelLabelString, xstr1); n++;
12899       XtSetArg(args[n], XmNhelpLabelString, xstr2); n++;
12900       XtSetArg(args[n], XmNokLabelString, xstr3); n++;
12901       XtSetArg(args[n], XmNmessageString, xstr4); n++;
12902       XtSetArg(args[n], XmNdialogTitle, titlestr); n++;
12903       XtSetArg(args[n], XmNautoUnmanage, false); n++;
12904       XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
12905       XtSetArg(args[n], XmNnoResize, false); n++;
12906       XtSetArg(args[n], XmNtransient, false); n++;
12907       ep->dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"Edit Header", args, n);
12908 
12909       XtAddCallback(ep->dialog, XmNcancelCallback, edit_header_cancel_callback, (XtPointer)ep);
12910       XtAddCallback(ep->dialog, XmNhelpCallback,   edit_header_help_callback,   (XtPointer)ep);
12911       XtAddCallback(ep->dialog, XmNokCallback,     edit_header_ok_callback,     (XtPointer)ep);
12912 
12913       XmStringFree(xstr1);
12914       XmStringFree(xstr2);
12915       XmStringFree(xstr3);
12916       XmStringFree(titlestr);
12917 
12918       n = 0;
12919       main_w = XtCreateManagedWidget("eh-main", xmFormWidgetClass, ep->dialog, args, n);
12920 
12921       n = 0;
12922       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
12923       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
12924       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
12925       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
12926       ep->edat = make_file_data_panel(main_w, "Edit Header", args, n,
12927 				      WITH_CHANNELS_FIELD,
12928 				      hdr->type,
12929 				      hdr->sample_type,
12930 				      WITH_DATA_LOCATION_FIELD,
12931 				      WITH_SAMPLES_FIELD,
12932 				      WITH_HEADER_TYPE_FIELD,
12933 				      WITH_COMMENT_FIELD,
12934 				      WITH_BUILTIN_HEADERS,
12935 				      WITHOUT_SRATE,
12936 				      WITHOUT_AUTO_COMMENT);
12937       ep->edat->dialog = ep->dialog;
12938 
12939       if (hdr->type == MUS_RAW)
12940 	set_file_dialog_sound_attributes(ep->edat,
12941 					 default_output_header_type(ss),
12942 					 hdr->sample_type, hdr->srate, hdr->chans,
12943 					 hdr->data_location, hdr->samples, hdr->comment);
12944       else set_file_dialog_sound_attributes(ep->edat,
12945 					    hdr->type, hdr->sample_type, hdr->srate, hdr->chans,
12946 					    hdr->data_location, hdr->samples, hdr->comment);
12947       XtManageChild(ep->edat->error_text);
12948       XtManageChild(ep->dialog);
12949 
12950       map_over_children(ep->dialog, set_main_color_of_widget);
12951       XtVaSetValues(MSG_BOX(ep->dialog, XmDIALOG_OK_BUTTON),     XmNarmColor,   ss->selection_color, NULL);
12952       XtVaSetValues(MSG_BOX(ep->dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor,   ss->selection_color, NULL);
12953       XtVaSetValues(MSG_BOX(ep->dialog, XmDIALOG_HELP_BUTTON),   XmNarmColor,   ss->selection_color, NULL);
12954       XtVaSetValues(MSG_BOX(ep->dialog, XmDIALOG_OK_BUTTON),     XmNbackground, ss->highlight_color,   NULL);
12955       XtVaSetValues(MSG_BOX(ep->dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color,   NULL);
12956       XtVaSetValues(MSG_BOX(ep->dialog, XmDIALOG_HELP_BUTTON),   XmNbackground, ss->highlight_color,   NULL);
12957       XtVaSetValues(ep->edat->header_type_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL);
12958       XtVaSetValues(ep->edat->sample_type_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL);
12959 
12960       XtVaSetValues(MSG_BOX(ep->dialog, XmDIALOG_MESSAGE_LABEL), XmNbackground, ss->basic_color, NULL);
12961 
12962       set_dialog_widget(EDIT_HEADER_DIALOG, ep->dialog);
12963 
12964       {
12965 	Atom wm_delete_window;
12966 	wm_delete_window = XmInternAtom(main_display(ss), (char *)"WM_DELETE_WINDOW", false);
12967 	XmAddWMProtocolCallback(XtParent(ep->dialog), wm_delete_window, edit_header_wm_delete_callback, (XtPointer)ep);
12968       }
12969 
12970       XtUnmanageChild(ep->edat->error_text);
12971     }
12972   else
12973     {
12974       XtVaSetValues(ep->dialog,
12975 		    XmNmessageString, xstr4,
12976 		    NULL);
12977       if (hdr->type == MUS_RAW)
12978 	set_file_dialog_sound_attributes(ep->edat,
12979 					 default_output_header_type(ss),
12980 					 hdr->sample_type, hdr->srate, hdr->chans,
12981 					 hdr->data_location, hdr->samples, hdr->comment);
12982       else set_file_dialog_sound_attributes(ep->edat,
12983 					    hdr->type, hdr->sample_type, hdr->srate, hdr->chans,
12984 					    hdr->data_location, hdr->samples, hdr->comment);
12985       raise_dialog(ep->dialog);
12986       clear_dialog_error(ep->edat);
12987     }
12988   set_sensitive(MSG_BOX(ep->dialog, XmDIALOG_OK_BUTTON), (hdr->type == MUS_RAW)); /* nothing needs to be saved when we start */
12989   XmStringFree(xstr4);
12990   if (!(XtIsManaged(ep->dialog))) XtManageChild(ep->dialog);
12991   reflect_file_data_panel_change(ep->edat, (void *)ep, edit_header_set_ok_sensitive);
12992   return(ep->dialog);
12993 }
12994 
12995 
save_edit_header_dialog_state(FILE * fd)12996 void save_edit_header_dialog_state(FILE *fd)
12997 {
12998   int i;
12999   for (i = 0; i < edhead_info_size; i++)
13000     if (edhead_infos[i])
13001       {
13002 	edhead_info *ep;
13003 	ep = edhead_infos[i];
13004 	if ((ep->dialog) &&
13005 	    (XtIsManaged(ep->dialog)) &&
13006 	    (snd_ok(ep->sp)))
13007 	  {
13008 #if HAVE_SCHEME
13009 	    fprintf(fd, "(%s (%s \"%s\"))\n", S_edit_header_dialog, S_find_sound, ep->sp->short_filename);
13010 #endif
13011 #if HAVE_RUBY
13012 	    fprintf(fd, "%s(%s(\"%s\"))\n", to_proc_name(S_edit_header_dialog), to_proc_name(S_find_sound), ep->sp->short_filename);
13013 #endif
13014 #if HAVE_FORTH
13015 	    fprintf(fd, "\"%s\" %s %s drop\n", ep->sp->short_filename, S_find_sound, S_edit_header_dialog);
13016 #endif
13017 	    break;
13018 	  }
13019     }
13020 }
13021 
13022 
13023 typedef enum {VF_AT_CURSOR, VF_AT_END, VF_AT_BEGINNING, VF_AT_MARK, VF_AT_SAMPLE} vf_location_t;
13024 
13025 typedef struct {
13026   widget_t rw;
13027   widget_t nm;
13028 #if WITH_AUDIO
13029   widget_t pl;
13030 #endif
13031   int pos;
13032   void *vdat;
13033 } vf_row;
13034 
13035 typedef struct {
13036   vf_row **file_list_entries;
13037   int index, size;
13038   char **names;
13039   char **full_names;
13040   int end;
13041   int sorter;
13042   int *selected_files;
13043   int selected_files_size;
13044   int currently_selected_files;
13045   mus_float_t amp;
13046   vf_location_t location_choice;
13047   mus_float_t speed;
13048   graphics_context *env_ax;
13049   env_editor *spf;
13050   env *amp_env;
13051   bool has_error;
13052   int sort_items_size;
13053   speed_style_t speed_style;
13054   mus_long_t beg;
13055 
13056   int dirs_size;
13057   void *dirs;
13058   char **dir_names;
13059   bool need_update;
13060 
13061   widget_t dialog;
13062   widget_t file_list;
13063   widget_t file_list_holder;
13064   widget_t left_title;
13065   widget_t info1;
13066   widget_t info2;
13067   widget_t mixB;
13068   widget_t insertB;
13069   widget_t at_cursor_button;
13070   widget_t at_end_button;
13071   widget_t at_beginning_button;
13072   widget_t at_mark_button;
13073   widget_t at_sample_button;
13074   widget_t at_sample_text;
13075   widget_t at_mark_text;
13076   widget_t amp_number;
13077   widget_t amp_scrollbar;
13078   widget_t speed_number;
13079   widget_t speed_scrollbar;
13080   widget_t env_drawer;
13081   widget_t a_to_z;
13082   widget_t z_to_a;
13083   widget_t new_to_old;
13084   widget_t old_to_new;
13085   widget_t small_to_big;
13086   widget_t big_to_small;
13087   widget_t smenu;
13088   widget_t current_play_button;
13089   widget_t amp_event;
13090   widget_t speed_event;
13091   widget_t speed_label_event;
13092   widget_t add_text;
13093   widget_t* sort_items;
13094 
13095   GC env_gc;
13096 } view_files_info;
13097 
13098 static void vf_unhighlight_row(widget_t nm, widget_t rw);
13099 static void vf_highlight_row(widget_t nm, widget_t rw);
13100 static void vf_post_info(view_files_info *vdat, int pos);
13101 static void vf_unpost_info(view_files_info *vdat);
13102 static mus_long_t vf_location(view_files_info *vdat);
13103 static void vf_post_error(const char *error_msg, view_files_info *data);
13104 static void redirect_vf_post_error(const char *error_msg, void *data);
13105 static void redirect_vf_post_location_error(const char *error_msg, void *data);
13106 static void vf_post_add_error(const char *error_msg, view_files_info *data);
13107 static widget_t make_view_files_dialog_1(view_files_info *vdat, bool managed);
13108 static void vf_post_selected_files_list(view_files_info *vdat);
13109 static void view_files_add_file_or_directory(view_files_info *vdat, const char *file_or_dir);
13110 static void vf_reflect_sort_choice_in_menu(view_files_info *vdat);
13111 static vf_row *view_files_make_row(view_files_info *vdat, widget_t last_row);
13112 static void vf_flash_row(vf_row *r);
13113 static void vf_set_amp(view_files_info *vdat, mus_float_t val);
13114 static void vf_set_speed(view_files_info *vdat, mus_float_t val);
13115 static void vf_set_amp_env(view_files_info *vdat, env *new_e);
13116 static void vf_clear_error(view_files_info *vdat);
13117 static void vf_mix_insert_buttons_set_sensitive(view_files_info *vdat, bool sensitive);
13118 static int vf_mix(view_files_info *vdat);
13119 static bool vf_insert(view_files_info *vdat);
13120 static void view_files_display_list(view_files_info *vdat);
13121 
view_files_unmonitor_directories(view_files_info * vdat)13122 static void view_files_unmonitor_directories(view_files_info *vdat) {}
view_files_monitor_directory(view_files_info * vdat,const char * dirname)13123 static void view_files_monitor_directory(view_files_info *vdat, const char *dirname) {}
13124 
13125 
13126 
13127 
13128 /* -------------------------------- Raw Data Dialog -------------------------------- */
13129 
13130 /* we keep an array of raw data dialogs so that any number can be active at once */
13131 
13132 typedef struct raw_info {
13133   Widget dialog;
13134   mus_long_t location;
13135   file_data *rdat;
13136   read_only_t read_only;
13137   bool selected;
13138   char *filename;
13139   char *help;
13140   open_requestor_t requestor;
13141   void *requestor_data;
13142   Widget requestor_dialog;
13143 } raw_info;
13144 
13145 static int raw_info_size = 0;
13146 static raw_info **raw_infos = NULL;
13147 
13148 
new_raw_dialog(void)13149 static raw_info *new_raw_dialog(void)
13150 {
13151   int loc = -1;
13152   if (raw_info_size == 0)
13153     {
13154       loc = 0;
13155       raw_info_size = 4;
13156       raw_infos = (raw_info **)calloc(raw_info_size, sizeof(raw_info *));
13157     }
13158   else
13159     {
13160       int i;
13161       for (i = 0; i < raw_info_size; i++)
13162 	if ((!raw_infos[i]) ||
13163 	    (!(XtIsManaged(raw_infos[i]->dialog))))
13164 	  {
13165 	    loc = i;
13166 	    break;
13167 	  }
13168       if (loc == -1)
13169 	{
13170 	  loc = raw_info_size;
13171 	  raw_info_size += 4;
13172 	  raw_infos = (raw_info **)realloc(raw_infos, raw_info_size * sizeof(raw_info *));
13173 	  for (i = loc; i < raw_info_size; i++) raw_infos[i] = NULL;
13174 	}
13175     }
13176   if (!raw_infos[loc])
13177     {
13178       raw_infos[loc] = (raw_info *)calloc(1, sizeof(raw_info));
13179       raw_infos[loc]->dialog = NULL;
13180       raw_infos[loc]->filename = NULL;
13181       raw_infos[loc]->help = NULL;
13182     }
13183   raw_infos[loc]->requestor = NO_REQUESTOR;
13184   raw_infos[loc]->requestor_data = NULL;
13185   raw_infos[loc]->location = 0;
13186   return(raw_infos[loc]);
13187 }
13188 
13189 
raw_data_ok_callback(Widget w,XtPointer context,XtPointer info)13190 static void raw_data_ok_callback(Widget w, XtPointer context, XtPointer info)
13191 {
13192   raw_info *rp = (raw_info *)context;
13193   int raw_srate = 0, raw_chans = 0;
13194   mus_sample_t raw_sample_type = MUS_UNKNOWN_SAMPLE;
13195 
13196   redirect_snd_error_to(post_file_panel_error, (void *)(rp->rdat));
13197   get_file_dialog_sound_attributes(rp->rdat, &raw_srate, &raw_chans, NULL, &raw_sample_type, &(rp->location), NULL, 1);
13198   redirect_snd_error_to(NULL, NULL);
13199 
13200   if (rp->rdat->error_widget != NOT_A_SCANF_WIDGET)
13201     {
13202       clear_error_if_panel_changes(rp->dialog, rp->rdat);
13203     }
13204   else
13205     {
13206       mus_header_set_raw_defaults(raw_srate, raw_chans, raw_sample_type);
13207       mus_sound_override_header(rp->filename, raw_srate, raw_chans,
13208 				raw_sample_type, MUS_RAW, rp->location,
13209 				mus_bytes_to_samples(raw_sample_type,
13210 						     mus_sound_length(rp->filename) - rp->location));
13211       /* choose action based on how we got here */
13212       if ((rp->requestor_dialog) &&
13213 	  ((rp->requestor == FROM_MIX_DIALOG) ||
13214 	   (rp->requestor == FROM_INSERT_DIALOG) ||
13215 	   (rp->requestor == FROM_VIEW_FILES_MIX_DIALOG) ||
13216 	   (rp->requestor == FROM_VIEW_FILES_INSERT_DIALOG)))
13217 	{
13218 	  ss->reloading_updated_file = true; /* don't reread lack-of-header! */
13219 	  /* redirection may be still set here, but I'll make it obvious */
13220 	  switch (rp->requestor)
13221 	    {
13222 	    case FROM_MIX_DIALOG:
13223 	      redirect_snd_error_to(redirect_file_open_error, (void *)mdat);
13224 	      mix_complete_file_at_cursor(any_selected_sound(), rp->filename);
13225 	      break;
13226 
13227 	    case FROM_INSERT_DIALOG:
13228 	      redirect_snd_error_to(redirect_file_open_error, (void *)idat);
13229 	      insert_complete_file_at_cursor(any_selected_sound(), rp->filename);
13230 	      break;
13231 
13232 	    case FROM_VIEW_FILES_MIX_DIALOG:
13233 	      {
13234 		view_files_info *vdat = (view_files_info *)(rp->requestor_data);
13235 		redirect_snd_error_to(redirect_vf_post_error, rp->requestor_data);
13236 		vf_mix(vdat);
13237 	      }
13238 	      break;
13239 
13240 	    case FROM_VIEW_FILES_INSERT_DIALOG:
13241 	      {
13242 		view_files_info *vdat = (view_files_info *)(rp->requestor_data);
13243 		redirect_snd_error_to(redirect_vf_post_error, rp->requestor_data);
13244 		vf_insert(vdat);
13245 	      }
13246 	      break;
13247 
13248 	    default:
13249 	      snd_error("wrong requestor type in raw data dialog? %d\n", (int)(rp->requestor));
13250 	      break;
13251 	    }
13252 	  redirect_snd_error_to(NULL, NULL);
13253 	  ss->reloading_updated_file = false;
13254 	}
13255       else
13256 	{
13257 	  /* FROM_OPEN_DIALOG (has requestor_dialog)
13258 	   * FROM_KEYBOARD (has sp = requestor_data)
13259 	   * FROM_DRAG_AND_DROP (just open, no needed side effects)
13260 	   * FROM_VIEW_FILES (ditto)
13261 	   * FROM_VIEW_FILES_MIX_DIALOG or INSERT -- requestor_data contains needed info to complete the action
13262 	   */
13263 	  file_info *hdr;
13264 	  hdr = (file_info *)calloc(1, sizeof(file_info));
13265 	  hdr->name = mus_strdup(rp->filename);
13266 	  hdr->type = MUS_RAW;
13267 	  hdr->srate = raw_srate;
13268 	  hdr->chans = raw_chans;
13269 	  hdr->sample_type = raw_sample_type;
13270 	  hdr->samples = mus_bytes_to_samples(raw_sample_type,
13271 					      mus_sound_length(rp->filename) - rp->location);
13272 	  hdr->data_location = rp->location;
13273 	  hdr->comment = NULL;
13274 	  if (rp->requestor == FROM_KEYBOARD)
13275 	    {
13276 	      clear_status_area((snd_info *)(rp->requestor_data));
13277 	      rp->selected = true;
13278 	    }
13279 	  finish_opening_sound(add_sound_window(rp->filename, rp->read_only, hdr), rp->selected);
13280 	}
13281       XtUnmanageChild(rp->dialog);
13282     }
13283 }
13284 
13285 
raw_data_cancel_callback(Widget w,XtPointer context,XtPointer info)13286 static void raw_data_cancel_callback(Widget w, XtPointer context, XtPointer info)
13287 {
13288   raw_info *rp = (raw_info *)context;
13289   XtUnmanageChild(rp->dialog);
13290   if ((rp->requestor_dialog) &&
13291       ((rp->requestor == FROM_OPEN_DIALOG) ||
13292        (rp->requestor == FROM_MIX_DIALOG)))
13293     XtManageChild(rp->requestor_dialog);
13294 }
13295 
13296 
raw_data_reset_callback(Widget w,XtPointer context,XtPointer info)13297 static void raw_data_reset_callback(Widget w, XtPointer context, XtPointer info)
13298 {
13299   raw_info *rp = (raw_info *)context;
13300   int raw_srate, raw_chans;
13301   mus_sample_t raw_sample_type;
13302   rp->location = 0;
13303   mus_header_raw_defaults(&raw_srate, &raw_chans, &raw_sample_type); /* pick up defaults */
13304   set_file_dialog_sound_attributes(rp->rdat,
13305 				   IGNORE_HEADER_TYPE,
13306 				   raw_sample_type, raw_srate, raw_chans, rp->location,
13307 				   IGNORE_SAMPLES, NULL);
13308   if (XtIsManaged(rp->rdat->error_text))
13309     XtUnmanageChild(rp->rdat->error_text);
13310 }
13311 
13312 
raw_data_help_callback(Widget w,XtPointer context,XtPointer info)13313 static void raw_data_help_callback(Widget w, XtPointer context, XtPointer info)
13314 {
13315   raw_info *rp = (raw_info *)context;
13316   raw_data_dialog_help(rp->help);
13317 }
13318 
13319 
make_raw_data_dialog(raw_info * rp,const char * title)13320 static void make_raw_data_dialog(raw_info *rp, const char *title)
13321 {
13322   XmString go_away, xhelp, xok, xtitle, titlestr;
13323   int n;
13324   int raw_srate, raw_chans;
13325   mus_sample_t raw_sample_type;
13326   Arg args[20];
13327   Widget reset_button, main_w;
13328 
13329   go_away = XmStringCreateLocalized((char *)I_GO_AWAY); /* needed by template dialog */
13330   xhelp = XmStringCreateLocalized((char *)I_HELP);
13331   xok = XmStringCreateLocalized((char *)"Ok");
13332   if (!title)
13333     titlestr = XmStringCreateLocalized((char *)"No header on file");
13334   else titlestr = XmStringCreateLocalized((char *)title);
13335   xtitle = XmStringCreateLocalized((char *)title);
13336 
13337   n = 0;
13338   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
13339   XtSetArg(args[n], XmNcancelLabelString, go_away); n++;
13340   XtSetArg(args[n], XmNhelpLabelString, xhelp); n++;
13341   XtSetArg(args[n], XmNokLabelString, xok); n++;
13342   XtSetArg(args[n], XmNmessageString, xtitle); n++;
13343   XtSetArg(args[n], XmNdialogTitle, titlestr); n++;
13344   XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
13345   XtSetArg(args[n], XmNallowShellResize, true); n++;
13346   XtSetArg(args[n], XmNnoResize, false); n++;
13347   XtSetArg(args[n], XmNautoUnmanage, false); n++;
13348   /* not transient -- we want this window to remain visible if possible */
13349   rp->dialog = XmCreateWarningDialog(main_shell(ss), (char *)"raw data", args, n);
13350 
13351   XtAddCallback(rp->dialog, XmNcancelCallback, raw_data_cancel_callback, (XtPointer)rp);
13352   XtAddCallback(rp->dialog, XmNhelpCallback,   raw_data_help_callback,   (XtPointer)rp);
13353   XtAddCallback(rp->dialog, XmNokCallback,     raw_data_ok_callback,     (XtPointer)rp);
13354   XmStringFree(go_away);
13355   XmStringFree(xhelp);
13356   XmStringFree(xok);
13357   XmStringFree(xtitle);
13358   XmStringFree(titlestr);
13359 
13360   n = 0;
13361   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
13362   XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
13363   reset_button = XtCreateManagedWidget("Reset", xmPushButtonGadgetClass, rp->dialog, args, n);
13364   XtAddCallback(reset_button, XmNactivateCallback, raw_data_reset_callback, (XtPointer)rp);
13365 
13366   mus_header_raw_defaults(&raw_srate, &raw_chans, &raw_sample_type); /* pick up defaults */
13367 
13368   n = 0;
13369   XtSetArg(args[n], XmNallowResize, true); n++;
13370   XtSetArg(args[n], XmNresizePolicy, XmRESIZE_NONE); n++;
13371   main_w = XtCreateManagedWidget("raw-main", xmFormWidgetClass, rp->dialog, args, n);
13372 
13373   n = 0;
13374   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
13375   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
13376   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
13377   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
13378   rp->rdat = make_file_data_panel(main_w, "data-form", args, n,
13379 				  WITH_CHANNELS_FIELD,
13380 				  MUS_RAW, raw_sample_type,
13381 				  WITH_DATA_LOCATION_FIELD,
13382 				  WITHOUT_SAMPLES_FIELD,
13383 				  WITHOUT_HEADER_TYPE_FIELD,
13384 				  WITHOUT_COMMENT_FIELD,
13385 				  WITH_READABLE_HEADERS,
13386 				  WITHOUT_SRATE,
13387 				  WITHOUT_AUTO_COMMENT);
13388   rp->rdat->dialog = rp->dialog;
13389 
13390   set_file_dialog_sound_attributes(rp->rdat,
13391 				   IGNORE_HEADER_TYPE,
13392 				   raw_sample_type, raw_srate, raw_chans, rp->location,
13393 				   IGNORE_SAMPLES, NULL);
13394 
13395   map_over_children(rp->dialog, set_main_color_of_widget);
13396   XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_OK_BUTTON),     XmNarmColor,   ss->selection_color, NULL);
13397   XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor,   ss->selection_color, NULL);
13398   XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_HELP_BUTTON),   XmNarmColor,   ss->selection_color, NULL);
13399   XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_OK_BUTTON),     XmNbackground, ss->highlight_color,   NULL);
13400   XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color,   NULL);
13401   XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_HELP_BUTTON),   XmNbackground, ss->highlight_color,   NULL);
13402   XtVaSetValues(reset_button, XmNselectColor, ss->selection_color, NULL);
13403   XtVaSetValues(rp->rdat->sample_type_list, XmNbackground, ss->white, XmNforeground, ss->black, NULL);
13404   /*
13405    * this line makes the dialog take up all vertical space on the screen
13406    * XtManageChild(rp->rdat->error_text);
13407   */
13408   XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_MESSAGE_LABEL), XmNbackground, ss->basic_color, NULL);
13409 
13410   XtManageChild(rp->dialog);
13411   XtUnmanageChild(rp->rdat->error_text);
13412   set_dialog_widget(RAW_DATA_DIALOG, rp->dialog);
13413 }
13414 
13415 
raw_data_dialog_to_file_info(const char * filename,char * title,char * info,read_only_t read_only,bool selected)13416 void raw_data_dialog_to_file_info(const char *filename, char *title, char *info, read_only_t read_only, bool selected)
13417 {
13418   /* put up dialog for srate, chans, sample type */
13419   raw_info *rp;
13420   rp = new_raw_dialog();
13421   rp->read_only = read_only;
13422   rp->selected = selected;
13423   if (rp->filename) free(rp->filename);
13424   rp->filename = mus_strdup(filename);
13425   rp->requestor = ss->open_requestor;
13426   rp->requestor_data = ss->open_requestor_data;
13427   rp->requestor_dialog = ss->requestor_dialog;
13428   ss->open_requestor = NO_REQUESTOR;
13429   ss->requestor_dialog = NULL;
13430   ss->open_requestor_data = NULL;
13431   if ((rp->requestor_dialog) &&
13432       ((rp->requestor == FROM_OPEN_DIALOG) ||
13433        (rp->requestor == FROM_MIX_DIALOG)))
13434     XtUnmanageChild(rp->requestor_dialog);
13435   if (!title)
13436     title = mus_format("no header found on %s\n", filename);
13437   if (!(rp->dialog))
13438     make_raw_data_dialog(rp, title);
13439   else
13440     {
13441       XmString xstr4;
13442       xstr4 = XmStringCreateLocalized(title);
13443       XtVaSetValues(rp->dialog,
13444 		    XmNmessageString, xstr4,
13445 		    NULL);
13446       XmStringFree(xstr4);
13447     }
13448   free(title);
13449   if (rp->help) free(rp->help);
13450   if (info)
13451     {
13452       XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_HELP_BUTTON),
13453 		    XmNbackground, ss->green,
13454 		    NULL);
13455       rp->help = mus_strdup(info);
13456       free(info);
13457     }
13458   else
13459     {
13460       XtVaSetValues(MSG_BOX(rp->dialog, XmDIALOG_HELP_BUTTON),
13461 		    XmNbackground, ss->highlight_color,
13462 		    NULL);
13463       rp->help = NULL;
13464     }
13465   raise_dialog(rp->dialog);
13466   if (!XtIsManaged(rp->dialog))
13467     XtManageChild(rp->dialog);
13468 }
13469 
13470 
13471 
13472 /* ---------------- INFO MONOLOG ---------------- */
13473 
13474 #define POST_IT_ROWS 12
13475 #define POST_IT_COLUMNS 56
13476 
13477 static Widget post_it_dialog = NULL;
13478 static Widget post_it_text = NULL;
13479 
13480 
create_post_it_monolog(void)13481 static void create_post_it_monolog(void)
13482 {
13483   /* create scrollable but not editable text window; used for fft peaks, sp info, and raw data help displays */
13484   Arg args[20];
13485   int n;
13486 
13487   n = 0;
13488   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
13489   XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
13490   XtSetArg(args[n], XmNnoResize, false); n++;
13491   XtSetArg(args[n], XmNtransient, false); n++;
13492   post_it_dialog = XmCreateMessageDialog(main_pane(ss), (char *)"info", args, n);
13493 
13494   XtUnmanageChild(MSG_BOX(post_it_dialog, XmDIALOG_CANCEL_BUTTON));
13495   XtUnmanageChild(MSG_BOX(post_it_dialog, XmDIALOG_HELP_BUTTON));
13496   XtUnmanageChild(MSG_BOX(post_it_dialog, XmDIALOG_SYMBOL_LABEL));
13497 
13498   XtVaSetValues(MSG_BOX(post_it_dialog, XmDIALOG_MESSAGE_LABEL), XmNbackground, ss->highlight_color, NULL);
13499 
13500   n = 0;
13501   XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
13502   XtSetArg(args[n], XmNeditable, false); n++;
13503   XtSetArg(args[n], XmNcolumns, POST_IT_COLUMNS); n++;
13504   XtSetArg(args[n], XmNrows, POST_IT_ROWS); n++;
13505   XtSetArg(args[n], XmNforeground, ss->black); n++; /* needed if color allocation fails completely */
13506   XtSetArg(args[n], XmNbackground, ss->white); n++;
13507   post_it_text = XmCreateScrolledText(post_it_dialog, (char *)"post-it-text", args, n);
13508   XtManageChild(post_it_text);
13509   XtManageChild(post_it_dialog);
13510 
13511   map_over_children(post_it_dialog, set_main_color_of_widget);
13512   XtVaSetValues(post_it_text, XmNbackground, ss->white, XmNforeground, ss->black, NULL);
13513   XtVaSetValues(MSG_BOX(post_it_dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL);
13514   XtVaSetValues(MSG_BOX(post_it_dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL);
13515 
13516   set_dialog_widget(POST_IT_DIALOG, post_it_dialog);
13517 }
13518 
13519 
post_it(const char * subject,const char * str)13520 widget_t post_it(const char *subject, const char *str)
13521 {
13522   /* place string in scrollable help window */
13523   XmString xstr1, xstr2;
13524   if (!ss) return(NULL); /* an attempt to call this before X/Motif is ready */
13525   if (!(post_it_dialog))
13526     create_post_it_monolog();
13527   else raise_dialog(post_it_dialog);
13528   xstr1 = XmStringCreateLocalized((char *)subject);
13529   xstr2 = XmStringCreateLocalized((char *)subject);
13530   XtVaSetValues(post_it_dialog,
13531 		XmNmessageString, xstr1,
13532 		XmNdialogTitle, xstr2,
13533 		NULL);
13534   XmTextSetString(post_it_text, (char *)str);
13535   if (!XtIsManaged(post_it_dialog))
13536     XtManageChild(post_it_dialog);
13537   XmStringFree(xstr1);
13538   XmStringFree(xstr2);
13539   return(post_it_dialog);
13540 }
13541 
13542 
post_it_append(const char * str)13543 void post_it_append(const char *str)
13544 {
13545   if (post_it_dialog)
13546     XmTextInsert(post_it_text, XmTextGetLastPosition(post_it_text), (char *)str);
13547 }
13548 
13549 
save_post_it_dialog_state(FILE * fd)13550 void save_post_it_dialog_state(FILE *fd)
13551 {
13552   if ((post_it_dialog) && (XtIsManaged(post_it_dialog)))
13553     {
13554       char *subject = NULL, *text = NULL;
13555       subject = dialog_get_title(post_it_dialog);
13556       text = XmTextGetString(post_it_text);
13557 #if HAVE_SCHEME
13558       fprintf(fd, "(%s \"%s\" \"%s\")\n", S_info_dialog, subject, text);
13559 #endif
13560 #if HAVE_RUBY
13561       fprintf(fd, "%s(\"%s\", \"%s\")\n", to_proc_name(S_info_dialog), subject, text);
13562 #endif
13563 #if HAVE_FORTH
13564       fprintf(fd, "\"%s\" \"%s\" %s drop\n", subject, text, S_info_dialog);
13565 #endif
13566       if (subject) free(subject);
13567       if (text) XtFree(text);
13568     }
13569 }
13570 
13571 
13572 /* ---------------- unsaved edits dialog ---------------- */
13573 
13574 static int num_unsaved_edits_dialogs = 0;
13575 static Widget *unsaved_edits_dialogs = NULL;
13576 static snd_info **unsaved_edits_sounds = NULL;
13577 
unsaved_edits_dialog(snd_info * sp)13578 static Widget unsaved_edits_dialog(snd_info *sp)
13579 {
13580   int i;
13581   /* are there any such dialogs? */
13582   if (num_unsaved_edits_dialogs == 0)
13583     return(NULL);
13584 
13585   /* now see if we've already prompted about this sound */
13586   for (i = 0; i < num_unsaved_edits_dialogs; i++)
13587     if (unsaved_edits_sounds[i] == sp)
13588       return(unsaved_edits_dialogs[i]);
13589 
13590   /* try to find a free unmanaged dialog */
13591   for (i = 0; i < num_unsaved_edits_dialogs; i++)
13592     if ((unsaved_edits_dialogs[i]) &&
13593 	(!XtIsManaged(unsaved_edits_dialogs[i])))
13594       return(unsaved_edits_dialogs[i]);
13595 
13596   return(NULL);
13597 }
13598 
save_unsaved_edits_dialog(Widget d,snd_info * sp)13599 static void save_unsaved_edits_dialog(Widget d, snd_info *sp)
13600 {
13601   if (num_unsaved_edits_dialogs == 0)
13602     {
13603       unsaved_edits_dialogs = (Widget *)calloc(1, sizeof(Widget));
13604       unsaved_edits_sounds = (snd_info **)calloc(1, sizeof(snd_info *));
13605     }
13606   else
13607     {
13608       unsaved_edits_dialogs = (Widget *)realloc(unsaved_edits_dialogs, (num_unsaved_edits_dialogs + 1) * sizeof(Widget));
13609       unsaved_edits_sounds = (snd_info **)realloc(unsaved_edits_sounds, (num_unsaved_edits_dialogs + 1) * sizeof(snd_info *));
13610     }
13611 
13612   unsaved_edits_dialogs[num_unsaved_edits_dialogs] = d;
13613   unsaved_edits_sounds[num_unsaved_edits_dialogs] = sp;
13614   num_unsaved_edits_dialogs++;
13615 }
13616 
13617 
unpost_unsaved_edits_if_any(snd_info * sp)13618 void unpost_unsaved_edits_if_any(snd_info *sp)
13619 {
13620   int i;
13621   for (i = 0; i < num_unsaved_edits_dialogs; i++)
13622     if (((unsaved_edits_sounds[i] == sp) ||
13623 	 (!snd_ok(unsaved_edits_sounds[i]))) &&
13624 	(XtIsManaged(unsaved_edits_dialogs[i])))
13625       XtUnmanageChild(unsaved_edits_dialogs[i]);
13626 }
13627 
13628 
zero_edits(chan_info * cp)13629 static void zero_edits(chan_info *cp)
13630 {
13631   cp->edit_ctr = 0;
13632 }
13633 
unsaved_edits_no_callback(Widget w,XtPointer context,XtPointer info)13634 static void unsaved_edits_no_callback(Widget w, XtPointer context, XtPointer info)
13635 {
13636   snd_info *sp = (snd_info *)context;
13637   for_each_sound_chan(sp, zero_edits);
13638   snd_close_file(sp);
13639 }
13640 
unsaved_edits_yes_callback(Widget w,XtPointer context,XtPointer info)13641 static void unsaved_edits_yes_callback(Widget w, XtPointer context, XtPointer info)
13642 {
13643   snd_info *sp = (snd_info *)context;
13644   save_edits(sp);
13645   snd_close_file(sp);
13646 }
13647 
unsaved_edits_help_callback(Widget w,XtPointer context,XtPointer info)13648 static void unsaved_edits_help_callback(Widget w, XtPointer context, XtPointer info)
13649 {
13650   snd_help("save edits?",
13651 	   "You have set " S_ask_about_unsaved_edits " to " PROC_TRUE ", so you will be asked whether you want \
13652 to save edits if you try to close a sound that has unsaved edits.",
13653 	   WITH_WORD_WRAP);
13654 }
13655 
save_edits_now(snd_info * sp)13656 void save_edits_now(snd_info *sp)
13657 {
13658   char *question;
13659   XmString q;
13660   Widget dialog;
13661 
13662   question = mus_format("%s has unsaved edits.  Save them?", sp->short_filename);
13663   q = XmStringCreateLocalized(question);
13664 
13665   dialog = unsaved_edits_dialog(sp);
13666   if (!dialog)
13667     {
13668       Arg args[20];
13669       int n;
13670       XmString yes, no;
13671 
13672       yes = XmStringCreateLocalized((char *)"yes");
13673       no = XmStringCreateLocalized((char *)"no");
13674 
13675       n = 0;
13676       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
13677       XtSetArg(args[n], XmNokLabelString, yes); n++;
13678       XtSetArg(args[n], XmNcancelLabelString, no); n++;
13679       XtSetArg(args[n], XmNmessageString, q); n++;
13680       dialog = XmCreateQuestionDialog(main_pane(ss), sp->filename, args, n);
13681       save_unsaved_edits_dialog(dialog, sp);
13682 
13683       XtAddCallback(dialog, XmNhelpCallback,   unsaved_edits_help_callback, (XtPointer)sp);
13684       XtAddCallback(dialog, XmNokCallback,     unsaved_edits_yes_callback,  (XtPointer)sp);
13685       XtAddCallback(dialog, XmNcancelCallback, unsaved_edits_no_callback,   (XtPointer)sp);
13686 
13687       XmStringFree(yes);
13688       XmStringFree(no);
13689 
13690       map_over_children(dialog, set_main_color_of_widget);
13691       XtVaSetValues(MSG_BOX(dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL);
13692       XtVaSetValues(MSG_BOX(dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL);
13693       XtVaSetValues(MSG_BOX(dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL);
13694       XtVaSetValues(MSG_BOX(dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL);
13695       XtVaSetValues(MSG_BOX(dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL);
13696       XtVaSetValues(MSG_BOX(dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL);
13697     }
13698   else
13699     {
13700       XtVaSetValues(dialog, XmNmessageString, q, NULL);
13701     }
13702 
13703   XmStringFree(q);
13704   free(question);
13705   XtManageChild(dialog);
13706 }
13707 
13708 
13709 
13710 /* ---------------- file has changed dialog ---------------- */
13711 
13712 static int num_file_has_changed_dialogs = 0;
13713 static Widget *file_has_changed_dialogs = NULL;
13714 static snd_info **file_has_changed_sounds = NULL;
13715 
file_has_changed_dialog(snd_info * sp)13716 static Widget file_has_changed_dialog(snd_info *sp)
13717 {
13718   int i;
13719   /* are there any such dialogs? */
13720   if (num_file_has_changed_dialogs == 0)
13721     return(NULL);
13722 
13723   /* now see if we've already prompted about this sound */
13724   for (i = 0; i < num_file_has_changed_dialogs; i++)
13725     if (file_has_changed_sounds[i] == sp)
13726       return(file_has_changed_dialogs[i]);
13727 
13728   /* try to find a free unmanaged dialog */
13729   for (i = 0; i < num_file_has_changed_dialogs; i++)
13730     if ((file_has_changed_dialogs[i]) &&
13731 	(!XtIsManaged(file_has_changed_dialogs[i])))
13732       return(file_has_changed_dialogs[i]);
13733 
13734   return(NULL);
13735 }
13736 
save_file_has_changed_dialog(Widget d,snd_info * sp)13737 static void save_file_has_changed_dialog(Widget d, snd_info *sp)
13738 {
13739   if (num_file_has_changed_dialogs == 0)
13740     {
13741       file_has_changed_dialogs = (Widget *)calloc(1, sizeof(Widget));
13742       file_has_changed_sounds = (snd_info **)calloc(1, sizeof(snd_info *));
13743     }
13744   else
13745     {
13746       file_has_changed_dialogs = (Widget *)realloc(file_has_changed_dialogs, (num_file_has_changed_dialogs + 1) * sizeof(Widget));
13747       file_has_changed_sounds = (snd_info **)realloc(file_has_changed_sounds, (num_file_has_changed_dialogs + 1) * sizeof(snd_info *));
13748     }
13749 
13750   file_has_changed_dialogs[num_file_has_changed_dialogs] = d;
13751   file_has_changed_sounds[num_file_has_changed_dialogs] = sp;
13752   num_file_has_changed_dialogs++;
13753 }
13754 
13755 
unpost_file_has_changed_if_any(snd_info * sp)13756 void unpost_file_has_changed_if_any(snd_info *sp)
13757 {
13758   int i;
13759   for (i = 0; i < num_file_has_changed_dialogs; i++)
13760     if (((file_has_changed_sounds[i] == sp) ||
13761 	 (!snd_ok(file_has_changed_sounds[i]))) &&
13762 	(XtIsManaged(file_has_changed_dialogs[i])))
13763       XtUnmanageChild(file_has_changed_dialogs[i]);
13764 }
13765 
13766 
file_has_changed_no_callback(Widget w,XtPointer context,XtPointer info)13767 static void file_has_changed_no_callback(Widget w, XtPointer context, XtPointer info)
13768 {
13769 }
13770 
file_has_changed_yes_callback(Widget w,XtPointer context,XtPointer info)13771 static void file_has_changed_yes_callback(Widget w, XtPointer context, XtPointer info)
13772 {
13773   snd_info *sp = (snd_info *)context;
13774   save_edits_without_asking(sp);
13775   sp->need_update = false;
13776   stop_bomb(sp);                  /* in case Snd already noticed the problem */
13777   clear_status_area(sp);
13778 }
13779 
file_has_changed_help_callback(Widget w,XtPointer context,XtPointer info)13780 static void file_has_changed_help_callback(Widget w, XtPointer context, XtPointer info)
13781 {
13782   snd_help("save edits?",
13783 	   "The file has changed unexpectedly, so in most cases, saving the current edits can't do anything useful.  But you can try anyway!",
13784 	   WITH_WORD_WRAP);
13785 }
13786 
changed_file_dialog(snd_info * sp)13787 void changed_file_dialog(snd_info *sp)
13788 {
13789   char *question;
13790   XmString q;
13791   Widget dialog;
13792 
13793   question = mus_format("%s has changed!  Save edits anyway?", sp->short_filename);
13794   q = XmStringCreateLocalized(question);
13795 
13796   dialog = file_has_changed_dialog(sp);
13797   if (!dialog)
13798     {
13799       Arg args[20];
13800       int n;
13801       XmString yes, no;
13802 
13803       yes = XmStringCreateLocalized((char *)"yes");
13804       no = XmStringCreateLocalized((char *)"no");
13805 
13806       n = 0;
13807       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
13808       XtSetArg(args[n], XmNokLabelString, yes); n++;
13809       XtSetArg(args[n], XmNcancelLabelString, no); n++;
13810       XtSetArg(args[n], XmNmessageString, q); n++;
13811       dialog = XmCreateQuestionDialog(main_pane(ss), sp->filename, args, n);
13812       save_file_has_changed_dialog(dialog, sp);
13813 
13814       XtAddCallback(dialog, XmNhelpCallback,   file_has_changed_help_callback, (XtPointer)sp);
13815       XtAddCallback(dialog, XmNokCallback,     file_has_changed_yes_callback,  (XtPointer)sp);
13816       XtAddCallback(dialog, XmNcancelCallback, file_has_changed_no_callback,   (XtPointer)sp);
13817 
13818       XmStringFree(yes);
13819       XmStringFree(no);
13820 
13821       map_over_children(dialog, set_main_color_of_widget);
13822       XtVaSetValues(MSG_BOX(dialog, XmDIALOG_OK_BUTTON), XmNarmColor, ss->selection_color, NULL);
13823       XtVaSetValues(MSG_BOX(dialog, XmDIALOG_OK_BUTTON), XmNbackground, ss->highlight_color, NULL);
13824       XtVaSetValues(MSG_BOX(dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor, ss->selection_color, NULL);
13825       XtVaSetValues(MSG_BOX(dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL);
13826       XtVaSetValues(MSG_BOX(dialog, XmDIALOG_HELP_BUTTON), XmNarmColor, ss->selection_color, NULL);
13827       XtVaSetValues(MSG_BOX(dialog, XmDIALOG_HELP_BUTTON), XmNbackground, ss->highlight_color, NULL);
13828     }
13829   else
13830     {
13831       XtVaSetValues(dialog, XmNmessageString, q, NULL);
13832     }
13833 
13834   XmStringFree(q);
13835   free(question);
13836   XtManageChild(dialog);
13837 }
13838 
13839 
13840 
13841 /* ---------------- view files dialog ---------------- */
13842 
13843 
13844 /* -------- view files shared code -------- */
13845 
13846 static void view_files_clear_selected_files(view_files_info *vdat);
13847 static int view_files_add_selected_file(view_files_info *vdat, vf_row *r);
13848 static int view_files_find_row(view_files_info *vdat, const char *name);
13849 static int view_files_info_size = 0;
13850 static view_files_info **view_files_infos = NULL;
13851 
vf_open_file_watcher(Xen hook_or_reason)13852 static Xen vf_open_file_watcher(Xen hook_or_reason)
13853 {
13854   int k;
13855   /* reasons are FILE_OPENED|CLOSED, but it's not worth the trouble of splitting them out here */
13856 
13857   /* loop through all vf dialogs ... */
13858   for (k = 0; k < view_files_info_size; k++)
13859     if ((view_files_infos[k]) &&
13860 	(view_files_infos[k]->dialog) &&
13861 	(widget_is_active(view_files_infos[k]->dialog)))
13862       {
13863 	view_files_info *vdat;
13864 	vdat = view_files_infos[k];
13865 	vf_mix_insert_buttons_set_sensitive(vdat,
13866 					    ((vdat->currently_selected_files > 0) &&
13867 					     (any_selected_sound())));
13868       }
13869   return(Xen_false);
13870 }
13871 
13872 
view_files_dialog_list_length(void)13873 int view_files_dialog_list_length(void)
13874 {
13875   int i, n = 0;
13876   for (i = 0; i < view_files_info_size; i++)
13877     if ((view_files_infos[i]) &&
13878 	(view_files_infos[i]->dialog))
13879       n++;
13880   return(n);
13881 }
13882 
13883 
view_files_dialog_titles(void)13884 char **view_files_dialog_titles(void)
13885 {
13886   int n;
13887   n = view_files_dialog_list_length();
13888   if (n > 0)
13889     {
13890       char **titles;
13891       int i, j = 0;
13892       titles = (char **)calloc(n + 1, sizeof(char *));
13893       for (i = 0; i < view_files_info_size; i++)
13894 	if ((view_files_infos[i]) &&
13895 	    (view_files_infos[i]->dialog))
13896 	  titles[j++] = dialog_get_title(view_files_infos[i]->dialog);
13897       return(titles);
13898     }
13899   return(NULL);
13900 }
13901 
13902 
view_files_start_dialog_with_title(const char * title)13903 void view_files_start_dialog_with_title(const char *title)
13904 {
13905   int i;
13906   for (i = 0; i < view_files_info_size; i++)
13907     if ((view_files_infos[i]) &&
13908 	(view_files_infos[i]->dialog))
13909       {
13910 	char *dialog_title = NULL;
13911 	dialog_title = dialog_get_title(view_files_infos[i]->dialog);
13912 	if (mus_strcmp(title, dialog_title)) /* this includes NULL == NULL */
13913 	  {
13914 	    if (dialog_title) free(dialog_title);
13915 	    make_view_files_dialog_1(view_files_infos[i], true);
13916 	    return;
13917 	  }
13918 	if (dialog_title) free(dialog_title);
13919       }
13920 }
13921 
13922 
new_view_files_dialog(void)13923 static view_files_info *new_view_files_dialog(void)
13924 {
13925   /* always returns a new (empty) file viewer -- changed 8-Jan-08 */
13926   int loc = -1;
13927   view_files_info *vdat;
13928 
13929   if (view_files_info_size == 0)
13930     {
13931       loc = 0;
13932       view_files_info_size = 4;
13933       view_files_infos = (view_files_info **)calloc(view_files_info_size, sizeof(view_files_info *));
13934     }
13935   else
13936     {
13937       int i;
13938       for (i = 0; i < view_files_info_size; i++)
13939 	if (!view_files_infos[i])
13940 	  {
13941 	    loc = i;
13942 	    break;
13943 	  }
13944       if (loc == -1)
13945 	{
13946 	  loc = view_files_info_size;
13947 	  view_files_info_size += 4;
13948 	  view_files_infos = (view_files_info **)realloc(view_files_infos, view_files_info_size * sizeof(view_files_info *));
13949 	  for (i = loc; i < view_files_info_size; i++) view_files_infos[i] = NULL;
13950 	}
13951     }
13952 
13953   view_files_infos[loc] = (view_files_info *)calloc(1, sizeof(view_files_info));
13954   vdat = view_files_infos[loc];
13955   vdat->index = loc;
13956   vdat->dialog = NULL_WIDGET;
13957   vdat->file_list = NULL_WIDGET;
13958   vdat->file_list_holder = NULL_WIDGET;
13959   vdat->file_list_entries = NULL;
13960   vdat->size = 0;
13961   vdat->end = -1;
13962   vdat->names = NULL;
13963   vdat->full_names = NULL;
13964   vdat->selected_files = NULL;
13965   vdat->selected_files_size = 0;
13966   vdat->location_choice = VF_AT_CURSOR;
13967   vdat->has_error = false;
13968   vdat->need_update = false;
13969   vdat->dirs_size = 0;
13970   vdat->dirs = NULL;
13971   vdat->dir_names = NULL;
13972   vdat->amp = 1.0;
13973   vdat->speed = 1.0;
13974   vdat->amp_env = default_env(1.0, 1.0);
13975   vdat->sort_items_size = 0;
13976   vdat->sort_items = NULL;
13977   vdat->speed_style = speed_control_style(ss);
13978 
13979   /* don't clear at this point! */
13980   view_files_infos[loc]->currently_selected_files = 0;
13981   view_files_infos[loc]->sorter = view_files_sort(ss);
13982   return(view_files_infos[loc]);
13983 }
13984 
13985 
vf_dialog_to_index(widget_t dialog)13986 static int vf_dialog_to_index(widget_t dialog)
13987 {
13988   int i;
13989   if ((!dialog) &&
13990       (view_files_infos[0]) &&
13991       (view_files_infos[0]->dialog))
13992     return(0);
13993   for (i = 0; i < view_files_info_size; i++)
13994     if ((view_files_infos[i]) &&
13995 	(view_files_infos[i]->dialog == dialog))
13996       return(i);
13997   return(-1);
13998 }
13999 
14000 
vf_dialog_to_info(widget_t dialog)14001 static view_files_info *vf_dialog_to_info(widget_t dialog)
14002 {
14003   int index;
14004   index = vf_dialog_to_index(dialog);
14005   if (index >= 0)
14006     return(view_files_infos[index]);
14007   return(NULL);
14008 }
14009 
14010 
vf_selected_files(view_files_info * vdat)14011 static char **vf_selected_files(view_files_info *vdat)
14012 {
14013   int len;
14014   char **files = NULL;
14015   len = vdat->currently_selected_files;
14016   if (len > 0)
14017     {
14018       int i;
14019       files = (char **)calloc(len, sizeof(char *));
14020       for (i = 0; i < len; i++)
14021 	files[i] = mus_strdup(vdat->full_names[vdat->selected_files[i]]);
14022     }
14023   return(files);
14024 }
14025 
14026 
view_files_selected_files(widget_t dialog,int * len)14027 static char **view_files_selected_files(widget_t dialog, int *len)
14028 {
14029   /* free result */
14030   view_files_info *vdat;
14031   vdat = vf_dialog_to_info(dialog);
14032   if (vdat)
14033     {
14034       (*len) = vdat->currently_selected_files;
14035       return(vf_selected_files(vdat));
14036     }
14037   (*len) = 0;
14038   return(NULL);
14039 }
14040 
14041 
14042 static void view_files_run_select_hook(widget_t dialog, const char *selected_file);
14043 
view_files_set_selected_files(widget_t dialog,char ** files,int len)14044 static char **view_files_set_selected_files(widget_t dialog, char **files, int len)
14045 {
14046   view_files_info *vdat;
14047   vdat = vf_dialog_to_info(dialog);
14048   if (vdat)
14049     {
14050       int i;
14051       view_files_clear_selected_files(vdat);
14052       for (i = 0; i < len; i++)
14053 	if (files[i])
14054 	  {
14055 	    int loc;
14056 	    loc = view_files_find_row(vdat, (const char *)(files[i]));
14057 	    if (loc >= 0)
14058 	      {
14059 		view_files_add_selected_file(vdat, vdat->file_list_entries[loc]);
14060 		view_files_run_select_hook(vdat->dialog, (const char *)(files[i]));
14061 	      }
14062 	  }
14063       vf_mix_insert_buttons_set_sensitive(vdat,
14064 					  ((vdat->currently_selected_files > 0) &&
14065 					   (any_selected_sound())));
14066     }
14067   return(files);
14068 }
14069 
14070 
view_files_files(widget_t dialog,int * len)14071 static char **view_files_files(widget_t dialog, int *len)
14072 {
14073   /* don't free result! */
14074   view_files_info *vdat;
14075   vdat = vf_dialog_to_info(dialog);
14076   if (vdat)
14077     {
14078       (*len) = vdat->end + 1;
14079       return(vdat->full_names);
14080     }
14081   (*len) = 0;
14082   return(NULL);
14083 }
14084 
14085 
14086 static void view_files_clear_list(view_files_info *vdat);
14087 
view_files_set_files(widget_t dialog,char ** files,int len)14088 static char **view_files_set_files(widget_t dialog, char **files, int len)
14089 {
14090   view_files_info *vdat;
14091   vdat = vf_dialog_to_info(dialog);
14092   if (vdat)
14093     {
14094       view_files_clear_selected_files(vdat);
14095       view_files_clear_list(vdat);
14096       if (len > 0)
14097 	{
14098 	  int i;
14099 	  for (i = 0; i < len; i++)
14100 	    if (files[i])
14101 	      view_files_add_file_or_directory(vdat, (const char *)(files[i]));
14102 	}
14103       view_files_display_list(vdat);
14104     }
14105   return(files);
14106 }
14107 
14108 
vf_mix_insert_buttons_set_sensitive(view_files_info * vdat,bool sensitive)14109 static void vf_mix_insert_buttons_set_sensitive(view_files_info *vdat, bool sensitive)
14110 {
14111   if (vdat->mixB)
14112     {
14113       set_sensitive(vdat->mixB, sensitive);
14114       set_sensitive(vdat->insertB, sensitive);
14115     }
14116 }
14117 
14118 
view_files_clear_selected_files(view_files_info * vdat)14119 static void view_files_clear_selected_files(view_files_info *vdat)
14120 {
14121   int len;
14122   len = vdat->currently_selected_files;
14123   if (len > 0)
14124     {
14125       int i;
14126       for (i = 0; i < len; i++)
14127 	{
14128 	  vf_row *r;
14129 	  r = vdat->file_list_entries[vdat->selected_files[i]];
14130 	  if (r)
14131 	    vf_unhighlight_row(r->nm, r->rw);
14132 	}
14133     }
14134   vdat->currently_selected_files = 0;
14135   vf_mix_insert_buttons_set_sensitive(vdat, false);
14136 }
14137 
14138 
view_files_unselect_file(view_files_info * vdat,vf_row * r)14139 static void view_files_unselect_file(view_files_info *vdat, vf_row *r)
14140 {
14141   vf_unhighlight_row(r->nm, r->rw);
14142   if (vdat->currently_selected_files > 1)
14143     {
14144       /* need to fixup selected_files list */
14145       int i, new_loc = 0;
14146       for (i = 0; i < vdat->currently_selected_files; i++)
14147 	if (vdat->selected_files[i] != r->pos)
14148 	  vdat->selected_files[new_loc++] = vdat->selected_files[i];
14149     }
14150   vdat->currently_selected_files--;
14151   if (vdat->currently_selected_files < 0)
14152     vdat->currently_selected_files = 0;
14153   if (vdat->currently_selected_files == 0)
14154     {
14155       vf_mix_insert_buttons_set_sensitive(vdat, false);
14156       vf_unpost_info(vdat);
14157     }
14158 }
14159 
14160 
view_files_add_selected_file(view_files_info * vdat,vf_row * r)14161 static int view_files_add_selected_file(view_files_info *vdat, vf_row *r)
14162 {
14163   /* returns how many are now selected (counting new) */
14164   if (vdat->selected_files_size == 0)
14165     {
14166       vdat->selected_files_size = 4;
14167       vdat->selected_files = (int *)calloc(vdat->selected_files_size, sizeof(int));
14168       vdat->selected_files[0] = r->pos;
14169       vdat->currently_selected_files = 1;
14170     }
14171   else
14172     {
14173       if (vdat->currently_selected_files >= vdat->selected_files_size)
14174 	{
14175 	  vdat->selected_files_size += 4;
14176 	  vdat->selected_files = (int *)realloc(vdat->selected_files, vdat->selected_files_size * sizeof(int));
14177 	  vdat->selected_files[vdat->currently_selected_files++] = r->pos;
14178 	}
14179       else
14180 	{
14181 	  vdat->selected_files[vdat->currently_selected_files++] = r->pos;
14182 	}
14183     }
14184   vf_highlight_row(r->nm, r->rw);
14185   return(vdat->currently_selected_files);
14186 }
14187 
14188 
vf_fixup_selected_files(view_files_info * vdat,char ** saved_selected_files,int len)14189 static void vf_fixup_selected_files(view_files_info *vdat, char **saved_selected_files, int len)
14190 {
14191   /* various things change the order or contents of the files list, so the selected locs list needs to reflect that */
14192   int i, newly_selected = 0;
14193   for (i = 0; i < len; i++)
14194     {
14195       int j;
14196       for (j = 0; j <= vdat->end; j++)
14197 	if ((vdat->full_names[j]) &&
14198 	    (mus_strcmp(vdat->full_names[j], saved_selected_files[i])))
14199 	  {
14200 	    vf_row *old_r, *new_r;
14201 	    /* fprintf(stderr,"old %d at %d -> %d at %d\n", vdat->selected_files[i], i, j, newly_selected); */
14202 	    old_r = vdat->file_list_entries[vdat->selected_files[i]];
14203 	    vdat->selected_files[newly_selected++] = j;
14204 	    new_r = vdat->file_list_entries[j];
14205 	    if (new_r != old_r)
14206 	      {
14207 		vf_highlight_row(new_r->nm, new_r->rw);
14208 		vf_unhighlight_row(old_r->nm, old_r->rw);
14209 	      }
14210 	    break;
14211 	  }
14212     }
14213   vdat->currently_selected_files = newly_selected;
14214 }
14215 
14216 
view_files_find_row(view_files_info * vdat,const char * name)14217 static int view_files_find_row(view_files_info *vdat, const char *name)
14218 {
14219   int i;
14220   if (vdat->names)
14221     for (i = 0; i <= vdat->end; i++)
14222       if ((vdat->names[i]) &&
14223 	  (mus_strcmp(vdat->names[i], name)))
14224   	return(i);
14225   if (vdat->full_names)
14226     for (i = 0; i <= vdat->end; i++)
14227       if ((vdat->full_names[i]) &&
14228 	  (mus_strcmp(vdat->full_names[i], name)))
14229 	return(i);
14230   return(-1);
14231 }
14232 
14233 
view_files_select(vf_row * r,bool add_to_selected)14234 static void view_files_select(vf_row *r, bool add_to_selected)
14235 {
14236   view_files_info *vdat = (view_files_info *)(r->vdat);
14237   int i, curloc = -1;
14238 
14239   for (i = 0; i < vdat->currently_selected_files; i++)
14240     if (vdat->selected_files[i] == r->pos)
14241       {
14242 	curloc = r->pos;
14243 	break;
14244       }
14245   if (curloc == -1)
14246     {
14247       /* file not currently selected */
14248       if (!add_to_selected)         /* not shift click, so remove all currently selected files first */
14249 	view_files_clear_selected_files(vdat);
14250       view_files_add_selected_file(vdat, r);
14251       view_files_run_select_hook(vdat->dialog, vdat->full_names[r->pos]);
14252     }
14253   else
14254     {
14255       /* file already selected, so remove from selected files list */
14256       view_files_unselect_file(vdat, r);
14257     }
14258 
14259   if ((vdat->currently_selected_files == 0) ||
14260       ((vdat->currently_selected_files == 1) &&
14261        (!(is_plausible_sound_file(vdat->full_names[vdat->selected_files[0]])))))
14262     vf_unpost_info(vdat);
14263   else
14264     {
14265       if (vdat->currently_selected_files == 1)
14266 	vf_post_info(vdat, vdat->selected_files[0]);
14267       else vf_post_selected_files_list(vdat);
14268     }
14269   vf_mix_insert_buttons_set_sensitive(vdat,
14270 				      ((vdat->currently_selected_files > 0) &&
14271 				       (any_selected_sound())));
14272 }
14273 
14274 
view_files_play(view_files_info * vdat,int pos,bool play)14275 static bool view_files_play(view_files_info *vdat, int pos, bool play)
14276 {
14277   static snd_info *play_sp;
14278   if (play)
14279     {
14280       if (play_sp)
14281 	{
14282 	  if (play_sp->playing) return(true); /* can't play two of these at once */
14283 	  if ((!vdat->names[pos]) ||
14284 	      (!mus_strcmp(play_sp->short_filename, vdat->names[pos])))
14285 	    {
14286 	      completely_free_snd_info(play_sp);
14287 	      play_sp = NULL;
14288 	    }
14289 	}
14290       if ((!play_sp) &&
14291 	  (vdat->full_names[pos]))
14292 	play_sp = make_sound_readable(vdat->full_names[pos], false);
14293       if (play_sp)
14294 	{
14295 	  play_sp->short_filename = vdat->names[pos];
14296 	  play_sp->filename = NULL;
14297 	  /* pass view files dialog settings to play */
14298 	  play_sp->speed_control = vdat->speed;
14299 	  play_sp->amp_control = vdat->amp;
14300 	  play_sound(play_sp, 0, NO_END_SPECIFIED);
14301 	}
14302       else return(true); /* can't find or setup file */
14303     }
14304   else
14305     { /* play toggled off */
14306       if ((play_sp) && (play_sp->playing))
14307 	{
14308 	  stop_playing_sound(play_sp, PLAY_BUTTON_UNSET);
14309 	  vdat->current_play_button = NULL_WIDGET;
14310 	}
14311     }
14312   return(false);
14313 }
14314 
14315 
view_files_unplay(void)14316 void view_files_unplay(void)
14317 {
14318   int k;
14319   for (k = 0; k < view_files_info_size; k++)
14320     if ((view_files_infos[k]) &&
14321 	(view_files_infos[k]->dialog) &&
14322 	(widget_is_active(view_files_infos[k]->dialog)))
14323       {
14324 	view_files_info *vdat;
14325 	vdat = view_files_infos[k];
14326 	if ((vdat->current_play_button) &&
14327 	    (XmToggleButtonGetState(vdat->current_play_button) != XmUNSET))
14328 	  {
14329 	    set_toggle_button(vdat->current_play_button, false, true, (void *)vdat);
14330 	    vdat->current_play_button = NULL_WIDGET;
14331 	  }
14332       }
14333 }
14334 
14335 
view_files_reflect_sort_items(void)14336 static void view_files_reflect_sort_items(void)
14337 {
14338   int i;
14339   view_files_info *vdat;
14340   int j = 0, k;
14341 
14342   if (view_files_info_size == 0) return;
14343   for (i = 0; i < ss->file_sorters_size; i++)
14344     {
14345       Xen ref;
14346       ref = Xen_vector_ref(ss->file_sorters, i);
14347       if (Xen_is_pair(ref))
14348 	{
14349 	  XmString s1;
14350 	  s1 = XmStringCreateLocalized((char *)Xen_string_to_C_string(Xen_car(ref)));
14351 	  for (k = 0; k < view_files_info_size; k++)
14352 	    if ((view_files_infos[k]) &&
14353 		(view_files_infos[k]->dialog))
14354 	      {
14355 		vdat = view_files_infos[k];
14356 		if (j >= vdat->sort_items_size)
14357 		  {
14358 		    int n = 0, k, old_size;
14359 		    Arg args[20];
14360 		    old_size = vdat->sort_items_size;
14361 		    XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
14362 		    vdat->sort_items_size += 4;
14363 		    vdat->sort_items = (Widget *)realloc(vdat->sort_items, vdat->sort_items_size * sizeof(Widget));
14364 		    for (k = old_size; k < vdat->sort_items_size; k++)
14365 		      vdat->sort_items[k] = XtCreateWidget("unused", xmPushButtonWidgetClass, vdat->smenu, args, n);
14366 		  }
14367 		XtVaSetValues(vdat->sort_items[j],
14368 			      XmNlabelString, s1,
14369 			      XmNuserData, i + SORT_XEN, /* this is an index into the file_sorters list, not the widget list */
14370 			      NULL);
14371 		XtManageChild(vdat->sort_items[j]);
14372 	      }
14373 	  j++;
14374 	  XmStringFree(s1);
14375 	}
14376     }
14377 }
14378 
14379 
14380 /* (add-file-sorter "duration"
14381 		(lambda (lst)
14382 		  (sort lst
14383 			(lambda (a b)
14384 			  (> (mus-sound-duration a) (mus-sound-duration b))))))
14385 
14386  */
14387 
14388 
vf_add_file(view_files_info * vdat,const char * filename,const char * fullname)14389 static void vf_add_file(view_files_info *vdat, const char *filename, const char *fullname)
14390 {
14391   vdat->end++;
14392   if (vdat->end >= vdat->size)
14393     {
14394       int new_size;
14395       new_size = vdat->size + 32;
14396       if (vdat->size == 0)
14397 	{
14398 	  vdat->names = (char **)calloc(new_size, sizeof(char *));
14399 	  vdat->full_names = (char **)calloc(new_size, sizeof(char *));
14400 	}
14401       else
14402 	{
14403 	  int i;
14404 	  vdat->names = (char **)realloc(vdat->names, new_size * sizeof(char *));
14405 	  vdat->full_names = (char **)realloc(vdat->full_names, new_size * sizeof(char *));
14406 	  for (i = vdat->size; i < new_size; i++)
14407 	    {
14408 	      vdat->names[i] = NULL;
14409 	      vdat->full_names[i] = NULL;
14410 	    }
14411 	}
14412       if (!vdat->file_list_entries)
14413 	vdat->file_list_entries = (vf_row **)calloc(new_size, sizeof(vf_row *));
14414       else
14415 	{
14416 	  int i;
14417 	  vdat->file_list_entries = (vf_row **)realloc(vdat->file_list_entries, new_size * sizeof(vf_row *));
14418 	  for (i = vdat->size; i < new_size; i++) vdat->file_list_entries[i] = NULL;
14419 	}
14420       vdat->size = new_size;
14421     }
14422   vdat->names[vdat->end] = mus_strdup(filename);
14423   vdat->full_names[vdat->end] = mus_strdup(fullname);
14424 }
14425 
14426 
add_file_to_view_files_list(view_files_info * vdat,const char * filename,const char * fullname)14427 static void add_file_to_view_files_list(view_files_info *vdat, const char *filename, const char *fullname)
14428 {
14429   int row;
14430 
14431   row = view_files_find_row(vdat, filename);
14432   if (row != -1)
14433     {
14434       if ((vdat->dialog) &&
14435 	  (widget_is_active(vdat->dialog)) &&
14436 	  (vdat->file_list_entries[row]))
14437 	{
14438 	  ensure_scrolled_window_row_visible(vdat->file_list, row, vdat->end + 1);
14439 	  vf_flash_row(vdat->file_list_entries[row]);
14440 	}
14441       return;
14442     }
14443 
14444   errno = 0;
14445   if (!(mus_file_probe(fullname)))
14446     {
14447       if ((vdat->dialog) &&
14448 	  (widget_is_active(vdat->dialog)))
14449 	{
14450 	  char *msg;
14451 	  if (errno != 0)
14452 	    msg = mus_format("%s: %s", filename, strerror(errno));
14453 	  else msg = mus_format("%s does not exist", filename);
14454 	  vf_post_add_error(msg, vdat);
14455 	  free(msg);
14456 	}
14457       return;
14458     }
14459 
14460   vf_add_file(vdat, filename, fullname);
14461 }
14462 
14463 
14464 
14465 /* what about temps coming and going -- should we just add a need-update switch for later remanage? */
14466 /*   remanagement only through make_view_files_dialog -- this file */
14467 /*   perhaps ss->making|deleting_temp_file -> ignore this fam event? */
14468 
add_directory_to_view_files_list(view_files_info * vdat,const char * dirname)14469 static void add_directory_to_view_files_list(view_files_info *vdat, const char *dirname)
14470 {
14471   /* I think all directory additions come through here */
14472 
14473   if ((dirname) && (dirname[strlen(dirname) - 1] != '/'))
14474     {
14475       char *add_slash;
14476       add_slash = mus_format("%s/", dirname);
14477       add_directory_to_view_files_list(vdat, add_slash);
14478       free(add_slash);
14479     }
14480   else
14481     {
14482       dir_info *sound_files = NULL;
14483 #if (!USE_NO_GUI)
14484       view_files_monitor_directory(vdat, dirname);
14485 #endif
14486       sound_files = find_sound_files_in_dir(dirname);
14487       if ((sound_files) &&
14488 	  (sound_files->len > 0))
14489 	{
14490 	  int i, dirs = 0, len = 16;
14491 	  for (i = 0; i < sound_files->len; i++)
14492 	    add_file_to_view_files_list(vdat, sound_files->files[i]->filename, sound_files->files[i]->full_filename);
14493 	  sound_files = free_dir_info(sound_files);
14494 
14495 	  /* fixup title */
14496 	  for (i = 0; i < vdat->dirs_size; i++)
14497 	    if (vdat->dir_names[i])
14498 	      {
14499 		dirs++;
14500 		len += mus_strlen(just_filename(vdat->dir_names[i]));
14501 	      }
14502 	  if ((dirs < 4) &&
14503 	      (len < 512))
14504 	    {
14505 	      int cur_dir = 0;
14506 	      char *titlestr = NULL, *dirstr;
14507 	      titlestr = (char *)calloc(len + dirs * 8, sizeof(char));
14508 	      strcat(titlestr, "Files: ");
14509 	      for (i = 0; i < vdat->dirs_size; i++)
14510 		if (vdat->dir_names[i])
14511 		  {
14512 		    dirstr = just_filename(vdat->dir_names[i]);
14513 		    strcat(titlestr, dirstr);
14514 		    free(dirstr);
14515 		    cur_dir++;
14516 		    if (cur_dir < dirs)
14517 		      strcat(titlestr, ", ");
14518 		  }
14519 	      dialog_set_title(vdat->dialog, titlestr);
14520 	      free(titlestr);
14521 	    }
14522 	}
14523     }
14524 }
14525 
14526 
view_files_sort_list(view_files_info * vdat)14527 static void view_files_sort_list(view_files_info *vdat)
14528 {
14529   if (vdat->end >= 0)
14530     {
14531       sort_info **data;
14532       int i, len;
14533 
14534       len = vdat->end + 1;
14535       data = (sort_info **)calloc(len, sizeof(sort_info *));
14536 
14537       for (i = 0; i < len; i++)
14538 	{
14539 	  data[i] = (sort_info *)calloc(1, sizeof(sort_info));
14540 	  data[i]->filename = vdat->names[i];
14541 	  data[i]->full_filename = vdat->full_names[i];
14542 	}
14543 
14544       snd_sort(vdat->sorter, data, len);
14545 
14546       for (i = 0; i < len; i++)
14547 	{
14548 	  vdat->names[i] = data[i]->filename;
14549 	  vdat->full_names[i] = data[i]->full_filename;
14550 	  free(data[i]);
14551 	}
14552       free(data);
14553     }
14554 }
14555 
14556 
view_files_display_list(view_files_info * vdat)14557 static void view_files_display_list(view_files_info *vdat)
14558 {
14559   int i;
14560   vf_row *r;
14561 
14562   if (!vdat) return;
14563   if (!(vdat->dialog)) return;
14564 
14565   if (vdat->end >= 0)
14566     {
14567       int i, old_len;
14568       char **old_names = NULL;
14569       widget_t last_row = NULL_WIDGET;
14570 
14571       old_len = vdat->currently_selected_files;
14572       if (old_len > 0)
14573 	old_names = vf_selected_files(vdat);
14574 
14575       view_files_sort_list(vdat);
14576       for (i = 0; i <= vdat->end; i++)
14577 	{
14578 	  r = vdat->file_list_entries[i];
14579 	  if (!r)
14580 	    {
14581 	      r = view_files_make_row(vdat, last_row);
14582 	      vdat->file_list_entries[i] = r;
14583 	      r->pos = i;
14584 	    }
14585 	  set_button_label(r->nm, vdat->names[r->pos]);
14586 #if WITH_AUDIO
14587 	  set_toggle_button(r->pl, false, false, (void *)vdat);
14588 #endif
14589 	  if (!(widget_is_active(r->rw))) activate_widget(r->rw);
14590 	  last_row = r->rw;
14591 	}
14592 
14593       if (old_names)
14594 	{
14595 	  vf_fixup_selected_files(vdat, old_names, old_len);
14596 	  for (i = 0; i < old_len; i++) free(old_names[i]);
14597 	  free(old_names);
14598 	}
14599     }
14600 
14601   for (i = vdat->end + 1; i < vdat->size; i++)
14602     {
14603       r = vdat->file_list_entries[i];
14604       if (r)
14605 	{
14606 	  if (widget_is_active(r->rw))
14607 	    deactivate_widget(r->rw);
14608 	}
14609     }
14610 
14611   if (!(widget_is_active(vdat->file_list)))
14612     activate_widget(vdat->file_list);
14613 }
14614 
14615 
view_files_clear_list(view_files_info * vdat)14616 static void view_files_clear_list(view_files_info *vdat)
14617 {
14618 #if (!USE_NO_GUI)
14619   view_files_unmonitor_directories(vdat);
14620 #endif
14621   if (vdat->names)
14622     {
14623       int i;
14624       for (i = 0; i < vdat->size; i++)
14625 	if (vdat->names[i])
14626 	  {
14627 	    free(vdat->names[i]);
14628 	    vdat->names[i] = NULL;
14629 	    free(vdat->full_names[i]);
14630 	    vdat->full_names[i] = NULL;
14631 	  }
14632       vdat->end = -1;
14633       vdat->currently_selected_files = 0;
14634     }
14635 }
14636 
14637 #if 0
14638 static void view_files_update_list(view_files_info *vdat)
14639 {
14640   /* here we need the file's full name */
14641   int i, old_len;
14642   char **old_names = NULL;
14643 
14644   old_len = vdat->currently_selected_files;
14645   if (old_len > 0)
14646     old_names = vf_selected_files(vdat);
14647 
14648   if (vdat->names)
14649     {
14650       int i, j;
14651       for (i = 0; i <= vdat->end; i++)
14652 	if (vdat->names[i])
14653 	  {
14654 	    if (!(mus_file_probe(vdat->full_names[i])))
14655 	      {
14656 		free(vdat->names[i]);
14657 		vdat->names[i] = NULL;
14658 		free(vdat->full_names[i]);
14659 		vdat->full_names[i] = NULL;
14660 	      }
14661 	  }
14662 
14663       for (i = 0, j = 0; i <= vdat->end; i++)
14664 	if (vdat->names[i])
14665 	  {
14666 	    if (i != j)
14667 	      {
14668 		vdat->names[j] = vdat->names[i];
14669 		vdat->names[i] = NULL;
14670 		vdat->full_names[j] = vdat->full_names[i];
14671 		vdat->full_names[i] = NULL;
14672 	      }
14673 	    j++;
14674 	  }
14675       vdat->end = j - 1;
14676     }
14677 
14678   if (old_names)
14679     {
14680       vf_fixup_selected_files(vdat, old_names, old_len);
14681       for (i = 0; i < old_len; i++) free(old_names[i]);
14682       free(old_names);
14683     }
14684 }
14685 #endif
14686 
14687 
vf_clear_error(view_files_info * vdat)14688 static void vf_clear_error(view_files_info *vdat)
14689 {
14690   if (vdat->currently_selected_files == 1)
14691     vf_post_info(vdat, vdat->selected_files[0]);
14692   else
14693     {
14694       if (vdat->currently_selected_files == 0)
14695 	vf_unpost_info(vdat);
14696       else vf_post_selected_files_list(vdat);
14697     }
14698   vdat->has_error = false;
14699 }
14700 
14701 
vf_mix(view_files_info * vdat)14702 static int vf_mix(view_files_info *vdat)
14703 {
14704   int len, id_or_error = 0;
14705   snd_info *sp;
14706 
14707   sp = any_selected_sound();
14708   len = vdat->currently_selected_files;
14709 
14710   if ((len == 1) &&
14711       (snd_feq(vdat->amp, 1.0)) &&
14712       (snd_feq(vdat->speed, 1.0)) &&
14713       (is_default_env(vdat->amp_env)))
14714     id_or_error = mix_complete_file(sp, vdat->beg,
14715 				    vdat->full_names[vdat->selected_files[0]],
14716 				    with_mix_tags(ss), DONT_DELETE_ME, MIX_SETS_SYNC_LOCALLY, NULL);
14717   else
14718     {
14719       int i;
14720       bool err = false;
14721       char *tempfile;
14722       char **selected_files;
14723 
14724       selected_files = vf_selected_files(vdat);
14725       tempfile = scale_and_src(selected_files, len, sp->nchans, vdat->amp, vdat->speed, vdat->amp_env, &err);
14726 
14727       if (err)
14728 	{
14729 	  vf_post_error(tempfile, vdat);
14730 	  id_or_error = MIX_FILE_NO_TEMP_FILE;
14731 	}
14732       else
14733 	{
14734 	  if (sp->nchans > 1)
14735 	    remember_temp(tempfile, sp->nchans);
14736 	  id_or_error = mix_complete_file(sp, vdat->beg, tempfile,
14737 					  with_mix_tags(ss),
14738 					  (sp->nchans > 1) ? MULTICHANNEL_DELETION : DELETE_ME,
14739 					  MIX_SETS_SYNC_LOCALLY, NULL);
14740 	}
14741       free(tempfile);
14742       for (i = 0; i < len; i++)
14743 	free(selected_files[i]);
14744       free(selected_files);
14745     }
14746   return(id_or_error);
14747 }
14748 
14749 
view_files_mix_selected_files(widget_t w,view_files_info * vdat)14750 static void view_files_mix_selected_files(widget_t w, view_files_info *vdat)
14751 {
14752   vdat->has_error = false;
14753   redirect_snd_error_to(redirect_vf_post_location_error, (void *)vdat);
14754   vdat->beg = vf_location(vdat);
14755   redirect_snd_error_to(NULL, NULL);
14756 
14757   if (!(vdat->has_error))
14758     {
14759       int id_or_error = 0;
14760 
14761       redirect_snd_error_to(redirect_vf_post_error, (void *)vdat);
14762       ss->requestor_dialog = w;
14763       ss->open_requestor_data = (void *)vdat;
14764       ss->open_requestor = FROM_VIEW_FILES_MIX_DIALOG;
14765       id_or_error = vf_mix(vdat);
14766 
14767       /* "id_or_error" here is either one of the mix id's or an error indication such as MIX_FILE_NO_MIX */
14768       /*    the possible error conditions have been checked already, or go through snd_error */
14769 
14770       redirect_snd_error_to(NULL, NULL);
14771       if (id_or_error >= 0)
14772 	{
14773 	  char *msg;
14774 	  if (vdat->currently_selected_files == 1)
14775 	    msg = mus_format("%s mixed in at %" print_mus_long, vdat->names[vdat->selected_files[0]], vdat->beg);
14776 	  else msg = mus_format("selected files mixed in at %" print_mus_long, vdat->beg);
14777 	  vf_post_error(msg, vdat);
14778 	  vdat->has_error = false;
14779 	  free(msg);
14780 	}
14781     }
14782 }
14783 
14784 
vf_insert(view_files_info * vdat)14785 static bool vf_insert(view_files_info *vdat)
14786 {
14787   int len;
14788   bool ok = false;
14789   snd_info *sp;
14790   sp = any_selected_sound();
14791 
14792   len = vdat->currently_selected_files;
14793   if ((len == 1) &&
14794       (snd_feq(vdat->amp, 1.0)) &&
14795       (snd_feq(vdat->speed, 1.0)) &&
14796       (is_default_env(vdat->amp_env)))
14797     ok = insert_complete_file(sp,
14798 			      vdat->full_names[vdat->selected_files[0]],
14799 			      vdat->beg,
14800 			      DONT_DELETE_ME);
14801   else
14802     {
14803       int i;
14804       bool err = false;
14805       char *tempfile;
14806       char **selected_files;
14807 
14808       selected_files = vf_selected_files(vdat);
14809       tempfile = scale_and_src(selected_files, len, sp->nchans, vdat->amp, vdat->speed, vdat->amp_env, &err);
14810 
14811       if (err)
14812 	{
14813 	  vf_post_error(tempfile, vdat);
14814 	  ok = false;
14815 	}
14816       else
14817 	{
14818 	  vf_clear_error(vdat);
14819 	  if (sp->nchans > 1)
14820 	    remember_temp(tempfile, sp->nchans);
14821 	  ok = insert_complete_file(sp,
14822 				    tempfile,
14823 				    vdat->beg,
14824 				    (sp->nchans > 1) ? MULTICHANNEL_DELETION : DELETE_ME);
14825 	}
14826       free(tempfile);
14827       for (i = 0; i < len; i++)
14828 	free(selected_files[i]);
14829       free(selected_files);
14830     }
14831   return(ok);
14832 }
14833 
14834 
view_files_insert_selected_files(widget_t w,view_files_info * vdat)14835 static void view_files_insert_selected_files(widget_t w, view_files_info *vdat)
14836 {
14837   vdat->has_error = false;
14838   redirect_snd_error_to(redirect_vf_post_location_error, (void *)vdat);
14839   vdat->beg = vf_location(vdat);
14840   redirect_snd_error_to(NULL, NULL);
14841 
14842   if (!(vdat->has_error))
14843     {
14844       bool ok;
14845 
14846       redirect_snd_error_to(redirect_vf_post_error, (void *)vdat);
14847       redirect_snd_warning_to(redirect_vf_post_error, (void *)vdat);
14848       ss->requestor_dialog = w;
14849       ss->open_requestor = FROM_VIEW_FILES_INSERT_DIALOG;
14850       ss->open_requestor_data = (void *)vdat;
14851       ok = vf_insert(vdat);
14852       redirect_snd_error_to(NULL, NULL);
14853       redirect_snd_warning_to(NULL, NULL);
14854 
14855       if (ok)
14856 	{
14857 	  char *msg;
14858 	  if (vdat->currently_selected_files == 1)
14859 	    msg = mus_format("%s inserted at %" print_mus_long, vdat->names[vdat->selected_files[0]], vdat->beg);
14860 	  else msg = mus_format("selected files inserted at %" print_mus_long, vdat->beg);
14861 	  vf_post_error(msg, vdat);
14862 	  vdat->has_error = false;
14863 	  free(msg);
14864 	}
14865       /* else we've already posted whatever went wrong (make_file_info etc) */
14866     }
14867 }
14868 
14869 
view_files_amp(widget_t dialog)14870 static mus_float_t view_files_amp(widget_t dialog)
14871 {
14872   view_files_info *vdat;
14873   vdat = vf_dialog_to_info(dialog);
14874   if (vdat)
14875     return(vdat->amp);
14876   return(0.0);
14877 }
14878 
14879 
view_files_set_amp(widget_t dialog,mus_float_t new_amp)14880 static mus_float_t view_files_set_amp(widget_t dialog, mus_float_t new_amp)
14881 {
14882   view_files_info *vdat;
14883   vdat = vf_dialog_to_info(dialog);
14884   if (vdat)
14885     vf_set_amp(vdat, new_amp);
14886   return(new_amp);
14887 }
14888 
14889 
view_files_speed(widget_t dialog)14890 static mus_float_t view_files_speed(widget_t dialog)
14891 {
14892   view_files_info *vdat;
14893   vdat = vf_dialog_to_info(dialog);
14894   if (vdat)
14895     return(vdat->speed);
14896   return(1.0);
14897 }
14898 
14899 
view_files_set_speed(widget_t dialog,mus_float_t new_speed)14900 static mus_float_t view_files_set_speed(widget_t dialog, mus_float_t new_speed)
14901 {
14902   view_files_info *vdat;
14903   vdat = vf_dialog_to_info(dialog);
14904   if (vdat)
14905     vf_set_speed(vdat, new_speed);
14906   return(new_speed);
14907 }
14908 
14909 
view_files_speed_style(widget_t dialog)14910 static speed_style_t view_files_speed_style(widget_t dialog)
14911 {
14912   view_files_info *vdat;
14913   vdat = vf_dialog_to_info(dialog);
14914   if (vdat)
14915     return(vdat->speed_style);
14916   return(SPEED_CONTROL_AS_FLOAT);
14917 }
14918 
14919 
view_files_set_speed_style(widget_t dialog,speed_style_t speed_style)14920 static speed_style_t view_files_set_speed_style(widget_t dialog, speed_style_t speed_style)
14921 {
14922   view_files_info *vdat;
14923   vdat = vf_dialog_to_info(dialog);
14924   if (vdat)
14925     {
14926       vdat->speed_style = speed_style;
14927       vf_set_speed(vdat, vdat->speed); /* update label etc */
14928     }
14929   return(speed_style);
14930 }
14931 
14932 
view_files_amp_env(widget_t dialog)14933 static env *view_files_amp_env(widget_t dialog)
14934 {
14935   view_files_info *vdat;
14936   vdat = vf_dialog_to_info(dialog);
14937   if (vdat)
14938     return(vdat->amp_env);
14939   return(NULL);
14940 }
14941 
14942 
view_files_set_amp_env(widget_t dialog,env * new_e)14943 static void view_files_set_amp_env(widget_t dialog, env *new_e)
14944 {
14945   vf_set_amp_env(vf_dialog_to_info(dialog), new_e);
14946 }
14947 
14948 
view_files_local_sort(widget_t dialog)14949 static int view_files_local_sort(widget_t dialog)
14950 {
14951   view_files_info *vdat;
14952   vdat = vf_dialog_to_info(dialog);
14953   if (vdat)
14954     return(vdat->sorter);
14955   return(-1);
14956 }
14957 
14958 
view_files_set_local_sort(widget_t dialog,int sort_choice)14959 static int view_files_set_local_sort(widget_t dialog, int sort_choice)
14960 {
14961   view_files_info *vdat;
14962   vdat = vf_dialog_to_info(dialog);
14963   if (vdat)
14964     {
14965       vdat->sorter = sort_choice;
14966       view_files_display_list(vdat);
14967       vf_reflect_sort_choice_in_menu(vdat);
14968     }
14969   return(sort_choice);
14970 }
14971 
14972 
view_files_find_dialog(widget_t dialog)14973 static view_files_info *view_files_find_dialog(widget_t dialog)
14974 {
14975   int i;
14976   for (i = 0; i < view_files_info_size; i++)
14977     if ((view_files_infos[i]) &&
14978 	(view_files_infos[i]->dialog == dialog))
14979       return(view_files_infos[i]);
14980   return(NULL);
14981 }
14982 
14983 
make_view_files_dialog(bool managed,bool make_new)14984 widget_t make_view_files_dialog(bool managed, bool make_new)
14985 {
14986   int i;
14987   view_files_info *vdat = NULL;
14988 
14989   if (make_new)
14990     return(make_view_files_dialog_1(new_view_files_dialog(), managed));
14991 
14992   for (i = 0; i < view_files_info_size; i++)
14993     if ((view_files_infos[i]) &&
14994 	(view_files_infos[i]->dialog))
14995       {
14996 	vdat = view_files_infos[i];
14997 	if (widget_is_active(vdat->dialog))
14998 	  break;
14999       }
15000 
15001   if (vdat)
15002     return(make_view_files_dialog_1(vdat, managed));
15003   return(make_view_files_dialog_1(new_view_files_dialog(), managed));
15004 }
15005 
15006 
save_view_files_dialogs(FILE * fd)15007 void save_view_files_dialogs(FILE *fd)
15008 {
15009 #if HAVE_EXTENSION_LANGUAGE
15010   int i;
15011   view_files_info *vdat;
15012   for (i = 0; i < view_files_info_size; i++)
15013     if ((view_files_infos[i]) &&
15014 	(view_files_infos[i]->dialog) &&
15015 	(widget_is_active(view_files_infos[i]->dialog)))
15016       {
15017 	vdat = view_files_infos[i];
15018 
15019 #if HAVE_SCHEME
15020 	fprintf(fd, "(let ((vf (" S_view_files_dialog " #t #t)))\n");
15021 
15022 	if (vdat->full_names)
15023 	  {
15024 	    int k;
15025 	    fprintf(fd, "  (set! (" S_view_files_files " vf) (list");
15026 	    for (k = 0; k <= vdat->end; k++)
15027 	      fprintf(fd, " \"%s\"", vdat->full_names[k]);
15028 	    fprintf(fd, "))\n");
15029 	    if (vdat->currently_selected_files > 0)
15030 	      {
15031 		fprintf(fd, "  (set! (" S_view_files_selected_files " vf) (list");
15032 		for (k = 0; k < vdat->currently_selected_files; k++)
15033 		  fprintf(fd, " \"%s\"", vdat->full_names[vdat->selected_files[k]]);
15034 		fprintf(fd, "))\n");
15035 	      }
15036 	  }
15037 	if (!(snd_feq(vdat->amp, 1.0)))
15038 	  fprintf(fd, "  (set! (" S_view_files_amp " vf) %.3f)\n", vdat->amp);
15039 
15040 	if (!(snd_feq(vdat->speed, 1.0)))
15041 	  fprintf(fd, "  (set! (" S_view_files_speed " vf) %.3f)\n", vdat->speed);
15042 
15043 	if (!(is_default_env(vdat->amp_env)))
15044 	  fprintf(fd, "  (set! (" S_view_files_amp_env " vf) %s)\n", env_to_string(vdat->amp_env));
15045 
15046 	/* assume file-sorters are set up already */
15047 	fprintf(fd, "  (set! (" S_view_files_sort " vf) %d)\n", vdat->sorter);
15048 	fprintf(fd, ")\n");
15049 #endif
15050 
15051 #if HAVE_RUBY
15052 	fprintf(fd, "vf = view_files_dialog(true, true)\n");
15053 
15054 	if (vdat->full_names)
15055 	  {
15056 	    int k;
15057 	    fprintf(fd, "  set_view_files_files(vf, [");
15058 	    for (k = 0; k < vdat->end; k++)
15059 	      fprintf(fd, "\"%s\", ", vdat->full_names[k]);
15060 	    fprintf(fd, "\"%s\"])\n", vdat->full_names[vdat->end]);
15061 	    if (vdat->currently_selected_files > 0)
15062 	      {
15063 		fprintf(fd, "  set_view_files_selected_files(vf, [");
15064 		for (k = 0; k < vdat->currently_selected_files - 1; k++)
15065 		  fprintf(fd, "\"%s\", ", vdat->full_names[vdat->selected_files[k]]);
15066 		fprintf(fd, "\"%s\"])\n", vdat->full_names[vdat->selected_files[vdat->currently_selected_files]]);
15067 	      }
15068 	  }
15069 	if (!(snd_feq(vdat->amp, 1.0)))
15070 	  fprintf(fd, "  set_view_files_amp(vf, %.3f)\n", vdat->amp);
15071 
15072 	if (!(snd_feq(vdat->speed, 1.0)))
15073 	  fprintf(fd, "  set_view_files_speed(vf, %.3f)\n", vdat->speed);
15074 
15075 	if (!(is_default_env(vdat->amp_env)))
15076 	  fprintf(fd, "  set_view_files_amp_env(vf, %s)\n", env_to_string(vdat->amp_env));
15077 
15078 	/* assume file-sorters are set up already */
15079 	fprintf(fd, "  set_view_files_sort(vf, %d)\n", vdat->sorter);
15080 	fprintf(fd, "\n");
15081 #endif
15082 
15083 #if HAVE_FORTH
15084 	fprintf(fd, "#t #t view-files-dialog value vf\n");
15085 
15086 	if (vdat->full_names)
15087 	  {
15088 	    int k;
15089 	    fprintf(fd, "  vf '(");
15090 	    for (k = 0; k <= vdat->end; k++)
15091 	      fprintf(fd, " \"%s\"", vdat->full_names[k]);
15092 	    fprintf(fd, " ) set-view-files-files drop\n");
15093 	    if (vdat->currently_selected_files > 0)
15094 	      {
15095 		fprintf(fd, "  vf '(");
15096 		for (k = 0; k <= vdat->currently_selected_files; k++)
15097 		  fprintf(fd, " \"%s\"", vdat->full_names[vdat->selected_files[k]]);
15098 		fprintf(fd, " ) set-view-files-selected-files drop\n");
15099 	      }
15100 	  }
15101 	if (!(snd_feq(vdat->amp, 1.0)))
15102 	  fprintf(fd, "  vf %.3f set-view-files-amp drop\n", vdat->amp);
15103 
15104 	if (!(snd_feq(vdat->speed, 1.0)))
15105 	  fprintf(fd, "  vf %.3f set-view-files-speed drop\n", vdat->speed);
15106 
15107 	if (!(is_default_env(vdat->amp_env)))
15108 	  fprintf(fd, "  vf %s set-view-files-amp-env drop\n", env_to_string(vdat->amp_env));
15109 
15110 	/* assume file-sorters are set up already */
15111 	fprintf(fd, "  vf %d set-view-files-sort drop\n\n", vdat->sorter);
15112 #endif
15113       }
15114 #endif
15115 }
15116 
15117 
view_files_add_directory(widget_t dialog,const char * dirname)15118 void view_files_add_directory(widget_t dialog, const char *dirname)
15119 {
15120   view_files_info *vdat = NULL;
15121 
15122   if (dialog)
15123     vdat = view_files_find_dialog(dialog);
15124   else
15125     {
15126       if (view_files_info_size > 0)
15127 	vdat = view_files_infos[0];
15128       else
15129 	{
15130 	  vdat = new_view_files_dialog();
15131 	  make_view_files_dialog_1(vdat, false);
15132 	}
15133     }
15134 
15135   if (vdat)
15136     {
15137       char *full_filename;
15138       full_filename = mus_expand_filename((const char *)dirname);
15139       if (!(mus_file_probe(full_filename)))
15140 	{
15141 	  if ((vdat->dialog) &&
15142 	      (widget_is_active(vdat->dialog)))
15143 	    {
15144 	      char *msg;
15145 	      if (errno != 0)
15146 		msg = mus_format("%s: %s", full_filename, strerror(errno));
15147 	      else msg = mus_format("%s does not exist", full_filename);
15148 	      vf_post_add_error(msg, vdat);
15149 	      free(msg);
15150 	    }
15151 	}
15152       else
15153 	{
15154 	  add_directory_to_view_files_list(vdat, full_filename);
15155 	}
15156       free(full_filename);
15157     }
15158 }
15159 
15160 
view_files_add_file(widget_t dialog,const char * filename)15161 static void view_files_add_file(widget_t dialog, const char *filename)
15162 {
15163   view_files_info *vdat = NULL;
15164 
15165   if (dialog)
15166     vdat = view_files_find_dialog(dialog);
15167   else
15168     {
15169       if (view_files_info_size > 0)
15170 	vdat = view_files_infos[0];
15171       else
15172 	{
15173 	  vdat = new_view_files_dialog();
15174 	  make_view_files_dialog_1(vdat, false);
15175 	}
15176     }
15177 
15178   if (vdat)
15179     {
15180       char *full_filename;
15181       full_filename = mus_expand_filename((const char *)filename);
15182       add_file_to_view_files_list(vdat, filename, full_filename);
15183       free(full_filename);
15184     }
15185 }
15186 
15187 
view_files_open_selected_files(view_files_info * vdat)15188 static void view_files_open_selected_files(view_files_info *vdat)
15189 {
15190   ss->open_requestor = FROM_VIEW_FILES;
15191 
15192   if (vdat->currently_selected_files > 0)
15193     {
15194       int i;
15195       snd_info *sp = NULL;
15196       for (i = 0; i < vdat->currently_selected_files; i++)
15197 	sp = snd_open_file(vdat->full_names[vdat->selected_files[i]], FILE_READ_WRITE);
15198       if (sp) select_channel(sp, 0);
15199     }
15200 }
15201 
15202 
view_files_find_any_directory(void)15203 char *view_files_find_any_directory(void)
15204 {
15205   /* find any active directory in any vf dialog */
15206   if (view_files_info_size > 0)
15207     {
15208       int j;
15209       for (j = 0; j < view_files_info_size; j++)
15210 	{
15211 	  view_files_info *vdat;
15212 	  vdat = view_files_infos[j];
15213 	  if ((vdat) &&
15214 	      (vdat->dir_names))
15215 	    {
15216 	      int i;
15217 	      for (i = 0; i < vdat->dirs_size; i++)
15218 		if (vdat->dir_names[i])
15219 		  return(vdat->dir_names[i]);
15220 	    }
15221 	}
15222     }
15223   return(NULL);
15224 }
15225 
15226 
15227 
15228 static Xen mouse_enter_label_hook;
15229 static Xen mouse_leave_label_hook;
15230 
vf_row_get_label(void * ur)15231 static char *vf_row_get_label(void *ur)
15232 {
15233   vf_row *r = (vf_row *)ur;
15234   return(((view_files_info *)(r->vdat))->full_names[r->pos]);
15235 }
15236 
15237 
vf_row_get_pos(void * ur)15238 static int vf_row_get_pos(void *ur)
15239 {
15240   vf_row *r = (vf_row *)ur;
15241   return(r->pos);
15242 }
15243 
15244 
mouse_enter_or_leave_label(void * r,int type,Xen hook,const char * caller)15245 static void mouse_enter_or_leave_label(void *r, int type, Xen hook, const char *caller)
15246 {
15247   if ((r) &&
15248       (Xen_hook_has_list(hook)))
15249     {
15250       char *label = NULL;
15251       bool need_free = false;
15252       if (type == FILE_VIEWER)
15253 	label = vf_row_get_label(r);
15254       else
15255 	{
15256 	  label = regrow_get_label(r);
15257 	  if (label) need_free = true;
15258 	}
15259       if (label)
15260 	run_hook(hook,
15261 		 Xen_list_3(C_int_to_Xen_integer(type),
15262 			    C_int_to_Xen_integer((type == FILE_VIEWER) ? (vf_row_get_pos(r)) : (regrow_get_pos(r))),
15263 			    C_string_to_Xen_string(label)),
15264 		 caller);
15265       if (need_free) XtFree(label);
15266     }
15267 }
15268 
15269 
mouse_leave_label(void * r,int type)15270 void mouse_leave_label(void *r, int type)
15271 {
15272   mouse_enter_or_leave_label(r, type, mouse_leave_label_hook, S_mouse_leave_label_hook);
15273 }
15274 
15275 
mouse_enter_label(void * r,int type)15276 void mouse_enter_label(void *r, int type)
15277 {
15278   mouse_enter_or_leave_label(r, type, mouse_enter_label_hook, S_mouse_enter_label_hook);
15279 }
15280 
15281 
vf_mouse_enter_label(Widget w,XtPointer context,XEvent * event,Boolean * flag)15282 static void vf_mouse_enter_label(Widget w, XtPointer context, XEvent *event, Boolean *flag)
15283 {
15284   mouse_enter_label(context, FILE_VIEWER);
15285 }
15286 
15287 
vf_mouse_leave_label(Widget w,XtPointer context,XEvent * event,Boolean * flag)15288 static void vf_mouse_leave_label(Widget w, XtPointer context, XEvent *event, Boolean *flag)
15289 {
15290   mouse_leave_label(context, FILE_VIEWER);
15291 }
15292 
15293 
make_vf_row(view_files_info * vdat,Widget last_row,XtCallbackProc play_callback,XtCallbackProc name_callback)15294 static vf_row *make_vf_row(view_files_info *vdat,
15295 			   Widget last_row,
15296 			   XtCallbackProc play_callback, XtCallbackProc name_callback)
15297 {
15298   int n;
15299   Arg args[32];
15300   vf_row *r;
15301   XmString s1;
15302 #if WITH_AUDIO
15303   XtCallbackList n1;
15304 #endif
15305   XtCallbackList n3;
15306 
15307   s1 = XmStringCreateLocalized((char *)"");
15308   r = (vf_row *)calloc(1, sizeof(vf_row));
15309   r->vdat = (void *)vdat;
15310 
15311   n = 0;
15312   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
15313   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
15314   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
15315   XtSetArg(args[n], XmNtopAttachment, (last_row) ? XmATTACH_WIDGET : XmATTACH_FORM); n++;
15316   if (last_row) {XtSetArg(args[n], XmNtopWidget, last_row); n++;}
15317   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
15318   XtSetArg(args[n], XmNheight, 18); n++;
15319   r->rw = XtCreateWidget("rw", xmFormWidgetClass, vdat->file_list_holder, args, n);
15320 
15321 #if WITH_AUDIO
15322   n = 0;
15323   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
15324   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
15325   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
15326   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
15327   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
15328   XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
15329   XtSetArg(args[n], XmNlabelString, s1); n++;
15330   XtSetArg(args[n], XmNvalueChangedCallback, n1 = make_callback_list(play_callback, (XtPointer)r)); n++;
15331   if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;}
15332   XtSetArg(args[n], XmNmarginWidth, 8); n++;
15333   r->pl = make_togglebutton_widget("pl", r->rw, args, n);
15334 #endif
15335 
15336   n = 0;
15337   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
15338 #if WITH_AUDIO
15339   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
15340   XtSetArg(args[n], XmNleftWidget, r->pl); n++;
15341 #else
15342   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
15343 #endif
15344   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
15345   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
15346   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
15347   XtSetArg(args[n], XmNshadowThickness, 0); n++;
15348   XtSetArg(args[n], XmNhighlightThickness, 0); n++;
15349   XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
15350   XtSetArg(args[n], XmNfillOnArm, false); n++;
15351   XtSetArg(args[n], XmNrecomputeSize, false); n++;
15352   XtSetArg(args[n], XmNwidth, 500); n++;                /* this sets the max name length indirectly -- was 300 which truncates some long file names (29-Oct-07) */
15353   XtSetArg(args[n], XmNactivateCallback, n3 = make_callback_list(name_callback, (XtPointer)r)); n++;
15354   r->nm = XtCreateManagedWidget("nm", xmPushButtonWidgetClass, r->rw, args, n);
15355   XmStringFree(s1);
15356 
15357   XtAddEventHandler(r->nm, EnterWindowMask, false, vf_mouse_enter_label, (XtPointer)r);
15358   XtAddEventHandler(r->nm, LeaveWindowMask, false, vf_mouse_leave_label, (XtPointer)r);
15359 
15360 #if WITH_AUDIO
15361   free(n1);
15362 #endif
15363   free(n3);
15364   return(r);
15365 }
15366 
15367 
vf_unhighlight_row(widget_t nm,widget_t rw)15368 static void vf_unhighlight_row(widget_t nm, widget_t rw)
15369 {
15370   XtVaSetValues(rw, XmNbackground, ss->highlight_color, NULL);
15371   XtVaSetValues(nm, XmNbackground, ss->highlight_color, NULL);
15372 }
15373 
15374 
vf_highlight_row(widget_t nm,widget_t rw)15375 static void vf_highlight_row(widget_t nm, widget_t rw)
15376 {
15377   XtVaSetValues(rw, XmNbackground, ss->zoom_color, NULL);
15378   XtVaSetValues(nm, XmNbackground, ss->zoom_color, NULL);
15379 }
15380 
15381 
15382 typedef struct {
15383   vf_row *r;
15384   color_t old_color;
15385 } vf_flash_data;
15386 
15387 
vf_unflash_row(XtPointer data,XtIntervalId * id)15388 static void vf_unflash_row(XtPointer data, XtIntervalId *id)
15389 {
15390   vf_flash_data *v = (vf_flash_data *)data;
15391   XtVaSetValues(v->r->rw, XmNbackground, v->old_color, NULL);
15392   XtVaSetValues(v->r->nm, XmNbackground, v->old_color, NULL);
15393   free(v);
15394 }
15395 
15396 
vf_flash_row(vf_row * r)15397 static void vf_flash_row(vf_row *r)
15398 {
15399   vf_flash_data *v;
15400   v = (vf_flash_data *)calloc(1, sizeof(vf_flash_data));
15401   v->r = r;
15402   XtVaGetValues(r->rw, XmNbackground, &(v->old_color), NULL);
15403   XtVaSetValues(r->rw, XmNbackground, ss->light_blue, NULL);
15404   XtVaSetValues(r->nm, XmNbackground, ss->light_blue, NULL);
15405   XtAppAddTimeOut(main_app(ss),
15406 		  500,
15407 		  (XtTimerCallbackProc)vf_unflash_row,
15408 		  (void *)v);
15409 }
15410 
15411 
vf_post_info(view_files_info * vdat,int pos)15412 static void vf_post_info(view_files_info *vdat, int pos)
15413 {
15414   char *title;
15415   XmString s3;
15416   title = mus_format("%s:", vdat->names[pos]);
15417   s3 = XmStringCreateLocalized(title);
15418   XtVaSetValues(vdat->left_title,
15419 		XmNlabelString, s3,
15420 		NULL);
15421   XmStringFree(s3);
15422   free(title);
15423   post_sound_info(vdat->info1, vdat->info2, vdat->full_names[pos], false);
15424 }
15425 
15426 
vf_post_selected_files_list(view_files_info * vdat)15427 static void vf_post_selected_files_list(view_files_info *vdat)
15428 {
15429   int len;
15430   char *msg1 = NULL, *msg2 = NULL, *title;
15431   XmString s1, s2, s3;
15432   len = vdat->currently_selected_files;
15433 
15434   title = mus_strdup("selected files:");
15435   s3 = XmStringCreateLocalized(title);
15436   XtVaSetValues(vdat->left_title,
15437 		XmNlabelString, s3,
15438 		NULL);
15439   XmStringFree(s3);
15440   free(title);
15441 
15442   if (len == 2)
15443     {
15444       msg1 = mus_strdup(vdat->names[vdat->selected_files[0]]);
15445       msg2 = mus_strdup(vdat->names[vdat->selected_files[1]]);
15446     }
15447   else
15448     {
15449       if (len == 3)
15450 	{
15451 	  msg1 = mus_format("%s, %s", vdat->names[vdat->selected_files[0]], vdat->names[vdat->selected_files[1]]);
15452 	  msg2 = mus_strdup(vdat->names[vdat->selected_files[2]]);
15453 	}
15454       else
15455 	{
15456 	  msg1 = mus_format("%s, %s", vdat->names[vdat->selected_files[0]], vdat->names[vdat->selected_files[1]]);
15457 	  msg2 = mus_format("%s, %s%s", vdat->names[vdat->selected_files[2]], vdat->names[vdat->selected_files[3]],
15458 			    (len == 4) ? "" : "...");
15459 	}
15460     }
15461 
15462   s1 = XmStringCreateLocalized(msg1);
15463   s2 = XmStringCreateLocalized(msg2);
15464   XtVaSetValues(vdat->info1, XmNlabelString, s1, NULL);
15465   XtVaSetValues(vdat->info2, XmNlabelString, s2, NULL);
15466   XmStringFree(s1);
15467   XmStringFree(s2);
15468   free(msg1);
15469   free(msg2);
15470 }
15471 
15472 
vf_unpost_info(view_files_info * vdat)15473 static void vf_unpost_info(view_files_info *vdat)
15474 {
15475   XmString s1, s2, s3;
15476   char *title;
15477 
15478   title = mus_strdup("(no files selected)");
15479   s3 = XmStringCreateLocalized(title);
15480   XtVaSetValues(vdat->left_title,
15481 		XmNlabelString, s3,
15482 		NULL);
15483   XmStringFree(s3);
15484   free(title);
15485 
15486   s1 = XmStringCreateLocalized((char *)"|");
15487   s2 = XmStringCreateLocalized((char *)"|");
15488   XtVaSetValues(vdat->info1, XmNlabelString, s1, NULL);
15489   XtVaSetValues(vdat->info2, XmNlabelString, s2, NULL);
15490   XmStringFree(s1);
15491   XmStringFree(s2);
15492 }
15493 
15494 
view_files_select_callback(Widget w,XtPointer context,XtPointer info)15495 static void view_files_select_callback(Widget w, XtPointer context, XtPointer info)
15496 {
15497   static oclock_t mouse_down_time = 0;
15498   XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info;
15499   XButtonEvent *ev;
15500   ev = (XButtonEvent *)(cb->event);
15501 
15502   /* cb->click_count is always 1 so we can't detect a double-click that way
15503    *   ss->click_time has the (very short!) multiclick time
15504    */
15505 
15506   if (mouse_down_time != 0)
15507     {
15508       if ((ev->time - mouse_down_time) < ss->click_time) /* open file if double clicked */
15509 	{
15510 	  mouse_down_time = ev->time;
15511 	  view_files_open_selected_files((view_files_info *)(((vf_row *)context)->vdat));
15512 	  return;
15513 	}
15514     }
15515   mouse_down_time = ev->time;
15516   view_files_select((vf_row *)context, ev->state & ShiftMask);
15517 }
15518 
15519 
view_files_play_callback(Widget w,XtPointer context,XtPointer info)15520 static void view_files_play_callback(Widget w, XtPointer context, XtPointer info)
15521 {
15522 #if WITH_AUDIO
15523   /* open and play -- close at end or when button off toggled */
15524   vf_row *r = (vf_row *)context;
15525   view_files_info *vdat;
15526   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
15527   vdat = (view_files_info *)(r->vdat);
15528   if (view_files_play(vdat, r->pos, cb->set))
15529     XmToggleButtonSetState(w, false, false);
15530   else vdat->current_play_button = w;
15531 #endif
15532 }
15533 
15534 
view_files_make_row(view_files_info * vdat,widget_t last_row)15535 static vf_row *view_files_make_row(view_files_info *vdat, widget_t last_row)
15536 {
15537   return(make_vf_row(vdat, last_row, view_files_play_callback, view_files_select_callback));
15538 }
15539 
15540 
view_files_help_callback(Widget w,XtPointer context,XtPointer info)15541 static void view_files_help_callback(Widget w, XtPointer context, XtPointer info)
15542 {
15543   view_files_dialog_help();
15544 }
15545 
15546 
view_files_quit_callback(Widget w,XtPointer context,XtPointer info)15547 static void view_files_quit_callback(Widget w, XtPointer context, XtPointer info)
15548 {
15549   view_files_info *vdat = (view_files_info *)context;
15550   XtUnmanageChild(vdat->dialog);
15551 }
15552 
15553 
view_files_new_viewer_callback(Widget w,XtPointer context,XtPointer info)15554 static void view_files_new_viewer_callback(Widget w, XtPointer context, XtPointer info)
15555 {
15556   view_files_info *vdat = (view_files_info *)context;
15557   if ((vdat) &&
15558       (vdat->dialog) &&
15559       (XtIsManaged(vdat->dialog)) &&
15560       (XmGetFocusWidget(vdat->dialog) == XmMessageBoxGetChild(vdat->dialog, XmDIALOG_OK_BUTTON)))
15561     {
15562       Position x = 0, y = 0;
15563 
15564       /* jog the current one over a bit -- otherwise the new one lands exactly on top of the old! */
15565       XtVaGetValues(vdat->dialog, XmNx, &x, XmNy, &y, NULL);
15566       XtVaSetValues(vdat->dialog, XmNx, x + 30, XmNy, y - 30, NULL);
15567 
15568       vdat = new_view_files_dialog();
15569       make_view_files_dialog_1(vdat, true);
15570     }
15571 }
15572 
15573 
sort_vf(view_files_info * vdat,int sort_choice)15574 static void sort_vf(view_files_info *vdat, int sort_choice)
15575 {
15576   vdat->sorter = sort_choice;
15577   vf_reflect_sort_choice_in_menu(vdat);
15578   view_files_display_list(vdat);
15579 }
15580 
15581 
sort_view_files_a_to_z(Widget w,XtPointer context,XtPointer info)15582 static void sort_view_files_a_to_z(Widget w, XtPointer context, XtPointer info)
15583 {
15584   sort_vf((view_files_info *)context, SORT_A_TO_Z);
15585 }
15586 
15587 
sort_view_files_z_to_a(Widget w,XtPointer context,XtPointer info)15588 static void sort_view_files_z_to_a(Widget w, XtPointer context, XtPointer info)
15589 {
15590   sort_vf((view_files_info *)context, SORT_Z_TO_A);
15591 }
15592 
15593 
sort_view_files_new_to_old(Widget w,XtPointer context,XtPointer info)15594 static void sort_view_files_new_to_old(Widget w, XtPointer context, XtPointer info)
15595 {
15596   sort_vf((view_files_info *)context, SORT_NEW_TO_OLD);
15597 }
15598 
15599 
sort_view_files_old_to_new(Widget w,XtPointer context,XtPointer info)15600 static void sort_view_files_old_to_new(Widget w, XtPointer context, XtPointer info)
15601 {
15602   sort_vf((view_files_info *)context, SORT_OLD_TO_NEW);
15603 }
15604 
15605 
sort_view_files_big_to_small(Widget w,XtPointer context,XtPointer info)15606 static void sort_view_files_big_to_small(Widget w, XtPointer context, XtPointer info)
15607 {
15608   sort_vf((view_files_info *)context, SORT_BIG_TO_SMALL);
15609 }
15610 
15611 
sort_view_files_small_to_big(Widget w,XtPointer context,XtPointer info)15612 static void sort_view_files_small_to_big(Widget w, XtPointer context, XtPointer info)
15613 {
15614   sort_vf((view_files_info *)context, SORT_SMALL_TO_BIG);
15615 }
15616 
15617 
sort_view_files_xen(Widget w,XtPointer context,XtPointer info)15618 static void sort_view_files_xen(Widget w, XtPointer context, XtPointer info)
15619 {
15620   intptr_t index;
15621   XtVaGetValues(w, XmNuserData, &index, NULL); /* index is location in list of file-sorters */
15622   sort_vf((view_files_info *)context, (int)index);
15623 }
15624 
15625 
vf_reflect_sort_choice_in_menu(view_files_info * vdat)15626 static void vf_reflect_sort_choice_in_menu(view_files_info *vdat)
15627 {
15628   int i;
15629   set_sensitive(vdat->a_to_z, vdat->sorter != SORT_A_TO_Z);
15630   set_sensitive(vdat->z_to_a, vdat->sorter != SORT_Z_TO_A);
15631   set_sensitive(vdat->new_to_old, vdat->sorter != SORT_NEW_TO_OLD);
15632   set_sensitive(vdat->old_to_new, vdat->sorter != SORT_OLD_TO_NEW);
15633   set_sensitive(vdat->small_to_big, vdat->sorter != SORT_SMALL_TO_BIG);
15634   set_sensitive(vdat->big_to_small, vdat->sorter != SORT_BIG_TO_SMALL);
15635   for (i = 0; i < vdat->sort_items_size; i++)
15636     if (XtIsManaged(vdat->sort_items[i]))
15637       set_sensitive(vdat->sort_items[i], vdat->sorter != (SORT_XEN + i));
15638 }
15639 
15640 
view_files_add_file_or_directory(view_files_info * vdat,const char * file_or_dir)15641 static void view_files_add_file_or_directory(view_files_info *vdat, const char *file_or_dir)
15642 {
15643   char *filename;
15644   filename = mus_expand_filename((const char *)file_or_dir);
15645   if (filename)
15646     {
15647       int len;
15648       len = strlen(filename);
15649       if (filename[len - 1] == '*')
15650 	filename[len - 1] = 0;
15651       if (is_directory(filename))
15652 	add_directory_to_view_files_list(vdat, (const char *)filename);
15653       else add_file_to_view_files_list(vdat, file_or_dir, filename);
15654       free(filename);
15655     }
15656 }
15657 
15658 
view_files_add_files(Widget w,XtPointer context,XtPointer info)15659 static void view_files_add_files(Widget w, XtPointer context, XtPointer info)
15660 {
15661   view_files_info *vdat = (view_files_info *)context;
15662   char *file_or_dir;
15663   file_or_dir = XmTextFieldGetString(w);
15664   if ((file_or_dir) && (*file_or_dir))
15665     {
15666       view_files_add_file_or_directory(vdat, (const char *)file_or_dir);
15667       XtFree(file_or_dir);
15668       view_files_display_list(vdat);
15669     }
15670 }
15671 
15672 
view_files_drop_watcher(Widget w,const char * str,Position x,Position y,void * context)15673 static void view_files_drop_watcher(Widget w, const char *str, Position x, Position y, void *context)
15674 {
15675   view_files_info *vdat = (view_files_info *)context;
15676   /* incoming str is a single filename (drop watcher code splits the possible list and calls us on each one) */
15677   view_files_add_file_or_directory(vdat, str);
15678   view_files_display_list(vdat);
15679 }
15680 
15681 
view_files_drag_watcher(Widget w,const char * str,Position x,Position y,drag_style_t dtype,void * context)15682 static void view_files_drag_watcher(Widget w, const char *str, Position x, Position y, drag_style_t dtype, void *context)
15683 {
15684   view_files_info *vdat = (view_files_info *)context;
15685   switch (dtype)
15686     {
15687     case DRAG_ENTER:
15688       XmChangeColor(vdat->file_list, ss->selection_color);
15689       break;
15690 
15691     case DRAG_LEAVE:
15692       XmChangeColor(vdat->file_list, ss->basic_color);
15693       break;
15694 
15695     default:
15696       break;
15697     }
15698 }
15699 
15700 
vf_location(view_files_info * vdat)15701 static mus_long_t vf_location(view_files_info *vdat)
15702 {
15703   mus_long_t pos = 0;
15704   snd_info *sp;
15705   chan_info *cp;
15706   char *str;
15707   switch (vdat->location_choice)
15708     {
15709     case VF_AT_CURSOR:
15710       sp = any_selected_sound();
15711       if (sp)
15712 	{
15713 	  cp = any_selected_channel(sp);
15714 	  return(cursor_sample(cp));
15715 	}
15716       break;
15717 
15718     case VF_AT_END:
15719       sp = any_selected_sound();
15720       if (sp)
15721 	{
15722 	  cp = any_selected_channel(sp);
15723 	  return(current_samples(cp));
15724 	}
15725       break;
15726 
15727     case VF_AT_BEGINNING:
15728       return(0);
15729       break;
15730 
15731     case VF_AT_MARK:
15732       str = XmTextGetString(vdat->at_mark_text);
15733       if ((str) && (*str))
15734 	{
15735 	  pos = mark_id_to_sample(string_to_int(str, 0, "mark"));
15736 	  XtFree(str);
15737 	  if (pos < 0)
15738 	    snd_error_without_format("no such mark");
15739 	}
15740       else snd_error_without_format("no mark?");
15741       break;
15742 
15743     case VF_AT_SAMPLE:
15744       str = XmTextGetString(vdat->at_sample_text);
15745       if ((str) && (*str))
15746 	{
15747 	  pos = string_to_mus_long_t(str, 0, "sample");
15748 	  XtFree(str);
15749 	  /* pos already checked for lower bound */
15750 	}
15751       else snd_error_without_format("no sample number?");
15752       break;
15753     }
15754   return(pos);
15755 }
15756 
15757 
15758 static void vf_clear_sample(view_files_info *vdat);
15759 
vf_sample_button_modify_callback(Widget w,XtPointer context,XtPointer info)15760 static void vf_sample_button_modify_callback(Widget w, XtPointer context, XtPointer info)
15761 {
15762   vf_clear_sample((view_files_info *)context);
15763 }
15764 
15765 
vf_sample_text_modify_callback(Widget w,XtPointer context,XtPointer info)15766 static void vf_sample_text_modify_callback(Widget w, XtPointer context, XtPointer info)
15767 {
15768   XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info;
15769   vf_clear_sample((view_files_info *)context);
15770   cbs->doit = true;
15771 }
15772 
15773 
vf_clear_sample(view_files_info * vdat)15774 static void vf_clear_sample(view_files_info *vdat)
15775 {
15776   vf_clear_error(vdat);
15777   XtRemoveCallback(vdat->at_sample_text, XmNmodifyVerifyCallback, vf_sample_text_modify_callback, (XtPointer)vdat);
15778   XtRemoveCallback(vdat->at_sample_button, XmNvalueChangedCallback, vf_sample_button_modify_callback, (XtPointer)vdat);
15779 }
15780 
15781 
15782 static void vf_clear_mark(view_files_info *vdat);
15783 
vf_mark_button_modify_callback(Widget w,XtPointer context,XtPointer info)15784 static void vf_mark_button_modify_callback(Widget w, XtPointer context, XtPointer info)
15785 {
15786   vf_clear_mark((view_files_info *)context);
15787 }
15788 
15789 
vf_mark_text_modify_callback(Widget w,XtPointer context,XtPointer info)15790 static void vf_mark_text_modify_callback(Widget w, XtPointer context, XtPointer info)
15791 {
15792   XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info;
15793   vf_clear_mark((view_files_info *)context);
15794   cbs->doit = true;
15795 }
15796 
15797 
vf_clear_mark(view_files_info * vdat)15798 static void vf_clear_mark(view_files_info *vdat)
15799 {
15800   vf_clear_error(vdat);
15801   XtRemoveCallback(vdat->at_mark_text, XmNmodifyVerifyCallback, vf_mark_text_modify_callback, (XtPointer)vdat);
15802   XtRemoveCallback(vdat->at_mark_button, XmNvalueChangedCallback, vf_mark_button_modify_callback, (XtPointer)vdat);
15803 }
15804 
15805 
15806 static void vf_add_text_modify_callback(Widget w, XtPointer context, XtPointer info);
15807 
remove_all_pending_clear_callbacks(view_files_info * vdat)15808 static void remove_all_pending_clear_callbacks(view_files_info *vdat)
15809 {
15810   /* docs say this is a no-op if the indicated callback does not exist (i.e. not an error or segfault) */
15811   XtRemoveCallback(vdat->at_mark_text, XmNmodifyVerifyCallback, vf_mark_text_modify_callback, (XtPointer)vdat);
15812   XtRemoveCallback(vdat->at_mark_button, XmNvalueChangedCallback, vf_mark_button_modify_callback, (XtPointer)vdat);
15813   XtRemoveCallback(vdat->at_sample_text, XmNmodifyVerifyCallback, vf_sample_text_modify_callback, (XtPointer)vdat);
15814   XtRemoveCallback(vdat->at_sample_button, XmNvalueChangedCallback, vf_sample_button_modify_callback, (XtPointer)vdat);
15815   XtRemoveCallback(vdat->add_text, XmNmodifyVerifyCallback, vf_add_text_modify_callback, (XtPointer)vdat);
15816 }
15817 
15818 
vf_post_error(const char * error_msg,view_files_info * vdat)15819 static void vf_post_error(const char *error_msg, view_files_info *vdat)
15820 {
15821   XmString msg;
15822   remove_all_pending_clear_callbacks(vdat);
15823   vdat->has_error = true;
15824   msg = XmStringCreateLocalized((char *)error_msg);
15825   XtVaSetValues(vdat->info1,
15826 		XmNlabelString, msg,
15827 		NULL);
15828   XmStringFree(msg);
15829   msg = XmStringCreateLocalized((char *)"");
15830   XtVaSetValues(vdat->info2,
15831 		XmNlabelString, msg,
15832 		NULL);
15833   XmStringFree(msg);
15834 }
15835 
15836 
redirect_vf_post_error(const char * error_msg,void * vdat)15837 static void redirect_vf_post_error(const char *error_msg, void *vdat)
15838 {
15839   vf_post_error(error_msg, (view_files_info *)vdat);
15840 }
15841 
15842 
redirect_vf_post_location_error(const char * error_msg,void * data)15843 static void redirect_vf_post_location_error(const char *error_msg, void *data)
15844 {
15845   view_files_info *vdat = (view_files_info *)data;
15846   vf_post_error(error_msg, vdat);
15847   if (vdat->location_choice == VF_AT_SAMPLE)
15848     {
15849       /* watch at_sample_text or button (undo) */
15850       XtAddCallback(vdat->at_sample_text, XmNmodifyVerifyCallback, vf_sample_text_modify_callback, (XtPointer)vdat);
15851       XtAddCallback(vdat->at_sample_button, XmNvalueChangedCallback, vf_sample_button_modify_callback, (XtPointer)vdat);
15852     }
15853   else
15854     {
15855       /* watch at_mark_text or button */
15856       XtAddCallback(vdat->at_mark_text, XmNmodifyVerifyCallback, vf_mark_text_modify_callback, (XtPointer)vdat);
15857       XtAddCallback(vdat->at_mark_button, XmNvalueChangedCallback, vf_mark_button_modify_callback, (XtPointer)vdat);
15858     }
15859 }
15860 
15861 
vf_add_text_modify_callback(Widget w,XtPointer context,XtPointer info)15862 static void vf_add_text_modify_callback(Widget w, XtPointer context, XtPointer info)
15863 {
15864   XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info;
15865   view_files_info *vdat = (view_files_info *)context;
15866   vf_clear_error(vdat);
15867   XtRemoveCallback(vdat->add_text, XmNmodifyVerifyCallback, vf_add_text_modify_callback, (XtPointer)vdat);
15868   cbs->doit = true;
15869 }
15870 
15871 
vf_post_add_error(const char * error_msg,view_files_info * vdat)15872 static void vf_post_add_error(const char *error_msg, view_files_info *vdat)
15873 {
15874   vf_post_error(error_msg, vdat);
15875   XtAddCallback(vdat->add_text, XmNmodifyVerifyCallback, vf_add_text_modify_callback, (XtPointer)vdat);
15876   /* what about other clearing actions? */
15877 }
15878 
15879 
view_files_mix_selected_callback(Widget w,XtPointer context,XtPointer info)15880 static void view_files_mix_selected_callback(Widget w, XtPointer context, XtPointer info)
15881 {
15882   view_files_mix_selected_files(w, (view_files_info *)context);
15883 }
15884 
15885 
view_files_insert_selected_callback(Widget w,XtPointer context,XtPointer info)15886 static void view_files_insert_selected_callback(Widget w, XtPointer context, XtPointer info)
15887 {
15888   view_files_insert_selected_files(w, (view_files_info *)context);
15889 }
15890 
15891 
view_files_at_cursor_callback(Widget w,XtPointer context,XtPointer info)15892 static void view_files_at_cursor_callback(Widget w, XtPointer context, XtPointer info)
15893 {
15894   view_files_info *vdat = (view_files_info *)context;
15895   if (vdat->has_error)
15896     {
15897       if (vdat->location_choice == VF_AT_SAMPLE)
15898 	vf_clear_sample(vdat);
15899       else vf_clear_mark(vdat);
15900     }
15901   XmToggleButtonSetState(vdat->at_cursor_button, true, false);
15902   XmToggleButtonSetState(vdat->at_end_button, false, false);
15903   XmToggleButtonSetState(vdat->at_beginning_button, false, false);
15904   XmToggleButtonSetState(vdat->at_mark_button, false, false);
15905   XmToggleButtonSetState(vdat->at_sample_button, false, false);
15906   vdat->location_choice = VF_AT_CURSOR;
15907 }
15908 
15909 
view_files_at_end_callback(Widget w,XtPointer context,XtPointer info)15910 static void view_files_at_end_callback(Widget w, XtPointer context, XtPointer info)
15911 {
15912   view_files_info *vdat = (view_files_info *)context;
15913   if (vdat->has_error)
15914     {
15915       if (vdat->location_choice == VF_AT_SAMPLE)
15916 	vf_clear_sample(vdat);
15917       else vf_clear_mark(vdat);
15918     }
15919   XmToggleButtonSetState(vdat->at_cursor_button, false, false);
15920   XmToggleButtonSetState(vdat->at_end_button, true, false);
15921   XmToggleButtonSetState(vdat->at_beginning_button, false, false);
15922   XmToggleButtonSetState(vdat->at_mark_button, false, false);
15923   XmToggleButtonSetState(vdat->at_sample_button, false, false);
15924   vdat->location_choice = VF_AT_END;
15925 }
15926 
15927 
view_files_at_beginning_callback(Widget w,XtPointer context,XtPointer info)15928 static void view_files_at_beginning_callback(Widget w, XtPointer context, XtPointer info)
15929 {
15930   view_files_info *vdat = (view_files_info *)context;
15931   if (vdat->has_error)
15932     {
15933       if (vdat->location_choice == VF_AT_SAMPLE)
15934 	vf_clear_sample(vdat);
15935       else vf_clear_mark(vdat);
15936     }
15937   XmToggleButtonSetState(vdat->at_cursor_button, false, false);
15938   XmToggleButtonSetState(vdat->at_end_button, false, false);
15939   XmToggleButtonSetState(vdat->at_beginning_button, true, false);
15940   XmToggleButtonSetState(vdat->at_mark_button, false, false);
15941   XmToggleButtonSetState(vdat->at_sample_button, false, false);
15942   vdat->location_choice = VF_AT_BEGINNING;
15943 }
15944 
15945 
view_files_at_sample_callback(Widget w,XtPointer context,XtPointer info)15946 static void view_files_at_sample_callback(Widget w, XtPointer context, XtPointer info)
15947 {
15948   view_files_info *vdat = (view_files_info *)context;
15949   if ((vdat->has_error) &&
15950       (vdat->location_choice == VF_AT_MARK))
15951       vf_clear_mark(vdat);
15952   XmToggleButtonSetState(vdat->at_cursor_button, false, false);
15953   XmToggleButtonSetState(vdat->at_end_button, false, false);
15954   XmToggleButtonSetState(vdat->at_beginning_button, false, false);
15955   XmToggleButtonSetState(vdat->at_mark_button, false, false);
15956   XmToggleButtonSetState(vdat->at_sample_button, true, false);
15957   vdat->location_choice = VF_AT_SAMPLE;
15958 }
15959 
15960 
view_files_at_mark_callback(Widget w,XtPointer context,XtPointer info)15961 static void view_files_at_mark_callback(Widget w, XtPointer context, XtPointer info)
15962 {
15963   view_files_info *vdat = (view_files_info *)context;
15964   if ((vdat->has_error) &&
15965       (vdat->location_choice == VF_AT_SAMPLE))
15966     vf_clear_sample(vdat);
15967   XmToggleButtonSetState(vdat->at_cursor_button, false, false);
15968   XmToggleButtonSetState(vdat->at_end_button, false, false);
15969   XmToggleButtonSetState(vdat->at_beginning_button, false, false);
15970   XmToggleButtonSetState(vdat->at_mark_button, true, false);
15971   XmToggleButtonSetState(vdat->at_sample_button, false, false);
15972   vdat->location_choice = VF_AT_MARK;
15973 }
15974 
15975 
15976 
15977 /* -------- speed -------- */
15978 
vf_speed_to_scroll(mus_float_t minval,mus_float_t val,mus_float_t maxval)15979 static int vf_speed_to_scroll(mus_float_t minval, mus_float_t val, mus_float_t maxval)
15980 {
15981   if (val <= minval) return(0);
15982   if (val >= maxval) return((int)(0.9 * SCROLLBAR_MAX));
15983   return(snd_round(0.9 * SCROLLBAR_MAX * ((log(val) - log(minval)) / (log(maxval) - log(minval)))));
15984 }
15985 
15986 
vf_set_speed(view_files_info * vdat,mus_float_t val)15987 static void vf_set_speed(view_files_info *vdat, mus_float_t val)
15988 {
15989   char speed_number_buffer[6];
15990   vdat->speed = speed_changed(val,
15991 			      speed_number_buffer,
15992 			      vdat->speed_style,
15993 			      speed_control_tones(ss),
15994 			      6);
15995   set_label(vdat->speed_number, speed_number_buffer);
15996   XtVaSetValues(vdat->speed_scrollbar,
15997 		XmNvalue, vf_speed_to_scroll(speed_control_min(ss), val, speed_control_max(ss)),
15998 		NULL);
15999 }
16000 
16001 
vf_speed_click_callback(Widget w,XtPointer context,XtPointer info)16002 static void vf_speed_click_callback(Widget w, XtPointer context, XtPointer info)
16003 {
16004   view_files_info *vdat = (view_files_info *)context;
16005   vf_set_speed(vdat, 1.0);
16006   XtVaSetValues(vdat->speed_scrollbar,
16007 		XmNvalue, vf_speed_to_scroll(speed_control_min(ss), 1.0, speed_control_max(ss)),
16008 		NULL);
16009 }
16010 
16011 
vf_speed_label_click_callback(Widget w,XtPointer context,XtPointer info)16012 static void vf_speed_label_click_callback(Widget w, XtPointer context, XtPointer info)
16013 {
16014   char speed_number_buffer[6];
16015   view_files_info *vdat = (view_files_info *)context;
16016 
16017   switch (vdat->speed_style)
16018     {
16019     default:
16020     case SPEED_CONTROL_AS_FLOAT:    vdat->speed_style = SPEED_CONTROL_AS_RATIO;    break;
16021     case SPEED_CONTROL_AS_RATIO:    vdat->speed_style = SPEED_CONTROL_AS_SEMITONE; break;
16022     case SPEED_CONTROL_AS_SEMITONE: vdat->speed_style = SPEED_CONTROL_AS_FLOAT;    break;
16023     }
16024   speed_changed(vdat->speed,
16025 		speed_number_buffer,
16026 		vdat->speed_style,
16027 		speed_control_tones(ss),
16028 		6);
16029   set_label(vdat->speed_number, speed_number_buffer);
16030 }
16031 
16032 
vf_speed_valuechanged_callback(Widget w,XtPointer context,XtPointer info)16033 static void vf_speed_valuechanged_callback(Widget w, XtPointer context, XtPointer info)
16034 {
16035   view_files_info *vdat = (view_files_info *)context;
16036   XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info;
16037   vf_set_speed(vdat, exp((cb->value *
16038 			  (log(speed_control_max(ss)) - log(speed_control_min(ss))) /
16039 			  (0.9 * SCROLLBAR_MAX)) + log(speed_control_min(ss))));
16040 }
16041 
16042 
vf_speed_drag_callback(Widget w,XtPointer context,XtPointer info)16043 static void vf_speed_drag_callback(Widget w, XtPointer context, XtPointer info)
16044 {
16045   view_files_info *vdat = (view_files_info *)context;
16046   XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info;
16047   vf_set_speed(vdat, exp((cb->value *
16048 			  (log(speed_control_max(ss)) - log(speed_control_min(ss))) /
16049 			  (0.9 * SCROLLBAR_MAX)) + log(speed_control_min(ss))));
16050 }
16051 
16052 
16053 
16054 /* -------- amp -------- */
16055 
vf_scroll_to_amp(int val)16056 static mus_float_t vf_scroll_to_amp(int val)
16057 {
16058   if (val <= 0)
16059     return(amp_control_min(ss));
16060   if (val >= (0.9 * SCROLLBAR_MAX))
16061     return(amp_control_max(ss));
16062   if (val > (0.5 * 0.9 * SCROLLBAR_MAX))
16063     return((((val / (0.5 * 0.9 * SCROLLBAR_MAX)) - 1.0) * (amp_control_max(ss) - 1.0)) + 1.0);
16064   else return((val * (1.0 - amp_control_min(ss)) / (0.5 * 0.9 * SCROLLBAR_MAX)) + amp_control_min(ss));
16065 }
16066 
16067 
vf_amp_to_scroll(mus_float_t amp)16068 static int vf_amp_to_scroll(mus_float_t amp)
16069 {
16070   return(amp_to_scroll(amp_control_min(ss), amp, amp_control_max(ss)));
16071 }
16072 
16073 
vf_set_amp(view_files_info * vdat,mus_float_t val)16074 static void vf_set_amp(view_files_info *vdat, mus_float_t val)
16075 {
16076   char sfs[6];
16077   vdat->amp = val;
16078   snprintf(sfs, 6, "%.2f", val);
16079   set_label(vdat->amp_number, sfs);
16080   XtVaSetValues(vdat->amp_scrollbar,
16081 		XmNvalue, amp_to_scroll(amp_control_min(ss), val, amp_control_max(ss)),
16082 		NULL);
16083 }
16084 
16085 
vf_amp_click_callback(Widget w,XtPointer context,XtPointer info)16086 static void vf_amp_click_callback(Widget w, XtPointer context, XtPointer info)
16087 {
16088   vf_set_amp((view_files_info *)context, 1.0);
16089 }
16090 
16091 
vf_amp_valuechanged_callback(Widget w,XtPointer context,XtPointer info)16092 static void vf_amp_valuechanged_callback(Widget w, XtPointer context, XtPointer info)
16093 {
16094   vf_set_amp((view_files_info *)context,
16095 	     vf_scroll_to_amp(((XmScrollBarCallbackStruct *)info)->value));
16096 }
16097 
16098 
vf_amp_drag_callback(Widget w,XtPointer context,XtPointer info)16099 static void vf_amp_drag_callback(Widget w, XtPointer context, XtPointer info)
16100 {
16101   vf_set_amp((view_files_info *)context,
16102 	     vf_scroll_to_amp(((XmScrollBarCallbackStruct *)info)->value));
16103 }
16104 
16105 
16106 
16107 
16108 /* -------- amp-envs -------- */
16109 
vf_amp_env_resize(Widget w,XtPointer context,XtPointer info)16110 static void vf_amp_env_resize(Widget w, XtPointer context, XtPointer info)
16111 {
16112   view_files_info *vdat = (view_files_info *)context;
16113   if (!vdat->env_ax)
16114     {
16115       XGCValues gv;
16116       gv.function = GXcopy;
16117       XtVaGetValues(vdat->env_drawer, XmNbackground, &gv.background, XmNforeground, &gv.foreground, NULL);
16118       vdat->env_gc = XtGetGC(vdat->env_drawer, GCForeground | GCFunction, &gv);
16119       vdat->env_ax = (graphics_context *)calloc(1, sizeof(graphics_context));
16120       vdat->env_ax->wn = XtWindow(vdat->env_drawer);
16121       vdat->env_ax->dp = XtDisplay(vdat->env_drawer);
16122       vdat->env_ax->gc = vdat->env_gc;
16123       if (!(vdat->env_ax->wn)) return;
16124     }
16125   else
16126     {
16127       if (!(vdat->env_ax->wn))
16128 	{
16129 	  vdat->env_ax->wn = XtWindow(vdat->env_drawer); /* sometimes the dialog window is not ready when display_env gets called */
16130 	  if (!(vdat->env_ax->wn)) return;
16131 	}
16132       clear_window(vdat->env_ax);
16133     }
16134   vdat->spf->with_dots = true;
16135   env_editor_display_env(vdat->spf, vdat->amp_env, vdat->env_ax, "amp env",
16136 			 0, 0,
16137 			 widget_width(w), widget_height(w),
16138 			 NOT_PRINTING);
16139   /* it might be nice to show the sound data in the background, but there are
16140    *   complications involving multichannel and multiselection cases, also
16141    *   how to get the "peak-func" and how to call g_channel_amp_envs.
16142    * Too many problems...
16143    *   but perhaps something like the region browser display would work:
16144    *   label saying file+chan and up/down arrows to see the rest + off button
16145    */
16146 }
16147 
16148 
vf_amp_env_redraw(Widget w,view_files_info * vdat)16149 static void vf_amp_env_redraw(Widget w, view_files_info *vdat)
16150 {
16151   vf_amp_env_resize(w, (void *)vdat, NULL);
16152 }
16153 
16154 
vf_drawer_button_motion(Widget w,XtPointer context,XEvent * event,Boolean * cont)16155 static void vf_drawer_button_motion(Widget w, XtPointer context, XEvent *event, Boolean *cont)
16156 {
16157   view_files_info *vdat = (view_files_info *)context;
16158   XMotionEvent *ev = (XMotionEvent *)event;
16159   /* mus_float_t pos; */
16160 
16161 #ifdef __APPLE__
16162   if ((press_x == ev->x) && (press_y == ev->y)) return;
16163 #endif
16164 
16165   /* pos = (mus_float_t)(ev->x) / (mus_float_t)widget_width(w); */
16166   env_editor_button_motion(vdat->spf, ev->x, ev->y, ev->time, vdat->amp_env);
16167   vf_amp_env_resize(w, context, NULL);
16168 }
16169 
16170 
vf_drawer_button_press(Widget w,XtPointer context,XEvent * event,Boolean * cont)16171 static void vf_drawer_button_press(Widget w, XtPointer context, XEvent *event, Boolean *cont)
16172 {
16173   view_files_info *vdat = (view_files_info *)context;
16174   XButtonEvent *ev = (XButtonEvent *)event;
16175   /* mus_float_t pos; */
16176 
16177 #ifdef __APPLE__
16178   press_x = ev->x;
16179   press_y = ev->y;
16180 #endif
16181 
16182   /* pos = (mus_float_t)(ev->x) / (mus_float_t)widget_width(w); */
16183   if (env_editor_button_press(vdat->spf, ev->x, ev->y, ev->time, vdat->amp_env))
16184     vf_amp_env_resize(w, context, NULL);
16185 }
16186 
16187 
vf_drawer_button_release(Widget w,XtPointer context,XEvent * event,Boolean * cont)16188 static void vf_drawer_button_release(Widget w, XtPointer context, XEvent *event, Boolean *cont)
16189 {
16190   view_files_info *vdat = (view_files_info *)context;
16191   /* XButtonEvent *ev = (XButtonEvent *)event; */
16192   /* mus_float_t pos; */
16193 
16194   /* pos = (mus_float_t)(ev->x) / (mus_float_t)widget_width(w); */
16195   env_editor_button_release(vdat->spf, vdat->amp_env);
16196   vf_amp_env_resize(w, context, NULL);
16197 }
16198 
16199 
vf_set_amp_env(view_files_info * vdat,env * new_e)16200 static void vf_set_amp_env(view_files_info *vdat, env *new_e)
16201 {
16202   if (!vdat) return;
16203   if (vdat->amp_env) free_env(vdat->amp_env);
16204   vdat->amp_env = copy_env(new_e);
16205   if ((vdat->dialog) &&
16206       (widget_is_active(vdat->dialog)))
16207     vf_amp_env_redraw(vdat->env_drawer, vdat);
16208 }
16209 
16210 
blue_textfield_unfocus_callback(Widget w,XtPointer context,XtPointer info)16211 static void blue_textfield_unfocus_callback(Widget w, XtPointer context, XtPointer info)
16212 {
16213   XtVaSetValues(w, XmNbackground, ss->lighter_blue, NULL);
16214   XtVaSetValues(w, XmNcursorPositionVisible, false, NULL);
16215 }
16216 
16217 
blue_mouse_leave_text_callback(Widget w,XtPointer context,XEvent * event,Boolean * flag)16218 static void blue_mouse_leave_text_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag)
16219 {
16220   XtVaSetValues(w, XmNbackground, ss->lighter_blue, NULL);
16221   XtVaSetValues(w, XmNcursorPositionVisible, false, NULL);
16222 }
16223 
16224 
white_mouse_enter_text_callback(Widget w,XtPointer context,XEvent * event,Boolean * flag)16225 static void white_mouse_enter_text_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag)
16226 {
16227   XtVaSetValues(w, XmNbackground, ss->text_focus_color, NULL);
16228   XtVaSetValues(w, XmNcursorPositionVisible, true, NULL);
16229 }
16230 
16231 
view_files_reset_callback(Widget w,XtPointer context,XtPointer info)16232 static void view_files_reset_callback(Widget w, XtPointer context, XtPointer info)
16233 {
16234   view_files_info *vdat = (view_files_info *)context;
16235   env *e;
16236   vf_set_amp(vdat, 1.0);
16237   vf_set_speed(vdat, 1.0);
16238   vf_set_amp_env(vdat, e = default_env(1.0, 1.0)); /* vf_set_amp_env copies the envelope */
16239   free_env(e);
16240   sort_vf(vdat, view_files_sort(ss));
16241 }
16242 
16243 
16244 
make_view_files_dialog_1(view_files_info * vdat,bool managed)16245 static widget_t make_view_files_dialog_1(view_files_info *vdat, bool managed)
16246 {
16247   if (!(vdat->dialog))
16248     {
16249       int i, n;
16250       Arg args[20];
16251       XmString go_away, xhelp, titlestr, new_viewer_str, s1, bstr;
16252       Widget mainform, viewform, leftform, reset_button, new_viewer_button;
16253       Widget left_title_sep, add_label, sep1, sep3, sep4, sep6, sep7;
16254 #if WITH_AUDIO
16255       Widget plw;
16256 #endif
16257       Widget rlw, sbar;
16258       XtCallbackList n1, n2, n3, n4;
16259       Widget amp_label, speed_label, env_frame;
16260       Widget bframe, bform;
16261 
16262       go_away = XmStringCreateLocalized((char *)I_GO_AWAY);
16263       xhelp = XmStringCreateLocalized((char *)I_HELP);
16264       new_viewer_str = XmStringCreateLocalized((char *)"New Viewer");
16265 
16266       {
16267 	char *filestr = NULL;
16268 	filestr = mus_format("%s %d", "Files", vdat->index + 1);
16269 	titlestr = XmStringCreateLocalized(filestr);
16270 	free(filestr);
16271       }
16272 
16273       n = 0;
16274       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16275       XtSetArg(args[n], XmNhelpLabelString, xhelp); n++;
16276       XtSetArg(args[n], XmNokLabelString, new_viewer_str); n++;
16277       XtSetArg(args[n], XmNcancelLabelString, go_away); n++;
16278       XtSetArg(args[n], XmNautoUnmanage, false); n++;
16279       XtSetArg(args[n], XmNdialogTitle, titlestr); n++;
16280       XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
16281       XtSetArg(args[n], XmNnoResize, false); n++;
16282       XtSetArg(args[n], XmNtransient, false); n++;
16283       vdat->dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"Files", args, n);
16284       new_viewer_button = MSG_BOX(vdat->dialog, XmDIALOG_OK_BUTTON);
16285 
16286       XtAddCallback(vdat->dialog, XmNhelpCallback,   view_files_help_callback,       (XtPointer)vdat);
16287       /* XtAddCallback(vdat->dialog, XmNokCallback,     view_files_new_viewer_callback,    (XtPointer)vdat); */
16288       XtAddCallback(new_viewer_button, XmNactivateCallback, view_files_new_viewer_callback, (XtPointer)vdat);
16289       XtAddCallback(vdat->dialog, XmNcancelCallback, view_files_quit_callback, (XtPointer)vdat);
16290 
16291       n = 0;
16292       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
16293       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
16294       reset_button = XtCreateManagedWidget("Reset", xmPushButtonGadgetClass, vdat->dialog, args, n);
16295       XtAddCallback(reset_button, XmNactivateCallback, view_files_reset_callback, (XtPointer)vdat);
16296 
16297       XmStringFree(xhelp);
16298       XmStringFree(go_away);
16299       XmStringFree(titlestr);
16300       XmStringFree(new_viewer_str);
16301 
16302       XtVaSetValues(MSG_BOX(vdat->dialog, XmDIALOG_OK_BUTTON),     XmNarmColor,   ss->selection_color, NULL);
16303       XtVaSetValues(MSG_BOX(vdat->dialog, XmDIALOG_HELP_BUTTON),   XmNarmColor,   ss->selection_color, NULL);
16304       XtVaSetValues(MSG_BOX(vdat->dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor,   ss->selection_color,  NULL);
16305       XtVaSetValues(MSG_BOX(vdat->dialog, XmDIALOG_OK_BUTTON),     XmNbackground, ss->highlight_color,   NULL);
16306       XtVaSetValues(MSG_BOX(vdat->dialog, XmDIALOG_HELP_BUTTON),   XmNbackground, ss->highlight_color,   NULL);
16307       XtVaSetValues(MSG_BOX(vdat->dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color,  NULL);
16308 
16309       n = 0;
16310       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16311       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16312       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16313       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
16314       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
16315       XtSetArg(args[n], XmNbottomWidget, MSG_BOX(vdat->dialog, XmDIALOG_SEPARATOR)); n++;
16316       XtSetArg(args[n], XmNsashIndent, 2); n++;
16317       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
16318       XtSetArg(args[n], XmNspacing, 24); n++;
16319       XtSetArg(args[n], XmNpaneMaximum, LOTSA_PIXELS); n++;
16320       mainform = XtCreateManagedWidget("formd", xmPanedWindowWidgetClass, vdat->dialog, args, n);
16321 
16322       /* -------- left side controls -------- */
16323       n = 0;
16324       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16325       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16326       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16327       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
16328       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
16329       leftform = XtCreateManagedWidget("leftform", xmFormWidgetClass, mainform, args, n);
16330 
16331       n = 0;
16332       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
16333       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16334       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16335       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
16336       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16337       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
16338       vdat->left_title = XtCreateManagedWidget("(no files selected)", xmLabelWidgetClass, leftform, args, n);
16339 
16340       n = 0;
16341       XtSetArg(args[n], XmNbackground, ss->white); n++;
16342       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16343       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16344       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16345       XtSetArg(args[n], XmNtopWidget, vdat->left_title); n++;
16346       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16347       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
16348       XtSetArg(args[n], XmNseparatorType, XmDOUBLE_LINE); n++;
16349       left_title_sep = XtCreateManagedWidget("sep", xmSeparatorWidgetClass, leftform, args, n);
16350 
16351       n = 0;
16352       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
16353       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16354       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16355       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16356       XtSetArg(args[n], XmNtopWidget, left_title_sep); n++;
16357       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16358       vdat->info1 = XtCreateManagedWidget("|", xmLabelWidgetClass, leftform, args, n);
16359 
16360       n = 0;
16361       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
16362       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16363       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16364       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16365       XtSetArg(args[n], XmNtopWidget, vdat->info1); n++;
16366       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16367       vdat->info2 = XtCreateManagedWidget("|", xmLabelWidgetClass, leftform, args, n);
16368 
16369       n = 0;
16370       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16371       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16372       XtSetArg(args[n], XmNtopWidget, vdat->info2); n++;
16373       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16374       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16375       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16376       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
16377       XtSetArg(args[n], XmNheight, 8); n++;
16378       XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
16379       sep6 = XtCreateManagedWidget("dialog-sep1", xmSeparatorWidgetClass, leftform, args, n);
16380 
16381       n = 0;
16382       XtSetArg(args[n], XmNbackground, ss->zoom_color); n++;
16383       XtSetArg(args[n], XmNborderColor, ss->zoom_color); n++;
16384       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16385       XtSetArg(args[n], XmNtopWidget, sep6); n++;
16386       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16387       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16388       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16389       XtSetArg(args[n], XmNborderWidth, 2); n++;
16390       bframe = XtCreateManagedWidget("bframe", xmFrameWidgetClass, leftform, args, n);
16391 
16392       n = 0;
16393       XtSetArg(args[n], XmNbackground, ss->position_color); n++;
16394       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
16395       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
16396       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16397       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16398       bform = XtCreateManagedWidget("bform", xmFormWidgetClass, bframe, args, n);
16399 
16400       n = 0;
16401       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
16402       XtSetArg(args[n], XmNmarginTop, 0); n++;
16403       XtSetArg(args[n], XmNmarginBottom, 0); n++;
16404       XtSetArg(args[n], XmNshadowThickness, 1); n++;
16405       XtSetArg(args[n], XmNhighlightThickness, 1); n++;
16406       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
16407       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16408       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16409       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
16410       XtSetArg(args[n], XmNrightPosition, 50); n++;
16411       vdat->mixB = XtCreateManagedWidget("Mix", xmPushButtonWidgetClass, bform, args, n);
16412       XtAddCallback(vdat->mixB, XmNactivateCallback, view_files_mix_selected_callback, (XtPointer)vdat);
16413 
16414       n = 0;
16415       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
16416       XtSetArg(args[n], XmNmarginTop, 0); n++;
16417       XtSetArg(args[n], XmNmarginBottom, 0); n++;
16418       XtSetArg(args[n], XmNshadowThickness, 1); n++;
16419       XtSetArg(args[n], XmNhighlightThickness, 1); n++;
16420       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
16421       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16422       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
16423       XtSetArg(args[n], XmNleftWidget, vdat->mixB); n++;
16424       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16425       vdat->insertB = XtCreateManagedWidget("Insert", xmPushButtonWidgetClass, bform, args, n);
16426       XtAddCallback(vdat->insertB, XmNactivateCallback, view_files_insert_selected_callback, (XtPointer)vdat);
16427 
16428       n = 0;
16429       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
16430       XtSetArg(args[n], XmNselectColor, ss->red); n++;
16431       bstr = XmStringCreateLocalized((char *)"at cursor");
16432       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16433       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16434       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16435       XtSetArg(args[n], XmNtopWidget, vdat->mixB); n++;
16436       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16437       XtSetArg(args[n], XmNlabelString, bstr); n++;
16438       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
16439       XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++;
16440       XtSetArg(args[n], XmNset, XmSET); n++;
16441       vdat->at_cursor_button = make_togglebutton_widget("at-cursor-button", bform, args, n);
16442       XtAddCallback(vdat->at_cursor_button, XmNdisarmCallback, view_files_at_cursor_callback, (XtPointer)vdat);
16443       XmStringFree(bstr);
16444 
16445       n = 0;
16446       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
16447       XtSetArg(args[n], XmNselectColor, ss->red); n++;
16448       bstr = XmStringCreateLocalized((char *)"at end");
16449       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16450       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16451       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16452       XtSetArg(args[n], XmNtopWidget, vdat->at_cursor_button); n++;
16453       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16454       XtSetArg(args[n], XmNlabelString, bstr); n++;
16455       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
16456       XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++;
16457       vdat->at_end_button = make_togglebutton_widget("at-end-button", bform, args, n);
16458       XtAddCallback(vdat->at_end_button, XmNdisarmCallback, view_files_at_end_callback, (XtPointer)vdat);
16459       XmStringFree(bstr);
16460 
16461       n = 0;
16462       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
16463       XtSetArg(args[n], XmNselectColor, ss->red); n++;
16464       bstr = XmStringCreateLocalized((char *)"at beginning");
16465       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16466       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16467       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16468       XtSetArg(args[n], XmNtopWidget, vdat->at_end_button); n++;
16469       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16470       XtSetArg(args[n], XmNlabelString, bstr); n++;
16471       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
16472       XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++;
16473       vdat->at_beginning_button = make_togglebutton_widget("at-beginning-button", bform, args, n);
16474       XtAddCallback(vdat->at_beginning_button, XmNdisarmCallback, view_files_at_beginning_callback, (XtPointer)vdat);
16475       XmStringFree(bstr);
16476 
16477       n = 0;
16478       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
16479       XtSetArg(args[n], XmNselectColor, ss->red); n++;
16480       bstr = XmStringCreateLocalized((char *)"at sample");
16481       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16482       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
16483       XtSetArg(args[n], XmNrightPosition, 50); n++;
16484       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16485       XtSetArg(args[n], XmNtopWidget, vdat->at_beginning_button); n++;
16486       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16487       XtSetArg(args[n], XmNlabelString, bstr); n++;
16488       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
16489       XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++;
16490       vdat->at_sample_button = make_togglebutton_widget("at-sample-button", bform, args, n);
16491       XtAddCallback(vdat->at_sample_button, XmNdisarmCallback, view_files_at_sample_callback, (XtPointer)vdat);
16492       XmStringFree(bstr);
16493 
16494       n = 0;
16495       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
16496       XtSetArg(args[n], XmNborderWidth, 0); n++;
16497       XtSetArg(args[n], XmNshadowThickness, 0); n++;
16498       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16499       XtSetArg(args[n], XmNtopWidget, vdat->at_beginning_button); n++;
16500       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
16501       XtSetArg(args[n], XmNbottomWidget, vdat->at_sample_button); n++;
16502       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
16503       XtSetArg(args[n], XmNleftWidget, vdat->at_sample_button); n++;
16504       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16505       vdat->at_sample_text = make_textfield_widget("at-sample-text", bform, args, n, NOT_ACTIVATABLE, NO_COMPLETER);
16506       XtRemoveCallback(vdat->at_sample_text, XmNlosingFocusCallback, textfield_unfocus_callback, NULL);
16507       XtAddCallback(vdat->at_sample_text, XmNlosingFocusCallback, blue_textfield_unfocus_callback, NULL);
16508       XtAddEventHandler(vdat->at_sample_text, LeaveWindowMask, false, blue_mouse_leave_text_callback, NULL);
16509       XtAddEventHandler(vdat->at_sample_text, EnterWindowMask, false, white_mouse_enter_text_callback, NULL);
16510 
16511       n = 0;
16512       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
16513       XtSetArg(args[n], XmNselectColor, ss->red); n++;
16514       bstr = XmStringCreateLocalized((char *)"at mark");
16515       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16516       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
16517       XtSetArg(args[n], XmNrightPosition, 50); n++;
16518       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16519       XtSetArg(args[n], XmNtopWidget, vdat->at_sample_button); n++;
16520       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
16521       XtSetArg(args[n], XmNlabelString, bstr); n++;
16522       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
16523       XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++;
16524       vdat->at_mark_button = make_togglebutton_widget("at-mark-button", bform, args, n);
16525       XtAddCallback(vdat->at_mark_button, XmNdisarmCallback, view_files_at_mark_callback, (XtPointer)vdat);
16526       XmStringFree(bstr);
16527 
16528       n = 0;
16529       XtSetArg(args[n], XmNbackground, ss->lighter_blue); n++;
16530       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16531       XtSetArg(args[n], XmNtopWidget, vdat->at_sample_text); n++;
16532       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
16533       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
16534       XtSetArg(args[n], XmNleftWidget, vdat->at_mark_button); n++;
16535       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16536       XtSetArg(args[n], XmNborderWidth, 0); n++;
16537       XtSetArg(args[n], XmNshadowThickness, 0); n++;
16538       vdat->at_mark_text = make_textfield_widget("at-mark-text", bform, args, n, NOT_ACTIVATABLE, NO_COMPLETER);
16539       XtRemoveCallback(vdat->at_mark_text, XmNlosingFocusCallback, textfield_unfocus_callback, NULL);
16540       XtAddCallback(vdat->at_mark_text, XmNlosingFocusCallback, blue_textfield_unfocus_callback, NULL);
16541       XtAddEventHandler(vdat->at_mark_text, LeaveWindowMask, false, blue_mouse_leave_text_callback, NULL);
16542       XtAddEventHandler(vdat->at_mark_text, EnterWindowMask, false, white_mouse_enter_text_callback, NULL);
16543 
16544 
16545       n = 0;
16546       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16547       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16548       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16549       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16550       XtSetArg(args[n], XmNtopWidget, bframe); n++;
16551 
16552       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16553       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
16554       XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
16555       XtSetArg(args[n], XmNheight, 8); n++;
16556       sep4 = XtCreateManagedWidget("sep4", xmSeparatorWidgetClass, leftform, args, n);
16557 
16558       n = 0;
16559       /* AMP */
16560       s1 = XmStringCreateLocalized((char *)"amp:");
16561       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16562       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
16563       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16564       XtSetArg(args[n], XmNtopWidget, sep4); n++;
16565       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16566       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16567       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
16568       XtSetArg(args[n], XmNlabelString, s1); n++;
16569       /* XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; */
16570       XtSetArg(args[n], XmNrecomputeSize, false); n++;
16571       XtSetArg(args[n], XmNshadowThickness, 0); n++;
16572       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
16573       XtSetArg(args[n], XmNfillOnArm, false); n++;
16574       amp_label = make_pushbutton_widget("amp-label", leftform, args, n);
16575       XtAddCallback(amp_label, XmNactivateCallback, vf_amp_click_callback, (XtPointer)vdat);
16576       XmStringFree(s1);
16577 
16578       n = 0;
16579       s1 = XmStringCreateLocalized((char *)"1.0 ");
16580       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16581       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
16582       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16583       XtSetArg(args[n], XmNtopWidget, sep4); n++;
16584       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16585       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
16586       XtSetArg(args[n], XmNleftWidget, amp_label); n++;
16587       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
16588       /* XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; */
16589       XtSetArg(args[n], XmNrecomputeSize, false); n++;
16590       XtSetArg(args[n], XmNlabelString, s1); n++;
16591       /* XtSetArg(args[n], XmNmarginRight, 3); n++; */
16592       vdat->amp_number = XtCreateManagedWidget("amp-number", xmLabelWidgetClass, leftform, args, n);
16593       XmStringFree(s1);
16594 
16595       n = 0;
16596       XtSetArg(args[n], XmNbackground, ss->position_color); n++;
16597       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16598       XtSetArg(args[n], XmNtopWidget, sep4); n++;
16599       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16600       XtSetArg(args[n], XmNheight, 16); n++;
16601       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
16602       XtSetArg(args[n], XmNleftWidget, vdat->amp_number); n++;
16603       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16604       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
16605       XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++;
16606       XtSetArg(args[n], XmNvalue, vf_amp_to_scroll(1.0)); n++;
16607       XtSetArg(args[n], XmNvalueChangedCallback, n2 = make_callback_list(vf_amp_valuechanged_callback, (XtPointer)vdat)); n++;
16608       XtSetArg(args[n], XmNdragCallback, n3 = make_callback_list(vf_amp_drag_callback, (XtPointer)vdat)); n++;
16609       vdat->amp_scrollbar = XtCreateManagedWidget("amp-scroll", xmScrollBarWidgetClass, leftform, args, n);
16610 
16611       n = 0;
16612       /* SPEED */
16613       s1 = XmStringCreateLocalized((char *)"speed:");
16614       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16615       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
16616       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16617       XtSetArg(args[n], XmNtopWidget, amp_label); n++;
16618       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16619       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16620       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
16621       XtSetArg(args[n], XmNlabelString, s1); n++;
16622       /* XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;  */
16623       XtSetArg(args[n], XmNrecomputeSize, false); n++;
16624       XtSetArg(args[n], XmNshadowThickness, 0); n++;
16625       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
16626       XtSetArg(args[n], XmNfillOnArm, false); n++;
16627       speed_label = make_pushbutton_widget("speed-label", leftform, args, n);
16628       XtAddCallback(speed_label, XmNactivateCallback, vf_speed_click_callback, (XtPointer)vdat);
16629       XmStringFree(s1);
16630 
16631       n = 0;
16632       s1 = initial_speed_label(speed_control_style(ss));
16633       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16634       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
16635       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
16636       XtSetArg(args[n], XmNtopWidget, speed_label); n++;
16637       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16638       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
16639       XtSetArg(args[n], XmNleftWidget, speed_label); n++;
16640       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
16641       XtSetArg(args[n], XmNlabelString, s1); n++;
16642       /* XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++; */
16643       XtSetArg(args[n], XmNrecomputeSize, false); n++;
16644       /* XtSetArg(args[n], XmNmarginRight, 3); n++; */
16645       XtSetArg(args[n], XmNshadowThickness, 0); n++;
16646       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
16647       XtSetArg(args[n], XmNfillOnArm, false); n++;
16648       vdat->speed_number = make_pushbutton_widget("speed-number", leftform, args, n);
16649       XtAddCallback(vdat->speed_number, XmNactivateCallback, vf_speed_label_click_callback, (XtPointer)vdat);
16650       XmStringFree(s1);
16651 
16652       n = 0;
16653       XtSetArg(args[n], XmNbackground, ss->position_color); n++;
16654       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
16655       XtSetArg(args[n], XmNtopWidget, vdat->speed_number); n++;
16656       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16657       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
16658       XtSetArg(args[n], XmNleftWidget, vdat->speed_number); n++;
16659       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16660       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
16661       XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++;
16662       XtSetArg(args[n], XmNvalue, vf_speed_to_scroll(speed_control_min(ss), 1.0, speed_control_max(ss))); n++;
16663       XtSetArg(args[n], XmNheight, 16); n++;
16664       XtSetArg(args[n], XmNvalueChangedCallback, n4 = make_callback_list(vf_speed_valuechanged_callback, (XtPointer)vdat)); n++;
16665       XtSetArg(args[n], XmNdragCallback, n1 = make_callback_list(vf_speed_drag_callback, (XtPointer)vdat)); n++;
16666       vdat->speed_scrollbar = XtCreateManagedWidget("speed-scroll", xmScrollBarWidgetClass, leftform, args, n);
16667 
16668 
16669       /* separator before envelope */
16670       n = 0;
16671       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16672       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16673       XtSetArg(args[n], XmNtopWidget, speed_label); n++;
16674       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16675       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16676       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16677       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
16678       XtSetArg(args[n], XmNheight, 8); n++;
16679       XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
16680       sep7 = XtCreateManagedWidget("dialog-sep1", xmSeparatorWidgetClass, leftform, args, n);
16681 
16682 
16683       /* amp env */
16684       n = 0;
16685       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16686       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16687       XtSetArg(args[n], XmNtopWidget, sep7); n++;
16688       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
16689       XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
16690       XtSetArg(args[n], XmNleftPosition, 4); n++;
16691       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
16692       XtSetArg(args[n], XmNrightPosition, 98); n++;
16693       XtSetArg(args[n], XmNheight, 100); n++;
16694       XtSetArg(args[n], XmNallowResize, true); n++;
16695       XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++;
16696       XtSetArg(args[n], XmNshadowThickness, 4); n++;
16697       env_frame = XtCreateManagedWidget("amp-env-frame", xmFrameWidgetClass, leftform, args, n);
16698 
16699       n = 0;
16700       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
16701       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
16702       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
16703       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16704       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16705       XtSetArg(args[n], XmNallowResize, true); n++;
16706       XtSetArg(args[n], XmNheight, 100); n++;
16707       vdat->env_drawer = XtCreateManagedWidget("amp-env-window", xmDrawingAreaWidgetClass, env_frame, args, n);
16708 
16709       /* right side */
16710       n = 0;
16711       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16712       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16713       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16714       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
16715       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
16716       viewform = XtCreateManagedWidget("viewform", xmFormWidgetClass, mainform, args, n);
16717 
16718       /* Add dir/file text entry at bottom */
16719       n = 0;
16720       s1 = XmStringCreateLocalized((char *)"add:");
16721       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16722       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
16723       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
16724       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
16725       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16726       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
16727       XtSetArg(args[n], XmNlabelString, s1); n++;
16728       XtSetArg(args[n], XmNshadowThickness, 0); n++;
16729       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
16730       add_label = XtCreateManagedWidget("add", xmLabelWidgetClass, viewform, args, n);
16731       XmStringFree(s1);
16732 
16733       n = 0;
16734       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16735       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
16736       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
16737       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
16738       XtSetArg(args[n], XmNleftWidget, add_label); n++;
16739       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16740       vdat->add_text = make_textfield_widget("add-text", viewform, args, n, ACTIVATABLE, add_completer_func(filename_completer, NULL));
16741       XtAddCallback(vdat->add_text, XmNactivateCallback, view_files_add_files, (XtPointer)vdat);
16742 
16743       n = 0;
16744       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16745       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16746       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16747       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
16748       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
16749       XtSetArg(args[n], XmNbottomWidget, vdat->add_text); n++;
16750       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
16751       XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
16752       XtSetArg(args[n], XmNheight, 4); n++;
16753       sep3 = XtCreateManagedWidget("sep3", xmSeparatorWidgetClass, viewform, args, n);
16754 
16755       n = 0;
16756       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
16757       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16758       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16759       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
16760       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16761       XtSetArg(args[n], XmNalignment, XmALIGNMENT_CENTER); n++;
16762       rlw = XtCreateManagedWidget("files", xmLabelWidgetClass, viewform, args, n);
16763 
16764       n = 0;
16765       XtSetArg(args[n], XmNbackground, ss->white); n++;
16766       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
16767       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16768       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16769       XtSetArg(args[n], XmNtopWidget, rlw); n++;
16770       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16771       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
16772       XtSetArg(args[n], XmNseparatorType, XmDOUBLE_LINE); n++;
16773       sep1 = XtCreateManagedWidget("sep1", xmSeparatorWidgetClass, viewform, args, n);
16774 
16775 #if WITH_AUDIO
16776       n = 0;
16777       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16778       XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
16779       XtSetArg(args[n], XmNleftPosition, 5); n++;
16780       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
16781       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16782       XtSetArg(args[n], XmNtopWidget, sep1); n++;
16783       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16784       plw = XtCreateManagedWidget("play", xmLabelWidgetClass, viewform, args, n);
16785 #endif
16786 
16787       n = 0;
16788       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16789       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
16790       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16791       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
16792       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16793       XtSetArg(args[n], XmNtopWidget, sep1); n++;
16794       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
16795       XtSetArg(args[n], XmNshadowThickness, 0); n++;
16796       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
16797       XtSetArg(args[n], XmNmarginHeight, 0); n++;
16798       sbar = XmCreateMenuBar(viewform, (char *)"menuBar", args, n);
16799 
16800       n = 0;
16801       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16802       vdat->smenu = XmCreatePulldownMenu(sbar, (char *)"sort-menu", args, n);
16803 
16804       n = 0;
16805       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16806       XtSetArg(args[n], XmNsubMenuId, vdat->smenu); n++;
16807       XtSetArg(args[n], XmNshadowThickness, 0); n++;
16808       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
16809       XtSetArg(args[n], XmNmarginHeight, 1); n++;
16810       XtCreateManagedWidget("sort", xmCascadeButtonWidgetClass, sbar, args, n);
16811 
16812       n = 0;
16813       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
16814       vdat->a_to_z =        XtCreateManagedWidget("a..z",       xmPushButtonWidgetClass, vdat->smenu, args, n);
16815       vdat->z_to_a =        XtCreateManagedWidget("z..a",       xmPushButtonWidgetClass, vdat->smenu, args, n);
16816       vdat->new_to_old =    XtCreateManagedWidget("new..old",   xmPushButtonWidgetClass, vdat->smenu, args, n);
16817       vdat->old_to_new =    XtCreateManagedWidget("old..new",   xmPushButtonWidgetClass, vdat->smenu, args, n);
16818       vdat->small_to_big =  XtCreateManagedWidget("small..big", xmPushButtonWidgetClass, vdat->smenu, args, n);
16819       vdat->big_to_small =  XtCreateManagedWidget("big..small", xmPushButtonWidgetClass, vdat->smenu, args, n);
16820 
16821       vdat->sort_items_size = 4;
16822       vdat->sort_items = (Widget *)calloc(vdat->sort_items_size, sizeof(Widget));
16823       for (i = 0; i < vdat->sort_items_size; i++)
16824 	vdat->sort_items[i] = XtCreateWidget("unused", xmPushButtonWidgetClass, vdat->smenu, args, n);
16825 
16826       XtManageChild(sbar);
16827 
16828       n = 0;
16829       XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
16830       XtSetArg(args[n], XmNleftPosition, 5); n++;
16831       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
16832 #if WITH_AUDIO
16833       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16834       XtSetArg(args[n], XmNtopWidget, plw); n++;
16835 #else
16836       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
16837       XtSetArg(args[n], XmNtopWidget, sep1); n++;
16838 #endif
16839       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
16840       XtSetArg(args[n], XmNbottomWidget, sep3); n++;
16841       XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); n++;
16842       XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); n++;
16843       vdat->file_list = XmCreateScrolledWindow(viewform, (char *)"file_list", args, n);
16844 
16845       n = attach_all_sides(args, 0);
16846       vdat->file_list_holder = XtCreateManagedWidget("file_list_holder", xmRowColumnWidgetClass, vdat->file_list, args, n);
16847       XtVaSetValues(vdat->file_list,
16848 		    XmNworkWindow, vdat->file_list_holder,
16849 		    NULL);
16850       add_drag_and_drop(vdat->file_list, view_files_drop_watcher, view_files_drag_watcher, (void *)vdat);
16851 
16852       if (managed) view_files_display_list(vdat);
16853 
16854       XtAddCallback(vdat->a_to_z,       XmNactivateCallback, sort_view_files_a_to_z,       (XtPointer)vdat);
16855       XtAddCallback(vdat->z_to_a,       XmNactivateCallback, sort_view_files_z_to_a,       (XtPointer)vdat);
16856       XtAddCallback(vdat->new_to_old,   XmNactivateCallback, sort_view_files_new_to_old,   (XtPointer)vdat);
16857       XtAddCallback(vdat->old_to_new,   XmNactivateCallback, sort_view_files_old_to_new,   (XtPointer)vdat);
16858       XtAddCallback(vdat->small_to_big, XmNactivateCallback, sort_view_files_small_to_big, (XtPointer)vdat);
16859       XtAddCallback(vdat->big_to_small, XmNactivateCallback, sort_view_files_big_to_small, (XtPointer)vdat);
16860       vf_reflect_sort_choice_in_menu(vdat);
16861 
16862       {
16863 	int i;
16864 	for (i = 0; i < vdat->sort_items_size; i++)
16865 	  XtAddCallback(vdat->sort_items[i], XmNactivateCallback, sort_view_files_xen, (XtPointer)vdat);
16866       }
16867 
16868       map_over_children(vdat->file_list, set_main_color_of_widget);
16869       set_dialog_widget(VIEW_FILES_DIALOG, vdat->dialog);
16870 
16871       if (managed)
16872 	XtManageChild(vdat->dialog);
16873 
16874       XtAddCallback(vdat->env_drawer, XmNresizeCallback, vf_amp_env_resize, (XtPointer)vdat);
16875       XtAddCallback(vdat->env_drawer, XmNexposeCallback, vf_amp_env_resize, (XtPointer)vdat);
16876 
16877       vdat->spf = new_env_editor(); /* one global amp env */
16878 
16879       XtAddEventHandler(vdat->env_drawer, ButtonPressMask, false, vf_drawer_button_press, (XtPointer)vdat);
16880       XtAddEventHandler(vdat->env_drawer, ButtonMotionMask, false, vf_drawer_button_motion, (XtPointer)vdat);
16881       XtAddEventHandler(vdat->env_drawer, ButtonReleaseMask, false, vf_drawer_button_release, (XtPointer)vdat);
16882 
16883       free(n1);
16884       free(n2);
16885       free(n3);
16886       free(n4);
16887 
16888       vf_mix_insert_buttons_set_sensitive(vdat, false);
16889     }
16890   else
16891     {
16892       if (managed)
16893 	{
16894 	  if (!XtIsManaged(vdat->dialog))
16895 	    XtManageChild(vdat->dialog);
16896 	  raise_dialog(vdat->dialog);
16897 	  view_files_display_list(vdat);
16898 	}
16899     }
16900   if (managed)
16901     {
16902       vf_amp_env_resize(vdat->env_drawer, (XtPointer)vdat, NULL);
16903       view_files_reflect_sort_items();
16904     }
16905   return(vdat->dialog);
16906 }
16907 
16908 
16909 /* -------- view-files variables -------- */
16910 
g_view_files_dialog(Xen managed,Xen make_new)16911 static Xen g_view_files_dialog(Xen managed, Xen make_new)
16912 {
16913   #define H_view_files_dialog "(" S_view_files_dialog " :optional managed create-new-dialog): start the View Files dialog"
16914   Xen_check_type(Xen_is_boolean_or_unbound(managed), managed, 1, S_view_files_dialog, "a boolean");
16915   return(Xen_wrap_widget(make_view_files_dialog(Xen_boolean_to_C_bool(managed), Xen_is_true(make_new))));
16916 }
16917 
16918 
g_add_directory_to_view_files_list(Xen directory,Xen dialog)16919 static Xen g_add_directory_to_view_files_list(Xen directory, Xen dialog)
16920 {
16921   #define H_add_directory_to_view_files_list "(" S_add_directory_to_view_files_list " dir :optional w): adds any sound files in 'dir' to the View:Files dialog"
16922 
16923   Xen_check_type(Xen_is_string(directory), directory, 1, S_add_directory_to_view_files_list, "a string");
16924   Xen_check_type(Xen_is_widget(dialog) || !Xen_is_bound(dialog), dialog, 2, S_add_directory_to_view_files_list, "a view-files dialog widget");
16925 
16926   if (!Xen_is_bound(dialog))
16927     view_files_add_directory(NULL_WIDGET, Xen_string_to_C_string(directory));
16928   else view_files_add_directory((widget_t)(Xen_unwrap_widget(dialog)), Xen_string_to_C_string(directory));
16929   return(directory);
16930 }
16931 
16932 
g_add_file_to_view_files_list(Xen file,Xen dialog)16933 static Xen g_add_file_to_view_files_list(Xen file, Xen dialog)
16934 {
16935   #define H_add_file_to_view_files_list "(" S_add_file_to_view_files_list " file :optional w): adds file to the View:Files dialog's list"
16936   char *name = NULL;
16937 
16938   Xen_check_type(Xen_is_string(file), file, 1, S_add_file_to_view_files_list, "a string");
16939   Xen_check_type(Xen_is_widget(dialog) || !Xen_is_bound(dialog), dialog, 2, S_add_file_to_view_files_list, "a view-files dialog widget");
16940 
16941   name = mus_expand_filename(Xen_string_to_C_string(file));
16942   if (mus_file_probe(name))
16943     {
16944       if (!Xen_is_bound(dialog))
16945 	view_files_add_file(NULL_WIDGET, name);
16946       else view_files_add_file((widget_t)(Xen_unwrap_widget(dialog)), name);
16947     }
16948   if (name) free(name);
16949   return(file);
16950 }
16951 
16952 
g_view_files_sort(Xen dialog)16953 static Xen g_view_files_sort(Xen dialog)
16954 {
16955   #define H_view_files_sort "(" S_view_files_sort " :optional dialog): sort choice in View:files dialog."
16956   if (Xen_is_bound(dialog))
16957     {
16958       Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_view_files_sort, "a view-files dialog widget");
16959       return(C_int_to_Xen_integer(view_files_local_sort((widget_t)(Xen_unwrap_widget(dialog)))));
16960     }
16961   return(C_int_to_Xen_integer(view_files_sort(ss)));
16962 }
16963 
16964 
g_set_view_files_sort(Xen dialog,Xen val)16965 static Xen g_set_view_files_sort(Xen dialog, Xen val)
16966 {
16967   int choice;
16968   Xen sort_choice;
16969 
16970   if (Xen_is_bound(val)) sort_choice = val; else sort_choice = dialog;
16971   Xen_check_type(Xen_is_integer(sort_choice), sort_choice, 1, S_set S_view_files_sort, "an integer");
16972 
16973   choice = Xen_integer_to_C_int(sort_choice);
16974   if ((choice < 0) ||
16975       (choice >= (ss->file_sorters_size + SORT_XEN)))
16976     Xen_out_of_range_error(S_set S_view_files_sort, 2, sort_choice, "must be a valid file-sorter index");
16977 
16978   if (Xen_is_bound(val))
16979     {
16980       widget_t w;
16981       Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_set S_view_files_sort, "a view-files dialog widget");
16982       w = (widget_t)(Xen_unwrap_widget(dialog));
16983       view_files_set_local_sort(w, choice);
16984       return(C_int_to_Xen_integer((int)view_files_sort(ss)));
16985     }
16986   /* else set global (default) sort choice */
16987   set_view_files_sort(choice);
16988   return(C_int_to_Xen_integer((int)view_files_sort(ss)));
16989 }
16990 
16991 
g_view_files_amp(Xen dialog)16992 static Xen g_view_files_amp(Xen dialog)
16993 {
16994   #define H_view_files_amp "(" S_view_files_amp " dialog): amp setting in the given View:Files dialog"
16995   Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_view_files_amp, "a view-files dialog widget");
16996   return(C_double_to_Xen_real(view_files_amp((widget_t)(Xen_unwrap_widget(dialog)))));
16997 }
16998 
16999 
g_view_files_set_amp(Xen dialog,Xen amp)17000 static Xen g_view_files_set_amp(Xen dialog, Xen amp)
17001 {
17002   Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_set S_view_files_amp, "a view-files dialog widget");
17003   Xen_check_type(Xen_is_number(amp), amp, 2, S_set S_view_files_amp, "a number");
17004   view_files_set_amp((widget_t)(Xen_unwrap_widget(dialog)), Xen_real_to_C_double(amp));
17005   return(amp);
17006 }
17007 
17008 
g_view_files_speed(Xen dialog)17009 static Xen g_view_files_speed(Xen dialog)
17010 {
17011   #define H_view_files_speed "(" S_view_files_speed " dialog): speed setting in the given View:Files dialog"
17012   Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_view_files_speed, "a view-files dialog widget");
17013   return(C_double_to_Xen_real(view_files_speed((widget_t)(Xen_unwrap_widget(dialog)))));
17014 }
17015 
17016 
g_view_files_set_speed(Xen dialog,Xen speed)17017 static Xen g_view_files_set_speed(Xen dialog, Xen speed)
17018 {
17019   Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_set S_view_files_speed, "a view-files dialog widget");
17020   Xen_check_type(Xen_is_number(speed), speed, 2, S_set S_view_files_speed, "a number");
17021   view_files_set_speed((widget_t)(Xen_unwrap_widget(dialog)), Xen_real_to_C_double(speed));
17022   return(speed);
17023 }
17024 
17025 
g_view_files_amp_env(Xen dialog)17026 static Xen g_view_files_amp_env(Xen dialog)
17027 {
17028   #define H_view_files_amp_env "(" S_view_files_amp_env " dialog): amp env breakpoints in the given View:Files dialog"
17029   Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_view_files_amp_env, "a view-files dialog widget");
17030   return(env_to_xen(view_files_amp_env((widget_t)(Xen_unwrap_widget(dialog)))));
17031 }
17032 
17033 
g_view_files_set_amp_env(Xen dialog,Xen amp_env)17034 static Xen g_view_files_set_amp_env(Xen dialog, Xen amp_env)
17035 {
17036   Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_set S_view_files_amp_env, "a view-files dialog widget");
17037   Xen_check_type(Xen_is_list(amp_env), amp_env, 2, S_set S_view_files_amp_env, "an envelope");
17038   view_files_set_amp_env((widget_t)(Xen_unwrap_widget(dialog)), xen_to_env(amp_env));
17039   return(amp_env);
17040 }
17041 
17042 
g_view_files_speed_style(Xen dialog)17043 static Xen g_view_files_speed_style(Xen dialog)
17044 {
17045   #define H_view_files_speed_style "(" S_view_files_speed_style " dialog): speed_style in use in the given View:Files dialog"
17046   Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_view_files_speed_style, "a view-files dialog widget");
17047   return(C_int_to_Xen_integer((int)(view_files_speed_style((widget_t)(Xen_unwrap_widget(dialog))))));
17048 }
17049 
17050 
g_view_files_set_speed_style(Xen dialog,Xen speed_style)17051 static Xen g_view_files_set_speed_style(Xen dialog, Xen speed_style)
17052 {
17053   Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_set S_view_files_speed_style, "a view-files dialog widget");
17054   Xen_check_type(Xen_is_integer(speed_style), speed_style, 2, S_set S_view_files_speed_style, "an int");
17055   view_files_set_speed_style((widget_t)(Xen_unwrap_widget(dialog)), (speed_style_t)(Xen_integer_to_C_int(speed_style)));
17056   return(speed_style);
17057 }
17058 
17059 
g_view_files_selected_files(Xen dialog)17060 static Xen g_view_files_selected_files(Xen dialog)
17061 {
17062   #define H_view_files_selected_files "(" S_view_files_selected_files " dialog): list of files currently selected in the given View:Files dialog"
17063   Xen result = Xen_empty_list;
17064   char **selected_files;
17065   int len = 0;
17066 
17067   Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_view_files_selected_files, "a view-files dialog widget");
17068 
17069   selected_files = view_files_selected_files((widget_t)(Xen_unwrap_widget(dialog)), &len);
17070   if ((selected_files) && (len > 0))
17071     {
17072       int i;
17073       for (i = 0; i < len; i++)
17074 	{
17075 	  result = Xen_cons(C_string_to_Xen_string(selected_files[i]), result);
17076 	  free(selected_files[i]);
17077 	}
17078       free(selected_files);
17079     }
17080   return(result);
17081 }
17082 
17083 
g_view_files_set_selected_files(Xen dialog,Xen files)17084 static Xen g_view_files_set_selected_files(Xen dialog, Xen files)
17085 {
17086   int len;
17087 
17088   Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_set S_view_files_selected_files, "a view-files dialog widget");
17089   Xen_check_type(Xen_is_list(files), files, 2, S_set S_view_files_selected_files, "a list of files or directories");
17090 
17091   len = Xen_list_length(files);
17092   if (len > 0)
17093     {
17094       char **cfiles = NULL;
17095       int i;
17096       for (i = 0; i < len; i++)
17097 	if (!(Xen_is_string(Xen_list_ref(files, i))))
17098 	  {
17099 	    Xen_check_type(false, Xen_list_ref(files, i), i, S_set S_view_files_selected_files, "a filename (string)");
17100 	    return(Xen_false);
17101 	  }
17102       cfiles = (char **)calloc(len, sizeof(char *));
17103       for (i = 0; i < len; i++)
17104 	cfiles[i] = (char *)Xen_string_to_C_string(Xen_list_ref(files, i));
17105       view_files_set_selected_files((widget_t)(Xen_unwrap_widget(dialog)), cfiles, len);
17106       free(cfiles);
17107     }
17108   return(files);
17109 }
17110 
17111 
g_view_files_files(Xen dialog)17112 static Xen g_view_files_files(Xen dialog)
17113 {
17114   #define H_view_files_files "(" S_view_files_files " dialog): list of files currently available in the given View:Files dialog"
17115   Xen result = Xen_empty_list;
17116   char **files;
17117   int i, len = 0;
17118 
17119   Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_view_files_files, "a view-files dialog widget");
17120 
17121   files = view_files_files((widget_t)(Xen_unwrap_widget(dialog)), &len);
17122   if ((files) && (len > 0))
17123     for (i = 0; i < len; i++)
17124       result = Xen_cons(C_string_to_Xen_string(files[i]), result);
17125   return(result);
17126 }
17127 
17128 
g_view_files_set_files(Xen dialog,Xen files)17129 static Xen g_view_files_set_files(Xen dialog, Xen files)
17130 {
17131   int len = 0;
17132   char **cfiles = NULL;
17133 
17134   Xen_check_type(Xen_is_widget(dialog), dialog, 1, S_set S_view_files_files, "a view-files dialog widget");
17135   Xen_check_type(Xen_is_list(files), files, 2, S_set S_view_files_files, "a list of files or directories");
17136 
17137   len = Xen_list_length(files);
17138   if (len > 0)
17139     {
17140       int i;
17141       for (i = 0; i < len; i++)
17142 	if (!(Xen_is_string(Xen_list_ref(files, i))))
17143 	  {
17144 	    Xen_check_type(false, Xen_list_ref(files, i), i, S_set S_view_files_files, "a filename (string)");
17145 	    return(Xen_false);
17146 	  }
17147       cfiles = (char **)calloc(len, sizeof(char *));
17148       for (i = 0; i < len; i++)
17149 	cfiles[i] = (char *)Xen_string_to_C_string(Xen_list_ref(files, i));
17150     }
17151   view_files_set_files((widget_t)(Xen_unwrap_widget(dialog)), cfiles, len);
17152   if (cfiles) free(cfiles);
17153   return(files);
17154 }
17155 
17156 
17157 static Xen view_files_select_hook;
17158 
view_files_run_select_hook(widget_t dialog,const char * selected_file)17159 static void view_files_run_select_hook(widget_t dialog, const char *selected_file)
17160 {
17161   if (Xen_hook_has_list(view_files_select_hook))
17162     run_hook(view_files_select_hook,
17163 	     Xen_list_2(Xen_wrap_widget(dialog),
17164 			C_string_to_Xen_string(selected_file)),
17165 	     S_view_files_select_hook);
17166 }
17167 
17168 /* -------- file-filters and file-sorters -------- */
17169 
17170 #define INITIAL_FILE_SORTERS_SIZE 4
17171 
file_sorter_ok(Xen name,Xen proc,const char * caller)17172 static bool file_sorter_ok(Xen name, Xen proc, const char *caller)
17173 {
17174   char *errmsg;
17175   Xen_check_type(Xen_is_string(name), name, 1, caller, "a string");
17176   Xen_check_type(Xen_is_procedure(proc), proc, 2, caller, "a procedure of 2 args (file1 and file2)");
17177   errmsg = procedure_ok(proc, 2, caller, "file sort", 2);
17178   if (errmsg)
17179     {
17180       Xen errstr;
17181       errstr = C_string_to_Xen_string(errmsg);
17182       free(errmsg);
17183       snd_bad_arity_error(caller, errstr, proc);
17184       return(false);
17185     }
17186   return(true);
17187 }
17188 
17189 
g_add_file_sorter(Xen name,Xen proc)17190 static Xen g_add_file_sorter(Xen name, Xen proc)
17191 {
17192   #define H_add_file_sorter "(" S_add_file_sorter " name proc) -- add proc with identifier name to file sorter list, returns its index"
17193   int choice = -1;
17194   /* type checks are redundant here */
17195 
17196   if (file_sorter_ok(name, proc, S_add_file_sorter))
17197     {
17198       int i, len;
17199       len = ss->file_sorters_size;
17200       for (i = 0; i < len; i++)
17201 	{
17202 	  if (Xen_is_false(Xen_vector_ref(ss->file_sorters, i)))
17203 	    {
17204 	      Xen_vector_set(ss->file_sorters, i, Xen_list_2(name, proc));
17205 	      choice = i;
17206 	      break;
17207 	    }
17208 	}
17209       if (choice == -1)
17210 	{
17211 	  ss->file_sorters_size = len * 2;
17212 	  ss->file_sorters = g_expand_vector(ss->file_sorters, ss->file_sorters_size);
17213 	  Xen_vector_set(ss->file_sorters, len, Xen_list_2(name, proc));
17214 	  choice = len;
17215 	}
17216       view_files_reflect_sort_items();
17217     }
17218   return(C_int_to_Xen_integer(choice + SORT_XEN));
17219 }
17220 
17221 
g_delete_file_sorter(Xen index)17222 static Xen g_delete_file_sorter(Xen index)
17223 {
17224   #define H_delete_file_sorter "(" S_delete_file_sorter " index) -- delete proc with identifier name from file sorter list"
17225   int pos;
17226   Xen_check_type(Xen_is_integer(index), index, 1, S_delete_file_sorter, "a file-sorter index");
17227   pos = Xen_integer_to_C_int(index);
17228   if ((pos >= SORT_XEN) &&
17229       ((pos - SORT_XEN) < ss->file_sorters_size))
17230     Xen_vector_set(ss->file_sorters, pos - SORT_XEN, Xen_false);
17231   view_files_reflect_sort_items();
17232   return(index);
17233 }
17234 
17235 
17236 
17237 /* -------- drop watcher lists -------- */
17238 
17239 /* the rigamarole for dealing with a drop is so messed up that I think it's
17240  *   worth the trouble of setting up a separate callback list -- hence the
17241  *   drop watchers
17242  */
17243 
17244 typedef struct {
17245   void (*drop_watcher)(Widget w, const char *message, Position x, Position y, void *data);
17246   void (*drag_watcher)(Widget w, const char *message, Position x, Position y, drag_style_t dtype, void *data);
17247   Widget caller;
17248   void *context;
17249 } drop_watcher_t;
17250 
17251 static drop_watcher_t **drop_watchers = NULL;
17252 static int drop_watchers_size = 0;
17253 
17254 #define DROP_WATCHER_SIZE_INCREMENT 2
17255 
17256 
add_drop_watcher(Widget w,void (* drop_watcher)(Widget w,const char * message,Position x,Position y,void * data),void (* drag_watcher)(Widget w,const char * message,Position x,Position y,drag_style_t dtype,void * data),void * context)17257 static int add_drop_watcher(Widget w,
17258 			    void (*drop_watcher)(Widget w, const char *message, Position x, Position y, void *data),
17259 			    void (*drag_watcher)(Widget w, const char *message, Position x, Position y, drag_style_t dtype, void *data),
17260 			    void *context)
17261 {
17262   int loc = -1;
17263   if (!(drop_watchers))
17264     {
17265       loc = 0;
17266       drop_watchers_size = DROP_WATCHER_SIZE_INCREMENT;
17267       drop_watchers = (drop_watcher_t **)calloc(drop_watchers_size, sizeof(drop_watcher_t *));
17268     }
17269   else
17270     {
17271       int i;
17272       for (i = 0; i < drop_watchers_size; i++)
17273 	if (!(drop_watchers[i]))
17274 	  {
17275 	    loc = i;
17276 	    break;
17277 	  }
17278       if (loc == -1)
17279 	{
17280 	  loc = drop_watchers_size;
17281 	  drop_watchers_size += DROP_WATCHER_SIZE_INCREMENT;
17282 	  drop_watchers = (drop_watcher_t **)realloc(drop_watchers, drop_watchers_size * sizeof(drop_watcher_t *));
17283 	  for (i = loc; i < drop_watchers_size; i++) drop_watchers[i] = NULL;
17284 	}
17285     }
17286   drop_watchers[loc] = (drop_watcher_t *)calloc(1, sizeof(drop_watcher_t));
17287   drop_watchers[loc]->drop_watcher = drop_watcher;
17288   drop_watchers[loc]->drag_watcher = drag_watcher;
17289   drop_watchers[loc]->context = context;
17290   drop_watchers[loc]->caller = w;
17291   return(loc);
17292 }
17293 
17294 
17295 #if 0
17296 static bool remove_drop_watcher(int loc)
17297 {
17298   if ((drop_watchers) &&
17299       (loc < drop_watchers_size) &&
17300       (loc >= 0) &&
17301       (drop_watchers[loc]))
17302     {
17303       free(drop_watchers[loc]);
17304       drop_watchers[loc] = NULL;
17305       return(true);
17306     }
17307   return(false);
17308 }
17309 #endif
17310 
17311 
find_drop_watcher(Widget caller)17312 static drop_watcher_t *find_drop_watcher(Widget caller)
17313 {
17314   if (drop_watchers)
17315     {
17316       int i;
17317       for (i = 0; i < drop_watchers_size; i++)
17318 	{
17319 	  if (drop_watchers[i])
17320 	    {
17321 	      drop_watcher_t *d;
17322 	      d = drop_watchers[i];
17323 	      if (d->caller == caller)
17324 		return(d);
17325 	    }
17326 	}
17327     }
17328   return(NULL);
17329 }
17330 
17331 
17332 /* can't move axes if icon dragged to end of graph because the entire system freezes! */
17333 
17334 static Atom FILE_NAME;               /* Sun uses this, SGI uses STRING */
17335 static Atom COMPOUND_TEXT;           /* various Motif widgets use this and the next */
17336 static Atom _MOTIF_COMPOUND_STRING;
17337 static Atom text_plain;
17338 static Atom uri_list;                /* rox uses this -- looks just like text/plain to me */
17339 static Atom TEXT;                    /* ditto */
17340 
17341 static Xen drop_hook;
17342 
17343 
atom_to_string(Atom type,XtPointer value,unsigned long length)17344 static char *atom_to_string(Atom type, XtPointer value, unsigned long length)
17345 {
17346   char *str = NULL;
17347   if ((type == XA_STRING) || (type == FILE_NAME) || (type == text_plain) || (type == uri_list) || (type == TEXT))
17348     {
17349       unsigned long i;
17350       str = (char *)calloc(length + 1, sizeof(char));
17351       for (i = 0; i < length; i++)
17352 	str[i] = ((char *)value)[i];
17353     }
17354   else
17355     {
17356       if ((type == COMPOUND_TEXT) || (type == _MOTIF_COMPOUND_STRING))
17357 	{
17358 	  char *temp;
17359 	  XmString cvt, tmp;
17360 	  XmParseTable parser = (XmParseTable)XtCalloc(1, sizeof(XmParseMapping));
17361 	  int n;
17362 	  Arg args[12];
17363 
17364 	  /* create parse table to catch separator in XmString and insert "\n" in output */
17365 	  /*   multiple file names are passed this way in Motif */
17366 	  tmp = XmStringSeparatorCreate();
17367 	  n = 0;
17368 	  XtSetArg(args[n], XmNincludeStatus, XmINSERT); n++;
17369 	  XtSetArg(args[n], XmNsubstitute, tmp); n++;
17370 	  XtSetArg(args[n], XmNpattern, "\n"); n++;
17371 	  parser[0] = XmParseMappingCreate(args, n);
17372 
17373 	  if (type == _MOTIF_COMPOUND_STRING)
17374 	    cvt = XmCvtByteStreamToXmString((unsigned char *)value);
17375 	  else cvt = XmCvtCTToXmString((char *)value);
17376 	  temp = (char *)XmStringUnparse(cvt, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, parser, 1, XmOUTPUT_ALL);
17377 
17378 	  XmParseTableFree(parser, 1);
17379 	  XmStringFree(cvt);
17380 	  str = mus_strdup(temp);
17381 	  XtFree(temp);
17382 	}
17383     }
17384   return(str);
17385 }
17386 
17387 
17388 static Position mx, my;
17389 
massage_selection(Widget w,XtPointer context,Atom * selection,Atom * type,XtPointer value,unsigned long * length,int * format)17390 static void massage_selection(Widget w, XtPointer context, Atom *selection, Atom *type, XtPointer value, unsigned long *length, int *format)
17391 {
17392   char *str = NULL;
17393   str = atom_to_string(*type, value, *length);
17394   /* str can contain more than one name (separated by cr) */
17395   if (str)
17396     {
17397       if ((!(Xen_hook_has_list(drop_hook))) ||
17398 	  (!(Xen_is_true(run_or_hook(drop_hook,
17399 				    Xen_list_1(C_string_to_Xen_string(str)),
17400 				    S_drop_hook)))))
17401 	{
17402 	  Widget caller; /* "w" above is the transfer control widget, not the drop-receiver */
17403 	  drop_watcher_t *d;
17404 	  caller = (Widget)((XmDropTransferEntry)context)->client_data;
17405 	  d = find_drop_watcher(caller);
17406 	  if (d)
17407 	    {
17408 	      /* loop through possible list of filenames, calling watcher on each */
17409 	      char *filename;
17410 	      int len = 0, i, j = 0;
17411 	      len = mus_strlen(str);
17412 	      filename = (char *)calloc(len, sizeof(char));
17413 	      for (i = 0; i < len; i++)
17414 		{
17415 		  if ((str[i] == '\n') || (str[i] == '\r')) /* apparently the only space chars here are \n and \r? */
17416 		    {
17417 		      if (j > 0)
17418 			{
17419 			  filename[j] = '\0';
17420 			  if (strncmp(filename, "file://", 7) == 0)
17421 			    {
17422 			      char *tmp;
17423 			      tmp = (char *)(filename + 7);
17424 			      (*(d->drop_watcher))(caller, (const char *)tmp, mx, my, d->context);
17425 			    }
17426 			  else (*(d->drop_watcher))(caller, (const char *)filename, mx, my, d->context);
17427 			  j = 0;
17428 			}
17429 		      /* else ignore extra white space chars */
17430 		    }
17431 		  else
17432 		    {
17433 		      filename[j++] = str[i];
17434 		    }
17435 		}
17436 	      free(filename);
17437 	    }
17438 	}
17439       free(str);
17440     }
17441 }
17442 
17443 
handle_drop(Widget w,XtPointer context,XtPointer info)17444 static void handle_drop(Widget w, XtPointer context, XtPointer info)
17445 {
17446   XmDropProcCallbackStruct *cb = (XmDropProcCallbackStruct *)info;
17447   Arg args[12];
17448   int n, i, num_targets, k;
17449   Atom *targets;
17450   XmDropTransferEntryRec entries[2];
17451 
17452   if ((cb->dropAction != XmDROP) ||
17453       ((cb->operation != XmDROP_COPY) &&
17454        (cb->operation != XmDROP_LINK)))
17455     {
17456       cb->dropSiteStatus = XmINVALID_DROP_SITE;
17457       return;
17458     }
17459 
17460   k = -1;
17461   XtVaGetValues(cb->dragContext,
17462 		XmNexportTargets, &targets,
17463 		XmNnumExportTargets, &num_targets,
17464 		NULL);
17465 
17466   for (i = 0; i < num_targets; i++)
17467     if ((targets[i] == XA_STRING) ||
17468 	(targets[i] == FILE_NAME) ||
17469 	(targets[i] == COMPOUND_TEXT) ||
17470 	(targets[i] == _MOTIF_COMPOUND_STRING) ||
17471 	(targets[i] == TEXT) ||
17472 	(targets[i] == text_plain) ||
17473 	(targets[i] == uri_list))
17474       {
17475 	k = i;
17476 	break;
17477       }
17478   if (k == -1)
17479     {
17480 #if 0
17481       fprintf(stderr, "failed drop attempt:\n");
17482       for (i = 0; i < num_targets; i++)
17483 	fprintf(stderr, "  target %d = %s\n", i,
17484 		XGetAtomName(main_display(ss),
17485 			     targets[i]));
17486 #endif
17487       cb->dropSiteStatus = XmINVALID_DROP_SITE;
17488       cb->operation = XmDROP_NOOP;
17489       n = 0;
17490       XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
17491       XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
17492       XmDropTransferStart(cb->dragContext, args, n);
17493       return;
17494     }
17495 
17496   mx = cb->x;
17497   my = cb->y;
17498   entries[0].target = targets[k];
17499   entries[0].client_data = (XtPointer)w;
17500   n = 0;
17501   XtSetArg(args[n], XmNdropTransfers, entries); n++;
17502   XtSetArg(args[n], XmNnumDropTransfers, 1); n++;
17503   XtSetArg(args[n], XmNtransferProc, massage_selection); n++;
17504   /* cb->operation = XmDROP_COPY; */
17505 
17506   XmDropTransferStart(cb->dragContext, args, n);
17507 }
17508 
17509 
handle_drag(Widget w,XtPointer context,XtPointer info)17510 static void handle_drag(Widget w, XtPointer context, XtPointer info)
17511 {
17512   XmDragProcCallbackStruct *cb = (XmDragProcCallbackStruct *)info;
17513   drop_watcher_t *d;
17514   d = find_drop_watcher(w);
17515   if ((d) && (d->drag_watcher))
17516     {
17517       switch (cb->reason)
17518 	{
17519 	case XmCR_DROP_SITE_MOTION_MESSAGE:
17520 	  (*(d->drag_watcher))(w, NULL, cb->x, cb->y, DRAG_MOTION, d->context);
17521 	  break;
17522 	case XmCR_DROP_SITE_ENTER_MESSAGE:
17523 	  (*(d->drag_watcher))(w, NULL, cb->x, cb->y, DRAG_ENTER, d->context);
17524 	  break;
17525 	case XmCR_DROP_SITE_LEAVE_MESSAGE:
17526 	  (*(d->drag_watcher))(w, NULL, cb->x, cb->y, DRAG_LEAVE, d->context);
17527 	  break;
17528 	}
17529     }
17530 }
17531 
17532 #define NUM_TARGETS 7
add_drag_and_drop(Widget w,void (* drop_watcher)(Widget w,const char * message,Position x,Position y,void * data),void (* drag_watcher)(Widget w,const char * message,Position x,Position y,drag_style_t dtype,void * data),void * context)17533 void add_drag_and_drop(Widget w,
17534 		       void (*drop_watcher)(Widget w, const char *message, Position x, Position y, void *data),
17535 		       void (*drag_watcher)(Widget w, const char *message, Position x, Position y, drag_style_t dtype, void *data),
17536 		       void *context)
17537 {
17538   Display *dpy;
17539   int n;
17540   Atom targets[NUM_TARGETS];
17541   Arg args[12];
17542   dpy = main_display(ss);
17543   targets[0] = XA_STRING;
17544   FILE_NAME = XInternAtom(dpy, "FILE_NAME", false);
17545   targets[1] = FILE_NAME;
17546   COMPOUND_TEXT = XInternAtom(dpy, "COMPOUND_TEXT", false);
17547   targets[2] = COMPOUND_TEXT;
17548   _MOTIF_COMPOUND_STRING = XInternAtom(dpy, "_MOTIF_COMPOUND_STRING", false);
17549   targets[3] = _MOTIF_COMPOUND_STRING;
17550   text_plain = XInternAtom(dpy, "text/plain", false);
17551   targets[4] = text_plain;
17552   TEXT = XInternAtom(dpy, "TEXT", false);
17553   targets[5] = TEXT;
17554   uri_list = XInternAtom(dpy, "text/uri-list", false);
17555   targets[6] = uri_list;
17556   n = 0;
17557   XtSetArg(args[n], XmNdropSiteOperations, XmDROP_COPY | XmDROP_LINK); n++;
17558   XtSetArg(args[n], XmNimportTargets, targets); n++;
17559   XtSetArg(args[n], XmNnumImportTargets, NUM_TARGETS); n++;
17560   XtSetArg(args[n], XmNdropProc, handle_drop); n++;
17561   XtSetArg(args[n], XmNdragProc, handle_drag); n++;
17562   XmDropSiteRegister(w, args, n);
17563   add_drop_watcher(w, drop_watcher, drag_watcher, context);
17564 }
17565 
17566 
17567 
17568 /* -------------------------------------------------------------------------------- */
17569 
17570 
17571 #include "sndlib-strings.h"
17572 
17573 /* preferences dialog; layout design taken from webmail
17574  */
17575 
17576 static Widget preferences_dialog = NULL, load_path_text_widget = NULL;
17577 static bool prefs_unsaved = false;
17578 static char *prefs_saved_filename = NULL;
17579 static char *include_load_path = NULL;
17580 
17581 #define MID_POSITION 50
17582 #define PREFS_COLOR_POSITION 62  /* COLOR_POSITION is slider_choice_t in snd-0.h */
17583 #define FIRST_COLOR_POSITION 6
17584 #define SECOND_COLOR_POSITION 30
17585 #define THIRD_COLOR_POSITION 55
17586 
17587 #define MID_SPACE 16
17588 #define INTER_TOPIC_SPACE 3
17589 #define INTER_VARIABLE_SPACE 2
17590 
17591 #define POWER_WAIT_TIME 100
17592 #define POWER_INITIAL_WAIT_TIME 500
17593 /* "power" is an old-timey name for auto-repeat */
17594 #define ERROR_WAIT_TIME 5000
17595 
17596 #define STARTUP_WIDTH 925
17597 #define STARTUP_HEIGHT 800
17598 
17599 
17600 typedef struct prefs_info {
17601   Widget label, text, arrow_up, arrow_down, arrow_right, error, toggle, scale, toggle2, toggle3;
17602   Widget color, rscl, gscl, bscl, rtxt, gtxt, btxt, list_menu, radio_button;
17603   Widget *radio_buttons;
17604   bool got_error;
17605   timeout_result_t power_id;
17606   const char *var_name, *saved_label;
17607   int num_buttons;
17608   mus_float_t scale_max;
17609   void (*toggle_func)(struct prefs_info *prf);
17610   void (*toggle2_func)(struct prefs_info *prf);
17611   void (*scale_func)(struct prefs_info *prf);
17612   void (*arrow_up_func)(struct prefs_info *prf);
17613   void (*arrow_down_func)(struct prefs_info *prf);
17614   void (*text_func)(struct prefs_info *prf);
17615   void (*list_func)(struct prefs_info *prf, char *value);
17616   void (*color_func)(struct prefs_info *prf, double r, double g, double b);
17617   void (*reflect_func)(struct prefs_info *prf);
17618   void (*save_func)(struct prefs_info *prf, FILE *fd);
17619   const char *(*help_func)(struct prefs_info *prf);
17620   void (*clear_func)(struct prefs_info *prf);
17621   void (*revert_func)(struct prefs_info *prf);
17622 } prefs_info;
17623 
17624 
17625 static void prefs_set_dialog_title(const char *filename);
17626 static void reflect_key(prefs_info *prf, const char *key_name);
17627 static void save_key(prefs_info *prf, FILE *fd, char *(*binder)(char *key, bool c, bool m, bool x));
17628 static void key_bind(prefs_info *prf, char *(*binder)(char *key, bool c, bool m, bool x));
17629 static void clear_prefs_dialog_error(void);
17630 static void scale_set_color(prefs_info *prf, color_t pixel);
17631 static color_t rgb_to_color(mus_float_t r, mus_float_t g, mus_float_t b);
17632 static void post_prefs_error(const char *msg, prefs_info *data);
17633 #ifdef __GNUC__
17634   static void va_post_prefs_error(const char *msg, prefs_info *data, ...) __attribute__ ((format (printf, 1, 0)));
17635 #else
17636   static void va_post_prefs_error(const char *msg, prefs_info *data, ...);
17637 #endif
17638 
17639 /* used in snd-prefs */
17640 #define GET_TOGGLE(Toggle)        (XmToggleButtonGetState(Toggle) == XmSET)
17641 #define SET_TOGGLE(Toggle, Value) XmToggleButtonSetState(Toggle, Value, false)
17642 #define GET_TEXT(Text)            XmTextFieldGetString(Text)
17643 #define SET_TEXT(Text, Val)       XmTextFieldSetString(Text, (char *)Val)
17644 #define free_TEXT(Val)            XtFree(Val)
17645 #define SET_SCALE(Value)          XmScaleSetValue(prf->scale, (int)(100 * Value))
17646 #define SET_SENSITIVE(Wid, Val)   XtSetSensitive(Wid, Val)
17647 #define black_text(Prf)           XtVaSetValues(Prf->label, XmNforeground, ss->black, NULL)
17648 #define red_text(Prf)             XtVaSetValues(Prf->label, XmNforeground, ss->red, NULL)
17649 
17650 #define TIMEOUT(Func)             XtAppAddTimeOut(main_app(ss), ERROR_WAIT_TIME, Func, (XtPointer)prf)
17651 
17652 
get_scale_1(Widget scale)17653 static int get_scale_1(Widget scale)
17654 {
17655   int val = 0;
17656   XmScaleGetValue(scale, &val);
17657   return(val);
17658 }
17659 
17660 #define GET_SCALE()               (get_scale_1(prf->scale) * 0.01)
17661 
17662 
set_radio_button(prefs_info * prf,int which)17663 static void set_radio_button(prefs_info *prf, int which)
17664 {
17665   if ((which >= 0) && (which < prf->num_buttons))
17666     {
17667       int i;
17668       for (i = 0; i < prf->num_buttons; i++)
17669 	{
17670 	  if ((prf->radio_buttons[i]) &&
17671 	      (XmIsToggleButton(prf->radio_buttons[i])))
17672 	    XmToggleButtonSetState(prf->radio_buttons[i], (i == which), false);
17673 	}
17674       prf->radio_button = prf->radio_buttons[which];
17675     }
17676 }
17677 
17678 
which_radio_button(prefs_info * prf)17679 static int which_radio_button(prefs_info *prf)
17680 {
17681   intptr_t which = 0;
17682   XtVaGetValues(prf->radio_button, XmNuserData, &which, NULL);
17683   return(which);
17684 }
17685 
17686 
17687 #include "snd-prefs.c"
17688 
17689 static bool prefs_dialog_error_is_posted = false;
17690 
post_prefs_dialog_error(const char * message,void * data)17691 static void post_prefs_dialog_error(const char *message, void *data)
17692 {
17693   XmString title;
17694   title = XmStringCreateLocalized((char *)message);
17695   XtVaSetValues(preferences_dialog,
17696 		XmNmessageString, title,
17697 		NULL);
17698   XmStringFree(title);
17699   prefs_dialog_error_is_posted = (bool)message;
17700 }
17701 
17702 
clear_prefs_dialog_error(void)17703 static void clear_prefs_dialog_error(void)
17704 {
17705   if (prefs_dialog_error_is_posted)
17706     {
17707       prefs_dialog_error_is_posted = false;
17708       post_prefs_dialog_error(NULL, NULL);
17709     }
17710 }
17711 
17712 
prefs_change_callback(Widget w,XtPointer context,XtPointer info)17713 static void prefs_change_callback(Widget w, XtPointer context, XtPointer info)
17714 {
17715   prefs_unsaved = true;
17716   prefs_set_dialog_title(NULL);
17717   clear_prefs_dialog_error();
17718 }
17719 
17720 
17721 /* ---------------- row (main) label widget ---------------- */
17722 
make_row_label(prefs_info * prf,const char * label,Widget box,Widget top_widget)17723 static Widget make_row_label(prefs_info *prf, const char *label, Widget box, Widget top_widget)
17724 {
17725   Widget w;
17726   Arg args[20];
17727   int n;
17728 
17729   n = 0;
17730   XtSetArg(args[n], XmNbackground, ss->white); n++;
17731   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
17732   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
17733   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
17734   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
17735   XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
17736   XtSetArg(args[n], XmNrightPosition, MID_POSITION); n++;
17737   XtSetArg(args[n], XmNalignment, XmALIGNMENT_END); n++;
17738   w = XtCreateManagedWidget(label, xmLabelWidgetClass, box, args, n);
17739   prf->saved_label = label;
17740   return(w);
17741 }
17742 
17743 
17744 /* ---------------- row inner label widget ---------------- */
17745 
make_row_inner_label(prefs_info * prf,const char * label,Widget left_widget,Widget box,Widget top_widget)17746 static Widget make_row_inner_label(prefs_info *prf, const char *label, Widget left_widget, Widget box, Widget top_widget)
17747 {
17748   Widget w;
17749   Arg args[20];
17750   int n;
17751 
17752   n = 0;
17753   XtSetArg(args[n], XmNbackground, ss->white); n++;
17754   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
17755   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
17756   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
17757   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
17758   XtSetArg(args[n], XmNleftWidget, left_widget); n++;
17759   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
17760   w = XtCreateManagedWidget(label, xmLabelWidgetClass, box, args, n);
17761   return(w);
17762 }
17763 
17764 
17765 /* ---------------- row middle separator widget ---------------- */
17766 
make_row_middle_separator(Widget label,Widget box,Widget top_widget)17767 static Widget make_row_middle_separator(Widget label, Widget box, Widget top_widget)
17768 {
17769   Arg args[20];
17770   int n;
17771 
17772   n = 0;
17773   XtSetArg(args[n], XmNbackground, ss->white); n++;
17774   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
17775   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
17776   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
17777   XtSetArg(args[n], XmNbottomWidget, label); n++;
17778   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
17779   XtSetArg(args[n], XmNleftWidget, label); n++;
17780   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
17781   XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
17782   XtSetArg(args[n], XmNwidth, MID_SPACE); n++;
17783   XtSetArg(args[n], XmNseparatorType, XmSHADOW_ETCHED_OUT); n++;
17784   return(XtCreateManagedWidget("sep", xmSeparatorWidgetClass, box, args, n));
17785 }
17786 
17787 
17788 /* ---------------- row inner separator widget ---------------- */
17789 
make_row_inner_separator(int width,Widget left_widget,Widget box,Widget top_widget)17790 static Widget make_row_inner_separator(int width, Widget left_widget, Widget box, Widget top_widget)
17791 {
17792   Arg args[20];
17793   int n;
17794 
17795   n = 0;
17796   XtSetArg(args[n], XmNbackground, ss->white); n++;
17797   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
17798   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
17799   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
17800   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
17801   XtSetArg(args[n], XmNleftWidget, left_widget); n++;
17802   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
17803   XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
17804   XtSetArg(args[n], XmNwidth, width); n++;
17805   XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
17806   return(XtCreateManagedWidget("sep1", xmSeparatorWidgetClass, box, args, n));
17807 }
17808 
17809 
make_row_error(prefs_info * prf,Widget box,Widget left_widget,Widget top_widget)17810 static Widget make_row_error(prefs_info *prf, Widget box, Widget left_widget, Widget top_widget)
17811 {
17812   Arg args[20];
17813   int n;
17814   Widget w;
17815 
17816   n = 0;
17817   XtSetArg(args[n], XmNbackground, ss->white); n++;
17818   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
17819   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
17820   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
17821   XtSetArg(args[n], XmNbottomWidget, left_widget); n++;
17822   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
17823   XtSetArg(args[n], XmNleftWidget, left_widget); n++;
17824   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
17825   XtSetArg(args[n], XmNalignment, XmALIGNMENT_END); n++;
17826   w = XtCreateManagedWidget("", xmLabelWidgetClass, box, args, n);
17827   return(w);
17828 }
17829 
17830 
17831 /* ---------------- row toggle widget ---------------- */
17832 
make_row_toggle_with_label(prefs_info * prf,bool current_value,Widget left_widget,Widget box,Widget top_widget,const char * label)17833 static Widget make_row_toggle_with_label(prefs_info *prf, bool current_value, Widget left_widget, Widget box, Widget top_widget, const char *label)
17834 {
17835   Widget w;
17836   Arg args[20];
17837   int n;
17838 
17839   n = 0;
17840   XtSetArg(args[n], XmNbackground, ss->white); n++;
17841   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
17842   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
17843   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
17844   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
17845   XtSetArg(args[n], XmNleftWidget, left_widget); n++;
17846   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
17847   XtSetArg(args[n], XmNset, (current_value) ? XmSET : XmUNSET); n++;
17848   XtSetArg(args[n], XmNborderWidth, 0); n++;
17849   XtSetArg(args[n], XmNborderColor, ss->white); n++;
17850   XtSetArg(args[n], XmNmarginHeight, 0); n++;
17851   XtSetArg(args[n], XmNindicatorOn, XmINDICATOR_FILL); n++;
17852   XtSetArg(args[n], XmNindicatorSize, 14); n++;
17853   w = XtCreateManagedWidget(label, xmToggleButtonWidgetClass, box, args, n);
17854   return(w);
17855 }
17856 
17857 
make_row_toggle(prefs_info * prf,bool current_value,Widget left_widget,Widget box,Widget top_widget)17858 static Widget make_row_toggle(prefs_info *prf, bool current_value, Widget left_widget, Widget box, Widget top_widget)
17859 {
17860   return(make_row_toggle_with_label(prf, current_value, left_widget, box, top_widget, " "));
17861 }
17862 
17863 
17864 
17865 /* ---------------- row arrows ---------------- */
17866 
remove_arrow_func(Widget w,XtPointer context,XtPointer info)17867 static void remove_arrow_func(Widget w, XtPointer context, XtPointer info)
17868 {
17869   prefs_info *prf = (prefs_info *)context;
17870   if (prf->power_id != 0)
17871     {
17872       XtRemoveTimeOut(prf->power_id);
17873       prf->power_id = 0;
17874     }
17875 }
17876 
17877 
arrow_func_up(XtPointer context,XtIntervalId * id)17878 static void arrow_func_up(XtPointer context, XtIntervalId *id)
17879 {
17880   prefs_info *prf = (prefs_info *)context;
17881   if (XtIsSensitive(prf->arrow_up))
17882     {
17883       if ((prf) && (prf->arrow_up_func))
17884 	{
17885 	  (*(prf->arrow_up_func))(prf);
17886 	  prf->power_id = XtAppAddTimeOut(main_app(ss),
17887 					  POWER_WAIT_TIME,
17888 					  arrow_func_up,
17889 					  (XtPointer)prf);
17890 	}
17891       else prf->power_id = 0;
17892     }
17893 }
17894 
17895 
arrow_func_down(XtPointer context,XtIntervalId * id)17896 static void arrow_func_down(XtPointer context, XtIntervalId *id)
17897 {
17898   prefs_info *prf = (prefs_info *)context;
17899   if (XtIsSensitive(prf->arrow_down))
17900     {
17901       if ((prf) && (prf->arrow_down_func))
17902 	{
17903 	  (*(prf->arrow_down_func))(prf);
17904 	  prf->power_id = XtAppAddTimeOut(main_app(ss),
17905 					  POWER_WAIT_TIME,
17906 					  arrow_func_down,
17907 					  (XtPointer)prf);
17908 	}
17909       else prf->power_id = 0;
17910     }
17911 }
17912 
17913 
call_arrow_down_press(Widget w,XtPointer context,XtPointer info)17914 static void call_arrow_down_press(Widget w, XtPointer context, XtPointer info)
17915 {
17916   prefs_info *prf = (prefs_info *)context;
17917   if ((prf) && (prf->arrow_down_func))
17918     {
17919       (*(prf->arrow_down_func))(prf);
17920       if (XtIsSensitive(w))
17921 	prf->power_id = XtAppAddTimeOut(main_app(ss),
17922 					POWER_INITIAL_WAIT_TIME,
17923 					arrow_func_down,
17924 					(XtPointer)prf);
17925       else prf->power_id = 0;
17926     }
17927 }
17928 
17929 
call_arrow_up_press(Widget w,XtPointer context,XtPointer info)17930 static void call_arrow_up_press(Widget w, XtPointer context, XtPointer info)
17931 {
17932   prefs_info *prf = (prefs_info *)context;
17933   if ((prf) && (prf->arrow_up_func))
17934     {
17935       (*(prf->arrow_up_func))(prf);
17936       if (XtIsSensitive(w))
17937 	prf->power_id = XtAppAddTimeOut(main_app(ss),
17938 					POWER_INITIAL_WAIT_TIME,
17939 					arrow_func_up,
17940 					(XtPointer)prf);
17941       else prf->power_id = 0;
17942     }
17943 }
17944 
17945 
make_row_arrows(prefs_info * prf,Widget box,Widget left_widget,Widget top_widget)17946 static Widget make_row_arrows(prefs_info *prf, Widget box, Widget left_widget, Widget top_widget)
17947 {
17948   Arg args[20];
17949   int n;
17950 
17951   n = 0;
17952   XtSetArg(args[n], XmNbackground, ss->white); n++;
17953   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
17954   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
17955   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
17956   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
17957   XtSetArg(args[n], XmNleftWidget, left_widget); n++;
17958   XtSetArg(args[n], XmNarrowDirection, XmARROW_DOWN); n++;
17959   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
17960   prf->arrow_down = XtCreateManagedWidget("arrow-down", xmArrowButtonWidgetClass, box, args, n);
17961 
17962   n = 0;
17963   XtSetArg(args[n], XmNbackground, ss->white); n++;
17964   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
17965   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
17966   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
17967   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
17968   XtSetArg(args[n], XmNleftWidget, prf->arrow_down); n++;
17969   XtSetArg(args[n], XmNarrowDirection, XmARROW_UP); n++;
17970   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
17971   prf->arrow_up = XtCreateManagedWidget("arrow-up", xmArrowButtonWidgetClass, box, args, n);
17972 
17973   XtAddCallback(prf->arrow_down, XmNarmCallback, call_arrow_down_press, (XtPointer)prf);
17974   XtAddCallback(prf->arrow_down, XmNdisarmCallback, remove_arrow_func, (XtPointer)prf);
17975   XtAddCallback(prf->arrow_up, XmNarmCallback, call_arrow_up_press, (XtPointer)prf);
17976   XtAddCallback(prf->arrow_up, XmNdisarmCallback, remove_arrow_func, (XtPointer)prf);
17977 
17978   XtAddCallback(prf->arrow_up, XmNactivateCallback, prefs_change_callback, NULL);
17979   XtAddCallback(prf->arrow_down, XmNactivateCallback, prefs_change_callback, NULL);
17980 
17981   return(prf->arrow_up);
17982 }
17983 
17984 
17985 /* ---------------- bool row ---------------- */
17986 
call_toggle_func(Widget w,XtPointer context,XtPointer info)17987 static void call_toggle_func(Widget w, XtPointer context, XtPointer info)
17988 {
17989   prefs_info *prf = (prefs_info *)context;
17990   if ((prf) && (prf->toggle_func))
17991     (*(prf->toggle_func))(prf);
17992 }
17993 
17994 
prefs_row_with_toggle(const char * label,const char * varname,bool current_value,Widget box,Widget top_widget,void (* toggle_func)(prefs_info * prf))17995 static prefs_info *prefs_row_with_toggle(const char *label, const char *varname, bool current_value,
17996 					 Widget box, Widget top_widget,
17997 					 void (*toggle_func)(prefs_info *prf))
17998 {
17999   prefs_info *prf = NULL;
18000   Widget sep;
18001   prf = (prefs_info *)calloc(1, sizeof(prefs_info));
18002   prf->var_name = varname;
18003   prf->toggle_func = toggle_func;
18004 
18005   prf->label = make_row_label(prf, label, box, top_widget);
18006   sep = make_row_middle_separator(prf->label, box, top_widget);
18007   prf->toggle = make_row_toggle(prf, current_value, sep, box, top_widget);
18008 
18009   XtAddCallback(prf->toggle, XmNvalueChangedCallback, call_toggle_func, (XtPointer)prf);
18010   return(prf);
18011 }
18012 
18013 
18014 /* ---------------- two toggles ---------------- */
18015 
call_toggle2_func(Widget w,XtPointer context,XtPointer info)18016 static void call_toggle2_func(Widget w, XtPointer context, XtPointer info)
18017 {
18018   prefs_info *prf = (prefs_info *)context;
18019   if ((prf) && (prf->toggle2_func))
18020     (*(prf->toggle2_func))(prf);
18021 }
18022 
18023 
prefs_row_with_two_toggles(const char * label,const char * varname,const char * label1,bool value1,const char * label2,bool value2,Widget box,Widget top_widget,void (* toggle_func)(prefs_info * prf),void (* toggle2_func)(prefs_info * prf))18024 static prefs_info *prefs_row_with_two_toggles(const char *label, const char *varname,
18025 					      const char *label1, bool value1,
18026 					      const char *label2, bool value2,
18027 					      Widget box, Widget top_widget,
18028 					      void (*toggle_func)(prefs_info *prf),
18029 					      void (*toggle2_func)(prefs_info *prf))
18030 {
18031   prefs_info *prf = NULL;
18032   Widget sep, sep1;
18033   prf = (prefs_info *)calloc(1, sizeof(prefs_info));
18034   prf->var_name = varname;
18035   prf->toggle_func = toggle_func;
18036   prf->toggle2_func = toggle2_func;
18037 
18038   prf->label = make_row_label(prf, label, box, top_widget);
18039   sep = make_row_middle_separator(prf->label, box, top_widget);
18040   prf->toggle = make_row_toggle_with_label(prf, value1, sep, box, top_widget, label1);
18041   sep1 = make_row_inner_separator(20, prf->toggle, box, top_widget);
18042   prf->toggle2 = make_row_toggle_with_label(prf, value2, sep1, box, top_widget, label2);
18043 
18044   XtAddCallback(prf->toggle, XmNvalueChangedCallback, call_toggle_func, (XtPointer)prf);
18045   XtAddCallback(prf->toggle2, XmNvalueChangedCallback, call_toggle2_func, (XtPointer)prf);
18046   return(prf);
18047 }
18048 
18049 
18050 /* ---------------- toggle with text ---------------- */
18051 
call_text_func(Widget w,XtPointer context,XtPointer info)18052 static void call_text_func(Widget w, XtPointer context, XtPointer info)
18053 {
18054   prefs_info *prf = (prefs_info *)context;
18055   if ((prf) && (prf->text_func))
18056     (*(prf->text_func))(prf);
18057 }
18058 
18059 
18060 /* earlier versions of this dialog assumed the user would type <cr> to save a new value
18061  *    typed in a text widget, but no one does that anymore, so now, to catch these changes
18062  *    but not be confused by automatic changes (such as in a scale widget's label),
18063  *    we'll use XmNfocusCallback to set a text_focussed flag, XmNlosingFocusCallback to
18064  *    unset it, XmNvalueChangedCallback to set a text_changed flag, XmNactivateCallback
18065  *    to clear text_changed, and if XmNlosingFocusCallback sees that flag set, it
18066  *    calls the activate function and unsets the flag.
18067  */
18068 
18069 typedef struct {
18070   bool text_focussed, text_changed;
18071   prefs_info *prf;
18072 } text_info;
18073 
18074 
text_change_callback(Widget w,XtPointer context,XtPointer info)18075 static void text_change_callback(Widget w, XtPointer context, XtPointer info)
18076 {
18077   text_info *data = (text_info *)context;
18078   if (data->text_focussed) /* try to omit non-user actions that change the value */
18079     data->text_changed = true;
18080 }
18081 
18082 
text_activate_callback(Widget w,XtPointer context,XtPointer info)18083 static void text_activate_callback(Widget w, XtPointer context, XtPointer info)
18084 {
18085   text_info *data = (text_info *)context;
18086   data->text_changed = false;
18087 }
18088 
18089 
text_grab_focus_callback(Widget w,XtPointer context,XtPointer info)18090 static void text_grab_focus_callback(Widget w, XtPointer context, XtPointer info)
18091 {
18092   text_info *data = (text_info *)context;
18093   data->text_focussed = true;
18094 }
18095 
18096 
text_lose_focus_callback(Widget w,XtPointer context,XtPointer info)18097 static void text_lose_focus_callback(Widget w, XtPointer context, XtPointer info)
18098 {
18099   text_info *data = (text_info *)context;
18100   if ((data->text_focussed) &&
18101       (data->text_changed) &&
18102       (data->prf) &&
18103       (data->prf->text_func))
18104     {
18105       (*(data->prf->text_func))(data->prf);
18106       data->text_changed = false;
18107     }
18108 }
18109 
18110 
make_row_text(prefs_info * prf,const char * text_value,int cols,Widget left_widget,Widget box,Widget top_widget)18111 static Widget make_row_text(prefs_info *prf, const char *text_value, int cols, Widget left_widget, Widget box, Widget top_widget)
18112 {
18113   Widget w;
18114   int n;
18115   Arg args[30];
18116   text_info *info;
18117 
18118   n = 0;
18119   XtSetArg(args[n], XmNbackground, ss->white); n++;
18120   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
18121   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
18122   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
18123   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
18124   XtSetArg(args[n], XmNleftWidget, left_widget); n++;
18125   if (cols != 0)
18126     {
18127       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
18128       XtSetArg(args[n], XmNcolumns, cols); n++;
18129     }
18130   else
18131     {
18132       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
18133     }
18134   if (text_value)
18135     {
18136       XtSetArg(args[n], XmNvalue, text_value); n++;
18137     }
18138   XtSetArg(args[n], XmNmarginHeight, 1); n++;
18139   XtSetArg(args[n], XmNborderWidth, 0); n++;
18140   XtSetArg(args[n], XmNborderColor, ss->white); n++;
18141   XtSetArg(args[n], XmNbottomShadowColor, ss->white); n++;
18142   XtSetArg(args[n], XmNshadowThickness, 0); n++;
18143   XtSetArg(args[n], XmNtopShadowColor, ss->white); n++;
18144   w = make_textfield_widget("text", box, args, n, ACTIVATABLE_BUT_NOT_FOCUSED, NO_COMPLETER);
18145 
18146   XtAddCallback(w, XmNactivateCallback, prefs_change_callback, NULL);
18147 
18148   info = (text_info *)calloc(1, sizeof(text_info));
18149   info->prf = prf;
18150 
18151   XtAddCallback(w, XmNactivateCallback, text_activate_callback, (XtPointer)info);
18152   XtAddCallback(w, XmNvalueChangedCallback, text_change_callback, (XtPointer)info);
18153   XtAddCallback(w, XmNfocusCallback, text_grab_focus_callback, (XtPointer)info);
18154   XtAddCallback(w, XmNlosingFocusCallback, text_lose_focus_callback, (XtPointer)info);
18155 
18156   return(w);
18157 }
18158 
18159 
prefs_row_with_toggle_with_text(const char * label,const char * varname,bool current_value,const char * text_label,const char * text_value,int cols,Widget box,Widget top_widget,void (* toggle_func)(prefs_info * prf),void (* text_func)(prefs_info * prf))18160 static prefs_info *prefs_row_with_toggle_with_text(const char *label, const char *varname, bool current_value,
18161 						   const char *text_label, const char *text_value, int cols,
18162 						   Widget box, Widget top_widget,
18163 						   void (*toggle_func)(prefs_info *prf),
18164 						   void (*text_func)(prefs_info *prf))
18165 {
18166   prefs_info *prf = NULL;
18167   Widget sep, sep1, lab1;
18168   prf = (prefs_info *)calloc(1, sizeof(prefs_info));
18169   prf->var_name = varname;
18170   prf->toggle_func = toggle_func;
18171   prf->text_func = text_func;
18172 
18173   prf->label = make_row_label(prf, label, box, top_widget);
18174   sep = make_row_middle_separator(prf->label, box, top_widget);
18175   prf->toggle = make_row_toggle(prf, current_value, sep, box, top_widget);
18176   sep1 = make_row_inner_separator(16, prf->toggle, box, top_widget);
18177   lab1 = make_row_inner_label(prf, text_label, sep1, box, top_widget);
18178   prf->text = make_row_text(prf, text_value, cols, lab1, box, top_widget);
18179 
18180   XtAddCallback(prf->toggle, XmNvalueChangedCallback, call_toggle_func, (XtPointer)prf);
18181   XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf);
18182 
18183   return(prf);
18184 }
18185 
18186 
prefs_row_with_toggle_with_two_texts(const char * label,const char * varname,bool current_value,const char * label1,const char * text1,const char * label2,const char * text2,int cols,Widget box,Widget top_widget,void (* toggle_func)(prefs_info * prf),void (* text_func)(prefs_info * prf))18187 static prefs_info *prefs_row_with_toggle_with_two_texts(const char *label, const char *varname, bool current_value,
18188 							const char *label1, const char *text1,
18189 							const char *label2, const char *text2, int cols,
18190 							Widget box, Widget top_widget,
18191 							void (*toggle_func)(prefs_info *prf),
18192 							void (*text_func)(prefs_info *prf))
18193 {
18194   prefs_info *prf = NULL;
18195   Widget sep, lab1, lab2, sep1;
18196   prf = (prefs_info *)calloc(1, sizeof(prefs_info));
18197   prf->var_name = varname;
18198   prf->toggle_func = toggle_func;
18199   prf->text_func = text_func;
18200 
18201   prf->label = make_row_label(prf, label, box, top_widget);
18202   sep = make_row_middle_separator(prf->label, box, top_widget);
18203   prf->toggle = make_row_toggle(prf, current_value, sep, box, top_widget);
18204   sep1 = make_row_inner_separator(16, prf->toggle, box, top_widget);
18205   lab1 = make_row_inner_label(prf, label1, sep1, box, top_widget);
18206   prf->text = make_row_text(prf, text1, cols, lab1, box, top_widget);
18207   lab2 = make_row_inner_label(prf, label2, prf->text, box, top_widget);
18208   prf->rtxt = make_row_text(prf, text2, cols, lab2, box, top_widget);
18209 
18210   XtAddCallback(prf->toggle, XmNvalueChangedCallback, call_toggle_func, (XtPointer)prf);
18211   XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf);
18212   XtAddCallback(prf->rtxt, XmNactivateCallback, call_text_func, (XtPointer)prf);
18213 
18214   return(prf);
18215 }
18216 
18217 
18218 /* ---------------- text with toggle ---------------- */
18219 
prefs_row_with_text_with_toggle(const char * label,const char * varname,bool current_value,const char * toggle_label,const char * text_value,int cols,Widget box,Widget top_widget,void (* toggle_func)(prefs_info * prf),void (* text_func)(prefs_info * prf))18220 static prefs_info *prefs_row_with_text_with_toggle(const char *label, const char *varname, bool current_value,
18221 						   const char *toggle_label, const char *text_value, int cols,
18222 						   Widget box, Widget top_widget,
18223 						   void (*toggle_func)(prefs_info *prf),
18224 						   void (*text_func)(prefs_info *prf))
18225 {
18226   prefs_info *prf = NULL;
18227   Widget sep, sep1, lab1;
18228   prf = (prefs_info *)calloc(1, sizeof(prefs_info));
18229   prf->var_name = varname;
18230   prf->toggle_func = toggle_func;
18231   prf->text_func = text_func;
18232 
18233   prf->label = make_row_label(prf, label, box, top_widget);
18234   sep = make_row_middle_separator(prf->label, box, top_widget);
18235   prf->text = make_row_text(prf, text_value, cols, sep, box, top_widget);
18236   sep1 = make_row_inner_separator(8, prf->text, box, top_widget);
18237   lab1 = make_row_inner_label(prf, toggle_label, sep1, box, top_widget);
18238   prf->toggle = make_row_toggle(prf, current_value, lab1, box, top_widget);
18239 
18240   XtAddCallback(prf->toggle, XmNvalueChangedCallback, call_toggle_func, (XtPointer)prf);
18241   XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf);
18242 
18243   return(prf);
18244 }
18245 
18246 
18247 /* ---------------- text with toggle ---------------- */
18248 
prefs_row_with_text_and_three_toggles(const char * label,const char * varname,const char * text_label,int cols,const char * toggle1_label,const char * toggle2_label,const char * toggle3_label,const char * text_value,bool toggle1_value,bool toggle2_value,bool toggle3_value,Widget box,Widget top_widget,void (* text_func)(prefs_info * prf))18249 static prefs_info *prefs_row_with_text_and_three_toggles(const char *label, const char *varname,
18250 							 const char *text_label, int cols,
18251 							 const char *toggle1_label, const char *toggle2_label, const char *toggle3_label,
18252 							 const char *text_value,
18253 							 bool toggle1_value, bool toggle2_value, bool toggle3_value,
18254 							 Widget box, Widget top_widget,
18255 							 void (*text_func)(prefs_info *prf))
18256 {
18257   prefs_info *prf = NULL;
18258   Widget sep, sep1, lab1, sep2, lab2, lab3, sep3, lab4;
18259   prf = (prefs_info *)calloc(1, sizeof(prefs_info));
18260   prf->var_name = varname;
18261   prf->text_func = text_func;
18262 
18263   prf->label = make_row_label(prf, label, box, top_widget);
18264   sep = make_row_middle_separator(prf->label, box, top_widget);
18265   lab3 = make_row_inner_label(prf, text_label, sep, box, top_widget);
18266   prf->text = make_row_text(prf, text_value, cols, lab3, box, top_widget);
18267   sep1 = make_row_inner_separator(12, prf->text, box, top_widget);
18268   lab1 = make_row_inner_label(prf, toggle1_label, sep1, box, top_widget);
18269   prf->toggle = make_row_toggle(prf, toggle1_value, lab1, box, top_widget);
18270   sep2 = make_row_inner_separator(4, prf->toggle, box, top_widget);
18271   lab2 = make_row_inner_label(prf, toggle2_label, sep2, box, top_widget);
18272   prf->toggle2 = make_row_toggle(prf, toggle2_value, lab2, box, top_widget);
18273   sep3 = make_row_inner_separator(4, prf->toggle2, box, top_widget);
18274   lab4 = make_row_inner_label(prf, toggle3_label, sep3, box, top_widget);
18275   prf->toggle3 = make_row_toggle(prf, toggle3_value, lab4, box, top_widget);
18276 
18277   XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf);
18278 
18279   return(prf);
18280 }
18281 
18282 
18283 /* ---------------- radio row ---------------- */
18284 
call_radio_func(Widget w,XtPointer context,XtPointer info)18285 static void call_radio_func(Widget w, XtPointer context, XtPointer info)
18286 {
18287   prefs_info *prf = (prefs_info *)context;
18288   if ((prf) && (prf->toggle_func))
18289     {
18290       prf->radio_button = w;
18291       (*(prf->toggle_func))(prf);
18292     }
18293 }
18294 
18295 
make_row_radio_box(prefs_info * prf,const char ** labels,int num_labels,int current_value,Widget box,Widget left_widget,Widget top_widget)18296 static Widget make_row_radio_box(prefs_info *prf,
18297 				 const char **labels, int num_labels, int current_value,
18298 				 Widget box, Widget left_widget, Widget top_widget)
18299 {
18300   Arg args[20];
18301   int i, n;
18302   Widget w;
18303 
18304   prf->radio_buttons = (Widget *)calloc(num_labels, sizeof(Widget));
18305   prf->num_buttons = num_labels;
18306 
18307   n = 0;
18308   XtSetArg(args[n], XmNbackground, ss->white); n++;
18309   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
18310   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
18311   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
18312   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
18313   XtSetArg(args[n], XmNleftWidget, left_widget); n++;
18314   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
18315   XtSetArg(args[n], XmNborderWidth, 0); n++;
18316   XtSetArg(args[n], XmNborderColor, ss->white); n++;
18317   XtSetArg(args[n], XmNmarginHeight, 0); n++;
18318   XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
18319   XtSetArg(args[n], XmNpacking, XmPACK_TIGHT); n++;
18320   w = XmCreateRadioBox(box, (char *)"radio-box", args, n);
18321   XtManageChild(w);
18322 
18323   for (i = 0; i < num_labels; i++)
18324     {
18325       Widget button;
18326 
18327       n = 0;
18328       XtSetArg(args[n], XmNbackground, ss->white); n++;
18329       XtSetArg(args[n], XmNset, (i == current_value) ? XmSET : XmUNSET); n++;
18330       XtSetArg(args[n], XmNborderWidth, 0); n++;
18331       XtSetArg(args[n], XmNborderColor, ss->white); n++;
18332       XtSetArg(args[n], XmNmarginHeight, 0); n++;
18333       XtSetArg(args[n], XmNindicatorOn, XmINDICATOR_FILL); n++;
18334       XtSetArg(args[n], XmNindicatorSize, 14); n++;
18335       XtSetArg(args[n], XmNselectColor, ss->green); n++;
18336       XtSetArg(args[n], XmNuserData, i); n++;
18337       button = XtCreateManagedWidget(labels[i], xmToggleButtonWidgetClass, w, args, n);
18338       prf->radio_buttons[i] = button;
18339 
18340       XtAddCallback(button, XmNvalueChangedCallback, call_radio_func, (XtPointer)prf);
18341       XtAddCallback(button, XmNvalueChangedCallback, prefs_change_callback, NULL);
18342     }
18343   return(w);
18344 }
18345 
18346 
prefs_row_with_radio_box(const char * label,const char * varname,const char ** labels,int num_labels,int current_value,Widget box,Widget top_widget,void (* toggle_func)(prefs_info * prf))18347 static prefs_info *prefs_row_with_radio_box(const char *label, const char *varname,
18348 					    const char **labels, int num_labels, int current_value,
18349 					    Widget box, Widget top_widget,
18350 					    void (*toggle_func)(prefs_info *prf))
18351 {
18352   prefs_info *prf = NULL;
18353   Widget sep;
18354   prf = (prefs_info *)calloc(1, sizeof(prefs_info));
18355   prf->var_name = varname;
18356   prf->toggle_func = toggle_func;
18357   prf->label = make_row_label(prf, label, box, top_widget);
18358   sep = make_row_middle_separator(prf->label, box, top_widget);
18359   prf->toggle = make_row_radio_box(prf, labels, num_labels, current_value, box, sep, top_widget);
18360   return(prf);
18361 }
18362 
18363 
18364 /* ---------------- radio box + number ---------------- */
18365 
prefs_row_with_radio_box_and_number(const char * label,const char * varname,const char ** labels,int num_labels,int current_value,const char * text_value,int text_cols,Widget box,Widget top_widget,void (* toggle_func)(prefs_info * prf),void (* arrow_up_func)(prefs_info * prf),void (* arrow_down_func)(prefs_info * prf),void (* text_func)(prefs_info * prf))18366 static prefs_info *prefs_row_with_radio_box_and_number(const char *label, const char *varname,
18367 						       const char **labels, int num_labels, int current_value,
18368 						       const char *text_value, int text_cols,
18369 						       Widget box, Widget top_widget,
18370 						       void (*toggle_func)(prefs_info *prf),
18371 						       void (*arrow_up_func)(prefs_info *prf), void (*arrow_down_func)(prefs_info *prf),
18372 						       void (*text_func)(prefs_info *prf))
18373 {
18374   prefs_info *prf = NULL;
18375   Widget sep;
18376   prf = (prefs_info *)calloc(1, sizeof(prefs_info));
18377   prf->var_name = varname;
18378   prf->toggle_func = toggle_func;
18379   prf->text_func = text_func;
18380   prf->arrow_up_func = arrow_up_func;
18381   prf->arrow_down_func = arrow_down_func;
18382   prf->label = make_row_label(prf, label, box, top_widget);
18383   sep = make_row_middle_separator(prf->label, box, top_widget);
18384   prf->toggle = make_row_radio_box(prf, labels, num_labels, current_value, box, sep, top_widget);
18385   prf->text = make_row_text(prf, text_value, text_cols, prf->toggle, box, top_widget);
18386   prf->arrow_up = make_row_arrows(prf, box, prf->text, top_widget);
18387 
18388   XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf);
18389   return(prf);
18390 }
18391 
18392 
18393 /* ---------------- scale row ---------------- */
18394 
call_scale_func(Widget w,XtPointer context,XtPointer info)18395 static void call_scale_func(Widget w, XtPointer context, XtPointer info)
18396 {
18397   prefs_info *prf = (prefs_info *)context;
18398   if ((prf) && (prf->scale_func))
18399     (*(prf->scale_func))(prf);
18400 }
18401 
18402 
call_scale_text_func(Widget w,XtPointer context,XtPointer info)18403 static void call_scale_text_func(Widget w, XtPointer context, XtPointer info)
18404 {
18405   prefs_info *prf = (prefs_info *)context;
18406   if ((prf) && (prf->text_func))
18407     (*(prf->text_func))(prf);
18408 }
18409 
18410 
prefs_scale_callback(Widget w,XtPointer context,XtPointer info)18411 static void prefs_scale_callback(Widget w, XtPointer context, XtPointer info)
18412 {
18413   prefs_info *prf = (prefs_info *)context;
18414   XmScaleCallbackStruct *cb = (XmScaleCallbackStruct *)info;
18415   float_to_textfield(prf->text, (cb->value * prf->scale_max) / 100.0);
18416 }
18417 
18418 
prefs_row_with_scale(const char * label,const char * varname,mus_float_t max_val,mus_float_t current_value,Widget box,Widget top_widget,void (* scale_func)(prefs_info * prf),void (* text_func)(prefs_info * prf))18419 static prefs_info *prefs_row_with_scale(const char *label, const char *varname,
18420 					mus_float_t max_val, mus_float_t current_value,
18421 					Widget box, Widget top_widget,
18422 					void (*scale_func)(prefs_info *prf),
18423 					void (*text_func)(prefs_info *prf))
18424 {
18425   Arg args[20];
18426   int n;
18427   prefs_info *prf = NULL;
18428   Widget sep;
18429   XtCallbackList n1, n2;
18430   char *str;
18431 
18432   prf = (prefs_info *)calloc(1, sizeof(prefs_info));
18433   prf->var_name = varname;
18434   prf->scale_max = max_val;
18435 
18436   prf->label = make_row_label(prf, label, box, top_widget);
18437   sep = make_row_middle_separator(prf->label, box, top_widget);
18438 
18439   str = (char *)calloc(12, sizeof(char));
18440   snprintf(str, 12, "%.3f", current_value);
18441   prf->text = make_row_text(prf, str, 6, sep, box, top_widget);
18442   free(str);
18443 
18444   n = 0;
18445   XtSetArg(args[n], XmNbackground, ss->white); n++;
18446   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
18447   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
18448   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
18449   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
18450   XtSetArg(args[n], XmNleftWidget, prf->text); n++;
18451   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
18452   XtSetArg(args[n], XmNborderWidth, 0); n++;
18453   XtSetArg(args[n], XmNborderColor, ss->white); n++;
18454   XtSetArg(args[n], XmNmarginHeight, 0); n++;
18455   XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
18456   XtSetArg(args[n], XmNshowValue, XmNONE); n++;
18457   XtSetArg(args[n], XmNvalue, (int)(100 * current_value / max_val)); n++;
18458   XtSetArg(args[n], XmNdragCallback, n1 = make_callback_list(prefs_scale_callback, (XtPointer)prf)); n++;
18459   XtSetArg(args[n], XmNvalueChangedCallback, n2 = make_callback_list(prefs_scale_callback, (XtPointer)prf)); n++;
18460   prf->scale = XtCreateManagedWidget("", xmScaleWidgetClass, box, args, n);
18461 
18462   prf->scale_func = scale_func;
18463   prf->text_func = text_func;
18464 
18465   XtAddCallback(prf->scale, XmNvalueChangedCallback, call_scale_func, (XtPointer)prf);
18466   XtAddCallback(prf->text, XmNactivateCallback, call_scale_text_func, (XtPointer)prf);
18467   XtAddCallback(prf->scale, XmNvalueChangedCallback, prefs_change_callback, NULL);
18468 
18469   free(n1);
18470   free(n2);
18471 
18472   return(prf);
18473 }
18474 
18475 
18476 /* ---------------- text row ---------------- */
18477 
prefs_row_with_text(const char * label,const char * varname,const char * value,Widget box,Widget top_widget,void (* text_func)(prefs_info * prf))18478 static prefs_info *prefs_row_with_text(const char *label, const char *varname, const char *value,
18479 				       Widget box, Widget top_widget,
18480 				       void (*text_func)(prefs_info *prf))
18481 {
18482   prefs_info *prf = NULL;
18483   Widget sep;
18484   prf = (prefs_info *)calloc(1, sizeof(prefs_info));
18485   prf->var_name = varname;
18486 
18487   prf->label = make_row_label(prf, label, box, top_widget);
18488   sep = make_row_middle_separator(prf->label, box, top_widget);
18489   prf->text = make_row_text(prf, value, 0, sep, box, top_widget);
18490 
18491   prf->text_func = text_func;
18492   XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf);
18493   return(prf);
18494 }
18495 
18496 
18497 
18498 /* ---------------- two texts in a row ---------------- */
18499 
prefs_row_with_two_texts(const char * label,const char * varname,const char * label1,const char * text1,const char * label2,const char * text2,int cols,Widget box,Widget top_widget,void (* text_func)(prefs_info * prf))18500 static prefs_info *prefs_row_with_two_texts(const char *label, const char *varname,
18501 					    const char *label1, const char *text1, const char *label2, const char *text2, int cols,
18502 					    Widget box, Widget top_widget,
18503 					    void (*text_func)(prefs_info *prf))
18504 {
18505   prefs_info *prf = NULL;
18506   Widget sep, lab1, lab2;
18507   prf = (prefs_info *)calloc(1, sizeof(prefs_info));
18508   prf->var_name = varname;
18509 
18510   prf->label = make_row_label(prf, label, box, top_widget);
18511   sep = make_row_middle_separator(prf->label, box, top_widget);
18512   lab1 = make_row_inner_label(prf, label1, sep, box, top_widget);
18513   prf->text = make_row_text(prf, text1, cols, lab1, box, top_widget);
18514   lab2 = make_row_inner_label(prf, label2, prf->text, box, top_widget);
18515   prf->rtxt = make_row_text(prf, text2, cols, lab2, box, top_widget);
18516 
18517   prf->text_func = text_func;
18518   XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf);
18519   XtAddCallback(prf->rtxt, XmNactivateCallback, call_text_func, (XtPointer)prf);
18520 
18521   return(prf);
18522 }
18523 
18524 
18525 /* ---------------- number row ---------------- */
18526 
prefs_row_with_number(const char * label,const char * varname,const char * value,int cols,Widget box,Widget top_widget,void (* arrow_up_func)(prefs_info * prf),void (* arrow_down_func)(prefs_info * prf),void (* text_func)(prefs_info * prf))18527 static prefs_info *prefs_row_with_number(const char *label, const char *varname, const char *value, int cols,
18528 					 Widget box, Widget top_widget,
18529  					 void (*arrow_up_func)(prefs_info *prf), void (*arrow_down_func)(prefs_info *prf),
18530 					 void (*text_func)(prefs_info *prf))
18531 {
18532   prefs_info *prf = NULL;
18533   Widget sep;
18534   prf = (prefs_info *)calloc(1, sizeof(prefs_info));
18535   prf->var_name = varname;
18536 
18537   prf->label = make_row_label(prf, label, box, top_widget);
18538   sep = make_row_middle_separator(prf->label, box, top_widget);
18539   prf->text = make_row_text(prf, value, cols, sep, box, top_widget);
18540   prf->arrow_up = make_row_arrows(prf, box, prf->text, top_widget);
18541   prf->error = make_row_error(prf, box, prf->arrow_up, top_widget);
18542 
18543   prf->text_func = text_func;
18544   prf->arrow_up_func = arrow_up_func;
18545   prf->arrow_down_func = arrow_down_func;
18546 
18547   XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf);
18548 
18549   return(prf);
18550 }
18551 
18552 
18553 /* ---------------- list row ---------------- */
18554 
18555 typedef struct {
18556   prefs_info *prf;
18557   char *value;
18558 } list_entry;
18559 
make_list_entry(prefs_info * prf,const char * value)18560 static list_entry *make_list_entry(prefs_info *prf, const char *value)
18561 {
18562   list_entry *le;
18563   le = (list_entry *)calloc(1, sizeof(list_entry));
18564   le->prf = prf;
18565   le->value = (char *)value;
18566   return(le);
18567 }
18568 
18569 
prefs_list_callback(Widget w,XtPointer context,XtPointer info)18570 static void prefs_list_callback(Widget w, XtPointer context, XtPointer info)
18571 {
18572   list_entry *le = (list_entry *)context;
18573   if ((le) && (le->prf->list_func))
18574     (*(le->prf->list_func))(le->prf, le->value);
18575 }
18576 
18577 
prefs_row_with_list(const char * label,const char * varname,const char * value,const char ** values,int num_values,Widget box,Widget top_widget,void (* text_func)(prefs_info * prf),char * (* completion_func)(widget_t w,const char * text,void * context),void * completion_context,void (* list_func)(prefs_info * prf,char * value))18578 static prefs_info *prefs_row_with_list(const char *label, const char *varname, const char *value,
18579 				       const char **values, int num_values,
18580 				       Widget box, Widget top_widget,
18581 				       void (*text_func)(prefs_info *prf),
18582 				       char *(*completion_func)(widget_t w, const char *text, void *context), void *completion_context,
18583 				       void (*list_func)(prefs_info *prf, char *value))
18584 {
18585   Arg args[20];
18586   int n, i, cols = 0;
18587   prefs_info *prf = NULL;
18588   Widget sep, sbar;
18589   prf = (prefs_info *)calloc(1, sizeof(prefs_info));
18590   prf->var_name = varname;
18591 
18592   prf->label = make_row_label(prf, label, box, top_widget);
18593   sep = make_row_middle_separator(prf->label, box, top_widget);
18594 
18595   /* get text widget size */
18596   for (i = 0; i < num_values; i++)
18597     if (values[i])
18598       {
18599 	int len;
18600 	len = strlen(values[i]);
18601 	if (len > cols) cols = len;
18602       }
18603 
18604   n = 0;
18605   XtSetArg(args[n], XmNbackground, ss->white); n++;
18606   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
18607   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
18608   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
18609   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
18610   XtSetArg(args[n], XmNleftWidget, sep); n++;
18611   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
18612   XtSetArg(args[n], XmNcolumns, cols + 1); n++;
18613   XtSetArg(args[n], XmNvalue, value); n++;
18614   XtSetArg(args[n], XmNmarginHeight, 1); n++;
18615   XtSetArg(args[n], XmNborderWidth, 0); n++;
18616   XtSetArg(args[n], XmNborderColor, ss->white); n++;
18617   XtSetArg(args[n], XmNbottomShadowColor, ss->white); n++;
18618   XtSetArg(args[n], XmNshadowThickness, 0); n++;
18619   XtSetArg(args[n], XmNtopShadowColor, ss->white); n++;
18620   if (completion_func)
18621     prf->text = make_textfield_widget("text", box, args, n, ACTIVATABLE_BUT_NOT_FOCUSED, add_completer_func(completion_func, completion_context));
18622   else prf->text = make_textfield_widget("text", box, args, n, ACTIVATABLE_BUT_NOT_FOCUSED, NO_COMPLETER);
18623 
18624   n = 0;
18625   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
18626   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
18627   XtSetArg(args[n], XmNleftWidget, prf->text); n++;
18628   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
18629   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
18630   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
18631   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
18632   XtSetArg(args[n], XmNshadowThickness, 0); n++;
18633   XtSetArg(args[n], XmNhighlightThickness, 0); n++;
18634   XtSetArg(args[n], XmNmarginHeight, 0); n++;
18635   sbar = XmCreateMenuBar(box, (char *)"menuBar", args, n);
18636   XtManageChild(sbar);
18637 
18638   n = 0;
18639   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
18640   prf->list_menu = XmCreatePulldownMenu(sbar, (char *)"sort-menu", args, n);
18641 
18642   n = 0;
18643   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
18644   XtSetArg(args[n], XmNsubMenuId, prf->list_menu); n++;
18645   XtSetArg(args[n], XmNshadowThickness, 0); n++;
18646   XtSetArg(args[n], XmNhighlightThickness, 0); n++;
18647   XtSetArg(args[n], XmNmarginHeight, 1); n++;
18648   XtSetArg(args[n], XmNbackground, ss->white); n++;
18649   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
18650   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
18651   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
18652   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
18653   XtSetArg(args[n], XmNleftWidget, prf->text); n++;
18654   XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
18655   prf->arrow_right = XtCreateManagedWidget(">", xmCascadeButtonWidgetClass, sbar, args, n);
18656 
18657   n = 0;
18658   XtSetArg(args[n], XmNbackground, ss->white); n++;
18659   for (i = 0; i < num_values; i++)
18660     if (values[i])
18661       {
18662 	Widget tmp;
18663 	tmp = XtCreateManagedWidget(values[i],  xmPushButtonWidgetClass, prf->list_menu, args, n);
18664 	XtAddCallback(tmp, XmNactivateCallback, prefs_list_callback, make_list_entry(prf, values[i]));
18665 	XtAddCallback(tmp, XmNactivateCallback, prefs_change_callback, NULL);
18666       }
18667 
18668   prf->error = make_row_error(prf, box, prf->arrow_right, top_widget);
18669   prf->text_func = text_func;
18670   XtAddCallback(prf->text, XmNactivateCallback, call_text_func, (XtPointer)prf);
18671   XtAddCallback(prf->text, XmNactivateCallback, prefs_change_callback, NULL);
18672   XtAddCallback(prf->arrow_right, XmNactivateCallback, prefs_change_callback, NULL);
18673 
18674   prf->list_func = list_func;
18675   return(prf);
18676 }
18677 
18678 
18679 /* ---------------- color selector row(s) ---------------- */
18680 
rgb_to_color_1(mus_float_t r,mus_float_t g,mus_float_t b)18681 static XColor *rgb_to_color_1(mus_float_t r, mus_float_t g, mus_float_t b)
18682 {
18683   Display *dpy;
18684   XColor *new_color;
18685   new_color = (XColor *)calloc(1, sizeof(XColor));
18686   new_color->flags = DoRed | DoGreen | DoBlue;
18687   new_color->red = float_to_rgb(r);
18688   new_color->green = float_to_rgb(g);
18689   new_color->blue = float_to_rgb(b);
18690   dpy = main_display(ss);
18691   XAllocColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), new_color);
18692   return(new_color);
18693 }
18694 
18695 
18696 #define COLOR_MAX 90
18697 #define COLOR_MAXF 90.0
18698 #define COLOR_MARGIN 1
18699 
rgb_to_color(mus_float_t r,mus_float_t g,mus_float_t b)18700 static color_t rgb_to_color(mus_float_t r, mus_float_t g, mus_float_t b)
18701 {
18702   color_t temp;
18703   XColor *color;
18704   color = rgb_to_color_1(r, g, b);
18705   temp = color->pixel;
18706   free(color);
18707   return(temp);
18708 }
18709 
18710 
pixel_to_rgb(Pixel pix,double * r,double * g,double * b)18711 static void pixel_to_rgb(Pixel pix, double *r, double *g, double *b)
18712 {
18713   XColor tmp_color;
18714   Display *dpy;
18715   dpy = XtDisplay(main_shell(ss));
18716   tmp_color.flags = DoRed | DoGreen | DoBlue;
18717   tmp_color.pixel = pix;
18718   XQueryColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), &tmp_color);
18719   (*r) = rgb_to_float(tmp_color.red);
18720   (*g) = rgb_to_float(tmp_color.green);
18721   (*b) = rgb_to_float(tmp_color.blue);
18722 }
18723 
18724 
XmScrollBarGetValue(Widget w,int * val)18725 static void XmScrollBarGetValue(Widget w, int *val)
18726 {
18727   XtVaGetValues(w, XmNvalue, val, NULL);
18728 }
18729 
18730 
XmScrollBarSetValue(Widget w,int val)18731 static void XmScrollBarSetValue(Widget w, int val)
18732 {
18733   XtVaSetValues(w, XmNvalue, val, NULL);
18734 }
18735 
18736 
reflect_color(prefs_info * prf)18737 static void reflect_color(prefs_info *prf)
18738 {
18739   int ir = 0, ig = 0, ib = 0;
18740   mus_float_t r, g, b;
18741   XColor *current_color;
18742   Pixel pixel;
18743 
18744   XmScrollBarGetValue(prf->rscl, &ir);
18745   XmScrollBarGetValue(prf->gscl, &ig);
18746   XmScrollBarGetValue(prf->bscl, &ib);
18747 
18748   current_color = rgb_to_color_1(ir / COLOR_MAXF, ig / COLOR_MAXF, ib / COLOR_MAXF);
18749   r = rgb_to_float(current_color->red);
18750   g = rgb_to_float(current_color->green);
18751   b = rgb_to_float(current_color->blue);
18752 
18753   pixel = current_color->pixel;
18754   free(current_color);
18755   current_color = NULL;
18756 
18757   XtVaSetValues(prf->color, XmNbackground, pixel, NULL);
18758   float_to_textfield(prf->rtxt, r);
18759   float_to_textfield(prf->gtxt, g);
18760   float_to_textfield(prf->btxt, b);
18761 }
18762 
18763 
prefs_color_callback(Widget w,XtPointer context,XtPointer info)18764 static void prefs_color_callback(Widget w, XtPointer context, XtPointer info)
18765 {
18766   reflect_color((prefs_info *)context);
18767 }
18768 
18769 
unpost_color_error(XtPointer data,XtIntervalId * id)18770 static void unpost_color_error(XtPointer data, XtIntervalId *id)
18771 {
18772   prefs_info *prf = (prefs_info *)data;
18773   reflect_color(prf);
18774   prf->got_error = false;
18775   black_text(prf);
18776   set_label(prf->label, prf->saved_label);
18777 }
18778 
18779 
errors_to_color_text(const char * msg,void * data)18780 static void errors_to_color_text(const char *msg, void *data)
18781 {
18782   prefs_info *prf = (prefs_info *)data;
18783   prf->got_error = true;
18784   red_text(prf);
18785   set_label(prf->label, msg);
18786   XtAppAddTimeOut(main_app(ss),
18787 		  ERROR_WAIT_TIME,
18788 		  (XtTimerCallbackProc)unpost_color_error,
18789 		  data);
18790 }
18791 
18792 
prefs_r_callback(Widget w,XtPointer context,XtPointer info)18793 static void prefs_r_callback(Widget w, XtPointer context, XtPointer info)
18794 {
18795   prefs_info *prf = (prefs_info *)context;
18796   char *str;
18797   double r;
18798   str = XmTextFieldGetString(w);
18799   redirect_errors_to(errors_to_color_text, (void *)prf);
18800   r = (double)string_to_mus_float_t(str, 0.0, "red amount");
18801   redirect_errors_to(NULL, NULL);
18802 
18803   XmScrollBarSetValue(prf->rscl, mus_iclamp(0, (int)(COLOR_MAX * r), COLOR_MAX));
18804 
18805   if (!(prf->got_error)) reflect_color(prf);
18806   if (str) XtFree(str);
18807 }
18808 
18809 
prefs_g_callback(Widget w,XtPointer context,XtPointer info)18810 static void prefs_g_callback(Widget w, XtPointer context, XtPointer info)
18811 {
18812   prefs_info *prf = (prefs_info *)context;
18813   char *str;
18814   double r;
18815   str = XmTextFieldGetString(w);
18816   redirect_errors_to(errors_to_color_text, (void *)prf);
18817   r = (double)string_to_mus_float_t(str, 0.0, "green amount");
18818   redirect_errors_to(NULL, NULL);
18819 
18820   XmScrollBarSetValue(prf->gscl, mus_iclamp(0, (int)(COLOR_MAX * r), COLOR_MAX));
18821 
18822   if (!(prf->got_error)) reflect_color(prf);
18823   if (str) XtFree(str);
18824 }
18825 
18826 
prefs_b_callback(Widget w,XtPointer context,XtPointer info)18827 static void prefs_b_callback(Widget w, XtPointer context, XtPointer info)
18828 {
18829   prefs_info *prf = (prefs_info *)context;
18830   char *str;
18831   double r;
18832   str = XmTextFieldGetString(w);
18833   redirect_errors_to(errors_to_color_text, (void *)prf);
18834   r = (double)string_to_mus_float_t(str, 0.0, "blue amount");
18835   redirect_errors_to(NULL, NULL);
18836 
18837   XmScrollBarSetValue(prf->bscl, mus_iclamp(0, (int)(COLOR_MAX * r), COLOR_MAX));
18838 
18839   if (!(prf->got_error)) reflect_color(prf);
18840   if (str) XtFree(str);
18841 }
18842 
18843 
prefs_call_color_func_callback(Widget w,XtPointer context,XtPointer info)18844 static void prefs_call_color_func_callback(Widget w, XtPointer context, XtPointer info)
18845 {
18846   prefs_info *prf = (prefs_info *)context;
18847   if ((prf) && (prf->color_func))
18848     {
18849       int ir = 0, ig = 0, ib = 0;
18850 
18851       XmScrollBarGetValue(prf->rscl, &ir);
18852       XmScrollBarGetValue(prf->gscl, &ig);
18853       XmScrollBarGetValue(prf->bscl, &ib);
18854 
18855       (*(prf->color_func))(prf, (double)ir / COLOR_MAXF, (double)ig / COLOR_MAXF, (double)ib / COLOR_MAXF);
18856     }
18857 }
18858 
18859 
scale_set_color(prefs_info * prf,color_t pixel)18860 static void scale_set_color(prefs_info *prf, color_t pixel)
18861 {
18862   double r = 0.0, g = 0.0, b = 0.0;
18863   pixel_to_rgb(pixel, &r, &g, &b);
18864   float_to_textfield(prf->rtxt, r);
18865   XmScrollBarSetValue(prf->rscl, (int)(COLOR_MAX * r));
18866   float_to_textfield(prf->gtxt, g);
18867   XmScrollBarSetValue(prf->gscl, (int)(COLOR_MAX * g));
18868   float_to_textfield(prf->btxt, b);
18869   XmScrollBarSetValue(prf->bscl, (int)(COLOR_MAX * b));
18870   XtVaSetValues(prf->color, XmNbackground, pixel, NULL);
18871 }
18872 
18873 
18874 static Pixel red, green, blue;
18875 
prefs_color_selector_row(const char * label,const char * varname,Pixel current_pixel,Widget box,Widget top_widget,void (* color_func)(prefs_info * prf,double r,double g,double b))18876 static prefs_info *prefs_color_selector_row(const char *label, const char *varname,
18877 					    Pixel current_pixel,
18878 					    Widget box, Widget top_widget,
18879 					    void (*color_func)(prefs_info *prf, double r, double g, double b))
18880 {
18881   Arg args[20];
18882   int n;
18883   prefs_info *prf = NULL;
18884   Widget sep, sep1, frame;
18885   XtCallbackList n1;
18886   double r = 0.0, g = 0.0, b = 0.0;
18887 
18888   prf = (prefs_info *)calloc(1, sizeof(prefs_info));
18889   prf->var_name = varname;
18890   pixel_to_rgb(current_pixel, &r, &g, &b);
18891 
18892   prf->label = make_row_label(prf, label, box, top_widget);
18893   sep = make_row_middle_separator(prf->label, box, top_widget);
18894 
18895   n = 0;
18896   XtSetArg(args[n], XmNbackground, current_pixel); n++;
18897   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
18898   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
18899   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
18900   XtSetArg(args[n], XmNbottomWidget, sep); n++;
18901   XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
18902   XtSetArg(args[n], XmNleftWidget, sep); n++;
18903   XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
18904   XtSetArg(args[n], XmNrightPosition, PREFS_COLOR_POSITION); n++;
18905   XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++;
18906   frame = XtCreateManagedWidget("frame", xmFrameWidgetClass, box, args, n);
18907 
18908   n = 0;
18909   XtSetArg(args[n], XmNbackground, current_pixel); n++;
18910   prf->color = XtCreateManagedWidget("", xmLabelWidgetClass, frame, args, n);
18911 
18912   sep1 = make_row_inner_separator(8, prf->color, box, top_widget);
18913 
18914   prf->rtxt = make_row_text(prf, NULL, 6, sep1, box, top_widget);
18915   float_to_textfield(prf->rtxt, r);
18916 
18917   prf->gtxt = make_row_text(prf, NULL, 6, prf->rtxt, box, top_widget);
18918   float_to_textfield(prf->gtxt, g);
18919 
18920   prf->btxt = make_row_text(prf, NULL, 6, prf->gtxt, box, top_widget);
18921   float_to_textfield(prf->btxt, b);
18922 
18923   /* second row = 3 scales */
18924   n1 = make_callback_list(prefs_color_callback, (XtPointer)prf);
18925 
18926   n = 0;
18927   XtSetArg(args[n], XmNbackground, ss->white); n++;
18928   XtSetArg(args[n], XmNforeground, red); n++;
18929   XtSetArg(args[n], XmNsliderVisual, XmFOREGROUND_COLOR); n++;
18930   XtSetArg(args[n], XmNsliderMark, XmTHUMB_MARK); n++;
18931   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
18932   XtSetArg(args[n], XmNtopWidget, prf->label); n++;
18933   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
18934   if (FIRST_COLOR_POSITION == 0)
18935     {
18936       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
18937     }
18938   else
18939     {
18940       XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
18941       XtSetArg(args[n], XmNleftPosition, FIRST_COLOR_POSITION); n++;
18942     }
18943   XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
18944   XtSetArg(args[n], XmNrightPosition, SECOND_COLOR_POSITION - COLOR_MARGIN); n++;
18945   XtSetArg(args[n], XmNmarginHeight, 0); n++;
18946   /* scale widget borders are messed up in some Motifs -- they aren't erased correctly in a scrolled window
18947    *   so, try to use a scrollbar instead.
18948    */
18949   XtSetArg(args[n], XmNmaximum, 100); n++;
18950   XtSetArg(args[n], XmNheight, 16); n++;
18951   XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
18952   XtSetArg(args[n], XmNshowArrows, XmNONE); n++;
18953   XtSetArg(args[n], XmNvalue, (int)(COLOR_MAX * r)); n++;
18954   XtSetArg(args[n], XmNdragCallback, n1); n++;
18955   XtSetArg(args[n], XmNvalueChangedCallback, n1); n++;
18956   prf->rscl = XtCreateManagedWidget("", xmScrollBarWidgetClass, box, args, n);
18957 
18958 
18959   n = 0;
18960   XtSetArg(args[n], XmNbackground, ss->white); n++;
18961   XtSetArg(args[n], XmNforeground, green); n++;
18962   XtSetArg(args[n], XmNsliderVisual, XmFOREGROUND_COLOR); n++;
18963   XtSetArg(args[n], XmNsliderMark, XmTHUMB_MARK); n++;
18964   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
18965   XtSetArg(args[n], XmNtopWidget, prf->label); n++;
18966   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
18967   XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
18968   XtSetArg(args[n], XmNleftPosition, SECOND_COLOR_POSITION + COLOR_MARGIN); n++;
18969   XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
18970   XtSetArg(args[n], XmNrightPosition, THIRD_COLOR_POSITION - COLOR_MARGIN); n++;
18971   XtSetArg(args[n], XmNmarginHeight, 0); n++;
18972   XtSetArg(args[n], XmNmaximum, 100); n++;
18973   XtSetArg(args[n], XmNheight, 16); n++;
18974   XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
18975   XtSetArg(args[n], XmNshowArrows, XmNONE); n++;
18976   XtSetArg(args[n], XmNvalue, (int)(COLOR_MAX * g)); n++;
18977   XtSetArg(args[n], XmNdragCallback, n1); n++;
18978   XtSetArg(args[n], XmNvalueChangedCallback, n1); n++;
18979   prf->gscl = XtCreateManagedWidget("", xmScrollBarWidgetClass, box, args, n);
18980 
18981   n = 0;
18982   XtSetArg(args[n], XmNbackground, ss->white); n++;
18983   XtSetArg(args[n], XmNforeground, blue); n++;
18984   XtSetArg(args[n], XmNsliderVisual, XmFOREGROUND_COLOR); n++;
18985   XtSetArg(args[n], XmNsliderMark, XmTHUMB_MARK); n++;
18986   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
18987   XtSetArg(args[n], XmNtopWidget, prf->label); n++;
18988   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
18989   XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
18990   XtSetArg(args[n], XmNleftPosition, THIRD_COLOR_POSITION + COLOR_MARGIN); n++;
18991   XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
18992   XtSetArg(args[n], XmNrightPosition, 80); n++;
18993   XtSetArg(args[n], XmNmarginHeight, 0); n++;
18994   XtSetArg(args[n], XmNmaximum, 100); n++;
18995   XtSetArg(args[n], XmNheight, 16); n++;
18996   XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
18997   XtSetArg(args[n], XmNshowArrows, XmNONE); n++;
18998   XtSetArg(args[n], XmNvalue, (int)(COLOR_MAX * b)); n++;
18999   XtSetArg(args[n], XmNdragCallback, n1); n++;
19000   XtSetArg(args[n], XmNvalueChangedCallback, n1); n++;
19001   prf->bscl = XtCreateManagedWidget("", xmScrollBarWidgetClass, box, args, n);
19002 
19003   XtAddCallback(prf->rtxt, XmNactivateCallback, prefs_r_callback, (XtPointer)prf);
19004   XtAddCallback(prf->gtxt, XmNactivateCallback, prefs_g_callback, (XtPointer)prf);
19005   XtAddCallback(prf->btxt, XmNactivateCallback, prefs_b_callback, (XtPointer)prf);
19006 
19007   XtAddCallback(prf->rscl, XmNvalueChangedCallback, prefs_call_color_func_callback, (XtPointer)prf);
19008   XtAddCallback(prf->gscl, XmNvalueChangedCallback, prefs_call_color_func_callback, (XtPointer)prf);
19009   XtAddCallback(prf->bscl, XmNvalueChangedCallback, prefs_call_color_func_callback, (XtPointer)prf);
19010 
19011   XtAddCallback(prf->rscl, XmNvalueChangedCallback, prefs_change_callback, NULL);
19012   XtAddCallback(prf->gscl, XmNvalueChangedCallback, prefs_change_callback, NULL);
19013   XtAddCallback(prf->bscl, XmNvalueChangedCallback, prefs_change_callback, NULL);
19014 
19015   prf->color_func = color_func;
19016   free(n1);
19017   return(prf);
19018 }
19019 
19020 
19021 /* ---------------- topic separator ---------------- */
19022 
make_inter_topic_separator(Widget topics)19023 static Widget make_inter_topic_separator(Widget topics)
19024 {
19025   int n;
19026   Arg args[20];
19027   n = 0;
19028   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
19029   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
19030   XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
19031   XtSetArg(args[n], XmNheight, INTER_TOPIC_SPACE); n++;
19032   XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
19033   return(XtCreateManagedWidget("sep", xmSeparatorWidgetClass, topics, args, n));
19034 }
19035 
19036 
19037 /* ---------------- variable separator ---------------- */
19038 
make_inter_variable_separator(Widget topics,Widget top_widget)19039 static Widget make_inter_variable_separator(Widget topics, Widget top_widget)
19040 {
19041   int n;
19042   Arg args[20];
19043   n = 0;
19044   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
19045   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
19046   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
19047   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
19048   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
19049   XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
19050   XtSetArg(args[n], XmNheight, INTER_VARIABLE_SPACE); n++;
19051   XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++;
19052   return(XtCreateManagedWidget("sep", xmSeparatorWidgetClass, topics, args, n));
19053 }
19054 
19055 
19056 /* ---------------- top-level contents label ---------------- */
19057 
make_top_level_label(const char * label,Widget parent)19058 static Widget make_top_level_label(const char *label, Widget parent)
19059 {
19060   int n;
19061   Arg args[20];
19062   n = 0;
19063   XtSetArg(args[n], XmNbackground, ss->light_blue); n++;
19064   XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
19065   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
19066   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
19067   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
19068   XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
19069   XtSetArg(args[n], XmNheight, 32); n++;
19070   return(XtCreateManagedWidget(label, xmLabelWidgetClass, parent, args, n));
19071 }
19072 
19073 
make_top_level_box(Widget topics)19074 static Widget make_top_level_box(Widget topics)
19075 {
19076   Widget frame;
19077   int n;
19078   Arg args[20];
19079   n = 0;
19080   XtSetArg(args[n], XmNbackground, ss->white); n++;
19081   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
19082   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
19083   frame = XtCreateManagedWidget("pref-frame", xmFrameWidgetClass, topics, args, n);
19084 
19085   n = 0;
19086   XtSetArg(args[n], XmNbackground, ss->white); n++;
19087   return(XtCreateManagedWidget("pref-box", xmFormWidgetClass, frame, args, n));
19088 }
19089 
make_inner_label(const char * label,Widget parent,Widget top_widget)19090 static Widget make_inner_label(const char *label, Widget parent, Widget top_widget)
19091 {
19092   int n;
19093   Arg args[20];
19094   n = 0;
19095   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
19096   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
19097   XtSetArg(args[n], XmNtopWidget, top_widget); n++;
19098   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
19099   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
19100   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
19101   XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
19102   XtSetArg(args[n], XmNheight, 32); n++;
19103   return(XtCreateManagedWidget(label, xmLabelWidgetClass, parent, args, n));
19104 }
19105 
19106 
19107 /* ---------------- base buttons ---------------- */
19108 
wm_delete_callback(Widget w,XtPointer context,XtPointer info)19109 static void wm_delete_callback(Widget w, XtPointer context, XtPointer info)
19110 {
19111   clear_prefs_dialog_error();
19112 }
19113 
19114 
preferences_help_callback(Widget w,XtPointer context,XtPointer info)19115 static void preferences_help_callback(Widget w, XtPointer context, XtPointer info)
19116 {
19117   snd_help("preferences",
19118 	   "This dialog sets various global variables. 'Save' then writes the new values \
19119 to ~/.snd_prefs_ruby|forth|s7 so that they take effect the next time you start Snd.  'Revert' resets each variable either to \
19120 its value when the Preferences dialog was started, or to the last saved value.  'Clear' resets each variable to its default value (its \
19121 value when Snd starts, before loading initialization files). 'Help' starts this dialog, and as long as it's active, it will post helpful \
19122 information if the mouse lingers over some variable -- sort of a tooltip that stays out of your way. \
19123 You can also request help on a given topic by clicking the variable name on the far right.",
19124 	   WITH_WORD_WRAP);
19125 }
19126 
19127 
preferences_quit_callback(Widget w,XtPointer context,XtPointer info)19128 static void preferences_quit_callback(Widget w, XtPointer context, XtPointer info)
19129 {
19130   clear_prefs_dialog_error();
19131   if (XmGetFocusWidget(preferences_dialog) == XmMessageBoxGetChild(preferences_dialog, XmDIALOG_CANCEL_BUTTON))
19132     XtUnmanageChild(preferences_dialog);
19133 }
19134 
19135 
prefs_set_dialog_title(const char * filename)19136 static void prefs_set_dialog_title(const char *filename)
19137 {
19138   XmString title;
19139   char *str;
19140   if (filename)
19141     {
19142       if (prefs_saved_filename) free(prefs_saved_filename);
19143       prefs_saved_filename = mus_strdup(filename);
19144     }
19145   if (prefs_saved_filename)
19146     str = mus_format("Preferences%s (saved in %s)\n",
19147 		     (prefs_unsaved) ? "*" : "",
19148 		     prefs_saved_filename);
19149   else str = mus_format("Preferences%s",
19150 			(prefs_unsaved) ? "*" : "");
19151   title = XmStringCreateLocalized(str);
19152   free(str);
19153   XtVaSetValues(preferences_dialog,
19154 		XmNdialogTitle, title,
19155 		NULL);
19156   XmStringFree(title);
19157 }
19158 
19159 
preferences_revert_callback(Widget w,XtPointer context,XtPointer info)19160 static void preferences_revert_callback(Widget w, XtPointer context, XtPointer info)
19161 {
19162   preferences_revert_or_clear(true);
19163 }
19164 
19165 
preferences_clear_callback(Widget w,XtPointer context,XtPointer info)19166 static void preferences_clear_callback(Widget w, XtPointer context, XtPointer info)
19167 {
19168   preferences_revert_or_clear(false);
19169 }
19170 
19171 
19172 #if HAVE_EXTENSION_LANGUAGE
preferences_save_callback(Widget w,XtPointer context,XtPointer info)19173 static void preferences_save_callback(Widget w, XtPointer context, XtPointer info)
19174 {
19175   clear_prefs_dialog_error();
19176   redirect_snd_error_to(post_prefs_dialog_error, NULL);
19177   redirect_snd_warning_to(post_prefs_dialog_error, NULL);
19178   save_prefs();
19179   redirect_snd_error_to(NULL, NULL);
19180   redirect_snd_warning_to(NULL, NULL);
19181 }
19182 #endif
19183 
19184 
19185 
19186 /* ---------------- errors ---------------- */
19187 
clear_prefs_error(Widget w,XtPointer context,XtPointer info)19188 static void clear_prefs_error(Widget w, XtPointer context, XtPointer info)
19189 {
19190   prefs_info *prf = (prefs_info *)context;
19191   XtRemoveCallback(prf->text, XmNvalueChangedCallback, clear_prefs_error, context);
19192   set_label(prf->error, "");
19193 }
19194 
19195 
post_prefs_error(const char * msg,prefs_info * prf)19196 static void post_prefs_error(const char *msg, prefs_info *prf)
19197 {
19198   prf->got_error = true;
19199   set_label(prf->error, msg);
19200   XtAddCallback(prf->text, XmNvalueChangedCallback, clear_prefs_error, (XtPointer)prf);
19201 }
19202 
19203 
va_post_prefs_error(const char * msg,prefs_info * data,...)19204 static void va_post_prefs_error(const char *msg, prefs_info *data, ...)
19205 {
19206   char *buf;
19207   va_list ap;
19208   va_start(ap, data);
19209   buf = vstr(msg, ap);
19210   va_end(ap);
19211   post_prefs_error(buf, data);
19212   free(buf);
19213 }
19214 
19215 
19216 /* ---------------- preferences dialog ---------------- */
19217 
make_preferences_dialog(void)19218 widget_t make_preferences_dialog(void)
19219 {
19220   Arg args[20];
19221   Widget scroller, topics, current_sep;
19222   char *str;
19223   prefs_info *prf;
19224 
19225   if (preferences_dialog)
19226     {
19227       /* I don't think this should reflect current state except when it is created */
19228       if (!(XtIsManaged(preferences_dialog)))
19229 	XtManageChild(preferences_dialog);
19230       else raise_dialog(preferences_dialog);
19231       return(preferences_dialog);
19232     }
19233 
19234   /* -------- base buttons -------- */
19235   {
19236     int n;
19237     XmString title, help, revert, clear, save, go_away;
19238     Widget clear_button, revert_button;
19239 #if HAVE_EXTENSION_LANGUAGE
19240     Widget save_button;
19241 
19242     save = XmStringCreateLocalized((char *)"Save");
19243 #endif
19244 
19245     title = XmStringCreateLocalized((char *)"Preferences");
19246     help = XmStringCreateLocalized((char *)I_HELP);
19247     revert = XmStringCreateLocalized((char *)"Revert");
19248     clear = XmStringCreateLocalized((char *)"Clear");
19249     go_away = XmStringCreateLocalized((char *)I_GO_AWAY);
19250 
19251     n = 0;
19252     XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
19253     XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
19254     XtSetArg(args[n], XmNnoResize, false); n++;
19255     XtSetArg(args[n], XmNtransient, false); n++;
19256     XtSetArg(args[n], XmNcancelLabelString, go_away); n++;
19257     XtSetArg(args[n], XmNhelpLabelString, help); n++;
19258     XtSetArg(args[n], XmNokLabelString, revert); n++;
19259     XtSetArg(args[n], XmNdialogTitle, title); n++;
19260     XtSetArg(args[n], XmNallowShellResize, true); n++;
19261     XtSetArg(args[n], XmNautoUnmanage, false); n++;
19262     {
19263       Dimension width, height;
19264       width = XDisplayWidth(main_display(ss), DefaultScreen(main_display(ss)));
19265       height = XDisplayHeight(main_display(ss), DefaultScreen(main_display(ss)));
19266 
19267       XtSetArg(args[n], XmNwidth, (STARTUP_WIDTH < width) ? (Dimension)STARTUP_WIDTH : ((Dimension)(width - 50))); n++;
19268       XtSetArg(args[n], XmNheight, (STARTUP_HEIGHT < height) ? (Dimension)STARTUP_HEIGHT : ((Dimension)(height - 50))); n++;
19269     }
19270     preferences_dialog = XmCreateTemplateDialog(main_pane(ss), (char *)"preferences", args, n);
19271     revert_button = XmMessageBoxGetChild(preferences_dialog, XmDIALOG_OK_BUTTON);
19272 
19273     n = 0;
19274     XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
19275     XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
19276     clear_button = XtCreateManagedWidget("Clear", xmPushButtonGadgetClass, preferences_dialog, args, n);
19277 
19278 #if HAVE_EXTENSION_LANGUAGE
19279     n = 0;
19280     XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
19281     XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
19282     save_button = XtCreateManagedWidget("Save", xmPushButtonGadgetClass, preferences_dialog, args, n);
19283     XtAddCallback(save_button, XmNactivateCallback, preferences_save_callback, NULL);
19284 #endif
19285 
19286     XtAddCallback(preferences_dialog, XmNcancelCallback, preferences_quit_callback, NULL);
19287     XtAddCallback(preferences_dialog, XmNhelpCallback, preferences_help_callback, NULL);
19288     /* XtAddCallback(preferences_dialog, XmNokCallback, preferences_revert_callback, NULL); */
19289     XtAddCallback(revert_button, XmNactivateCallback, preferences_revert_callback, NULL);
19290     XtAddCallback(clear_button, XmNactivateCallback, preferences_clear_callback, NULL);
19291 
19292     XmStringFree(title);
19293     XmStringFree(help);
19294 #if HAVE_EXTENSION_LANGUAGE
19295     XmStringFree(save);
19296 #endif
19297     XmStringFree(go_away);
19298     XmStringFree(revert);
19299     XmStringFree(clear);
19300 
19301     map_over_children(preferences_dialog, set_main_color_of_widget);
19302 #if HAVE_EXTENSION_LANGUAGE
19303     XtVaSetValues(XmMessageBoxGetChild(preferences_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor,   ss->selection_color, NULL);
19304     XtVaSetValues(XmMessageBoxGetChild(preferences_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color,   NULL);
19305 #endif
19306     XtVaSetValues(XmMessageBoxGetChild(preferences_dialog, XmDIALOG_OK_BUTTON),     XmNarmColor,   ss->selection_color, NULL);
19307     XtVaSetValues(XmMessageBoxGetChild(preferences_dialog, XmDIALOG_HELP_BUTTON),   XmNarmColor,   ss->selection_color, NULL);
19308     XtVaSetValues(XmMessageBoxGetChild(preferences_dialog, XmDIALOG_OK_BUTTON),     XmNbackground, ss->highlight_color,   NULL);
19309     XtVaSetValues(XmMessageBoxGetChild(preferences_dialog, XmDIALOG_HELP_BUTTON),   XmNbackground, ss->highlight_color,   NULL);
19310 
19311     n = 0;
19312     XtSetArg(args[n], XmNbackground, ss->white); n++;
19313     XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
19314     XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
19315     XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
19316     XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
19317     XtSetArg(args[n], XmNbottomWidget, XmMessageBoxGetChild(preferences_dialog, XmDIALOG_SEPARATOR)); n++;
19318     XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); n++;
19319     XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); n++;
19320     scroller = XmCreateScrolledWindow(preferences_dialog, (char *)"pref-scroller", args, n);
19321     XtManageChild(scroller);
19322 
19323     n = attach_all_sides(args, 0);
19324     XtSetArg(args[n], XmNbackground, ss->white); n++;
19325     XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
19326     topics = XtCreateManagedWidget("pref-topics", xmRowColumnWidgetClass, scroller, args, n);
19327     XtVaSetValues(scroller,
19328 		  XmNworkWindow, topics,
19329 		  NULL);
19330   }
19331 
19332   red = rgb_to_color(1.0, 0.0, 0.0);
19333   green = rgb_to_color(0.0, 1.0, 0.0);
19334   blue = rgb_to_color(0.0, 0.0, 1.0);
19335 
19336 
19337   /* ---------------- overall behavior ---------------- */
19338 
19339   {
19340     Widget dpy_box, dpy_label, file_label, cursor_label, key_label;
19341     char *str1, *str2;
19342 
19343     /* ---------------- overall behavior ----------------*/
19344 
19345     dpy_box = make_top_level_box(topics);
19346     dpy_label = make_top_level_label("overall behavior choices", dpy_box);
19347 
19348     current_sep = dpy_label;
19349     str1 = mus_format("%d", ss->init_window_width);
19350     str2 = mus_format("%d", ss->init_window_height);
19351     rts_init_window_width = ss->init_window_width;
19352     rts_init_window_height = ss->init_window_height;
19353     prf = prefs_row_with_two_texts("start up size", S_window_width,
19354 				   "width:", str1, "height:", str2, 6,
19355 				   dpy_box, current_sep,
19356 				   startup_size_text);
19357     remember_pref(prf, reflect_init_window_size, save_init_window_size, help_init_window_size, clear_init_window_size, revert_init_window_size);
19358     free(str2);
19359     free(str1);
19360 
19361     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19362     prf = prefs_row_with_toggle("ask before overwriting anything", S_ask_before_overwrite,
19363 				rts_ask_before_overwrite = ask_before_overwrite(ss),
19364 				dpy_box, current_sep,
19365 				overwrite_toggle);
19366     remember_pref(prf, reflect_ask_before_overwrite, save_ask_before_overwrite, help_ask_before_overwrite, NULL, revert_ask_before_overwrite);
19367 
19368     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19369     prf = prefs_row_with_toggle("ask about unsaved edits before exiting", S_ask_about_unsaved_edits,
19370 				rts_unsaved_edits = ask_about_unsaved_edits(ss),
19371 				dpy_box, current_sep,
19372 				unsaved_edits_toggle);
19373     remember_pref(prf, reflect_unsaved_edits, save_unsaved_edits, help_unsaved_edits, clear_unsaved_edits, revert_unsaved_edits);
19374 
19375     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19376     prf = prefs_row_with_toggle("include thumbnail graph in upper right corner", S_with_inset_graph,
19377 				rts_with_inset_graph = with_inset_graph(ss),
19378 				dpy_box, current_sep,
19379 				with_inset_graph_toggle);
19380     remember_pref(prf, reflect_with_inset_graph, save_with_inset_graph, help_inset_graph,
19381 		  clear_with_inset_graph, revert_with_inset_graph);
19382 
19383     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19384     prf = prefs_row_with_toggle("resize main window as sounds open and close", S_auto_resize,
19385 				rts_auto_resize = auto_resize(ss),
19386 				dpy_box, current_sep,
19387 				resize_toggle);
19388     remember_pref(prf, reflect_auto_resize, save_auto_resize, help_auto_resize, NULL, revert_auto_resize);
19389 
19390     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19391     prf = prefs_row_with_toggle("pointer focus", S_with_pointer_focus,
19392 				rts_with_pointer_focus = with_pointer_focus(ss),
19393 				dpy_box, current_sep,
19394 				with_pointer_focus_toggle);
19395     remember_pref(prf, reflect_with_pointer_focus, save_with_pointer_focus, help_pointer_focus,
19396 		  clear_with_pointer_focus, revert_with_pointer_focus);
19397 
19398     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19399     rts_sync_style = sync_style(ss);
19400     prf = prefs_row_with_two_toggles("operate on all channels together", S_sync,
19401 				     "within each sound", rts_sync_style == SYNC_BY_SOUND,
19402 				     "across all sounds", rts_sync_style == SYNC_ALL,
19403 				     dpy_box, current_sep,
19404 				     sync1_choice, sync2_choice);
19405     remember_pref(prf, reflect_sync_style, save_sync_style, help_sync_style, clear_sync_style, revert_sync_style);
19406 
19407     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19408     rts_remember_sound_state = remember_sound_state(ss);
19409     prf = prefs_row_with_toggle("restore a sound's state if reopened later", S_remember_sound_state,
19410 				rts_remember_sound_state,
19411 				dpy_box, current_sep,
19412 				toggle_remember_sound_state);
19413     remember_pref(prf, reflect_remember_sound_state, save_remember_sound_state, help_remember_sound_state,
19414 		  clear_remember_sound_state, revert_remember_sound_state);
19415 
19416     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19417     prf = prefs_row_with_toggle("show the control panel upon opening a sound", S_show_controls,
19418 				rts_show_controls = in_show_controls(ss),
19419 				dpy_box, current_sep,
19420 				controls_toggle);
19421     remember_pref(prf, reflect_show_controls, save_show_controls, help_show_controls, NULL, revert_show_controls);
19422 
19423     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19424     include_peak_env_directory = mus_strdup(peak_env_dir(ss));
19425     rts_peak_env_directory = mus_strdup(include_peak_env_directory);
19426     include_peak_envs = find_peak_envs();
19427     rts_peak_envs = include_peak_envs;
19428     prf = prefs_row_with_toggle_with_text("save peak envs to speed up initial display", S_peak_env_dir,
19429 					  include_peak_envs,
19430 					  "directory:", include_peak_env_directory, 25,
19431 					  dpy_box, current_sep,
19432 					  peak_envs_toggle, peak_envs_text);
19433     remember_pref(prf, reflect_peak_envs, save_peak_envs, help_peak_envs, clear_peak_envs, revert_peak_envs);
19434 
19435     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19436     str = mus_format("%d", rts_max_regions = max_regions(ss));
19437     prf = prefs_row_with_toggle_with_text("selection creates an associated region", S_selection_creates_region,
19438 					  rts_selection_creates_region = selection_creates_region(ss),
19439 					  "max regions:", str, 5,
19440 					  dpy_box, current_sep,
19441 					  selection_creates_region_toggle, max_regions_text);
19442     remember_pref(prf, reflect_selection_creates_region, save_selection_creates_region, help_selection_creates_region, NULL, revert_selection_creates_region);
19443     free(str);
19444 
19445     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19446     rts_with_toolbar = with_toolbar(ss);
19447     prf = prefs_row_with_toggle("include a toolbar", S_with_toolbar,
19448 				rts_with_toolbar,
19449 				dpy_box, current_sep,
19450 				toggle_with_toolbar);
19451     remember_pref(prf, reflect_with_toolbar, save_with_toolbar, help_with_toolbar, clear_with_toolbar, revert_with_toolbar);
19452 
19453     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19454     rts_with_tooltips = with_tooltips(ss);
19455     prf = prefs_row_with_toggle("enable tooltips", S_with_tooltips,
19456 				rts_with_tooltips,
19457 				dpy_box, current_sep,
19458 				toggle_with_tooltips);
19459     remember_pref(prf, reflect_with_tooltips, save_with_tooltips, help_with_tooltips, clear_with_tooltips, revert_with_tooltips);
19460 
19461 
19462 
19463     /* ---------------- file options ---------------- */
19464 
19465     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19466     file_label = make_inner_label("  file options", dpy_box, current_sep);
19467 
19468     rts_load_path = find_sources();
19469     prf = prefs_row_with_text("directory containing Snd's " Xen_language " files", "load path",
19470 			      rts_load_path,
19471 			      dpy_box, file_label,
19472 			      load_path_text);
19473     remember_pref(prf, reflect_load_path, NULL, help_load_path, clear_load_path, revert_load_path);
19474     load_path_text_widget = prf->text;
19475 
19476     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19477     prf = prefs_row_with_toggle("display only sound files in various file lists", S_just_sounds,
19478 				rts_just_sounds = just_sounds(ss),
19479 				dpy_box, current_sep,
19480 				just_sounds_toggle);
19481     remember_pref(prf, prefs_reflect_just_sounds, save_just_sounds, help_just_sounds, NULL, revert_just_sounds);
19482 
19483     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19484     rts_temp_dir = mus_strdup(temp_dir(ss));
19485     prf = prefs_row_with_text("directory for temporary files", S_temp_dir,
19486 			      temp_dir(ss),
19487 			      dpy_box, current_sep,
19488 			      temp_dir_text);
19489     remember_pref(prf, reflect_temp_dir, save_temp_dir, help_temp_dir, NULL, revert_temp_dir);
19490 
19491     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19492     rts_save_dir = mus_strdup(save_dir(ss));
19493     prf = prefs_row_with_text("directory for save-state files", S_save_dir,
19494 			      save_dir(ss),
19495 			      dpy_box, current_sep,
19496 			      save_dir_text);
19497     remember_pref(prf, reflect_save_dir, save_save_dir, help_save_dir, NULL, revert_save_dir);
19498 
19499     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19500     rts_save_state_file = mus_strdup(save_state_file(ss));
19501     prf = prefs_row_with_text("default save-state filename", S_save_state_file,
19502 			      save_state_file(ss),
19503 			      dpy_box, current_sep,
19504 			      save_state_file_text);
19505     remember_pref(prf, reflect_save_state_file, save_save_state_file, help_save_state_file, NULL, revert_save_state_file);
19506 
19507 #if HAVE_LADSPA
19508     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19509     rts_ladspa_dir = mus_strdup(ladspa_dir(ss));
19510     prf = prefs_row_with_text("directory for ladspa plugins", S_ladspa_dir,
19511 			      ladspa_dir(ss),
19512 			      dpy_box, current_sep,
19513 			      ladspa_dir_text);
19514     remember_pref(prf, reflect_ladspa_dir, save_ladspa_dir, help_ladspa_dir, NULL, revert_ladspa_dir);
19515 #endif
19516 
19517     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19518     rts_vf_directory = mus_strdup(view_files_find_any_directory());
19519     prf = prefs_row_with_text("directory for view-files dialog", S_add_directory_to_view_files_list,
19520 			      rts_vf_directory,
19521 			      dpy_box, current_sep,
19522 			      view_files_directory_text);
19523     remember_pref(prf, reflect_view_files_directory, save_view_files_directory, help_view_files_directory, NULL, revert_view_files_directory);
19524 
19525     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19526     rts_html_program = mus_strdup(html_program(ss));
19527     prf = prefs_row_with_text("external program to read HTML files via snd-help", S_html_program,
19528 			      html_program(ss),
19529 			      dpy_box, current_sep,
19530 			      html_program_text);
19531     remember_pref(prf, reflect_html_program, save_html_program, help_html_program, NULL, revert_html_program);
19532     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19533 
19534     rts_default_output_chans = default_output_chans(ss);
19535     prf = prefs_row_with_radio_box("default new sound attributes: chans", S_default_output_chans,
19536 				   output_chan_choices, NUM_OUTPUT_CHAN_CHOICES, -1,
19537 				   dpy_box, current_sep,
19538 				   default_output_chans_choice);
19539     remember_pref(prf, reflect_default_output_chans, save_default_output_chans, help_default_output_chans, NULL, revert_default_output_chans);
19540     reflect_default_output_chans(prf);
19541 
19542     rts_default_output_srate = default_output_srate(ss);
19543     prf = prefs_row_with_radio_box("srate", S_default_output_srate,
19544 				   output_srate_choices, NUM_OUTPUT_SRATE_CHOICES, -1,
19545 				   dpy_box, prf->label,
19546 				   default_output_srate_choice);
19547     remember_pref(prf, reflect_default_output_srate, save_default_output_srate, help_default_output_srate, NULL, revert_default_output_srate);
19548     reflect_default_output_srate(prf);
19549 
19550     rts_default_output_header_type = default_output_header_type(ss);
19551     prf = prefs_row_with_radio_box("header type", S_default_output_header_type,
19552 				   output_header_type_choices, NUM_OUTPUT_HEADER_TYPE_CHOICES, -1,
19553 				   dpy_box, prf->label,
19554 				   default_output_header_type_choice);
19555     output_header_type_prf = prf;
19556     remember_pref(prf, reflect_default_output_header_type, save_default_output_header_type, help_default_output_header_type, NULL, revert_default_output_header_type);
19557 
19558     rts_default_output_sample_type = default_output_sample_type(ss);
19559     prf = prefs_row_with_radio_box("sample type", S_default_output_sample_type,
19560 				   output_sample_type_choices, NUM_OUTPUT_SAMPLE_TYPE_CHOICES, -1,
19561 				   dpy_box, prf->label,
19562 				   default_output_sample_type_choice);
19563     output_sample_type_prf = prf;
19564     remember_pref(prf, reflect_default_output_sample_type, save_default_output_sample_type, help_default_output_sample_type, NULL, revert_default_output_sample_type);
19565     reflect_default_output_header_type(output_header_type_prf);
19566     reflect_default_output_sample_type(output_sample_type_prf);
19567 
19568     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19569     {
19570       int i, srate = 0, chans = 0;
19571       mus_sample_t sample_type = MUS_UNKNOWN_SAMPLE;
19572       mus_header_raw_defaults(&srate, &chans, &sample_type);
19573       rts_raw_chans = chans;
19574       rts_raw_srate = srate;
19575       rts_raw_sample_type = sample_type;
19576       str = mus_format("%d", chans);
19577       str1 = mus_format("%d", srate);
19578       raw_sample_type_choices = (char **)calloc(MUS_NUM_SAMPLES - 1, sizeof(char *));
19579       for (i = 1; i < MUS_NUM_SAMPLES; i++)
19580 	raw_sample_type_choices[i - 1] = raw_sample_type_to_string((mus_sample_t)i); /* skip MUS_UNKNOWN_SAMPLE = 0 */
19581       prf = prefs_row_with_text("default raw sound attributes: chans", S_mus_header_raw_defaults, str,
19582 				dpy_box, current_sep,
19583 				raw_chans_choice);
19584       remember_pref(prf, reflect_raw_chans, save_raw_chans, help_raw_chans, NULL, revert_raw_chans);
19585 
19586       prf = prefs_row_with_text("srate", S_mus_header_raw_defaults, str1,
19587 				dpy_box, prf->label,
19588 				raw_srate_choice);
19589       remember_pref(prf, reflect_raw_srate, save_raw_srate, help_raw_srate, NULL, revert_raw_srate);
19590 
19591       prf = prefs_row_with_list("sample type", S_mus_header_raw_defaults, raw_sample_type_choices[sample_type - 1],
19592 				(const char **)raw_sample_type_choices, MUS_NUM_SAMPLES - 1,
19593 				dpy_box, prf->label,
19594 				raw_sample_type_from_text,
19595 				NULL, NULL,
19596 				raw_sample_type_from_menu);
19597       remember_pref(prf, reflect_raw_sample_type, save_raw_sample_type, help_raw_sample_type, NULL, revert_raw_sample_type);
19598       free(str);
19599       free(str1);
19600     }
19601 
19602 
19603     /* ---------------- additional keys ---------------- */
19604 
19605     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19606     key_label = make_inner_label("  additional keys", dpy_box, current_sep);
19607 
19608     {
19609       key_info *ki;
19610 
19611       ki = find_prefs_key("play-from-cursor");
19612       prf = prefs_row_with_text_and_three_toggles("play all chans from cursor", S_play,
19613 						  "key:", 8, "ctrl:", "meta:",  "C-x:",
19614 						  ki->key, ki->c, ki->m, ki->x,
19615 						  dpy_box, key_label,
19616 						  bind_play_from_cursor);
19617       remember_pref(prf, reflect_play_from_cursor, save_pfc, help_play_from_cursor, clear_play_from_cursor, NULL);
19618       free(ki);
19619 
19620       current_sep = make_inter_variable_separator(dpy_box, prf->label);
19621       ki = find_prefs_key("show-all");
19622       prf = prefs_row_with_text_and_three_toggles("show entire sound", S_x_bounds,
19623 						  "key:", 8, "ctrl:", "meta:",  "C-x:",
19624 						  ki->key, ki->c, ki->m, ki->x,
19625 						  dpy_box, current_sep,
19626 						  bind_show_all);
19627       remember_pref(prf, reflect_show_all, save_show_all, help_show_all, clear_show_all, NULL);
19628       free(ki);
19629 
19630       current_sep = make_inter_variable_separator(dpy_box, prf->label);
19631       ki = find_prefs_key("select-all");
19632       prf = prefs_row_with_text_and_three_toggles("select entire sound", S_select_all,
19633 						  "key:", 8, "ctrl:", "meta:",  "C-x:",
19634 						  ki->key, ki->c, ki->m, ki->x,
19635 						  dpy_box, current_sep,
19636 						  bind_select_all);
19637       remember_pref(prf, reflect_select_all, save_select_all, help_select_all, clear_select_all, NULL);
19638       free(ki);
19639 
19640       current_sep = make_inter_variable_separator(dpy_box, prf->label);
19641       ki = find_prefs_key("show-selection");
19642       prf = prefs_row_with_text_and_three_toggles("show current selection", "show-selection",
19643 						  "key:", 8, "ctrl:", "meta:",  "C-x:",
19644 						  ki->key, ki->c, ki->m, ki->x,
19645 						  dpy_box, current_sep,
19646 						  bind_show_selection);
19647       remember_pref(prf, reflect_show_selection, save_show_selection, help_show_selection, clear_show_selection, NULL);
19648       free(ki);
19649 
19650       current_sep = make_inter_variable_separator(dpy_box, prf->label);
19651       ki = find_prefs_key("revert-sound");
19652       prf = prefs_row_with_text_and_three_toggles("undo all edits (revert)", S_revert_sound,
19653 						  "key:", 8, "ctrl:", "meta:",  "C-x:",
19654 						  ki->key, ki->c, ki->m, ki->x,
19655 						  dpy_box, current_sep,
19656 						  bind_revert);
19657       remember_pref(prf, reflect_revert, save_revert, help_revert, clear_revert_sound, NULL);
19658       free(ki);
19659 
19660       current_sep = make_inter_variable_separator(dpy_box, prf->label);
19661       ki = find_prefs_key("exit");
19662       prf = prefs_row_with_text_and_three_toggles("exit from Snd", S_exit,
19663 						  "key:", 8, "ctrl:", "meta:",  "C-x:",
19664 						  ki->key, ki->c, ki->m, ki->x,
19665 						  dpy_box, current_sep,
19666 						  bind_exit);
19667       remember_pref(prf, reflect_exit, save_exit, help_exit, clear_exit, NULL);
19668       free(ki);
19669 
19670       current_sep = make_inter_variable_separator(dpy_box, prf->label);
19671       ki = find_prefs_key("goto-maxamp");
19672       prf = prefs_row_with_text_and_three_toggles("move cursor to channel's maximum sample", S_maxamp_position,
19673 						  "key:", 8, "ctrl:", "meta:",  "C-x:",
19674 						  ki->key, ki->c, ki->m, ki->x,
19675 						  dpy_box, current_sep,
19676 						  bind_goto_maxamp);
19677       remember_pref(prf, reflect_goto_maxamp, save_goto_maxamp, help_goto_maxamp, clear_goto_maxamp, NULL);
19678       free(ki);
19679 
19680     }
19681 
19682 
19683     /* ---------------- cursor options ---------------- */
19684 
19685     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19686     cursor_label = make_inner_label("  cursor options", dpy_box, current_sep);
19687 
19688     prf = prefs_row_with_toggle("report cursor location as it moves", S_with_verbose_cursor,
19689 				rts_with_verbose_cursor = with_verbose_cursor(ss),
19690 				dpy_box, cursor_label,
19691 				with_verbose_cursor_toggle);
19692     remember_pref(prf, reflect_with_verbose_cursor, save_with_verbose_cursor, help_with_verbose_cursor, NULL, revert_with_verbose_cursor);
19693 
19694     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19695     {
19696       char *str1;
19697       str = mus_format("%.2f", rts_cursor_update_interval = cursor_update_interval(ss));
19698       str1 = mus_format("%d", rts_cursor_location_offset = cursor_location_offset(ss));
19699       prf = prefs_row_with_toggle_with_two_texts("track current location while playing", S_with_tracking_cursor,
19700 						 (rts_with_tracking_cursor = with_tracking_cursor(ss)),
19701 						 "update:", str,
19702 						 "offset:", str1, 8,
19703 						 dpy_box, current_sep,
19704 						 with_tracking_cursor_toggle,
19705 						 cursor_location_text);
19706       remember_pref(prf, reflect_with_tracking_cursor, save_with_tracking_cursor, help_with_tracking_cursor, NULL, revert_with_tracking_cursor);
19707       free(str);
19708       free(str1);
19709     }
19710 
19711     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19712     str = mus_format("%d", rts_cursor_size = cursor_size(ss));
19713     prf = prefs_row_with_number("size", S_cursor_size,
19714 				str, 4,
19715 				dpy_box, current_sep,
19716 				cursor_size_up, cursor_size_down, cursor_size_from_text);
19717     remember_pref(prf, reflect_cursor_size, save_cursor_size, help_cursor_size, NULL, revert_cursor_size);
19718     free(str);
19719     if (cursor_size(ss) <= 0) XtSetSensitive(prf->arrow_down, false);
19720 
19721     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19722     prf = prefs_row_with_radio_box("shape", S_cursor_style,
19723 				   cursor_styles, NUM_CURSOR_STYLES,
19724 				   rts_cursor_style = cursor_style(ss),
19725 				   dpy_box, current_sep,
19726 				   cursor_style_choice);
19727     remember_pref(prf, reflect_cursor_style, save_cursor_style, help_cursor_style, NULL, revert_cursor_style);
19728 
19729     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19730     prf = prefs_row_with_radio_box("tracking cursor shape", S_tracking_cursor_style,
19731 				   cursor_styles, NUM_CURSOR_STYLES,
19732 				   rts_tracking_cursor_style = tracking_cursor_style(ss),
19733 				   dpy_box, current_sep,
19734 				   tracking_cursor_style_choice);
19735     remember_pref(prf, reflect_tracking_cursor_style, save_tracking_cursor_style, help_tracking_cursor_style, NULL, revert_tracking_cursor_style);
19736 
19737     current_sep = make_inter_variable_separator(dpy_box, prf->label);
19738     saved_cursor_color = ss->cursor_color;
19739     prf = prefs_color_selector_row("color", S_cursor_color, ss->cursor_color,
19740 				   dpy_box, current_sep,
19741 				   cursor_color_func);
19742     remember_pref(prf, NULL, save_cursor_color, help_cursor_color, clear_cursor_color, revert_cursor_color);
19743 
19744 
19745     /* ---------------- (overall) colors ---------------- */
19746 
19747     current_sep = make_inter_variable_separator(dpy_box, prf->rscl);
19748     cursor_label = make_inner_label("  colors", dpy_box, current_sep);
19749 
19750     saved_basic_color = ss->basic_color;
19751     prf = prefs_color_selector_row("main background color", S_basic_color, ss->basic_color,
19752 				   dpy_box, cursor_label,
19753 				   basic_color_func);
19754     remember_pref(prf, NULL, save_basic_color, help_basic_color, clear_basic_color, revert_basic_color);
19755 
19756     current_sep = make_inter_variable_separator(dpy_box, prf->rscl);
19757     saved_highlight_color = ss->highlight_color;
19758     prf = prefs_color_selector_row("main highlight color", S_highlight_color, ss->highlight_color,
19759 				   dpy_box, current_sep,
19760 				   highlight_color_func);
19761     remember_pref(prf, NULL, save_highlight_color, help_highlight_color, clear_highlight_color, revert_highlight_color);
19762 
19763     current_sep = make_inter_variable_separator(dpy_box, prf->rscl);
19764     saved_position_color = ss->position_color;
19765     prf = prefs_color_selector_row("second highlight color", S_position_color, ss->position_color,
19766 				   dpy_box, current_sep,
19767 				   position_color_func);
19768     remember_pref(prf, NULL, save_position_color, help_position_color, clear_position_color, revert_position_color);
19769 
19770     current_sep = make_inter_variable_separator(dpy_box, prf->rscl);
19771     saved_zoom_color = ss->zoom_color;
19772     prf = prefs_color_selector_row("third highlight color", S_zoom_color, ss->zoom_color,
19773 				   dpy_box, current_sep,
19774 				   zoom_color_func);
19775     remember_pref(prf, NULL, save_zoom_color, help_zoom_color, clear_zoom_color, revert_zoom_color);
19776   }
19777 
19778   current_sep = make_inter_topic_separator(topics);
19779 
19780   /* -------- graphs -------- */
19781   {
19782     Widget grf_box, grf_label, colgrf_label;
19783 
19784     /* ---------------- graph options ---------------- */
19785 
19786     grf_box = make_top_level_box(topics);
19787     grf_label = make_top_level_label("graph options", grf_box);
19788 
19789     prf = prefs_row_with_radio_box("how to connect the dots", S_graph_style,
19790 				   graph_styles, NUM_GRAPH_STYLES,
19791 				   rts_graph_style = graph_style(ss),
19792 				   grf_box, grf_label,
19793 				   graph_style_choice);
19794     remember_pref(prf, reflect_graph_style, save_graph_style, help_graph_style, NULL, revert_graph_style);
19795 
19796     current_sep = make_inter_variable_separator(grf_box, prf->label);
19797     str = mus_format("%d", rts_dot_size = dot_size(ss));
19798     prf = prefs_row_with_number("dot size", S_dot_size,
19799 				str, 4,
19800 				grf_box, current_sep,
19801 				dot_size_up, dot_size_down, dot_size_from_text);
19802     remember_pref(prf, reflect_dot_size, save_dot_size, help_dot_size, NULL, revert_dot_size);
19803     free(str);
19804     if (dot_size(ss) <= 0) XtSetSensitive(prf->arrow_down, false);
19805 
19806     current_sep = make_inter_variable_separator(grf_box, prf->label);
19807     rts_initial_beg = initial_beg(ss);
19808     rts_initial_dur = initial_dur(ss);
19809     str = mus_format("%.2f : %.2f", rts_initial_beg, rts_initial_dur);
19810     prf = prefs_row_with_text_with_toggle("initial graph x bounds", S_initial_graph_hook,
19811 					  (rts_full_duration = show_full_duration(ss)),
19812 					  "show full duration", str, 16,
19813 					  grf_box, current_sep,
19814 					  initial_bounds_toggle,
19815 					  initial_bounds_text);
19816     free(str);
19817     remember_pref(prf, reflect_initial_bounds, save_initial_bounds, help_initial_bounds, clear_initial_bounds, revert_initial_bounds);
19818 
19819     current_sep = make_inter_variable_separator(grf_box, prf->label);
19820     prf = prefs_row_with_radio_box("how to layout multichannel graphs", S_channel_style,
19821 				   channel_styles, NUM_CHANNEL_STYLES,
19822 				   rts_channel_style = channel_style(ss),
19823 				   grf_box, current_sep,
19824 				   channel_style_choice);
19825     remember_pref(prf, reflect_channel_style, save_channel_style, help_channel_style, NULL, revert_channel_style);
19826 
19827     current_sep = make_inter_variable_separator(grf_box, prf->label);
19828     prf = prefs_row_with_toggle("layout wave and fft graphs horizontally", S_graphs_horizontal,
19829 				rts_graphs_horizontal = graphs_horizontal(ss),
19830 				grf_box, current_sep,
19831 				graphs_horizontal_toggle);
19832     remember_pref(prf, reflect_graphs_horizontal, save_graphs_horizontal, help_graphs_horizontal, NULL, revert_graphs_horizontal);
19833 
19834     current_sep = make_inter_variable_separator(grf_box, prf->label);
19835    prf = prefs_row_with_toggle("include y=0 line in sound graphs", S_show_y_zero,
19836 				rts_show_y_zero = show_y_zero(ss),
19837 				grf_box, current_sep,
19838 				y_zero_toggle);
19839     remember_pref(prf, reflect_show_y_zero, save_show_y_zero, help_show_y_zero, NULL, revert_show_y_zero);
19840 
19841     current_sep = make_inter_variable_separator(grf_box, prf->label);
19842     rts_show_grid = show_grid(ss);
19843     prf = prefs_row_with_toggle("include a grid in sound graphs", S_show_grid,
19844 				rts_show_grid == WITH_GRID,
19845 				grf_box, current_sep,
19846 				grid_toggle);
19847     remember_pref(prf, reflect_show_grid, save_show_grid, help_show_grid, NULL, revert_show_grid);
19848 
19849     current_sep = make_inter_variable_separator(grf_box, prf->label);
19850     prf = prefs_row_with_scale("grid density", S_grid_density,
19851 			       2.0, rts_grid_density = grid_density(ss),
19852 			       grf_box, current_sep,
19853 			       grid_density_scale_callback, grid_density_text_callback);
19854     remember_pref(prf, reflect_grid_density, save_grid_density, help_grid_density, NULL, revert_grid_density);
19855 
19856     current_sep = make_inter_variable_separator(grf_box, prf->label);
19857     rts_show_axes = show_axes(ss);
19858     prf = prefs_row_with_list("what axes to display", S_show_axes, show_axes_choices[(int)rts_show_axes],
19859 			      show_axes_choices, NUM_SHOW_AXES,
19860 			      grf_box, current_sep,
19861 			      show_axes_from_text,
19862 			      NULL, NULL,
19863 			      show_axes_from_menu);
19864     remember_pref(prf, reflect_show_axes, save_show_axes, help_show_axes, clear_show_axes, revert_show_axes);
19865 
19866     current_sep = make_inter_variable_separator(grf_box, prf->label);
19867     rts_x_axis_style = x_axis_style(ss);
19868     prf = prefs_row_with_list("time division", S_x_axis_style, x_axis_styles[(int)rts_x_axis_style],
19869 			      x_axis_styles, NUM_X_AXIS_STYLES,
19870 			      grf_box, current_sep,
19871 			      x_axis_style_from_text,
19872 			      NULL, NULL,
19873 			      x_axis_style_from_menu);
19874     remember_pref(prf, reflect_x_axis_style, save_x_axis_style, help_x_axis_style, clear_x_axis_style, revert_x_axis_style);
19875 
19876     current_sep = make_inter_variable_separator(grf_box, prf->label);
19877     prf = prefs_row_with_toggle("include smpte info", "show-smpte-label",
19878 				rts_with_smpte_label = with_smpte_label(ss),
19879 				grf_box, current_sep,
19880 				smpte_toggle);
19881     remember_pref(prf, reflect_smpte, save_smpte, help_smpte, clear_smpte, revert_smpte);
19882 
19883 
19884     /* ---------------- (graph) colors ---------------- */
19885 
19886     current_sep = make_inter_variable_separator(grf_box, prf->label);
19887     colgrf_label = make_inner_label("  colors", grf_box, current_sep);
19888 
19889     saved_data_color = ss->data_color;
19890     prf = prefs_color_selector_row("unselected data (waveform) color", S_data_color, ss->data_color,
19891 				   grf_box, colgrf_label,
19892 				   data_color_func);
19893     remember_pref(prf, NULL, save_data_color, help_data_color, clear_data_color, revert_data_color);
19894 
19895     current_sep = make_inter_variable_separator(grf_box, prf->rscl);
19896     saved_graph_color = ss->graph_color;
19897     prf = prefs_color_selector_row("unselected graph (background) color", S_graph_color, ss->graph_color,
19898 				   grf_box, current_sep,
19899 				   graph_color_func);
19900     remember_pref(prf, NULL, save_graph_color, help_graph_color, clear_graph_color, revert_graph_color);
19901 
19902     current_sep = make_inter_variable_separator(grf_box, prf->rscl);
19903     saved_selected_data_color = ss->selected_data_color;
19904     prf = prefs_color_selector_row("selected channel data (waveform) color", S_selected_data_color, ss->selected_data_color,
19905 				   grf_box, current_sep,
19906 				   selected_data_color_func);
19907     remember_pref(prf, NULL, save_selected_data_color, help_selected_data_color, clear_selected_data_color, revert_selected_data_color);
19908 
19909     current_sep = make_inter_variable_separator(grf_box, prf->rscl);
19910     saved_selected_graph_color = ss->selected_graph_color;
19911     prf = prefs_color_selector_row("selected channel graph (background) color", S_selected_graph_color, ss->selected_graph_color,
19912 				   grf_box, current_sep,
19913 				   selected_graph_color_func);
19914     remember_pref(prf, NULL, save_selected_graph_color, help_selected_graph_color, clear_selected_graph_color, revert_selected_graph_color);
19915 
19916     current_sep = make_inter_variable_separator(grf_box, prf->rscl);
19917     saved_selection_color = ss->selection_color;
19918     prf = prefs_color_selector_row("selection color", S_selection_color, ss->selection_color,
19919 				   grf_box, current_sep,
19920 				   selection_color_func);
19921     remember_pref(prf, NULL, save_selection_color, help_selection_color, clear_selection_color, revert_selection_color);
19922 
19923     /* ---------------- (graph) fonts ---------------- */
19924 
19925     current_sep = make_inter_variable_separator(grf_box, prf->rscl);
19926     colgrf_label = make_inner_label("  fonts", grf_box, current_sep);
19927 
19928     rts_axis_label_font = mus_strdup(axis_label_font(ss));
19929     prf = prefs_row_with_text("axis label font", S_axis_label_font,
19930 			      axis_label_font(ss),
19931 			      grf_box, colgrf_label,
19932 			      axis_label_font_text);
19933     remember_pref(prf, reflect_axis_label_font, save_axis_label_font, help_axis_label_font, clear_axis_label_font, revert_axis_label_font);
19934 
19935     current_sep = make_inter_variable_separator(grf_box, prf->label);
19936     rts_axis_numbers_font = mus_strdup(axis_numbers_font(ss));
19937     prf = prefs_row_with_text("axis number font", S_axis_numbers_font,
19938 			      axis_numbers_font(ss),
19939 			      grf_box, current_sep,
19940 			      axis_numbers_font_text);
19941     remember_pref(prf, reflect_axis_numbers_font, save_axis_numbers_font, help_axis_numbers_font, clear_axis_numbers_font, revert_axis_numbers_font);
19942 
19943     current_sep = make_inter_variable_separator(grf_box, prf->label);
19944     rts_peaks_font = mus_strdup(peaks_font(ss));
19945     prf = prefs_row_with_text("fft peaks font", S_peaks_font,
19946 			      peaks_font(ss),
19947 			      grf_box, current_sep,
19948 			      peaks_font_text);
19949     remember_pref(prf, reflect_peaks_font, save_peaks_font, help_peaks_font, clear_peaks_font, revert_peaks_font);
19950 
19951     current_sep = make_inter_variable_separator(grf_box, prf->label);
19952     rts_bold_peaks_font = mus_strdup(bold_peaks_font(ss));
19953     prf = prefs_row_with_text("fft peaks bold font (for main peaks)", S_bold_peaks_font,
19954 			      bold_peaks_font(ss),
19955 			      grf_box, current_sep,
19956 			      bold_peaks_font_text);
19957     remember_pref(prf, reflect_bold_peaks_font, save_bold_peaks_font, help_bold_peaks_font, clear_bold_peaks_font, revert_bold_peaks_font);
19958 
19959     current_sep = make_inter_variable_separator(grf_box, prf->label);
19960     rts_tiny_font = mus_strdup(tiny_font(ss));
19961     prf = prefs_row_with_text("tiny font (for various annotations)", S_peaks_font,
19962 			      tiny_font(ss),
19963 			      grf_box, current_sep,
19964 			      tiny_font_text);
19965     remember_pref(prf, reflect_tiny_font, save_tiny_font, help_tiny_font, clear_tiny_font, revert_tiny_font);
19966   }
19967 
19968   current_sep = make_inter_topic_separator(topics);
19969 
19970   /* -------- transform -------- */
19971   {
19972     Widget fft_box, fft_label;
19973 
19974     /* ---------------- transform options ---------------- */
19975 
19976     fft_box = make_top_level_box(topics);
19977     fft_label = make_top_level_label("transform options", fft_box);
19978 
19979     rts_fft_size = transform_size(ss);
19980     str = mus_format("%" print_mus_long, rts_fft_size);
19981     prf = prefs_row_with_number("size", S_transform_size,
19982 				str, 12,
19983 				fft_box, fft_label,
19984 				fft_size_up, fft_size_down, fft_size_from_text);
19985     remember_pref(prf, reflect_fft_size, save_fft_size, help_fft_size, NULL, revert_fft_size);
19986     free(str);
19987     if (transform_size(ss) <= 2) XtSetSensitive(prf->arrow_down, false);
19988 
19989     current_sep = make_inter_variable_separator(fft_box, prf->label);
19990     prf = prefs_row_with_radio_box("transform graph choice", S_transform_graph_type,
19991 				   transform_graph_types, NUM_TRANSFORM_GRAPH_TYPES,
19992 				   rts_transform_graph_type = transform_graph_type(ss),
19993 				   fft_box, current_sep,
19994 				   transform_graph_type_choice);
19995     remember_pref(prf, reflect_transform_graph_type, save_transform_graph_type, help_transform_graph_type, NULL, revert_transform_graph_type);
19996 
19997     current_sep = make_inter_variable_separator(fft_box, prf->label);
19998     rts_transform_type = transform_type(ss);
19999     prf = prefs_row_with_list("transform", S_transform_type, transform_types[rts_transform_type],
20000 			      transform_types, NUM_BUILTIN_TRANSFORM_TYPES,
20001 			      fft_box, current_sep,
20002 			      transform_type_from_text,
20003 			      transform_type_completer, NULL,
20004 			      transform_type_from_menu);
20005     remember_pref(prf, reflect_transform_type, save_transform_type, help_transform_type, clear_transform_type, revert_transform_type);
20006 
20007     current_sep = make_inter_variable_separator(fft_box, prf->label);
20008     rts_fft_window = fft_window(ss);
20009     prf = prefs_row_with_list("data window", S_fft_window, mus_fft_window_name(rts_fft_window),
20010 			      mus_fft_window_names(), MUS_NUM_FFT_WINDOWS,
20011 			      fft_box, current_sep,
20012 			      fft_window_from_text,
20013 			      fft_window_completer, NULL,
20014 			      fft_window_from_menu);
20015     remember_pref(prf, reflect_fft_window, save_fft_window, help_fft_window, clear_fft_window, revert_fft_window);
20016 
20017     current_sep = make_inter_variable_separator(fft_box, prf->label);
20018     prf = prefs_row_with_scale("data window family parameter", S_fft_window_beta,
20019 			       1.0, rts_fft_window_beta = fft_window_beta(ss),
20020 			       fft_box, current_sep,
20021 			       fft_window_beta_scale_callback, fft_window_beta_text_callback);
20022     remember_pref(prf, reflect_fft_window_beta, save_fft_window_beta, help_fft_window_beta, NULL, revert_fft_window_beta);
20023 
20024     current_sep = make_inter_variable_separator(fft_box, prf->label);
20025     str = mus_format("%d", rts_max_transform_peaks = max_transform_peaks(ss));
20026     prf = prefs_row_with_toggle_with_text("show fft peak data", S_show_transform_peaks,
20027 					  rts_show_transform_peaks = show_transform_peaks(ss),
20028 					  "max peaks:", str, 5,
20029 					  fft_box, current_sep,
20030 					  transform_peaks_toggle, max_peaks_text);
20031     remember_pref(prf, reflect_transform_peaks, save_transform_peaks, help_transform_peaks, NULL, revert_transform_peaks);
20032     free(str);
20033 
20034     current_sep = make_inter_variable_separator(fft_box, prf->label);
20035     {
20036       const char **cmaps;
20037       int i, len;
20038       len = num_colormaps();
20039       cmaps = (const char **)calloc(len, sizeof(const char *));
20040       for (i = 0; i < len; i++)
20041 	cmaps[i] = (const char *)colormap_name(i);
20042       rts_colormap = color_map(ss);
20043       prf = prefs_row_with_list("sonogram colormap", S_colormap, cmaps[rts_colormap],
20044 				cmaps, len,
20045 				fft_box, current_sep,
20046 				colormap_from_text,
20047 				colormap_completer, NULL,
20048 				colormap_from_menu);
20049       remember_pref(prf, reflect_colormap, save_colormap, help_colormap, clear_colormap, revert_colormap);
20050       free(cmaps);
20051     }
20052 
20053     current_sep = make_inter_variable_separator(fft_box, prf->label);
20054     prf = prefs_row_with_toggle("y axis as log magnitude (dB)", S_fft_log_magnitude,
20055 				rts_fft_log_magnitude = fft_log_magnitude(ss),
20056 				fft_box, current_sep,
20057 				log_magnitude_toggle);
20058     remember_pref(prf, reflect_fft_log_magnitude, save_fft_log_magnitude, help_fft_log_magnitude, NULL, revert_fft_log_magnitude);
20059 
20060     current_sep = make_inter_variable_separator(fft_box, prf->label);
20061     str = mus_format("%.1f", rts_min_dB = min_dB(ss));
20062     prf = prefs_row_with_text("minimum y-axis dB value", S_min_dB, str,
20063 			      fft_box, current_sep,
20064 			      min_dB_text);
20065     remember_pref(prf, reflect_min_dB, save_min_dB, help_min_dB, NULL, revert_min_dB);
20066     free(str);
20067 
20068     current_sep = make_inter_variable_separator(fft_box, prf->label);
20069     prf = prefs_row_with_toggle("x axis as log freq", S_fft_log_frequency,
20070 				rts_fft_log_frequency = fft_log_frequency(ss),
20071 				fft_box, current_sep,
20072 				log_frequency_toggle);
20073     remember_pref(prf, reflect_fft_log_frequency, save_fft_log_frequency, help_fft_log_frequency, NULL, revert_fft_log_frequency);
20074 
20075     current_sep = make_inter_variable_separator(fft_box, prf->label);
20076     prf = prefs_row_with_radio_box("normalization", S_transform_normalization,
20077 				   transform_normalizations, NUM_TRANSFORM_NORMALIZATIONS,
20078 				   rts_transform_normalization = transform_normalization(ss),
20079 				   fft_box, current_sep,
20080 				   transform_normalization_choice);
20081     remember_pref(prf, reflect_transform_normalization, save_transform_normalization, help_transform_normalization, NULL, revert_transform_normalization);
20082   }
20083 
20084   current_sep = make_inter_topic_separator(topics);
20085 
20086   /* -------- marks, mixes, and regions -------- */
20087   {
20088     Widget mmr_box, mmr_label;
20089     char *str1, *str2;
20090 
20091     /* ---------------- marks and mixes ---------------- */
20092 
20093     mmr_box = make_top_level_box(topics);
20094     mmr_label = make_top_level_label("marks and mixes", mmr_box);
20095 
20096     saved_mark_color = ss->mark_color;
20097     prf = prefs_color_selector_row("mark and mix tag color", S_mark_color, ss->mark_color,
20098 				   mmr_box, mmr_label,
20099 				   mark_color_func);
20100     remember_pref(prf, NULL, save_mark_color, help_mark_color, clear_mark_color, revert_mark_color);
20101 
20102     current_sep = make_inter_variable_separator(mmr_box, prf->rscl);
20103 
20104     str1 = mus_format("%d", rts_mark_tag_width = mark_tag_width(ss));
20105     str2 = mus_format("%d", rts_mark_tag_height = mark_tag_height(ss));
20106     prf = prefs_row_with_two_texts("mark tag size", S_mark_tag_width,
20107 				   "width:", str1, "height:", str2, 4,
20108 				   mmr_box, current_sep,
20109 				   mark_tag_size_text);
20110     remember_pref(prf, reflect_mark_tag_size, save_mark_tag_size, help_mark_tag_size, NULL, revert_mark_tag_size);
20111     free(str2);
20112     free(str1);
20113 
20114     current_sep = make_inter_variable_separator(mmr_box, prf->label);
20115     str1 = mus_format("%d", rts_mix_tag_width = mix_tag_width(ss));
20116     str2 = mus_format("%d", rts_mix_tag_height = mix_tag_height(ss));
20117     prf = prefs_row_with_two_texts("mix tag size", S_mix_tag_width,
20118 				   "width:", str1, "height:", str2, 4,
20119 				   mmr_box, current_sep,
20120 				   mix_tag_size_text);
20121     remember_pref(prf, reflect_mix_tag_size, save_mix_tag_size, help_mix_tag_size, NULL, revert_mix_tag_size);
20122     free(str2);
20123     free(str1);
20124 
20125     current_sep = make_inter_variable_separator(mmr_box, prf->label);
20126     saved_mix_color = ss->mix_color;
20127     prf = prefs_color_selector_row("mix waveform color", S_mix_color, ss->mix_color,
20128 				   mmr_box, current_sep,
20129 				   mix_color_func);
20130     remember_pref(prf, NULL, save_mix_color, help_mix_color, clear_mix_color, revert_mix_color);
20131 
20132     current_sep = make_inter_variable_separator(mmr_box, prf->rscl);
20133     str = mus_format("%d", rts_mix_waveform_height = mix_waveform_height(ss));
20134     prf = prefs_row_with_toggle_with_text("show mix waveforms (attached to the mix tag)", S_show_mix_waveforms,
20135 					  rts_show_mix_waveforms = show_mix_waveforms(ss),
20136 					  "max waveform height:", str, 5,
20137 					  mmr_box, current_sep,
20138 					  show_mix_waveforms_toggle, mix_waveform_height_text);
20139     remember_pref(prf, reflect_mix_waveforms, save_mix_waveforms, help_mix_waveforms, NULL, revert_mix_waveforms);
20140     free(str);
20141   }
20142 
20143   current_sep = make_inter_topic_separator(topics);
20144 
20145   /* -------- clm -------- */
20146   {
20147     Widget clm_box, clm_label;
20148 
20149     /* ---------------- clm options ---------------- */
20150 
20151     clm_box = make_top_level_box(topics);
20152     clm_label = make_top_level_label("clm", clm_box);
20153 
20154     rts_speed_control_style = speed_control_style(ss);
20155     str = mus_format("%d", rts_speed_control_tones = speed_control_tones(ss));
20156     prf = prefs_row_with_radio_box_and_number("speed control choice", S_speed_control_style,
20157 					      speed_control_styles, NUM_SPEED_CONTROL_STYLES, (int)speed_control_style(ss),
20158 					      str, 6,
20159 					      clm_box, clm_label,
20160 					      speed_control_choice, speed_control_up, speed_control_down, speed_control_text);
20161     XtSetSensitive(prf->arrow_down, (speed_control_tones(ss) > MIN_SPEED_CONTROL_SEMITONES));
20162     remember_pref(prf, reflect_speed_control, save_speed_control, help_speed_control, NULL, revert_speed_control);
20163     free(str);
20164 
20165     current_sep = make_inter_variable_separator(clm_box, prf->label);
20166     str = mus_format("%d", rts_sinc_width = sinc_width(ss));
20167     prf = prefs_row_with_text("sinc interpolation width in srate converter", S_sinc_width, str,
20168 			      clm_box, current_sep,
20169 			      sinc_width_text);
20170     remember_pref(prf, reflect_sinc_width, save_sinc_width, help_sinc_width, NULL, revert_sinc_width);
20171     free(str);
20172   }
20173 
20174   current_sep = make_inter_topic_separator(topics);
20175 
20176   /* -------- programming -------- */
20177   {
20178     Widget prg_box, prg_label;
20179 
20180     /* ---------------- listener options ---------------- */
20181 
20182     prg_box = make_top_level_box(topics);
20183     prg_label = make_top_level_label("listener options", prg_box);
20184 
20185     prf = prefs_row_with_toggle("show listener at start up", S_show_listener,
20186 				rts_show_listener = listener_is_visible(),
20187 				prg_box, prg_label,
20188 				show_listener_toggle);
20189     remember_pref(prf, reflect_show_listener, save_show_listener, help_show_listener, clear_show_listener, revert_show_listener);
20190 
20191     current_sep = make_inter_variable_separator(prg_box, prf->label);
20192     rts_listener_prompt = mus_strdup(listener_prompt(ss));
20193     prf = prefs_row_with_text("prompt", S_listener_prompt,
20194 			      listener_prompt(ss),
20195 			      prg_box, current_sep,
20196 			      listener_prompt_text);
20197     remember_pref(prf, reflect_listener_prompt, save_listener_prompt, help_listener_prompt, NULL, revert_listener_prompt);
20198 
20199     current_sep = make_inter_variable_separator(prg_box, prf->label);
20200     str = mus_format("%d", rts_print_length = print_length(ss));
20201     prf = prefs_row_with_text("number of vector elements to display", S_print_length, str,
20202 			      prg_box, current_sep,
20203 			      print_length_text);
20204     remember_pref(prf, reflect_print_length, save_print_length, help_print_length, NULL, revert_print_length);
20205     free(str);
20206 
20207     current_sep = make_inter_variable_separator(prg_box, prf->label);
20208     rts_listener_font = mus_strdup(listener_font(ss));
20209     prf = prefs_row_with_text("font", S_listener_font,
20210 			      listener_font(ss),
20211 			      prg_box, current_sep,
20212 			      listener_font_text);
20213     remember_pref(prf, reflect_listener_font, save_listener_font, help_listener_font, clear_listener_font, revert_listener_font);
20214 
20215     current_sep = make_inter_variable_separator(prg_box, prf->label);
20216     saved_listener_color = ss->listener_color;
20217     prf = prefs_color_selector_row("background color", S_listener_color, ss->listener_color,
20218 				   prg_box, current_sep,
20219 				   listener_color_func);
20220     remember_pref(prf, NULL, save_listener_color, help_listener_color, clear_listener_color, revert_listener_color);
20221 
20222     current_sep = make_inter_variable_separator(prg_box, prf->rscl);
20223     saved_listener_text_color = ss->listener_text_color;
20224     prf = prefs_color_selector_row("text color", S_listener_text_color, ss->listener_text_color,
20225 				   prg_box, current_sep,
20226 				   listener_text_color_func);
20227     remember_pref(prf, NULL, save_listener_text_color, help_listener_text_color, clear_listener_text_color, revert_listener_text_color);
20228   }
20229 
20230   current_sep = make_inter_topic_separator(topics);
20231 
20232   /* -------- audio -------- */
20233   {
20234     Widget aud_box, aud_label;
20235 
20236     /* ---------------- audio options ---------------- */
20237 
20238     aud_box = make_top_level_box(topics);
20239     aud_label = make_top_level_label("audio options", aud_box);
20240 
20241     str = mus_format("%d", rts_dac_size = dac_size(ss));
20242     prf = prefs_row_with_text("dac buffer size", S_dac_size,
20243 			      str,
20244 			      aud_box, aud_label,
20245 			      dac_size_text);
20246     remember_pref(prf, reflect_dac_size, save_dac_size, help_dac_size, NULL, revert_dac_size);
20247     free(str);
20248 
20249     current_sep = make_inter_variable_separator(aud_box, prf->label);
20250     prf = prefs_row_with_toggle("fold in otherwise unplayable channels", S_dac_combines_channels,
20251 				rts_dac_combines_channels = dac_combines_channels(ss),
20252 				aud_box, current_sep,
20253 				dac_combines_channels_toggle);
20254     remember_pref(prf, reflect_dac_combines_channels, save_dac_combines_channels, help_dac_combines_channels, NULL, revert_dac_combines_channels);
20255   }
20256 
20257   {
20258     Atom wm_delete_window;
20259     wm_delete_window = XmInternAtom(main_display(ss), (char *)"WM_DELETE_WINDOW", false);
20260     XmAddWMProtocolCallback(XtParent(preferences_dialog), wm_delete_window, wm_delete_callback, NULL);
20261   }
20262 
20263   XtManageChild(preferences_dialog);
20264   set_dialog_widget(PREFERENCES_DIALOG, preferences_dialog);
20265 
20266   return(preferences_dialog);
20267 }
20268 
20269 
20270 #include "snd-menu.h"
20271 #include <X11/cursorfont.h>
20272 
20273 /* X side of file print */
20274 
20275 static Widget print_dialog = NULL;
20276 static Widget print_name = NULL;
20277 static Widget print_eps_or_lpr = NULL;
20278 static char print_string[PRINT_BUFFER_SIZE];
20279 static Widget error_info_box, error_info_frame, error_info;
20280 
print_help_callback(Widget w,XtPointer context,XtPointer info)20281 static void print_help_callback(Widget w, XtPointer context, XtPointer info)
20282 {
20283   print_dialog_help();
20284 }
20285 
20286 
20287 static void clear_print_error(void);
20288 
print_cancel_callback(Widget w,XtPointer context,XtPointer info)20289 static void print_cancel_callback(Widget w, XtPointer context, XtPointer info)
20290 {
20291   if (XmGetFocusWidget(print_dialog) == XmMessageBoxGetChild(print_dialog, XmDIALOG_CANCEL_BUTTON))
20292     {
20293       ss->print_choice = PRINT_SND;
20294       clear_print_error();
20295       XtUnmanageChild(print_dialog);
20296     }
20297   /* else it's the <cr> from the text widget probably */
20298 }
20299 
20300 
lpr(char * name)20301 static int lpr(char *name)
20302 {
20303   /* make some desultory effort to print the file */
20304   snprintf(print_string, PRINT_BUFFER_SIZE, "lpr %s", name);
20305   return(system(print_string));
20306 }
20307 
20308 
watch_print(Widget w,XtPointer context,XtPointer info)20309 static void watch_print(Widget w, XtPointer context, XtPointer info)
20310 {
20311   clear_print_error();
20312 }
20313 
20314 
20315 static Widget rc;
20316 static bool print_watching = false, print_error = false;
20317 
clear_print_error(void)20318 static void clear_print_error(void)
20319 {
20320   XtUnmanageChild(rc);
20321   XtUnmanageChild(error_info_box);
20322   XtVaSetValues(print_eps_or_lpr, XmNbottomAttachment, XmATTACH_FORM, NULL);
20323   XtManageChild(rc);
20324   print_error = false;
20325   if (print_watching)
20326     {
20327       print_watching = false;
20328       XtRemoveCallback(print_name, XmNvalueChangedCallback, watch_print, NULL);
20329       XtRemoveCallback(print_eps_or_lpr, XmNvalueChangedCallback, watch_print, NULL);
20330     }
20331 }
20332 
20333 
report_in_error_info(const char * msg,void * ignore)20334 static void report_in_error_info(const char *msg, void *ignore)
20335 {
20336   XmString s1;
20337   if ((!msg) || (!(*msg))) return;
20338   print_error = true;
20339   s1 = XmStringCreateLocalized((char *)msg);
20340   XtVaSetValues(error_info, XmNlabelString, s1, NULL);
20341   if (!(XtIsManaged(error_info_box)))
20342     {
20343       Dimension text_wid = 0, dialog_wid = 0;
20344       XmFontList fonts;
20345 
20346       XtVaGetValues(error_info, XmNfontList, &fonts, NULL);
20347       XtVaGetValues(print_dialog, XmNwidth, &dialog_wid, NULL);
20348       text_wid = XmStringWidth(fonts, s1);
20349       XtUnmanageChild(rc);
20350 
20351       XtVaSetValues(print_eps_or_lpr, XmNbottomAttachment, XmATTACH_NONE, NULL);
20352       if (text_wid > dialog_wid)
20353 	{
20354 	  XtUnmanageChild(print_dialog);
20355 	  XtVaSetValues(print_dialog, XmNwidth, text_wid + 40, NULL);
20356 	  XtManageChild(print_dialog);
20357 	}
20358       XtManageChild(error_info_box);
20359       XtManageChild(rc);
20360       print_watching = true;
20361       XtAddCallback(print_name, XmNvalueChangedCallback, watch_print, NULL);
20362       XtAddCallback(print_eps_or_lpr, XmNvalueChangedCallback, watch_print, NULL);
20363     }
20364   XmStringFree(s1);
20365 }
20366 
20367 
20368 static printing_t printing = NOT_PRINTING;
20369 
print_ok_callback(Widget w,XtPointer context,XtPointer info)20370 static void print_ok_callback(Widget w, XtPointer context, XtPointer info)
20371 {
20372   bool quit = false;
20373   XmString plab, slab;
20374   snd_info *nsp = NULL;
20375 
20376   if (printing)
20377     ss->stopped_explicitly = true;
20378   else
20379     {
20380       bool print_it;
20381 
20382       clear_print_error();
20383       if (ss->print_choice == PRINT_SND)
20384 	{
20385 	  plab = XmStringCreateLocalized((char *)I_STOP);
20386 	  nsp = any_selected_sound();
20387 	  snprintf(print_string, PRINT_BUFFER_SIZE, "printing %s", nsp->short_filename);
20388 	  slab = XmStringCreateLocalized(print_string);
20389 	  XtVaSetValues(print_dialog,
20390 			XmNokLabelString, plab,
20391 			XmNmessageString, slab,
20392 			NULL);
20393 	  XmStringFree(plab);
20394 	  XmStringFree(slab);
20395 	}
20396 
20397       printing = PRINTING;
20398       print_it = (bool)XmToggleButtonGetState(print_eps_or_lpr);
20399       quit = (ss->print_choice == PRINT_ENV);
20400 
20401       if (print_it)
20402 	{
20403 	  char *name;
20404 	  name = snd_tempnam();
20405 
20406 	  redirect_snd_error_to(report_in_error_info, NULL);
20407 	  switch (ss->print_choice)
20408 	    {
20409 	    case PRINT_SND:
20410 	      snd_print(name);
20411 	      break;
20412 
20413 	    case PRINT_ENV:
20414 	      enved_print(name);
20415 	      break;
20416 	    }
20417 	  redirect_snd_error_to(NULL, NULL);
20418 	  if (!print_error)
20419 	    {
20420 	      int err;
20421 	      err = lpr(name); /* lpr apparently insists on printing to stderr? */
20422 	      if (err != 0)
20423 		report_in_error_info("can't print!", NULL);
20424 	      snd_remove(name, IGNORE_CACHE);
20425 	    }
20426 	  free(name);
20427 	}
20428       else
20429 	{
20430 	  char *str = NULL;
20431 	  redirect_snd_error_to(report_in_error_info, NULL);
20432 	  str = XmTextGetString(print_name);
20433 	  switch (ss->print_choice)
20434 	    {
20435 	    case PRINT_SND:
20436 	      if (snd_print(str))
20437 		status_report(nsp, "printed current view to %s", str);
20438 	      break;
20439 
20440 	    case PRINT_ENV:
20441 	      enved_print(str);
20442 	      break;
20443 	    }
20444 	  redirect_snd_error_to(NULL, NULL);
20445 	  if (str) XtFree(str);
20446 	}
20447     }
20448 
20449   printing = NOT_PRINTING;
20450   if (ss->print_choice == PRINT_SND)
20451     {
20452       plab = XmStringCreateLocalized((char *)"Print");
20453       snprintf(print_string, PRINT_BUFFER_SIZE, "print %s", nsp->short_filename);
20454       slab = XmStringCreateLocalized(print_string);
20455       XtVaSetValues(print_dialog,
20456 		    XmNokLabelString, plab,
20457 		    XmNmessageString, slab,
20458 		    NULL);
20459       XmStringFree(plab);
20460       XmStringFree(slab);
20461     }
20462   ss->print_choice = PRINT_SND;
20463   if (quit)
20464     XtUnmanageChild(print_dialog);
20465 }
20466 
20467 
start_print_dialog(XmString xmstr4,bool managed)20468 static void start_print_dialog(XmString xmstr4, bool managed)
20469 {
20470   if (!print_dialog)
20471     {
20472       Widget dl;
20473       XmString xmstr1, xmstr2, xmstr3, titlestr;
20474       Arg args[20];
20475       int n;
20476 
20477       n = 0;
20478       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
20479       xmstr1 = XmStringCreateLocalized((char *)"Print");  /* "ok" here is confusing -- might mean, ok I'm done */
20480       xmstr2 = XmStringCreateLocalized((char *)I_HELP);
20481       xmstr3 = XmStringCreateLocalized((char *)I_GO_AWAY);
20482       titlestr = XmStringCreateLocalized((char *)"Print");
20483 
20484       XtSetArg(args[n], XmNmessageString, xmstr4); n++;
20485       XtSetArg(args[n], XmNokLabelString, xmstr1); n++;
20486       XtSetArg(args[n], XmNhelpLabelString, xmstr2); n++;
20487       XtSetArg(args[n], XmNcancelLabelString, xmstr3); n++;
20488       XtSetArg(args[n], XmNautoUnmanage, false); n++;
20489       XtSetArg(args[n], XmNdialogTitle, titlestr); n++;
20490       XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
20491       XtSetArg(args[n], XmNallowResize, true); n++;
20492       XtSetArg(args[n], XmNnoResize, false); n++;
20493       XtSetArg(args[n], XmNtransient, false); n++; /* this gives us the resize handles */
20494       print_dialog = XmCreateMessageDialog(main_pane(ss), (char *)"eps file:", args, n);
20495 
20496       XtVaSetValues(XmMessageBoxGetChild(print_dialog, XmDIALOG_MESSAGE_LABEL), XmNbackground, ss->basic_color, NULL);
20497 
20498       XmStringFree(xmstr1);
20499       XmStringFree(xmstr2);
20500       XmStringFree(xmstr3);
20501       XmStringFree(titlestr);
20502 
20503       XtUnmanageChild(XmMessageBoxGetChild(print_dialog, XmDIALOG_SYMBOL_LABEL));
20504 
20505       XtAddCallback(print_dialog, XmNhelpCallback, print_help_callback, NULL);
20506       XtAddCallback(print_dialog, XmNcancelCallback, print_cancel_callback, NULL);
20507       XtAddCallback(print_dialog, XmNokCallback, print_ok_callback, NULL);
20508 
20509       n = 0;
20510       rc = XtCreateManagedWidget("form", xmFormWidgetClass, print_dialog, args, n);
20511 
20512       n = 0;
20513       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
20514       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
20515       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
20516       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
20517       dl = XtCreateManagedWidget("eps file:", xmLabelWidgetClass, rc, args, n);
20518 
20519       n = 0;
20520       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
20521       XtSetArg(args[n], XmNleftWidget, dl); n++;
20522       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
20523       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
20524       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
20525       XtSetArg(args[n], XmNvalue, eps_file(ss)); n++;
20526       print_name = make_textfield_widget("text", rc, args, n, ACTIVATABLE, NO_COMPLETER);
20527 
20528       n = 0;
20529       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
20530       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
20531       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
20532       XtSetArg(args[n], XmNtopWidget, print_name); n++;
20533       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
20534       print_eps_or_lpr = make_togglebutton_widget("direct to printer", rc, args, n);
20535 
20536       /* error display */
20537 
20538       n = 0;
20539       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
20540       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
20541       XtSetArg(args[n], XmNtopWidget, print_eps_or_lpr); n++;
20542       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
20543       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
20544       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
20545       XtSetArg(args[n], XmNallowResize, true); n++;
20546       XtSetArg(args[n], XmNmargin, 0); n++;
20547       error_info_box = XtCreateWidget("error-box", xmRowColumnWidgetClass, rc, args, n);
20548 
20549       n = 0;
20550       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
20551       XtSetArg(args[n], XmNmarginHeight, 4); n++;
20552       error_info_frame = XtCreateManagedWidget("error-frame", xmFrameWidgetClass, error_info_box, args, n);
20553 
20554       n = 0;
20555       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
20556       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
20557       error_info = XtCreateManagedWidget("error-info", xmLabelWidgetClass, error_info_frame, args, n);
20558 
20559       XtVaSetValues(print_eps_or_lpr, XmNbottomAttachment, XmATTACH_FORM, NULL);
20560 
20561       if (managed) XtManageChild(print_dialog);
20562 
20563       map_over_children(print_dialog, set_main_color_of_widget);
20564       XtVaSetValues(XmMessageBoxGetChild(print_dialog, XmDIALOG_OK_BUTTON),     XmNarmColor,   ss->selection_color, NULL);
20565       XtVaSetValues(XmMessageBoxGetChild(print_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor,   ss->selection_color, NULL);
20566       XtVaSetValues(XmMessageBoxGetChild(print_dialog, XmDIALOG_HELP_BUTTON),   XmNarmColor,   ss->selection_color, NULL);
20567       XtVaSetValues(XmMessageBoxGetChild(print_dialog, XmDIALOG_OK_BUTTON),     XmNbackground, ss->highlight_color, NULL);
20568       XtVaSetValues(XmMessageBoxGetChild(print_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL);
20569       XtVaSetValues(XmMessageBoxGetChild(print_dialog, XmDIALOG_HELP_BUTTON),   XmNbackground, ss->highlight_color, NULL);
20570       XtVaSetValues(print_eps_or_lpr, XmNselectColor, ss->selection_color, NULL);
20571 
20572       set_dialog_widget(PRINT_DIALOG, print_dialog);
20573     }
20574   else
20575     {
20576       XtVaSetValues(print_dialog, XmNmessageString, xmstr4, NULL);
20577       if (managed)
20578 	{
20579 	  if (!XtIsManaged(print_dialog))
20580 	    XtManageChild(print_dialog);
20581 	  raise_dialog(print_dialog); /* a no-op unless already managed */
20582 	}
20583     }
20584 }
20585 
20586 
make_file_print_dialog(bool managed,bool direct_to_printer)20587 widget_t make_file_print_dialog(bool managed, bool direct_to_printer)
20588 {
20589   XmString xmstr4;
20590   xmstr4 = XmStringCreateLocalized((char *)"print");
20591   start_print_dialog(xmstr4, managed);
20592   XmStringFree(xmstr4);
20593   XmToggleButtonSetState(print_eps_or_lpr, direct_to_printer, false);
20594   return(print_dialog);
20595 }
20596 
20597 
file_print_callback(Widget w,XtPointer context,XtPointer info)20598 static void file_print_callback(Widget w, XtPointer context, XtPointer info)
20599 {
20600   XmString xmstr4;
20601   if (ss->print_choice == PRINT_SND)
20602     {
20603       snd_info *nsp;
20604       nsp = any_selected_sound();
20605       if (!nsp) return;
20606       snprintf(print_string, PRINT_BUFFER_SIZE, "print %s", nsp->short_filename);
20607       xmstr4 = XmStringCreateLocalized(print_string);
20608     }
20609   else xmstr4 = XmStringCreateLocalized((char *)"print env");
20610   start_print_dialog(xmstr4, true);
20611   XmStringFree(xmstr4);
20612 }
20613 
20614 
save_print_dialog_state(FILE * fd)20615 void save_print_dialog_state(FILE *fd)
20616 {
20617   if ((print_dialog) && (XtIsManaged(print_dialog)))
20618     {
20619 #if HAVE_SCHEME
20620       fprintf(fd, "(%s #t %s)\n", S_print_dialog, ((bool)(XmToggleButtonGetState(print_eps_or_lpr))) ? "#t" : "#f");
20621 #endif
20622 #if HAVE_RUBY
20623       fprintf(fd, "%s(true, %s)\n", to_proc_name(S_print_dialog), ((bool)(XmToggleButtonGetState(print_eps_or_lpr))) ? "true" : "false");
20624 #endif
20625 #if HAVE_FORTH
20626       fprintf(fd, "#t %s %s drop\n", ((bool)(XmToggleButtonGetState(print_eps_or_lpr))) ? "#t" : "#f", S_print_dialog);
20627 #endif
20628     }
20629 }
20630 
20631 
20632 
set_menu_label(Widget w,const char * label)20633 void set_menu_label(Widget w, const char *label) {if (w) set_button_label(w, label);}
20634 
20635 
20636 /* -------------------------------- FILE MENU -------------------------------- */
20637 
20638 static Widget *recent_file_items = NULL;
20639 static int recent_file_items_size = 0;
20640 
open_recent_file_callback(Widget w,XtPointer context,XtPointer info)20641 static void open_recent_file_callback(Widget w, XtPointer context, XtPointer info)
20642 {
20643   char *filename;
20644   snd_info *sp;
20645   filename = get_label(w);
20646   ss->open_requestor = FROM_OPEN_RECENT_MENU;
20647   ss->open_requestor_data = NULL;
20648   sp = snd_open_file(filename, FILE_READ_WRITE);
20649   if (sp) select_channel(sp, 0);
20650 }
20651 
20652 
file_open_recent_callback(Widget w,XtPointer info,XtPointer context)20653 static void file_open_recent_callback(Widget w, XtPointer info, XtPointer context)
20654 {
20655   int size;
20656   size = recent_files_size();
20657   if (size > 0)
20658     {
20659       int i;
20660       char **recent_file_names;
20661 
20662       if (size > recent_file_items_size)
20663 	{
20664 	  if (recent_file_items_size == 0)
20665 	    recent_file_items = (Widget *)calloc(size, sizeof(Widget));
20666 	  else
20667 	    {
20668 	      recent_file_items = (Widget *)realloc(recent_file_items, size * sizeof(Widget));
20669 	      for (i = recent_file_items_size; i < size; i++)
20670 		recent_file_items[i] = NULL;
20671 	    }
20672 	  recent_file_items_size = size;
20673 	}
20674 
20675       recent_file_names = recent_files();
20676 
20677       for (i = 0; i < size; i++)
20678 	{
20679 	  if (!recent_file_items[i])
20680 	    {
20681 	      int n = 0;
20682 	      Arg args[6];
20683 
20684 	      XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
20685 
20686 	      recent_file_items[i] = XtCreateManagedWidget(recent_file_names[i], xmPushButtonWidgetClass, file_open_recent_menu, args, n);
20687 	      XtAddCallback(recent_file_items[i], XmNactivateCallback, open_recent_file_callback, NULL);
20688 	    }
20689 	  else
20690 	    {
20691 	      set_label(recent_file_items[i], recent_file_names[i]);
20692 	      XtManageChild(recent_file_items[i]);
20693 	    }
20694 	}
20695 
20696       for (i = size; i < recent_file_items_size; i++) /* maybe previous file was deleted */
20697 	if ((recent_file_items[i]) &&
20698 	    (XtIsManaged(recent_file_items[i])))
20699 	  XtUnmanageChild(recent_file_items[i]);
20700     }
20701 }
20702 
20703 
make_open_recent_menu(void)20704 static void make_open_recent_menu(void)
20705 {
20706   int n = 0;
20707   Arg args[6];
20708   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
20709   XtSetArg(args[n], XmNpositionIndex, 1); n++;  /* just after "Open" menu */
20710 
20711   file_open_recent_menu = XmCreatePulldownMenu(file_menu, (char *)"open-recent", args, n);
20712 
20713   XtSetArg(args[n], XmNsubMenuId, file_open_recent_menu); n++;
20714 
20715   file_open_recent_cascade_menu = XtCreateManagedWidget("Open recent", xmCascadeButtonWidgetClass, file_menu, args, n);
20716   XtAddCallback(file_open_recent_cascade_menu, XmNcascadingCallback, file_open_recent_callback, NULL);
20717 }
20718 
20719 
file_menu_update_1(Widget w,XtPointer info,XtPointer context)20720 static void file_menu_update_1(Widget w, XtPointer info, XtPointer context)
20721 {
20722   if (recent_files_size() > 0)
20723     {
20724       if (!file_open_recent_menu)
20725 	make_open_recent_menu();
20726       else set_sensitive(file_open_recent_cascade_menu, true);
20727     }
20728   else
20729     {
20730       if (file_open_recent_menu)
20731 	set_sensitive(file_open_recent_cascade_menu, false);
20732     }
20733 
20734   file_menu_update();
20735 }
20736 
20737 
file_open_callback(Widget w,XtPointer info,XtPointer context)20738 static void file_open_callback(Widget w, XtPointer info, XtPointer context) {make_open_file_dialog(FILE_READ_WRITE, true);}
file_view_callback(Widget w,XtPointer info,XtPointer context)20739 static void file_view_callback(Widget w, XtPointer info, XtPointer context) {make_open_file_dialog(FILE_READ_ONLY, true);}
file_new_callback(Widget w,XtPointer info,XtPointer context)20740 static void file_new_callback(Widget w, XtPointer info, XtPointer context) {make_new_file_dialog(true);}
file_close_callback(Widget w,XtPointer info,XtPointer context)20741 static void file_close_callback(Widget w, XtPointer info, XtPointer context) {if (any_selected_sound()) snd_close_file(any_selected_sound());}
file_close_all_callback(Widget w,XtPointer info,XtPointer context)20742 static void file_close_all_callback(Widget w, XtPointer info, XtPointer context) {for_each_sound(snd_close_file);}
file_save_callback(Widget w,XtPointer info,XtPointer context)20743 static void file_save_callback(Widget w, XtPointer info, XtPointer context) {if (any_selected_sound()) save_edits_from_kbd(any_selected_sound());}
file_update_callback(Widget w,XtPointer info,XtPointer context)20744 static void file_update_callback(Widget w, XtPointer info, XtPointer context) {update_file_from_menu();}
file_save_as_callback(Widget w,XtPointer info,XtPointer context)20745 static void file_save_as_callback(Widget w, XtPointer info, XtPointer context) {make_sound_save_as_dialog(true);}
file_revert_callback(Widget w,XtPointer info,XtPointer context)20746 static void file_revert_callback(Widget w, XtPointer info, XtPointer context) {revert_file_from_menu();}
file_exit_callback(Widget w,XtPointer info,XtPointer context)20747 static void file_exit_callback(Widget w, XtPointer info, XtPointer context) {if (snd_exit_cleanly(EXIT_NOT_FORCED)) snd_exit(1);}
file_mix_callback_1(Widget w,XtPointer info,XtPointer context)20748 static void file_mix_callback_1(Widget w, XtPointer info, XtPointer context) {make_mix_file_dialog(true);}
file_insert_callback_1(Widget w,XtPointer info,XtPointer context)20749 static void file_insert_callback_1(Widget w, XtPointer info, XtPointer context) {make_insert_file_dialog(true);}
file_print_callback_1(Widget w,XtPointer info,XtPointer context)20750 static void file_print_callback_1(Widget w, XtPointer info, XtPointer context) {file_print_callback(w, info, context);}
20751 
20752 
20753 /* -------------------------------- EDIT MENU -------------------------------- */
20754 
edit_mix_callback(Widget w,XtPointer info,XtPointer context)20755 static void edit_mix_callback(Widget w, XtPointer info, XtPointer context) {add_selection_or_region(0, selected_channel());}
edit_envelope_callback(Widget w,XtPointer info,XtPointer context)20756 static void edit_envelope_callback(Widget w, XtPointer info, XtPointer context) {create_envelope_editor();}
edit_cut_callback(Widget w,XtPointer info,XtPointer context)20757 static void edit_cut_callback(Widget w, XtPointer info, XtPointer context) {delete_selection(UPDATE_DISPLAY);}
edit_paste_callback(Widget w,XtPointer info,XtPointer context)20758 static void edit_paste_callback(Widget w, XtPointer info, XtPointer context) {insert_selection_from_menu();}
edit_save_as_callback(Widget w,XtPointer info,XtPointer context)20759 static void edit_save_as_callback(Widget w, XtPointer info, XtPointer context) {make_selection_save_as_dialog(true);}
edit_select_all_callback(Widget w,XtPointer info,XtPointer context)20760 static void edit_select_all_callback(Widget w, XtPointer info, XtPointer context) {select_all(current_channel());}
edit_unselect_callback(Widget w,XtPointer info,XtPointer context)20761 static void edit_unselect_callback(Widget w, XtPointer info, XtPointer context) {deactivate_selection();}
edit_undo_callback(Widget w,XtPointer info,XtPointer context)20762 static void edit_undo_callback(Widget w, XtPointer info, XtPointer context) {undo_edit_with_sync(current_channel(), 1);}
edit_redo_callback(Widget w,XtPointer info,XtPointer context)20763 static void edit_redo_callback(Widget w, XtPointer info, XtPointer context) {redo_edit_with_sync(current_channel(), 1);}
20764 
edit_menu_update_1(Widget w,XtPointer info,XtPointer context)20765 static void edit_menu_update_1(Widget w, XtPointer info, XtPointer context) {edit_menu_update();}
20766 
20767 
20768 #if WITH_AUDIO
edit_play_callback(Widget w,XtPointer info,XtPointer context)20769 static void edit_play_callback(Widget w, XtPointer info, XtPointer context)
20770 {
20771   if (ss->selection_play_stop)
20772     {
20773       stop_playing_all_sounds(PLAY_BUTTON_UNSET);
20774       reflect_play_selection_stop(); /* if there was an error, stop_playing might not remember to clear this */
20775     }
20776   else
20777     {
20778       set_menu_label(edit_play_menu, I_STOP);
20779       ss->selection_play_stop = true;
20780       play_selection(IN_BACKGROUND);
20781     }
20782 }
20783 
20784 
reflect_play_selection_stop(void)20785 void reflect_play_selection_stop(void)
20786 {
20787   set_menu_label(edit_play_menu, "Play Selection");
20788   ss->selection_play_stop = false;
20789 }
20790 
20791 #else
20792 
reflect_play_selection_stop(void)20793 void reflect_play_selection_stop(void)
20794 {
20795 }
20796 
20797 #endif
20798 
20799 
edit_header_callback_1(Widget w,XtPointer info,XtPointer context)20800 static void edit_header_callback_1(Widget w, XtPointer info, XtPointer context)
20801 {
20802   snd_info *sp;
20803   sp = any_selected_sound();
20804   if (sp) edit_header(sp);
20805 }
20806 
20807 
20808 #if HAVE_EXTENSION_LANGUAGE
edit_find_callback_1(Widget w,XtPointer info,XtPointer context)20809 static void edit_find_callback_1(Widget w, XtPointer info, XtPointer context)
20810 {
20811   edit_find_callback(w, info, context);
20812 }
20813 #endif
20814 
20815 
20816 
20817 /* -------------------------------- VIEW MENU -------------------------------- */
20818 
20819 static Widget *view_files_items = NULL;
20820 static Widget view_files_cascade_menu = NULL;
20821 static int view_files_items_size = 0;
20822 
20823 
view_files_item_callback(Widget w,XtPointer context,XtPointer info)20824 static void view_files_item_callback(Widget w, XtPointer context, XtPointer info)
20825 {
20826   view_files_start_dialog_with_title(get_label(w));
20827 }
20828 
20829 
view_files_callback(Widget w,XtPointer info,XtPointer context)20830 static void view_files_callback(Widget w, XtPointer info, XtPointer context)
20831 {
20832   int size;
20833 
20834   size = view_files_dialog_list_length();
20835   if (size == 0)
20836     make_view_files_dialog(true, true); /* managed and empty (brand-new) */
20837   else
20838     {
20839       if (size == 1)
20840 	make_view_files_dialog(true, false); /* raise current */
20841       else
20842 	{
20843 	  int i;
20844 	  char **view_files_names;
20845 
20846 	  if ((XmIsPushButton(view_files_menu)) && /* autotest check */
20847 	      (!view_files_cascade_menu))
20848 	    return;
20849 
20850 	  view_files_names = view_files_dialog_titles();
20851 	  if (size > view_files_items_size)
20852 	    {
20853 	      if (view_files_items_size == 0)
20854 		view_files_items = (Widget *)calloc(size, sizeof(Widget));
20855 	      else
20856 		{
20857 		  view_files_items = (Widget *)realloc(view_files_items, size * sizeof(Widget));
20858 		  for (i = view_files_items_size; i < size; i++)
20859 		    view_files_items[i] = NULL;
20860 		}
20861 	      view_files_items_size = size;
20862 	    }
20863 
20864 	  for (i = 0; i < size; i++)
20865 	    {
20866 	      if (!view_files_items[i])
20867 		{
20868 		  int n = 0;
20869 		  Arg args[6];
20870 		  XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
20871 
20872 		  view_files_items[i] = XtCreateManagedWidget(view_files_names[i], xmPushButtonWidgetClass, view_files_menu, args, n);
20873 		  XtAddCallback(view_files_items[i], XmNactivateCallback, view_files_item_callback, NULL);
20874 		}
20875 	      else
20876 		{
20877 		  set_label(view_files_items[i], view_files_names[i]);
20878 		  XtManageChild(view_files_items[i]);
20879 		}
20880 	      free(view_files_names[i]);
20881 	    }
20882 	  free(view_files_names);
20883 	}
20884     }
20885 }
20886 
20887 
make_view_files_list_menu(void)20888 static void make_view_files_list_menu(void)
20889 {
20890   int n = 0, pos = 2;
20891   Arg args[6];
20892 
20893   if ((view_files_menu) &&
20894       (XmIsPushButton(view_files_menu)))
20895     {
20896       XtVaGetValues(view_files_menu, XmNpositionIndex, &pos, NULL);
20897       XtUnmanageChild(view_files_menu);
20898     }
20899   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
20900   XtSetArg(args[n], XmNpositionIndex, pos); n++;
20901 
20902   view_files_menu = XmCreatePulldownMenu(view_menu, (char *)"view-files", args, n);
20903   XtSetArg(args[n], XmNsubMenuId, view_files_menu); n++;
20904 
20905   view_files_cascade_menu = XtCreateManagedWidget("Files", xmCascadeButtonWidgetClass, view_menu, args, n);
20906   XtAddCallback(view_files_cascade_menu, XmNcascadingCallback, view_files_callback, NULL);
20907 }
20908 
20909 
view_menu_update_1(Widget w,XtPointer info,XtPointer context)20910 static void view_menu_update_1(Widget w, XtPointer info, XtPointer context)
20911 {
20912   if ((view_files_dialog_list_length() > 1) &&
20913       (!view_files_cascade_menu))
20914     make_view_files_list_menu();
20915 
20916   view_menu_update();
20917 }
20918 
20919 
20920 
view_separate_callback(Widget w,XtPointer info,XtPointer context)20921 static void view_separate_callback(Widget w, XtPointer info, XtPointer context) {set_channel_style(CHANNELS_SEPARATE);}
view_combined_callback(Widget w,XtPointer info,XtPointer context)20922 static void view_combined_callback(Widget w, XtPointer info, XtPointer context) {set_channel_style(CHANNELS_COMBINED);}
view_superimposed_callback(Widget w,XtPointer info,XtPointer context)20923 static void view_superimposed_callback(Widget w, XtPointer info, XtPointer context) {set_channel_style(CHANNELS_SUPERIMPOSED);}
view_dots_callback(Widget w,XtPointer info,XtPointer context)20924 static void view_dots_callback(Widget w, XtPointer info, XtPointer context) {set_graph_style(GRAPH_DOTS);}
view_lines_callback(Widget w,XtPointer info,XtPointer context)20925 static void view_lines_callback(Widget w, XtPointer info, XtPointer context) {set_graph_style(GRAPH_LINES);}
view_filled_callback(Widget w,XtPointer info,XtPointer context)20926 static void view_filled_callback(Widget w, XtPointer info, XtPointer context) {set_graph_style(GRAPH_FILLED);}
view_dots_and_lines_callback(Widget w,XtPointer info,XtPointer context)20927 static void view_dots_and_lines_callback(Widget w, XtPointer info, XtPointer context) {set_graph_style(GRAPH_DOTS_AND_LINES);}
view_lollipops_callback(Widget w,XtPointer info,XtPointer context)20928 static void view_lollipops_callback(Widget w, XtPointer info, XtPointer context) {set_graph_style(GRAPH_LOLLIPOPS);}
20929 #if HAVE_EXTENSION_LANGUAGE
view_listener_callback(Widget w,XtPointer info,XtPointer context)20930 static void view_listener_callback(Widget w, XtPointer info, XtPointer context) {handle_listener(!(listener_is_visible()));}
20931 #endif
view_mix_dialog_callback(Widget w,XtPointer info,XtPointer context)20932 static void view_mix_dialog_callback(Widget w, XtPointer info, XtPointer context) {make_mix_dialog();}
view_zero_callback(Widget w,XtPointer info,XtPointer context)20933 static void view_zero_callback(Widget w, XtPointer info, XtPointer context){set_show_y_zero((!(show_y_zero(ss))));}
view_cursor_callback(Widget w,XtPointer info,XtPointer context)20934 static void view_cursor_callback(Widget w, XtPointer info, XtPointer context){set_with_verbose_cursor((!(with_verbose_cursor(ss))));}
20935 
20936 #if HAVE_EXTENSION_LANGUAGE
view_inset_callback(Widget w,XtPointer info,XtPointer context)20937 static void view_inset_callback(Widget w, XtPointer info, XtPointer context)
20938 {
20939   set_with_inset_graph((!(with_inset_graph(ss))));
20940   for_each_chan(update_graph);
20941 }
20942 #endif
20943 
view_controls_callback(Widget w,XtPointer info,XtPointer context)20944 static void view_controls_callback(Widget w, XtPointer info, XtPointer context) {set_show_controls(!in_show_controls(ss));}
view_region_callback_1(Widget w,XtPointer info,XtPointer context)20945 static void view_region_callback_1(Widget w, XtPointer info, XtPointer context) {view_region_callback(w, info, context);}
view_color_orientation_callback_1(Widget w,XtPointer info,XtPointer context)20946 static void view_color_orientation_callback_1(Widget w, XtPointer info, XtPointer context) {view_color_orientation_callback(w, info, context);}
20947 
view_x_axis_seconds_callback(Widget w,XtPointer info,XtPointer context)20948 static void view_x_axis_seconds_callback(Widget w, XtPointer info, XtPointer context) {set_x_axis_style(X_AXIS_IN_SECONDS);}
view_x_axis_clock_callback(Widget w,XtPointer info,XtPointer context)20949 static void view_x_axis_clock_callback(Widget w, XtPointer info, XtPointer context) {set_x_axis_style(X_AXIS_AS_CLOCK);}
view_x_axis_beats_callback(Widget w,XtPointer info,XtPointer context)20950 static void view_x_axis_beats_callback(Widget w, XtPointer info, XtPointer context) {set_x_axis_style(X_AXIS_IN_BEATS);}
view_x_axis_measures_callback(Widget w,XtPointer info,XtPointer context)20951 static void view_x_axis_measures_callback(Widget w, XtPointer info, XtPointer context) {set_x_axis_style(X_AXIS_IN_MEASURES);}
view_x_axis_samples_callback(Widget w,XtPointer info,XtPointer context)20952 static void view_x_axis_samples_callback(Widget w, XtPointer info, XtPointer context) {set_x_axis_style(X_AXIS_IN_SAMPLES);}
view_x_axis_percentage_callback(Widget w,XtPointer info,XtPointer context)20953 static void view_x_axis_percentage_callback(Widget w, XtPointer info, XtPointer context) {set_x_axis_style(X_AXIS_AS_PERCENTAGE);}
20954 
view_no_axes_callback(Widget w,XtPointer info,XtPointer context)20955 static void view_no_axes_callback(Widget w, XtPointer info, XtPointer context) {set_show_axes(SHOW_NO_AXES);}
view_all_axes_callback(Widget w,XtPointer info,XtPointer context)20956 static void view_all_axes_callback(Widget w, XtPointer info, XtPointer context) {set_show_axes(SHOW_ALL_AXES);}
view_just_x_axis_callback(Widget w,XtPointer info,XtPointer context)20957 static void view_just_x_axis_callback(Widget w, XtPointer info, XtPointer context) {set_show_axes(SHOW_X_AXIS);}
view_all_axes_unlabelled_callback(Widget w,XtPointer info,XtPointer context)20958 static void view_all_axes_unlabelled_callback(Widget w, XtPointer info, XtPointer context) {set_show_axes(SHOW_ALL_AXES_UNLABELLED);}
view_just_x_axis_unlabelled_callback(Widget w,XtPointer info,XtPointer context)20959 static void view_just_x_axis_unlabelled_callback(Widget w, XtPointer info, XtPointer context) {set_show_axes(SHOW_X_AXIS_UNLABELLED);}
view_bare_x_axis_callback(Widget w,XtPointer info,XtPointer context)20960 static void view_bare_x_axis_callback(Widget w, XtPointer info, XtPointer context) {set_show_axes(SHOW_BARE_X_AXIS);}
20961 
view_focus_right_callback(Widget w,XtPointer info,XtPointer context)20962 static void view_focus_right_callback(Widget w, XtPointer info, XtPointer context) {set_zoom_focus_style(ZOOM_FOCUS_RIGHT);}
view_focus_left_callback(Widget w,XtPointer info,XtPointer context)20963 static void view_focus_left_callback(Widget w, XtPointer info, XtPointer context) {set_zoom_focus_style(ZOOM_FOCUS_LEFT);}
view_focus_middle_callback(Widget w,XtPointer info,XtPointer context)20964 static void view_focus_middle_callback(Widget w, XtPointer info, XtPointer context) {set_zoom_focus_style(ZOOM_FOCUS_MIDDLE);}
view_focus_active_callback(Widget w,XtPointer info,XtPointer context)20965 static void view_focus_active_callback(Widget w, XtPointer info, XtPointer context) {set_zoom_focus_style(ZOOM_FOCUS_ACTIVE);}
20966 
view_grid_callback(Widget w,XtPointer info,XtPointer context)20967 static void view_grid_callback(Widget w, XtPointer info, XtPointer context)
20968 {
20969   if (show_grid(ss) == NO_GRID)
20970     set_show_grid(WITH_GRID);
20971   else set_show_grid(NO_GRID);
20972 }
20973 
20974 
20975 
20976 /* -------------------------------- OPTIONS MENU -------------------------------- */
20977 
options_transform_callback(Widget w,XtPointer info,XtPointer context)20978 static void options_transform_callback(Widget w, XtPointer info, XtPointer context) {make_transform_dialog(true);}
options_controls_callback(Widget w,XtPointer info,XtPointer context)20979 static void options_controls_callback(Widget w, XtPointer info, XtPointer context) {make_controls_dialog();}
20980 #if HAVE_EXTENSION_LANGUAGE
options_save_state_callback(Widget w,XtPointer info,XtPointer context)20981 static void options_save_state_callback(Widget w, XtPointer info, XtPointer context) {save_state_from_menu();}
20982 #endif
options_preferences_callback(Widget w,XtPointer info,XtPointer context)20983 static void options_preferences_callback(Widget w, XtPointer info, XtPointer context) {make_preferences_dialog();}
20984 
20985 
20986 
20987 /* -------------------------------- HELP MENU -------------------------------- */
20988 
help_about_snd_callback(Widget w,XtPointer info,XtPointer context)20989 static void help_about_snd_callback(Widget w, XtPointer info, XtPointer context) {about_snd_help();}
help_fft_callback(Widget w,XtPointer info,XtPointer context)20990 static void help_fft_callback(Widget w, XtPointer info, XtPointer context) {fft_help();}
20991 #if HAVE_EXTENSION_LANGUAGE
help_find_callback(Widget w,XtPointer info,XtPointer context)20992 static void help_find_callback(Widget w, XtPointer info, XtPointer context) {find_help();}
help_init_file_callback(Widget w,XtPointer info,XtPointer context)20993 static void help_init_file_callback(Widget w, XtPointer info, XtPointer context) {init_file_help();}
20994 #endif
help_undo_callback(Widget w,XtPointer info,XtPointer context)20995 static void help_undo_callback(Widget w, XtPointer info, XtPointer context) {undo_help();}
help_sync_callback(Widget w,XtPointer info,XtPointer context)20996 static void help_sync_callback(Widget w, XtPointer info, XtPointer context) {sync_help();}
help_debug_callback(Widget w,XtPointer info,XtPointer context)20997 static void help_debug_callback(Widget w, XtPointer info, XtPointer context) {debug_help();}
help_controls_callback(Widget w,XtPointer info,XtPointer context)20998 static void help_controls_callback(Widget w, XtPointer info, XtPointer context) {controls_help();}
help_env_callback(Widget w,XtPointer info,XtPointer context)20999 static void help_env_callback(Widget w, XtPointer info, XtPointer context) {env_help();}
help_marks_callback(Widget w,XtPointer info,XtPointer context)21000 static void help_marks_callback(Widget w, XtPointer info, XtPointer context) {marks_help();}
help_mix_callback(Widget w,XtPointer info,XtPointer context)21001 static void help_mix_callback(Widget w, XtPointer info, XtPointer context) {mix_help();}
help_sound_files_callback(Widget w,XtPointer info,XtPointer context)21002 static void help_sound_files_callback(Widget w, XtPointer info, XtPointer context) {sound_files_help();}
help_keys_callback(Widget w,XtPointer info,XtPointer context)21003 static void help_keys_callback(Widget w, XtPointer info, XtPointer context) {key_help();}
help_play_callback(Widget w,XtPointer info,XtPointer context)21004 static void help_play_callback(Widget w, XtPointer info, XtPointer context) {play_help();}
help_filter_callback(Widget w,XtPointer info,XtPointer context)21005 static void help_filter_callback(Widget w, XtPointer info, XtPointer context) {filter_help();}
help_save_callback(Widget w,XtPointer info,XtPointer context)21006 static void help_save_callback(Widget w, XtPointer info, XtPointer context) {save_help();}
help_reverb_callback(Widget w,XtPointer info,XtPointer context)21007 static void help_reverb_callback(Widget w, XtPointer info, XtPointer context) {reverb_help();}
help_resample_callback(Widget w,XtPointer info,XtPointer context)21008 static void help_resample_callback(Widget w, XtPointer info, XtPointer context) {resample_help();}
help_insert_callback(Widget w,XtPointer info,XtPointer context)21009 static void help_insert_callback(Widget w, XtPointer info, XtPointer context) {insert_help();}
help_delete_callback(Widget w,XtPointer info,XtPointer context)21010 static void help_delete_callback(Widget w, XtPointer info, XtPointer context) {delete_help();}
help_region_callback(Widget w,XtPointer info,XtPointer context)21011 static void help_region_callback(Widget w, XtPointer info, XtPointer context) {region_help();}
help_selection_callback(Widget w,XtPointer info,XtPointer context)21012 static void help_selection_callback(Widget w, XtPointer info, XtPointer context) {selection_help();}
help_colors_callback(Widget w,XtPointer info,XtPointer context)21013 static void help_colors_callback(Widget w, XtPointer info, XtPointer context) {colors_help();}
21014 
check_menu_labels(int key,int state,bool extended)21015 void check_menu_labels(int key, int state, bool extended)
21016 {
21017   /* user has redefined key, so erase old key binding info from the menu label */
21018   if (extended)
21019     {
21020       if (state == ControlMask)
21021 	{
21022 	  if (key == snd_K_f) set_label(file_open_menu, "Open"); else
21023 	  if (key == snd_K_s) set_label(file_save_menu, "Save"); else
21024 	  if (key == snd_K_q) set_label(file_mix_menu, "Mix"); else
21025 	  if (key == snd_K_i) set_label(file_insert_menu, "Insert"); else
21026 	  if (key == snd_K_u) set_label(edit_undo_menu, "Undo"); else
21027 	  if (key == snd_K_r) set_label(edit_redo_menu, "Redo");
21028 	}
21029       else
21030 	{
21031 	  if (key == snd_K_k) set_label(file_close_menu, "Close"); else
21032 	  if (key == snd_K_i) set_label(edit_paste_menu, "Insert Selection"); else
21033 	  if (key == snd_K_q) set_label(edit_mix_menu, "Mix Selection"); else
21034 #if WITH_AUDIO
21035 	  if (key == snd_K_p) set_label(edit_play_menu, "Play Selection"); else
21036 #endif
21037 	  if (key == snd_K_w) set_label(edit_save_as_menu, "Save Selection");
21038 	}
21039     }
21040 #if HAVE_EXTENSION_LANGUAGE
21041   else
21042     {
21043       if ((key == snd_K_s) && (state == ControlMask))
21044 	set_label(edit_find_menu, I_FIND);
21045     }
21046 #endif
21047 }
21048 
21049 
21050 /* -------------------------------- MAIN MENU -------------------------------- */
21051 
menu_drag_watcher(Widget w,const char * str,Position x,Position y,drag_style_t dtype,void * data)21052 static void menu_drag_watcher(Widget w, const char *str, Position x, Position y, drag_style_t dtype, void *data)
21053 {
21054   char *new_title;
21055   switch (dtype)
21056     {
21057     case DRAG_ENTER:
21058       new_title = mus_format("%s: drop to open file", ss->startup_title);
21059       XtVaSetValues(main_shell(ss), XmNtitle, (char *)new_title, NULL);
21060       XmChangeColor(w, ss->selection_color);
21061       free(new_title);
21062       break;
21063 
21064     case DRAG_LEAVE:
21065       reflect_file_change_in_title();
21066       XmChangeColor(w, ss->highlight_color);
21067       break;
21068 
21069     default:
21070       break;
21071     }
21072 }
21073 
21074 
menu_drop_watcher(Widget w,const char * str,Position x,Position y,void * data)21075 static void menu_drop_watcher(Widget w, const char *str, Position x, Position y, void *data)
21076 {
21077   snd_info *sp = NULL;
21078   ss->open_requestor = FROM_DRAG_AND_DROP;
21079   sp = snd_open_file(str, FILE_READ_WRITE);
21080   if (sp) select_channel(sp, 0);
21081 }
21082 
21083 
add_menu_drop(void)21084 void add_menu_drop(void)
21085 {
21086   add_drag_and_drop(main_menu, menu_drop_watcher, menu_drag_watcher, NULL);
21087 }
21088 
21089 
add_menu(void)21090 Widget add_menu(void)
21091 {
21092   static Arg main_args[12];
21093   static Arg in_args[12];
21094   static Arg high_args[12];
21095   Arg sep_args[12];
21096   int in_n = 0, n, high_n = 0, main_n = 0, start_high_n, k, j;
21097 
21098   ss->mw = (Widget *)calloc(NUM_MENU_WIDGETS, sizeof(Widget));
21099 
21100   XtSetArg(main_args[main_n], XmNbackground, ss->basic_color); main_n++;
21101   XtSetArg(high_args[high_n], XmNbackground, ss->highlight_color); high_n++;
21102   XtSetArg(in_args[in_n], XmNbackground, ss->basic_color); in_n++;
21103 
21104   start_high_n = high_n;
21105   XtSetArg(in_args[in_n], XmNsensitive, false); in_n++;
21106 
21107   n = high_n;
21108   XtSetArg(high_args[n], XmNtopAttachment, XmATTACH_FORM); n++;
21109   XtSetArg(high_args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
21110   XtSetArg(high_args[n], XmNleftAttachment, XmATTACH_FORM); n++;
21111   XtSetArg(high_args[n], XmNrightAttachment, XmATTACH_FORM); n++;
21112 
21113   main_menu = XmCreateMenuBar(main_pane(ss), (char *)"menuBar", high_args, n);
21114 
21115 
21116   /* FILE MENU */
21117   XtSetArg(main_args[main_n], XmNuserData, (XtPointer)0);
21118   file_menu = XmCreatePulldownMenu(main_menu, (char *)"File", main_args, main_n + 1);
21119 
21120   high_n = start_high_n;
21121   XtSetArg(high_args[high_n], XmNsubMenuId, file_menu); high_n++;
21122   XtSetArg(high_args[high_n], XmNmnemonic, 'F'); high_n++;
21123   XtSetArg(high_args[high_n], XmNuserData, (XtPointer)0); high_n++;
21124   file_cascade_menu = XtCreateManagedWidget("File", xmCascadeButtonWidgetClass, main_menu, high_args, high_n);
21125 
21126   file_open_menu = XtCreateManagedWidget("Open", xmPushButtonWidgetClass, file_menu, main_args, main_n);
21127   XtAddCallback(file_open_menu, XmNactivateCallback, file_open_callback, NULL);
21128   XtVaSetValues(file_open_menu, XmNmnemonic, 'O', NULL);
21129 
21130   file_close_menu = XtCreateManagedWidget("Close", xmPushButtonWidgetClass, file_menu, in_args, in_n);
21131   XtAddCallback(file_close_menu, XmNactivateCallback, file_close_callback, NULL);
21132   XtVaSetValues(file_close_menu, XmNmnemonic, 'C', NULL);
21133 
21134   file_close_all_menu = XtCreateWidget("Close all", xmPushButtonWidgetClass, file_menu, main_args, main_n);
21135   XtAddCallback(file_close_all_menu, XmNactivateCallback, file_close_all_callback, NULL);
21136 
21137   file_save_menu = XtCreateManagedWidget("Save", xmPushButtonWidgetClass, file_menu, in_args, in_n);
21138   XtAddCallback(file_save_menu, XmNactivateCallback, file_save_callback, NULL);
21139   XtVaSetValues(file_save_menu, XmNmnemonic, 'S', NULL);
21140 
21141   file_save_as_menu = XtCreateManagedWidget("Save as", xmPushButtonWidgetClass, file_menu, in_args, in_n);
21142   XtAddCallback(file_save_as_menu, XmNactivateCallback, file_save_as_callback, NULL);
21143   XtVaSetValues(file_save_as_menu, XmNmnemonic, 'a', NULL);
21144 
21145   file_revert_menu = XtCreateManagedWidget("Revert", xmPushButtonWidgetClass, file_menu, in_args, in_n);
21146   XtAddCallback(file_revert_menu, XmNactivateCallback, file_revert_callback, NULL);
21147   XtVaSetValues(file_revert_menu, XmNmnemonic, 'R', NULL);
21148 
21149   file_mix_menu = XtCreateManagedWidget("Mix", xmPushButtonWidgetClass, file_menu, in_args, in_n);
21150   XtAddCallback(file_mix_menu, XmNactivateCallback, file_mix_callback_1, NULL);
21151   XtVaSetValues(file_mix_menu, XmNmnemonic, 'M', NULL);
21152 
21153   file_insert_menu = XtCreateManagedWidget("Insert", xmPushButtonWidgetClass, file_menu, in_args, in_n);
21154   XtAddCallback(file_insert_menu, XmNactivateCallback, file_insert_callback_1, NULL);
21155   XtVaSetValues(file_insert_menu, XmNmnemonic, 'I', NULL);
21156 
21157   file_update_menu = XtCreateManagedWidget("Update", xmPushButtonWidgetClass, file_menu, in_args, in_n);
21158   XtAddCallback(file_update_menu, XmNactivateCallback, file_update_callback, NULL);
21159   XtVaSetValues(file_update_menu, XmNmnemonic, 'U', NULL);
21160 
21161   file_new_menu = XtCreateManagedWidget("New", xmPushButtonWidgetClass, file_menu, main_args, main_n);
21162   XtAddCallback(file_new_menu, XmNactivateCallback, file_new_callback, NULL);
21163   XtVaSetValues(file_new_menu, XmNmnemonic, 'N', NULL);
21164 
21165   file_view_menu = XtCreateManagedWidget("View", xmPushButtonWidgetClass, file_menu, main_args, main_n);
21166   XtAddCallback(file_view_menu, XmNactivateCallback, file_view_callback, NULL);
21167   XtVaSetValues(file_view_menu, XmNmnemonic, 'V', NULL);
21168 
21169   file_print_menu = XtCreateManagedWidget("Print", xmPushButtonWidgetClass, file_menu, in_args, in_n);
21170   XtAddCallback(file_print_menu, XmNactivateCallback, file_print_callback_1, NULL);
21171   XtVaSetValues(file_print_menu, XmNmnemonic, 'P', NULL);
21172 
21173   j = 0;
21174   XtSetArg(sep_args[j], XmNbackground, ss->basic_color); j++;
21175   XtSetArg(sep_args[j], XmNseparatorType, XmSHADOW_ETCHED_IN); j++;
21176   file_sep_menu = XtCreateManagedWidget("", xmSeparatorWidgetClass, file_menu, sep_args, j);
21177 
21178   file_exit_menu = XtCreateManagedWidget("Exit", xmPushButtonWidgetClass, file_menu, main_args, main_n);
21179   XtAddCallback(file_exit_menu, XmNactivateCallback, file_exit_callback, NULL);
21180   XtVaSetValues(file_exit_menu, XmNmnemonic, 'E', NULL);
21181 
21182 
21183   /* EDIT MENU */
21184   XtSetArg(main_args[main_n], XmNuserData, (XtPointer)1);
21185   edit_menu = XmCreatePulldownMenu(main_menu, (char *)"Edit", main_args, main_n + 1);
21186 
21187   high_n = start_high_n;
21188   XtSetArg(high_args[high_n], XmNsubMenuId, edit_menu); high_n++;
21189   XtSetArg(high_args[high_n], XmNmnemonic, 'E'); high_n++;
21190   XtSetArg(high_args[high_n], XmNuserData, (XtPointer)1); high_n++;
21191   edit_cascade_menu = XtCreateManagedWidget("Edit", xmCascadeButtonWidgetClass, main_menu, high_args, high_n);
21192 
21193   edit_undo_menu = XtCreateManagedWidget("Undo", xmPushButtonWidgetClass, edit_menu, in_args, in_n);
21194   XtAddCallback(edit_undo_menu, XmNactivateCallback, edit_undo_callback, NULL);
21195   XtVaSetValues(edit_undo_menu, XmNmnemonic, 'U', NULL);
21196 
21197   edit_redo_menu = XtCreateManagedWidget("Redo", xmPushButtonWidgetClass, edit_menu, in_args, in_n);
21198   XtAddCallback(edit_redo_menu, XmNactivateCallback, edit_redo_callback, NULL);
21199   XtVaSetValues(edit_redo_menu, XmNmnemonic, 'R', NULL);
21200 
21201 #if HAVE_EXTENSION_LANGUAGE
21202   edit_find_menu = XtCreateManagedWidget(I_FIND, xmPushButtonWidgetClass, edit_menu, in_args, in_n);
21203   XtAddCallback(edit_find_menu, XmNactivateCallback, edit_find_callback_1, NULL);
21204   XtVaSetValues(edit_find_menu, XmNmnemonic, 'F', NULL);
21205 #endif
21206 
21207   edit_select_sep_menu = XtCreateManagedWidget("", xmSeparatorWidgetClass, edit_menu, sep_args, j);
21208 
21209   edit_cut_menu = XtCreateManagedWidget("Delete selection", xmPushButtonWidgetClass, edit_menu, in_args, in_n);
21210   XtAddCallback(edit_cut_menu, XmNactivateCallback, edit_cut_callback, NULL);
21211   XtVaSetValues(edit_cut_menu, XmNmnemonic, 'C', NULL);
21212 
21213   edit_paste_menu = XtCreateManagedWidget("Insert selection", xmPushButtonWidgetClass, edit_menu, in_args, in_n);
21214   XtAddCallback(edit_paste_menu, XmNactivateCallback, edit_paste_callback, NULL);
21215   XtVaSetValues(edit_paste_menu, XmNmnemonic, 'P', NULL);
21216 
21217   edit_mix_menu = XtCreateManagedWidget("Mix selection", xmPushButtonWidgetClass, edit_menu, in_args, in_n);
21218   XtAddCallback(edit_mix_menu, XmNactivateCallback, edit_mix_callback, NULL);
21219   XtVaSetValues(edit_mix_menu, XmNmnemonic, 'M', NULL);
21220 
21221 #if WITH_AUDIO
21222   edit_play_menu = XtCreateManagedWidget("Play selection", xmPushButtonWidgetClass, edit_menu, in_args, in_n);
21223   XtAddCallback(edit_play_menu, XmNactivateCallback, edit_play_callback, NULL);
21224   XtVaSetValues(edit_play_menu, XmNmnemonic, 'P', NULL);
21225 #endif
21226 
21227   edit_save_as_menu = XtCreateManagedWidget("Save selection", xmPushButtonWidgetClass, edit_menu, in_args, in_n);
21228   XtAddCallback(edit_save_as_menu, XmNactivateCallback, edit_save_as_callback, NULL);
21229   XtVaSetValues(edit_save_as_menu, XmNmnemonic, 'S', NULL);
21230 
21231   edit_select_all_menu = XtCreateManagedWidget("Select all", xmPushButtonWidgetClass, edit_menu, in_args, in_n);
21232   XtAddCallback(edit_select_all_menu, XmNactivateCallback, edit_select_all_callback, NULL);
21233 
21234   edit_unselect_menu = XtCreateManagedWidget("Unselect all", xmPushButtonWidgetClass, edit_menu, in_args, in_n);
21235   XtAddCallback(edit_unselect_menu, XmNactivateCallback, edit_unselect_callback, NULL);
21236 
21237   edit_edit_sep_menu = XtCreateManagedWidget("", xmSeparatorWidgetClass, edit_menu, sep_args, j);
21238 
21239   edit_env_menu = XtCreateManagedWidget("Edit envelope", xmPushButtonWidgetClass, edit_menu, main_args, main_n);
21240   XtAddCallback(edit_env_menu, XmNactivateCallback, edit_envelope_callback, NULL);
21241   XtVaSetValues(edit_env_menu, XmNmnemonic, 'E', NULL);
21242 
21243   edit_header_menu = XtCreateManagedWidget("Edit header", xmPushButtonWidgetClass, edit_menu, in_args, in_n);
21244   XtAddCallback(edit_header_menu, XmNactivateCallback, edit_header_callback_1, NULL);
21245   XtVaSetValues(edit_header_menu, XmNmnemonic, 'H', NULL);
21246 
21247 
21248   /* VIEW MENU */
21249   XtSetArg(main_args[main_n], XmNuserData, (XtPointer)2);
21250   view_menu = XmCreatePulldownMenu(main_menu, (char *)"View", main_args, main_n + 1);
21251 
21252   high_n = start_high_n;
21253   XtSetArg(high_args[high_n], XmNsubMenuId, view_menu); high_n++;
21254   XtSetArg(high_args[high_n], XmNmnemonic, 'V'); high_n++;
21255   XtSetArg(high_args[high_n], XmNuserData, (XtPointer)2); high_n++;
21256   view_cascade_menu = XtCreateManagedWidget("View", xmCascadeButtonWidgetClass, main_menu, high_args, high_n);
21257 
21258 #if HAVE_EXTENSION_LANGUAGE
21259   view_listener_menu = XtCreateManagedWidget("Open listener", xmPushButtonWidgetClass, view_menu, main_args, main_n);
21260   XtAddCallback(view_listener_menu, XmNactivateCallback, view_listener_callback, NULL);
21261   XtVaSetValues(view_listener_menu, XmNmnemonic, 'L', NULL);
21262 #endif
21263 
21264   view_files_menu = XtCreateManagedWidget("Files", xmPushButtonWidgetClass, view_menu, main_args, main_n);
21265   XtAddCallback(view_files_menu, XmNactivateCallback, view_files_callback, NULL);
21266   XtVaSetValues(view_files_menu, XmNmnemonic, 'F', NULL);
21267 
21268   view_mix_dialog_menu = XtCreateManagedWidget("Mixes", xmPushButtonWidgetClass, view_menu, main_args, main_n);
21269   XtAddCallback(view_mix_dialog_menu, XmNactivateCallback, view_mix_dialog_callback, NULL);
21270 
21271   view_region_menu = XtCreateManagedWidget("Regions", xmPushButtonWidgetClass, view_menu, in_args, in_n);
21272   XtAddCallback(view_region_menu, XmNactivateCallback, view_region_callback_1, NULL);
21273   XtVaSetValues(view_region_menu, XmNmnemonic, 'R', NULL);
21274 
21275   view_color_orientation_menu = XtCreateManagedWidget("Color/Orientation", xmPushButtonWidgetClass, view_menu, main_args, main_n);
21276   XtAddCallback(view_color_orientation_menu, XmNactivateCallback, view_color_orientation_callback_1, NULL);
21277 
21278   view_controls_menu = XtCreateManagedWidget("Show controls", xmPushButtonWidgetClass, view_menu, main_args, main_n);
21279   XtAddCallback(view_controls_menu, XmNactivateCallback, view_controls_callback, NULL);
21280   XtVaSetValues(view_controls_menu, XmNmnemonic, 'S', NULL);
21281 
21282   view_sep2_menu = XtCreateManagedWidget("", xmSeparatorWidgetClass, view_menu, sep_args, j);
21283 
21284   view_graph_style_menu = XmCreatePulldownMenu(view_menu, (char *)"graph-style", main_args, main_n);
21285 
21286   k = main_n;
21287   XtSetArg(main_args[k], XmNsubMenuId, view_graph_style_menu); k++;
21288   view_graph_style_cascade_menu = XtCreateManagedWidget(I_LINES_OR_DOTS, xmCascadeButtonWidgetClass, view_menu, main_args, k);
21289 
21290   view_lines_menu = XtCreateManagedWidget("lines", xmPushButtonWidgetClass, view_graph_style_menu, main_args, main_n);
21291   XtAddCallback(view_lines_menu, XmNactivateCallback, view_lines_callback, NULL);
21292   if (graph_style(ss) == GRAPH_LINES) set_sensitive(view_lines_menu, false);
21293 
21294   view_dots_menu = XtCreateManagedWidget("dots", xmPushButtonWidgetClass, view_graph_style_menu, main_args, main_n);
21295   XtAddCallback(view_dots_menu, XmNactivateCallback, view_dots_callback, NULL);
21296   if (graph_style(ss) == GRAPH_DOTS) set_sensitive(view_dots_menu, false);
21297 
21298   view_filled_menu = XtCreateManagedWidget("filled", xmPushButtonWidgetClass, view_graph_style_menu, main_args, main_n);
21299   XtAddCallback(view_filled_menu, XmNactivateCallback, view_filled_callback, NULL);
21300   if (graph_style(ss) == GRAPH_FILLED) set_sensitive(view_filled_menu, false);
21301 
21302   view_dots_and_lines_menu = XtCreateManagedWidget("dots and lines", xmPushButtonWidgetClass, view_graph_style_menu, main_args, main_n);
21303   XtAddCallback(view_dots_and_lines_menu, XmNactivateCallback, view_dots_and_lines_callback, NULL);
21304   if (graph_style(ss) == GRAPH_DOTS_AND_LINES) set_sensitive(view_dots_and_lines_menu, false);
21305 
21306   view_lollipops_menu = XtCreateManagedWidget("lollipops", xmPushButtonWidgetClass, view_graph_style_menu, main_args, main_n);
21307   XtAddCallback(view_lollipops_menu, XmNactivateCallback, view_lollipops_callback, NULL);
21308   if (graph_style(ss) == GRAPH_LOLLIPOPS) set_sensitive(view_lollipops_menu, false);
21309 
21310   view_cursor_menu = XtCreateManagedWidget("Verbose cursor", xmPushButtonWidgetClass, view_menu, main_args, main_n);
21311   XtAddCallback(view_cursor_menu, XmNactivateCallback, view_cursor_callback, NULL);
21312 
21313 #if HAVE_EXTENSION_LANGUAGE
21314   view_inset_menu = XtCreateManagedWidget("With inset graph", xmPushButtonWidgetClass, view_menu, main_args, main_n);
21315   XtAddCallback(view_inset_menu, XmNactivateCallback, view_inset_callback, NULL);
21316 #endif
21317 
21318   view_combine_menu = XmCreatePulldownMenu(view_menu, (char *)"combine", main_args, main_n);
21319 
21320   k = main_n;
21321   XtSetArg(main_args[k], XmNsubMenuId, view_combine_menu); k++;
21322   view_combine_cascade_menu = XtCreateManagedWidget(I_CHANNEL_LAYOUT, xmCascadeButtonWidgetClass, view_menu, main_args, k);
21323 
21324   view_combine_separate_menu = XtCreateManagedWidget("separate", xmPushButtonWidgetClass, view_combine_menu, main_args, main_n);
21325   XtAddCallback(view_combine_separate_menu, XmNactivateCallback, view_separate_callback, NULL);
21326   if (channel_style(ss) == CHANNELS_SEPARATE) set_sensitive(view_combine_separate_menu, false);
21327 
21328   view_combine_combined_menu = XtCreateManagedWidget("combined", xmPushButtonWidgetClass, view_combine_menu, main_args, main_n);
21329   XtAddCallback(view_combine_combined_menu, XmNactivateCallback, view_combined_callback, NULL);
21330   if (channel_style(ss) == CHANNELS_COMBINED) set_sensitive(view_combine_combined_menu, false);
21331 
21332   view_combine_superimposed_menu = XtCreateManagedWidget("superimposed", xmPushButtonWidgetClass, view_combine_menu, main_args, main_n);
21333   XtAddCallback(view_combine_superimposed_menu, XmNactivateCallback, view_superimposed_callback, NULL);
21334   if (channel_style(ss) == CHANNELS_SUPERIMPOSED) set_sensitive(view_combine_superimposed_menu, false);
21335 
21336   view_zero_menu = XtCreateManagedWidget("Show y = 0", xmPushButtonWidgetClass, view_menu, main_args, main_n);
21337   XtAddCallback(view_zero_menu, XmNactivateCallback, view_zero_callback, NULL);
21338   XtVaSetValues(view_zero_menu, XmNmnemonic, 'y', NULL);
21339 
21340   view_x_axis_menu = XmCreatePulldownMenu(view_menu, (char *)"xaxis", main_args, main_n);
21341 
21342   k = main_n;
21343   XtSetArg(main_args[k], XmNsubMenuId, view_x_axis_menu); k++;
21344   view_x_axis_cascade_menu = XtCreateManagedWidget("X axis units", xmCascadeButtonWidgetClass, view_menu, main_args, k);
21345 
21346   view_x_axis_seconds_menu = XtCreateManagedWidget("seconds", xmPushButtonWidgetClass, view_x_axis_menu, main_args, main_n);
21347   XtAddCallback(view_x_axis_seconds_menu, XmNactivateCallback, view_x_axis_seconds_callback, NULL);
21348   set_sensitive(view_x_axis_seconds_menu, false);
21349 
21350   view_x_axis_samples_menu = XtCreateManagedWidget("samples", xmPushButtonWidgetClass, view_x_axis_menu, main_args, main_n);
21351   XtAddCallback(view_x_axis_samples_menu, XmNactivateCallback, view_x_axis_samples_callback, NULL);
21352 
21353   view_x_axis_clock_menu = XtCreateManagedWidget("clock", xmPushButtonWidgetClass, view_x_axis_menu, main_args, main_n);
21354   XtAddCallback(view_x_axis_clock_menu, XmNactivateCallback, view_x_axis_clock_callback, NULL);
21355 
21356   view_x_axis_percentage_menu = XtCreateManagedWidget("percentage", xmPushButtonWidgetClass, view_x_axis_menu, main_args, main_n);
21357   XtAddCallback(view_x_axis_percentage_menu, XmNactivateCallback, view_x_axis_percentage_callback, NULL);
21358 
21359   view_x_axis_beats_menu = XtCreateManagedWidget("beats", xmPushButtonWidgetClass, view_x_axis_menu, main_args, main_n);
21360   XtAddCallback(view_x_axis_beats_menu, XmNactivateCallback, view_x_axis_beats_callback, NULL);
21361 
21362   view_x_axis_measures_menu = XtCreateManagedWidget("measures", xmPushButtonWidgetClass, view_x_axis_menu, main_args, main_n);
21363   XtAddCallback(view_x_axis_measures_menu, XmNactivateCallback, view_x_axis_measures_callback, NULL);
21364 
21365 
21366   view_axes_menu = XmCreatePulldownMenu(view_menu, (char *)"axes", main_args, main_n);
21367 
21368   k = main_n;
21369   XtSetArg(main_args[k], XmNsubMenuId, view_axes_menu); k++;
21370   view_axes_cascade_menu = XtCreateManagedWidget(I_AXIS_LAYOUT, xmCascadeButtonWidgetClass, view_menu, main_args, k);
21371 
21372   view_no_axes_menu = XtCreateManagedWidget("no axes", xmPushButtonWidgetClass, view_axes_menu, main_args, main_n);
21373   XtAddCallback(view_no_axes_menu, XmNactivateCallback, view_no_axes_callback, NULL);
21374   if (show_axes(ss) == SHOW_NO_AXES) set_sensitive(view_no_axes_menu, false); /* false because it is already chosen */
21375 
21376   view_all_axes_menu = XtCreateManagedWidget("both axes", xmPushButtonWidgetClass, view_axes_menu, main_args, main_n);
21377   XtAddCallback(view_all_axes_menu, XmNactivateCallback, view_all_axes_callback, NULL);
21378   if (show_axes(ss) == SHOW_ALL_AXES) set_sensitive(view_all_axes_menu, false);
21379 
21380   view_just_x_axis_menu = XtCreateManagedWidget("just x axis", xmPushButtonWidgetClass, view_axes_menu, main_args, main_n);
21381   XtAddCallback(view_just_x_axis_menu, XmNactivateCallback, view_just_x_axis_callback, NULL);
21382   if (show_axes(ss) == SHOW_X_AXIS) set_sensitive(view_just_x_axis_menu, false);
21383 
21384   view_all_axes_unlabelled_menu = XtCreateManagedWidget("both axes, no labels", xmPushButtonWidgetClass, view_axes_menu, main_args, main_n);
21385   XtAddCallback(view_all_axes_unlabelled_menu, XmNactivateCallback, view_all_axes_unlabelled_callback, NULL);
21386   if (show_axes(ss) == SHOW_ALL_AXES_UNLABELLED) set_sensitive(view_all_axes_unlabelled_menu, false);
21387 
21388   view_just_x_axis_unlabelled_menu = XtCreateManagedWidget("just x axis, no label", xmPushButtonWidgetClass, view_axes_menu, main_args, main_n);
21389   XtAddCallback(view_just_x_axis_unlabelled_menu, XmNactivateCallback, view_just_x_axis_unlabelled_callback, NULL);
21390   if (show_axes(ss) == SHOW_X_AXIS_UNLABELLED) set_sensitive(view_just_x_axis_unlabelled_menu, false);
21391 
21392   view_bare_x_axis_menu = XtCreateManagedWidget("bare x axis", xmPushButtonWidgetClass, view_axes_menu, main_args, main_n);
21393   XtAddCallback(view_bare_x_axis_menu, XmNactivateCallback, view_bare_x_axis_callback, NULL);
21394   if (show_axes(ss) == SHOW_BARE_X_AXIS) set_sensitive(view_bare_x_axis_menu, false);
21395 
21396   view_focus_style_menu = XmCreatePulldownMenu(view_menu, (char *)"focusstyle", main_args, main_n);
21397 
21398   k = main_n;
21399   XtSetArg(main_args[k], XmNsubMenuId, view_focus_style_menu); k++;
21400   view_focus_cascade_menu = XtCreateManagedWidget(I_ZOOM_CENTERS_ON, xmCascadeButtonWidgetClass, view_menu, main_args, k);
21401 
21402   view_focus_left_menu = XtCreateManagedWidget("window left edge", xmPushButtonWidgetClass, view_focus_style_menu, main_args, main_n);
21403   XtAddCallback(view_focus_left_menu, XmNactivateCallback, view_focus_left_callback, NULL);
21404 
21405   view_focus_right_menu = XtCreateManagedWidget("window right edge", xmPushButtonWidgetClass, view_focus_style_menu, main_args, main_n);
21406   XtAddCallback(view_focus_right_menu, XmNactivateCallback, view_focus_right_callback, NULL);
21407 
21408   view_focus_middle_menu = XtCreateManagedWidget("window midpoint", xmPushButtonWidgetClass, view_focus_style_menu, main_args, main_n);
21409   XtAddCallback(view_focus_middle_menu, XmNactivateCallback, view_focus_middle_callback, NULL);
21410 
21411   view_focus_active_menu = XtCreateManagedWidget("cursor or selection", xmPushButtonWidgetClass, view_focus_style_menu, main_args, main_n);
21412   XtAddCallback(view_focus_active_menu, XmNactivateCallback, view_focus_active_callback, NULL);
21413 
21414 
21415   view_grid_menu = XtCreateManagedWidget("With grid", xmPushButtonWidgetClass, view_menu, main_args, main_n);
21416   XtAddCallback(view_grid_menu, XmNactivateCallback, view_grid_callback, NULL);
21417 
21418 
21419   /* OPTIONS MENU */
21420   XtSetArg(main_args[main_n], XmNuserData, (XtPointer)3);
21421   options_menu = XmCreatePulldownMenu(main_menu, (char *)"Option", main_args, main_n + 1);
21422 
21423   high_n = start_high_n;
21424   XtSetArg(high_args[high_n], XmNsubMenuId, options_menu); high_n++;
21425   XtSetArg(high_args[high_n], XmNmnemonic, 'O'); high_n++;
21426   XtSetArg(high_args[high_n], XmNuserData, (XtPointer)3); high_n++;
21427   options_cascade_menu = XtCreateManagedWidget("Options", xmCascadeButtonWidgetClass, main_menu, high_args, high_n);
21428 
21429   options_transform_menu = XtCreateManagedWidget("Transform options", xmPushButtonWidgetClass, options_menu, main_args, main_n);
21430   XtAddCallback(options_transform_menu, XmNactivateCallback, options_transform_callback, NULL);
21431   XtVaSetValues(options_transform_menu, XmNmnemonic, 't', NULL);
21432 
21433   options_controls_menu = XtCreateManagedWidget("Control panel options", xmPushButtonWidgetClass, options_menu, main_args, main_n);
21434   XtAddCallback(options_controls_menu, XmNactivateCallback, options_controls_callback, NULL);
21435   XtVaSetValues(options_controls_menu, XmNmnemonic, 'c', NULL);
21436 
21437 
21438 #if HAVE_EXTENSION_LANGUAGE
21439   options_save_state_menu = XtCreateManagedWidget("Save session", xmPushButtonWidgetClass, options_menu, main_args, main_n);
21440   XtAddCallback(options_save_state_menu, XmNactivateCallback, options_save_state_callback, NULL);
21441 #endif
21442 
21443   options_sep_menu = XtCreateManagedWidget("", xmSeparatorWidgetClass, options_menu, sep_args, j);
21444 
21445   options_preferences_menu = XtCreateManagedWidget("Preferences", xmPushButtonWidgetClass, options_menu, main_args, main_n);
21446   XtAddCallback(options_preferences_menu, XmNactivateCallback, options_preferences_callback, NULL);
21447 
21448 
21449   /* HELP MENU */
21450   XtSetArg(main_args[main_n], XmNuserData, (XtPointer)4);
21451   help_menu = XmCreatePulldownMenu(main_menu, (char *)I_HELP, main_args, main_n + 1);
21452 
21453   high_n = start_high_n;
21454   XtSetArg(high_args[high_n], XmNsubMenuId, help_menu); high_n++;
21455   XtSetArg(high_args[high_n], XmNmnemonic, 'H'); high_n++;
21456   XtSetArg(high_args[high_n], XmNuserData, (XtPointer)4); high_n++;
21457   help_cascade_menu = XtCreateManagedWidget(I_HELP, xmCascadeButtonWidgetClass, main_menu, high_args, high_n);
21458 
21459   help_about_snd_menu = XtCreateManagedWidget("About Snd", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21460   XtAddCallback(help_about_snd_menu, XmNactivateCallback, help_about_snd_callback, NULL);
21461   XtVaSetValues(help_about_snd_menu, XmNmnemonic, 'O', NULL);
21462 
21463 #if HAVE_EXTENSION_LANGUAGE
21464   help_init_file_menu = XtCreateManagedWidget("Customization", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21465   XtAddCallback(help_init_file_menu, XmNactivateCallback, help_init_file_callback, NULL);
21466 #endif
21467 
21468   help_controls_menu = XtCreateManagedWidget("Control panel", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21469   XtAddCallback(help_controls_menu, XmNactivateCallback, help_controls_callback, NULL);
21470 
21471   help_keys_menu = XtCreateManagedWidget("Key bindings", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21472   XtAddCallback(help_keys_menu, XmNactivateCallback, help_keys_callback, NULL);
21473 
21474   help_play_menu = XtCreateManagedWidget("Play", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21475   XtAddCallback(help_play_menu, XmNactivateCallback, help_play_callback, NULL);
21476 
21477   help_save_menu = XtCreateManagedWidget("Save", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21478   XtAddCallback(help_save_menu, XmNactivateCallback, help_save_callback, NULL);
21479 
21480   help_mix_menu = XtCreateManagedWidget("Mix", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21481   XtAddCallback(help_mix_menu, XmNactivateCallback, help_mix_callback, NULL);
21482 
21483   help_resample_menu = XtCreateManagedWidget("Resample", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21484   XtAddCallback(help_resample_menu, XmNactivateCallback, help_resample_callback, NULL);
21485 
21486   help_fft_menu = XtCreateManagedWidget("FFT", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21487   XtAddCallback(help_fft_menu, XmNactivateCallback, help_fft_callback, NULL);
21488 
21489   help_filter_menu = XtCreateManagedWidget("Filter", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21490   XtAddCallback(help_filter_menu, XmNactivateCallback, help_filter_callback, NULL);
21491 
21492   help_reverb_menu = XtCreateManagedWidget("Reverb", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21493   XtAddCallback(help_reverb_menu, XmNactivateCallback, help_reverb_callback, NULL);
21494 
21495   help_env_menu = XtCreateManagedWidget("Envelope", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21496   XtAddCallback(help_env_menu, XmNactivateCallback, help_env_callback, NULL);
21497 
21498   help_marks_menu = XtCreateManagedWidget("Mark", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21499   XtAddCallback(help_marks_menu, XmNactivateCallback, help_marks_callback, NULL);
21500 
21501   help_insert_menu = XtCreateManagedWidget("Insert", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21502   XtAddCallback(help_insert_menu, XmNactivateCallback, help_insert_callback, NULL);
21503 
21504   help_delete_menu = XtCreateManagedWidget("Delete", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21505   XtAddCallback(help_delete_menu, XmNactivateCallback, help_delete_callback, NULL);
21506 
21507   help_undo_menu = XtCreateManagedWidget("Undo and redo", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21508   XtAddCallback(help_undo_menu, XmNactivateCallback, help_undo_callback, NULL);
21509 
21510 #if HAVE_EXTENSION_LANGUAGE
21511   help_find_menu = XtCreateManagedWidget("Search", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21512   XtAddCallback(help_find_menu, XmNactivateCallback, help_find_callback, NULL);
21513 #endif
21514 
21515   help_sync_menu = XtCreateManagedWidget("Sync and unite", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21516   XtAddCallback(help_sync_menu, XmNactivateCallback, help_sync_callback, NULL);
21517 
21518   help_sound_files_menu = XtCreateManagedWidget("Headers and data", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21519   XtAddCallback(help_sound_files_menu, XmNactivateCallback, help_sound_files_callback, NULL);
21520 
21521   help_debug_menu = XtCreateManagedWidget("Debugging", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21522   XtAddCallback(help_debug_menu, XmNactivateCallback, help_debug_callback, NULL);
21523 
21524   help_region_menu = XtCreateManagedWidget("Regions", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21525   XtAddCallback(help_region_menu, XmNactivateCallback, help_region_callback, NULL);
21526 
21527   help_selection_menu = XtCreateManagedWidget("Selections", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21528   XtAddCallback(help_selection_menu, XmNactivateCallback, help_selection_callback, NULL);
21529 
21530   help_colors_menu = XtCreateManagedWidget("Colors", xmPushButtonWidgetClass, help_menu, main_args, main_n);
21531   XtAddCallback(help_colors_menu, XmNactivateCallback, help_colors_callback, NULL);
21532 
21533   XtVaSetValues(main_menu, XmNmenuHelpWidget, help_cascade_menu, NULL);
21534 
21535   XtAddCallback(file_cascade_menu, XmNcascadingCallback, file_menu_update_1, NULL);
21536   XtAddCallback(edit_cascade_menu, XmNcascadingCallback, edit_menu_update_1, NULL);
21537   XtAddCallback(view_cascade_menu, XmNcascadingCallback, view_menu_update_1, NULL);
21538 
21539   XtManageChild(main_menu);
21540   return(main_menu);
21541 }
21542 
21543 
21544 /* -------------------------------- POPUP MENU -------------------------------- */
21545 
21546 static Widget basic_popup_menu = NULL, selection_popup_menu = NULL, fft_popup_menu = NULL;
21547 
add_menu_item(Widget menu,const char * label,void (* callback)(Widget w,XtPointer info,XtPointer context))21548 static Widget add_menu_item(Widget menu, const char *label, void (*callback)(Widget w, XtPointer info, XtPointer context))
21549 {
21550   Arg args[20];
21551   int n;
21552   Widget w;
21553 
21554   n = 0;
21555   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
21556   w = XtCreateManagedWidget(label, xmPushButtonWidgetClass, menu, args, n);
21557   XtAddCallback(w, XmNactivateCallback, callback, NULL);
21558   return(w);
21559 }
21560 
popup_info_callback(Widget w,XtPointer info,XtPointer context)21561 static void popup_info_callback(Widget w, XtPointer info, XtPointer context)
21562 {
21563   snd_info *sp;
21564   sp = any_selected_sound();
21565   if (sp) display_info(sp);
21566 }
21567 
popup_normalize_callback(Widget w,XtPointer info,XtPointer context)21568 static void popup_normalize_callback(Widget w, XtPointer info, XtPointer context)
21569 {
21570   mus_float_t scl[1];
21571   scl[0] = 1.0;
21572   scale_to(any_selected_sound(), current_channel(), scl, 1, OVER_SOUND);
21573 }
21574 
21575 
popup_reverse_callback(Widget w,XtPointer info,XtPointer context)21576 static void popup_reverse_callback(Widget w, XtPointer info, XtPointer context)
21577 {
21578   reverse_sound(current_channel(), OVER_SOUND, C_int_to_Xen_integer(AT_CURRENT_EDIT_POSITION), 0);
21579 }
21580 
21581 
stop_everything_callback(Widget w,XtPointer info,XtPointer context)21582 static void stop_everything_callback(Widget w, XtPointer info, XtPointer context)
21583 {
21584   control_g(any_selected_sound());
21585 }
21586 
21587 
play_channel_callback(Widget w,XtPointer info,XtPointer context)21588 static void play_channel_callback(Widget w, XtPointer info, XtPointer context)
21589 {
21590   chan_info *cp;
21591   cp = current_channel();
21592   play_channel(cp, 0, current_samples(cp));
21593 }
21594 
21595 
21596 static Widget popup_play;
21597 
post_basic_popup_menu(void * e)21598 void post_basic_popup_menu(void *e)
21599 {
21600   XButtonPressedEvent *event = (XButtonPressedEvent *)e;
21601   snd_info *sp;
21602   if (!basic_popup_menu)
21603     {
21604       Arg args[20];
21605       int n;
21606 
21607       n = 0;
21608       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
21609       XtSetArg(args[n], XmNpopupEnabled, false); n++;      /* this was XmPOPUP_AUTOMATIC_RECURSIVE */
21610       basic_popup_menu = XmCreatePopupMenu(main_pane(ss), (char *)"basic-popup-menu", args, n);
21611 
21612       add_menu_item(basic_popup_menu, "Info",           popup_info_callback);
21613       add_menu_item(basic_popup_menu, "Select all",     edit_select_all_callback);
21614       popup_play = add_menu_item(basic_popup_menu, "Play channel", play_channel_callback);
21615       add_menu_item(basic_popup_menu, "Stop!",          stop_everything_callback);
21616       add_menu_item(basic_popup_menu, "-> 1.0",         popup_normalize_callback);
21617       add_menu_item(basic_popup_menu, "Reverse",        popup_reverse_callback);
21618     }
21619 
21620   XmMenuPosition(basic_popup_menu, event);
21621 
21622   sp = any_selected_sound();
21623   if ((!sp) || (sp->nchans == 1))
21624     XtUnmanageChild(popup_play);
21625   else XtManageChild(popup_play);
21626 
21627   XtManageChild(basic_popup_menu);
21628 }
21629 
21630 
21631 /* -------- selection popup -------- */
21632 
popup_show_selection_callback(Widget w,XtPointer info,XtPointer context)21633 static void popup_show_selection_callback(Widget w, XtPointer info, XtPointer context)
21634 {
21635   show_selection();
21636 }
21637 
popup_zero_selection_callback(Widget w,XtPointer info,XtPointer context)21638 static void popup_zero_selection_callback(Widget w, XtPointer info, XtPointer context)
21639 {
21640   mus_float_t scl[1];
21641   scl[0] = 0.0;
21642   scale_by(NULL, scl, 1, OVER_SELECTION);
21643 }
21644 
popup_normalize_selection_callback(Widget w,XtPointer info,XtPointer context)21645 static void popup_normalize_selection_callback(Widget w, XtPointer info, XtPointer context)
21646 {
21647   mus_float_t scl[1];
21648   scl[0] = 1.0;
21649   scale_to(NULL, NULL, scl, 1, OVER_SELECTION);
21650 }
21651 
popup_error_handler(const char * msg,void * data)21652 static void popup_error_handler(const char *msg, void *data)
21653 {
21654   redirect_snd_error_to(NULL, NULL);
21655   redirect_snd_warning_to(NULL, NULL);
21656   status_report(any_selected_sound(), "%s: %s", (char *)data, msg);
21657 }
21658 
popup_cut_to_new_callback_1(bool cut)21659 static void popup_cut_to_new_callback_1(bool cut)
21660 {
21661   char *temp_file;
21662   io_error_t io_err;
21663 
21664   temp_file = snd_tempnam();
21665   io_err = save_selection(temp_file, selection_srate(), default_output_sample_type(ss), default_output_header_type(ss), NULL, SAVE_ALL_CHANS);
21666   if (io_err == IO_NO_ERROR)
21667     {
21668       if (cut) delete_selection(UPDATE_DISPLAY);
21669 
21670       ss->open_requestor = FROM_POPUP_CUT_TO_NEW;
21671       redirect_snd_error_to(popup_error_handler, (void *)"popup cut->new");
21672       snd_open_file(temp_file, FILE_READ_WRITE);
21673       redirect_snd_error_to(NULL, NULL);
21674 
21675       free(temp_file);
21676     }
21677 }
21678 
popup_cut_to_new_callback(Widget w,XtPointer info,XtPointer context)21679 static void popup_cut_to_new_callback(Widget w, XtPointer info, XtPointer context) {popup_cut_to_new_callback_1(true);}
popup_copy_to_new_callback(Widget w,XtPointer info,XtPointer context)21680 static void popup_copy_to_new_callback(Widget w, XtPointer info, XtPointer context) {popup_cut_to_new_callback_1(false);}
21681 
crop(chan_info * cp)21682 static void crop(chan_info *cp)
21683 {
21684   if (selection_is_active_in_channel(cp))
21685     {
21686       mus_long_t beg, end, framples;
21687       framples = current_samples(cp);
21688       beg = selection_beg(cp);
21689       end = selection_end(cp);
21690       if (beg > 0)
21691 	delete_samples(0, beg, cp, cp->edit_ctr);
21692       if (end < (framples - 1))
21693 	delete_samples(end + 1, framples - end, cp, cp->edit_ctr);
21694     }
21695 }
21696 
popup_crop_callback(Widget w,XtPointer info,XtPointer context)21697 static void popup_crop_callback(Widget w, XtPointer info, XtPointer context)
21698 {
21699   for_each_chan(crop);
21700 }
21701 
21702 
popup_cut_and_smooth_callback(Widget w,XtPointer info,XtPointer context)21703 static void popup_cut_and_smooth_callback(Widget w, XtPointer info, XtPointer context)
21704 {
21705   for_each_chan(cut_and_smooth);
21706 }
21707 
mark_selection(chan_info * cp)21708 static void mark_selection(chan_info *cp)
21709 {
21710   if (selection_is_active_in_channel(cp))
21711     {
21712       add_mark(selection_beg(cp), NULL, cp);
21713       add_mark(selection_end(cp), NULL, cp);
21714     }
21715 }
21716 
popup_mark_selection_callback(Widget w,XtPointer info,XtPointer context)21717 static void popup_mark_selection_callback(Widget w, XtPointer info, XtPointer context)
21718 {
21719   for_each_chan(mark_selection);
21720 }
21721 
popup_reverse_selection_callback(Widget w,XtPointer info,XtPointer context)21722 static void popup_reverse_selection_callback(Widget w, XtPointer info, XtPointer context)
21723 {
21724   reverse_sound(current_channel(), OVER_SELECTION, C_int_to_Xen_integer(AT_CURRENT_EDIT_POSITION), 0);
21725 }
21726 
21727 static mus_float_t selection_max = 0.0;
21728 
selection_info(chan_info * cp)21729 static void selection_info(chan_info *cp)
21730 {
21731   if ((selection_is_active_in_channel(cp)) &&
21732       (selection_maxamp(cp) > selection_max))
21733     selection_max = selection_maxamp(cp);
21734 }
21735 
popup_selection_info_callback(Widget w,XtPointer info,XtPointer context)21736 static void popup_selection_info_callback(Widget w, XtPointer info, XtPointer context)
21737 {
21738   selection_max = 0.0;
21739   for_each_chan(selection_info);
21740   status_report(any_selected_sound(), "selection max: %f", selection_max);
21741 }
21742 
21743 #if WITH_AUDIO
popup_loop_play_callback(Widget w,XtPointer info,XtPointer context)21744 static void popup_loop_play_callback(Widget w, XtPointer info, XtPointer context)
21745 {
21746   if (ss->selection_play_stop)
21747     {
21748       stop_playing_all_sounds(PLAY_BUTTON_UNSET);
21749       reflect_play_selection_stop();
21750     }
21751   else
21752     {
21753       set_menu_label(edit_play_menu, I_STOP);
21754       ss->selection_play_stop = true;
21755       loop_play_selection();
21756     }
21757 }
21758 #endif
21759 
21760 
post_selection_popup_menu(void * e)21761 void post_selection_popup_menu(void *e)
21762 {
21763   XButtonPressedEvent *event = (XButtonPressedEvent *)e;
21764   if (!selection_popup_menu)
21765     {
21766       Arg args[20];
21767       int n;
21768 
21769       n = 0;
21770       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
21771       XtSetArg(args[n], XmNpopupEnabled, false); n++;      /* this was XmPOPUP_AUTOMATIC_RECURSIVE */
21772       selection_popup_menu = XmCreatePopupMenu(main_pane(ss), (char *)"selection-popup-menu", args, n);
21773 
21774       add_menu_item(selection_popup_menu, "Fill window",    popup_show_selection_callback);
21775       add_menu_item(selection_popup_menu, "Cut",            edit_cut_callback);
21776       add_menu_item(selection_popup_menu, "Cut and smooth", popup_cut_and_smooth_callback);
21777       add_menu_item(selection_popup_menu, "Cut -> new",     popup_cut_to_new_callback);
21778       add_menu_item(selection_popup_menu, "Save as",        edit_save_as_callback);
21779 #if WITH_AUDIO
21780       add_menu_item(selection_popup_menu, "Play",           edit_play_callback);
21781       add_menu_item(selection_popup_menu, "Play looping",   popup_loop_play_callback);
21782 #endif
21783       add_menu_item(selection_popup_menu, "Crop",           popup_crop_callback);
21784       add_menu_item(selection_popup_menu, "Unselect all",   edit_unselect_callback);
21785       add_menu_item(selection_popup_menu, "-> 0.0",         popup_zero_selection_callback);
21786       add_menu_item(selection_popup_menu, "-> 1.0",         popup_normalize_selection_callback);
21787       add_menu_item(selection_popup_menu, "Copy -> new",    popup_copy_to_new_callback);
21788       add_menu_item(selection_popup_menu, "Paste",          edit_paste_callback);
21789       add_menu_item(selection_popup_menu, "Mix",            edit_mix_callback);
21790       add_menu_item(selection_popup_menu, "Mark",           popup_mark_selection_callback);
21791       add_menu_item(selection_popup_menu, "Reverse",        popup_reverse_selection_callback);
21792       add_menu_item(selection_popup_menu, "Info",           popup_selection_info_callback);
21793     }
21794 
21795   XmMenuPosition(selection_popup_menu, event);
21796   XtManageChild(selection_popup_menu);
21797 }
21798 
21799 
21800 /* -------- fft popup -------- */
21801 
popup_peaks_callback(Widget w,XtPointer info,XtPointer context)21802 static void popup_peaks_callback(Widget w, XtPointer info, XtPointer context)
21803 {
21804   FILE *peaks_fd;
21805   peaks_fd = FOPEN("fft.txt", "w");
21806   if (peaks_fd)
21807     {
21808       write_transform_peaks(peaks_fd, current_channel()); /* follows sync */
21809       fclose(peaks_fd);
21810     }
21811 }
21812 
fft_size_16_callback(Widget w,XtPointer info,XtPointer context)21813 static void fft_size_16_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(16);}
fft_size_64_callback(Widget w,XtPointer info,XtPointer context)21814 static void fft_size_64_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(64);}
fft_size_256_callback(Widget w,XtPointer info,XtPointer context)21815 static void fft_size_256_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(256);}
fft_size_1024_callback(Widget w,XtPointer info,XtPointer context)21816 static void fft_size_1024_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(1024);}
fft_size_4096_callback(Widget w,XtPointer info,XtPointer context)21817 static void fft_size_4096_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(4096);}
fft_size_16384_callback(Widget w,XtPointer info,XtPointer context)21818 static void fft_size_16384_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(16384);}
fft_size_65536_callback(Widget w,XtPointer info,XtPointer context)21819 static void fft_size_65536_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(65536);}
fft_size_262144_callback(Widget w,XtPointer info,XtPointer context)21820 static void fft_size_262144_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(262144);}
fft_size_1048576_callback(Widget w,XtPointer info,XtPointer context)21821 static void fft_size_1048576_callback(Widget w, XtPointer info, XtPointer context) {set_transform_size(1048576);}
21822 
21823 
fft_window_rectangular_callback(Widget w,XtPointer info,XtPointer context)21824 static void fft_window_rectangular_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_RECTANGULAR_WINDOW);}
fft_window_hann_callback(Widget w,XtPointer info,XtPointer context)21825 static void fft_window_hann_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_HANN_WINDOW);}
fft_window_welch_callback(Widget w,XtPointer info,XtPointer context)21826 static void fft_window_welch_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_WELCH_WINDOW);}
fft_window_parzen_callback(Widget w,XtPointer info,XtPointer context)21827 static void fft_window_parzen_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_PARZEN_WINDOW);}
fft_window_bartlett_callback(Widget w,XtPointer info,XtPointer context)21828 static void fft_window_bartlett_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_BARTLETT_WINDOW);}
fft_window_blackman2_callback(Widget w,XtPointer info,XtPointer context)21829 static void fft_window_blackman2_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_BLACKMAN2_WINDOW);}
fft_window_blackman3_callback(Widget w,XtPointer info,XtPointer context)21830 static void fft_window_blackman3_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_BLACKMAN3_WINDOW);}
fft_window_blackman4_callback(Widget w,XtPointer info,XtPointer context)21831 static void fft_window_blackman4_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_BLACKMAN4_WINDOW);}
fft_window_hamming_callback(Widget w,XtPointer info,XtPointer context)21832 static void fft_window_hamming_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_HAMMING_WINDOW);}
fft_window_exponential_callback(Widget w,XtPointer info,XtPointer context)21833 static void fft_window_exponential_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_EXPONENTIAL_WINDOW);}
fft_window_riemann_callback(Widget w,XtPointer info,XtPointer context)21834 static void fft_window_riemann_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_RIEMANN_WINDOW);}
fft_window_kaiser_callback(Widget w,XtPointer info,XtPointer context)21835 static void fft_window_kaiser_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_KAISER_WINDOW);}
fft_window_cauchy_callback(Widget w,XtPointer info,XtPointer context)21836 static void fft_window_cauchy_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_CAUCHY_WINDOW);}
fft_window_poisson_callback(Widget w,XtPointer info,XtPointer context)21837 static void fft_window_poisson_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_POISSON_WINDOW);}
fft_window_gaussian_callback(Widget w,XtPointer info,XtPointer context)21838 static void fft_window_gaussian_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_GAUSSIAN_WINDOW);}
fft_window_tukey_callback(Widget w,XtPointer info,XtPointer context)21839 static void fft_window_tukey_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_TUKEY_WINDOW);}
fft_window_dolph_chebyshev_callback(Widget w,XtPointer info,XtPointer context)21840 static void fft_window_dolph_chebyshev_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_DOLPH_CHEBYSHEV_WINDOW);}
fft_window_blackman6_callback(Widget w,XtPointer info,XtPointer context)21841 static void fft_window_blackman6_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_BLACKMAN6_WINDOW);}
fft_window_blackman8_callback(Widget w,XtPointer info,XtPointer context)21842 static void fft_window_blackman8_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_BLACKMAN8_WINDOW);}
fft_window_blackman10_callback(Widget w,XtPointer info,XtPointer context)21843 static void fft_window_blackman10_callback(Widget w, XtPointer info, XtPointer context) {set_fft_window(MUS_BLACKMAN10_WINDOW);}
21844 
fft_type_fourier_callback(Widget w,XtPointer info,XtPointer context)21845 static void fft_type_fourier_callback(Widget w, XtPointer info, XtPointer context) {set_transform_type(FOURIER);}
fft_type_wavelet_callback(Widget w,XtPointer info,XtPointer context)21846 static void fft_type_wavelet_callback(Widget w, XtPointer info, XtPointer context) {set_transform_type(WAVELET);}
fft_type_autocorrelation_callback(Widget w,XtPointer info,XtPointer context)21847 static void fft_type_autocorrelation_callback(Widget w, XtPointer info, XtPointer context) {set_transform_type(AUTOCORRELATION);}
fft_type_cepstrum_callback(Widget w,XtPointer info,XtPointer context)21848 static void fft_type_cepstrum_callback(Widget w, XtPointer info, XtPointer context) {set_transform_type(CEPSTRUM);}
21849 
21850 
fft_graph_once_callback(Widget w,XtPointer info,XtPointer context)21851 static void fft_graph_once_callback(Widget w, XtPointer info, XtPointer context) {set_transform_graph_type(GRAPH_ONCE);}
fft_graph_sonogram_callback(Widget w,XtPointer info,XtPointer context)21852 static void fft_graph_sonogram_callback(Widget w, XtPointer info, XtPointer context) {set_transform_graph_type(GRAPH_AS_SONOGRAM);}
fft_graph_spectrogram_callback(Widget w,XtPointer info,XtPointer context)21853 static void fft_graph_spectrogram_callback(Widget w, XtPointer info, XtPointer context) {set_transform_graph_type(GRAPH_AS_SPECTROGRAM);}
21854 
21855 
fft_gray_callback(Widget w,XtPointer info,XtPointer context)21856 static void fft_gray_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(GRAY_COLORMAP);}
fft_hot_callback(Widget w,XtPointer info,XtPointer context)21857 static void fft_hot_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(HOT_COLORMAP);}
fft_cool_callback(Widget w,XtPointer info,XtPointer context)21858 static void fft_cool_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(COOL_COLORMAP);}
fft_bone_callback(Widget w,XtPointer info,XtPointer context)21859 static void fft_bone_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(BONE_COLORMAP);}
fft_copper_callback(Widget w,XtPointer info,XtPointer context)21860 static void fft_copper_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(COPPER_COLORMAP);}
fft_pink_callback(Widget w,XtPointer info,XtPointer context)21861 static void fft_pink_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(PINK_COLORMAP);}
fft_jet_callback(Widget w,XtPointer info,XtPointer context)21862 static void fft_jet_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(JET_COLORMAP);}
fft_prism_callback(Widget w,XtPointer info,XtPointer context)21863 static void fft_prism_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(PRISM_COLORMAP);}
fft_autumn_callback(Widget w,XtPointer info,XtPointer context)21864 static void fft_autumn_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(AUTUMN_COLORMAP);}
fft_winter_callback(Widget w,XtPointer info,XtPointer context)21865 static void fft_winter_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(WINTER_COLORMAP);}
fft_spring_callback(Widget w,XtPointer info,XtPointer context)21866 static void fft_spring_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(SPRING_COLORMAP);}
fft_summer_callback(Widget w,XtPointer info,XtPointer context)21867 static void fft_summer_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(SUMMER_COLORMAP);}
fft_rainbow_callback(Widget w,XtPointer info,XtPointer context)21868 static void fft_rainbow_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(RAINBOW_COLORMAP);}
fft_flag_callback(Widget w,XtPointer info,XtPointer context)21869 static void fft_flag_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(FLAG_COLORMAP);}
fft_phases_callback(Widget w,XtPointer info,XtPointer context)21870 static void fft_phases_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(PHASES_COLORMAP);}
fft_black_and_white_callback(Widget w,XtPointer info,XtPointer context)21871 static void fft_black_and_white_callback(Widget w, XtPointer info, XtPointer context) {set_color_map(BLACK_AND_WHITE_COLORMAP);}
21872 
post_fft_popup_menu(void * e)21873 void post_fft_popup_menu(void *e)
21874 {
21875   XButtonPressedEvent *event = (XButtonPressedEvent *)e;
21876   if (!fft_popup_menu)
21877     {
21878       Widget outer_menu;
21879       Arg args[20];
21880       int n;
21881 
21882       n = 0;
21883       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
21884       XtSetArg(args[n], XmNpopupEnabled, false); n++;      /* this was XmPOPUP_AUTOMATIC_RECURSIVE */
21885       fft_popup_menu = XmCreatePopupMenu(main_pane(ss), (char *)"fft-popup-menu", args, n);
21886 
21887       n = 0;
21888       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
21889       outer_menu = XmCreatePulldownMenu(fft_popup_menu, (char *)"Size", args, n);
21890 
21891       n = 0;
21892       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
21893       XtSetArg(args[n], XmNsubMenuId, outer_menu); n++;
21894       XtCreateManagedWidget("Size", xmCascadeButtonWidgetClass, fft_popup_menu, args, n);
21895 
21896       add_menu_item(outer_menu, "16",      fft_size_16_callback);
21897       add_menu_item(outer_menu, "64",      fft_size_64_callback);
21898       add_menu_item(outer_menu, "256",     fft_size_256_callback);
21899       add_menu_item(outer_menu, "1024",    fft_size_1024_callback);
21900       add_menu_item(outer_menu, "4096",    fft_size_4096_callback);
21901       add_menu_item(outer_menu, "16384",   fft_size_16384_callback);
21902       add_menu_item(outer_menu, "65536",   fft_size_65536_callback);
21903       add_menu_item(outer_menu, "262144",  fft_size_262144_callback);
21904       add_menu_item(outer_menu, "1048576", fft_size_1048576_callback);
21905 
21906 
21907       n = 0;
21908       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
21909       outer_menu = XmCreatePulldownMenu(fft_popup_menu, (char *)"Window", args, n);
21910 
21911       n = 0;
21912       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
21913       XtSetArg(args[n], XmNsubMenuId, outer_menu); n++;
21914       XtCreateManagedWidget("Window", xmCascadeButtonWidgetClass, fft_popup_menu, args, n);
21915 
21916       add_menu_item(outer_menu, "rectangular",     fft_window_rectangular_callback);
21917       add_menu_item(outer_menu, "hann",            fft_window_hann_callback);
21918       add_menu_item(outer_menu, "welch",           fft_window_welch_callback);
21919       add_menu_item(outer_menu, "parzen",          fft_window_parzen_callback);
21920       add_menu_item(outer_menu, "bartlett",        fft_window_bartlett_callback);
21921       add_menu_item(outer_menu, "hamming",         fft_window_hamming_callback);
21922       add_menu_item(outer_menu, "blackman2",       fft_window_blackman2_callback);
21923       add_menu_item(outer_menu, "blackman3",       fft_window_blackman3_callback);
21924       add_menu_item(outer_menu, "blackman4",       fft_window_blackman4_callback);
21925       add_menu_item(outer_menu, "exponential",     fft_window_exponential_callback);
21926       add_menu_item(outer_menu, "riemann",         fft_window_riemann_callback);
21927       add_menu_item(outer_menu, "kaiser",          fft_window_kaiser_callback);
21928       add_menu_item(outer_menu, "cauchy",          fft_window_cauchy_callback);
21929       add_menu_item(outer_menu, "poisson",         fft_window_poisson_callback);
21930       add_menu_item(outer_menu, "gaussian",        fft_window_gaussian_callback);
21931       add_menu_item(outer_menu, "tukey",           fft_window_tukey_callback);
21932       add_menu_item(outer_menu, "dolph-chebyshev", fft_window_dolph_chebyshev_callback);
21933       add_menu_item(outer_menu, "blackman6",       fft_window_blackman6_callback);
21934       add_menu_item(outer_menu, "blackman8",       fft_window_blackman8_callback);
21935       add_menu_item(outer_menu, "blackman10" ,     fft_window_blackman10_callback);
21936 
21937 
21938       n = 0;
21939       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
21940       outer_menu = XmCreatePulldownMenu(fft_popup_menu, (char *)"Graph type", args, n);
21941 
21942       n = 0;
21943       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
21944       XtSetArg(args[n], XmNsubMenuId, outer_menu); n++;
21945       XtCreateManagedWidget("Graph type", xmCascadeButtonWidgetClass, fft_popup_menu, args, n);
21946 
21947       add_menu_item(outer_menu, "one fft",     fft_graph_once_callback);
21948       add_menu_item(outer_menu, "sonogram",    fft_graph_sonogram_callback);
21949       add_menu_item(outer_menu, "spectrogram", fft_graph_spectrogram_callback);
21950 
21951 
21952       n = 0;
21953       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
21954       outer_menu = XmCreatePulldownMenu(fft_popup_menu, (char *)"Transform type", args, n);
21955 
21956       n = 0;
21957       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
21958       XtSetArg(args[n], XmNsubMenuId, outer_menu); n++;
21959       XtCreateManagedWidget("Transform type", xmCascadeButtonWidgetClass, fft_popup_menu, args, n);
21960 
21961       add_menu_item(outer_menu, "fourier",         fft_type_fourier_callback);
21962       add_menu_item(outer_menu, "wavelet",         fft_type_wavelet_callback);
21963       add_menu_item(outer_menu, "autocorrelation", fft_type_autocorrelation_callback);
21964       add_menu_item(outer_menu, "cepstrum",        fft_type_cepstrum_callback);
21965 
21966 
21967       n = 0;
21968       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
21969       outer_menu = XmCreatePulldownMenu(fft_popup_menu, (char *)"Colormap", args, n);
21970 
21971       n = 0;
21972       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
21973       XtSetArg(args[n], XmNsubMenuId, outer_menu); n++;
21974       XtCreateManagedWidget("Colormap", xmCascadeButtonWidgetClass, fft_popup_menu, args, n);
21975 
21976       add_menu_item(outer_menu, "gray",    fft_gray_callback);
21977       add_menu_item(outer_menu, "autumn",  fft_autumn_callback);
21978       add_menu_item(outer_menu, "spring",  fft_spring_callback);
21979       add_menu_item(outer_menu, "winter",  fft_winter_callback);
21980       add_menu_item(outer_menu, "summer",  fft_summer_callback);
21981       add_menu_item(outer_menu, "cool",    fft_cool_callback);
21982       add_menu_item(outer_menu, "copper",  fft_copper_callback);
21983       add_menu_item(outer_menu, "flag",    fft_flag_callback);
21984       add_menu_item(outer_menu, "prism",   fft_prism_callback);
21985       add_menu_item(outer_menu, "bone",    fft_bone_callback);
21986       add_menu_item(outer_menu, "hot",     fft_hot_callback);
21987       add_menu_item(outer_menu, "jet",     fft_jet_callback);
21988       add_menu_item(outer_menu, "pink",    fft_pink_callback);
21989       add_menu_item(outer_menu, "rainbow", fft_rainbow_callback);
21990       add_menu_item(outer_menu, "phases",  fft_phases_callback);
21991       add_menu_item(outer_menu, "black and white", fft_black_and_white_callback);
21992 
21993 
21994       add_menu_item(fft_popup_menu, "Peaks->fft.txt", popup_peaks_callback);
21995     }
21996 
21997   XmMenuPosition(fft_popup_menu, event);
21998   XtManageChild(fft_popup_menu);
21999 }
22000 
22001 
22002 
post_lisp_popup_menu(void * e)22003 void post_lisp_popup_menu(void *e) {}
22004 
22005 
22006 
22007 
22008 /* ---------------- tooltips ---------------- */
22009 
22010 static Widget tooltip_shell = NULL;
22011 #if (!HAVE_GL)
22012   static Widget tooltip_label = NULL;
22013 #endif
22014 static timeout_result_t tool_proc = 0, quit_proc = 0;
22015 static Time tool_last_time = 0;
22016 static Position tool_x, tool_y;
22017 static Widget tool_w;
22018 
22019 #if (!HAVE_GL)
leave_tooltip(XtPointer tooltip,XtIntervalId * id)22020 static void leave_tooltip(XtPointer tooltip, XtIntervalId *id)
22021 {
22022   XtUnmanageChild(tooltip_shell);
22023   quit_proc = 0;
22024 }
22025 #endif
22026 
handle_tooltip(XtPointer tooltip,XtIntervalId * id)22027 static void handle_tooltip(XtPointer tooltip, XtIntervalId *id)
22028 {
22029 #if (!HAVE_GL)
22030   /* if GL, we get a segfault here -- I don't know why */
22031 
22032   char *tip = (char *)tooltip;
22033   Position rx, ry;
22034   XmString str;
22035   int lines = 0;
22036 
22037   if (!tooltip_shell)
22038     {
22039       tooltip_shell = XtVaCreatePopupShell(tip, overrideShellWidgetClass, main_shell(ss),
22040 					   XmNallowShellResize, true,
22041 					   NULL);
22042       tooltip_label = XtVaCreateManagedWidget("tooltip", xmLabelWidgetClass, tooltip_shell,
22043 					      XmNrecomputeSize, true,
22044 					      XmNbackground, ss->lighter_blue,
22045 					      NULL);
22046     }
22047   str = multi_line_label(tip, &lines);
22048   XtVaSetValues(tooltip_label, XmNlabelString, str, NULL);
22049   XmStringFree(str);
22050 
22051   XtTranslateCoords(tool_w, tool_x, tool_y, &rx, &ry);
22052   XtVaSetValues(tooltip_shell, XmNx, rx, XmNy, ry, NULL);
22053   XtManageChild(tooltip_shell);
22054   quit_proc = XtAppAddTimeOut(main_app(ss), (unsigned long)10000, (XtTimerCallbackProc)leave_tooltip, NULL);
22055 #endif
22056 }
22057 
22058 
tool_starter(Widget w,XtPointer context,XEvent * event,Boolean * cont)22059 static void tool_starter(Widget w, XtPointer context, XEvent *event, Boolean *cont)
22060 {
22061   XEnterWindowEvent *ev = (XEnterWindowEvent *)event;
22062   char *tip = (char *)context;
22063   if ((with_tooltips(ss)) &&
22064       ((ev->time - tool_last_time) > 2))
22065     {
22066       tool_x = ev->x;
22067       tool_y = ev->y;
22068       tool_w = w;
22069       tool_last_time = ev->time;
22070       tool_proc = XtAppAddTimeOut(main_app(ss), (unsigned long)300, (XtTimerCallbackProc)handle_tooltip, (XtPointer)tip);
22071     }
22072 }
22073 
22074 
tool_stopper(Widget w,XtPointer context,XEvent * event,Boolean * cont)22075 static void tool_stopper(Widget w, XtPointer context, XEvent *event, Boolean *cont)
22076 {
22077   XLeaveWindowEvent *ev = (XLeaveWindowEvent *)event;
22078   tool_last_time = ev->time;
22079   if (tool_proc != 0)
22080     {
22081       XtRemoveTimeOut(tool_proc);
22082       tool_proc = 0;
22083     }
22084   if (quit_proc != 0)
22085     {
22086       XtRemoveTimeOut(quit_proc);
22087       quit_proc = 0;
22088     }
22089   if ((tooltip_shell) && (XtIsManaged(tooltip_shell)))
22090     XtUnmanageChild(tooltip_shell);
22091 }
22092 
22093 
add_tooltip(Widget w,const char * tip)22094 void add_tooltip(Widget w, const char *tip)
22095 {
22096   XtAddEventHandler(w, EnterWindowMask, false, tool_starter, (XtPointer)tip);
22097   XtAddEventHandler(w, LeaveWindowMask, false, tool_stopper, NULL);
22098 }
22099 
22100 
22101 
22102 /* ---------------- toolbar ---------------- */
22103 
add_to_toolbar(Widget bar,Pixmap icon,const char * tip,void (* callback)(Widget w,XtPointer info,XtPointer context))22104 static void add_to_toolbar(Widget bar, Pixmap icon, const char *tip, void (*callback)(Widget w, XtPointer info, XtPointer context))
22105 {
22106   Widget w;
22107   w = XtVaCreateManagedWidget("icon", xmPushButtonWidgetClass, bar,
22108 			      XmNlabelPixmap, icon,
22109 			      XmNlabelType, XmPIXMAP,
22110 			      XmNwidth, 24,
22111 			      XmNheight, 24,
22112 			      XmNshadowThickness, 0,
22113 			      XmNhighlightThickness, 0,
22114 			      /* XmNmarginHeight, 0, */
22115 			      XmNbackground, ss->basic_color,
22116 			      NULL);
22117   XtAddCallback(w, XmNactivateCallback, callback, NULL);
22118   add_tooltip(w, tip);
22119 }
22120 
22121 
add_separator_to_toolbar(Widget bar)22122 static void add_separator_to_toolbar(Widget bar)
22123 {
22124   XtVaCreateManagedWidget("icon", xmPushButtonWidgetClass, bar,
22125 			  XmNlabelPixmap, toolbar_icon(SND_XPM_SEPARATOR),
22126 			  XmNlabelType, XmPIXMAP,
22127 			  XmNwidth, 8,
22128 			  XmNheight, 24,
22129 			  XmNshadowThickness, 0,
22130 			  XmNhighlightThickness, 0,
22131 			  XmNbackground, ss->basic_color,
22132 			  NULL);
22133 }
22134 
22135 
22136 #if WITH_AUDIO
play_from_start_callback(Widget w,XtPointer info,XtPointer context)22137 static void play_from_start_callback(Widget w, XtPointer info, XtPointer context)
22138 {
22139   snd_info *sp;
22140   sp = any_selected_sound();
22141   if (sp)
22142     play_sound(sp, 0, NO_END_SPECIFIED);
22143 }
22144 
22145 
play_from_cursor_callback(Widget w,XtPointer info,XtPointer context)22146 static void play_from_cursor_callback(Widget w, XtPointer info, XtPointer context)
22147 {
22148   snd_info *sp;
22149   sp = any_selected_sound();
22150   if (sp)
22151     {
22152       chan_info *cp;
22153       cp = any_selected_channel(sp);
22154       if (cp)
22155 	play_sound(sp, cursor_sample(cp), NO_END_SPECIFIED);
22156     }
22157 }
22158 
22159 
stop_playing_callback(Widget w,XtPointer info,XtPointer context)22160 static void stop_playing_callback(Widget w, XtPointer info, XtPointer context)
22161 {
22162   stop_playing_all_sounds(PLAY_C_G);
22163   reflect_play_selection_stop(); /* this sets ss->selection_play_stop = false; */
22164 }
22165 #endif
22166 
22167 
full_dur_callback(Widget w,XtPointer info,XtPointer context)22168 static void full_dur_callback(Widget w, XtPointer info, XtPointer context)
22169 {
22170   snd_info *sp;
22171   sp = any_selected_sound();
22172   if (sp)
22173     {
22174       uint32_t i;
22175       for (i = 0; i < sp->nchans; i++)
22176 	set_x_axis_x0x1(sp->chans[i], 0.0, sp->chans[i]->axis->xmax);
22177     }
22178 }
22179 
22180 
zoom_out_callback(Widget w,XtPointer info,XtPointer context)22181 static void zoom_out_callback(Widget w, XtPointer info, XtPointer context)
22182 {
22183   snd_info *sp;
22184   sp = any_selected_sound();
22185   if (sp)
22186     {
22187       uint32_t i;
22188       for (i = 0; i < sp->nchans; i++)
22189 	zx_incremented(sp->chans[i], 2.0);
22190     }
22191 }
22192 
22193 
zoom_in_callback(Widget w,XtPointer info,XtPointer context)22194 static void zoom_in_callback(Widget w, XtPointer info, XtPointer context)
22195 {
22196   snd_info *sp;
22197   sp = any_selected_sound();
22198   if (sp)
22199     {
22200       uint32_t i;
22201       for (i = 0; i < sp->nchans; i++)
22202 	zx_incremented(sp->chans[i], 0.5);
22203     }
22204 }
22205 
22206 
goto_start_callback(Widget w,XtPointer info,XtPointer context)22207 static void goto_start_callback(Widget w, XtPointer info, XtPointer context)
22208 {
22209   snd_info *sp;
22210   sp = any_selected_sound();
22211   if (sp)
22212     {
22213       uint32_t i;
22214       for (i = 0; i < sp->nchans; i++)
22215 	set_x_axis_x0x1(sp->chans[i], 0.0, sp->chans[i]->axis->x1 - sp->chans[i]->axis->x0);
22216     }
22217 }
22218 
go_back_callback(Widget w,XtPointer info,XtPointer context)22219 static void go_back_callback(Widget w, XtPointer info, XtPointer context)
22220 {
22221   snd_info *sp;
22222   sp = any_selected_sound();
22223   if (sp)
22224     {
22225       uint32_t i;
22226       for (i = 0; i < sp->nchans; i++)
22227 	sx_incremented(sp->chans[i], -1.0);
22228     }
22229 }
22230 
22231 
go_forward_callback(Widget w,XtPointer info,XtPointer context)22232 static void go_forward_callback(Widget w, XtPointer info, XtPointer context)
22233 {
22234   snd_info *sp;
22235   sp = any_selected_sound();
22236   if (sp)
22237     {
22238       uint32_t i;
22239       for (i = 0; i < sp->nchans; i++)
22240 	sx_incremented(sp->chans[i], 1.0);
22241     }
22242 }
22243 
goto_end_callback(Widget w,XtPointer info,XtPointer context)22244 static void goto_end_callback(Widget w, XtPointer info, XtPointer context)
22245 {
22246   snd_info *sp;
22247   sp = any_selected_sound();
22248   if (sp)
22249     {
22250       uint32_t i;
22251       for (i = 0; i < sp->nchans; i++)
22252 	set_x_axis_x0x1(sp->chans[i], sp->chans[i]->axis->xmax - sp->chans[i]->axis->x1 + sp->chans[i]->axis->x0, sp->chans[i]->axis->xmax);
22253     }
22254 }
22255 
22256 
22257 
22258 static Widget toolbar = NULL;
22259 
show_toolbar(void)22260 void show_toolbar(void)
22261 {
22262   if (!toolbar)
22263     {
22264       #define ICON_HEIGHT 28
22265       Arg args[32];
22266       int n;
22267 
22268       XtVaSetValues(main_shell(ss), XmNallowShellResize, false, NULL);
22269 
22270       n = attach_all_sides(args, 0);
22271       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
22272       XtSetArg(args[n], XmNheight, ICON_HEIGHT); n++;
22273       XtSetArg(args[n], XmNpaneMaximum, ICON_HEIGHT); n++; /* Xm/Paned initializes each pane max to 1000 apparently! */
22274       XtSetArg(args[n], XmNpositionIndex, 0); n++;
22275       XtSetArg(args[n], XmNshadowThickness, 0); n++;
22276       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
22277       XtSetArg(args[n], XmNmarginHeight, 0); n++;
22278 
22279       if ((sound_style(ss) == SOUNDS_IN_NOTEBOOK) ||
22280 	  (sound_style(ss) == SOUNDS_HORIZONTAL))
22281 	toolbar = XtCreateManagedWidget("toolbar", xmRowColumnWidgetClass, sound_pane_box(ss), args, n);
22282       else toolbar = XtCreateManagedWidget("toolbar", xmRowColumnWidgetClass, sound_pane(ss), args, n);
22283       ss->toolbar = toolbar;
22284 
22285       if (auto_resize(ss))
22286 	XtVaSetValues(main_shell(ss), XmNallowShellResize, true, NULL);
22287 
22288       make_toolbar_icons(main_shell(ss));
22289 
22290       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_NEW),           "new sound",                  file_new_callback);
22291       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_OPEN),          "open sound",                 file_open_callback);
22292       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_SAVE),          "save current sound, overwriting it", file_save_callback);
22293       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_SAVE_AS),       "save current sound in a new file", file_save_as_callback);
22294       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_REVERT),        "revert to saved",            file_revert_callback);
22295       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_UNDO),          "undo edit",                  edit_undo_callback);
22296       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_REDO),          "redo last (undone) edit",    edit_redo_callback);
22297       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_CLOSE),         "close selected sound",       file_close_callback);
22298       add_separator_to_toolbar(toolbar);
22299 
22300 #if WITH_AUDIO
22301       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_PLAY),          "play from the start",        play_from_start_callback);
22302       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_CURSOR_PLAY),   "play from the cursor",       play_from_cursor_callback);
22303       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_STOP_PLAY),     "stop playing",               stop_playing_callback);
22304       add_separator_to_toolbar(toolbar);
22305 #endif
22306 
22307       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_UP),            "show full sound",            full_dur_callback);
22308       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_ZOOM_OUT),      "zoom out",                   zoom_out_callback);
22309       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_ZOOM_IN),       "zoom in",                    zoom_in_callback);
22310       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_BACK_ARROW),    "go to start of sound",       goto_start_callback);
22311       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_BACK),          "go back a window",           go_back_callback);
22312       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_NEXT),          "go forward a window",        go_forward_callback);
22313       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_FORWARD_ARROW), "go to end of sound",         goto_end_callback);
22314       add_separator_to_toolbar(toolbar);
22315 
22316       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_CUT),           "delete selection",           edit_cut_callback);
22317       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_PASTE),         "insert selection at cursor", edit_paste_callback);
22318       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_PREFERENCES),   "open preferences dialog",    options_preferences_callback);
22319       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_STOP),          "stop the current operation", stop_everything_callback);
22320       add_to_toolbar(toolbar, toolbar_icon(SND_XPM_EXIT),          "exit Snd",                   file_exit_callback);
22321 
22322     }
22323   else
22324     {
22325       XtVaSetValues(main_shell(ss), XmNallowShellResize, false, NULL);
22326       XtManageChild(toolbar);
22327       if (auto_resize(ss))
22328 	XtVaSetValues(main_shell(ss), XmNallowShellResize, true, NULL);
22329     }
22330 }
22331 
22332 
hide_toolbar(void)22333 void hide_toolbar(void)
22334 {
22335   if (toolbar)
22336     {
22337       XtVaSetValues(main_shell(ss), XmNallowShellResize, false, NULL);
22338       XtUnmanageChild(toolbar);
22339       if (auto_resize(ss))
22340 	XtVaSetValues(main_shell(ss), XmNallowShellResize, true, NULL);
22341     }
22342 }
22343 
22344 
22345 
22346 
22347 /* ---------------- ext lang tie-ins ---------------- */
22348 
22349 #define INVALID_MENU -1
22350 #define call_index(Data) (Data >> 16)
22351 #define pack_menu_data(Slot, Menu) ((Slot << 16) | (Menu))
22352 
menu_callback(Widget w,XtPointer info,XtPointer context)22353 static void menu_callback(Widget w, XtPointer info, XtPointer context)
22354 {
22355   intptr_t callb;
22356   XtVaGetValues(w, XmNuserData, &callb, NULL);
22357   g_menu_callback(call_index(callb)); /* menu option activate callback */
22358 }
22359 
22360 
GHC_callback(Widget w,XtPointer info,XtPointer context)22361 static void GHC_callback(Widget w, XtPointer info, XtPointer context)
22362 {
22363   intptr_t slot;
22364   XtVaGetValues(w, XmNuserData, &slot, NULL);
22365   g_menu_callback(call_index(slot)); /* main menu cascading callback */
22366 }
22367 
22368 
22369 static Widget *main_menus = NULL;
22370 static int main_menus_size = 0;
22371 /* fancy code here looping through the main menus children hangs or segfaults in 86_64 unoptimized cases! */
22372 
menu_widget(int which_menu)22373 Widget menu_widget(int which_menu)
22374 {
22375   switch (which_menu)
22376     {
22377     case 0: return(file_menu);    break;
22378     case 1: return(edit_menu);    break;
22379     case 2: return(view_menu);    break;
22380     case 3: return(options_menu); break;
22381     case 4: return(help_menu);    break;
22382 
22383     default:
22384       if (which_menu < main_menus_size)
22385 	return(main_menus[which_menu]);
22386       break;
22387     }
22388   return(NULL);
22389 }
22390 
22391 
or_over_children(Widget w,bool (* func)(Widget uw,const char * ustr),const char * str)22392 static bool or_over_children(Widget w, bool (*func)(Widget uw, const char *ustr), const char *str)
22393 {
22394   if (w)
22395     {
22396       if ((*func)(w, str)) return(true);
22397       if (XtIsComposite(w))
22398 	{
22399 	  uint32_t i;
22400 	  CompositeWidget cw = (CompositeWidget)w;
22401 	  for (i = 0; i < cw->composite.num_children; i++)
22402 	    if (or_over_children(cw->composite.children[i], func, str))
22403 	      return(true);
22404 	}
22405     }
22406   return(false);
22407 }
22408 
22409 
clobber_menu(Widget w,const char * name)22410 static bool clobber_menu(Widget w, const char *name)
22411 {
22412   char *wname;
22413   wname = XtName(w);
22414   if ((wname) &&
22415       (mus_strcmp(name, wname)) &&
22416       (XtIsManaged(w)))
22417     {
22418       intptr_t slot;
22419       XtVaGetValues(w, XmNuserData, &slot, NULL);
22420       unprotect_callback(call_index(slot));
22421       XtUnmanageChild(w);
22422     }
22423   return(true); /* in any case, don't try to recurse into the children */
22424 }
22425 
22426 
g_remove_from_menu(int which_menu,const char * label)22427 int g_remove_from_menu(int which_menu, const char *label)
22428 {
22429   Widget top_menu;
22430   top_menu = menu_widget(which_menu);
22431   if (top_menu)
22432     {
22433       or_over_children(top_menu, clobber_menu, label);
22434       return(0);
22435     }
22436   return(INVALID_MENU);
22437 }
22438 
22439 
set_widget_name(Widget w,const char * new_name)22440 static void set_widget_name(Widget w, const char *new_name)
22441 {
22442   /* based on XtName in Xt/Intrinsic.c, Xt/Create.c, and Xt/ResourceI.h */
22443   w->core.xrm_name = XrmStringToName(new_name);
22444 }
22445 
22446 
22447 static int new_menu = 5;
22448 
g_add_to_main_menu(const char * label,int slot)22449 int g_add_to_main_menu(const char *label, int slot)
22450 {
22451   static Arg args[12];
22452   Widget m, cas;
22453   int n;
22454 
22455   if (auto_resize(ss)) XtVaSetValues(main_shell(ss), XmNallowShellResize, false, NULL);
22456   new_menu++;
22457 
22458   n = 0;
22459   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
22460   XtSetArg(args[n], XmNuserData, pack_menu_data(slot, new_menu)); n++;
22461   m = XmCreatePulldownMenu(main_menu, (char *)label, args, n);
22462 
22463   n = 0;
22464   XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
22465   XtSetArg(args[n], XmNsubMenuId, m); n++;
22466   XtSetArg(args[n], XmNuserData, pack_menu_data(slot, new_menu)); n++;
22467   cas = XtCreateManagedWidget(label, xmCascadeButtonWidgetClass, main_menu, args, n);
22468   if (slot >= 0) XtAddCallback(cas, XmNcascadingCallback, GHC_callback, NULL);
22469 
22470   if (auto_resize(ss)) XtVaSetValues(main_shell(ss), XmNallowShellResize, true, NULL);
22471 
22472   if (main_menus_size == 0)
22473     {
22474       main_menus_size = 8;
22475       main_menus = (Widget *)calloc(main_menus_size, sizeof(Widget));
22476     }
22477   else
22478     {
22479       if (new_menu >= main_menus_size)
22480 	{
22481 	  main_menus_size = new_menu + 8;
22482 	  main_menus = (Widget *)realloc(main_menus, main_menus_size * sizeof(Widget));
22483 	}
22484     }
22485   main_menus[new_menu] = m;
22486   return(new_menu);
22487 }
22488 
22489 
g_add_to_menu(int which_menu,const char * label,int callb,int position)22490 Widget g_add_to_menu(int which_menu, const char *label, int callb, int position)
22491 {
22492   Widget m, menw;
22493   Arg args[12];
22494   int n = 0;
22495   menw = menu_widget(which_menu);
22496   if (!menw) return(NULL);
22497   if (label)
22498     {
22499       uint32_t i;
22500       /* look for currently unused widget first */
22501       /*   but close-all and open-recent should be left alone! */
22502       CompositeWidget cw = (CompositeWidget)menw;
22503       for (i = 0; i < cw->composite.num_children; i++)
22504 	{
22505 	  m = cw->composite.children[i];
22506 	  if ((m) &&
22507 	      (!(XtIsManaged(m))) &&
22508 	      (m != file_close_all_menu) &&
22509 	      (m != file_open_recent_menu) &&
22510 	      (m != file_open_recent_cascade_menu))
22511 	    {
22512 	      if (!(mus_strcmp(XtName(m), label)))
22513 		{
22514 		  set_widget_name(m, label);
22515 		  set_button_label(m, label);
22516 		}
22517 	      if (position >= 0) XtVaSetValues(m, XmNpositionIndex, position, NULL);
22518 	      XtVaSetValues(m, XmNuserData, pack_menu_data(callb, which_menu), NULL);
22519 	      XtManageChild(m);
22520 	      return(m);
22521 	    }
22522 	}
22523       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
22524       if (position >= 0) {XtSetArg(args[n], XmNpositionIndex, position); n++;}
22525       XtSetArg(args[n], XmNuserData, pack_menu_data(callb, which_menu)); n++;
22526       m = XtCreateManagedWidget(label, xmPushButtonWidgetClass, menw, args, n);
22527       XtAddCallback(m, XmNactivateCallback, menu_callback, NULL);
22528     }
22529   else
22530     {
22531       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
22532       if (position >= 0) {XtSetArg(args[n], XmNpositionIndex, position); n++;}
22533       m = XtCreateManagedWidget("sep", xmSeparatorWidgetClass, menw, args, n);
22534     }
22535   return(m);
22536 }
22537 
22538 
g_menu_widgets(void)22539 static Xen g_menu_widgets(void)
22540 {
22541   #define H_menu_widgets "(" S_menu_widgets "): a list of top level menu widgets: ((0)main (1)file (2)edit (3)view (4)options (5)help)"
22542   return(Xen_cons(Xen_wrap_widget(main_menu),
22543 	  Xen_cons(Xen_wrap_widget(file_cascade_menu),
22544            Xen_cons(Xen_wrap_widget(edit_cascade_menu),
22545             Xen_cons(Xen_wrap_widget(view_cascade_menu),
22546              Xen_cons(Xen_wrap_widget(options_cascade_menu),
22547               Xen_cons(Xen_wrap_widget(help_cascade_menu),
22548 	       Xen_empty_list)))))));
22549 }
22550 
22551 /* Motif bug: the button backgrounds remain in the original highlight color? but the widget (if it is one) is not the child of any obvious widget
22552  */
22553 
22554 
22555 /* motif case needs prompt length fixups, listener if no panes, minibuffer as label not text entry
22556  */
22557 
22558 /* ---------------- listener text history ---------------- */
22559 
22560 static char **listener_strings = NULL;
22561 static int listener_strings_size = 0, listener_strings_pos = 0;
22562 static bool listener_first_time = true;
22563 
remember_listener_string(const char * str)22564 static void remember_listener_string(const char *str)
22565 {
22566   int i, top;
22567   if (!str) return;
22568 
22569   if (listener_strings_size == 0)
22570     {
22571       listener_strings_size = 8;
22572       listener_strings = (char **)calloc(listener_strings_size, sizeof(char *));
22573     }
22574 
22575   listener_strings_pos = 0;
22576   listener_first_time = true;
22577 
22578   /* if str matches current history top entry, ignore it (as in tcsh) */
22579   if ((listener_strings[0]) &&
22580       (mus_strcmp(str, listener_strings[0])))
22581     return;
22582 
22583   top = listener_strings_size - 1;
22584   if (listener_strings[top]) free(listener_strings[top]);
22585   for (i = top; i > 0; i--) listener_strings[i] = listener_strings[i - 1];
22586 
22587   listener_strings[0] = mus_strdup(str);
22588 }
22589 
22590 
restore_listener_string(bool back)22591 static void restore_listener_string(bool back)
22592 {
22593   if (listener_strings)
22594     {
22595       char *str;
22596       if (!(listener_first_time))
22597 	{
22598 	  if (back)
22599 	    listener_strings_pos++;
22600 	  else listener_strings_pos--;
22601 	}
22602       listener_first_time = false;
22603       if (listener_strings_pos < 0) listener_strings_pos = 0;
22604       if (listener_strings_pos > (listener_strings_size - 1)) listener_strings_pos = listener_strings_size - 1;
22605       str = listener_strings[listener_strings_pos];
22606       if (str)
22607 	append_listener_text(-1, str);
22608     }
22609 }
22610 
is_prompt(const char * str,int beg)22611 static bool is_prompt(const char *str, int beg)
22612 {
22613   int i, j;
22614   /* fprintf(stderr, "check %s %s for %d at %d\n", str, ss->Listener_Prompt, ss->listener_prompt_length, beg); */
22615 
22616   for (i = beg, j = ss->listener_prompt_length - 1; (i >= 0) && (j >= 0); i--, j--)
22617     if (str[i] != ss->Listener_Prompt[j])
22618       {
22619 	/* fprintf(stderr, "%c != %c at %d\n", str[i], ss->Listener_Prompt[j], j); */
22620       return(false);
22621       }
22622   if (j != -1)
22623     {
22624       /* fprintf(stderr, "j: %d\n", j); */
22625     return(false);
22626     }
22627   if ((i == -1) || (str[i] == '\n'))
22628     {
22629       /* fprintf(stderr, "found prompt!\n"); */
22630     return(true);
22631     }
22632   /* fprintf(stderr, "i: %d, str[i]: %c\n", i, str[i]); */
22633   return(false);
22634 }
22635 
22636 
listener_help_at_cursor(char * buf,int name_curpos,int len,int prompt_pos)22637 static void listener_help_at_cursor(char *buf, int name_curpos, int len, int prompt_pos)
22638 {
22639   int i, name_start, name_end;
22640 
22641   if (isspace(buf[name_curpos]))
22642     {
22643       for (i = name_curpos - 1; i >= 0; i--)
22644 	if ((!isspace(buf[i])) &&
22645 	    (buf[i] != '(') &&
22646 	    (buf[i] != ')'))
22647 	  break;
22648       if (i > 0)
22649 	name_curpos = i;
22650     }
22651 
22652   for (i = name_curpos; i >= 0; i--)
22653     if ((isspace(buf[i])) ||
22654 	(buf[i] == '(') ||
22655 	(buf[i] == ')'))
22656       break;
22657   name_start = i + 1;
22658 
22659   for (i = name_curpos + 1; i < len; i++)
22660     if ((isspace(buf[i])) ||
22661 	(buf[i] == '(') ||
22662 	(buf[i] == ')'))
22663       break;
22664   name_end = i - 1;
22665 
22666   if (name_end > name_start)
22667     {
22668       char *new_text;
22669 
22670       buf[name_end + 1] = '\0';
22671       new_text = direct_completions((char *)(buf + name_start));
22672 
22673       if (new_text)
22674 	{
22675 	  int matches;
22676 	  matches = get_possible_completions_size();
22677 
22678 	  if (matches == 1)
22679 	    {
22680 	      Xen help;
22681 	      help = g_snd_help(C_string_to_Xen_string(new_text), 0);
22682 	      if (Xen_is_string(help))
22683 		snd_help((char *)(buf + name_start), Xen_string_to_C_string(help), WITH_WORD_WRAP);
22684 	    }
22685 	  else
22686 	    {
22687 	      if (matches > 1)
22688 		{
22689 		  char **buffer;
22690 		  char *help_str;
22691 		  int match_len = 0;
22692 
22693 		  buffer = get_possible_completions();
22694 		  for (i = 0; i < matches; i++)
22695 		    match_len += mus_strlen(buffer[i]);
22696 
22697 		  help_str = (char *)calloc(match_len + matches * 8, sizeof(char));
22698 		  for (i = 0; i < matches; i++)
22699 		    {
22700 		      strcat(help_str, buffer[i]);
22701 		      strcat(help_str, "\n");
22702 		    }
22703 		  snd_help((char *)(buf + name_start), help_str, WITHOUT_WORD_WRAP);
22704 		  free(help_str);
22705 		}
22706 	    }
22707 	  free(new_text);
22708 	}
22709     }
22710 }
22711 
22712 
within_prompt(const char * str,int beg,int end)22713 static bool within_prompt(const char *str, int beg, int end)
22714 {
22715   /* search backwards up to prompt length for cr (or 0), check for prompt */
22716   int i, lim;
22717   if ((beg + 1 == end) && (str[beg] == '\n')) return(false); /* end-of-page cr within double quotes probably */
22718   lim = beg - ss->listener_prompt_length;
22719   if (lim < 0) return(true);
22720   for (i = beg; i >= lim; i--)
22721     if ((str[i] == '\n') || (i == 0))
22722       {
22723 	int j, k;
22724 	for (j = 0, k = i + 1; (j < ss->listener_prompt_length) && (k < end); j++, k++)
22725 	  if (str[k] != ss->Listener_Prompt[j])
22726 	    return(false);
22727 	return(true);
22728       }
22729   return(false);
22730 }
22731 
22732 
trim(char * orig)22733 static char *trim(char *orig)
22734 {
22735   int i, j, start = -1, end = -1, len;
22736   char *str;
22737 
22738   len = mus_strlen(orig);
22739   if (len == 0) return(NULL);
22740 
22741   for (start = 0; start < len; start++)
22742     if ((!isspace(orig[start])) &&
22743 	(orig[start] != '(') &&
22744 	(orig[start] != ')'))
22745       break;
22746   if (start >= len) return(NULL);
22747   for (end = len - 1; end > start; end--)
22748     if ((!isspace(orig[end])) &&
22749 	(orig[end] != '(') &&
22750 	(orig[end] != ')'))
22751       break;
22752   if (start == end) return(NULL);
22753 
22754   len = end - start + 1;
22755   str = (char *)calloc(len + 1, sizeof(char));
22756   for (i = start, j = 0; i <= end; i++, j++)
22757     str[j] = orig[i];
22758   return(str);
22759 }
22760 
22761 
find_matching_paren(const char * str,int parens,int pos,int * highlight_pos)22762 static int find_matching_paren(const char *str, int parens, int pos, int *highlight_pos)
22763 {
22764   int i, j;
22765   bool quoting = false;
22766   int up_comment = -1;
22767   for (i = pos - 1; i > 0;)
22768     {
22769       if (is_prompt(str, i))
22770 	break;
22771       if (str[i] == '\"')
22772 	{
22773 	  /* there could be any number of slashified slashes before this quote. */
22774 	  int k, slashes = 0;
22775 	  for (k = i - 1; k >= 0; k--)
22776 	    {
22777 	      if (str[k] == '\\')
22778 		slashes++;
22779 	      else break;
22780 	    }
22781 	  if ((slashes & 1) == 0)
22782 	    quoting = !quoting;
22783 	}
22784       if (!quoting)
22785 	{
22786 	  if ((i <= 1) || (str[i - 1] != '\\') || (str[i - 2] != '#'))
22787 	    {
22788 	      if (str[i] == ')') parens++; else
22789 	      if (str[i] == '(') parens--; else
22790 	      if (str[i] == '\n')
22791 		{
22792 		  /* check for comment on next line up */
22793 		  bool up_quoting = false;
22794 		  int quote_comment = -1;
22795 		  for (j = i - 1; j > 0; j--)
22796 		    {
22797 		      if (str[j] == '\n') break;
22798 		      if ((str[j] == '\"') && (str[j - 1] != '\\'))
22799 			up_quoting = !up_quoting;
22800 		      if ((str[j] == ';') &&
22801 			  ((j <= 1) || (str[j - 1] != '\\') || (str[j - 2] != '#')))
22802 			{
22803 			  if (!up_quoting)
22804 			    up_comment = j;
22805 			  else quote_comment = j;
22806 			}
22807 		    }
22808 		  if (up_comment < i)
22809 		    {
22810 		      if (up_comment > 0)
22811 			i = up_comment;
22812 		      else
22813 			{
22814 			  if ((up_quoting) && (quote_comment > 0))
22815 			    i = quote_comment;
22816 			}
22817 		    }
22818 		}
22819 	    }
22820 	}
22821       if (parens == 0)
22822 	{
22823 	  (*highlight_pos) = i;
22824 	  break;
22825 	}
22826       i--;
22827     }
22828   return(parens);
22829 }
22830 
22831 #if (!HAVE_RUBY) && (!HAVE_FORTH)
22832 static bool highlight_unbalanced_paren(void);
22833 
check_balance(const char * expr,int start,int end,bool in_listener)22834 static int check_balance(const char *expr, int start, int end, bool in_listener)
22835 {
22836   int i;
22837   bool not_whitespace = false;
22838   int paren_count = 0;
22839   bool prev_separator = true;
22840   bool quote_wait = false;
22841 
22842   i = start;
22843   while (i < end)
22844     {
22845       switch (expr[i])
22846 	{
22847 	case ';' :
22848 	  /* skip till newline. */
22849 	  do {
22850 	    i++;
22851 	  } while ((expr[i] != '\n') && (i < end));
22852 	  break;
22853 
22854 	case ' ':
22855 	case '\n':
22856 	case '\t':
22857 	case '\r':
22858 	  if ((not_whitespace) && (paren_count == 0) && (!quote_wait))
22859 	    return(i);
22860 	  else
22861 	    {
22862 	      prev_separator = true;
22863 	      i++;
22864 	    }
22865 	  break;
22866 
22867 	case '\"' :
22868 	  if ((not_whitespace) && (paren_count == 0) && (!quote_wait))
22869 	    return(i);
22870 	  else
22871 	    {
22872 	      /* skip past ", ignoring \", some cases:
22873 	       *  "\"\"" '("\"\"") "\\" "#\\(" "'(\"#\\\")"
22874 	       */
22875 	      while (i < end)
22876 		{
22877 		  i++;
22878 		  if (expr[i] == '\\')
22879 		    i++;
22880 		  else
22881 		    {
22882 		      if (expr[i] == '\"')
22883 			break;
22884 		    }
22885 		}
22886 	      i++;
22887 	      if (paren_count == 0)
22888 		{
22889 		  if (i < end)
22890 		    return(i);
22891 		  else return(0);
22892 		}
22893 	      else
22894 		{
22895 		  prev_separator = true;
22896 		  not_whitespace = true;
22897 		  quote_wait = false;
22898 		}
22899 	    }
22900 	  break;
22901 
22902 	case '#':
22903 	  if ((i < end - 1) &&
22904 	      (expr[i + 1] == '|'))
22905 	    {
22906 	      /* (+ #| a comment |# 2 1) */
22907 	      i++;
22908 	      do {
22909 		i++;
22910 	      } while (((expr[i] != '|') || (expr[i + 1] != '#')) && (i < end));
22911 	      i++;
22912 	      break;
22913 	    }
22914 	  else
22915 	    {
22916 	      /* (set! *#readers* (cons (cons #\c (lambda (str) (apply make-rectangular (read)))) *#readers*))
22917 	       */
22918 	      if ((not_whitespace) && (paren_count == 0) && (!quote_wait))
22919 		return(i);
22920 	      else
22921 		{
22922 		  bool found_it = false;
22923 		  if (prev_separator)
22924 		    {
22925 		      int k, incr = 0;
22926 		      for (k = i + 1; k < end; k++)
22927 			{
22928 			  if (expr[k] == '(')
22929 			    {
22930 			      /* should we look at the readers here? I want to support #c(1 2) for example */
22931 			      not_whitespace = false;
22932 			      prev_separator = false;
22933 			      incr = k - i;
22934 			      break;
22935 			    }
22936 			  else
22937 			    {
22938 			      if ((!isdigit(expr[k])) && /* #2d(...)? */
22939 				  (!isalpha(expr[k])) && /* #c(1 2)? */
22940 				  (expr[k] != 'D') &&
22941 				  (expr[k] != 'd') &&
22942 				  (expr[k] != '=') &&   /* what is this for? */
22943 				  (expr[k] != '#'))     /* perhaps #1d(#(1 2) 3) ? */
22944 				break;
22945 			    }
22946 			}
22947 		      if (incr > 0)
22948 			{
22949 			  i += incr;
22950 			  found_it = true;
22951 			}
22952 		    }
22953 		  if (!found_it)
22954 		    {
22955 		      if ((i + 2 < end) && (expr[i + 1] == '\\') &&
22956 			  ((expr[i + 2] == ')') || (expr[i + 2] == ';') || (expr[i + 2] == '\"') || (expr[i + 2] == '(')))
22957 			i += 3;
22958 		      else
22959 			{
22960 			  prev_separator = false;
22961 			  quote_wait = false;
22962 			  not_whitespace = true;
22963 			  i++;
22964 			}
22965 		    }
22966 		}
22967 	    }
22968 	  break;
22969 
22970 	case '(' :
22971 	  if ((not_whitespace) && (paren_count == 0) && (!quote_wait))
22972 	    return(i - 1); /* 'a(...) -- ignore the (...) */
22973 	  else
22974 	    {
22975 	      i++;
22976 	      paren_count++;
22977 	      not_whitespace = true;
22978 	      prev_separator = true;
22979 	      quote_wait = false;
22980 	    }
22981 	  break;
22982 
22983 	case ')' :
22984 	  paren_count--;
22985 	  if ((not_whitespace) && (paren_count == 0))
22986 	    return(i + 1);
22987 	  else
22988 	    {
22989 	      i++;
22990 	      not_whitespace = true;
22991 	      prev_separator = true;
22992 	      quote_wait = false;
22993 	    }
22994 	  break;
22995 
22996 	case '\'' :
22997 	case '`' :                  /* `(1 2) */
22998 	  if (prev_separator)
22999 	    quote_wait = true;
23000 	  not_whitespace = true;
23001 	  i++;
23002 	  break;
23003 
23004 	case ',':                   /* `,(+ 1 2) */
23005 	case '@':                   /* `,@(list 1 2) */
23006 	  prev_separator = false;
23007 	  not_whitespace = true;
23008 	  i++;
23009 	  break;
23010 
23011 	default:
23012 	  prev_separator = false;
23013 	  quote_wait = false;
23014 	  not_whitespace = true;
23015 	  i++;
23016 	  break;
23017 	}
23018     }
23019 
23020   if ((in_listener) && (!(highlight_unbalanced_paren())))
23021     return(-1);
23022   return(0);
23023 }
23024 #endif
23025 
23026 static char listener_prompt_buffer[LABEL_BUFFER_SIZE];
23027 
listener_prompt_with_cr(void)23028 static char *listener_prompt_with_cr(void)
23029 {
23030   snprintf(listener_prompt_buffer, LABEL_BUFFER_SIZE, "\n%s", listener_prompt(ss));
23031   return(listener_prompt_buffer);
23032 }
23033 
23034 #define GUI_TEXT_END(w) XmTextGetLastPosition(w)
23035 #define GUI_TEXT_POSITION_TYPE XmTextPosition
23036 #define GUI_TEXT(w) XmTextGetString(w)
23037 #define GUI_TEXT_INSERTION_POSITION(w) XmTextGetInsertionPosition(w)
23038 #define GUI_TEXT_SET_INSERTION_POSITION(w, pos) XmTextSetInsertionPosition(w, pos)
23039 #define GUI_LISTENER_TEXT_INSERT(w, pos, text) XmTextInsert(w, pos, text)
23040 #define GUI_FREE(w) XtFree(w)
23041 #define GUI_SET_CURSOR(w, cursor) XUndefineCursor(XtDisplay(w), XtWindow(w)); XDefineCursor(XtDisplay(w), XtWindow(w), cursor)
23042 #define GUI_UNSET_CURSOR(w, cursor) XUndefineCursor(XtDisplay(w), XtWindow(w)); XDefineCursor(XtDisplay(w), XtWindow(w), None)
23043 #define GUI_UPDATE(w) XmUpdateDisplay(w)
23044 #define GUI_TEXT_GOTO(w, pos) XmTextShowPosition(w, pos)
23045 
23046 
23047 static int current_listener_position = -1, listener_positions_size = 0;
23048 static int *listener_positions = NULL;
23049 
23050 
add_listener_position(int pos)23051 static void add_listener_position(int pos)
23052 {
23053   if (listener_positions_size == 0)
23054     {
23055       listener_positions_size = 32;
23056       listener_positions = (int *)calloc(listener_positions_size, sizeof(int));
23057       current_listener_position = 0;
23058     }
23059   else
23060     {
23061       int i;
23062       if (pos > listener_positions[current_listener_position])
23063 	{
23064 	  current_listener_position++;
23065 	  if (current_listener_position >= listener_positions_size)
23066 	    {
23067 	      listener_positions_size += 32;
23068 	      listener_positions = (int *)realloc(listener_positions, listener_positions_size * sizeof(int));
23069 	      for (i = current_listener_position + 1; i < listener_positions_size; i++) listener_positions[i] = 0;
23070 	    }
23071 	}
23072       else
23073 	{
23074 	  for (i = current_listener_position - 1; i >= 0; i--)
23075 	    if (listener_positions[i] < pos)
23076 	      break;
23077 	  current_listener_position = i + 1;
23078 	}
23079     }
23080   listener_positions[current_listener_position] = pos;
23081 }
23082 
23083 
backup_listener_to_previous_expression(void)23084 static void backup_listener_to_previous_expression(void)
23085 {
23086   if (current_listener_position > 0)
23087     {
23088       current_listener_position--;
23089       listener_delete_text(listener_positions[current_listener_position]);
23090     }
23091 }
23092 
23093 #if HAVE_SCHEME
23094 static s7_pointer top_level_let = NULL;
g_top_level_let(s7_scheme * sc,s7_pointer args)23095 static s7_pointer g_top_level_let(s7_scheme *sc, s7_pointer args)
23096 {
23097   return(top_level_let);
23098 }
23099 
g_set_top_level_let(s7_scheme * sc,s7_pointer args)23100 static s7_pointer g_set_top_level_let(s7_scheme *sc, s7_pointer args)
23101 {
23102   top_level_let = s7_car(args);
23103   return(top_level_let);
23104 }
23105 #endif
23106 
listener_return(widget_t w,int last_prompt)23107 static void listener_return(widget_t w, int last_prompt)
23108 {
23109 #if (!USE_NO_GUI)
23110   /* try to find complete form either enclosing current cursor, or just before it */
23111   GUI_TEXT_POSITION_TYPE cmd_eot = 0;
23112   char *str = NULL, *full_str = NULL;
23113   int i, j;
23114   Xen form = Xen_undefined;
23115   GUI_TEXT_POSITION_TYPE last_position = 0, current_position = 0;
23116 
23117 #if (!HAVE_RUBY && !HAVE_FORTH)
23118   GUI_TEXT_POSITION_TYPE end_of_text = 0, start_of_text = 0;
23119   int parens;
23120 #if USE_MOTIF
23121   GUI_TEXT_POSITION_TYPE new_eot = 0;
23122 #endif
23123 #endif
23124 
23125   full_str = GUI_TEXT(w);
23126   current_position = GUI_TEXT_INSERTION_POSITION(w);
23127 #if (!HAVE_RUBY && !HAVE_FORTH)
23128   start_of_text = current_position;
23129   end_of_text = current_position;
23130 #endif
23131   last_position = GUI_TEXT_END(w);
23132   add_listener_position(last_position);
23133 
23134 #if (!HAVE_SCHEME)
23135   if (have_read_hook())
23136     {
23137       Xen result;
23138       int len;
23139       len = last_position - last_prompt;
23140       if (len > 0)
23141 	{
23142 	  str = (char *)calloc(len + 1, sizeof(char));
23143 	  for (i = last_prompt, j = 0; i < last_position; i++, j++) str[j] = full_str[i];
23144 	  result = run_read_hook(str);
23145 	  free(str);
23146 	  if (Xen_is_true(result))
23147 	    {
23148 	      if (full_str) GUI_FREE(full_str);
23149 	      return;
23150 	    }
23151 	}
23152     }
23153 #endif
23154 
23155   /* prompt = listener_prompt(ss); */
23156 
23157   /* first look for a form just before the current mouse location,
23158    *   independent of everything (i.e. user may have made changes
23159    *   in a form included in a comment, then typed return, expecting
23160    *   us to use the new version, but the check_balance procedure
23161    *   tries to ignore comments).
23162    */
23163 
23164   str = NULL;
23165 
23166 #if HAVE_RUBY || HAVE_FORTH
23167   {
23168     int k, len, start, full_len;
23169     for (i = current_position - 1; i >= 0; i--)
23170       if (is_prompt(full_str, i))
23171 	{
23172 	  full_len = strlen(full_str);
23173 	  for (k = current_position - 1; k < full_len; k++)
23174 	    if (full_str[k] == '\n')
23175 	      break;
23176 	  start = i + 1;
23177 	  len = (k - start + 1);
23178 	  str = (char *)calloc(len, sizeof(char));
23179 	  for (k = 0; k < len - 1; k++)
23180 	    str[k] = full_str[k + start];
23181           break;
23182 	}
23183   }
23184 #else
23185   if (last_position > end_of_text)
23186     {
23187       end_of_text = last_position; /* added 12-Nov-07 for first form */
23188       for (i = current_position; i < last_position; i++)
23189 	if (is_prompt(full_str, i + 1))
23190 	  {
23191 	    /* fprintf(stderr, "set end to %d (%d)\n", i - ss->listener_prompt_length + 1, i); */
23192 	    end_of_text = i - ss->listener_prompt_length + 1;
23193 	    break;
23194 	  }
23195     }
23196   if (start_of_text > 0)
23197     {
23198       for (i = end_of_text; i >= 0; i--)
23199 	if (is_prompt(full_str, i))
23200 	  {
23201 	    /* fprintf(stderr, "set start to %d\n", i + 1); */
23202 	    start_of_text = i + 1;
23203 	    break;
23204 	  }
23205     }
23206 
23207   /* fprintf(stderr, "found %d %d\n", start_of_text, end_of_text); */
23208 
23209   if (end_of_text > start_of_text)
23210     {
23211       int slen;
23212       parens = 0;
23213       slen = end_of_text - start_of_text + 2;
23214       str = (char *)calloc(slen, sizeof(char));
23215       for (i = start_of_text, j = 0; i <= end_of_text; j++, i++)
23216 	{
23217 	  str[j] = full_str[i];
23218 	  if (str[j] == '(')
23219 	    parens++;
23220 	}
23221       str[end_of_text - start_of_text + 1] = 0;
23222       end_of_text = mus_strlen(str);
23223 
23224       if (parens)
23225 	{
23226 	  end_of_text = check_balance(str, 0, (int)end_of_text, true); /* last-arg->we are in the listener */
23227 	  if ((end_of_text > 0) &&
23228 	      (end_of_text < slen))
23229 	    {
23230 	      if (end_of_text < (slen - 1))
23231 		str[end_of_text + 1] = 0;
23232 	      else str[end_of_text] = 0;
23233 	      if (str[end_of_text] == '\n') str[end_of_text] = 0;
23234 	    }
23235 	  else
23236 	    {
23237 	      free(str);
23238 	      str = NULL;
23239 	      if (end_of_text < 0)
23240 		listener_append_and_prompt(NULL);
23241 	      else
23242 		{
23243 #if USE_MOTIF
23244 		  new_eot = GUI_TEXT_END(w);
23245 		  GUI_LISTENER_TEXT_INSERT(w, new_eot, (char *)"\n");
23246 #else
23247 		  GUI_LISTENER_TEXT_INSERT(w, 0, (char *)"\n");
23248 #endif
23249 		}
23250 	      if (full_str) GUI_FREE(full_str);
23251 	      return;
23252 	    }
23253 	}
23254       else
23255 	{
23256 	  /* no parens -- pick up closest entity */
23257 	  int loc, k, len;
23258 	  char *tmp;
23259 	  loc = current_position - start_of_text - 1;
23260 	  for (i = loc; i >= 0; i--)
23261 	    if ((str[i] == '\n') || (i == 0))
23262 	      {
23263 		len = mus_strlen(str);
23264 		tmp = (char *)calloc(len + 1, sizeof(char));
23265 		if (i != 0) i++;
23266 		for (k = 0; i < len; i++, k++)
23267 		  if ((i > loc) &&
23268 		      ((str[i] == '\n') ||
23269 		       (str[i] == ' ')))
23270 		    break;
23271 		  else tmp[k] = str[i];
23272 		free(str);
23273 		str = tmp;
23274 		break;
23275 	      }
23276 	}
23277     }
23278 #endif
23279 
23280   if (full_str) GUI_FREE(full_str);
23281   {
23282     bool need_eval = false;
23283     int i, len;
23284     /* fprintf(stderr, "return: %s\n", str); */
23285 
23286     len = mus_strlen(str);
23287     for (i = 0; i < len; i++)
23288       if ((str[i] != ' ') &&
23289 	  (str[i] != '\n') &&
23290 	  (str[i] != '\r') &&
23291 	  (str[i] != '\t'))
23292 	{
23293 	  need_eval = true;
23294 	  break;
23295 	}
23296     if (!need_eval)
23297       append_listener_text(-1, "\n");
23298     else
23299       {
23300 	if (str)
23301 	  {
23302 	    char *errmsg = NULL;
23303 
23304 	    if (current_position < (last_position - 2))
23305 	      GUI_LISTENER_TEXT_INSERT(w, GUI_TEXT_END(w), str);
23306 
23307 	    GUI_SET_CURSOR(w, ss->wait_cursor);
23308 	    GUI_UPDATE(w); /* not sure about this... */
23309 
23310 	    if ((mus_strlen(str) > 1) || (str[0] != '\n'))
23311 	      remember_listener_string(str);
23312 
23313 #if HAVE_RUBY || HAVE_FORTH
23314 	    form = Xen_eval_C_string(str);
23315 #endif
23316 
23317 #if HAVE_SCHEME
23318 	    /* very tricky -- we need the interface running to see C-g, and in ordinary (not-hung, but very slow-to-compute) code
23319 	     *   we need to let other interface stuff run.  We can't look at each event and flush all but the C-g we're waiting
23320 	     *   for because that confuses the rest of the GUI, and some such interactions are expected.  But if interface actions
23321 	     *   are tied to scheme code, the check_for_event lets that code be evaluated, even though we're actually running
23322 	     *   the evaluator already in a separate thread.  If we block on the thread ID (pthread_self), bad stuff still gets
23323 	     *   through somehow.
23324 	     *
23325 	     * s7 threads here only solves the s7 side of the problem.
23326 	     *
23327 	     * So... set begin_hook to a func that calls check_for_event;
23328 	     *   if C-g, the begin_hook func returns true, and s7 calls s7_quit, and C_g_typed is true here.
23329 	     *   Otherwise, I think anything is safe because we're only looking at the block start, and
23330 	     *   we're protected there by a stack barrier.
23331 	     *
23332 	     * But this polling at block starts is expensive, mainly because XtAppPending
23333 	     *   are very slow.  So with_interrupts can turn off this check.
23334 	     */
23335 
23336 	    if (s7_begin_hook(s7)) return;      /* s7 is already running (user typed <cr> during computation) */
23337 
23338 	    if ((mus_strlen(str) > 1) || (str[0] != '\n'))
23339 	      {
23340 		s7_int gc_loc;
23341 		s7_pointer old_port;
23342 
23343 		old_port = s7_set_current_error_port(s7, s7_open_output_string(s7));
23344 		gc_loc = s7_gc_protect(s7, old_port);
23345 
23346 		if (with_interrupts(ss))
23347 		  s7_set_begin_hook(s7, listener_begin_hook);
23348 
23349 		if (have_read_hook())
23350 		  form = run_read_hook(str);
23351 		else form = s7_eval_c_string_with_environment(s7, str, top_level_let);
23352 
23353 		s7_set_begin_hook(s7, NULL);
23354 		if (ss->C_g_typed)
23355 		  {
23356 		    errmsg = mus_strdup("\nSnd interrupted!");
23357 		    ss->C_g_typed = false;
23358 		  }
23359 		else errmsg = mus_strdup(s7_get_output_string(s7, s7_current_error_port(s7)));
23360 
23361 		s7_close_output_port(s7, s7_current_error_port(s7));
23362 		s7_set_current_error_port(s7, old_port);
23363 		s7_gc_unprotect_at(s7, gc_loc);
23364 	      }
23365 #endif
23366 
23367 	    if (errmsg)
23368 	      {
23369 		if (*errmsg)
23370 		  snd_display_result(errmsg, NULL);
23371 		free(errmsg);
23372 	      }
23373 	    else snd_report_listener_result(form); /* used to check for unbound form here, but that's no good in Ruby */
23374 
23375 	    free(str);
23376 	    str = NULL;
23377 	    GUI_UNSET_CURSOR(w, ss->arrow_cursor);
23378 	  }
23379 	else
23380 	  {
23381 	    listener_append_and_prompt(NULL);
23382 	  }
23383       }
23384   }
23385 
23386   cmd_eot = GUI_TEXT_END(w);
23387   add_listener_position(cmd_eot);
23388   GUI_TEXT_GOTO(w, cmd_eot - 1);
23389   GUI_TEXT_SET_INSERTION_POSITION(w, cmd_eot + 1);
23390 #endif
23391 }
23392 
23393 
23394 
23395 /* -------------------------------------------------------------------------------- */
23396 
23397 
23398 #define OVERRIDE_TOGGLE 1
23399 /* Motif 2.0 defines control-button1 to be "take focus" -- this is not a good idea!! */
23400 
23401 
Tab_completion(Widget w,XEvent * event,char ** str,Cardinal * num)23402 static void Tab_completion(Widget w, XEvent *event, char **str, Cardinal *num)
23403 {
23404   int completer;
23405   intptr_t data;
23406 
23407   XtVaGetValues(w, XmNuserData, &data, NULL);
23408   completer = (int)data;
23409 
23410   if (completer >= 0)
23411     {
23412       int matches;
23413       char *old_text, *new_text;
23414 
23415       old_text = XmTextGetString(w);
23416       if (mus_strlen(old_text) == 0) return; /* C-x C-f TAB in kbd??, for example */
23417 
23418       new_text = complete_text(w, old_text, completer);
23419       if (mus_strlen(new_text) == 0) return; /* can this happen? */
23420       XmTextSetString(w, new_text);
23421       XmTextSetCursorPosition(w, XmTextGetLastPosition(w));
23422 
23423       matches = get_completion_matches();
23424 
23425       if ((mus_strcmp(old_text, new_text)) &&
23426 	  (matches != -1))
23427 	{
23428 	  Pixel old_color;
23429 	  XtVaGetValues(w, XmNforeground, &old_color, NULL);
23430 	  if (matches > 1)
23431 	    XtVaSetValues(w, XmNforeground, ss->green, NULL);
23432 	  else
23433 	    if (matches == 0)
23434 	      XtVaSetValues(w, XmNforeground, ss->red, NULL);
23435 	  if (matches != 1)
23436 	    {
23437 	      XmUpdateDisplay(w);
23438 	      sleep(1);
23439 	      XtVaSetValues(w, XmNforeground, old_color, NULL);
23440 	      XmUpdateDisplay(w);
23441 	    }
23442 
23443 	  if (matches > 1)                          /* there are several possible completions -- let the widget decide how to handle it */
23444 	    handle_completions(w, completer);
23445 	}
23446 
23447       if (old_text) XtFree(old_text);
23448       if (new_text) free(new_text);
23449     }
23450 }
23451 
23452 
23453 /* listener completions */
23454 
23455 static Widget listener_text = NULL;
23456 static Widget listener_pane = NULL;  /* form widget that hold the listener scrolled text widget */
23457 
23458 static Widget completions_list = NULL;
23459 static Widget completions_pane = NULL;
23460 
23461 
perform_completion(XmString selection)23462 static void perform_completion(XmString selection)
23463 {
23464   int i, j, old_len, new_len;
23465   char *text = NULL, *old_text = NULL;
23466 
23467   text = (char *)XmStringUnparse(selection, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL);
23468   save_completion_choice(text);
23469 
23470   old_text = XmTextGetString(listener_text);
23471   old_len = mus_strlen(old_text);
23472   new_len = mus_strlen(text);
23473   for (i = old_len - 1, j = new_len - 1; j >= 0; j--)
23474     {
23475       if (old_text[i] != text[j])
23476 	{
23477 	  i = old_len - 1;
23478 	  if (old_text[i] == text[j]) i--;
23479 	  /* this added 15-Apr-02 for case like map-chan(nel) */
23480 	  /*   probably should go back new_len and scan forwards instead */
23481 	}
23482       else i--;
23483     }
23484 
23485   append_listener_text(XmTextGetLastPosition(listener_text), (char *)(text - 1 + old_len - i));
23486 
23487   if (text) XtFree(text);
23488   if (old_text) XtFree(old_text);
23489 }
23490 
23491 
listener_completions_browse_callback(Widget w,XtPointer context,XtPointer info)23492 static void listener_completions_browse_callback(Widget w, XtPointer context, XtPointer info)
23493 {
23494   XmListCallbackStruct *cbs = (XmListCallbackStruct *)info;
23495   /* choice = cbs->item_position - 1; */
23496   perform_completion(cbs->item);
23497   XtUnmanageChild(completions_pane);
23498 }
23499 
23500 
alphabetize(const void * a,const void * b)23501 static int alphabetize(const void *a, const void *b)
23502 {
23503   return(strcmp(*((const char **)a), (*(const char **)b)));
23504 }
23505 
23506 
find_prompt(Widget w,XmTextPosition start)23507 static int find_prompt(Widget w, XmTextPosition start)
23508 {
23509   Boolean found_prompt = false, found_newline;
23510   XmTextPosition loc = 0;
23511 
23512   if (start == 0) /* try to avoid strlen null in motif */
23513     return(0);
23514 
23515   /* the prompt defaults to ">", so a naive backwards search for the prompt is easily confused.
23516    *   (bugfix thanks to Tito Latini).
23517    */
23518   while (!found_prompt)
23519     {
23520       found_newline = XmTextFindString(w, start, (char *)"\n", XmTEXT_BACKWARD, &loc);
23521       start = found_newline ? loc : 0;
23522       found_prompt = XmTextFindString(w, start, listener_prompt(ss), XmTEXT_FORWARD, &loc);
23523       if ((found_prompt && loc <= (start + 1)) || (start == 0))
23524         break;
23525       start--;
23526     }
23527 
23528   if (!found_prompt)
23529     return(0);
23530   else return((int)loc + mus_strlen(listener_prompt(ss)));
23531 }
23532 
23533 
motif_listener_completion(Widget w,XEvent * event,char ** str,Cardinal * num)23534 static void motif_listener_completion(Widget w, XEvent *event, char **str, Cardinal *num)  /* change name because emacs is confused */
23535 {
23536   /* used only by the listener widget -- needs to be smart about text since overall string can be enormous
23537    *   and we don't want to back up past the last prompt
23538    *   also if at start of line (or all white-space to previous \n), indent
23539    */
23540   int beg, end, replace_end, len;
23541   char *old_text;
23542 
23543   if ((completions_pane) &&
23544       (XtIsManaged(completions_pane)))
23545     {
23546       XmString *strs = NULL;
23547       XtVaGetValues(completions_list,
23548 		    XmNselectedItems, &strs,
23549 		    NULL);
23550       if (strs)
23551 	{
23552 	  perform_completion(strs[0]);
23553 	  XtUnmanageChild(completions_pane);
23554 	  return;
23555 	}
23556     }
23557 
23558   end = XmTextGetInsertionPosition(w);
23559   replace_end = end;
23560 
23561   beg = find_prompt(w, (XmTextPosition)end);
23562   len = end - beg + 1;
23563 
23564   old_text = (char *)calloc(len + 1, sizeof(char));
23565   XmTextGetSubstring(w, beg, len, len + 1, old_text);
23566   /* now old_text is the stuff typed since the last prompt */
23567 
23568   if (old_text[len - 1] == '\n')
23569     {
23570       old_text[len - 1] = 0;
23571       end--;
23572     }
23573 
23574   if (old_text)
23575     {
23576       int matches = 0;
23577       char *new_text = NULL, *file_text = NULL;
23578       bool try_completion = true;
23579       new_text = complete_listener_text(old_text, end, &try_completion, &file_text);
23580 
23581       if (!try_completion)
23582 	{
23583 	  free(old_text);
23584 	  return;
23585 	}
23586 
23587       if (mus_strcmp(old_text, new_text))
23588 	matches = get_completion_matches();
23589       else XmTextReplace(w, beg, replace_end, new_text);
23590 
23591       if (new_text)
23592 	{
23593 	  free(new_text);
23594 	  new_text = NULL;
23595 	}
23596 
23597       if (matches > 1)
23598 	{
23599 	  int num;
23600 	  clear_possible_completions();
23601 	  set_save_completions(true);
23602 	  if (file_text)
23603 	    new_text = filename_completer(w, file_text, NULL);
23604 	  else new_text = expression_completer(w, old_text, NULL);
23605 	  if (new_text)
23606 	    {
23607 	      free(new_text);
23608 	      new_text = NULL;
23609 	    }
23610 	  num = get_possible_completions_size();
23611 	  if (num > 0)
23612 	    {
23613 	      int i;
23614 	      XmString *match;
23615 	      char **buffer;
23616 
23617 	      if (!completions_list)
23618 		{
23619 		  Arg args[20];
23620 		  int n = 0;
23621 
23622 		  XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
23623 		  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
23624 		  XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
23625 		  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
23626 		  XtSetArg(args[n], XmNscrollBarPlacement, XmBOTTOM_LEFT); n++;
23627 		  XtSetArg(args[n], XmNbackground, ss->white); n++;
23628 		  XtSetArg(args[n], XmNforeground, ss->black); n++;
23629 		  XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
23630 
23631 		  completions_list = XmCreateScrolledList(listener_pane, (char *)"completion-help-text", args, n);
23632 		  completions_pane = XtParent(completions_list);
23633 
23634 		  XtAddCallback(completions_list, XmNbrowseSelectionCallback, listener_completions_browse_callback, NULL);
23635 		  XtManageChild(completions_list);
23636 		}
23637 
23638 	      buffer = get_possible_completions();
23639 	      qsort((void *)buffer, num, sizeof(char *), alphabetize);
23640 
23641 	      match = (XmString *)calloc(num, sizeof(XmString));
23642 	      for (i = 0; i < num; i++)
23643 		match[i] = XmStringCreateLocalized(buffer[i]);
23644 
23645 	      XtVaSetValues(completions_list,
23646 			    XmNitems, match,
23647 			    XmNitemCount, num,
23648 			    XmNvisibleItemCount, mus_iclamp(1, num, 20),
23649 			    NULL);
23650 
23651 	      if (!(XtIsManaged(completions_pane)))
23652 		XtManageChild(completions_pane);
23653 
23654 	      /* look at previous completions list first for a match, then
23655 	       *   look back from "beg" for any member of the match list previously typed
23656 	       */
23657 	      {
23658 		int row;
23659 		row = find_best_completion(buffer, num);
23660 		XmListSelectPos(completions_list, row, false);
23661 		ensure_list_row_visible(completions_list, row);
23662 	      }
23663 
23664 	      for (i = 0; i < num; i++)
23665 		XmStringFree(match[i]);
23666 	      free(match);
23667 	    }
23668 	  set_save_completions(false);
23669 	}
23670 
23671       if (file_text) free(file_text);
23672       if (old_text) free(old_text);
23673     }
23674 }
23675 
23676 
23677 
23678 
23679 /* ---------------- text widget specializations ---------------- */
23680 
textfield_focus_callback(Widget w,XtPointer context,XtPointer info)23681 void textfield_focus_callback(Widget w, XtPointer context, XtPointer info)
23682 {
23683   XtVaSetValues(w, XmNbackground, ss->text_focus_color, NULL);
23684   XtVaSetValues(w, XmNcursorPositionVisible, true, NULL);
23685 }
23686 
23687 
textfield_unfocus_callback(Widget w,XtPointer context,XtPointer info)23688 void textfield_unfocus_callback(Widget w, XtPointer context, XtPointer info)
23689 {
23690   XtVaSetValues(w, XmNbackground, ss->basic_color, NULL);
23691   XtVaSetValues(w, XmNcursorPositionVisible, false, NULL);
23692 }
23693 
23694 
textfield_no_color_focus_callback(Widget w,XtPointer context,XtPointer info)23695 static void textfield_no_color_focus_callback(Widget w, XtPointer context, XtPointer info)
23696 {
23697   XtVaSetValues(w, XmNcursorPositionVisible, true, NULL);
23698 }
23699 
23700 
textfield_no_color_unfocus_callback(Widget w,XtPointer context,XtPointer info)23701 static void textfield_no_color_unfocus_callback(Widget w, XtPointer context, XtPointer info)
23702 {
23703   XtVaSetValues(w, XmNcursorPositionVisible, false, NULL);
23704 }
23705 
23706 
23707 /* -------- specialized action procs -------- */
23708 
23709 static bool actions_loaded = false;
23710 #define CONTROL_KEY 4
23711 
No_op(Widget w,XEvent * ev,char ** str,Cardinal * num)23712 static void No_op(Widget w, XEvent *ev, char **str, Cardinal *num)
23713 {
23714   /* return does not cause widget activation in many textfield cases -- it is a true no-op */
23715 }
23716 
23717 
23718 #define snd_K_u XK_u
23719 #define snd_K_x XK_x
23720 
Activate_keyboard(Widget w,XEvent * ev,char ** str,Cardinal * num)23721 static void Activate_keyboard(Widget w, XEvent *ev, char **str, Cardinal *num)
23722 {
23723   /* make the current channel active preloading kbd cmd with str[0]+ctrl bit */
23724   chan_info *cp;
23725   cp = current_channel();
23726   if (cp)
23727     {
23728       goto_graph(cp);
23729       keyboard_command(cp, (str[0][0] == 'u') ? snd_K_u : snd_K_x, CONTROL_KEY);
23730     }
23731 }
23732 
23733 
23734 static char *listener_selection = NULL;
23735 
Kill_line(Widget w,XEvent * ev,char ** str,Cardinal * num)23736 static void Kill_line(Widget w, XEvent *ev, char **str, Cardinal *num)
23737 {
23738   /* C-k with storage of killed text */
23739   XmTextPosition curpos, loc;
23740   Boolean found;
23741   curpos = XmTextGetCursorPosition(w);
23742   found = XmTextFindString(w, curpos, (char *)"\n", XmTEXT_FORWARD, &loc);
23743   if (!found) loc = XmTextGetLastPosition(w);
23744   if (loc > curpos)
23745     {
23746       if (listener_selection) {XtFree(listener_selection); listener_selection = NULL;}
23747       XmTextSetSelection(w, curpos, loc, CurrentTime);
23748       listener_selection = XmTextGetSelection(w); /* xm manual p329 sez storage is allocated here */
23749       XmTextCut(w, CurrentTime);
23750     }
23751 }
23752 
23753 
Yank(Widget w,XEvent * ev,char ** str,Cardinal * num)23754 static void Yank(Widget w, XEvent *ev, char **str, Cardinal *num)
23755 {
23756   /* copy current selection at current cursor position */
23757   if (listener_selection)
23758     {
23759       XmTextPosition curpos;
23760       curpos = XmTextGetCursorPosition(w);
23761       XmTextInsert(w, curpos, listener_selection);
23762       curpos += strlen(listener_selection);
23763       XmTextShowPosition(w, curpos);
23764       XmTextSetCursorPosition(w, curpos);
23765       XmTextClearSelection(w, ev->xkey.time); /* so C-y + edit doesn't forbid the edit */
23766     }
23767 }
23768 
23769 
Begin_of_line(Widget w,XEvent * ev,char ** ustr,Cardinal * num)23770 static void Begin_of_line(Widget w, XEvent *ev, char **ustr, Cardinal *num)
23771 {
23772   /* don't back up before listener prompt */
23773   XmTextPosition curpos, loc;
23774   Boolean found;
23775   curpos = XmTextGetCursorPosition(w) - 1;
23776   found = XmTextFindString(w, curpos, (char *)"\n", XmTEXT_BACKWARD, &loc);
23777   if (curpos >= ss->listener_prompt_length - 1)
23778     {
23779       char *str = NULL;
23780       str = (char *)calloc(ss->listener_prompt_length + 3, sizeof(char));
23781       loc = found ? loc + 1 : 0;
23782       XmTextGetSubstring(w, loc, ss->listener_prompt_length, ss->listener_prompt_length + 2, str);
23783       if (strncmp(listener_prompt(ss), str, ss->listener_prompt_length) == 0)
23784 	XmTextSetCursorPosition(w, loc + ss->listener_prompt_length);
23785       else XmTextSetCursorPosition(w, loc);
23786       free(str);
23787     }
23788   else XmTextSetCursorPosition(w, 0);
23789 }
23790 
23791 
Delete_region(Widget w,XEvent * ev,char ** str,Cardinal * num)23792 static void Delete_region(Widget w, XEvent *ev, char **str, Cardinal *num)
23793 {
23794   XmTextCut(w, CurrentTime);
23795 }
23796 
23797 
23798 static XmTextPosition down_pos, last_pos;
23799 static Xen listener_click_hook;
23800 
B1_press(Widget w,XEvent * event,char ** str,Cardinal * num)23801 static void B1_press(Widget w, XEvent *event, char **str, Cardinal *num)
23802 {
23803   XmTextPosition pos;
23804   XButtonEvent *ev = (XButtonEvent *)event;
23805   XmProcessTraversal(w, XmTRAVERSE_CURRENT);
23806   /* we're replacing the built-in take_focus action here, so do it by hand, but leave listener blue, so to speak */
23807   if (w != listener_text)
23808     XtVaSetValues(w, XmNbackground, ss->white, NULL);
23809   else XmTextClearSelection(listener_text, CurrentTime); /* should this happen in other windows as well? */
23810   pos = XmTextXYToPos(w, (Position)(ev->x), (Position)(ev->y));
23811   XmTextSetCursorPosition(w, pos);
23812   down_pos = pos;
23813   last_pos = pos;
23814   if (Xen_hook_has_list(listener_click_hook))
23815     run_hook(listener_click_hook,
23816 	     Xen_list_1(C_int_to_Xen_integer((int)pos)),
23817 	     S_listener_click_hook);
23818 }
23819 
23820 
B1_move(Widget w,XEvent * event,char ** str,Cardinal * num)23821 static void B1_move(Widget w, XEvent *event, char **str, Cardinal *num)
23822 {
23823   XmTextPosition pos;
23824   XButtonEvent *ev = (XButtonEvent *)event;
23825   pos = XmTextXYToPos(w, (Position)(ev->x), (Position)(ev->y));
23826   if (last_pos > pos)                                 /* must have backed up the cursor */
23827     XmTextSetHighlight(w, pos, last_pos, XmHIGHLIGHT_NORMAL);
23828   if (down_pos != pos)
23829     XmTextSetHighlight(w, down_pos, pos, XmHIGHLIGHT_SELECTED);
23830   last_pos = pos;
23831 }
23832 
23833 
B1_release(Widget w,XEvent * event,char ** str,Cardinal * num)23834 static void B1_release(Widget w, XEvent *event, char **str, Cardinal *num)
23835 {
23836   XmTextPosition pos;
23837   XButtonEvent *ev = (XButtonEvent *)event;
23838   pos = XmTextXYToPos(w, (Position)(ev->x), (Position)(ev->y));
23839   XmTextSetCursorPosition(w, pos);
23840   if (down_pos != pos)
23841     {
23842       XmTextSetHighlight(w, down_pos, pos, XmHIGHLIGHT_SELECTED);
23843       if (listener_selection) {XtFree(listener_selection); listener_selection = NULL;}
23844       XmTextSetSelection(w, down_pos, pos, CurrentTime);
23845       listener_selection = XmTextGetSelection(w);
23846     }
23847 }
23848 
23849 
Text_transpose(Widget w,XEvent * event,char ** str,Cardinal * num)23850 static void Text_transpose(Widget w, XEvent *event, char **str, Cardinal *num)
23851 {
23852   XmTextPosition curpos;
23853   curpos = XmTextGetCursorPosition(w);
23854   if (curpos > 1)
23855     {
23856       char buf[3]; /* needs room for null */
23857       char tmp;
23858       XmTextGetSubstring(w, (XmTextPosition)(curpos - 1), 2, 3, buf);
23859       tmp = buf[0];
23860       buf[0] = buf[1];
23861       buf[1] = tmp;
23862       XmTextReplace(w, curpos - 1, curpos + 1, buf);
23863       XmTextSetCursorPosition(w, curpos + 1);
23864     }
23865 }
23866 
23867 
Complain(Widget w,XEvent * event,char ** str,Cardinal * num)23868 static void Complain(Widget w, XEvent *event, char **str, Cardinal *num)
23869 {
23870   char *old_text, *new_text;
23871   XmTextPosition curpos;
23872   int len;
23873 
23874   curpos = XmTextGetCursorPosition(w);
23875   old_text = XmTextGetString(w);
23876   len = mus_strlen(old_text) + 5;
23877   new_text = (char *)calloc(len, sizeof(char));
23878   snprintf(new_text, len, "%s C-%c", (old_text) ? old_text : "", str[0][0]);
23879 
23880   XmTextSetString(w, new_text);
23881   XmTextSetCursorPosition(w, curpos);
23882 
23883   if (old_text) XtFree(old_text);
23884   free(new_text);
23885 }
23886 
23887 
text_at_cursor(Widget w)23888 static void text_at_cursor(Widget w)
23889 {
23890   XmTextPosition curpos, endpos, start, end;
23891   int len, prompt_pos;
23892   char *buf;
23893 
23894   curpos = XmTextGetCursorPosition(w);
23895   if (curpos <= 1)
23896     curpos = XmTextGetInsertionPosition(w);
23897   if (curpos <= 1)
23898     {
23899       snd_help("Listener", "This is the 'listener', a text widget in which you can interact with Snd's extension language.  See extsnd.html.", WITH_WORD_WRAP);
23900       return;
23901     }
23902 
23903   prompt_pos = find_prompt(w, curpos);
23904 
23905   if (curpos > 40)
23906     start = curpos - 40;
23907   else start = 0;
23908   if (start < prompt_pos)
23909     start = prompt_pos;
23910 
23911   endpos = XmTextGetLastPosition(w);
23912   if ((endpos - curpos) > 40)
23913     end = curpos + 40;
23914   else end = endpos;
23915 
23916   len = end - start + 1;
23917   buf = (char *)calloc(len + 1, sizeof(char));
23918   XmTextGetSubstring(w, start, len, len + 1, buf);
23919 
23920   listener_help_at_cursor(buf, curpos - start - 1, len, prompt_pos);
23921   free(buf);
23922 }
23923 
23924 
Help_At_Cursor(Widget w,XEvent * ev,char ** str,Cardinal * num)23925 static void Help_At_Cursor(Widget w, XEvent *ev, char **str, Cardinal *num)
23926 {
23927   text_at_cursor(w);
23928 }
23929 
23930 
Word_upper(Widget w,XEvent * event,char ** str,Cardinal * num)23931 static void Word_upper(Widget w, XEvent *event, char **str, Cardinal *num)
23932 {
23933   bool up, cap;
23934   XmTextPosition curpos, endpos;
23935   up = (str[0][0] == 'u');
23936   cap = (str[0][0] == 'c');
23937   curpos = XmTextGetCursorPosition(w);
23938   endpos = XmTextGetLastPosition(w);
23939   if (curpos < endpos)
23940     {
23941       int i, length, wstart, wend;
23942       char *buf = NULL;
23943       length = endpos - curpos;
23944       buf = (char *)calloc(length + 1, sizeof(char));
23945       XmTextGetSubstring(w, curpos, length, length + 1, buf);
23946       wstart = 0;
23947       wend = length;
23948       for (i = 0; i < length; i++)
23949 	if (!isspace((int)(buf[i])))
23950 	  {
23951 	    wstart = i;
23952 	    break;
23953 	  }
23954       for (i = wstart + 1; i < length; i++)
23955 	if (isspace((int)(buf[i])))
23956 	  {
23957 	    wend = i;
23958 	    break;
23959 	  }
23960       if (cap)
23961 	{
23962 	  buf[0] = toupper(buf[wstart]);
23963 	  buf[1] = '\0';
23964 	  XmTextReplace(w, curpos + wstart, curpos + wstart + 1, buf);
23965 	}
23966       else
23967 	{
23968 	  int j;
23969 	  for (i = wstart, j = 0; i < wend; i++, j++)
23970 	    if (up)
23971 	      buf[j] = toupper(buf[i]);
23972 	    else buf[j] = tolower(buf[i]);
23973 	  buf[j] = '\0';
23974 	  XmTextReplace(w, curpos + wstart, curpos + wend, buf);
23975 	}
23976       XmTextSetCursorPosition(w, curpos + wend);
23977       if (buf) free(buf);
23978     }
23979 }
23980 
23981 
append_listener_text(int end,const char * msg)23982 void append_listener_text(int end, const char *msg)
23983 {
23984   if (listener_text)
23985     {
23986       if (end == -1) end = XmTextGetLastPosition(listener_text);
23987       XmTextInsert(listener_text, end, (char *)msg);
23988       XmTextSetCursorPosition(listener_text, XmTextGetLastPosition(listener_text));
23989     }
23990 }
23991 
23992 
23993 static bool dont_check_motion = false;
23994 
listener_delete_text(int new_end)23995 void listener_delete_text(int new_end)
23996 {
23997   int old_end;
23998   old_end = XmTextGetLastPosition(listener_text);
23999   if (old_end > new_end)
24000     {
24001       dont_check_motion = true;
24002       XmTextSetSelection(listener_text, new_end, old_end, CurrentTime);
24003       XmTextRemove(listener_text);
24004       dont_check_motion = false;
24005     }
24006 }
24007 
24008 
Listener_Meta_P(Widget w,XEvent * event,char ** str,Cardinal * num)24009 static void Listener_Meta_P(Widget w, XEvent *event, char **str, Cardinal *num)
24010 {
24011   listener_delete_text(find_prompt(w, XmTextGetInsertionPosition(w)));
24012   restore_listener_string(true);
24013 }
24014 
24015 
Listener_Meta_N(Widget w,XEvent * event,char ** str,Cardinal * num)24016 static void Listener_Meta_N(Widget w, XEvent *event, char **str, Cardinal *num)
24017 {
24018   listener_delete_text(find_prompt(w, XmTextGetInsertionPosition(w)));
24019   restore_listener_string(false);
24020 }
24021 
24022 
save_listener_text(FILE * fp)24023 int save_listener_text(FILE *fp)
24024 {
24025   /* return -1 if fwrite problem */
24026   if (listener_text)
24027     {
24028       char *str = NULL;
24029       str = XmTextGetString(listener_text);
24030       if (str)
24031 	{
24032 	  size_t bytes;
24033 	  bytes = fwrite((void *)str, sizeof(char), mus_strlen(str), fp);
24034 	  XtFree(str);
24035 	  if (bytes == 0) return(-1);
24036 	}
24037     }
24038   return(0);
24039 }
24040 
24041 
Listener_clear(Widget w,XEvent * event,char ** str,Cardinal * num)24042 static void Listener_clear(Widget w, XEvent *event, char **str, Cardinal *num)
24043 {
24044   clear_listener();
24045 }
24046 
24047 
Listener_g(Widget w,XEvent * event,char ** str,Cardinal * num)24048 static void Listener_g(Widget w, XEvent *event, char **str, Cardinal *num)
24049 {
24050   ss->C_g_typed = true;
24051   control_g(any_selected_sound());
24052 }
24053 
24054 
Listener_Backup(Widget w,XEvent * event,char ** str,Cardinal * num)24055 static void Listener_Backup(Widget w, XEvent *event, char **str, Cardinal *num)
24056 {
24057   backup_listener_to_previous_expression();
24058 }
24059 
24060 
Listener_Arrow_Up(Widget w,XEvent * event,char ** str,Cardinal * num)24061 static void Listener_Arrow_Up(Widget w, XEvent *event, char **str, Cardinal *num)
24062 {
24063   if ((completions_pane) &&
24064       (XtIsManaged(completions_pane)))
24065     {
24066       int *ns;
24067       int n;
24068       XmListGetSelectedPos(completions_list, &ns, &n);
24069       if (ns[0] > 1)
24070 	XmListSelectPos(completions_list, ns[0] - 1, false);
24071       free(ns);
24072     }
24073   else XtCallActionProc(w, "previous-line", event, str, *num);
24074 }
24075 
24076 
Listener_Arrow_Down(Widget w,XEvent * event,char ** str,Cardinal * num)24077 static void Listener_Arrow_Down(Widget w, XEvent *event, char **str, Cardinal *num)
24078 {
24079   if ((completions_pane) &&
24080       (XtIsManaged(completions_pane)))
24081     {
24082       int *ns;
24083       int n;
24084       XmListGetSelectedPos(completions_list, &ns, &n);
24085       XmListSelectPos(completions_list, ns[0] + 1, false);
24086       free(ns);
24087     }
24088   else XtCallActionProc(w, "next-line", event, str, *num);
24089 }
24090 
24091 
Listener_Return(Widget w,XEvent * event,char ** str,Cardinal * num)24092 static void Listener_Return(Widget w, XEvent *event, char **str, Cardinal *num)
24093 {
24094   if ((completions_pane) &&
24095       (XtIsManaged(completions_pane)))
24096     {
24097       XmString *strs = NULL;
24098       XtVaGetValues(completions_list,
24099 		    XmNselectedItems, &strs,
24100 		    NULL);
24101       if (strs)
24102 	{
24103 	  perform_completion(strs[0]);
24104 	  XtUnmanageChild(completions_pane);
24105 	}
24106     }
24107   else XtCallActionProc(w, "activate", event, str, *num);
24108 }
24109 
24110 
24111 #define NUM_ACTS 24
24112 static XtActionsRec acts[NUM_ACTS] = {
24113   {(char *)"no-op",                      No_op},
24114   {(char *)"activate-keyboard",          Activate_keyboard},
24115   {(char *)"yank",                       Yank},
24116   {(char *)"delete-region",              Delete_region},
24117   {(char *)"kill-line",                  Kill_line},
24118   {(char *)"begin-of-line",              Begin_of_line},
24119   {(char *)"b1-press",                   B1_press},
24120   {(char *)"b1-move",                    B1_move},
24121   {(char *)"b1-release",                 B1_release},
24122   {(char *)"text-transpose",             Text_transpose},
24123   {(char *)"word-upper",                 Word_upper},
24124   {(char *)"tab-completion",             Tab_completion},
24125   {(char *)"listener-completion",        motif_listener_completion},
24126   {(char *)"listener-clear",             Listener_clear},
24127   {(char *)"listener-g",                 Listener_g},
24128   {(char *)"listener-meta-p",            Listener_Meta_P},
24129   {(char *)"listener-meta-n",            Listener_Meta_N},
24130   {(char *)"listener-next-line",         Listener_Arrow_Down},
24131   {(char *)"listener-previous-line",     Listener_Arrow_Up},
24132   {(char *)"listener-return",            Listener_Return},
24133   {(char *)"delete-to-previous-command", Listener_Backup},
24134   {(char *)"complain",                   Complain},
24135   {(char *)"help-at-cursor",             Help_At_Cursor},
24136 };
24137 
24138 
24139 /* translation tables for emacs compatibility and better inter-widget communication */
24140 /* these values are listed in lib/Xm/Transltns.c */
24141 
24142 /* for textfield (single-line) widgets */
24143 static char TextTrans2[] =
24144        "Ctrl <Key>a:	    beginning-of-line()\n\
24145 	Ctrl <Key>b:	    backward-character()\n\
24146 	Mod1 <Key>b:	    backward-word()\n\
24147 	Mod1 <Key>c:	    word-upper(c)\n\
24148         Ctrl <Key>c:        complain(c)\n\
24149 	Ctrl <Key>d:	    delete-next-character()\n\
24150 	Mod1 <Key>d:	    delete-next-word()\n\
24151 	Ctrl <Key>e:	    end-of-line()\n\
24152 	Ctrl <Key>f:	    forward-character()\n\
24153 	Mod1 <Key>f:	    forward-word()\n\
24154 	Ctrl <Key>g:	    activate()\n\
24155 	Ctrl <Key>h:	    delete-previous-character()\n\
24156         Ctrl <Key>i:        complain(i)\n\
24157         Ctrl <Key>j:        complain(j)\n\
24158 	Ctrl <Key>k:	    delete-to-end-of-line()\n\
24159 	Mod1 <Key>l:	    word-upper(l)\n\
24160         Ctrl <Key>m:        complain(m)\n\
24161         Ctrl <Key>n:        complain(n)\n\
24162 	Mod1 <Key>n:	    activate()\n\
24163         Ctrl <Key>o:        complain(o)\n\
24164 	Mod1 <Key>p:	    activate()\n\
24165         Ctrl <Key>p:        complain(p)\n\
24166         Ctrl <Key>q:        complain(q)\n\
24167         Ctrl <Key>r:        activate()\n\
24168         Ctrl <Key>s:        activate()\n\
24169 	Ctrl <Key>t:	    text-transpose()\n\
24170 	Mod1 <Key>u:	    word-upper(u)\n\
24171         Ctrl <Key>u:        complain(u)\n\
24172         Ctrl <Key>v:        complain(v)\n\
24173         Ctrl <Key>w:        complain(w)\n\
24174 	Ctrl <Key>x:	    activate-keyboard(x)\n\
24175         Ctrl <Key>y:        complain(y)\n\
24176         Ctrl <Key>z:        complain(z)\n\
24177 	Mod1 <Key><:	    beginning-of-line()\n\
24178 	Mod1 <Key>>:	    end-of-line()\n\
24179 	<Key>Delete:	    delete-previous-character()\n\
24180 	Mod1 <Key>Delete:   delete-to-start-of-line()\n\
24181 	<Key>Tab:	    tab-completion()\n\
24182 	<Key>Return:	    activate()\n";
24183 static XtTranslations transTable2 = NULL;
24184 
24185 
24186 /* same (but not activatable), try to avoid causing the currently active pushbutton widget to appear to be activated by <cr> in the text widget */
24187 static char TextTrans6[] =
24188        "Ctrl <Key>a:	    beginning-of-line()\n\
24189 	Ctrl <Key>b:	    backward-character()\n\
24190 	Mod1 <Key>b:	    backward-word()\n\
24191 	Mod1 <Key>c:	    word-upper(c)\n\
24192 	Ctrl <Key>d:	    delete-next-character()\n\
24193 	Mod1 <Key>d:	    delete-next-word()\n\
24194 	Ctrl <Key>e:	    end-of-line()\n\
24195 	Ctrl <Key>f:	    forward-character()\n\
24196 	Mod1 <Key>f:	    forward-word()\n\
24197 	Ctrl <Key>g:	    no-op()\n\
24198 	Ctrl <Key>h:	    delete-previous-character()\n\
24199 	Ctrl <Key>k:	    delete-to-end-of-line()\n\
24200 	Mod1 <Key>l:	    word-upper(l)\n\
24201 	Ctrl <Key>t:	    text-transpose()\n\
24202 	Mod1 <Key>u:	    word-upper(u)\n\
24203 	Mod1 <Key><:	    beginning-of-line()\n\
24204 	Mod1 <Key>>:	    end-of-line()\n\
24205 	<Key>Delete:	    delete-previous-character()\n\
24206 	Mod1 <Key>Delete:   delete-to-start-of-line()\n\
24207 	<Key>Tab:	    tab-completion()\n\
24208 	<Key>Return:	    no-op()\n";
24209 static XtTranslations transTable6 = NULL;
24210 
24211 
24212 /* for text (multi-line) widgets */
24213 static char TextTrans3[] =
24214        "Ctrl <Key>a:	    beginning-of-line()\n\
24215 	Ctrl <Key>b:	    backward-character()\n\
24216 	Mod1 <Key>b:	    backward-word()\n\
24217 	Mod1 <Key>c:	    word-upper(c)\n\
24218 	Ctrl <Key>d:	    delete-next-character()\n\
24219 	Mod1 <Key>d:	    delete-next-word()\n\
24220 	Ctrl <Key>e:	    end-of-line()\n\
24221 	Ctrl <Key>f:	    forward-character()\n\
24222 	Mod1 <Key>f:	    forward-word()\n\
24223 	Ctrl <Key>g:	    activate()\n\
24224 	Ctrl <Key>h:	    delete-previous-character()\n\
24225 	Ctrl <Key>j:	    newline-and-indent()\n\
24226 	Ctrl <Key>k:	    kill-line()\n\
24227 	Mod1 <Key>l:	    word-upper(l)\n\
24228 	Ctrl <Key>n:	    next-line()\n\
24229 	Ctrl <Key>o:	    newline-and-backup()\n\
24230 	Ctrl <Key>p:	    previous-line()\n\
24231 	Ctrl <Key>t:	    text-transpose()\n\
24232 	Mod1 <Key>u:	    word-upper(u)\n\
24233 	Ctrl <Key>v:	    next-page()\n\
24234 	Mod1 <Key>v:	    previous-page()\n\
24235 	Ctrl <Key>w:	    delete-region()\n\
24236 	Ctrl <Key>y:	    yank()\n\
24237 	Ctrl <Key>z:	    activate()\n\
24238 	Mod1 <Key>[:	    backward-paragraph()\n\
24239 	Mod1 <Key>]:	    forward-paragraph()\n\
24240 	Mod1 <Key><:	    beginning-of-file()\n\
24241 	Mod1 <Key>>:	    end-of-file()\n\
24242 	<Key>Delete:	    delete-previous-character()\n\
24243 	Mod1 <Key>Delete:   delete-to-start-of-line()\n\
24244 	Ctrl <Key>osfLeft:  page-left()\n\
24245 	Ctrl <Key>osfRight: page-right()\n\
24246 	Ctrl <Key>osfDown:  next-page()\n\
24247 	Ctrl <Key>osfUp:    previous-page()\n\
24248 	Ctrl <Key>space:    set-anchor()\n\
24249 	<Btn1Down>:	    b1-press()\n\
24250 	<Btn1Up>:	    b1-release()\n\
24251 	<Btn1Motion>:	    b1-move()\n\
24252 	<Key>Return:	    newline()\n";
24253 static XtTranslations transTable3 = NULL;
24254 
24255 
24256 /* for lisp listener */
24257 static char TextTrans4[] =
24258        "Ctrl <Key>a:	    begin-of-line()\n\
24259 	Ctrl <Key>b:	    backward-character()\n\
24260 	Mod1 <Key>b:	    backward-word()\n\
24261 	Mod1 <Key>c:	    word-upper(c)\n\
24262 	Ctrl <Key>d:	    delete-next-character()\n\
24263 	Mod1 <Key>d:	    delete-next-word()\n\
24264 	Ctrl <Key>e:	    end-of-line()\n\
24265 	Ctrl <Key>f:	    forward-character()\n\
24266 	Mod1 <Key>f:	    forward-word()\n\
24267 	Ctrl Meta <Key>g:   listener-clear()\n\
24268 	Ctrl <Key>g:	    listener-g()\n\
24269 	Ctrl <Key>h:	    delete-previous-character()\n\
24270 	Ctrl <Key>j:	    newline-and-indent()\n\
24271 	Ctrl <Key>k:	    kill-line()\n\
24272 	Ctrl <Key>l:	    redraw-display()\n\
24273 	Mod1 <Key>l:	    word-upper(l)\n\
24274 	Ctrl <Key>n:	    next-line()\n\
24275         Mod1 <Key>n:        listener-meta-n()\n\
24276 	Ctrl <Key>o:	    newline-and-backup()\n\
24277 	Ctrl <Key>p:	    previous-line()\n\
24278         Mod1 <Key>p:        listener-meta-p()\n\
24279 	Ctrl <Key>t:	    text-transpose()\n\
24280 	Ctrl <Key>u:	    activate-keyboard(u)\n\
24281 	Mod1 <Key>u:	    word-upper(u)\n\
24282 	Ctrl <Key>v:	    next-page()\n\
24283 	Mod1 <Key>v:	    previous-page()\n\
24284 	Ctrl <Key>w:	    delete-region()\n\
24285 	Ctrl <Key>x:	    activate-keyboard(x)\n\
24286 	Ctrl <Key>y:	    yank()\n\
24287 	Ctrl <Key>z:	    activate()\n\
24288         Ctrl <Key>?:        help-at-cursor()\n\
24289         Mod1 <Key>.:        help-at-cursor()\n\
24290 	Mod1 <Key>[:	    backward-paragraph()\n\
24291 	Mod1 <Key>]:	    forward-paragraph()\n\
24292 	Mod1 <Key><:	    beginning-of-file()\n\
24293 	Mod1 <Key>>:	    end-of-file()\n\
24294         Shift Ctrl <Key>-:  delete-to-previous-command()\n\
24295 	<Key>Delete:	    delete-previous-character()\n\
24296 	Mod1 <Key>Delete:   delete-to-start-of-line()\n\
24297 	Ctrl <Key>osfLeft:  page-left()\n\
24298 	Ctrl <Key>osfRight: page-right()\n\
24299 	Ctrl <Key>osfDown:  next-page()\n\
24300 	Ctrl <Key>osfUp:    previous-page()\n\
24301 	<Key>osfDown:       listener-next-line()\n\
24302 	<Key>osfUp:         listener-previous-line()\n\
24303 	Ctrl <Key>space:    set-anchor()\n\
24304 	<Btn1Down>:	    b1-press()\n\
24305 	<Btn1Up>:	    b1-release()\n\
24306 	<Btn1Motion>:	    b1-move()\n\
24307 	<Key>Tab:	    listener-completion()\n\
24308 	<Key>Return:	    listener-return()\n";
24309 static XtTranslations transTable4 = NULL;
24310 
24311 
add_completer_to_builtin_textfield(Widget w,int completer)24312 void add_completer_to_builtin_textfield(Widget w, int completer)
24313 {
24314   /* used to make file selection dialog's file and filter text widgets act like other text field widgets */
24315   if (!actions_loaded)
24316     {
24317       XtAppAddActions(main_app(ss), acts, NUM_ACTS);
24318       actions_loaded = true;
24319     }
24320   if (!transTable2)
24321     transTable2 = XtParseTranslationTable(TextTrans2);
24322 
24323   XtOverrideTranslations(w, transTable2);
24324   XtVaSetValues(w, XmNuserData, completer, NULL);
24325 }
24326 
24327 
24328 
24329 /* -------- text related widgets -------- */
24330 
24331 static Xen mouse_enter_text_hook;
24332 static Xen mouse_leave_text_hook;
24333 
mouse_enter_text_callback(Widget w,XtPointer context,XEvent * event,Boolean * flag)24334 void mouse_enter_text_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag)
24335 {
24336   if (with_pointer_focus(ss))
24337     goto_window(w);
24338 
24339   if (Xen_hook_has_list(mouse_enter_text_hook))
24340     run_hook(mouse_enter_text_hook,
24341 	     Xen_list_1(Xen_wrap_widget(w)),
24342 	     S_mouse_enter_text_hook);
24343 }
24344 
24345 
mouse_leave_text_callback(Widget w,XtPointer context,XEvent * event,Boolean * flag)24346 void mouse_leave_text_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag)
24347 {
24348   if (Xen_hook_has_list(mouse_leave_text_hook))
24349     run_hook(mouse_leave_text_hook,
24350 	     Xen_list_1(Xen_wrap_widget(w)),
24351 	     S_mouse_leave_text_hook);
24352 }
24353 
24354 
make_textfield_widget(const char * name,Widget parent,Arg * args,int n,text_cr_t activatable,int completer)24355 Widget make_textfield_widget(const char *name, Widget parent, Arg *args, int n, text_cr_t activatable, int completer)
24356 {
24357   /* white background when active, emacs translations */
24358   Widget df;
24359 
24360   if (!actions_loaded)
24361     {
24362       XtAppAddActions(main_app(ss), acts, NUM_ACTS);
24363       actions_loaded = true;
24364     }
24365 
24366   XtSetArg(args[n], XmNuserData, completer); n++;
24367   XtSetArg(args[n], XmNhighlightThickness, 1); n++;
24368   XtSetArg(args[n], XmNcursorPositionVisible, false); n++;
24369   df = XtCreateManagedWidget(name, xmTextFieldWidgetClass, parent, args, n);
24370 
24371   if (activatable != ACTIVATABLE_BUT_NOT_FOCUSED)
24372     {
24373       XtAddCallback(df, XmNfocusCallback, textfield_focus_callback, NULL);
24374       XtAddCallback(df, XmNlosingFocusCallback, textfield_unfocus_callback, NULL);
24375     }
24376   else
24377     {
24378       XtAddCallback(df, XmNfocusCallback, textfield_no_color_focus_callback, NULL);
24379       XtAddCallback(df, XmNlosingFocusCallback, textfield_no_color_unfocus_callback, NULL);
24380     }
24381 
24382   XtAddEventHandler(df, EnterWindowMask, false, mouse_enter_text_callback, NULL);
24383   XtAddEventHandler(df, LeaveWindowMask, false, mouse_leave_text_callback, NULL);
24384 
24385   if ((activatable == ACTIVATABLE) ||
24386       (activatable == ACTIVATABLE_BUT_NOT_FOCUSED))
24387     {
24388       if (!transTable2)
24389 	transTable2 = XtParseTranslationTable(TextTrans2);
24390       XtOverrideTranslations(df, transTable2);
24391     }
24392   else
24393     {
24394       if (!transTable6)
24395 	transTable6 = XtParseTranslationTable(TextTrans6);
24396       XtOverrideTranslations(df, transTable6);
24397     }
24398 
24399   return(df);
24400 }
24401 
24402 
24403 
make_text_widget(const char * name,Widget parent,Arg * args,int n)24404 Widget make_text_widget(const char *name, Widget parent, Arg *args, int n)
24405 {
24406   /* white background when active, emacs translations */
24407   /* used only for comment widget in file data box (snd-xfile.c), but needs to be in this file to pick up actions etc */
24408   Widget df;
24409   if (!actions_loaded)
24410     {
24411       XtAppAddActions(main_app(ss), acts, NUM_ACTS);
24412       actions_loaded = true;
24413     }
24414   XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
24415   /* XmNblinkRate 0 turns off the cursor blink */
24416   XtSetArg(args[n], XmNcursorPositionVisible, false); n++;
24417   XtSetArg(args[n], XmNhighlightThickness, 1); n++;
24418   df = XmCreateScrolledText(parent, (char *)name, args, n);
24419   XtManageChild(df);
24420   XtAddCallback(df, XmNfocusCallback, textfield_focus_callback, NULL);
24421   XtAddCallback(df, XmNlosingFocusCallback, textfield_unfocus_callback, NULL);
24422   XtAddEventHandler(df, EnterWindowMask, false, mouse_enter_text_callback, NULL);
24423   XtAddEventHandler(df, LeaveWindowMask, false, mouse_leave_text_callback, NULL);
24424   if (!transTable3)
24425     transTable3 = XtParseTranslationTable(TextTrans3);
24426   XtOverrideTranslations(df, transTable3);
24427   return(df);
24428 }
24429 
24430 
24431 /* ---------------- listener widget ---------------- */
24432 
24433 static Widget lisp_window = NULL;
24434 
listener_append(const char * msg)24435 void listener_append(const char *msg)
24436 {
24437   if (listener_text)
24438     XmTextInsert(listener_text, XmTextGetLastPosition(listener_text), (char *)msg);
24439 }
24440 
24441 
listener_append_and_prompt(const char * msg)24442 void listener_append_and_prompt(const char *msg)
24443 {
24444   if (listener_text)
24445     {
24446       XmTextPosition cmd_eot;
24447       if (msg)
24448 	XmTextInsert(listener_text, XmTextGetLastPosition(listener_text), (char *)msg);
24449       cmd_eot = XmTextGetLastPosition(listener_text);
24450       XmTextInsert(listener_text, cmd_eot, listener_prompt_with_cr());
24451       cmd_eot = XmTextGetLastPosition(listener_text);
24452       XmTextShowPosition(listener_text, cmd_eot - 1);
24453     }
24454 }
24455 
24456 
listener_return_callback(Widget w,XtPointer context,XtPointer info)24457 static void listener_return_callback(Widget w, XtPointer context, XtPointer info)
24458 {
24459   listener_return(w, find_prompt(w, XmTextGetInsertionPosition(w)));
24460   /* prompt loc (last prompt pos) used only by read hook */
24461 }
24462 
24463 
24464 #if (!HAVE_FORTH) && (!HAVE_RUBY)
24465 
24466 static int flashes = 0;
24467 static int paren_pos = -1;
24468 #define FLASH_TIME 150
24469 
flash_unbalanced_paren(XtPointer context,XtIntervalId * id)24470 static void flash_unbalanced_paren(XtPointer context, XtIntervalId *id)
24471 {
24472   flashes--;
24473   XmTextSetHighlight(listener_text, paren_pos, paren_pos + 1, (flashes & 1) ? XmHIGHLIGHT_NORMAL : XmHIGHLIGHT_SELECTED);
24474   if (flashes > 0)
24475     XtAppAddTimeOut(main_app(ss),
24476 		    (unsigned long)FLASH_TIME,
24477 		    (XtTimerCallbackProc)flash_unbalanced_paren,
24478 		    NULL);
24479   else
24480     {
24481       XmTextSetHighlight(listener_text, paren_pos, paren_pos + 1, XmHIGHLIGHT_NORMAL);
24482       paren_pos = -1;
24483     }
24484 }
24485 
highlight_unbalanced_paren(void)24486 static bool highlight_unbalanced_paren(void)
24487 {
24488   /* if cursor is positioned at close paren, try to find reason for unbalanced expr and highlight it */
24489   int pos;
24490   bool success = true;
24491   pos = XmTextGetInsertionPosition(listener_text);
24492   if (pos > 2)
24493     {
24494       char *str;
24495       str = XmTextGetString(listener_text);
24496       if ((str[pos - 1] == ')') &&
24497 	  ((str[pos - 2] != '\\') || (str[pos - 3] != '#')))
24498 	{
24499 	  int parens;
24500 	  parens = find_matching_paren(str, 2, pos - 1, &paren_pos);
24501 	  if (parens == 0)
24502 	    {
24503 	      XmTextSetHighlight(listener_text, paren_pos, paren_pos + 1, XmHIGHLIGHT_SELECTED);
24504 	      flashes = 4;
24505 	      XtAppAddTimeOut(main_app(ss),
24506 			      (unsigned long)FLASH_TIME,
24507 			      (XtTimerCallbackProc)flash_unbalanced_paren,
24508 			      NULL);
24509 	    }
24510 	  else success = false;
24511 	}
24512       if (str) XtFree(str);
24513     }
24514   return(success);
24515 }
24516 #endif
24517 
24518 
24519 static int last_highlight_position = -1;
24520 
listener_motion_callback(Widget w,XtPointer context,XtPointer info)24521 static void listener_motion_callback(Widget w, XtPointer context, XtPointer info)
24522 {
24523   XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info;
24524   int pos;
24525 
24526   cbs->doit = true;
24527   if (dont_check_motion) return;
24528   if (last_highlight_position != -1)
24529     {
24530       XmTextSetHighlight(w, last_highlight_position, last_highlight_position + 1, XmHIGHLIGHT_NORMAL);
24531       last_highlight_position = -1;
24532     }
24533 
24534   pos = cbs->newInsert - 1;
24535   if (pos > 0)
24536     {
24537       char *str = NULL;
24538       str = XmTextGetString(w);
24539       if ((str[pos] == ')') &&
24540 	  ((pos <= 1) || (str[pos - 1] != '\\') || (str[pos - 2] != '#')))
24541 	{
24542 	  int parens;
24543 	  parens = find_matching_paren(str, 1, pos, &last_highlight_position);
24544 	  if (parens == 0)
24545 	    XmTextSetHighlight(w, last_highlight_position, last_highlight_position + 1, XmHIGHLIGHT_SECONDARY_SELECTED);
24546 	}
24547       if (str) XtFree(str);
24548     }
24549 }
24550 
24551 
listener_modify_callback(Widget w,XtPointer context,XtPointer info)24552 static void listener_modify_callback(Widget w, XtPointer context, XtPointer info)
24553 {
24554   XmTextVerifyCallbackStruct *cbs = (XmTextVerifyCallbackStruct *)info;
24555 
24556   /* pure motion stuff (arrow keys) does not trigger this callback */
24557 
24558   if ((completions_pane) &&
24559       (XtIsManaged(completions_pane)))
24560     XtUnmanageChild(completions_pane);
24561 
24562   if (((cbs->text)->length > 0) || (dont_check_motion))
24563     cbs->doit = true;
24564   else
24565     {
24566       char *str = NULL;
24567       int len;
24568       str = XmTextGetString(w);
24569       len = XmTextGetLastPosition(w);
24570       if (within_prompt(str, cbs->startPos, len))
24571 	cbs->doit = false;
24572       else cbs->doit = true;
24573       if (str) XtFree(str);
24574     }
24575 }
24576 
24577 
24578 static Xen mouse_enter_listener_hook;
24579 static Xen mouse_leave_listener_hook;
24580 
listener_focus_callback(Widget w,XtPointer context,XEvent * event,Boolean * flag)24581 static void listener_focus_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag)
24582 {
24583   if (with_pointer_focus(ss))
24584     goto_window(listener_text);
24585 
24586   if (Xen_hook_has_list(mouse_enter_listener_hook))
24587     run_hook(mouse_enter_listener_hook,
24588 	     Xen_list_1(Xen_wrap_widget(listener_text)), /* not w */
24589 	     S_mouse_enter_listener_hook);
24590 }
24591 
24592 
listener_unfocus_callback(Widget w,XtPointer context,XEvent * event,Boolean * flag)24593 static void listener_unfocus_callback(Widget w, XtPointer context, XEvent *event, Boolean *flag)
24594 {
24595   if (Xen_hook_has_list(mouse_leave_listener_hook))
24596     run_hook(mouse_leave_listener_hook,
24597 	     Xen_list_1(Xen_wrap_widget(listener_text)), /* not w */
24598 	     S_mouse_leave_listener_hook);
24599 }
24600 
24601 
24602 /* ---------------- popup callbacks ---------------- */
24603 
24604 static Widget listener_popup = NULL;
24605 
listener_help_callback(Widget w,XtPointer context,XtPointer info)24606 static void listener_help_callback(Widget w, XtPointer context, XtPointer info)
24607 {
24608   char *txt;
24609   txt = XmTextGetSelection(listener_text);
24610   if (txt)
24611     {
24612       char *trim_txt;
24613       trim_txt = trim(txt);
24614       if (trim_txt)
24615 	{
24616 	  snd_help(trim_txt, Xen_string_to_C_string(g_snd_help(C_string_to_Xen_string(trim_txt), 0)), WITH_WORD_WRAP);
24617 	  free(trim_txt);
24618 	}
24619       XtFree(txt);
24620     }
24621   else text_at_cursor(listener_text);
24622 }
24623 
listener_save_callback(Widget w,XtPointer context,XtPointer info)24624 static void listener_save_callback(Widget w, XtPointer context, XtPointer info)
24625 {
24626   FILE *fp = NULL;
24627   fp = FOPEN("listener.txt", "w");
24628   if (fp)
24629     {
24630       save_listener_text(fp);
24631       snd_fclose(fp, "listener.txt");
24632     }
24633 }
24634 
24635 
listener_clear_callback(Widget w,XtPointer context,XtPointer info)24636 static void listener_clear_callback(Widget w, XtPointer context, XtPointer info)
24637 {
24638   clear_listener();
24639 }
24640 
24641 
24642 #if HAVE_SCHEME
listener_stacktrace_callback(Widget w,XtPointer context,XtPointer info)24643 static void listener_stacktrace_callback(Widget w, XtPointer context, XtPointer info)
24644 {
24645   s7_pointer str;
24646   str = s7_eval_c_string(s7, "(stacktrace)");
24647   if (s7_string_length(str) == 0)
24648     str = s7_eval_c_string(s7, "(object->string (owlet))");
24649   snd_display_result(s7_string(str), NULL);
24650 }
24651 #endif
24652 
24653 
listener_stop_callback(Widget w,XtPointer context,XtPointer info)24654 static void listener_stop_callback(Widget w, XtPointer context, XtPointer info)
24655 {
24656   control_g(any_selected_sound());
24657 }
24658 
24659 
24660 #if HAVE_SCHEME
24661 static Widget stacktrace_popup_menu = NULL;
24662 #endif
24663 
listener_popup_callback(Widget w,XtPointer context,XtPointer info)24664 static void listener_popup_callback(Widget w, XtPointer context, XtPointer info)
24665 {
24666   XmPopupHandlerCallbackStruct *cb = (XmPopupHandlerCallbackStruct *)info;
24667   XEvent *e;
24668   e = cb->event;
24669   if (e->type == ButtonPress)
24670     {
24671 #if HAVE_SCHEME
24672       if (stacktrace_popup_menu)
24673 	set_menu_label(stacktrace_popup_menu, (s7_is_null(s7, s7_curlet(s7))) ? "Error info" : "Stacktrace");
24674 #endif
24675       cb->menuToPost = listener_popup;
24676     }
24677 }
24678 
24679 
make_listener_widget(int height)24680 static void make_listener_widget(int height)
24681 {
24682   if (!listener_text)
24683     {
24684       Arg args[32];
24685       Widget wv, wh, w;
24686       int n;
24687 
24688       if (!actions_loaded) {XtAppAddActions(main_app(ss), acts, NUM_ACTS); actions_loaded = true;}
24689 
24690       n = attach_all_sides(args, 0);
24691       XtSetArg(args[n], XmNheight, height); n++;
24692       XtSetArg(args[n], XmNpaneMaximum, LOTSA_PIXELS); n++; /* Xm/Paned initializes each pane max to 1000 apparently! */
24693 
24694       if ((sound_style(ss) == SOUNDS_IN_NOTEBOOK) || (sound_style(ss) == SOUNDS_HORIZONTAL))
24695 	listener_pane = XtCreateManagedWidget("frm", xmFormWidgetClass, sound_pane_box(ss), args, n);
24696       else listener_pane = XtCreateManagedWidget("frm", xmFormWidgetClass, sound_pane(ss), args, n);
24697       /* this widget is not redundant at least in Metroworks Motif */
24698 
24699       n = 0;
24700       XtSetArg(args[n], XmNbackground, ss->listener_color); n++;
24701       XtSetArg(args[n], XmNforeground, ss->listener_text_color); n++;
24702       if (ss->listener_fontlist) {XtSetArg(args[n], XM_FONT_RESOURCE, ss->listener_fontlist); n++;}
24703       n = attach_all_sides(args, n);
24704       XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++;
24705       XtSetArg(args[n], XmNskipAdjust, true); n++;
24706       XtSetArg(args[n], XmNvalue, listener_prompt(ss)); n++;
24707       XtSetArg(args[n], XmNpendingDelete, false); n++; /* don't cut selection upon paste */
24708       XtSetArg(args[n], XmNpositionIndex, XmLAST_POSITION); n++;
24709       XtSetArg(args[n], XmNhighlightThickness, 1); n++;
24710       listener_text = XmCreateScrolledText(listener_pane, (char *)"lisp-listener", args, n);
24711       ss->listener_pane = listener_text;
24712 
24713       n = 0;
24714       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
24715       XtSetArg(args[n], XmNpopupEnabled, XmPOPUP_AUTOMATIC); n++;
24716       listener_popup = XmCreatePopupMenu(listener_text, (char *)"listener-popup", args, n);
24717 
24718       w = XtCreateManagedWidget(I_STOP, xmPushButtonWidgetClass, listener_popup, args, n);
24719       XtAddCallback(w, XmNactivateCallback, listener_stop_callback, NULL);
24720 
24721 #if HAVE_SCHEME
24722       w = XtCreateManagedWidget("Stacktrace", xmPushButtonWidgetClass, listener_popup, args, n);
24723       XtAddCallback(w, XmNactivateCallback, listener_stacktrace_callback, NULL);
24724       stacktrace_popup_menu = w;
24725 #endif
24726 
24727       w = XtCreateManagedWidget(I_HELP, xmPushButtonWidgetClass, listener_popup, args, n);
24728       XtAddCallback(w, XmNactivateCallback, listener_help_callback, NULL);
24729 
24730       w = XtCreateManagedWidget("Clear", xmPushButtonWidgetClass, listener_popup, args, n);
24731       XtAddCallback(w, XmNactivateCallback, listener_clear_callback, NULL);
24732 
24733       w = XtCreateManagedWidget("Save", xmPushButtonWidgetClass, listener_popup, args, n);
24734       XtAddCallback(w, XmNactivateCallback, listener_save_callback, NULL);
24735 
24736       XtVaSetValues(main_shell(ss), XmNallowShellResize, false, NULL);
24737 
24738       XtManageChild(listener_text);
24739       XmTextSetCursorPosition(listener_text, ss->listener_prompt_length);
24740       if (!transTable4)
24741 	transTable4 = XtParseTranslationTable(TextTrans4);
24742       XtOverrideTranslations(listener_text, transTable4);
24743       XtAddCallback(listener_text, XmNactivateCallback, listener_return_callback, NULL);
24744       XtAddCallback(listener_text, XmNmodifyVerifyCallback, listener_modify_callback, NULL);
24745       XtAddCallback(listener_text, XmNmotionVerifyCallback, listener_motion_callback, NULL);
24746 
24747       lisp_window = XtParent(listener_text);
24748       XtAddEventHandler(lisp_window, EnterWindowMask, false, listener_focus_callback, NULL);
24749       XtAddEventHandler(lisp_window, LeaveWindowMask, false, listener_unfocus_callback, NULL);
24750 
24751       XtAddCallback(listener_text, XmNpopupHandlerCallback, listener_popup_callback, NULL);
24752 
24753       XmChangeColor(lisp_window, ss->basic_color);
24754       XtVaGetValues(lisp_window, XmNverticalScrollBar, &wv,
24755 		                 XmNhorizontalScrollBar, &wh,
24756 		                 NULL);
24757       XmChangeColor(wv, ss->basic_color);
24758       XmChangeColor(wh, ss->basic_color);
24759       map_over_children(sound_pane(ss), color_sashes);
24760 
24761       if (auto_resize(ss))
24762 	XtVaSetValues(main_shell(ss), XmNallowShellResize, true, NULL);
24763     }
24764 }
24765 
24766 
goto_listener(void)24767 void goto_listener(void)
24768 {
24769   goto_window(listener_text);
24770   XmTextSetCursorPosition(listener_text, XmTextGetLastPosition(listener_text) + 1);
24771   XmTextSetInsertionPosition(listener_text, XmTextGetLastPosition(listener_text) + 1);
24772 }
24773 
24774 
color_listener(Pixel pix)24775 void color_listener(Pixel pix)
24776 {
24777   ss->listener_color = pix;
24778 #if HAVE_SCHEME
24779   s7_symbol_set_value(s7, ss->listener_color_symbol, Xen_wrap_pixel(pix));
24780 #endif
24781   if (listener_text)
24782     XmChangeColor(listener_text, pix);
24783 }
24784 
24785 
color_listener_text(Pixel pix)24786 void color_listener_text(Pixel pix)
24787 {
24788   ss->listener_text_color = pix;
24789 #if HAVE_SCHEME
24790   s7_symbol_set_value(s7, ss->listener_text_color_symbol, Xen_wrap_pixel(pix));
24791 #endif
24792   if (listener_text)
24793     XtVaSetValues(listener_text, XmNforeground, pix, NULL);
24794 }
24795 
24796 
handle_listener(bool open)24797 void handle_listener(bool open)
24798 {
24799   if (open)
24800     {
24801       if (!listener_text)
24802 	make_listener_widget(100);
24803       else
24804 	{
24805 	  XtManageChild(listener_pane);
24806 	  if (!(listener_is_visible()))
24807 	    {
24808 	      XtUnmanageChild(listener_pane);
24809 	      XtVaSetValues(listener_pane, XmNpaneMinimum, 100, XmNpaneMaximum, LOTSA_PIXELS, NULL);
24810 	      XtManageChild(listener_pane);
24811 	      XtVaSetValues(listener_pane, XmNpaneMinimum, 1, NULL);
24812 	    }
24813 	}
24814     }
24815   else XtUnmanageChild(listener_pane);
24816 }
24817 
24818 
listener_exists(void)24819 bool listener_exists(void)
24820 {
24821   return((bool)listener_text);
24822 }
24823 
24824 
listener_height(void)24825 int listener_height(void)
24826 {
24827   if ((listener_text) && (XtIsManaged(listener_pane)))
24828     return(widget_height(listener_text));
24829   else return(0);
24830 }
24831 
24832 
listener_width(void)24833 int listener_width(void)
24834 {
24835   if ((listener_text) && (XtIsManaged(listener_pane)))
24836     return(widget_width(listener_text));
24837   else return(0);
24838 }
24839 
24840 
24841 #if OVERRIDE_TOGGLE
24842 static char ToggleTrans2[] =
24843        "c<Btn1Down>:   ArmAndActivate()\n";
24844 static XtTranslations toggleTable2 = NULL;
24845 
override_toggle_translation(Widget w)24846 static void override_toggle_translation(Widget w)
24847 {
24848   if (!toggleTable2) toggleTable2 = XtParseTranslationTable(ToggleTrans2);
24849   XtOverrideTranslations(w, toggleTable2);
24850 }
24851 #endif
24852 
24853 
make_togglebutton_widget(const char * name,Widget parent,Arg * args,int n)24854 Widget make_togglebutton_widget(const char *name, Widget parent, Arg *args, int n)
24855 {
24856   Widget w;
24857   w = XtCreateManagedWidget(name, xmToggleButtonWidgetClass, parent, args, n);
24858 #if OVERRIDE_TOGGLE
24859   override_toggle_translation(w);
24860 #endif
24861   return(w);
24862 }
24863 
24864 
make_pushbutton_widget(const char * name,Widget parent,Arg * args,int n)24865 Widget make_pushbutton_widget(const char *name, Widget parent, Arg *args, int n)
24866 {
24867   Widget w;
24868   w = XtCreateManagedWidget(name, xmPushButtonWidgetClass, parent, args, n);
24869 #if OVERRIDE_TOGGLE
24870   override_toggle_translation(w); /* ??? activate here (rather than armandactivate) fails? */
24871 #endif
24872   return(w);
24873 }
24874 
24875 
g_listener_selection(void)24876 static Xen g_listener_selection(void)
24877 {
24878   #define H_listener_selection "(" S_listener_selection "): currently selected text in listener or " PROC_FALSE
24879   Xen res = Xen_false;
24880   if (listener_text)
24881     {
24882       char *txt;
24883       txt = XmTextGetSelection(listener_text);
24884       if (txt)
24885 	{
24886 	  res = C_string_to_Xen_string(txt);
24887 	  XtFree(txt);
24888 	}
24889     }
24890   return(res);
24891 }
24892 
24893 
g_reset_listener_cursor(void)24894 static Xen g_reset_listener_cursor(void)
24895 {
24896   #define H_reset_listener_cursor "(" S_reset_listener_cursor "): reset listener cursor to the default pointer"
24897   if (listener_text)
24898     XUndefineCursor(XtDisplay(listener_text),
24899 		    XtWindow(listener_text));
24900   return(Xen_false);
24901 }
24902 
24903 
clear_listener(void)24904 void clear_listener(void)
24905 {
24906   if (listener_text)  /* this can be called even when there is no listener */
24907     {
24908       dont_check_motion = true;
24909       XmTextSetSelection(listener_text, 0, XmTextGetCursorPosition(listener_text), CurrentTime);
24910       XmTextRemove(listener_text);
24911       XmTextInsert(listener_text, 0, listener_prompt(ss));
24912       XmTextShowPosition(listener_text, ss->listener_prompt_length);
24913       dont_check_motion = false;
24914     }
24915 }
24916 
24917 
set_listener_text_font(void)24918 void set_listener_text_font(void)
24919 {
24920   if (listener_text)
24921     XtVaSetValues(listener_text, XM_FONT_RESOURCE, ss->listener_fontlist, NULL);
24922 }
24923 
24924 
g_goto_listener_end(void)24925 static Xen g_goto_listener_end(void)
24926 {
24927   #define H_goto_listener_end "(" S_goto_listener_end "): move cursor and scroll to bottom of listener pane"
24928   if (listener_text)
24929     {
24930       XmTextPosition eot;
24931       eot = XmTextGetLastPosition(listener_text);
24932       XmTextShowPosition(listener_text, eot);
24933       XmTextSetInsertionPosition(listener_text, eot);
24934       return(C_int_to_Xen_integer(eot));
24935     }
24936   return(Xen_false);
24937 }
24938 
24939 
24940 
24941 #include <X11/XKBlib.h>
24942 
24943 enum {W_top, W_form, W_main_window, W_edhist, W_wf_buttons, W_f, W_w, W_left_scrollers, W_zy, W_sy,
24944       W_bottom_scrollers, W_sx, W_zx, W_graph, W_gzy, W_gsy,
24945       CP_NUM_WIDGETS
24946 };
24947 
24948 
24949 #if ((XmVERSION >= 2) && (XmREVISION >= 3))
24950   #define DEFAULT_EDIT_HISTORY_WIDTH 2
24951 #else
24952   #define DEFAULT_EDIT_HISTORY_WIDTH 1
24953 #endif
24954 
24955 
channel_main_pane(chan_info * cp)24956 Widget channel_main_pane(chan_info *cp)
24957 {
24958   if (cp) return(cp->widgets[W_form]);
24959   return(NULL);
24960 }
24961 
24962 
channel_graph(chan_info * cp)24963 Widget channel_graph(chan_info *cp)      {return(cp->widgets[W_graph]);}
channel_sx(chan_info * cp)24964 static Widget channel_sx(chan_info *cp)  {return(cp->widgets[W_sx]);}
channel_sy(chan_info * cp)24965 static Widget channel_sy(chan_info *cp)  {return(cp->widgets[W_sy]);}
channel_zx(chan_info * cp)24966 static Widget channel_zx(chan_info *cp)  {return(cp->widgets[W_zx]);}
channel_zy(chan_info * cp)24967 static Widget channel_zy(chan_info *cp)  {return(cp->widgets[W_zy]);}
channel_gsy(chan_info * cp)24968 static Widget channel_gsy(chan_info *cp) {return(cp->widgets[W_gsy]);}
channel_gzy(chan_info * cp)24969 static Widget channel_gzy(chan_info *cp) {return(cp->widgets[W_gzy]);}
channel_w(chan_info * cp)24970 Widget channel_w(chan_info *cp)          {return(cp->widgets[W_w]);}
channel_f(chan_info * cp)24971 Widget channel_f(chan_info *cp)          {return(cp->widgets[W_f]);}
24972 
24973 
channel_graph_is_visible(chan_info * cp)24974 bool channel_graph_is_visible(chan_info *cp)
24975 {
24976   return((cp) &&
24977 	 (cp->widgets) &&
24978 	 (channel_graph(cp)) &&
24979 	 (XtIsManaged(channel_graph(cp))) &&
24980 	 (cp->sound) &&
24981 	 /* here we may have a sound wrapper for variable display in which case the sound widgets are not implemented */
24982 	 (((cp->sound->inuse == SOUND_WRAPPER) || (cp->sound->inuse == SOUND_REGION)) ||
24983 	  ((cp->sound->inuse == SOUND_NORMAL) &&
24984 	   /* other choice: SOUND_IDLE -> no display */
24985 	   (w_snd_pane(cp->sound)) &&
24986 	   (XtIsManaged(w_snd_pane(cp->sound))))));
24987 }
24988 
24989 
24990 #define EDIT_HISTORY_LIST(Cp) (Cp)->widgets[W_edhist]
24991 
24992 
sqr(mus_float_t a)24993 static mus_float_t sqr(mus_float_t a) {return(a * a);}
24994 
cube(mus_float_t a)24995 static mus_float_t cube(mus_float_t a) {return(a * a * a);}
24996 
24997 
get_scrollbar(Widget w,int val,int scrollbar_max)24998 static mus_float_t get_scrollbar(Widget w, int val, int scrollbar_max)
24999 {
25000   int size;
25001   if (val == 0) return(0.0);
25002   XtVaGetValues(w, XmNsliderSize, &size, NULL);
25003   return((mus_float_t)val / (mus_float_t)(scrollbar_max - size));
25004 }
25005 
25006 
sy_changed(int value,chan_info * cp)25007 static void sy_changed(int value, chan_info *cp)
25008 {
25009   axis_info *ap;
25010   mus_float_t low;
25011   ap = cp->axis;
25012   low = get_scrollbar(channel_sy(cp), value, SCROLLBAR_MAX);
25013   ap->sy = (1.0 - ap->zy) * low;
25014   apply_y_axis_change(cp);
25015 }
25016 
25017 
sx_changed(int value,chan_info * cp)25018 static void sx_changed(int value, chan_info *cp)
25019 {
25020   /* treat as centered with non-slider trough as defining current bounds */
25021   axis_info *ap;
25022   double low;
25023   ap = cp->axis;
25024   low = get_scrollbar(channel_sx(cp), value, SCROLLBAR_MAX);
25025   ap->sx = low * (1.0 - ap->zx);
25026   apply_x_axis_change(cp);
25027 }
25028 
25029 
zy_changed(int value,chan_info * cp)25030 static void zy_changed(int value, chan_info *cp)
25031 {
25032   axis_info *ap;
25033   mus_float_t old_zy;
25034   ap = cp->axis;
25035   if (value < 1) value = 1;
25036   old_zy = ap->zy;
25037   ap->zy = sqr(get_scrollbar(channel_zy(cp), value, SCROLLBAR_MAX));
25038   if (ap->zy < 1e-5) ap->zy = 1e-5;   /* if this goes to 0, X can hang */
25039   ap->sy += (.5 * (old_zy - ap->zy)); /* try to keep wave centered */
25040   if (ap->sy < 0) ap->sy = 0;
25041   apply_y_axis_change(cp);
25042   resize_sy(cp);
25043 }
25044 
25045 
25046 #define X_RANGE_CHANGEOVER 20.0
25047 
zx_changed(int value,chan_info * cp)25048 static void zx_changed(int value, chan_info *cp)
25049 { /* scrollbar change */
25050   axis_info *ap;
25051   static int old_zx_value = -1;
25052   #define ZX_MIN 20
25053 
25054   if (value < ZX_MIN) value = ZX_MIN; /* less than this causes underflow in snd-axis describe_ticks */
25055                                       /* snd-gchn uses .01 -- its equivalent here would be 100 */
25056                                       /* perhaps the definition should be ((int)(0.002 * MAX_SCROLLBAR)) */
25057   if (old_zx_value == value) return;  /* try to keep click on slider from moving the window! */
25058   old_zx_value = value;
25059 
25060   ap = cp->axis;
25061   if (ap->xmax == 0.0) return;
25062   if (ap->xmax <= ap->xmin)
25063     {
25064       ap->xmax = ap->xmin + .001;
25065       ap->x_ambit = .001;
25066     }
25067   if (ap->x_ambit < X_RANGE_CHANGEOVER)
25068     ap->zx = sqr(get_scrollbar(channel_zx(cp), value, SCROLLBAR_MAX));
25069   else ap->zx = cube(get_scrollbar(channel_zx(cp), value, SCROLLBAR_MAX));
25070   /* if cursor visible, focus on that, else selection, else mark, else left side */
25071   focus_x_axis_change(cp, zoom_focus_style(ss));
25072   resize_sx(cp);
25073 }
25074 
25075 
set_scrollbar(Widget w,mus_float_t position,mus_float_t range,int scrollbar_max)25076 static void set_scrollbar(Widget w, mus_float_t position, mus_float_t range, int scrollbar_max) /* position and range 0 to 1.0 */
25077 {
25078   int size, val;
25079   size = (int)(scrollbar_max * range);
25080   if (size > scrollbar_max)
25081     size = scrollbar_max; /* this can't happen!?! */
25082   if (size < 1) size = 1;
25083   val = (int)(scrollbar_max * position);
25084   if ((val + size) > scrollbar_max) val = scrollbar_max - size;
25085   if (val < 0) val = 0;
25086   XtVaSetValues(w,
25087 		XmNsliderSize, size,
25088 		XmNvalue, val,
25089 		NULL);
25090 }
25091 
25092 
change_gzy_1(mus_float_t val,chan_info * cp)25093 static void change_gzy_1(mus_float_t val, chan_info *cp)
25094 {
25095   mus_float_t chan_frac, new_gsy, new_size;
25096   cp->gzy = val;
25097   chan_frac = 1.0 / ((mus_float_t)(((snd_info *)(cp->sound))->nchans));
25098   new_size = chan_frac + ((1.0 - chan_frac) * cp->gzy);
25099   if ((cp->gsy + new_size) > 1.0)
25100     new_gsy = 1.0 - new_size;
25101   else new_gsy = cp->gsy;
25102   if (new_gsy < 0.0) new_gsy = 0.0;
25103   set_scrollbar(channel_gsy(cp), new_gsy, new_size, SCROLLBAR_MAX);
25104 }
25105 
25106 
gzy_changed(int value,chan_info * cp)25107 static void gzy_changed(int value, chan_info *cp)
25108 {
25109   change_gzy_1(get_scrollbar(channel_gzy(cp), value, SCROLLBAR_MAX), cp);
25110   for_each_sound_chan(cp->sound, update_graph_or_warn);
25111 }
25112 
25113 
change_gzy(mus_float_t val,chan_info * cp)25114 void change_gzy(mus_float_t val, chan_info *cp)
25115 {
25116   change_gzy_1(val, cp);
25117   set_scrollbar(channel_gzy(cp), val, 1.0 / (mus_float_t)(cp->sound->nchans), SCROLLBAR_MAX);
25118 }
25119 
25120 
gsy_changed(int value,chan_info * cp)25121 static void gsy_changed(int value, chan_info *cp)
25122 {
25123   mus_float_t low;
25124   low = get_scrollbar(channel_gsy(cp), value, SCROLLBAR_MAX);
25125   cp->gsy = (1.0 - cp->gzy) * low;
25126   for_each_sound_chan(cp->sound, update_graph_or_warn);
25127 }
25128 
25129 
gsy_value(chan_info * cp)25130 mus_float_t gsy_value(chan_info *cp)
25131 {
25132   Widget wcp;
25133   int ival;
25134   wcp = channel_gsy(cp);
25135   XtVaGetValues(wcp, XmNvalue, &ival, NULL);
25136   return((mus_float_t)ival / (mus_float_t)(SCROLLBAR_MAX));
25137 }
25138 
25139 
gsy_size(chan_info * cp)25140 mus_float_t gsy_size(chan_info *cp)
25141 {
25142   Widget wcp;
25143   int ival;
25144   wcp = channel_gsy(cp);
25145   XtVaGetValues(wcp, XmNsliderSize, &ival, NULL);
25146   return((mus_float_t)ival / (mus_float_t)(SCROLLBAR_MAX));
25147 }
25148 
25149 
set_zx_scrollbar(chan_info * cp,axis_info * ap)25150 static void set_zx_scrollbar(chan_info *cp, axis_info *ap)
25151 {
25152   if (ap->x_ambit < X_RANGE_CHANGEOVER)
25153     set_scrollbar(channel_zx(cp), sqrt(ap->zx), .1, SCROLLBAR_MAX);  /* assume size is 10% of scrollbar length */
25154   else set_scrollbar(channel_zx(cp), pow(ap->zx, .333), .1, SCROLLBAR_MAX);
25155 }
25156 
25157 
set_z_scrollbars(chan_info * cp,axis_info * ap)25158 void set_z_scrollbars(chan_info *cp, axis_info *ap)
25159 {
25160   set_zx_scrollbar(cp, ap);
25161   set_scrollbar(channel_zy(cp), sqrt(ap->zy), .1, SCROLLBAR_MAX);
25162 }
25163 
25164 
initialize_scrollbars(chan_info * cp)25165 void initialize_scrollbars(chan_info *cp)
25166 {
25167   axis_info *ap;
25168   snd_info *sp;
25169 
25170   cp->gzy = 1.0;
25171   cp->gsy = 1.0;
25172 
25173   ap = cp->axis;
25174   sp = cp->sound;
25175 
25176   set_scrollbar(channel_sx(cp), ap->sx, ap->zx, SCROLLBAR_MAX);
25177   set_scrollbar(channel_sy(cp), ap->sy, ap->zy, SCROLLBAR_MAX);
25178   set_z_scrollbars(cp, ap);
25179 
25180   if ((sp->nchans > 1) &&
25181       (cp->chan == 0) &&
25182       (channel_gsy(cp)))
25183     {
25184       set_scrollbar(channel_gsy(cp), 1.0, 1.0, SCROLLBAR_MAX);
25185       set_scrollbar(channel_gzy(cp), 1.0, 1.0 / (mus_float_t)(sp->nchans), SCROLLBAR_MAX);
25186     }
25187 }
25188 
25189 
resize_sy(chan_info * cp)25190 void resize_sy(chan_info *cp)
25191 {
25192   /* something changed the y axis view, so the scale scroller needs to reflect that change (in size and position) */
25193   axis_info *ap;
25194   ap = cp->axis;
25195   if (ap->y_ambit != 0.0)
25196     set_scrollbar(channel_sy(cp),
25197 		  (ap->y0 - ap->ymin) / ap->y_ambit,
25198 		  (ap->y1 - ap->y0) / ap->y_ambit,
25199 		  SCROLLBAR_MAX);
25200 }
25201 
25202 
resize_sy_and_zy(chan_info * cp)25203 void resize_sy_and_zy(chan_info *cp)
25204 {
25205   resize_sy(cp);
25206   set_scrollbar(channel_zy(cp), sqrt(cp->axis->zy), .1, SCROLLBAR_MAX);
25207 }
25208 
25209 
resize_sx(chan_info * cp)25210 void resize_sx(chan_info *cp)
25211 {
25212   axis_info *ap;
25213   ap = cp->axis;
25214   if (ap->x_ambit != 0.0)
25215     set_scrollbar(channel_sx(cp),
25216 		  (ap->x0 - ap->xmin) / ap->x_ambit,
25217 		  (ap->x1 - ap->x0) / ap->x_ambit,
25218 		  SCROLLBAR_MAX);
25219 }
25220 
25221 
resize_sx_and_zx(chan_info * cp)25222 void resize_sx_and_zx(chan_info *cp)
25223 {
25224   resize_sx(cp);
25225   /* change zx position (not its size) */
25226   set_zx_scrollbar(cp, cp->axis);
25227 }
25228 
25229 
channel_open_pane(chan_info * cp)25230 void channel_open_pane(chan_info *cp)
25231 {
25232   XtManageChild(channel_main_pane(cp));
25233 }
25234 
25235 
channel_unlock_pane(chan_info * cp)25236 void channel_unlock_pane(chan_info *cp)
25237 {
25238   XtVaSetValues(channel_main_pane(cp),
25239 		XmNpaneMinimum, 5,
25240 		XmNpaneMaximum, LOTSA_PIXELS,
25241 		NULL);
25242 }
25243 
25244 
channel_lock_pane(chan_info * cp,int val)25245 static void channel_lock_pane(chan_info *cp, int val)
25246 {
25247   if (val < 6) val = 6;
25248   XtUnmanageChild(channel_main_pane(cp));
25249   XtVaSetValues(channel_main_pane(cp),
25250 		XmNpaneMinimum, val - 5,
25251 		XmNpaneMaximum, val + 5,
25252 		NULL);
25253 }
25254 
25255 
sy_drag_callback(Widget w,XtPointer context,XtPointer info)25256 static void sy_drag_callback(Widget w, XtPointer context, XtPointer info)
25257 {
25258   chan_info *cp = (chan_info *)(context);
25259   if (cp->active == CHANNEL_HAS_AXES)
25260     sy_changed(((XmScrollBarCallbackStruct *)info)->value, cp);
25261 }
25262 
25263 
sy_valuechanged_callback(Widget w,XtPointer context,XtPointer info)25264 static void sy_valuechanged_callback(Widget w, XtPointer context, XtPointer info)
25265 {
25266   chan_info *cp = (chan_info *)(context);
25267   if (cp->active == CHANNEL_HAS_AXES)
25268     sy_changed(((XmScrollBarCallbackStruct *)info)->value, cp);
25269 }
25270 
25271 
sx_drag_callback(Widget w,XtPointer context,XtPointer info)25272 static void sx_drag_callback(Widget w, XtPointer context, XtPointer info)
25273 {
25274   chan_info *cp = (chan_info *)(context);
25275   if (cp->active == CHANNEL_HAS_AXES)
25276     sx_changed(((XmScrollBarCallbackStruct *)info)->value, cp);
25277 }
25278 
25279 
sx_valuechanged_callback(Widget w,XtPointer context,XtPointer info)25280 static void sx_valuechanged_callback(Widget w, XtPointer context, XtPointer info)
25281 {
25282   chan_info *cp = (chan_info *)(context);
25283   if (cp->active == CHANNEL_HAS_AXES)
25284     sx_changed(((XmScrollBarCallbackStruct *)info)->value, cp);
25285 }
25286 
25287 
sx_increment_callback(Widget w,XtPointer context,XtPointer info)25288 static void sx_increment_callback(Widget w, XtPointer context, XtPointer info)
25289 {
25290   /* problem here is that in large files these increments, if determined via scrollbar values, are huge */
25291   /* so, move ahead one-tenth window on each tick */
25292   chan_info *cp = (chan_info *)(context);
25293   if (cp->active == CHANNEL_HAS_AXES)
25294     sx_incremented(cp, 0.1);
25295 }
25296 
25297 
sx_decrement_callback(Widget w,XtPointer context,XtPointer info)25298 static void sx_decrement_callback(Widget w, XtPointer context, XtPointer info)
25299 {
25300   chan_info *cp = (chan_info *)(context);
25301   if (cp->active == CHANNEL_HAS_AXES)
25302     sx_incremented(cp, -0.1);
25303 }
25304 
25305 
zy_drag_callback(Widget w,XtPointer context,XtPointer info)25306 static void zy_drag_callback(Widget w, XtPointer context, XtPointer info)
25307 {
25308   chan_info *cp = (chan_info *)(context);
25309   if (cp->active == CHANNEL_HAS_AXES)
25310     zy_changed(((XmScrollBarCallbackStruct *)info)->value, cp);
25311 }
25312 
25313 
zy_valuechanged_callback(Widget w,XtPointer context,XtPointer info)25314 static void zy_valuechanged_callback(Widget w, XtPointer context, XtPointer info)
25315 {
25316   chan_info *cp = (chan_info *)(context);
25317   if (cp->active == CHANNEL_HAS_AXES)
25318     zy_changed(((XmScrollBarCallbackStruct *)info)->value, cp);
25319 }
25320 
25321 
zx_drag_callback(Widget w,XtPointer context,XtPointer info)25322 static void zx_drag_callback(Widget w, XtPointer context, XtPointer info)
25323 {
25324   chan_info *cp = (chan_info *)(context);
25325   if (cp->active == CHANNEL_HAS_AXES)
25326     zx_changed(((XmScrollBarCallbackStruct *)info)->value, cp);
25327 }
25328 
25329 
25330 /* can't use value changed callback in scrollbars because they are called upon mouse release
25331  *   even when nothing changed, and the value passed appears to be the right edge of the
25332  *   slider -- this is too unpredictable, and the result is the window moves when the user
25333  *   did not want it to.
25334  */
25335 
25336 
gzy_drag_callback(Widget w,XtPointer context,XtPointer info)25337 static void gzy_drag_callback(Widget w, XtPointer context, XtPointer info)
25338 {
25339   chan_info *cp = (chan_info *)(context);
25340   if (cp->active == CHANNEL_HAS_AXES)
25341     gzy_changed(((XmScrollBarCallbackStruct *)info)->value, cp);
25342 }
25343 
25344 
gsy_drag_callback(Widget w,XtPointer context,XtPointer info)25345 static void gsy_drag_callback(Widget w, XtPointer context, XtPointer info)
25346 {
25347   chan_info *cp = (chan_info *)(context);
25348   if (cp->active == CHANNEL_HAS_AXES)
25349     gsy_changed(((XmScrollBarCallbackStruct *)info)->value, cp);
25350 }
25351 
25352 
gsy_valuechanged_callback(Widget w,XtPointer context,XtPointer info)25353 static void gsy_valuechanged_callback(Widget w, XtPointer context, XtPointer info)
25354 {
25355   chan_info *cp = (chan_info *)(context);
25356   if (cp->active == CHANNEL_HAS_AXES)
25357     gsy_changed(((XmScrollBarCallbackStruct *)info)->value, cp);
25358 }
25359 
25360 /* anything special for increment?  XmNincrementCallback sx_increment_callback */
25361 
25362 
f_toggle_callback(Widget w,XtPointer context,XtPointer info)25363 static void f_toggle_callback(Widget w, XtPointer context, XtPointer info)
25364 {
25365   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
25366   XButtonEvent *ev;
25367   ev = (XButtonEvent *)(cb->event);
25368   f_button_callback((chan_info *)context, cb->set, (ev->state & ControlMask));
25369 }
25370 
25371 
w_toggle_callback(Widget w,XtPointer context,XtPointer info)25372 static void w_toggle_callback(Widget w, XtPointer context, XtPointer info)
25373 {
25374   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
25375   XButtonEvent *ev;
25376   ev = (XButtonEvent *)(cb->event);
25377   w_button_callback((chan_info *)context, cb->set, (ev->state & ControlMask));
25378 }
25379 
25380 
channel_expose_callback(Widget w,XtPointer context,XtPointer info)25381 static void channel_expose_callback(Widget w, XtPointer context, XtPointer info)
25382 {
25383   static oclock_t last_expose_event_time = 0;
25384   static chan_info *last_cp = NULL;
25385   chan_info *cp = (chan_info *)context;
25386   XmDrawingAreaCallbackStruct *cb = (XmDrawingAreaCallbackStruct *)info;
25387   XExposeEvent *ev;
25388   oclock_t curtime;
25389 
25390   if ((!cp) || (cp->active < CHANNEL_HAS_AXES) || (!cp->sound)) return;
25391 
25392   ev = (XExposeEvent *)(cb->event);
25393 
25394   /* if multiple channels/sounds displayed, each gets an expose event, but the earlier ones
25395    *   have count>0, and the last can get more than 1, causing our notion of last_cp to
25396    *   be useless, and we'll drop the earlier ones anyway, so if cp != last_cp, expose
25397    *   last_cp if last_count>0 or times equal (not sure which is safest).
25398    */
25399 
25400   curtime = XtLastTimestampProcessed(main_display(ss));
25401 
25402   if ((ev->count == 0) ||
25403       (last_expose_event_time != curtime) ||
25404       (cp != last_cp))
25405     {
25406       snd_info *sp;
25407       sp = cp->sound;
25408       if (sp->channel_style != CHANNELS_SEPARATE)
25409 	{
25410 	  if ((cp->chan == 0) && (ev->width > 10) && (ev->height > 10))
25411 	    for_each_sound_chan(sp, update_graph_or_warn);
25412 	}
25413       else update_graph_or_warn(cp);
25414     }
25415 
25416   last_cp = cp;
25417   last_expose_event_time = curtime;
25418 }
25419 
25420 
channel_resize_callback(Widget w,XtPointer context,XtPointer info)25421 static void channel_resize_callback(Widget w, XtPointer context, XtPointer info)
25422 {
25423   channel_resize((chan_info *)context);
25424 }
25425 
25426 
25427 static Xen mouse_enter_graph_hook;
25428 static Xen mouse_leave_graph_hook;
25429 
graph_mouse_enter(Widget w,XtPointer context,XEvent * event,Boolean * flag)25430 static void graph_mouse_enter(Widget w, XtPointer context, XEvent *event, Boolean *flag)
25431 {
25432   intptr_t data;
25433   XEnterWindowEvent *ev = (XEnterWindowEvent *)event;
25434 
25435   if (with_pointer_focus(ss))
25436     goto_window(w);
25437 
25438   XtVaGetValues(w, XmNuserData, &data, NULL);
25439 
25440   if (Xen_hook_has_list(mouse_enter_graph_hook))
25441     run_hook(mouse_enter_graph_hook,
25442 	     Xen_list_2(C_int_to_Xen_sound(unpack_sound(data)),
25443 			C_int_to_Xen_integer(unpack_channel(data))),
25444 	     S_mouse_enter_graph_hook);
25445 
25446   check_cursor_shape((chan_info *)context, ev->x, ev->y);
25447 }
25448 
25449 
graph_mouse_leave(Widget w,XtPointer context,XEvent * event,Boolean * flag)25450 static void graph_mouse_leave(Widget w, XtPointer context, XEvent *event, Boolean *flag)
25451 {
25452   intptr_t data;
25453   XLeaveWindowEvent *ev = (XLeaveWindowEvent *)event;
25454 
25455   XtVaGetValues(w, XmNuserData, &data, NULL);
25456   if (Xen_hook_has_list(mouse_leave_graph_hook))
25457     run_hook(mouse_leave_graph_hook,
25458 	     Xen_list_2(C_int_to_Xen_sound(unpack_sound(data)),
25459 			C_int_to_Xen_integer(unpack_channel(data))),
25460 	     S_mouse_leave_graph_hook);
25461 
25462   /*
25463   XUndefineCursor(XtDisplay(w), XtWindow(w));
25464   */
25465   check_cursor_shape((chan_info *)context, ev->x, ev->y);
25466 }
25467 
25468 
graph_button_press(Widget w,XtPointer context,XEvent * event,Boolean * cont)25469 static void graph_button_press(Widget w, XtPointer context, XEvent *event, Boolean *cont)
25470 {
25471   XButtonEvent *ev = (XButtonEvent *)event;
25472   graph_button_press_callback((chan_info *)context, (void *)ev, ev->x, ev->y, ev->state, ev->button, ev->time);
25473 }
25474 
25475 
graph_button_release(Widget w,XtPointer context,XEvent * event,Boolean * cont)25476 static void graph_button_release(Widget w, XtPointer context, XEvent *event, Boolean *cont) /* cont = "continue to dispatch" */
25477 {
25478   XButtonEvent *ev = (XButtonEvent *)event;
25479   graph_button_release_callback((chan_info *)context, ev->x, ev->y, ev->state, ev->button);
25480 }
25481 
25482 #if 0
25483 static void graph_button_motion(Widget w, XtPointer context, XEvent *event, Boolean *cont)
25484 { /* mouse drag */
25485   XMotionEvent *ev = (XMotionEvent *)event;
25486   graph_button_motion_callback((chan_info *)context, ev->x, ev->y, ev->time);
25487 }
25488 #endif
25489 
25490 
graph_mouse_motion(Widget w,XtPointer context,XEvent * event,Boolean * cont)25491 static void graph_mouse_motion(Widget w, XtPointer context, XEvent *event, Boolean *cont)
25492 { /* mouse movement */
25493   XMotionEvent *ev = (XMotionEvent *)event;
25494   if ((ev->state & Button1Mask) == 0)
25495     check_cursor_shape((chan_info *)context, ev->x, ev->y);
25496   else graph_button_motion_callback((chan_info *)context, ev->x, ev->y, ev->time);
25497 }
25498 
25499 
no_padding(Arg * args,int n)25500 static int no_padding(Arg *args, int n)
25501 {
25502   XtSetArg(args[n], XmNmarginHeight, 0); n++;
25503   XtSetArg(args[n], XmNmarginWidth, 0); n++;
25504   XtSetArg(args[n], XmNmarginTop, 0); n++;
25505   XtSetArg(args[n], XmNmarginBottom, 0); n++;
25506   XtSetArg(args[n], XmNmarginLeft, 0); n++;
25507   XtSetArg(args[n], XmNmarginRight, 0); n++;
25508   return(n);
25509 }
25510 
25511 
hide_gz_scrollbars(snd_info * sp)25512 static void hide_gz_scrollbars(snd_info *sp)
25513 {
25514   Widget w;
25515   w = channel_gsy(sp->chans[0]);
25516   if ((w) && (XtIsManaged(w))) XtUnmanageChild(w);
25517   w = channel_gzy(sp->chans[0]);
25518   if ((w) && (XtIsManaged(w))) XtUnmanageChild(w);
25519 }
25520 
25521 
show_gz_scrollbars(snd_info * sp)25522 static void show_gz_scrollbars(snd_info *sp)
25523 {
25524   Widget w;
25525   w = channel_gsy(sp->chans[0]);
25526   if ((w) && (!XtIsManaged(w))) XtManageChild(w);
25527   w = channel_gzy(sp->chans[0]);
25528   if ((w) && (!XtIsManaged(w))) XtManageChild(w);
25529 }
25530 
25531 
25532 /* edit history support */
25533 
history_select_callback(Widget w,XtPointer context,XtPointer info)25534 static void history_select_callback(Widget w, XtPointer context, XtPointer info)
25535 {
25536   /* undo/redo to reach selected position */
25537   XmListCallbackStruct *cbs = (XmListCallbackStruct *)info;
25538   edit_history_select((chan_info *)context, cbs->item_position - 1);
25539 }
25540 
25541 
25542 #if WITH_RELATIVE_PANES
25543 
25544 /* using undocumented callback here, as in snd-xsnd.c */
remake_edit_history(Widget lst,chan_info * cp,int from_graph)25545 static void remake_edit_history(Widget lst, chan_info *cp, int from_graph)
25546 {
25547   snd_info *sp;
25548   int i, eds;
25549   XmString *edits;
25550 
25551   if (cp->squelch_update) return;
25552   XmListDeleteAllItems(lst);
25553   sp = cp->sound;
25554 
25555   if (sp->channel_style != CHANNELS_SEPARATE)
25556     {
25557       chan_info *ncp;
25558       uint32_t k;
25559       int all_eds = 0, ed, filelen;
25560       char *title;
25561 
25562       for (k = 0; k < sp->nchans; k++)
25563 	{
25564 	  ncp = sp->chans[k];
25565 	  eds = ncp->edit_ctr;
25566 	  while ((eds < (ncp->edit_size - 1)) && (ncp->edits[eds + 1])) eds++;
25567 	  all_eds += eds;
25568 	}
25569       all_eds += 3 * sp->nchans;
25570       edits = (XmString *)calloc(all_eds, sizeof(XmString));
25571       filelen = 16 + strlen(sp->filename);
25572       title = (char *)calloc(filelen, sizeof(char));
25573       for (k = 0, ed = 0; k < sp->nchans; k++)
25574 	{
25575 	  ncp = sp->chans[k];
25576 	  ncp->edhist_base = ed;
25577 	  snprintf(title, filelen, "chan %d: %s", k + 1, sp->filename);
25578 	  edits[ed++] = XmStringCreateLocalized(title);
25579 	  eds = ncp->edit_ctr;
25580 	  while ((eds < (ncp->edit_size - 1)) && (ncp->edits[eds + 1])) eds++;
25581 	  for (i = 1; i <= eds; i++)
25582 	    {
25583 	      char *temp;
25584 	      temp = edit_to_string(ncp, i);
25585 	      edits[ed++] = XmStringCreateLocalized(temp);
25586 	      free(temp);
25587 	    }
25588 	  if (k < sp->nchans - 1)
25589 	    edits[ed++] = XmStringCreateLocalized((char *)"______________________________");
25590 	}
25591       free(title);
25592       XtVaSetValues(lst,
25593 		    XmNitems, edits,
25594 		    XmNitemCount, ed,
25595 		    NULL);
25596       for (i = 0; i < ed; i++)
25597 	XmStringFree(edits[i]);
25598       free(edits);
25599       XmListSelectPos(lst, cp->edhist_base + cp->edit_ctr + 1, false);
25600       if (from_graph) goto_graph(cp);
25601     }
25602   else
25603     {
25604       int items = 0;
25605       eds = cp->edit_ctr;
25606       while ((eds < (cp->edit_size - 1)) && (cp->edits[eds + 1])) eds++;
25607       edits = (XmString *)calloc(eds + 1, sizeof(XmString));
25608       edits[0] = XmStringCreateLocalized(sp->filename);
25609       for (i = 1; i <= eds; i++)
25610 	{
25611 	  char *temp;
25612 	  temp = edit_to_string(cp, i);
25613 	  edits[i] = XmStringCreateLocalized(temp);
25614 	  free(temp);
25615 	}
25616       XtVaSetValues(lst,
25617 		    XmNitems, edits,
25618 		    XmNitemCount, eds + 1,
25619 		    NULL);
25620       for (i = 0; i <= eds; i++)
25621 	XmStringFree(edits[i]);
25622       free(edits);
25623       XmListSelectPos(lst, cp->edit_ctr + 1, false);
25624       XtVaGetValues(lst, XmNvisibleItemCount, &items, NULL);
25625       if (items <= eds)
25626 	XtVaSetValues(lst, XmNtopItemPosition, eds - items + 2, NULL);
25627       if (from_graph) goto_graph(cp);
25628     }
25629 }
25630 
25631 
watch_edit_history_sash(Widget w,XtPointer closure,XtPointer info)25632 static void watch_edit_history_sash(Widget w, XtPointer closure, XtPointer info)
25633 {
25634   SashCallData call_data = (SashCallData)info;
25635   /* call_data->params[0]: Commit, Move, Key, Start (as strings) */
25636   if ((call_data->params) &&
25637       (mus_strcmp(call_data->params[0], "Start")))
25638     {
25639       chan_info *cp = (chan_info *)closure;
25640       Widget edhist;
25641       if ((cp) && (cp->widgets))
25642 	{
25643 	  edhist = EDIT_HISTORY_LIST(cp);
25644 	  if (edhist)
25645 	    remake_edit_history(edhist, cp, false);
25646 	}
25647     }
25648 }
25649 #endif
25650 
25651 
reflect_edit_history_change(chan_info * cp)25652 void reflect_edit_history_change(chan_info *cp)
25653 {
25654   /* new edit so it is added, and any trailing lines removed */
25655   snd_info *sp;
25656   Widget lst;
25657 
25658   if (cp->squelch_update) return;
25659   if (cp->in_as_one_edit > 0) return;
25660   sp = cp->sound;
25661   lst = EDIT_HISTORY_LIST(cp);
25662 #if WITH_RELATIVE_PANES
25663   if ((lst) && (widget_width(lst) > 1))
25664     remake_edit_history(lst, cp, true);
25665   else
25666     {
25667       if ((cp->chan > 0) && (sp->channel_style != CHANNELS_SEPARATE))
25668 	{
25669 	  lst = EDIT_HISTORY_LIST(sp->chans[0]);
25670 	  if ((lst) && (widget_width(lst) > 1))
25671 	    remake_edit_history(lst, sp->chans[0], true);
25672 	}
25673     }
25674 #else
25675   /* old form */
25676   if (lst)
25677     {
25678       int i, eds, items = 0;
25679       XmString *edits;
25680       eds = cp->edit_ctr;
25681       while ((eds < (cp->edit_size - 1)) && (cp->edits[eds + 1])) eds++;
25682       if (eds >= 0)
25683 	{
25684 	  if ((eds == cp->edit_ctr) && (eds > 1)) /* need to force 0 (1) case to start list with sound file name */
25685 	    {
25686 	      XmString edit;
25687 	      /* special common case -- we're appending a new edit description */
25688 	      XtVaGetValues(lst, XmNitemCount, &items, NULL);
25689 	      if (items > eds )
25690 		XmListDeleteItemsPos(lst, cp->edit_size, eds + 1);
25691 	      /* cp->edit_size is too large, but the manual says this is the way to delete to the end */
25692 	      {
25693 		char *temp;
25694 		temp = edit_to_string(cp, eds);
25695 		edit = XmStringCreateLocalized(temp);
25696 		free(temp);
25697 	      }
25698 	      XmListAddItemUnselected(lst, edit, eds + 1);
25699 	      XmStringFree(edit);
25700 	    }
25701 	  else
25702 	    {
25703 	      edits = (XmString *)calloc(eds + 1, sizeof(XmString));
25704 	      edits[0] = XmStringCreateLocalized(sp->filename);
25705 	      for (i = 1; i <= eds; i++)
25706 		{
25707 		  char *temp;
25708 		  temp = edit_to_string(cp, i);
25709 		  edits[i] = XmStringCreateLocalized(temp);
25710 		  free(temp);
25711 		}
25712 	      XtVaSetValues(lst,
25713 			    XmNitems, edits,
25714 			    XmNitemCount, eds + 1,
25715 			    NULL);
25716 	      for (i = 0; i <= eds; i++)
25717 		XmStringFree(edits[i]);
25718 	      free(edits);
25719 	    }
25720 	  XmListSelectPos(lst, cp->edit_ctr + 1, false);
25721 	  XtVaGetValues(lst, XmNvisibleItemCount, &items, NULL);
25722 	  if (items <= eds)
25723 	    XtVaSetValues(lst, XmNtopItemPosition, eds - items + 2, NULL);
25724 	  goto_graph(cp);
25725 	}
25726     }
25727 #endif
25728 }
25729 
25730 
reflect_edit_counter_change(chan_info * cp)25731 void reflect_edit_counter_change(chan_info *cp)
25732 {
25733   /* undo/redo/revert -- change which line is highlighted */
25734   Widget lst;
25735 
25736   if (cp->squelch_update) return;
25737   lst = EDIT_HISTORY_LIST(cp);
25738   if ((lst) && (widget_width(lst) > 1))
25739     {
25740       int len, top;
25741       XmListSelectPos(lst, cp->edit_ctr + 1, false);
25742       XtVaGetValues(lst,
25743 		    XmNvisibleItemCount, &len,
25744 		    XmNtopItemPosition, &top,
25745 		    NULL);
25746       if ((cp->edit_ctr + 1) < top)
25747 	XtVaSetValues(lst, XmNtopItemPosition, cp->edit_ctr + 1, NULL);
25748       else
25749 	if ((cp->edit_ctr + 1) >= (top + len))
25750 	  XtVaSetValues(lst, XmNtopItemPosition, cp->edit_ctr, NULL);
25751       goto_graph(cp);
25752     }
25753 }
25754 
25755 
25756 /* for combined cases, the incoming chan_info pointer is always chan[0],
25757  * but the actual channel depends on placement if mouse oriented.
25758  * virtual_selected_channel(cp) (snd-chn.c) retains the current selected channel
25759  */
25760 
graph_key_press(Widget w,XtPointer context,XEvent * event,Boolean * cont)25761 void graph_key_press(Widget w, XtPointer context, XEvent *event, Boolean *cont)
25762 {
25763   XKeyEvent *ev = (XKeyEvent *)event;
25764   KeySym keysym;
25765   int key_state;
25766   snd_info *sp = (snd_info *)context;
25767   key_state = ev->state;
25768   keysym = XkbKeycodeToKeysym(XtDisplay(w),
25769 			      (int)(ev->keycode),
25770 			      0, (key_state & ShiftMask) ? 1 : 0);
25771   key_press_callback(any_selected_channel(sp), ev->x, ev->y, ev->state, keysym);
25772 }
25773 
25774 
cp_graph_key_press(Widget w,XtPointer context,XEvent * event,Boolean * cont)25775 static void cp_graph_key_press(Widget w, XtPointer context, XEvent *event, Boolean *cont)
25776 {
25777   /* called by every key-intercepting widget in the entire sound pane */
25778   XKeyEvent *ev = (XKeyEvent *)event;
25779   KeySym keysym;
25780   int key_state;
25781   chan_info *cp = (chan_info *)context;
25782   if ((!cp) || (!cp->sound)) return; /* can't happen */
25783   key_state = ev->state;
25784   keysym = XkbKeycodeToKeysym(XtDisplay(w),
25785 			      (int)(ev->keycode),
25786 			      0, (key_state & ShiftMask) ? 1 : 0);
25787   key_press_callback(cp, ev->x, ev->y, ev->state, keysym);
25788 }
25789 
25790 
channel_drop_watcher(Widget w,const char * str,Position x,Position y,void * context)25791 static void channel_drop_watcher(Widget w, const char *str, Position x, Position y, void *context)
25792 {
25793   intptr_t data;
25794   data = (intptr_t)context;
25795   drag_and_drop_mix_at_x_y((int)data, str, x, y);
25796 }
25797 
25798 
channel_drag_watcher(Widget w,const char * str,Position x,Position y,drag_style_t dtype,void * context)25799 static void channel_drag_watcher(Widget w, const char *str, Position x, Position y, drag_style_t dtype, void *context)
25800 {
25801   int snd, chn;
25802   intptr_t data;
25803   snd_info *sp;
25804   XtVaGetValues(w, XmNuserData, &data, NULL);
25805   chn = unpack_channel(data);
25806   snd = unpack_sound(data);
25807 
25808   sp = ss->sounds[snd];
25809   if (snd_ok(sp))
25810     {
25811       mus_float_t seconds;
25812       chan_info *cp;
25813       switch (dtype)
25814 	{
25815 	case DRAG_ENTER:
25816 	case DRAG_MOTION:
25817 	  cp = sp->chans[chn];
25818 	  if ((sp->nchans > 1) && (sp->channel_style == CHANNELS_COMBINED))
25819 	    cp = which_channel(sp, y);
25820 	  seconds = ungrf_x(cp->axis, x);
25821 	  if (seconds < 0.0) seconds = 0.0;
25822 	  if (sp->nchans > 1)
25823 	    status_report(sp, "drop to mix file in chan %d at %.4f", cp->chan + 1, seconds);
25824 	  else status_report(sp, "drop to mix file at %.4f", seconds);
25825 	  break;
25826 
25827 	case DRAG_LEAVE:
25828 	  set_status(sp, " ", false); /* not clear_status_area here! => segfault */
25829 	  break;
25830 	}
25831     }
25832 }
25833 
25834 
add_channel_window(snd_info * sp,int channel,int chan_y,int insertion,Widget main,fw_button_t button_style,bool with_events)25835 int add_channel_window(snd_info *sp, int channel, int chan_y, int insertion, Widget main, fw_button_t button_style, bool with_events)
25836 {
25837   bool need_extra_scrollbars;
25838   Widget *cw;
25839   chan_info *cp;
25840   graphics_context *cax;
25841   bool make_widgets;
25842 
25843   /* if ((main) && ((!(XmIsForm(main))) || (!(XtWindow(main))))) return(-1); */ /* new gcc complains about the XmIsForm for some reason */
25844   if ((main) && (!(XtWindow(main)))) return(-1); /* can this happen? */
25845 
25846   make_widgets = (!sp->chans[channel]);
25847   sp->chans[channel] = make_chan_info(sp->chans[channel], channel, sp);
25848   cp = sp->chans[channel];
25849 
25850   if (!cp->widgets)
25851     cp->widgets = (Widget *)calloc(CP_NUM_WIDGETS, sizeof(Widget));
25852   cw = cp->widgets;
25853   need_extra_scrollbars = ((!main) && (channel == 0));
25854 
25855   if (make_widgets)
25856     {
25857       XtCallbackList n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15;
25858       int n;
25859       Arg args[32];
25860 
25861       /* allocate the entire widget apparatus for this channel of this sound */
25862 
25863       if (!main)
25864 	{
25865 	  n = 0;
25866 	  XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
25867 	  if (insertion) {XtSetArg(args[n], XmNpositionIndex, (short)channel); n++;}
25868 	  XtSetArg(args[n], XmNpaneMinimum, chan_y); n++;
25869 
25870 	  cw[W_form] = XtCreateManagedWidget("chn-form", xmFormWidgetClass, w_snd_pane(sp), args, n);
25871 	  if ((sp->channel_style == CHANNELS_COMBINED) && (channel > 0)) XtUnmanageChild(cw[W_form]);
25872 
25873 	  n = 0;
25874 	  XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
25875 	  /* n = no_padding(args, n); */
25876 	  n = attach_all_sides(args, n);
25877 	  XtSetArg(args[n], XmNsashIndent, 2); n++;
25878 	  XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
25879 	  XtSetArg(args[n], XmNpaneMaximum, LOTSA_PIXELS); n++;
25880 	  cw[W_top] = XtCreateManagedWidget("chn-top", xmPanedWindowWidgetClass, cw[W_form], args, n);
25881 	  XtAddEventHandler(cw[W_top], KeyPressMask, false, graph_key_press, (XtPointer)sp);
25882 
25883 	  n = 0;
25884 	  XtSetArg(args[n], XmNbackground, ss->white); n++;
25885 	  XtSetArg(args[n], XmNpaneMaximum, DEFAULT_EDIT_HISTORY_WIDTH); n++;
25886 	  XtSetArg(args[n], XmNlistSizePolicy, XmCONSTANT); n++;
25887 	  cw[W_edhist] = XmCreateScrolledList(cw[W_top], (char *)"chn-edhist", args, n);
25888 	  XtManageChild(cw[W_edhist]);
25889 
25890 	  XtAddCallback(cw[W_edhist], XmNbrowseSelectionCallback, history_select_callback, cp);
25891 	  XtAddEventHandler(cw[W_edhist], KeyPressMask, false, graph_key_press, (XtPointer)sp);
25892 	  XtAddEventHandler(XtParent(cw[W_edhist]), KeyPressMask, false, graph_key_press, (XtPointer)sp);
25893 
25894 	  n = 0;
25895 	  XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
25896 	  XtSetArg(args[n], XmNpaneMaximum, LOTSA_PIXELS); n++;
25897 	  cw[W_main_window] = XtCreateManagedWidget("chn-main-window", xmFormWidgetClass, cw[W_top], args, n);
25898 	  XtAddEventHandler(cw[W_main_window], KeyPressMask, false, graph_key_press, (XtPointer)sp);
25899 
25900 #if WITH_RELATIVE_PANES
25901 	{
25902 	  int k;
25903 	  Widget child;
25904 	  CompositeWidget w = (CompositeWidget)(cw[W_top]);
25905 	  for (k = w->composite.num_children - 1; k >= 0; k--)
25906 	    {
25907 	      child = w->composite.children[k];
25908 	      if ((XtIsWidget(child)) &&
25909 		  (XtIsSubclass(child, xmSashWidgetClass)))
25910 		{
25911 		  XtAddCallback(child, XmNcallback, watch_edit_history_sash, (XtPointer)cp);
25912 		  break; /* there seems to be more than 1?? */
25913 		}
25914 	    }
25915 	}
25916 #endif
25917 	}
25918       else cw[W_main_window] = main;
25919 
25920       n = 0;
25921       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
25922       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
25923       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
25924       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
25925       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
25926       n = no_padding(args, n);
25927       XtSetArg(args[n], XmNpacking, XmPACK_COLUMN); n++;
25928       XtSetArg(args[n], XmNnumColumns, 1); n++;
25929       XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
25930       cw[W_wf_buttons] = XtCreateManagedWidget("chn-buttons", xmRowColumnWidgetClass, cw[W_main_window], args, n);
25931 
25932       if (button_style == WITH_FW_BUTTONS)
25933 	{
25934 	  n = 0;
25935 	  XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
25936 	  XtSetArg(args[n], XmNspacing, 1); n++;
25937 	  XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
25938 	  cw[W_f] = make_togglebutton_widget("f", cw[W_wf_buttons], args, n);
25939 	  XtAddCallback(cw[W_f], XmNvalueChangedCallback, f_toggle_callback, cp);
25940 	  XtAddEventHandler(cw[W_f], KeyPressMask, false, graph_key_press, (XtPointer)sp);
25941 
25942 	  XtSetArg(args[n], XmNset, true); n++;
25943 	  cw[W_w] = make_togglebutton_widget("w", cw[W_wf_buttons], args, n);
25944 	  XtAddCallback(cw[W_w], XmNvalueChangedCallback, w_toggle_callback, cp);
25945 	  XtAddEventHandler(cw[W_w], KeyPressMask, false, graph_key_press, (XtPointer)sp);
25946 	}
25947       else
25948 	{
25949 	  n = 0;
25950 	  XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
25951 	  XtSetArg(args[n], XmNarrowDirection, XmARROW_UP); n++;
25952 	  XtSetArg(args[n], XmNsensitive, false); n++;
25953 	  cw[W_f] = XtCreateManagedWidget("up", xmArrowButtonWidgetClass, cw[W_wf_buttons], args, n);
25954 
25955 	  n = 0;
25956 	  XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
25957 	  XtSetArg(args[n], XmNarrowDirection, XmARROW_DOWN); n++;
25958 	  XtSetArg(args[n], XmNsensitive, false); n++;
25959 	  cw[W_w] = XtCreateManagedWidget("down", xmArrowButtonWidgetClass, cw[W_wf_buttons], args, n);
25960 	}
25961 
25962       n = 0;
25963       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
25964       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
25965       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
25966       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
25967       XtSetArg(args[n], XmNbottomWidget, cw[W_wf_buttons]); n++;
25968       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
25969       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
25970       XtSetArg(args[n], XmNspacing, 0); n++;
25971       cw[W_left_scrollers] = XtCreateManagedWidget("chn-left", xmRowColumnWidgetClass, cw[W_main_window], args, n);
25972       XtAddEventHandler(cw[W_left_scrollers], KeyPressMask, false, graph_key_press, (XtPointer)sp);
25973 
25974       n = 0;
25975       XtSetArg(args[n], XmNbackground, ss->zoom_color); n++;
25976       XtSetArg(args[n], XmNwidth, ss->position_slider_width); n++;
25977       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
25978       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
25979       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
25980       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
25981       XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
25982       XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++;
25983       XtSetArg(args[n], XmNincrement, 1); n++;
25984       XtSetArg(args[n], XmNprocessingDirection, XmMAX_ON_TOP); n++;
25985       XtSetArg(args[n], XmNdragCallback, n1 = make_callback_list(zy_drag_callback, (XtPointer)cp)); n++;
25986       XtSetArg(args[n], XmNvalueChangedCallback, n2 = make_callback_list(zy_valuechanged_callback, (XtPointer)cp)); n++;
25987       cw[W_zy] = XtCreateManagedWidget("chn-zy", xmScrollBarWidgetClass, cw[W_left_scrollers], args, n);
25988       XtAddEventHandler(cw[W_zy], KeyPressMask, false, graph_key_press, (XtPointer)sp);
25989 
25990       n = 0;
25991       XtSetArg(args[n], XmNbackground, ss->position_color); n++;
25992       XtSetArg(args[n], XmNwidth, ss->zoom_slider_width); n++;
25993       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
25994       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
25995       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
25996       XtSetArg(args[n], XmNleftWidget, cw[W_zy]); n++;
25997       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
25998       XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
25999       XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++;
26000       XtSetArg(args[n], XmNincrement, 1); n++;
26001       XtSetArg(args[n], XmNprocessingDirection, XmMAX_ON_TOP); n++;
26002       XtSetArg(args[n], XmNdragCallback, n3 = make_callback_list(sy_drag_callback, (XtPointer)cp)); n++;
26003       XtSetArg(args[n], XmNvalueChangedCallback, n4 = make_callback_list(sy_valuechanged_callback, (XtPointer)cp)); n++;
26004       cw[W_sy] = XtCreateManagedWidget("chn-sy", xmScrollBarWidgetClass, cw[W_left_scrollers], args, n);
26005       XtAddEventHandler(cw[W_sy], KeyPressMask, false, graph_key_press, (XtPointer)sp);
26006 
26007       n = 0;
26008       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
26009       XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
26010       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
26011       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
26012       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
26013       XtSetArg(args[n], XmNleftWidget, cw[W_wf_buttons]); n++;
26014       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
26015       XtSetArg(args[n], XmNspacing, 0); n++;
26016       cw[W_bottom_scrollers] = XtCreateManagedWidget("chn-bottom", xmRowColumnWidgetClass, cw[W_main_window], args, n);
26017       XtAddEventHandler(cw[W_bottom_scrollers], KeyPressMask, false, graph_key_press, (XtPointer)sp);
26018 
26019       n = 0;
26020       XtSetArg(args[n], XmNbackground, ss->position_color); n++;
26021       XtSetArg(args[n], XmNheight, ss->position_slider_width); n++;
26022       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
26023       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
26024       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
26025       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
26026       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
26027       XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++;
26028       XtSetArg(args[n], XmNincrement, 1); n++;
26029       XtSetArg(args[n], XmNdragCallback, n5 = make_callback_list(sx_drag_callback, (XtPointer)cp)); n++;
26030       XtSetArg(args[n], XmNincrementCallback, n6 = make_callback_list(sx_increment_callback, (XtPointer)cp)); n++;
26031       XtSetArg(args[n], XmNdecrementCallback, n7 = make_callback_list(sx_decrement_callback, (XtPointer)cp)); n++;
26032       XtSetArg(args[n], XmNvalueChangedCallback, n8 = make_callback_list(sx_valuechanged_callback, (XtPointer)cp)); n++;
26033       cw[W_sx] = XtCreateManagedWidget("chn-sx", xmScrollBarWidgetClass, cw[W_bottom_scrollers], args, n);
26034       XtAddEventHandler(cw[W_sx], KeyPressMask, false, graph_key_press, (XtPointer)sp);
26035 
26036       n = 0;
26037       XtSetArg(args[n], XmNbackground, ss->zoom_color); n++;
26038       XtSetArg(args[n], XmNheight, ss->zoom_slider_width + 2); n++;
26039       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
26040       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
26041       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
26042       XtSetArg(args[n], XmNbottomWidget, cw[W_sx]); n++;
26043       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
26044       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
26045       XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++;
26046       XtSetArg(args[n], XmNincrement, 1); n++;
26047       XtSetArg(args[n], XmNdragCallback, n9 = make_callback_list(zx_drag_callback, (XtPointer)cp)); n++;
26048       XtSetArg(args[n], XmNincrementCallback, n10 = make_callback_list(zx_drag_callback, (XtPointer)cp)); n++;
26049       XtSetArg(args[n], XmNdecrementCallback, n11 = make_callback_list(zx_drag_callback, (XtPointer)cp)); n++;
26050       XtSetArg(args[n], XmNpageIncrementCallback, n12 = make_callback_list(zx_drag_callback, (XtPointer)cp)); n++;
26051       XtSetArg(args[n], XmNpageDecrementCallback, n13 = make_callback_list(zx_drag_callback, (XtPointer)cp)); n++;
26052       XtSetArg(args[n], XmNtoTopCallback, n14 = make_callback_list(zx_drag_callback, (XtPointer)cp)); n++;
26053       XtSetArg(args[n], XmNtoBottomCallback, n15 = make_callback_list(zx_drag_callback, (XtPointer)cp)); n++;
26054 
26055       cw[W_zx] = XtCreateManagedWidget("chn-zx", xmScrollBarWidgetClass, cw[W_bottom_scrollers], args, n);
26056       XtAddEventHandler(cw[W_zx], KeyPressMask, false, graph_key_press, (XtPointer)sp);
26057 
26058       n = 0;
26059       XtSetArg(args[n], XmNbackground, ss->graph_color); n++;
26060       XtSetArg(args[n], XmNforeground, ss->data_color); n++;
26061       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
26062       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
26063       XtSetArg(args[n], XmNbottomWidget, cw[W_bottom_scrollers]); n++;
26064       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
26065       XtSetArg(args[n], XmNleftWidget, cw[W_left_scrollers]); n++;
26066       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
26067       XtSetArg(args[n], XmNuserData, pack_sound_and_channel(sp->index, cp->chan)); n++;
26068       /* this collides with W_gzy below, but a consistent version came up with half a window blank */
26069       XtSetArg(args[n], XmNnavigationType, XmNONE); n++;
26070       cw[W_graph] = XtCreateManagedWidget("chn-graph", xmDrawingAreaWidgetClass, cw[W_main_window], args, n);
26071 
26072       if (with_events)
26073 	{
26074 	  /* region regraph sets up its own callbacks */
26075 	  XtAddCallback(cw[W_graph], XmNresizeCallback, channel_resize_callback, (XtPointer)cp);
26076 	  XtAddCallback(cw[W_graph], XmNexposeCallback, channel_expose_callback, (XtPointer)cp);
26077 	}
26078       /* allow cursor in all cases (zoom to cursor in region window for example, or fft axis drag in variable display) */
26079       XtAddEventHandler(cw[W_graph], ButtonPressMask, false, graph_button_press, (XtPointer)cp);
26080       XtAddEventHandler(cw[W_graph], ButtonReleaseMask, false, graph_button_release, (XtPointer)cp);
26081       /* XtAddEventHandler(cw[W_graph], ButtonMotionMask, false, graph_button_motion, (XtPointer)cp); */
26082       XtAddEventHandler(cw[W_graph], PointerMotionMask, false, graph_mouse_motion, (XtPointer)cp);
26083       if (!main)
26084 	{
26085 	  intptr_t data;
26086 	  XtAddEventHandler(cw[W_graph], EnterWindowMask, false, graph_mouse_enter, (XtPointer)cp);
26087 	  XtAddEventHandler(cw[W_graph], LeaveWindowMask, false, graph_mouse_leave, (XtPointer)cp);
26088 	  XtAddEventHandler(cw[W_graph], KeyPressMask, false, cp_graph_key_press, (XtPointer)cp);
26089 
26090 	  data = (intptr_t)pack_sound_and_channel(sp->index, cp->chan);
26091 	  add_drag_and_drop(cw[W_graph], channel_drop_watcher, channel_drag_watcher, (void *)data);
26092 	}
26093 
26094       free(n1);
26095       free(n2);
26096       free(n3);
26097       free(n4);
26098       free(n5);
26099       free(n6);
26100       free(n7);
26101       free(n8);
26102       free(n9);
26103       free(n10);
26104       free(n11);
26105       free(n12);
26106       free(n13);
26107       free(n14);
26108       free(n15);
26109 
26110       if (need_extra_scrollbars)
26111 	{
26112 	  /* that is: not region browser chan, might need combined graph, channel 0 is the controller in that case */
26113 	  /* this is independent of sp->nchans because these structs are re-used and added to as needed */
26114 	  n = 0;
26115 	  XtSetArg(args[n], XmNbackground, ss->zoom_color); n++;
26116 	  XtSetArg(args[n], XmNwidth, ss->position_slider_width); n++;
26117 	  XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
26118 	  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
26119 	  XtSetArg(args[n], XmNbottomWidget, cw[W_bottom_scrollers]); n++;
26120 	  XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
26121 	  XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
26122 	  XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
26123 	  XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++;
26124 	  XtSetArg(args[n], XmNincrement, 1); n++;
26125 	  XtSetArg(args[n], XmNprocessingDirection, XmMAX_ON_TOP); n++;
26126 
26127 	  XtSetArg(args[n], XmNincrementCallback, n1 = make_callback_list(gzy_drag_callback, (XtPointer)cp)); n++;
26128 	  XtSetArg(args[n], XmNdecrementCallback, n2 = make_callback_list(gzy_drag_callback, (XtPointer)cp)); n++;
26129 	  XtSetArg(args[n], XmNpageIncrementCallback, n3 = make_callback_list(gzy_drag_callback, (XtPointer)cp)); n++;
26130 	  XtSetArg(args[n], XmNpageDecrementCallback, n4 = make_callback_list(gzy_drag_callback, (XtPointer)cp)); n++;
26131 	  XtSetArg(args[n], XmNtoTopCallback, n5 = make_callback_list(gzy_drag_callback, (XtPointer)cp)); n++;
26132 	  XtSetArg(args[n], XmNtoBottomCallback, n6 = make_callback_list(gzy_drag_callback, (XtPointer)cp)); n++;
26133 	  XtSetArg(args[n], XmNdragCallback, n7 = make_callback_list(gzy_drag_callback, (XtPointer)cp)); n++;
26134 
26135 	  cw[W_gzy] = XtCreateManagedWidget("chn-gzy", xmScrollBarWidgetClass, cw[W_main_window], args, n);
26136 	  XtAddEventHandler(cw[W_gzy], KeyPressMask, false, graph_key_press, (XtPointer)sp);
26137 
26138 
26139 	  n = 0;
26140 	  XtSetArg(args[n], XmNbackground, ss->position_color); n++;
26141 	  XtSetArg(args[n], XmNwidth, ss->position_slider_width); n++;
26142 	  XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
26143 	  XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
26144 	  XtSetArg(args[n], XmNbottomWidget, cw[W_bottom_scrollers]); n++;
26145 	  XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
26146 	  XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
26147 	  XtSetArg(args[n], XmNrightWidget, cw[W_gzy]); n++;
26148 	  XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
26149 	  XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++;
26150 	  XtSetArg(args[n], XmNincrement, 1); n++;
26151 	  XtSetArg(args[n], XmNprocessingDirection, XmMAX_ON_TOP); n++;
26152 	  XtSetArg(args[n], XmNdragCallback, n8 = make_callback_list(gsy_drag_callback, (XtPointer)cp)); n++;
26153 	  XtSetArg(args[n], XmNvalueChangedCallback, n9 = make_callback_list(gsy_valuechanged_callback, (XtPointer)cp)); n++;
26154 	  cw[W_gsy] = XtCreateManagedWidget("chn-gsy", xmScrollBarWidgetClass, cw[W_main_window], args, n);
26155 	  XtAddEventHandler(cw[W_gsy], KeyPressMask, false, graph_key_press, (XtPointer)sp);
26156 
26157 	  free(n1);
26158 	  free(n2);
26159 	  free(n3);
26160 	  free(n4);
26161 	  free(n5);
26162 	  free(n6);
26163 	  free(n7);
26164 
26165 	  free(n8);
26166 	  free(n9);
26167 	}
26168       else
26169 	{
26170 	  cw[W_gsy] = NULL;
26171 	  cw[W_gzy] = NULL;
26172 	}
26173       run_new_widget_hook(cw[W_main_window]);
26174       /* also position of current graph in overall sound as window */
26175 
26176     } /* end alloc new chan */
26177 
26178   else
26179     {
26180       int i;
26181       /* re-manage currently inactive chan */
26182       XtVaSetValues(cw[W_main_window], XmNpaneMinimum, chan_y, NULL);
26183       if (cw[W_edhist])
26184 	XtVaSetValues(XtParent(cw[W_edhist]), XmNpaneMaximum, 1, NULL);
26185       if ((sp->channel_style != CHANNELS_COMBINED) ||
26186 	  (channel == 0))
26187 	for (i = 0; i < CP_NUM_WIDGETS - 1; i++)
26188 	  if ((cw[i]) && (!XtIsManaged(cw[i])))
26189 	    XtManageChild(cw[i]);
26190       recolor_graph(cp, false); /* in case selection color left over from previous use */
26191     }
26192 
26193   if (cw[W_edhist])
26194     XtVaSetValues(XtParent(cw[W_edhist]), XmNpaneMaximum, LOTSA_PIXELS, NULL);
26195 
26196   if ((need_extra_scrollbars) &&
26197       (sp->channel_style != CHANNELS_COMBINED))
26198     hide_gz_scrollbars(sp); /* default is on in this case */
26199 
26200   cax = cp->ax;
26201   cax->wn = XtWindow(cw[W_graph]);
26202   cax->dp = XtDisplay(cw[W_graph]);
26203   cax->gc = ss->basic_gc;
26204   return(0);
26205 }
26206 
26207 
set_graph_font(chan_info * cp,graphics_context * ax,XFontStruct * bf)26208 static void set_graph_font(chan_info *cp, graphics_context *ax, XFontStruct *bf)
26209 {
26210   if (!ax) return;
26211   ax->current_font = bf->fid;
26212   XSetFont(XtDisplay(channel_to_widget(cp)), copy_GC(cp), bf->fid);
26213 }
26214 
26215 
set_peak_numbers_font(chan_info * cp,graphics_context * ax)26216 void set_peak_numbers_font(chan_info *cp, graphics_context *ax) {set_graph_font(cp, ax, PEAKS_FONT(ss));}
26217 
set_tiny_numbers_font(chan_info * cp,graphics_context * ax)26218 void set_tiny_numbers_font(chan_info *cp, graphics_context *ax) {set_graph_font(cp, ax, TINY_FONT(ss));}
26219 
set_bold_peak_numbers_font(chan_info * cp,graphics_context * ax)26220 void set_bold_peak_numbers_font(chan_info *cp, graphics_context *ax) {set_graph_font(cp, ax, BOLD_PEAKS_FONT(ss));}
26221 
26222 
get_foreground_color(graphics_context * ax)26223 color_t get_foreground_color(graphics_context *ax)
26224 {
26225   XGCValues gv;
26226   XGetGCValues(main_display(ss), ax->gc, GCForeground, &gv);
26227   return(gv.foreground);
26228 }
26229 
26230 
set_foreground_color(graphics_context * ax,Pixel color)26231 void set_foreground_color(graphics_context *ax, Pixel color)
26232 {
26233   XSetForeground(main_display(ss), ax->gc, color);
26234 }
26235 
26236 
copy_GC(chan_info * cp)26237 GC copy_GC(chan_info *cp)
26238 {
26239   if (cp->selected) return(ss->selected_basic_gc);
26240   return(ss->basic_gc);
26241 }
26242 
26243 
erase_GC(chan_info * cp)26244 GC erase_GC(chan_info *cp)
26245 {
26246   /* used only to clear partial bgs in chan graphs */
26247   snd_info *sp;
26248   sp = cp->sound;
26249   if ((cp->selected) ||
26250       ((sp) &&
26251        (sp->channel_style == CHANNELS_SUPERIMPOSED) &&
26252        (sp->index == ss->selected_sound)))
26253     return(ss->selected_erase_gc);
26254   return(ss->erase_gc);
26255 }
26256 
26257 
free_fft_pix(chan_info * cp)26258 void free_fft_pix(chan_info *cp)
26259 {
26260   if ((cp->fft_pix != None) &&
26261       (channel_graph(cp)))
26262     XFreePixmap(XtDisplay(channel_graph(cp)),
26263 		cp->fft_pix);
26264   cp->fft_pix = None;
26265   cp->fft_pix_ready = false;
26266 }
26267 
26268 
restore_fft_pix(chan_info * cp,graphics_context * ax)26269 bool restore_fft_pix(chan_info *cp, graphics_context *ax)
26270 {
26271   XCopyArea(ax->dp,
26272 	    cp->fft_pix,
26273 	    ax->wn,
26274 	    copy_GC(cp),
26275 	    0, 0,                          /* source x y */
26276 	    cp->fft_pix_width, cp->fft_pix_height,
26277 	    cp->fft_pix_x0, cp->fft_pix_y0);
26278   return(true);
26279 }
26280 
26281 
save_fft_pix(chan_info * cp,graphics_context * ax,int fwidth,int fheight,int x0,int y1)26282 void save_fft_pix(chan_info *cp, graphics_context *ax, int fwidth, int fheight, int x0, int y1)
26283 {
26284   if ((fwidth == 0) || (fheight == 0)) return;
26285   if (cp->fft_pix == None)
26286     {
26287       /* make new pixmap */
26288       cp->fft_pix_width = fwidth;
26289       cp->fft_pix_height = fheight;
26290       cp->fft_pix_x0 = x0;
26291       cp->fft_pix_y0 = y1;
26292       cp->fft_pix_cutoff = cp->spectrum_end;
26293       cp->fft_pix = XCreatePixmap(ax->dp,
26294 				  RootWindowOfScreen(XtScreen(channel_graph(cp))),
26295 				  fwidth, fheight,
26296 				  DefaultDepthOfScreen(XtScreen(channel_graph(cp))));
26297     }
26298   XCopyArea(ax->dp,
26299 	    ax->wn,
26300 	    cp->fft_pix,
26301 	    copy_GC(cp),
26302 	    cp->fft_pix_x0, cp->fft_pix_y0,
26303 	    cp->fft_pix_width, cp->fft_pix_height,
26304 	    0, 0);
26305   cp->fft_pix_ready = true;
26306 }
26307 
26308 
cleanup_cw(chan_info * cp)26309 void cleanup_cw(chan_info *cp)
26310 {
26311   if (cp)
26312     {
26313       Widget *cw;
26314       free_fft_pix(cp);
26315 
26316       cp->selected = false;
26317       cw = cp->widgets;
26318       if (cw)
26319 	{
26320 	  if (cw[W_w])
26321 	    {
26322 	      XtVaSetValues(cw[W_w], XmNset, true, NULL);
26323 	      XtVaSetValues(cw[W_f], XmNset, false, NULL);
26324 	    }
26325 	  if (channel_main_pane(cp))
26326 	    XtUnmanageChild(channel_main_pane(cp));
26327 	}
26328     }
26329 }
26330 
26331 
change_channel_style(snd_info * sp,channel_style_t new_style)26332 void change_channel_style(snd_info *sp, channel_style_t new_style)
26333 {
26334   if ((sp) &&
26335       (sp->nchans > 1))
26336     {
26337       channel_style_t old_style;
26338       chan_info *selected_cp;
26339 
26340       selected_cp = any_selected_channel(sp); /* chan 0 is none is selected */
26341       old_style = sp->channel_style;
26342       sp->channel_style = new_style;
26343 
26344       if (new_style != old_style)
26345 	{
26346 	  uint32_t i, height;
26347 
26348 #if WITH_RELATIVE_PANES
26349 	  if ((new_style == CHANNELS_SEPARATE) || (old_style == CHANNELS_SEPARATE))
26350 	    {
26351 	      Widget lst;
26352 	      lst = EDIT_HISTORY_LIST(sp->chans[0]);
26353 	      if ((lst) && (widget_width(lst) > 1))
26354 		remake_edit_history(lst, sp->chans[0], true);
26355 	    }
26356 #endif
26357 
26358 	  if (old_style == CHANNELS_COMBINED)
26359 	    {
26360 	      hide_gz_scrollbars(sp);
26361 	      for (i = 1; i < sp->nchans; i++) channel_set_mix_tags_erased(sp->chans[i]);
26362 	    }
26363 	  else
26364 	    {
26365 	      if (new_style == CHANNELS_COMBINED)
26366 		{
26367 		  show_gz_scrollbars(sp);
26368 		  for (i = 1; i < sp->nchans; i++) channel_set_mix_tags_erased(sp->chans[i]);
26369 		}
26370 	    }
26371 
26372 	  if (old_style == CHANNELS_SUPERIMPOSED)
26373 	    {
26374 	      syncb(sp, sp->previous_sync);
26375 	      XtVaSetValues(unite_button(sp), XmNselectColor, ss->selection_color, NULL);
26376 	    }
26377 	  else
26378 	    {
26379 	      if (new_style == CHANNELS_SUPERIMPOSED)
26380 		{
26381 		  sp->previous_sync = sp->sync;
26382 		  if (sp->sync == 0) syncb(sp, 1);
26383 		  XtVaSetValues(unite_button(sp), XmNselectColor, ss->green, NULL);
26384 
26385 		  apply_y_axis_change(selected_cp);
26386 		  apply_x_axis_change(selected_cp);
26387 
26388 		  for (i = 0; i < sp->nchans; i++)
26389 		    {
26390 		      if ((int)i != selected_cp->chan)
26391 			{
26392 			  chan_info *ncp;
26393 			  ncp = sp->chans[i];
26394 			  cursor_sample(ncp) = cursor_sample(selected_cp);
26395 			  if (selected_cp->graph_transform_on != ncp->graph_transform_on)
26396 			    {
26397 			      ncp->graph_transform_on = selected_cp->graph_transform_on;
26398 			      set_toggle_button(channel_f(ncp), selected_cp->graph_transform_on, false, (void *)ncp);
26399 			    }
26400 			  if (selected_cp->graph_time_on != ncp->graph_time_on)
26401 			    {
26402 			      ncp->graph_time_on = selected_cp->graph_time_on;
26403 			      set_toggle_button(channel_w(ncp), selected_cp->graph_time_on, false, (void *)ncp);
26404 			    }
26405 			}
26406 		    }
26407 		}
26408 	    }
26409 
26410 	  height = widget_height(w_snd_pane(sp)) - control_panel_height(sp);
26411 	  if (old_style == CHANNELS_SEPARATE)
26412 	    {
26413 	      axis_info *ap;
26414 	      ap = selected_cp->axis;
26415 	      channel_lock_pane(sp->chans[0], height);
26416 
26417 	      for (i = 0; i < sp->nchans; i++)
26418 		{
26419 		  if ((int)i != selected_cp->chan)
26420 		    set_axes(sp->chans[i], ap->x0, ap->x1, ap->y0, ap->y1);
26421 		  if (i > 0)
26422 		    cleanup_cw(sp->chans[i]);
26423 		}
26424 
26425 	      channel_open_pane(sp->chans[0]);
26426 	      channel_unlock_pane(sp->chans[0]);
26427 	      XmToggleButtonSetState(unite_button(sp), true, false);
26428 	    }
26429 	  else
26430 	    {
26431 	      if (new_style == CHANNELS_SEPARATE)
26432 		{
26433 		  /* height = total space available */
26434 		  height /= sp->nchans;
26435 		  for_each_sound_chan_with_int(sp, channel_lock_pane, height);
26436 		  for_each_sound_chan(sp, channel_open_pane);
26437 		  for_each_sound_chan(sp, channel_unlock_pane);
26438 
26439 		  for (i = 1; i < sp->nchans; i++)
26440 		    {
26441 		      Widget *cw;
26442 		      chan_info *cp;
26443 		      int j;
26444 
26445 		      cp = sp->chans[i];
26446 		      cw = cp->widgets;
26447 
26448 		      for (j = 0; j < CP_NUM_WIDGETS - 1; j++)
26449 			if ((cw[j]) && (!XtIsManaged(cw[j])))
26450 			  XtManageChild(cw[j]);
26451 
26452 		      XmToggleButtonSetState(cw[W_f], (Boolean)(cp->graph_transform_on), false);
26453 		      XmToggleButtonSetState(cw[W_w], (Boolean)(cp->graph_time_on), false);
26454 		      /* these can get out of sync if changes are made in the unseparated case */
26455 		    }
26456 
26457 		  XmToggleButtonSetState(unite_button(sp), false, false);
26458 		  if (sp->selected_channel > 0) color_selected_channel(sp);
26459 		}
26460 	    }
26461 
26462 	  if ((new_style == CHANNELS_COMBINED) &&
26463 	      (sp->selected_channel > 0))
26464 	    color_selected_channel(sp);
26465 	}
26466     }
26467 }
26468 
26469 
g_channel_widgets(Xen snd,Xen chn)26470 static Xen g_channel_widgets(Xen snd, Xen chn)
26471 {
26472   #define H_channel_widgets "(" S_channel_widgets " :optional snd chn): a list of widgets: ((0)graph (1)w (2)f (3)sx (4)sy (5)zx (6)zy (7)edhist)"
26473   chan_info *cp;
26474   Snd_assert_channel(S_channel_widgets, snd, chn, 1);
26475   cp = get_cp(snd, chn, S_channel_widgets);
26476   if (!cp) return(Xen_false);
26477   return(Xen_cons(Xen_wrap_widget(channel_graph(cp)),
26478 	   Xen_cons(Xen_wrap_widget(channel_w(cp)),
26479 	     Xen_cons(Xen_wrap_widget(channel_f(cp)),
26480 	       Xen_cons(Xen_wrap_widget(channel_sx(cp)),
26481 	         Xen_cons(Xen_wrap_widget(channel_sy(cp)),
26482 	           Xen_cons(Xen_wrap_widget(channel_zx(cp)),
26483 	             Xen_cons(Xen_wrap_widget(channel_zy(cp)),
26484 		       Xen_cons(Xen_wrap_widget(EDIT_HISTORY_LIST(cp)),
26485 			 Xen_cons(Xen_wrap_widget(channel_gsy(cp)),
26486 			   Xen_cons(Xen_wrap_widget(channel_gzy(cp)),
26487 			     Xen_cons(Xen_wrap_widget(channel_main_pane(cp)),
26488 	                       Xen_empty_list))))))))))));
26489 }
26490 
26491 
26492 /* previous snd-xxen.c contents) */
26493 
timed_eval(XtPointer in_code,XtIntervalId * id)26494 static void timed_eval(XtPointer in_code, XtIntervalId *id)
26495 {
26496 #if HAVE_EXTENSION_LANGUAGE
26497   Xen lst = (XEN)in_code;
26498   Xen_call_with_no_args(Xen_cadr(lst), "timed callback func");
26499   snd_unprotect_at(Xen_integer_to_C_int(Xen_car(lst)));
26500 #endif
26501 }
26502 
26503 
g_in(Xen ms,Xen code)26504 static Xen g_in(Xen ms, Xen code)
26505 {
26506   #define H_in "(" S_in " msecs thunk): invoke thunk in msecs milliseconds (named call_in in Ruby)"
26507 
26508 #if HAVE_EXTENSION_LANGUAGE
26509   Xen_check_type(Xen_is_number(ms), ms, 1, S_in, "a number");
26510   Xen_check_type(Xen_is_procedure(code), code, 2, S_in, "a procedure");
26511 
26512   if (Xen_is_aritable(code, 0))
26513     {
26514       int secs;
26515       Xen_check_type(Xen_is_integer(ms), ms, 3, S_in, "an integer");
26516       secs = Xen_integer_to_C_int(ms);
26517       if (secs < 0)
26518 	Xen_out_of_range_error(S_in, 1, ms, "a positive integer");
26519       else
26520 	{
26521 	  Xen lst;
26522 	  lst = Xen_list_2(Xen_false, code);
26523 	  Xen_list_set(lst, 0, C_int_to_Xen_integer(snd_protect(lst)));
26524 	  XtAppAddTimeOut(main_app(ss),
26525 			  (unsigned long)secs,
26526 			  (XtTimerCallbackProc)timed_eval,
26527 			  (XtPointer)lst);
26528 	}
26529     }
26530   else Xen_bad_arity_error(S_in, 2, code, "should take no args");
26531 #endif
26532 
26533   return(ms);
26534 }
26535 
26536 
color_unselected_graphs(color_t color)26537 void color_unselected_graphs(color_t color)
26538 {
26539   int i;
26540   for (i = 0; i < ss->max_sounds; i++)
26541     {
26542       snd_info *sp;
26543       int j;
26544       sp = ss->sounds[i];
26545       if ((sp) && (sp->inuse != SOUND_WRAPPER))
26546 	for (j = 0; j < sp->allocated_chans; j++)
26547 	  {
26548 	    chan_info *cp;
26549 	    cp = sp->chans[j];
26550 	    if ((cp) && ((i != ss->selected_sound) || (j != sp->selected_channel)))
26551 	      XtVaSetValues(channel_graph(cp), XmNbackground, color, NULL);
26552 	  }
26553     }
26554 }
26555 
26556 
color_chan_components(color_t color,slider_choice_t which_component)26557 void color_chan_components(color_t color, slider_choice_t which_component)
26558 {
26559   int i;
26560   for (i = 0; i < ss->max_sounds; i++)
26561     {
26562       snd_info *sp;
26563       int j;
26564       sp = ss->sounds[i];
26565       if ((sp) && (sp->inuse != SOUND_WRAPPER))
26566 	for (j = 0; j < sp->allocated_chans; j++)
26567 	  {
26568 	    chan_info *cp;
26569 	    cp = sp->chans[j];
26570 	    if (cp)
26571 	      {
26572 		if (which_component == COLOR_POSITION)
26573 		  {
26574 		    XtVaSetValues(channel_sx(cp), XmNbackground, color, NULL);
26575 		    XtVaSetValues(channel_sy(cp), XmNbackground, color, NULL);
26576 		  }
26577 		else
26578 		  {
26579 		    XtVaSetValues(channel_zy(cp), XmNbackground, color, NULL);
26580 		    XtVaSetValues(channel_zx(cp), XmNbackground, color, NULL);
26581 		  }
26582 	      }
26583 	  }
26584     }
26585 }
26586 
26587 
g_graph_cursor(void)26588 static Xen g_graph_cursor(void)
26589 {
26590   #define H_graph_cursor "(" S_graph_cursor "): current graph cursor shape"
26591   return(C_int_to_Xen_integer(in_graph_cursor(ss)));
26592 }
26593 
26594 
g_set_graph_cursor(Xen curs)26595 static Xen g_set_graph_cursor(Xen curs)
26596 {
26597   int val;
26598   Xen_check_type(Xen_is_integer(curs), curs, 1, S_set S_graph_cursor, "an integer");
26599   /* X11/cursorfont.h has various even-numbered glyphs, but the odd numbers are ok, and XC_num_glyphs is a lie */
26600   /*   if you use too high a number here, X dies */
26601   val = Xen_integer_to_C_int(curs);
26602   if ((val >= 0) && (val <= XC_xterm))
26603     {
26604       ss->Graph_Cursor = val;
26605       ss->graph_cursor = XCreateFontCursor(XtDisplay(main_shell(ss)), in_graph_cursor(ss));
26606     }
26607   else Xen_out_of_range_error(S_set S_graph_cursor, 1, curs, "invalid cursor");
26608   return(curs);
26609 }
26610 
26611 
26612 #include <X11/xpm.h>
26613 
26614 #define sound_env_editor(Sp) ((env_editor *)(sp->flt))
26615 #define TOGGLE_MARGIN 0
26616 
26617 enum {W_pane,
26618       W_name_form, W_amp_form,
26619       W_amp, W_amp_label, W_amp_number,
26620       W_speed, W_speed_label, W_speed_number, W_speed_arrow,
26621       W_expand, W_expand_label, W_expand_number, W_expand_button,
26622       W_contrast, W_contrast_label, W_contrast_number, W_contrast_button,
26623       W_revscl, W_revscl_label, W_revscl_number,
26624       W_revlen, W_revlen_label, W_revlen_number, W_reverb_button,
26625       W_filter_label, W_filter_order, W_filter_env, W_filter, W_filter_button, W_filter_dB, W_filter_hz, W_filter_frame,
26626       W_filter_order_down, W_filter_order_up,
26627       W_name, W_lock_or_bomb, W_stop_icon, W_info,
26628       W_play, W_sync, W_unite, W_close,
26629       SP_NUM_WIDGETS
26630 };
26631 
26632 
unite_button(snd_info * sp)26633 Widget unite_button(snd_info *sp) {return(sp->widgets[W_unite]);}
w_snd_pane(snd_info * sp)26634 Widget w_snd_pane(snd_info *sp)   {return(sp->widgets[W_pane]);}
26635 
26636 #define SND_PANE(Sp)             Sp->widgets[W_pane]
26637 #define SND_NAME(Sp)             Sp->widgets[W_name]
26638 
26639 #define NAME_BOX(Sp)             Sp->widgets[W_name_form]
26640 #define LOCK_OR_BOMB(Sp)         Sp->widgets[W_lock_or_bomb]
26641 #define STOP_ICON(Sp)            Sp->widgets[W_stop_icon]
26642 #define NAME_LABEL(Sp)           Sp->widgets[W_name]
26643 #define STATUS_AREA(Sp)          Sp->widgets[W_info]
26644 #define SYNC_BUTTON(Sp)          Sp->widgets[W_sync]
26645 #define PLAY_BUTTON(Sp)          Sp->widgets[W_play]
26646 #define UNITE_BUTTON(Sp)         Sp->widgets[W_unite]
26647 #define CLOSE_BUTTON(Sp)         Sp->widgets[W_close]
26648 
26649 #define CONTROLS(Sp)             Sp->widgets[W_amp_form]
26650 #define AMP_SCROLLBAR(Sp)        Sp->widgets[W_amp]
26651 #define AMP_LABEL(Sp)            Sp->widgets[W_amp_number]
26652 #define AMP_BUTTON(Sp)           Sp->widgets[W_amp_label]
26653 
26654 #define SPEED_SCROLLBAR(Sp)      Sp->widgets[W_speed]
26655 #define SPEED_ARROW(Sp)          Sp->widgets[W_speed_arrow]
26656 #define SPEED_LABEL(Sp)          Sp->widgets[W_speed_number]
26657 #define SPEED_BUTTON(Sp)         Sp->widgets[W_speed_label]
26658 
26659 #define EXPAND_SCROLLBAR(Sp)     Sp->widgets[W_expand]
26660 #define EXPAND_LABEL(Sp)         Sp->widgets[W_expand_number]
26661 #define EXPAND_RIGHT_BUTTON(Sp)  Sp->widgets[W_expand_button]
26662 #define EXPAND_LEFT_BUTTON(Sp)   Sp->widgets[W_expand_label]
26663 
26664 #define CONTRAST_SCROLLBAR(Sp)   Sp->widgets[W_contrast]
26665 #define CONTRAST_LABEL(Sp)       Sp->widgets[W_contrast_number]
26666 #define CONTRAST_RIGHT_BUTTON(Sp) Sp->widgets[W_contrast_button]
26667 #define CONTRAST_LEFT_BUTTON(Sp) Sp->widgets[W_contrast_label]
26668 
26669 #define REVSCL_SCROLLBAR(Sp)     Sp->widgets[W_revscl]
26670 #define REVLEN_SCROLLBAR(Sp)     Sp->widgets[W_revlen]
26671 #define REVSCL_LABEL(Sp)         Sp->widgets[W_revscl_number]
26672 #define REVLEN_LABEL(Sp)         Sp->widgets[W_revlen_number]
26673 #define REVSCL_BUTTON(Sp)        Sp->widgets[W_revscl_label]
26674 #define REVLEN_BUTTON(Sp)        Sp->widgets[W_revlen_label]
26675 #define REVERB_BUTTON(Sp)        Sp->widgets[W_reverb_button]
26676 
26677 #define FILTER_ORDER_TEXT(Sp)    Sp->widgets[W_filter_order]
26678 #define FILTER_COEFFS_TEXT(Sp)   Sp->widgets[W_filter]
26679 #define FILTER_BUTTON(Sp)        Sp->widgets[W_filter_button]
26680 #define FILTER_DB_BUTTON(Sp)     Sp->widgets[W_filter_dB]
26681 #define FILTER_HZ_BUTTON(Sp)     Sp->widgets[W_filter_hz]
26682 #define FILTER_LABEL(Sp)         Sp->widgets[W_filter_label]
26683 #define FILTER_GRAPH(Sp)         Sp->widgets[W_filter_env]
26684 #define FILTER_ORDER_UP(Sp)      Sp->widgets[W_filter_order_up]
26685 #define FILTER_ORDER_DOWN(Sp)    Sp->widgets[W_filter_order_down]
26686 #define FILTER_FRAME(Sp)         Sp->widgets[W_filter_frame]
26687 
26688 #define PROGRESS_ICON(Cp)        (Cp)->sound->progress_widgets[(Cp)->chan]
26689 
26690 
snd_pane_height(snd_info * sp)26691 int snd_pane_height(snd_info *sp)
26692 {
26693   Dimension height;
26694   XtVaGetValues(SND_PANE(sp), XmNheight, &height, NULL);
26695   return((int)height);
26696 }
26697 
26698 
set_status(snd_info * sp,const char * str,bool update)26699 void set_status(snd_info *sp, const char *str, bool update)
26700 {
26701   if ((sp->inuse != SOUND_NORMAL) || (!has_widgets(sp))) return;
26702   XmTextSetString(STATUS_AREA(sp), (char *)str);
26703   /* updating clears the entire graph widget and triggers an expose event -- this is evil if we're currently displaying! */
26704   /* there's also a bug in libxcb (fixed, but not propagated yet) that causes a segfault here if more than
26705    *   one thread is affected by this global X queue flush.
26706    */
26707 
26708   if (update) XmUpdateDisplay(STATUS_AREA(sp));
26709 }
26710 
26711 
name_click_callback(Widget w,XtPointer context,XtPointer info)26712 static void name_click_callback(Widget w, XtPointer context, XtPointer info)
26713 {
26714   char *str;
26715   snd_info *sp = (snd_info *)context;
26716   str = sp_name_click(sp);
26717   if (str)
26718     {
26719       status_report(sp, "%s", str);
26720       free(str);
26721     }
26722 }
26723 
26724 
stop_sign_click_callback(Widget w,XtPointer context,XtPointer info)26725 static void stop_sign_click_callback(Widget w, XtPointer context, XtPointer info)
26726 {
26727   snd_info *sp = (snd_info *)context;
26728   if ((ss->checking_explicitly) || (play_in_progress()))
26729     ss->stopped_explicitly = true;
26730   stop_playing_all_sounds(PLAY_C_G);
26731   if (sp->applying) stop_applying(sp);
26732   for_each_sound_chan(sp, stop_fft_in_progress);
26733 }
26734 
26735 
26736 /* The 0.9 * SCROLLBAR_MAX reflects the fact that the slider is 10% of the trough, and the left edge of the slider is the readback value */
26737 
26738 /* ---------------- AMP-CONTROL ---------------- */
26739 
amp_to_scroll(mus_float_t minval,mus_float_t val,mus_float_t maxval)26740 int amp_to_scroll(mus_float_t minval, mus_float_t val, mus_float_t maxval)
26741 {
26742   if (val <= minval) return(0);
26743   if (val >= maxval) return((int)(0.9 * SCROLLBAR_MAX));
26744   if (val >= 1.0)
26745     return(snd_round(0.9 * 0.5 * SCROLLBAR_MAX * (1.0 + (val - 1.0) / (maxval - 1.0))));
26746   return(snd_round(0.9 * 0.5 * SCROLLBAR_MAX * ((val - minval) / (1.0 - minval))));
26747 }
26748 
26749 
scroll_to_amp(snd_info * sp,int val)26750 static int scroll_to_amp(snd_info *sp, int val)
26751 {
26752   char amp_number_buffer[6];
26753   if (val <= 0)
26754     sp->amp_control = sp->amp_control_min;
26755   else
26756     {
26757       if (val >= (0.9 * SCROLLBAR_MAX))
26758 	sp->amp_control = sp->amp_control_max;
26759       else
26760 	{
26761 	  if (val > (0.5 * 0.9 * SCROLLBAR_MAX))
26762 	    sp->amp_control = (((val / (0.5 * 0.9 * SCROLLBAR_MAX)) - 1.0) * (sp->amp_control_max - 1.0)) + 1.0;
26763 	  else sp->amp_control = (val * (1.0 - sp->amp_control_min) / (0.5 * 0.9 * SCROLLBAR_MAX)) + sp->amp_control_min;
26764 	}
26765     }
26766   snprintf(amp_number_buffer, 6, "%.3f", sp->amp_control);
26767   set_label(AMP_LABEL(sp), amp_number_buffer);
26768   return(val);
26769 }
26770 
26771 
set_amp(snd_info * sp,mus_float_t val)26772 void set_amp(snd_info *sp, mus_float_t val)
26773 {
26774   if (!has_widgets(sp))
26775     sp->amp_control = val;
26776   else XtVaSetValues(AMP_SCROLLBAR(sp),
26777 		     XmNvalue,
26778 		     scroll_to_amp(sp, amp_to_scroll(sp->amp_control_min, val, sp->amp_control_max)),
26779 		     NULL);
26780 }
26781 
26782 
amp_click_callback(Widget w,XtPointer context,XtPointer info)26783 static void amp_click_callback(Widget w, XtPointer context, XtPointer info)
26784 {
26785   XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info;
26786   snd_info *sp = (snd_info *)context;
26787   XButtonEvent *ev;
26788   ev = (XButtonEvent *)(cb->event);
26789   if (ev->state & (ControlMask | MetaMask))
26790     set_amp(sp, sp->last_amp_control);
26791   else set_amp(sp, 1.0);
26792 }
26793 
26794 
amp_drag_callback(Widget w,XtPointer context,XtPointer info)26795 static void amp_drag_callback(Widget w, XtPointer context, XtPointer info)
26796 {
26797   scroll_to_amp((snd_info *)context, ((XmScrollBarCallbackStruct *)info)->value);
26798 }
26799 
26800 
amp_valuechanged_callback(Widget w,XtPointer context,XtPointer info)26801 static void amp_valuechanged_callback(Widget w, XtPointer context, XtPointer info)
26802 {
26803   XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info;
26804   snd_info *sp = (snd_info *)context;
26805   scroll_to_amp(sp, cb->value);
26806   sp->last_amp_control = sp->saved_amp_control;
26807   sp->saved_amp_control = sp->amp_control;
26808 }
26809 
26810 
26811 /* ---------------- SPEED-CONTROL ---------------- */
26812 
initial_speed_label(speed_style_t style)26813 XmString initial_speed_label(speed_style_t style)
26814 {
26815   /* used also in snd-xmix.c */
26816   switch (style)
26817     {
26818     case SPEED_CONTROL_AS_RATIO:    return(XmStringCreateLocalized((char *)"  1/1")); break;
26819     case SPEED_CONTROL_AS_SEMITONE: return(XmStringCreateLocalized((char *)"    0")); break;
26820     default:                        return(XmStringCreateLocalized((char *)" 1.00")); break;
26821     }
26822 }
26823 
26824 
speed_to_scroll(mus_float_t minval,mus_float_t val,mus_float_t maxval)26825 static int speed_to_scroll(mus_float_t minval, mus_float_t val, mus_float_t maxval)
26826 {
26827   if (val <= minval) return(0);
26828   if (val >= maxval) return((int)(0.9 * SCROLLBAR_MAX));
26829   return(snd_round(0.9 * SCROLLBAR_MAX * ((log(val) - log(minval)) / (log(maxval) - log(minval)))));
26830 }
26831 
26832 
scroll_to_speed(snd_info * sp,int ival)26833 static int scroll_to_speed(snd_info *sp, int ival)
26834 {
26835   char speed_number_buffer[6];
26836   sp->speed_control = speed_changed(exp((ival * (log(sp->speed_control_max) - log(sp->speed_control_min)) /
26837 					 (0.9 * SCROLLBAR_MAX)) +
26838 					log(sp->speed_control_min)),
26839 				    speed_number_buffer,
26840 				    sp->speed_control_style,
26841 				    sp->speed_control_tones,
26842 				    6);
26843   set_label(SPEED_LABEL(sp), speed_number_buffer);
26844   /* set_label works with buttons or labels */
26845   return(ival);
26846 }
26847 
26848 
set_speed(snd_info * sp,mus_float_t val)26849 void set_speed(snd_info *sp, mus_float_t val)
26850 {
26851   if (!has_widgets(sp))
26852     sp->speed_control = val;
26853   else XtVaSetValues(SPEED_SCROLLBAR(sp),
26854 		     XmNvalue,
26855 		     scroll_to_speed(sp, speed_to_scroll(sp->speed_control_min, val, sp->speed_control_max)),
26856 		     NULL);
26857 }
26858 
26859 
speed_click_callback(Widget w,XtPointer context,XtPointer info)26860 static void speed_click_callback(Widget w, XtPointer context, XtPointer info)
26861 {
26862   XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info;
26863   snd_info *sp = (snd_info *)context;
26864   XButtonEvent *ev;
26865 
26866 
26867   ev = (XButtonEvent *)(cb->event);
26868   if (ev->state & (ControlMask | MetaMask))
26869     set_speed(sp, sp->last_speed_control);
26870   else set_speed(sp, 1.0);
26871 
26872 #if XEN_HAVE_RATIOS
26873   if (sp->speed_control_style == SPEED_CONTROL_AS_RATIO)
26874     snd_rationalize(sp->speed_control, &(sp->speed_control_numerator), &(sp->speed_control_denominator));
26875 #endif
26876 }
26877 
26878 
speed_label_click_callback(Widget w,XtPointer context,XtPointer info)26879 static void speed_label_click_callback(Widget w, XtPointer context, XtPointer info)
26880 {
26881   snd_info *sp = (snd_info *)context;
26882   switch (sp->speed_control_style)
26883     {
26884     default:
26885     case SPEED_CONTROL_AS_FLOAT:    sp->speed_control_style = SPEED_CONTROL_AS_RATIO;    break;
26886     case SPEED_CONTROL_AS_RATIO:    sp->speed_control_style = SPEED_CONTROL_AS_SEMITONE; break;
26887     case SPEED_CONTROL_AS_SEMITONE: sp->speed_control_style = SPEED_CONTROL_AS_FLOAT;    break;
26888     }
26889   set_speed(sp, sp->speed_control);  /* remake label */
26890 }
26891 
26892 
speed_drag_callback(Widget w,XtPointer context,XtPointer info)26893 static void speed_drag_callback(Widget w, XtPointer context, XtPointer info)
26894 {
26895   snd_info *sp = (snd_info *)context;
26896   scroll_to_speed(sp, ((XmScrollBarCallbackStruct *)info)->value);
26897 
26898 #if XEN_HAVE_RATIOS
26899   if (sp->speed_control_style == SPEED_CONTROL_AS_RATIO)
26900     snd_rationalize(sp->speed_control, &(sp->speed_control_numerator), &(sp->speed_control_denominator));
26901 #endif
26902 }
26903 
26904 
speed_valuechanged_callback(Widget w,XtPointer context,XtPointer info)26905 static void speed_valuechanged_callback(Widget w, XtPointer context, XtPointer info)
26906 {
26907   XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info;
26908   snd_info *sp = (snd_info *)context;
26909   scroll_to_speed(sp, cb->value);
26910 
26911 #if XEN_HAVE_RATIOS
26912   if (sp->speed_control_style == SPEED_CONTROL_AS_RATIO)
26913     snd_rationalize(sp->speed_control, &(sp->speed_control_numerator), &(sp->speed_control_denominator));
26914 #endif
26915   sp->last_speed_control = sp->saved_speed_control;
26916   sp->saved_speed_control = sp->speed_control;
26917 }
26918 
26919 
toggle_direction_arrow(snd_info * sp,bool state)26920 void toggle_direction_arrow(snd_info *sp, bool state)
26921 {
26922   if (!has_widgets(sp))
26923     sp->speed_control_direction = ((state) ? -1 : 1);
26924   else XmToggleButtonSetState(SPEED_ARROW(sp), (Boolean)state, true);
26925 }
26926 
26927 
26928 /* ---------------- EXPAND-CONTROL ---------------- */
26929 
expand_to_scroll(mus_float_t minval,mus_float_t val,mus_float_t maxval)26930 static int expand_to_scroll(mus_float_t minval, mus_float_t val, mus_float_t maxval)
26931 {
26932   if (val <= minval) return(0);
26933   if (val >= maxval) return((int)(0.9 * SCROLLBAR_MAX));
26934   return(snd_round(0.9 * SCROLLBAR_MAX * ((log(val) - log(minval)) / (log(maxval) - log(minval)))));
26935 }
26936 
26937 
scroll_to_expand(snd_info * sp,int val)26938 static int scroll_to_expand(snd_info *sp, int val)
26939 {
26940   char expand_number_buffer[6];
26941 
26942   if (val <= 0)
26943     sp->expand_control = sp->expand_control_min;
26944   else
26945     {
26946       if (val >= (0.9 * SCROLLBAR_MAX))
26947 	sp->expand_control = sp->expand_control_max;
26948       else sp->expand_control = exp((val * (log(sp->expand_control_max) - log(sp->expand_control_min)) / (0.9 * SCROLLBAR_MAX)) + log(sp->expand_control_min));
26949     }
26950 
26951   if (sp->playing) dac_set_expand(sp, sp->expand_control);
26952   snprintf(expand_number_buffer, 6, "%.3f", sp->expand_control);
26953   set_label(EXPAND_LABEL(sp), expand_number_buffer);
26954   return(val);
26955 }
26956 
26957 
set_expand(snd_info * sp,mus_float_t val)26958 void set_expand(snd_info *sp, mus_float_t val)
26959 {
26960   if (!has_widgets(sp))
26961     sp->expand_control = val;
26962   else XtVaSetValues(EXPAND_SCROLLBAR(sp),
26963 		     XmNvalue,
26964 		     scroll_to_expand(sp, expand_to_scroll(sp->expand_control_min, val, sp->expand_control_max)),
26965 		     NULL);
26966 }
26967 
26968 
expand_click_callback(Widget w,XtPointer context,XtPointer info)26969 static void expand_click_callback(Widget w, XtPointer context, XtPointer info)
26970 {
26971   XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info;
26972   snd_info *sp = (snd_info *)context;
26973   XButtonEvent *ev;
26974   ev = (XButtonEvent *)(cb->event);
26975   if (ev->state & (ControlMask | MetaMask))
26976     set_expand(sp, sp->last_expand_control);
26977   else set_expand(sp, 1.0);
26978 }
26979 
26980 
expand_drag_callback(Widget w,XtPointer context,XtPointer info)26981 static void expand_drag_callback(Widget w, XtPointer context, XtPointer info)
26982 {
26983   scroll_to_expand((snd_info *)context, ((XmScrollBarCallbackStruct *)info)->value);
26984 }
26985 
26986 
expand_valuechanged_callback(Widget w,XtPointer context,XtPointer info)26987 static void expand_valuechanged_callback(Widget w, XtPointer context, XtPointer info)
26988 {
26989   XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info;
26990   snd_info *sp = (snd_info *)context;
26991   scroll_to_expand(sp, cb->value);
26992   sp->last_expand_control = sp->saved_expand_control;
26993   sp->saved_expand_control = sp->expand_control;
26994 }
26995 
26996 
expand_button_callback(Widget w,XtPointer context,XtPointer info)26997 static void expand_button_callback(Widget w, XtPointer context, XtPointer info)
26998 {
26999   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
27000   snd_info *sp = (snd_info *)context;
27001 
27002 
27003   sp->expand_control_on = cb->set;
27004   XmChangeColor(EXPAND_SCROLLBAR(sp), (Pixel)((sp->expand_control_on) ? (ss->position_color) : (ss->basic_color)));
27005 }
27006 
27007 
toggle_expand_button(snd_info * sp,bool state)27008 void toggle_expand_button(snd_info *sp, bool state)
27009 {
27010   if (!has_widgets(sp))
27011     sp->expand_control_on = state;
27012   else XmToggleButtonSetState(EXPAND_RIGHT_BUTTON(sp), (Boolean)state, true);
27013 }
27014 
27015 
27016 /* ---------------- CONTRAST-CONTROL ---------------- */
27017 
contrast_to_scroll(mus_float_t minval,mus_float_t val,mus_float_t maxval)27018 static int contrast_to_scroll(mus_float_t minval, mus_float_t val, mus_float_t maxval)
27019 {
27020   if (val <= minval) return(0);
27021   if (val >= maxval) return((int)(0.9 * SCROLLBAR_MAX));
27022   return(snd_round((val - minval) / (maxval - minval) * 0.9 * SCROLLBAR_MAX));
27023 }
27024 
27025 
scroll_to_contrast(snd_info * sp,int val)27026 static int scroll_to_contrast(snd_info *sp, int val)
27027 {
27028   char contrast_number_buffer[6];
27029   sp->contrast_control = sp->contrast_control_min + val * (sp->contrast_control_max - sp->contrast_control_min) / (0.9 * SCROLLBAR_MAX);
27030   snprintf(contrast_number_buffer, 6, "%.3f", sp->contrast_control);
27031   set_label(CONTRAST_LABEL(sp), contrast_number_buffer);
27032   return(val);
27033 }
27034 
27035 
set_contrast(snd_info * sp,mus_float_t val)27036 void set_contrast(snd_info *sp, mus_float_t val)
27037 {
27038   if (!has_widgets(sp))
27039     sp->contrast_control = val;
27040   else XtVaSetValues(CONTRAST_SCROLLBAR(sp),
27041 		     XmNvalue,
27042 		     scroll_to_contrast(sp, contrast_to_scroll(sp->contrast_control_min, val, sp->contrast_control_max)),
27043 		     NULL);
27044 }
27045 
27046 
contrast_click_callback(Widget w,XtPointer context,XtPointer info)27047 static void contrast_click_callback(Widget w, XtPointer context, XtPointer info)
27048 {
27049   XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info;
27050   snd_info *sp = (snd_info *)context;
27051   XButtonEvent *ev;
27052   ev = (XButtonEvent *)(cb->event);
27053   if (ev->state & (ControlMask | MetaMask))
27054     set_contrast(sp, sp->last_contrast_control);
27055   else set_contrast(sp, 0.0);
27056 }
27057 
27058 
contrast_drag_callback(Widget w,XtPointer context,XtPointer info)27059 static void contrast_drag_callback(Widget w, XtPointer context, XtPointer info)
27060 {
27061   scroll_to_contrast((snd_info *)context, ((XmScrollBarCallbackStruct *)info)->value);
27062 }
27063 
27064 
contrast_valuechanged_callback(Widget w,XtPointer context,XtPointer info)27065 static void contrast_valuechanged_callback(Widget w, XtPointer context, XtPointer info)
27066 {
27067   XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info;
27068   snd_info *sp = (snd_info *)context;
27069   scroll_to_contrast(sp, cb->value);
27070   sp->last_contrast_control = sp->saved_contrast_control;
27071   sp->saved_contrast_control = sp->contrast_control;
27072 }
27073 
27074 
contrast_button_callback(Widget w,XtPointer context,XtPointer info)27075 static void contrast_button_callback(Widget w, XtPointer context, XtPointer info)
27076 {
27077   snd_info *sp = (snd_info *)context;
27078   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
27079   sp->contrast_control_on = cb->set;
27080   XmChangeColor(CONTRAST_SCROLLBAR(sp), (Pixel)((sp->contrast_control_on) ? (ss->position_color) : (ss->basic_color)));
27081 }
27082 
27083 
toggle_contrast_button(snd_info * sp,bool state)27084 void toggle_contrast_button(snd_info *sp, bool state)
27085 {
27086   if (!has_widgets(sp))
27087     sp->contrast_control_on = state;
27088   else XmToggleButtonSetState(CONTRAST_RIGHT_BUTTON(sp), (Boolean)state, true);
27089 }
27090 
27091 
27092 /* ---------------- REVERB-CONTROL-SCALE ---------------- */
27093 
revscl_to_scroll(mus_float_t minval,mus_float_t val,mus_float_t maxval)27094 static int revscl_to_scroll(mus_float_t minval, mus_float_t val, mus_float_t maxval)
27095 {
27096   if (val <= minval) return(0);
27097   if (val >= maxval) return((int)(0.9 * SCROLLBAR_MAX));
27098   return(snd_round(0.9 * SCROLLBAR_MAX * (pow(val, 0.333) - pow(minval, 0.333)) / (pow(maxval, 0.333) - pow(minval, 0.333))));
27099 }
27100 
27101 
27102 /* static mus_float_t cube(mus_float_t a) {return(a*a*a);} */
27103 
27104 
scroll_to_revscl(snd_info * sp,int val)27105 static int scroll_to_revscl(snd_info *sp, int val)
27106 {
27107   char revscl_number_buffer[7];
27108 
27109   if (val <= 0)
27110     sp->reverb_control_scale = sp->reverb_control_scale_min;
27111   else
27112     {
27113       if (val >= (0.9 * SCROLLBAR_MAX))
27114 	sp->reverb_control_scale = sp->reverb_control_scale_max;
27115       else sp->reverb_control_scale = cube((val * (pow(sp->reverb_control_scale_max, 0.333) - pow(sp->reverb_control_scale_min, 0.333)) /
27116 					    (0.9 * SCROLLBAR_MAX)) +
27117 					   pow(sp->reverb_control_scale_min, 0.333));
27118     }
27119 
27120   snprintf(revscl_number_buffer, 7, "%.4f", sp->reverb_control_scale);
27121   set_label(REVSCL_LABEL(sp), revscl_number_buffer);
27122   return(val);
27123 }
27124 
27125 
set_revscl(snd_info * sp,mus_float_t val)27126 void set_revscl(snd_info *sp, mus_float_t val)
27127 {
27128   if (!has_widgets(sp))
27129     sp->reverb_control_scale = val;
27130   else XtVaSetValues(REVSCL_SCROLLBAR(sp),
27131 		     XmNvalue,
27132 		     scroll_to_revscl(sp, revscl_to_scroll(sp->reverb_control_scale_min, val, sp->reverb_control_scale_max)),
27133 		     NULL);
27134 }
27135 
27136 
revscl_click_callback(Widget w,XtPointer context,XtPointer info)27137 static void revscl_click_callback(Widget w, XtPointer context, XtPointer info)
27138 {
27139   XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info;
27140   snd_info *sp = (snd_info *)context;
27141   XButtonEvent *ev;
27142   ev = (XButtonEvent *)(cb->event);
27143   if (ev->state & (ControlMask | MetaMask))
27144     set_revscl(sp, sp->last_reverb_control_scale);
27145   else set_revscl(sp, 0.0);
27146 }
27147 
27148 
revscl_drag_callback(Widget w,XtPointer context,XtPointer info)27149 static void revscl_drag_callback(Widget w, XtPointer context, XtPointer info)
27150 {
27151   scroll_to_revscl((snd_info *)context, ((XmScrollBarCallbackStruct *)info)->value);
27152 }
27153 
27154 
revscl_valuechanged_callback(Widget w,XtPointer context,XtPointer info)27155 static void revscl_valuechanged_callback(Widget w, XtPointer context, XtPointer info)
27156 {
27157   XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info;
27158   snd_info *sp = (snd_info *)context;
27159   scroll_to_revscl(sp, cb->value);
27160   sp->last_reverb_control_scale = sp->saved_reverb_control_scale;
27161   sp->saved_reverb_control_scale = sp->reverb_control_scale;
27162 }
27163 
27164 
27165 /* ---------------- REVERB-CONTROL-LENGTH ---------------- */
27166 
revlen_to_scroll(mus_float_t minval,mus_float_t val,mus_float_t maxval)27167 static int revlen_to_scroll(mus_float_t minval, mus_float_t val, mus_float_t maxval)
27168 {
27169   if (val <= minval) return(0);
27170   if (val >= maxval) return((int)(0.9 * SCROLLBAR_MAX));
27171   return(snd_round((val - minval) / (maxval - minval) * 0.9 * SCROLLBAR_MAX));
27172 }
27173 
27174 
scroll_to_revlen(snd_info * sp,int val)27175 static int scroll_to_revlen(snd_info *sp, int val)
27176 {
27177   char revlen_number_buffer[5];
27178 
27179   sp->reverb_control_length = sp->reverb_control_length_min +
27180     (sp->reverb_control_length_max - sp->reverb_control_length_min) * (mus_float_t)val / (0.9 * SCROLLBAR_MAX);
27181   snprintf(revlen_number_buffer, 5, "%.2f", sp->reverb_control_length);
27182   set_label(REVLEN_LABEL(sp), revlen_number_buffer);
27183   return(val);
27184 }
27185 
27186 
set_revlen(snd_info * sp,mus_float_t val)27187 void set_revlen(snd_info *sp, mus_float_t val)
27188 {
27189   if (!has_widgets(sp))
27190     sp->reverb_control_length = val;
27191   else XtVaSetValues(REVLEN_SCROLLBAR(sp),
27192 		     XmNvalue,
27193 		     scroll_to_revlen(sp, revlen_to_scroll(sp->reverb_control_length_min, val, sp->reverb_control_length_max)),
27194 		     NULL);
27195 }
27196 
27197 
revlen_click_callback(Widget w,XtPointer context,XtPointer info)27198 static void revlen_click_callback(Widget w, XtPointer context, XtPointer info)
27199 {
27200   XmPushButtonCallbackStruct *cb = (XmPushButtonCallbackStruct *)info;
27201   snd_info *sp = (snd_info *)context;
27202   XButtonEvent *ev;
27203   ev = (XButtonEvent *)(cb->event);
27204   if (ev->state & (ControlMask | MetaMask))
27205     set_revlen(sp, sp->last_reverb_control_length);
27206   else set_revlen(sp, 1.0);
27207 }
27208 
27209 
revlen_drag_callback(Widget w,XtPointer context,XtPointer info)27210 static void revlen_drag_callback(Widget w, XtPointer context, XtPointer info)
27211 {
27212   scroll_to_revlen((snd_info *)context, ((XmScrollBarCallbackStruct *)info)->value);
27213 }
27214 
27215 
revlen_valuechanged_callback(Widget w,XtPointer context,XtPointer info)27216 static void revlen_valuechanged_callback(Widget w, XtPointer context, XtPointer info)
27217 {
27218   XmScrollBarCallbackStruct *cb = (XmScrollBarCallbackStruct *)info;
27219   snd_info *sp = (snd_info *)context;
27220   scroll_to_revlen(sp, cb->value);
27221   sp->last_reverb_control_length = sp->saved_reverb_control_length;
27222   sp->saved_reverb_control_length = sp->reverb_control_length;
27223 }
27224 
27225 
reverb_button_callback(Widget w,XtPointer context,XtPointer info)27226 static void reverb_button_callback(Widget w, XtPointer context, XtPointer info)
27227 {
27228   snd_info *sp = (snd_info *)context;
27229   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
27230   sp->reverb_control_on = cb->set;
27231   XmChangeColor(REVLEN_SCROLLBAR(sp), (Pixel)((sp->reverb_control_on) ? (ss->position_color) : (ss->basic_color)));
27232   XmChangeColor(REVSCL_SCROLLBAR(sp), (Pixel)((sp->reverb_control_on) ? (ss->position_color) : (ss->basic_color)));
27233 }
27234 
27235 
toggle_reverb_button(snd_info * sp,bool state)27236 void toggle_reverb_button(snd_info *sp, bool state)
27237 {
27238   if (!has_widgets(sp))
27239     sp->reverb_control_on = state;
27240   else XmToggleButtonSetState(REVERB_BUTTON(sp), (Boolean)state, true);
27241 }
27242 
27243 
27244 /* ---------------- FILTER_CONTROL ---------------- */
27245 
filter_button_callback(Widget w,XtPointer context,XtPointer info)27246 static void filter_button_callback(Widget w, XtPointer context, XtPointer info)
27247 {
27248   snd_info *sp = (snd_info *)context;
27249   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
27250   sp->filter_control_on = cb->set;
27251 }
27252 
27253 
toggle_filter_button(snd_info * sp,bool state)27254 void toggle_filter_button(snd_info *sp, bool state)
27255 {
27256   if (!has_widgets(sp))
27257     sp->filter_control_on = state;
27258   else XmToggleButtonSetState(FILTER_BUTTON(sp), (Boolean)state, true);
27259 }
27260 
27261 
filter_textfield_deactivate(snd_info * sp)27262 static void filter_textfield_deactivate(snd_info *sp)
27263 {
27264   chan_info *active_chan;
27265   active_chan = any_selected_channel(sp);
27266   if (active_chan)
27267     goto_window(channel_graph(active_chan));
27268 }
27269 
27270 
27271 #define MIN_FILTER_GRAPH_HEIGHT 20
27272 
display_filter_env(snd_info * sp)27273 void display_filter_env(snd_info *sp)
27274 {
27275   graphics_context *ax;
27276   int height, width;
27277   Widget drawer;
27278   env_editor *edp;
27279 
27280   if (!(snd_ok(sp))) return; /* autotest close + lagging X updates */
27281 
27282   edp = sp->flt;
27283   drawer = FILTER_GRAPH(sp);
27284   height = widget_height(drawer);
27285   if (height < MIN_FILTER_GRAPH_HEIGHT) return;
27286 
27287   width = widget_width(drawer);
27288   ax = (graphics_context *)calloc(1, sizeof(graphics_context));
27289   ax->gc = ss->fltenv_basic_gc;
27290   ax->wn = XtWindow(drawer);
27291   ax->dp = XtDisplay(drawer);
27292 
27293   XClearWindow(ax->dp, ax->wn);
27294   edp->in_dB = sp->filter_control_in_dB;
27295   edp->with_dots = true;
27296 
27297   if (sp->filter_control_in_hz)
27298     sp->filter_control_xmax = (mus_float_t)(snd_srate(sp) / 2);
27299   else sp->filter_control_xmax = 1.0;
27300 
27301   if (!sp->filter_control_envelope)
27302     sp->filter_control_envelope = default_env(sp->filter_control_xmax, 1.0);
27303 
27304   env_editor_display_env(edp, sp->filter_control_envelope, ax, "frequency response", 0, 0, width, height, NOT_PRINTING);
27305   if (edp->edited)
27306     {
27307       ax->gc = ss->fltenv_data_gc;
27308       display_frequency_response(sp->filter_control_envelope,
27309 				 (sound_env_editor(sp))->axis, ax,
27310 				 sp->filter_control_order,
27311 				 sp->filter_control_in_dB);
27312     }
27313   free(ax);
27314 }
27315 
27316 
set_filter_text(snd_info * sp,const char * str)27317 void set_filter_text(snd_info *sp, const char *str)
27318 {
27319   if (has_widgets(sp))
27320     XmTextSetString(FILTER_COEFFS_TEXT(sp), (char *)str);
27321 }
27322 
27323 
filter_drawer_button_motion(Widget w,XtPointer context,XEvent * event,Boolean * cont)27324 static void filter_drawer_button_motion(Widget w, XtPointer context, XEvent *event, Boolean *cont)
27325 {
27326   snd_info *sp = (snd_info *)context;
27327   XMotionEvent *ev = (XMotionEvent *)event;
27328   env_editor *edp;
27329 #ifdef __APPLE__
27330   if ((press_x == ev->x) && (press_y == ev->y)) return;
27331 #endif
27332   edp = sp->flt;
27333   edp->in_dB = sp->filter_control_in_dB;
27334   env_editor_button_motion(edp, ev->x, ev->y, ev->time, sp->filter_control_envelope);
27335   display_filter_env(sp);
27336   sp->filter_control_changed = true;
27337 }
27338 
27339 
filter_drawer_button_press(Widget w,XtPointer context,XEvent * event,Boolean * cont)27340 static void filter_drawer_button_press(Widget w, XtPointer context, XEvent *event, Boolean *cont)
27341 {
27342   snd_info *sp = (snd_info *)context;
27343   XButtonEvent *ev = (XButtonEvent *)event;
27344   env_editor *edp;
27345   if (!(sp->filter_control_envelope)) return;
27346 #ifdef __APPLE__
27347   press_x = ev->x;
27348   press_y = ev->y;
27349 #endif
27350   edp = sp->flt;
27351   edp->in_dB = sp->filter_control_in_dB;
27352   if (env_editor_button_press(edp, ev->x, ev->y, ev->time, sp->filter_control_envelope))
27353     display_filter_env(sp);
27354 }
27355 
27356 
filter_drawer_button_release(Widget w,XtPointer context,XEvent * event,Boolean * cont)27357 static void filter_drawer_button_release(Widget w, XtPointer context, XEvent *event, Boolean *cont)
27358 {
27359   char *tmpstr = NULL;
27360   snd_info *sp = (snd_info *)context;
27361   env_editor_button_release(sound_env_editor(sp), sp->filter_control_envelope);
27362   display_filter_env(sp);
27363   set_filter_text(sp, tmpstr = env_to_string(sp->filter_control_envelope));
27364   if (tmpstr) free(tmpstr);
27365   sp->filter_control_changed = true;
27366 }
27367 
27368 
filter_drawer_resize(Widget w,XtPointer context,XtPointer info)27369 static void filter_drawer_resize(Widget w, XtPointer context, XtPointer info)
27370 {
27371   snd_info *sp = (snd_info *)context;
27372   display_filter_env(sp);
27373 }
27374 
27375 
filter_dB_callback(Widget w,XtPointer context,XtPointer info)27376 static void filter_dB_callback(Widget w, XtPointer context, XtPointer info)
27377 {
27378   snd_info *sp = (snd_info *)context;
27379   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
27380   sp->filter_control_in_dB = (cb->set);
27381   display_filter_env(sp);
27382 }
27383 
27384 
set_filter_in_dB(snd_info * sp,bool val)27385 void set_filter_in_dB(snd_info *sp, bool val)
27386 {
27387   sp->filter_control_in_dB = val;
27388   if (has_widgets(sp))
27389     {
27390       XmToggleButtonSetState(FILTER_DB_BUTTON(sp), (Boolean)val, false);
27391       display_filter_env(sp);
27392     }
27393 }
27394 
27395 
new_in_hz(snd_info * sp,bool val)27396 static void new_in_hz(snd_info *sp, bool val)
27397 {
27398   sp->filter_control_in_hz = val;
27399   if (val)
27400     sp->filter_control_xmax = (mus_float_t)(snd_srate(sp) / 2);
27401   else sp->filter_control_xmax = 1.0;
27402   if (sp->filter_control_envelope) free_env(sp->filter_control_envelope);
27403   sp->filter_control_envelope = default_env(sp->filter_control_xmax, 1.0);
27404 }
27405 
27406 
filter_hz_callback(Widget w,XtPointer context,XtPointer info)27407 static void filter_hz_callback(Widget w, XtPointer context, XtPointer info)
27408 {
27409   snd_info *sp = (snd_info *)context;
27410   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
27411   new_in_hz(sp, cb->set);
27412   display_filter_env(sp);
27413 }
27414 
27415 
set_filter_in_hz(snd_info * sp,bool val)27416 void set_filter_in_hz(snd_info *sp, bool val)
27417 {
27418   new_in_hz(sp, val);
27419   if (has_widgets(sp))
27420     {
27421       XmToggleButtonSetState(FILTER_HZ_BUTTON(sp), (Boolean)val, false);
27422       display_filter_env(sp);
27423     }
27424 }
27425 
27426 
set_filter_order(snd_info * sp,int order)27427 void set_filter_order(snd_info *sp, int order)
27428 {
27429   if (order & 1) order++;
27430   if (order <= 0) order = 2;
27431   sp->filter_control_order = order;
27432   if (has_widgets(sp))
27433     {
27434       widget_int_to_text(FILTER_ORDER_TEXT(sp), order);
27435       display_filter_env(sp);
27436     }
27437   sp->filter_control_changed = true;
27438 }
27439 
27440 
filter_order_up_callback(Widget w,XtPointer context,XtPointer info)27441 static void filter_order_up_callback(Widget w, XtPointer context, XtPointer info)
27442 {
27443   snd_info *sp = (snd_info *)context;
27444   set_filter_order(sp, sp->filter_control_order + 2);
27445 }
27446 
27447 
filter_order_down_callback(Widget w,XtPointer context,XtPointer info)27448 static void filter_order_down_callback(Widget w, XtPointer context, XtPointer info)
27449 {
27450   snd_info *sp = (snd_info *)context;
27451   if (sp->filter_control_order > 2)
27452     set_filter_order(sp, sp->filter_control_order - 2);
27453 }
27454 
27455 
get_filter_order(snd_info * sp,char * str)27456 static void get_filter_order(snd_info *sp, char *str)
27457 {
27458   int order;
27459   redirect_errors_to(errors_to_status_area, (void *)sp);
27460   order = string_to_int(str, 1, "filter order");
27461   redirect_errors_to(NULL, NULL);
27462   if (order & 1) order++;
27463   if (order <= 0) order = 2;
27464   sp->filter_control_order = order;
27465 }
27466 
27467 
filter_activate_callback(Widget w,XtPointer context,XtPointer info)27468 static void filter_activate_callback(Widget w, XtPointer context, XtPointer info)
27469 {
27470   /* make an envelope out of the data */
27471   snd_info *sp = (snd_info *)context;
27472   char *str = NULL;
27473 
27474   str = XmTextGetString(w);
27475   if (sp->filter_control_envelope) sp->filter_control_envelope = free_env(sp->filter_control_envelope);
27476   redirect_errors_to(errors_to_status_area, (void *)sp);
27477   sp->filter_control_envelope = string_to_env((const char *)str);
27478   redirect_errors_to(NULL, NULL);
27479   if (str) XtFree(str);
27480 
27481   if (!(sp->filter_control_envelope)) /* maybe user cleared text field? */
27482     sp->filter_control_envelope = default_env(sp->filter_control_xmax, 1.0);
27483 
27484   str = XmTextGetString(FILTER_ORDER_TEXT(sp));
27485   if ((str) && (*str))
27486     {
27487       get_filter_order(sp, str);
27488       XtFree(str);
27489     }
27490   (sound_env_editor(sp))->edited = true;
27491   display_filter_env(sp);
27492   filter_textfield_deactivate(sp);
27493   sp->filter_control_changed = true;
27494 }
27495 
27496 
filter_order_activate_callback(Widget w,XtPointer context,XtPointer info)27497 static void filter_order_activate_callback(Widget w, XtPointer context, XtPointer info)
27498 {
27499   char *str;
27500   snd_info *sp = (snd_info *)context;
27501   str = XmTextGetString(w);
27502   if ((str) && (*str))
27503     {
27504       get_filter_order(sp, str);
27505       sp->filter_control_changed = true;
27506       display_filter_env(sp);
27507       XtFree(str);
27508     }
27509   filter_textfield_deactivate(sp);
27510 }
27511 
27512 
filter_env_changed(snd_info * sp,env * e)27513 void filter_env_changed(snd_info *sp, env *e)
27514 {
27515   /* turn e back into a string for textfield widget */
27516   if (has_widgets(sp))
27517     {
27518       char *tmpstr = NULL;
27519       XmTextSetString(FILTER_COEFFS_TEXT(sp), tmpstr = env_to_string(e));
27520       if (tmpstr) free(tmpstr);
27521       (sound_env_editor(sp))->edited = true;
27522       display_filter_env(sp);
27523     }
27524   sp->filter_control_changed = true;
27525 }
27526 
27527 
27528 /* ---------------- PLAY BUTTON ---------------- */
27529 
set_play_button(snd_info * sp,bool val)27530 void set_play_button(snd_info *sp, bool val)
27531 {
27532 #if WITH_AUDIO
27533   if (has_widgets(sp))
27534     XmToggleButtonSetState(PLAY_BUTTON(sp), (Boolean)val, false);
27535   set_open_file_play_button(val);
27536 #endif
27537 }
27538 
27539 
27540 #if WITH_AUDIO
play_button_callback(Widget w,XtPointer context,XtPointer info)27541 static void play_button_callback(Widget w, XtPointer context, XtPointer info)
27542 {
27543   snd_info *sp = (snd_info *)context;
27544   chan_info *cp;
27545   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
27546   XButtonEvent *ev;
27547 
27548   ev = (XButtonEvent *)(cb->event);
27549 
27550   if (sp->playing)
27551     stop_playing_sound(sp, PLAY_BUTTON_UNSET);
27552 
27553   ss->tracking = ((with_tracking_cursor(ss) != DONT_TRACK) ||
27554 		  ((cb->set) &&
27555 		   (ev->state & (ControlMask | MetaMask))));
27556 
27557   cp = any_selected_channel(sp);
27558   goto_graph(cp);
27559   if (cb->set)
27560     {
27561       XtVaSetValues(w, XmNselectColor, (ss->tracking) ? ss->green : ss->selection_color, NULL);
27562       play_sound(sp, 0, NO_END_SPECIFIED);
27563     }
27564 }
27565 #endif
27566 
27567 
27568 typedef struct {bool pausing; } pause_data;
27569 
27570 #if WITH_AUDIO
set_play_button_pause(snd_info * sp,void * ptr)27571 static void set_play_button_pause(snd_info *sp, void *ptr)
27572 {
27573   if ((sp->playing) && (has_widgets(sp)))
27574     {
27575       pause_data *pd = (pause_data *)ptr;
27576       Widget w;
27577       w = PLAY_BUTTON(sp);
27578       if (pd->pausing)
27579 	XtVaSetValues(w, XmNselectColor, ss->red, NULL);
27580       else XtVaSetValues(w, XmNselectColor, (ss->tracking) ? ss->green : ss->selection_color, NULL);
27581     }
27582 }
27583 #endif
27584 
27585 
play_button_pause(bool pausing)27586 void play_button_pause(bool pausing)
27587 {
27588 #if WITH_AUDIO
27589   pause_data *pd;
27590   pd = (pause_data *)calloc(1, sizeof(pause_data));
27591   pd->pausing = pausing;
27592   for_each_sound_with_void(set_play_button_pause, (void *)pd);
27593   free(pd);
27594 #endif
27595 }
27596 
27597 
set_control_panel_play_button(snd_info * sp)27598 void set_control_panel_play_button(snd_info *sp)
27599 {
27600 #if WITH_AUDIO
27601   if (has_widgets(sp))
27602     {
27603       set_toggle_button(PLAY_BUTTON(sp), false, false, sp);
27604       XtVaSetValues(PLAY_BUTTON(sp), XmNselectColor, ss->selection_color, NULL);
27605     }
27606 #endif
27607 }
27608 
27609 
play_arrow_callback(Widget w,XtPointer context,XtPointer info)27610 static void play_arrow_callback(Widget w, XtPointer context, XtPointer info)
27611 {
27612 #if WITH_AUDIO
27613   snd_info *sp = (snd_info *)context;
27614   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
27615   bool dir;
27616   dir = (bool)(cb->set);
27617   if (dir) sp->speed_control_direction = -1; else sp->speed_control_direction = 1;
27618 #endif
27619 }
27620 
27621 
27622 /* ---------------- SYNC BUTTON ---------------- */
27623 
set_sync_color(snd_info * sp)27624 static void set_sync_color(snd_info *sp)
27625 {
27626   Widget syb;
27627   syb = SYNC_BUTTON(sp);
27628   switch (sp->sync)
27629     {
27630     case 1: case 0: XtVaSetValues(syb, XmNselectColor, ss->selection_color, NULL); break;
27631     case 2:         XtVaSetValues(syb, XmNselectColor, ss->green, NULL);               break;
27632     case 3:         XtVaSetValues(syb, XmNselectColor, ss->yellow, NULL);              break;
27633     case 4:         XtVaSetValues(syb, XmNselectColor, ss->red, NULL);                 break;
27634     default:        XtVaSetValues(syb, XmNselectColor, ss->black, NULL);               break;
27635     }
27636 }
27637 
27638 
syncb(snd_info * sp,int on)27639 void syncb(snd_info *sp, int on)
27640 {
27641   sp->sync = on;
27642   if (on > ss->sound_sync_max) ss->sound_sync_max = on;
27643   if (has_widgets(sp))
27644     {
27645       set_sync_color(sp);
27646       XmToggleButtonSetState(SYNC_BUTTON(sp), (on != 0), false); /* need actual bool here, not a cast! */
27647     }
27648 }
27649 
27650 
sync_button_callback(Widget w,XtPointer context,XtPointer info)27651 static void sync_button_callback(Widget w, XtPointer context, XtPointer info)
27652 {
27653   snd_info *sp = (snd_info *)context;
27654   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
27655   XButtonEvent *ev;
27656 
27657 
27658   ev = (XButtonEvent *)(cb->event);
27659   if (cb->set)
27660     if (ev->state & ControlMask)
27661       if (ev->state & MetaMask)
27662 	if (ev->state & ShiftMask)
27663 	  sp->sync = 4;
27664 	else sp->sync = 3;
27665       else sp->sync = 2;
27666     else sp->sync = 1;
27667   else sp->sync = 0;
27668 
27669   set_sync_color(sp);
27670 
27671   if (sp->sync != 0)
27672     {
27673       chan_info *cp;
27674       if (sp->sync > ss->sound_sync_max) ss->sound_sync_max = sp->sync;
27675       cp = sp->lacp;
27676       if (!cp) cp = any_selected_channel(sp);
27677       goto_graph(cp);
27678       if (cp->cursor_on) sync_cursors(cp, cursor_sample(cp));
27679       apply_x_axis_change(cp);
27680     }
27681 }
27682 
27683 
27684 /* ---------------- UNITE BUTTON ---------------- */
27685 
unite_button_callback(Widget w,XtPointer context,XtPointer info)27686 static void unite_button_callback(Widget w, XtPointer context, XtPointer info)
27687 {
27688   /* click if set unsets, click if unset->combine, ctrl-click->superimpose */
27689   snd_info *sp = (snd_info *)context;
27690   XmToggleButtonCallbackStruct *cb = (XmToggleButtonCallbackStruct *)info;
27691   XButtonEvent *ev;
27692   channel_style_t val;
27693   ev = (XButtonEvent *)(cb->event);
27694 
27695   if (cb->set)
27696     {
27697       if (ev->state & (ControlMask | MetaMask))
27698 	val = CHANNELS_SUPERIMPOSED;
27699       else val = CHANNELS_COMBINED;
27700     }
27701   else val = CHANNELS_SEPARATE;
27702 
27703   set_sound_channel_style(sp, val);
27704 }
27705 
27706 
27707 /* ---------------- CLOSE BUTTON ---------------- */
27708 
close_button_callback(Widget w,XtPointer context,XtPointer info)27709 static void close_button_callback(Widget w, XtPointer context, XtPointer info)
27710 {
27711   snd_close_file((snd_info *)context);
27712 }
27713 
27714 
27715 
27716 /* apply is only safe if the DAC is currently inactive and remains safe only
27717  * if all other apply buttons are locked out (and play).
27718  */
27719 
27720 /* relative panes needs to notice overall window resize, but there's no way to do so in Motif, as far as I can tell */
27721 
27722 #if WITH_RELATIVE_PANES
27723 /* It would be nice if we could set a paned window to keep its children relative
27724  *   amounts the same upon outside resize, but the Paned Window widget doesn't
27725  *   have a resize callback, and no obvious way to advise the resize mechanism.
27726  *   An attempt to get the same effect by wrapping w_pane in a drawingarea widget
27727  *   ran into other troubles (the thing is seriously confused about its size).
27728  *   You'd naively think the Actions "Start" and "Commit" could be used, since
27729  *   XtActions are said to be a list of XtActionProcs, but I can't find a way to add
27730  *   my action without deactivating the built-in action of the same name --
27731  *   XtAugmentTranslations ignores new actions if the old exists, XtOverride
27732  *   replaces the old, etc. (And XtActions involve far more complexity than
27733  *   anyone should have to endure).
27734  *
27735  * so... drop down into the sashes...(using undocumented stuff throughout this code)
27736  */
27737 
sash_lock_control_panel(snd_info * sp)27738 static void sash_lock_control_panel(snd_info *sp)
27739 {
27740   if (showing_controls(sp))
27741     {
27742       /* lock to its current size */
27743       int hgt;
27744       hgt = control_panel_height(sp);
27745       XtVaSetValues(CONTROLS(sp),
27746 		    XmNpaneMinimum, hgt,
27747 		    XmNpaneMaximum, hgt,
27748 		    NULL);
27749     }
27750 }
27751 
27752 
sash_unlock_control_panel(snd_info * sp)27753 static void sash_unlock_control_panel(snd_info *sp)
27754 {
27755   if (showing_controls(sp))
27756     {
27757       XtVaSetValues(CONTROLS(sp),
27758 		    XmNpaneMinimum, 1,
27759 		    XmNpaneMaximum, LOTSA_PIXELS,
27760 		    NULL);
27761     }
27762 }
27763 
27764 
27765 static int outer_panes = 0;
27766 static int *inner_panes = NULL;
27767 static Dimension *outer_sizes = NULL;
27768 static Dimension **inner_sizes = NULL;
27769 
watch_sash(Widget w,XtPointer closure,XtPointer info)27770 static void watch_sash(Widget w, XtPointer closure, XtPointer info)
27771 {
27772   SashCallData call_data = (SashCallData)info;
27773   /* call_data->params[0]: Commit, Move, Key, Start (as strings) */
27774 
27775   if ((call_data->params) &&
27776       (call_data->params[0]) &&
27777       (with_relative_panes(ss)) &&
27778       (sound_style(ss) == SOUNDS_VERTICAL))
27779     {
27780       int i, k;
27781       snd_info *sp;
27782       if (mus_strcmp(call_data->params[0], "Start"))
27783 	{
27784 	  for (i = 0; i < ss->max_sounds; i++)
27785 	    {
27786 	      sp = ss->sounds[i];
27787 	      if ((sp) &&
27788 		  (sp->inuse == SOUND_NORMAL) &&
27789 		  (sp->nchans > 1) &&
27790 		  (sp->channel_style == CHANNELS_SEPARATE))
27791 		outer_panes++;
27792 	    }
27793 
27794 	  for_each_sound(sash_lock_control_panel);
27795 
27796 	  if (outer_panes > 0)
27797 	    {
27798 	      int outer_ctr;
27799 	      inner_panes = (int *)calloc(outer_panes, sizeof(int));
27800 	      outer_sizes = (Dimension *)calloc(outer_panes, sizeof(Dimension));
27801 	      inner_sizes = (Dimension **)calloc(outer_panes, sizeof(Dimension *));
27802 	      outer_ctr = 0;
27803 
27804 	      for (i = 0; i < ss->max_sounds; i++)
27805 		{
27806 		  sp = ss->sounds[i];
27807 		  if ((sp) &&
27808 		      (sp->inuse == SOUND_NORMAL) &&
27809 		      (sp->nchans > 1) &&
27810 		      (sp->channel_style == CHANNELS_SEPARATE))
27811 		    {
27812 		      Widget child;
27813 		      child = SND_PANE(sp);
27814 		      inner_panes[outer_ctr] = sp->nchans;
27815 		      inner_sizes[outer_ctr] = (Dimension *)calloc(sp->nchans, sizeof(Dimension));
27816 		      XtVaGetValues(child, XmNheight, &(outer_sizes[outer_ctr]), NULL);
27817 
27818 		      for (k = 0; k < (int)sp->nchans; k++)
27819 			XtVaGetValues(channel_main_pane(sp->chans[k]), XmNheight, &(inner_sizes[outer_ctr][k]), NULL);
27820 
27821 		      outer_ctr++;
27822 		      if (outer_ctr >= outer_panes) break;
27823 		    }
27824 		}
27825 	    }
27826 	}
27827       else
27828 	{
27829 	  if (mus_strcmp(call_data->params[0], "Commit")) /* release sash */
27830 	    {
27831 	      if (outer_panes > 0)
27832 		{
27833 		  int outer_ctr = 0;
27834 		  Dimension cur_outer_size = 0;
27835 
27836 		  for (i = 0; i < ss->max_sounds; i++)
27837 		    {
27838 		      sp = ss->sounds[i];
27839 		      if ((sp) &&
27840 			  (sp->inuse == SOUND_NORMAL) &&
27841 			  (sp->nchans > 1) &&
27842 			  (sp->channel_style == CHANNELS_SEPARATE))
27843 			{
27844 			  XtVaGetValues(SND_PANE(sp), XmNheight, &cur_outer_size, NULL);
27845 
27846 			  if ((cur_outer_size > 40) &&
27847 			      (abs(cur_outer_size - outer_sizes[outer_ctr]) > (int)(sp->nchans * 2)))
27848 			    {
27849 			      /* this pane has multiple chans and its size has changed enough to matter */
27850 			      Dimension total_inner = 0, diff;
27851 			      double ratio;
27852 
27853 			      for (k = 0; k < (int)sp->nchans; k++)
27854 				total_inner += inner_sizes[outer_ctr][k];
27855 			      diff = outer_sizes[outer_ctr] - total_inner; /* this is non-channel stuff */
27856 
27857 			      for (k = 0; k < (int)sp->nchans; k++)
27858 				XtUnmanageChild(channel_main_pane(sp->chans[k]));
27859 
27860 			      ratio = (double)(cur_outer_size - diff) / (double)(outer_sizes[outer_ctr] - diff);
27861 			      if (ratio > 0.0)
27862 				{
27863 				  for (k = 0; k < (int)sp->nchans; k++)
27864 				    {
27865 				      int size;
27866 				      size = (int)(ratio * inner_sizes[outer_ctr][k]);
27867 				      XtVaSetValues(channel_main_pane(sp->chans[k]),
27868 						    XmNpaneMinimum, size - 1,
27869 						    XmNpaneMaximum, size + 1,
27870 						    NULL);
27871 				    }
27872 				  for (k = 0; k < (int)sp->nchans; k++)
27873 				    XtManageChild(channel_main_pane(sp->chans[k]));
27874 				  for (k = 0; k < (int)sp->nchans; k++)
27875 				    XtVaSetValues(channel_main_pane(sp->chans[k]),
27876 						  XmNpaneMinimum, 1,
27877 						  XmNpaneMaximum, LOTSA_PIXELS,
27878 						  NULL);
27879 				}
27880 			    }
27881 			  outer_ctr++;
27882 			}
27883 		    }
27884 
27885 		  for (i = 0; i < outer_panes; i++)
27886 		    if (inner_sizes[i])
27887 		      free(inner_sizes[i]);
27888 		  free(inner_panes);
27889 		  free(inner_sizes);
27890 		  free(outer_sizes);
27891 		  outer_panes = 0;
27892 		}
27893 
27894 	      for_each_sound(sash_unlock_control_panel);
27895 	    }
27896 	}
27897     }
27898 }
27899 
27900 static Widget *sashes = NULL;
27901 static int sashes_size = 0;
27902 
remember_sash(Widget w)27903 static void remember_sash(Widget w)
27904 {
27905   /* add callback only once (means remembering which widgets already have our callback */
27906   int loc = -1;
27907   if (sashes_size == 0)
27908     {
27909       sashes = (Widget *)calloc(16, sizeof(Widget));
27910       sashes_size = 16;
27911       loc = 0;
27912     }
27913   else
27914     {
27915       int i;
27916       for (i = 0; i < sashes_size; i++)
27917 	{
27918 	  if (sashes[i] == w) return;
27919 	  if (!sashes[i])
27920 	    {
27921 	      loc = i;
27922 	      break;
27923 	    }
27924 	}
27925       if (loc == -1)
27926 	{
27927 	  sashes = (Widget *)realloc(sashes, sashes_size * 2 * sizeof(Widget));
27928 	  for (i = sashes_size; i < sashes_size * 2; i++) sashes[i] = NULL;
27929 	  loc = sashes_size;
27930 	  sashes_size *= 2;
27931 	}
27932     }
27933   sashes[loc] = w;
27934   XtAddCallback(w, XmNcallback, watch_sash, NULL);
27935 }
27936 
27937 
add_sash_watchers(Widget w)27938 static void add_sash_watchers(Widget w)
27939 {
27940   /* if relative panes, add sash watchers to the outer paned window sashes (sound_pane(ss)) */
27941   uint32_t i;
27942   CompositeWidget cw = (CompositeWidget)w;
27943   for (i = 0; i < cw->composite.num_children; i++) /* only outermost sashes count here */
27944     {
27945       Widget child;
27946       child = cw->composite.children[i];
27947       if ((XtIsWidget(child)) &&
27948 	  (XtIsManaged(child)) &&
27949 	  (XtIsSubclass(child, xmSashWidgetClass)))
27950 	remember_sash(child);
27951     }
27952 }
27953 
27954 #endif
27955 
27956 
cant_write(char * name)27957 static bool cant_write(char *name)
27958 {
27959 #ifndef _MSC_VER
27960   return((access(name, W_OK)) != 0);
27961 #else
27962   return(false);
27963 #endif
27964 }
27965 
27966 
27967 /* bitmaps for the playback direction arrow */
27968 
27969 static unsigned char speed_r_bits1[] = {
27970    0x00, 0x04, 0x10, 0x08, 0x00, 0x10, 0x04, 0x20, 0x00, 0x40, 0xa5, 0xbf,
27971    0x00, 0x40, 0x04, 0x20, 0x00, 0x10, 0x10, 0x08, 0x00, 0x04, 0x00, 0x00};
27972 static unsigned char speed_l_bits1[] = {
27973    0x20, 0x00, 0x10, 0x08, 0x08, 0x00, 0x04, 0x20, 0x02, 0x00, 0xfd, 0xa5,
27974    0x02, 0x00, 0x04, 0x20, 0x08, 0x00, 0x10, 0x08, 0x20, 0x00, 0x00, 0x00};
27975 
27976 #define NUM_BOMBS 15
27977 
27978 static Pixmap mini_lock = 0;
27979 static Pixmap close_icon = 0;
27980 static Pixmap blank_pixmap = 0;
27981 static bool mini_lock_allocated = false;
27982 static Pixmap bombs[NUM_BOMBS];
27983 static Pixmap hourglasses[NUM_HOURGLASSES];
27984 static Pixmap stop_sign = 0;
27985 
show_lock(snd_info * sp)27986 void show_lock(snd_info *sp)
27987 {
27988   if (!has_widgets(sp)) return;
27989   if (mini_lock)
27990     XtVaSetValues(LOCK_OR_BOMB(sp), XmNlabelPixmap, mini_lock, NULL);
27991 }
27992 
27993 
hide_lock(snd_info * sp)27994 void hide_lock(snd_info *sp)
27995 {
27996   if (!has_widgets(sp)) return;
27997   if (mini_lock)
27998     XtVaSetValues(LOCK_OR_BOMB(sp), XmNlabelPixmap, blank_pixmap, NULL);
27999   /* these Pixmaps can be null if the colormap is screwed up */
28000 }
28001 
28002 
show_stop_sign(snd_info * sp)28003 static void show_stop_sign(snd_info *sp)
28004 {
28005   if (!has_widgets(sp)) return;
28006   if (stop_sign)
28007     XtVaSetValues(STOP_ICON(sp), XmNlabelPixmap, stop_sign, NULL);
28008 }
28009 
28010 
hide_stop_sign(snd_info * sp)28011 static void hide_stop_sign(snd_info *sp)
28012 {
28013   if (!has_widgets(sp)) return;
28014   if (blank_pixmap)
28015     XtVaSetValues(STOP_ICON(sp), XmNlabelPixmap, blank_pixmap, NULL);
28016 }
28017 
28018 
show_bomb(snd_info * sp)28019 static void show_bomb(snd_info *sp)
28020 {
28021   if (!has_widgets(sp)) return;
28022   if (sp->bomb_ctr >= NUM_BOMBS)
28023     sp->bomb_ctr = 0;
28024   if (bombs[sp->bomb_ctr])
28025     XtVaSetValues(LOCK_OR_BOMB(sp), XmNlabelPixmap, bombs[sp->bomb_ctr], NULL);
28026   sp->bomb_ctr++;
28027 }
28028 
28029 
hide_bomb(snd_info * sp)28030 static void hide_bomb(snd_info *sp)
28031 {
28032   if (!has_widgets(sp)) return;
28033   XtVaSetValues(LOCK_OR_BOMB(sp), XmNlabelPixmap, blank_pixmap, NULL);
28034   sp->bomb_ctr = 0;
28035 }
28036 
28037 
28038 #define BOMB_TIME 200
28039 
tick_bomb(XtPointer context,XtIntervalId * id)28040 static void tick_bomb(XtPointer context, XtIntervalId *id)
28041 {
28042   snd_info *sp = (snd_info *)context;
28043   if (!has_widgets(sp)) return;
28044   if ((sp->need_update) || (sp->file_unreadable))
28045     {
28046       show_bomb(sp);
28047       XtAppAddTimeOut(main_app(ss),
28048 		      (unsigned long)BOMB_TIME,
28049 		      (XtTimerCallbackProc)tick_bomb,
28050 		      context);
28051     }
28052   else
28053     {
28054       hide_bomb(sp);
28055       sp->bomb_in_progress = false;
28056     }
28057 }
28058 
28059 
start_bomb(snd_info * sp)28060 void start_bomb(snd_info *sp)
28061 {
28062   if (!has_widgets(sp)) return;
28063   sp->bomb_ctr = 0;
28064   if (!(sp->bomb_in_progress))
28065     {
28066       sp->bomb_in_progress = true;
28067       XtAppAddTimeOut(main_app(ss),
28068 		      (unsigned long)BOMB_TIME,
28069 		      (XtTimerCallbackProc)tick_bomb,
28070 		      (void *)sp);
28071     }
28072 }
28073 
28074 
stop_bomb(snd_info * sp)28075 void stop_bomb(snd_info *sp)
28076 {
28077   if (!has_widgets(sp)) return;
28078   hide_bomb(sp);
28079   sp->bomb_in_progress = false;
28080 }
28081 
28082 
bits_to_string(const char ** icon)28083 static char *bits_to_string(const char **icon)
28084 {
28085   /* show first few lines */
28086   char *buf;
28087   buf = (char *)calloc(128, sizeof(char));
28088   snprintf(buf, 128, "\n%s\n%s\n%s...", icon[0], icon[1], icon[2]);
28089   return(buf);
28090 }
28091 
28092 
allocate_icons(Widget w)28093 static void allocate_icons(Widget w)
28094 {
28095   Pixmap shape1, shape2, shape3, shape4;
28096   XpmAttributes attributes;
28097   XpmColorSymbol symbols[1];
28098   int scr, k, pixerr;
28099   Display *dp;
28100   Drawable wn;
28101 
28102   dp = XtDisplay(w);
28103   wn = XtWindow(w);
28104   scr = DefaultScreen(dp);
28105   XtVaGetValues(w, XmNdepth, &attributes.depth, XmNcolormap, &attributes.colormap, NULL);
28106   attributes.visual = DefaultVisual(dp, scr);
28107   symbols[0].name = (char *)"basiccolor";
28108   symbols[0].value = NULL;
28109   symbols[0].pixel = ss->basic_color;
28110   attributes.colorsymbols = symbols;
28111   attributes.numsymbols = 1;
28112   attributes.valuemask = XpmColorSymbols | XpmDepth | XpmColormap | XpmVisual;
28113 
28114   pixerr = XpmCreatePixmapFromData(dp, wn, (char **)mini_lock_bits(), &mini_lock, &shape1, &attributes);
28115   if (pixerr != XpmSuccess)
28116     snd_error("lock pixmap trouble: %s from %s\n", XpmGetErrorString(pixerr), bits_to_string(mini_lock_bits()));
28117 
28118   pixerr = XpmCreatePixmapFromData(dp, wn, (char **)blank_bits(), &blank_pixmap, &shape1, &attributes);
28119   if (pixerr != XpmSuccess)
28120     snd_error("blank pixmap trouble: %s from %s\n", XpmGetErrorString(pixerr), bits_to_string(blank_bits()));
28121 
28122   pixerr = XpmCreatePixmapFromData(dp, wn, (char **)stop_sign_bits(), &stop_sign, &shape4, &attributes);
28123   if (pixerr != XpmSuccess)
28124     snd_error("stop sign pixmap trouble: %s from %s\n", XpmGetErrorString(pixerr), bits_to_string(stop_sign_bits()));
28125 
28126   pixerr = XpmCreatePixmapFromData(dp, wn, (char **)close_icon_bits(), &close_icon, &shape1, &attributes);
28127   if (pixerr != XpmSuccess)
28128     snd_error("stop sign pixmap trouble: %s from %s\n", XpmGetErrorString(pixerr), bits_to_string(close_icon_bits()));
28129 
28130   for (k = 0; k < NUM_BOMBS; k++)
28131     {
28132       pixerr = XpmCreatePixmapFromData(dp, wn, (char **)mini_bomb_bits(k), &(bombs[k]), &shape2, &attributes);
28133       if (pixerr != XpmSuccess)
28134 	{
28135 	  snd_error("bomb pixmap trouble: %s from %s\n", XpmGetErrorString(pixerr), bits_to_string(mini_bomb_bits(k)));
28136 	  break;
28137 	}
28138       pixerr = XpmCreatePixmapFromData(dp, wn, (char **)mini_glass_bits(k), &(hourglasses[k]), &shape3, &attributes);
28139       /* NUM_HOURGLASSES == NUM_BOMBS so this is safe */
28140       if (pixerr != XpmSuccess)
28141 	{
28142 	  snd_error("glass pixmap trouble: %s from %s\n", XpmGetErrorString(pixerr), bits_to_string(mini_glass_bits(k)));
28143 	  break;
28144 	}
28145     }
28146   mini_lock_allocated = true;
28147 }
28148 
28149 
change_pixmap_background(Widget w,Pixmap orig,Pixel old_color,Pixel new_color,int width,int height)28150 static void change_pixmap_background(Widget w, Pixmap orig, Pixel old_color, Pixel new_color, int width, int height)
28151 {
28152   XImage *before;
28153   Display *dp;
28154   Drawable wn;
28155   Visual *vis;
28156   XGCValues v;
28157   GC draw_gc;
28158   int depth, depth_bytes, x, y;
28159   char *data;
28160 
28161   dp = XtDisplay(w);
28162   wn = XtWindow(w);
28163   vis = DefaultVisual(dp, DefaultScreen(dp));
28164   XtVaGetValues(w, XmNdepth, &depth, NULL);
28165   depth_bytes = (depth >> 3);
28166 
28167   data = (char *)calloc((width + 1) * (height + 1) * depth_bytes, sizeof(char)); /* not calloc since X will free this */
28168   /* there's overflow in X here, apparently -- the +1's fix it according to valgrind */
28169   /*   perhaps this is supposed to be rounded up to byte boundaries? */
28170 
28171   before = XCreateImage(dp, vis, depth, XYPixmap, 0, data, width, height, 8, 0);
28172   XGetSubImage(dp, orig, 0, 0, width, height, AllPlanes, XYPixmap, before, 0, 0);
28173 
28174   v.background = new_color;
28175   draw_gc = XCreateGC(dp, wn, GCBackground, &v);
28176   XSetBackground(dp, draw_gc, new_color);
28177 
28178   for (x = 0; x < width; x++)
28179     for (y = 0; y < height; y++)
28180       if (XGetPixel(before, x, y) == old_color)
28181 	XPutPixel(before, x, y, new_color);
28182 
28183   XPutImage(dp, orig, draw_gc, before, 0, 0, 0, 0, width, height);
28184   XDestroyImage(before);  /* frees data as well */
28185   XFreeGC(dp, draw_gc);
28186 }
28187 
28188 
make_sound_icons_transparent_again(Pixel old_color,Pixel new_color)28189 void make_sound_icons_transparent_again(Pixel old_color, Pixel new_color)
28190 {
28191   int i;
28192   if (!mini_lock_allocated) allocate_icons(main_shell(ss));
28193   change_pixmap_background(main_shell(ss), mini_lock, old_color, new_color, 16, 14);
28194   change_pixmap_background(main_shell(ss), blank_pixmap, old_color, new_color, 16, 14);
28195   change_pixmap_background(main_shell(ss), close_icon, old_color, new_color, 16, 14);
28196   /* change_pixmap_background(main_shell(ss), stop_sign, old_color, new_color, 17, 17); */
28197   /* memory corruption here! */
28198   for (i = 0; i < NUM_BOMBS; i++)
28199     change_pixmap_background(main_shell(ss), bombs[i], old_color, new_color, 16, 14);
28200   for (i = 0; i < NUM_HOURGLASSES; i++)
28201     change_pixmap_background(main_shell(ss), hourglasses[i], old_color, new_color, 16, 14);
28202 }
28203 
28204 
28205 static Pixmap spd_r, spd_l;
28206 static bool spd_ok = false;
28207 
close_sound_dialog(Widget w,XtPointer context,XtPointer info)28208 static void close_sound_dialog(Widget w, XtPointer context, XtPointer info)
28209 {
28210   snd_info *sp = (snd_info *)context;
28211   if (sp) snd_close_file(sp);
28212 }
28213 
28214 
manage_sync_button(snd_info * sp)28215 static void manage_sync_button(snd_info *sp)
28216 {
28217   XtManageChild(SYNC_BUTTON(sp));
28218 }
28219 
28220 
attach_status_area(snd_info * sp)28221 static void attach_status_area(snd_info *sp)
28222 {
28223   XtUnmanageChild(STATUS_AREA(sp));
28224   XtVaSetValues(STATUS_AREA(sp),
28225 		XmNrightAttachment, XmATTACH_WIDGET,
28226 		XmNrightWidget, (XtIsManaged(UNITE_BUTTON(sp))) ? UNITE_BUTTON(sp) : ((XtIsManaged(SYNC_BUTTON(sp))) ? SYNC_BUTTON(sp) : PLAY_BUTTON(sp)),
28227 		NULL);
28228   XtManageChild(STATUS_AREA(sp));
28229 }
28230 
28231 
add_sound_window(char * filename,read_only_t read_only,file_info * hdr)28232 snd_info *add_sound_window(char *filename, read_only_t read_only, file_info *hdr)
28233 {
28234   snd_info *sp = NULL, *osp;
28235   Widget *sw;
28236   XmString s1;
28237   int snd_slot, nchans = 1, i, old_chans;
28238   bool make_widgets;
28239   Arg args[32];
28240   char *old_name = NULL, *title;
28241   Dimension app_dy, screen_y, chan_min_y;
28242   Position app_y;
28243   /* these dimensions are used to try to get a reasonable channel graph size without falling off the screen bottom */
28244   Pixmap rb, lb;
28245   int depth;
28246   bool free_filename = false;
28247   Widget form;
28248   XtCallbackList n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12;
28249   Atom sound_delete;
28250 
28251   if (ss->translated_filename)
28252     {
28253       old_name = filename;
28254       filename = ss->translated_filename;
28255       free_filename = true;
28256       ss->translated_filename = NULL;
28257     }
28258 
28259   nchans = hdr->chans;
28260   if (nchans <= 0) nchans = 1;
28261   XtVaGetValues(main_shell(ss),
28262 		XmNy, &app_y,
28263 		XmNheight, &app_dy,
28264 		NULL);
28265   screen_y = DisplayHeight(main_display(ss),
28266 			   DefaultScreen(main_display(ss)));
28267   app_dy = (screen_y - app_y - app_dy - 20 * nchans);
28268   chan_min_y = (Dimension)(app_dy / (Dimension)nchans);
28269   if (chan_min_y > (Dimension)(ss->channel_min_height))
28270     chan_min_y = ss->channel_min_height;
28271   else
28272     if (chan_min_y < 5)
28273       chan_min_y = 5;
28274 
28275   snd_slot = find_free_sound_slot(nchans); /* expands sound list if needed */
28276   if (ss->sounds[snd_slot]) /* we're trying to re-use an old, inactive set of widgets and whatnot */
28277     {
28278       osp = ss->sounds[snd_slot];
28279       old_chans = osp->allocated_chans;
28280     }
28281   else old_chans = 0;
28282   make_widgets = (!ss->sounds[snd_slot]);
28283   ss->sounds[snd_slot] = make_snd_info(ss->sounds[snd_slot], filename, hdr, snd_slot, read_only);
28284   sp = ss->sounds[snd_slot];
28285   sp->inuse = SOUND_NORMAL;
28286   sp->bomb_ctr = 0;
28287   sp->write_date = file_write_date(filename); /* needed early in this process by the peak-env handlers */
28288 
28289   if (!sp->widgets)
28290     sp->widgets = (Widget *)calloc(SP_NUM_WIDGETS, sizeof(Widget));
28291   sw = sp->widgets;
28292 
28293   if ((!make_widgets) && (old_chans < nchans))
28294     {
28295       for (i = old_chans; i < nchans; i++)
28296 	add_channel_window(sp, i, chan_min_y, 1, NULL, WITH_FW_BUTTONS, WITH_EVENTS);
28297     }
28298 
28299   if (make_widgets)
28300     {
28301       int n;
28302       if (sound_style(ss) == SOUNDS_IN_SEPARATE_WINDOWS)
28303 	{
28304 	  title = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char));
28305 	  snprintf(title, PRINT_BUFFER_SIZE, "%d: %s", snd_slot, sp->short_filename);
28306 	  if (!sp->dialog)
28307 	    {
28308 	      n = 0;
28309 	      XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28310 	      XtSetArg(args[n], XmNautoUnmanage, false); n++;
28311 	      XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
28312 	      XtSetArg(args[n], XmNnoResize, false); n++;
28313 	      XtSetArg(args[n], XmNtransient, false); n++;
28314 	      sp->dialog = XtCreatePopupShell(title, xmDialogShellWidgetClass, main_shell(ss), args, n);
28315 	      /* using popup shell here gets around the problem that the shell passes resize requests to all its children
28316 	       * -- as a popup, it's not considered a child, but that means we don't inherit things like popup menus from
28317 	       * the main shell.
28318 	       */
28319 	      sound_delete = XmInternAtom(XtDisplay(sp->dialog), (char *)"WM_DELETE_WINDOW", false);
28320 	      XmAddWMProtocolCallback(sp->dialog, sound_delete, close_sound_dialog, (XtPointer)sp);
28321 	    }
28322 	  else XtVaSetValues(sp->dialog, XmNtitle, title, NULL);
28323 	  free(title);
28324 	  if (!XtIsManaged(sp->dialog)) XtManageChild(sp->dialog);
28325 	}
28326 
28327       n = 0;
28328       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28329       n = attach_all_sides(args, n);
28330       XtSetArg(args[n], XmNallowResize, true); n++;
28331       XtSetArg(args[n], XmNsashIndent, ss->channel_sash_indent); n++;
28332       XtSetArg(args[n], XmNpaneMaximum, LOTSA_PIXELS); n++; /* Xm/Paned.c initializes this to 1000! */
28333       if (ss->channel_sash_size != 0)
28334 	{
28335 	  XtSetArg(args[n], XmNsashHeight, ss->channel_sash_size); n++;
28336 	  XtSetArg(args[n], XmNsashWidth, ss->channel_sash_size); n++;
28337 	}
28338 
28339       /* if (mumble_style(ss) == CHANNELS_HORIZONTAL) {XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;} */
28340       /* this doesn't work yet because the control panel is screwed up when trying to display itself horizontally */
28341       /* Perhaps another layer of panes? */
28342 
28343       if (sound_style(ss) == SOUNDS_VERTICAL)
28344 	{
28345 	  if (ss->toolbar)
28346 	    XtSetArg(args[n], XmNpositionIndex, snd_slot + 1);
28347 	  else XtSetArg(args[n], XmNpositionIndex, snd_slot);
28348 	  n++;
28349 	}
28350       XtSetArg(args[n], XmNuserData, sp->index); n++;
28351 
28352       if (sound_style(ss) == SOUNDS_IN_SEPARATE_WINDOWS)
28353 	SND_PANE(sp) = XtCreateManagedWidget("snd-pane", xmPanedWindowWidgetClass, sp->dialog, args, n);
28354       else
28355 	{
28356 	  uint32_t i;
28357 	  CompositeWidget cw = (CompositeWidget)sound_pane(ss);
28358 	  SND_PANE(sp) = XtCreateManagedWidget("snd-pane", xmPanedWindowWidgetClass, sound_pane(ss), args, n);
28359 
28360 	  /* try to make the division between sounds more obvious */
28361 	  for (i = 0; i < cw->composite.num_children; i++)
28362 	    {
28363 	      Widget child;
28364 	      child = cw->composite.children[i];
28365 	      if (((XtIsWidget(child))|| (XmIsGadget(child))) &&
28366 		  (XtIsManaged(child)) &&
28367 		  ((XmIsSeparator(child)) || (XmIsSeparatorGadget(child))))
28368 		XtVaSetValues(child, XmNseparatorType, XmDOUBLE_LINE,
28369 			      XmNbackground, ss->white,
28370 			      NULL);
28371 	    }
28372 	}
28373 
28374       XtAddEventHandler(SND_PANE(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28375       /* if user clicks in controls, then starts typing, try to send key events to current active channel */
28376       /* all widgets in the control-pane that would otherwise intercept the key events get this event handler */
28377 
28378       for (i = 0; i < nchans; i++)
28379 	add_channel_window(sp, i, chan_min_y, 0, NULL, WITH_FW_BUTTONS, WITH_EVENTS);
28380       /* creates channel (horizontal) paned window widget as child of w_snd_pane(sp) == SND_PANE(sp) */
28381 
28382 
28383       /* -------- sound file name, status area, various buttons -------- */
28384 
28385       n = 0;
28386       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28387       XtSetArg(args[n], XmNpaneMinimum, 20); n++;
28388       XtSetArg(args[n], XmNpaneMaximum, 20); n++;
28389       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
28390       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
28391       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
28392       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
28393       NAME_BOX(sp) = XtCreateManagedWidget("snd-name-form", xmFormWidgetClass, SND_PANE(sp), args, n);
28394       XtAddEventHandler(NAME_BOX(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28395 
28396       if (!mini_lock_allocated)
28397 	allocate_icons(NAME_BOX(sp));
28398 
28399       n = 0;
28400       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28401       XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++;
28402       XtSetArg(args[n], XmNlabelPixmap, close_icon); n++;
28403       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
28404       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
28405       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
28406       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28407       XtSetArg(args[n], XmNwidth, 32); n++;
28408       XtSetArg(args[n], XmNshadowThickness, 0); n++;
28409       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
28410       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
28411       CLOSE_BUTTON(sp) = XtCreateManagedWidget("close-button", xmPushButtonWidgetClass, NAME_BOX(sp), args, n);
28412       XtAddCallback(CLOSE_BUTTON(sp), XmNactivateCallback, close_button_callback, (XtPointer)sp);
28413 
28414       n = 0;
28415       s1 = XmStringCreateLocalized(shortname_indexed(sp));
28416       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
28417       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
28418       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
28419       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
28420       /* XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; */
28421 
28422       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
28423       XtSetArg(args[n], XmNleftWidget, CLOSE_BUTTON(sp)); n++;
28424 
28425       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28426       XtSetArg(args[n], XmNlabelString, s1); n++;
28427       XtSetArg(args[n], XmNshadowThickness, 0); n++;
28428       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
28429       XtSetArg(args[n], XmNfillOnArm, false); n++;
28430       NAME_LABEL(sp) = XtCreateManagedWidget("snd-name", xmPushButtonWidgetClass, NAME_BOX(sp), args, n);
28431       XtAddEventHandler(NAME_LABEL(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28432       XtAddCallback(NAME_LABEL(sp), XmNactivateCallback, name_click_callback, (XtPointer)sp);
28433       XmStringFree(s1);
28434 
28435       n = 0;
28436       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28437       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
28438       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
28439       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
28440       XtSetArg(args[n], XmNleftWidget, NAME_LABEL(sp)); n++;
28441       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28442 
28443       if (blank_pixmap)
28444 	{
28445 	  /* if xpm failed (blank_pixmap == 0), this can cause X to kill Snd! */
28446 	  XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++;
28447 	  XtSetArg(args[n], XmNlabelPixmap, blank_pixmap); n++;
28448 	}
28449 
28450       LOCK_OR_BOMB(sp) = XtCreateManagedWidget("", xmLabelWidgetClass, NAME_BOX(sp), args, n);
28451 
28452       {
28453 	uint32_t i;
28454 	Widget left_widget;
28455 
28456 	left_widget = LOCK_OR_BOMB(sp);
28457 	sp->progress_widgets = (Widget *)calloc(sp->nchans, sizeof(Widget));
28458 	sp->num_progress_widgets = sp->nchans;
28459 	/* when an unused sound is reopened in snd-data.c, it's possible for its channel number
28460 	 *   to be increased.  If we then try to draw the clock icon in the new channel, its
28461 	 *   widget will be unallocated -> segfault, so to keep things simple, we check this number.
28462 	 */
28463 
28464 	for (i = 0; i < sp->nchans; i++)
28465 	  {
28466 	    n = 0;
28467 	    XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28468 	    XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
28469 	    XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
28470 	    XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
28471 	    XtSetArg(args[n], XmNleftWidget, left_widget); n++;
28472 	    XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28473 
28474 	    if (blank_pixmap)
28475 	      {
28476 		/* if xpm failed (blank_pixmap == 0), this can cause X to kill Snd! */
28477 		XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++;
28478 		XtSetArg(args[n], XmNlabelPixmap, blank_pixmap); n++;
28479 	      }
28480 
28481 	    sp->progress_widgets[i] = XtCreateManagedWidget("", xmLabelWidgetClass, NAME_BOX(sp), args, n);
28482 	    left_widget = sp->progress_widgets[i];
28483 	  }
28484 
28485 	n = 0;
28486 	XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28487 	XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
28488 	XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
28489 	XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
28490 	XtSetArg(args[n], XmNleftWidget, left_widget); n++;
28491 	XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28492 
28493 	if (blank_pixmap)
28494 	  {
28495 	    XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++;
28496 	    XtSetArg(args[n], XmNlabelPixmap, blank_pixmap); n++;
28497 	  }
28498 
28499 	XtSetArg(args[n], XmNshadowThickness, 0); n++;
28500 	XtSetArg(args[n], XmNhighlightThickness, 0); n++;
28501 	XtSetArg(args[n], XmNfillOnArm, false); n++;
28502 	STOP_ICON(sp) = XtCreateManagedWidget("", xmPushButtonWidgetClass, NAME_BOX(sp), args, n);
28503 	XtAddCallback(STOP_ICON(sp), XmNactivateCallback, stop_sign_click_callback, (XtPointer)sp);
28504       }
28505 
28506       n = 0;
28507       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28508       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
28509       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
28510       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
28511       XtSetArg(args[n], XmNleftWidget, STOP_ICON(sp)); n++;
28512       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28513       XtSetArg(args[n], XmNresizeWidth, true); n++;
28514       XtSetArg(args[n], XmNmarginHeight, 1); n++;
28515       XtSetArg(args[n], XmNshadowThickness, 0); n++;
28516       XtSetArg(args[n], XmNeditable, false); n++;
28517       XtSetArg(args[n], XmNcursorPositionVisible, false); n++;
28518       STATUS_AREA(sp) = XtCreateManagedWidget("snd-info", xmTextFieldWidgetClass, NAME_BOX(sp), args, n);
28519 
28520 #if WITH_AUDIO
28521       n = 0;
28522       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28523       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
28524 #ifdef TOGGLE_MARGIN
28525       XtSetArg(args[n], XmNmarginHeight, TOGGLE_MARGIN); n++;
28526       XtSetArg(args[n], XmNmarginTop, TOGGLE_MARGIN); n++;
28527 #endif
28528       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
28529       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
28530       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
28531       XtSetArg(args[n], XmNrecomputeSize, false); n++;
28532       /* in Motif 2.2 this sets up a tooltip:
28533 	XtSetArg(args[n], XmNtoolTipString, XmStringCreateLocalized((char *)"play this sound")); n++;
28534       */
28535       XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
28536       PLAY_BUTTON(sp) = make_togglebutton_widget("play", NAME_BOX(sp), args, n);
28537       XtAddCallback(PLAY_BUTTON(sp), XmNvalueChangedCallback, play_button_callback, (XtPointer)sp);
28538 #endif
28539 
28540       n = 0;
28541       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28542       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
28543 #ifdef TOGGLE_MARGIN
28544       XtSetArg(args[n], XmNmarginHeight, TOGGLE_MARGIN); n++;
28545       XtSetArg(args[n], XmNmarginTop, TOGGLE_MARGIN); n++;
28546 #endif
28547       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
28548       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
28549 #if WITH_AUDIO
28550       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
28551       XtSetArg(args[n], XmNrightWidget, PLAY_BUTTON(sp)); n++;
28552 #else
28553       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
28554 #endif
28555       XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
28556       SYNC_BUTTON(sp) = make_togglebutton_widget("sync", NAME_BOX(sp), args, n);
28557       XtAddEventHandler(SYNC_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28558       XtAddCallback(SYNC_BUTTON(sp), XmNvalueChangedCallback, sync_button_callback, (XtPointer)sp);
28559 
28560       n = 0;
28561       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28562       XtSetArg(args[n], XmNtopAttachment, XmATTACH_NONE); n++;
28563       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28564       XtSetArg(args[n], XmNbottomWidget, SYNC_BUTTON(sp)); n++;
28565 #ifdef TOGGLE_MARGIN
28566       XtSetArg(args[n], XmNmarginHeight, TOGGLE_MARGIN); n++;
28567       XtSetArg(args[n], XmNmarginTop, TOGGLE_MARGIN); n++;
28568 #endif
28569       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
28570       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
28571       XtSetArg(args[n], XmNrightWidget, SYNC_BUTTON(sp)); n++;
28572       XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
28573       UNITE_BUTTON(sp) = make_togglebutton_widget("unite", NAME_BOX(sp), args, n);
28574       XtAddEventHandler(UNITE_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28575       XtAddCallback(UNITE_BUTTON(sp), XmNvalueChangedCallback, unite_button_callback, (XtPointer)sp);
28576 
28577 
28578       /* ---------------- control panel ---------------- */
28579       n = 0;
28580       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28581       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
28582       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
28583       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
28584       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
28585       CONTROLS(sp) = XtCreateManagedWidget("snd-amp", xmFormWidgetClass, SND_PANE(sp), args, n);
28586       XtAddEventHandler(CONTROLS(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28587 
28588       n = 0;
28589       /* AMP */
28590       s1 = XmStringCreateLocalized((char *)"amp:");
28591       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28592       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
28593       XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
28594       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28595       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
28596       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28597       XtSetArg(args[n], XmNlabelString, s1); n++;
28598       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28599       XtSetArg(args[n], XmNrecomputeSize, false); n++;
28600       XtSetArg(args[n], XmNshadowThickness, 0); n++;
28601       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
28602       XtSetArg(args[n], XmNfillOnArm, false); n++;
28603       AMP_BUTTON(sp) = make_pushbutton_widget("amp-label", CONTROLS(sp), args, n);
28604       XtAddEventHandler(AMP_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28605       XtAddCallback(AMP_BUTTON(sp), XmNactivateCallback, amp_click_callback, (XtPointer)sp);
28606       XmStringFree(s1);
28607 
28608       n = 0;
28609       s1 = XmStringCreateLocalized((char *)"1.0   ");
28610       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28611       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
28612       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28613       XtSetArg(args[n], XmNtopWidget, AMP_BUTTON(sp)); n++;
28614       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28615       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
28616       XtSetArg(args[n], XmNleftWidget, AMP_BUTTON(sp)); n++;
28617       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28618       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28619       XtSetArg(args[n], XmNrecomputeSize, false); n++;
28620       XtSetArg(args[n], XmNlabelString, s1); n++;
28621       XtSetArg(args[n], XmNmarginRight, 3); n++;
28622       AMP_LABEL(sp) = XtCreateManagedWidget("amp-number", xmLabelWidgetClass, CONTROLS(sp), args, n);
28623       XmStringFree(s1);
28624 
28625       n = 0;
28626       XtSetArg(args[n], XmNbackground, ss->position_color); n++;
28627       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28628       XtSetArg(args[n], XmNtopWidget, AMP_BUTTON(sp)); n++;
28629       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28630       XtSetArg(args[n], XmNheight, 16); n++;
28631       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
28632       XtSetArg(args[n], XmNleftWidget, AMP_LABEL(sp)); n++;
28633       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
28634       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
28635       XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++;
28636       XtSetArg(args[n], XmNvalue, amp_to_scroll(sp->amp_control_min, 1.0, sp->amp_control_max)); n++;
28637       XtSetArg(args[n], XmNdragCallback, n1 = make_callback_list(amp_drag_callback, (XtPointer)sp)); n++;
28638       XtSetArg(args[n], XmNvalueChangedCallback, n2 = make_callback_list(amp_valuechanged_callback, (XtPointer)sp)); n++;
28639       AMP_SCROLLBAR(sp) = XtCreateManagedWidget("amp", xmScrollBarWidgetClass, CONTROLS(sp), args, n);
28640       XtAddEventHandler(AMP_SCROLLBAR(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28641 
28642       n = 0;
28643       /* SPEED */
28644       s1 = XmStringCreateLocalized((char *)"speed:");
28645       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28646       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
28647       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
28648       XtSetArg(args[n], XmNtopWidget, AMP_BUTTON(sp)); n++;
28649       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28650       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
28651       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28652       XtSetArg(args[n], XmNlabelString, s1); n++;
28653       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28654       XtSetArg(args[n], XmNrecomputeSize, false); n++;
28655       XtSetArg(args[n], XmNshadowThickness, 0); n++;
28656       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
28657       XtSetArg(args[n], XmNfillOnArm, false); n++;
28658       SPEED_BUTTON(sp) = make_pushbutton_widget("speed-label", CONTROLS(sp), args, n);
28659       XtAddEventHandler(SPEED_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28660       XtAddCallback(SPEED_BUTTON(sp), XmNactivateCallback, speed_click_callback, (XtPointer)sp);
28661       XmStringFree(s1);
28662 
28663       n = 0;
28664       s1 = initial_speed_label(sp->speed_control_style);
28665       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28666       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
28667       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28668       XtSetArg(args[n], XmNtopWidget, SPEED_BUTTON(sp)); n++;
28669       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28670       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
28671       XtSetArg(args[n], XmNleftWidget, SPEED_BUTTON(sp)); n++;
28672       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28673       XtSetArg(args[n], XmNlabelString, s1); n++;
28674       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28675       XtSetArg(args[n], XmNrecomputeSize, false); n++;
28676       XtSetArg(args[n], XmNmarginRight, 3); n++;
28677       XtSetArg(args[n], XmNshadowThickness, 0); n++;
28678       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
28679       XtSetArg(args[n], XmNfillOnArm, false); n++;
28680       SPEED_LABEL(sp) = make_pushbutton_widget("speed-number", CONTROLS(sp), args, n);
28681       XtAddEventHandler(SPEED_LABEL(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28682       XtAddCallback(SPEED_LABEL(sp), XmNactivateCallback, speed_label_click_callback, (XtPointer)sp);
28683       XmStringFree(s1);
28684 
28685       n = 0;
28686       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28687       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28688       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
28689       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
28690       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28691       XtSetArg(args[n], XmNtopWidget, SPEED_BUTTON(sp)); n++;
28692       XtSetArg(args[n], XmNindicatorOn, false); n++;
28693       XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++;
28694       XtSetArg(args[n], XmNmarginHeight, 0); n++;
28695       XtSetArg(args[n], XmNmarginWidth, 0); n++;
28696       XtSetArg(args[n], XmNmarginTop, 0); n++;
28697       XtSetArg(args[n], XmNtopOffset, 0); n++;
28698       SPEED_ARROW(sp) = make_togglebutton_widget("dir", CONTROLS(sp), args, n);
28699       form = SPEED_ARROW(sp);
28700       if (!spd_ok)
28701 	{
28702 	  rb = XCreateBitmapFromData(XtDisplay(form), RootWindowOfScreen(XtScreen(form)), (const char *)speed_r_bits1, 16, 12);
28703 	  lb = XCreateBitmapFromData(XtDisplay(form), RootWindowOfScreen(XtScreen(form)), (const char *)speed_l_bits1, 16, 12);
28704 	  XtVaGetValues(form, XmNdepth, &depth, NULL);
28705 	  spd_r = XCreatePixmap(XtDisplay(form), RootWindowOfScreen(XtScreen(form)), 16, 12, depth);
28706 	  spd_l = XCreatePixmap(XtDisplay(form), RootWindowOfScreen(XtScreen(form)), 16, 12, depth);
28707 	  XCopyPlane(XtDisplay(form), rb, spd_r, ss->fltenv_basic_gc, 0, 0, 16, 12, 0, 0, 1);
28708 	  XCopyPlane(XtDisplay(form), lb, spd_l, ss->fltenv_basic_gc, 0, 0, 16, 12, 0, 0, 1);
28709 	  XFreePixmap(XtDisplay(form), rb);
28710 	  XFreePixmap(XtDisplay(form), lb);
28711 	  spd_ok = true;
28712 	}
28713       XtVaSetValues(form, XmNselectPixmap, spd_l, XmNlabelPixmap, spd_r, NULL);
28714       XtAddEventHandler(SPEED_ARROW(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28715       XtAddCallback(SPEED_ARROW(sp), XmNvalueChangedCallback, play_arrow_callback, (XtPointer)sp);
28716 
28717       n = 0;
28718       XtSetArg(args[n], XmNbackground, ss->position_color); n++;
28719       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28720       XtSetArg(args[n], XmNtopWidget, SPEED_BUTTON(sp)); n++;
28721       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28722       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
28723       XtSetArg(args[n], XmNleftWidget, SPEED_LABEL(sp)); n++;
28724       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
28725       XtSetArg(args[n], XmNrightWidget, SPEED_ARROW(sp)); n++;
28726       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
28727       XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++;
28728       XtSetArg(args[n], XmNvalue, speed_to_scroll(sp->speed_control_min, 1.0, sp->speed_control_max)); n++;
28729       XtSetArg(args[n], XmNheight, 16); n++;
28730       XtSetArg(args[n], XmNdragCallback, n3 = make_callback_list(speed_drag_callback, (XtPointer)sp)); n++;
28731       XtSetArg(args[n], XmNvalueChangedCallback, n4 = make_callback_list(speed_valuechanged_callback, (XtPointer)sp)); n++;
28732       SPEED_SCROLLBAR(sp) = XtCreateManagedWidget("speed-scroll", xmScrollBarWidgetClass, CONTROLS(sp), args, n);
28733       XtAddEventHandler(SPEED_SCROLLBAR(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28734 
28735       n = 0;
28736       /* EXPAND */
28737       s1 = XmStringCreateLocalized((char *)"expand:");
28738       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28739       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
28740       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
28741       XtSetArg(args[n], XmNtopWidget, SPEED_BUTTON(sp)); n++;
28742       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28743       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
28744       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28745       XtSetArg(args[n], XmNlabelString, s1); n++;
28746       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28747       XtSetArg(args[n], XmNrecomputeSize, false); n++;
28748       XtSetArg(args[n], XmNshadowThickness, 0); n++;
28749       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
28750       XtSetArg(args[n], XmNfillOnArm, false); n++;
28751       EXPAND_LEFT_BUTTON(sp) = make_pushbutton_widget("expand-label", CONTROLS(sp), args, n);
28752       XtAddEventHandler(EXPAND_LEFT_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28753       XtAddCallback(EXPAND_LEFT_BUTTON(sp), XmNactivateCallback, expand_click_callback, (XtPointer)sp);
28754       XmStringFree(s1);
28755 
28756       n = 0;
28757       s1 = XmStringCreateLocalized((char *)"1.0   ");
28758       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28759       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
28760       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28761       XtSetArg(args[n], XmNtopWidget, EXPAND_LEFT_BUTTON(sp)); n++;
28762       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28763       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
28764       XtSetArg(args[n], XmNleftWidget, EXPAND_LEFT_BUTTON(sp)); n++;
28765       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28766       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28767       XtSetArg(args[n], XmNrecomputeSize, false); n++;
28768       XtSetArg(args[n], XmNlabelString, s1); n++;
28769       XtSetArg(args[n], XmNmarginRight, 3); n++;
28770       EXPAND_LABEL(sp) = XtCreateManagedWidget("expand-number", xmLabelWidgetClass, CONTROLS(sp), args, n);
28771       XmStringFree(s1);
28772 
28773       n = 0;
28774       s1 = XmStringCreateLocalized((char *)"");
28775       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28776       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28777       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
28778       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
28779       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28780       XtSetArg(args[n], XmNtopWidget, EXPAND_LEFT_BUTTON(sp)); n++;
28781       XtSetArg(args[n], XmNheight, 16); n++;
28782       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28783       XtSetArg(args[n], XmNmarginWidth, 0); n++;
28784       XtSetArg(args[n], XmNtopOffset, 1); n++;
28785       XtSetArg(args[n], XmNspacing, 0); n++;
28786       XtSetArg(args[n], XmNlabelString, s1); n++;
28787       if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;}
28788       XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
28789       EXPAND_RIGHT_BUTTON(sp) = make_togglebutton_widget("expoff", CONTROLS(sp), args, n);
28790       XtAddEventHandler(EXPAND_RIGHT_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28791       XtAddCallback(EXPAND_RIGHT_BUTTON(sp), XmNvalueChangedCallback, expand_button_callback, (XtPointer)sp);
28792       XmStringFree(s1);
28793 
28794       n = 0;
28795       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28796       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28797       XtSetArg(args[n], XmNtopWidget, EXPAND_LEFT_BUTTON(sp)); n++;
28798       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28799       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
28800       XtSetArg(args[n], XmNleftWidget, EXPAND_LABEL(sp)); n++;
28801       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
28802       XtSetArg(args[n], XmNrightWidget, EXPAND_RIGHT_BUTTON(sp)); n++;
28803       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
28804       XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++;
28805       XtSetArg(args[n], XmNvalue, expand_to_scroll(sp->expand_control_min, 1.0, sp->expand_control_max)); n++;
28806       XtSetArg(args[n], XmNheight, 16); n++;
28807       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28808       XtSetArg(args[n], XmNdragCallback, n5 = make_callback_list(expand_drag_callback, (XtPointer)sp)); n++;
28809       XtSetArg(args[n], XmNvalueChangedCallback, n6 = make_callback_list(expand_valuechanged_callback, (XtPointer)sp)); n++;
28810       EXPAND_SCROLLBAR(sp) = XtCreateManagedWidget("expand-scroll", xmScrollBarWidgetClass, CONTROLS(sp), args, n);
28811       XtAddEventHandler(EXPAND_SCROLLBAR(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28812 
28813 
28814       /* CONTRAST */
28815       n = 0;
28816       s1 = XmStringCreateLocalized((char *)"contrast:");
28817       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28818       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
28819       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
28820       XtSetArg(args[n], XmNtopWidget, EXPAND_LEFT_BUTTON(sp)); n++;
28821       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28822       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
28823       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28824       XtSetArg(args[n], XmNlabelString, s1); n++;
28825       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28826       XtSetArg(args[n], XmNrecomputeSize, false); n++;
28827       XtSetArg(args[n], XmNshadowThickness, 0); n++;
28828       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
28829       XtSetArg(args[n], XmNfillOnArm, false); n++;
28830       CONTRAST_LEFT_BUTTON(sp) = make_pushbutton_widget("contrast-label", CONTROLS(sp), args, n);
28831       XtAddEventHandler(CONTRAST_LEFT_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28832       XtAddCallback(CONTRAST_LEFT_BUTTON(sp), XmNactivateCallback, contrast_click_callback, (XtPointer)sp);
28833       XmStringFree(s1);
28834 
28835       n = 0;
28836       s1 = XmStringCreateLocalized((char *)"1.0   ");
28837       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28838       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
28839       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28840       XtSetArg(args[n], XmNtopWidget, CONTRAST_LEFT_BUTTON(sp)); n++;
28841       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28842       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
28843       XtSetArg(args[n], XmNleftWidget, CONTRAST_LEFT_BUTTON(sp)); n++;
28844       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28845       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28846       XtSetArg(args[n], XmNrecomputeSize, false); n++;
28847       XtSetArg(args[n], XmNlabelString, s1); n++;
28848       XtSetArg(args[n], XmNmarginRight, 3); n++;
28849       CONTRAST_LABEL(sp) = XtCreateManagedWidget("contrast-number", xmLabelWidgetClass, CONTROLS(sp), args, n);
28850       XmStringFree(s1);
28851 
28852       n = 0;
28853       s1 = XmStringCreateLocalized((char *)"");
28854       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28855       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28856       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
28857       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
28858       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28859       XtSetArg(args[n], XmNtopWidget, CONTRAST_LEFT_BUTTON(sp)); n++;
28860       XtSetArg(args[n], XmNheight, 16); n++;
28861       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28862       XtSetArg(args[n], XmNmarginWidth, 0); n++;
28863       XtSetArg(args[n], XmNtopOffset, 1); n++;
28864       XtSetArg(args[n], XmNlabelString, s1); n++;
28865       XtSetArg(args[n], XmNspacing, 0); n++;
28866       if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;}
28867       XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
28868       CONTRAST_RIGHT_BUTTON(sp) = make_togglebutton_widget("conoff", CONTROLS(sp), args, n);
28869       XtAddEventHandler(CONTRAST_RIGHT_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28870       XtAddCallback(CONTRAST_RIGHT_BUTTON(sp), XmNvalueChangedCallback, contrast_button_callback, (XtPointer)sp);
28871       XmStringFree(s1);
28872 
28873       n = 0;
28874       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28875       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28876       XtSetArg(args[n], XmNtopWidget, CONTRAST_LEFT_BUTTON(sp)); n++;
28877       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28878       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
28879       XtSetArg(args[n], XmNleftWidget, CONTRAST_LABEL(sp)); n++;
28880       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
28881       XtSetArg(args[n], XmNrightWidget, CONTRAST_RIGHT_BUTTON(sp)); n++;
28882       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
28883       XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++;
28884       XtSetArg(args[n], XmNheight, 16); n++;
28885       XtSetArg(args[n], XmNvalue, 0); n++;
28886       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28887       XtSetArg(args[n], XmNdragCallback, n7 = make_callback_list(contrast_drag_callback, (XtPointer)sp)); n++;
28888       XtSetArg(args[n], XmNvalueChangedCallback, n8 = make_callback_list(contrast_valuechanged_callback, (XtPointer)sp)); n++;
28889       CONTRAST_SCROLLBAR(sp) = XtCreateManagedWidget("contrast-scroll", xmScrollBarWidgetClass, CONTROLS(sp), args, n);
28890       XtAddEventHandler(CONTRAST_SCROLLBAR(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28891 
28892       /* REVERB */
28893       /* REVSCL */
28894       n = 0;
28895       s1 = XmStringCreateLocalized((char *)"reverb:");
28896       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28897       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
28898       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
28899       XtSetArg(args[n], XmNtopWidget, CONTRAST_LEFT_BUTTON(sp)); n++;
28900       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28901       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
28902       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28903       XtSetArg(args[n], XmNlabelString, s1); n++;
28904       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28905       XtSetArg(args[n], XmNrecomputeSize, false); n++;
28906       XtSetArg(args[n], XmNshadowThickness, 0); n++;
28907       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
28908       XtSetArg(args[n], XmNfillOnArm, false); n++;
28909       REVSCL_BUTTON(sp) = make_pushbutton_widget("revscl-label", CONTROLS(sp), args, n);
28910       XtAddEventHandler(REVSCL_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28911       XtAddCallback(REVSCL_BUTTON(sp), XmNactivateCallback, revscl_click_callback, (XtPointer)sp);
28912       XmStringFree(s1);
28913 
28914       n = 0;
28915       s1 = XmStringCreateLocalized((char *)"0.0     ");
28916       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28917       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
28918       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28919       XtSetArg(args[n], XmNtopWidget, REVSCL_BUTTON(sp)); n++;
28920       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28921       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
28922       XtSetArg(args[n], XmNleftWidget, REVSCL_BUTTON(sp)); n++;
28923       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28924       XtSetArg(args[n], XmNlabelString, s1); n++;
28925       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28926       XtSetArg(args[n], XmNrecomputeSize, false); n++;
28927       XtSetArg(args[n], XmNmarginRight, 3); n++;
28928       REVSCL_LABEL(sp) = XtCreateManagedWidget("revscl-number", xmLabelWidgetClass, CONTROLS(sp), args, n);
28929       XmStringFree(s1);
28930 
28931       n = 0;
28932       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28933       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28934       XtSetArg(args[n], XmNtopWidget, REVSCL_BUTTON(sp)); n++;
28935       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28936       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
28937       XtSetArg(args[n], XmNleftWidget, REVSCL_LABEL(sp)); n++;
28938       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
28939       XtSetArg(args[n], XmNrightPosition, 60); n++;
28940       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
28941       XtSetArg(args[n], XmNheight, 16); n++;
28942       XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++;
28943       XtSetArg(args[n], XmNvalue, 0); n++;
28944       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28945       XtSetArg(args[n], XmNdragCallback, n9 = make_callback_list(revscl_drag_callback, (XtPointer)sp)); n++;
28946       XtSetArg(args[n], XmNvalueChangedCallback, n10 = make_callback_list(revscl_valuechanged_callback, (XtPointer)sp)); n++;
28947       REVSCL_SCROLLBAR(sp) = XtCreateManagedWidget("revscl-scroll", xmScrollBarWidgetClass, CONTROLS(sp), args, n);
28948       XtAddEventHandler(REVSCL_SCROLLBAR(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28949 
28950       /* REVOFF */
28951       n = 0;
28952       s1 = XmStringCreateLocalized((char *)"");
28953       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28954       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28955       XtSetArg(args[n], XmNtopWidget, REVSCL_BUTTON(sp)); n++;
28956       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28957       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
28958       XtSetArg(args[n], XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28959       XtSetArg(args[n], XmNrightWidget, CONTRAST_RIGHT_BUTTON(sp)); n++;
28960       XtSetArg(args[n], XmNheight, 16); n++;
28961       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28962       XtSetArg(args[n], XmNmarginWidth, 0); n++;
28963       XtSetArg(args[n], XmNtopOffset, 1); n++;
28964       XtSetArg(args[n], XmNspacing, 0); n++;
28965       XtSetArg(args[n], XmNlabelString, s1); n++;
28966       if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;}
28967       XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
28968       REVERB_BUTTON(sp) = make_togglebutton_widget("revoff", CONTROLS(sp), args, n);
28969       XtAddEventHandler(REVERB_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28970       XtAddCallback(REVERB_BUTTON(sp), XmNvalueChangedCallback, reverb_button_callback, (XtPointer)sp);
28971       XmStringFree(s1);
28972 
28973 
28974       /* REVLEN */
28975       n = 0;
28976       s1 = XmStringCreateLocalized((char *)"len:");
28977       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28978       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
28979       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
28980       XtSetArg(args[n], XmNtopWidget, REVSCL_SCROLLBAR(sp)); n++;
28981       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
28982       XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
28983       XtSetArg(args[n], XmNleftPosition, 60); n++;
28984       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
28985       XtSetArg(args[n], XmNlabelString, s1); n++;
28986       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
28987       XtSetArg(args[n], XmNrecomputeSize, false); n++;
28988       XtSetArg(args[n], XmNshadowThickness, 0); n++;
28989       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
28990       XtSetArg(args[n], XmNfillOnArm, false); n++;
28991       REVLEN_BUTTON(sp) = make_pushbutton_widget("revlen-label", CONTROLS(sp), args, n);
28992       XtAddEventHandler(REVLEN_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
28993       XtAddCallback(REVLEN_BUTTON(sp), XmNactivateCallback, revlen_click_callback, (XtPointer)sp);
28994       XmStringFree(s1);
28995 
28996       n = 0;
28997       s1 = XmStringCreateLocalized((char *)"1.0 ");
28998       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
28999       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
29000       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
29001       XtSetArg(args[n], XmNtopWidget, REVLEN_BUTTON(sp)); n++;
29002       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
29003       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
29004       XtSetArg(args[n], XmNleftWidget, REVLEN_BUTTON(sp)); n++;
29005       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
29006       XtSetArg(args[n], XmNlabelString, s1); n++;
29007       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
29008       XtSetArg(args[n], XmNrecomputeSize, false); n++;
29009       XtSetArg(args[n], XmNmarginRight, 3); n++;
29010       REVLEN_LABEL(sp) = XtCreateManagedWidget("revlen-number", xmLabelWidgetClass, CONTROLS(sp), args, n);
29011       XmStringFree(s1);
29012 
29013       n = 0;
29014       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
29015       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
29016       XtSetArg(args[n], XmNtopWidget, REVLEN_BUTTON(sp)); n++;
29017       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
29018       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
29019       XtSetArg(args[n], XmNleftWidget, REVLEN_LABEL(sp)); n++;
29020       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
29021       XtSetArg(args[n], XmNrightWidget, REVERB_BUTTON(sp)); n++;
29022       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
29023       XtSetArg(args[n], XmNheight, 16); n++;
29024       XtSetArg(args[n], XmNmaximum, SCROLLBAR_MAX); n++;
29025       XtSetArg(args[n], XmNvalue, revlen_to_scroll(sp->reverb_control_length_min, 1.0, sp->reverb_control_length_max)); n++;
29026       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
29027       XtSetArg(args[n], XmNdragCallback, n11 = make_callback_list(revlen_drag_callback, (XtPointer)sp)); n++;
29028       XtSetArg(args[n], XmNvalueChangedCallback, n12 = make_callback_list(revlen_valuechanged_callback, (XtPointer)sp)); n++;
29029       REVLEN_SCROLLBAR(sp) = XtCreateManagedWidget("revlen-scroll", xmScrollBarWidgetClass, CONTROLS(sp), args, n);
29030       XtAddEventHandler(REVLEN_SCROLLBAR(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
29031 
29032 
29033       /* FILTER */
29034       n = 0;
29035       s1 = XmStringCreateLocalized((char *)"filter:");
29036       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
29037       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
29038       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
29039       XtSetArg(args[n], XmNtopWidget, REVSCL_BUTTON(sp)); n++;
29040       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
29041       XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
29042       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
29043       XtSetArg(args[n], XmNlabelString, s1); n++;
29044       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
29045       XtSetArg(args[n], XmNrecomputeSize, false); n++;
29046       XtSetArg(args[n], XmNshadowThickness, 0); n++;
29047       XtSetArg(args[n], XmNhighlightThickness, 0); n++;
29048       XtSetArg(args[n], XmNfillOnArm, false); n++;
29049       FILTER_LABEL(sp) = XtCreateManagedWidget("filter-label", xmLabelWidgetClass, CONTROLS(sp), args, n);
29050       XmStringFree(s1);
29051 
29052       /* filter order */
29053       n = 0;
29054       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
29055       XtSetArg(args[n], XmNresizeWidth, false); n++;
29056       XtSetArg(args[n], XmNcolumns, 3); n++;
29057       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
29058       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
29059       XtSetArg(args[n], XmNtopWidget, FILTER_LABEL(sp)); n++;
29060       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
29061       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
29062       XtSetArg(args[n], XmNleftWidget, FILTER_LABEL(sp)); n++;
29063       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
29064       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
29065       XtSetArg(args[n], XmNrecomputeSize, false); n++;
29066       FILTER_ORDER_TEXT(sp) = make_textfield_widget("filter-order", CONTROLS(sp), args, n, ACTIVATABLE, NO_COMPLETER);
29067       XmTextSetString(FILTER_ORDER_TEXT(sp), (char *)" 20");
29068       XtAddCallback(FILTER_ORDER_TEXT(sp), XmNactivateCallback, filter_order_activate_callback, (XtPointer)sp);
29069 
29070       #define ARROW_SIZE 12
29071 
29072       n = 0;
29073       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
29074       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
29075       XtSetArg(args[n], XmNtopWidget, FILTER_ORDER_TEXT(sp)); n++;
29076       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
29077       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
29078       XtSetArg(args[n], XmNleftWidget, FILTER_ORDER_TEXT(sp)); n++;
29079       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
29080       XtSetArg(args[n], XmNheight, ARROW_SIZE); n++;
29081       XtSetArg(args[n], XmNwidth, ARROW_SIZE); n++;
29082       XtSetArg(args[n], XmNborderWidth, 0); n++;
29083       XtSetArg(args[n], XmNmarginWidth, 0); n++;
29084       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
29085       FILTER_ORDER_DOWN(sp) = make_pushbutton_widget("", CONTROLS(sp), args, n);
29086       XtAddEventHandler(FILTER_ORDER_DOWN(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
29087       XtAddCallback(FILTER_ORDER_DOWN(sp), XmNactivateCallback, filter_order_down_callback, (XtPointer)sp);
29088 
29089       n = 0;
29090       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
29091       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
29092       XtSetArg(args[n], XmNtopWidget, FILTER_ORDER_DOWN(sp)); n++;
29093       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
29094       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
29095       XtSetArg(args[n], XmNleftWidget, FILTER_ORDER_TEXT(sp)); n++;
29096       XtSetArg(args[n], XmNrightAttachment, XmATTACH_NONE); n++;
29097       XtSetArg(args[n], XmNheight, ARROW_SIZE); n++;
29098       XtSetArg(args[n], XmNwidth, ARROW_SIZE); n++;
29099       XtSetArg(args[n], XmNborderWidth, 0); n++;
29100       XtSetArg(args[n], XmNmarginWidth, 0); n++;
29101       XtSetArg(args[n], XmNarmColor, ss->selection_color); n++;
29102       FILTER_ORDER_UP(sp) = make_pushbutton_widget("", CONTROLS(sp), args, n);
29103       XtAddEventHandler(FILTER_ORDER_UP(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
29104       XtAddCallback(FILTER_ORDER_UP(sp), XmNactivateCallback, filter_order_up_callback, (XtPointer)sp);
29105 
29106       n = 0;
29107       s1 = XmStringCreateLocalized((char *)"");
29108       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
29109       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
29110       XtSetArg(args[n], XmNtopWidget, REVERB_BUTTON(sp)); n++;
29111       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
29112       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
29113       XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
29114       XtSetArg(args[n], XmNheight, 16); n++;
29115       XtSetArg(args[n], XmNmarginWidth, 0); n++;
29116       XtSetArg(args[n], XmNtopOffset, 2); n++;
29117       XtSetArg(args[n], XmNspacing, 0); n++;
29118       XtSetArg(args[n], XmNlabelString, s1); n++;
29119       if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;}
29120       XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
29121       FILTER_BUTTON(sp) = make_togglebutton_widget("fltoff", CONTROLS(sp), args, n);
29122       XtAddEventHandler(FILTER_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
29123       XtAddCallback(FILTER_BUTTON(sp), XmNvalueChangedCallback, filter_button_callback, (XtPointer)sp);
29124       XmStringFree(s1);
29125 
29126       n = 0;
29127       s1 = XmStringCreateLocalized((char *)"hz");
29128       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
29129       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
29130       XtSetArg(args[n], XmNtopWidget, FILTER_BUTTON(sp)); n++;
29131       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
29132       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
29133       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
29134       XtSetArg(args[n], XmNrightWidget, FILTER_BUTTON(sp)); n++;
29135       XtSetArg(args[n], XmNlabelString, s1); n++;
29136       XtSetArg(args[n], XmNvalue, sp->filter_control_in_hz); n++;
29137       if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;}
29138       XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
29139       FILTER_HZ_BUTTON(sp) = make_togglebutton_widget("flthz", CONTROLS(sp), args, n);
29140       XtAddEventHandler(FILTER_HZ_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
29141       XtAddCallback(FILTER_HZ_BUTTON(sp), XmNvalueChangedCallback, filter_hz_callback, (XtPointer)sp);
29142       XmStringFree(s1);
29143 
29144       n = 0;
29145       s1 = XmStringCreateLocalized((char *)"dB");
29146       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
29147       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
29148       XtSetArg(args[n], XmNtopWidget, FILTER_HZ_BUTTON(sp)); n++;
29149       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
29150       XtSetArg(args[n], XmNleftAttachment, XmATTACH_NONE); n++;
29151       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
29152       XtSetArg(args[n], XmNrightWidget, FILTER_HZ_BUTTON(sp)); n++;
29153       XtSetArg(args[n], XmNlabelString, s1); n++;
29154       XtSetArg(args[n], XmNvalue, sp->filter_control_in_dB); n++;
29155       if (ss->toggle_size > 0) {XtSetArg(args[n], XmNindicatorSize, ss->toggle_size); n++;}
29156       XtSetArg(args[n], XmNselectColor, ss->selection_color); n++;
29157       FILTER_DB_BUTTON(sp) = make_togglebutton_widget("fltdB", CONTROLS(sp), args, n);
29158       XtAddEventHandler(FILTER_DB_BUTTON(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
29159       XtAddCallback(FILTER_DB_BUTTON(sp), XmNvalueChangedCallback, filter_dB_callback, (XtPointer)sp);
29160       XmStringFree(s1);
29161 
29162       n = 0;
29163       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
29164       XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
29165       XtSetArg(args[n], XmNtopAttachment, XmATTACH_OPPOSITE_WIDGET); n++;
29166       XtSetArg(args[n], XmNtopWidget, FILTER_ORDER_DOWN(sp)); n++;
29167       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
29168       XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
29169       XtSetArg(args[n], XmNleftWidget, FILTER_ORDER_DOWN(sp)); n++;
29170       XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
29171       XtSetArg(args[n], XmNrightWidget, FILTER_DB_BUTTON(sp)); n++;
29172       XtSetArg(args[n], XmNmarginHeight, CONTROLS_MARGIN); n++;
29173       FILTER_COEFFS_TEXT(sp) = make_textfield_widget("filter-text", CONTROLS(sp), args, n, ACTIVATABLE, add_completer_func(filename_completer, NULL));
29174       XtAddCallback(FILTER_COEFFS_TEXT(sp), XmNactivateCallback, filter_activate_callback, (XtPointer)sp);
29175 
29176       /* FILTER GRAPH */
29177       n = 0;
29178       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
29179       XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
29180       XtSetArg(args[n], XmNtopWidget, FILTER_COEFFS_TEXT(sp)); n++;
29181       XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
29182       XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
29183       XtSetArg(args[n], XmNleftPosition, 4); n++;
29184       XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
29185       XtSetArg(args[n], XmNrightPosition, 98); n++;
29186       XtSetArg(args[n], XmNallowResize, true); n++;
29187       XtSetArg(args[n], XmNshadowType, XmSHADOW_ETCHED_IN); n++;
29188       XtSetArg(args[n], XmNshadowThickness, 4); n++;
29189       FILTER_FRAME(sp) = XtCreateManagedWidget("filter-frame", xmFrameWidgetClass, CONTROLS(sp), args, n);
29190 
29191       n = 0;
29192       XtSetArg(args[n], XmNbackground, ss->highlight_color); n++;
29193       n = attach_all_sides(args, n);
29194       XtSetArg(args[n], XmNallowResize, true); n++;
29195       FILTER_GRAPH(sp) = XtCreateManagedWidget("filter-window", xmDrawingAreaWidgetClass, FILTER_FRAME(sp), args, n);
29196       XtAddCallback(FILTER_GRAPH(sp), XmNresizeCallback, filter_drawer_resize, (XtPointer)sp);
29197       XtAddCallback(FILTER_GRAPH(sp), XmNexposeCallback, filter_drawer_resize, (XtPointer)sp);
29198 
29199       sp->flt = new_env_editor();
29200 
29201       XtAddEventHandler(FILTER_GRAPH(sp), ButtonPressMask, false, filter_drawer_button_press, sp);
29202       XtAddEventHandler(FILTER_GRAPH(sp), ButtonMotionMask, false, filter_drawer_button_motion, sp);
29203       XtAddEventHandler(FILTER_GRAPH(sp), ButtonReleaseMask, false, filter_drawer_button_release, sp);
29204       XtAddEventHandler(FILTER_GRAPH(sp), KeyPressMask, false, graph_key_press, (XtPointer)sp);
29205 
29206       free(n1); free(n2); free(n3); free(n4); free(n5); free(n6);
29207       free(n7); free(n8); free(n9); free(n10); free(n11); free(n12);
29208       /* end if control-panel */
29209       if (sound_style(ss) == SOUNDS_IN_NOTEBOOK)
29210 	{
29211 	  char *name;
29212 	  name = just_filename(sp->short_filename); /* copies */
29213 	  if (strlen(name) > 8) name[8] = '\0';
29214 	  n = 0;
29215 	  XtSetArg(args[n], XmNbackground, ss->graph_color); n++;
29216 	  XtSetArg(args[n], XmNnotebookChildType, XmMAJOR_TAB); n++;
29217 	  XtSetArg(args[n], XmNuserData, sp->index); n++;
29218 	  sp->tab = XtCreateManagedWidget(name, xmPushButtonWidgetClass, sound_pane(ss), args, n);
29219 	  free(name);
29220 	}
29221 
29222 
29223       if (sound_style(ss) != SOUNDS_IN_SEPARATE_WINDOWS)
29224 	run_new_widget_hook(SND_PANE(sp));
29225       else run_new_widget_hook(sp->dialog);
29226 
29227 #if WITH_RELATIVE_PANES
29228       if (sound_style(ss) == SOUNDS_VERTICAL)
29229 	add_sash_watchers(sound_pane(ss)); /* add in any case since we might later change the sense of with_relative_panes */
29230 #endif
29231 
29232     } /* new sound ss */
29233   else
29234     { /* re-manage currently inactive chan */
29235       int k;
29236       if (sound_style(ss) == SOUNDS_IN_SEPARATE_WINDOWS)
29237 	{
29238 	  title = (char *)calloc(PRINT_BUFFER_SIZE, sizeof(char));
29239 	  snprintf(title, PRINT_BUFFER_SIZE, "%d: %s", snd_slot, sp->short_filename);
29240 	  XtVaSetValues(sp->dialog, XmNtitle, title, NULL);
29241 	  free(title);
29242 	  if (!XtIsManaged(sp->dialog)) XtManageChild(sp->dialog);
29243 	}
29244 
29245       for (i = 0; i < SP_NUM_WIDGETS - 1; i++)
29246 	if ((sw[i]) &&
29247 	    (!XtIsManaged(sw[i])) &&
29248 	    (in_show_controls(ss) || (i != W_amp_form)))
29249 	  XtManageChild(sw[i]);
29250 
29251       for (k = 0; k < nchans; k++)
29252 	add_channel_window(sp, k, chan_min_y, 0, NULL, WITH_FW_BUTTONS, WITH_EVENTS);
29253 
29254       set_button_label(NAME_LABEL(sp), shortname_indexed(sp));
29255       XtVaSetValues(SND_PANE(sp), XmNuserData, sp->index, NULL);
29256 
29257       if (sound_style(ss) == SOUNDS_IN_NOTEBOOK)
29258 	{
29259 	  char *name;
29260 	  name = just_filename(sp->short_filename);
29261 	  set_label(sp->tab, name);
29262 	  free(name);
29263 	}
29264     }
29265 
29266   map_over_children(sound_pane(ss), color_sashes);
29267   if (!(in_show_controls(ss)))
29268     hide_controls(sp);
29269   else show_controls(sp);
29270 
29271   if (sp->nchans == 1)
29272     {
29273       XmToggleButtonSetState(UNITE_BUTTON(sp), false, false);
29274       XtUnmanageChild(UNITE_BUTTON(sp));
29275 
29276       if (ss->active_sounds == 0) /* ticked at the end in snd-file.c */
29277 	{
29278 	  XmToggleButtonSetState(SYNC_BUTTON(sp), false, false);
29279 	  XtUnmanageChild(SYNC_BUTTON(sp));
29280 	}
29281       else
29282 	{
29283 	  for_each_sound(manage_sync_button);
29284 	}
29285     }
29286   else
29287     {
29288       for_each_sound(manage_sync_button);
29289     }
29290   attach_status_area(sp);
29291 
29292   add_sound_data(filename, sp, WITH_GRAPH);
29293 
29294   if (cant_write(sp->filename))
29295     sp->file_read_only = FILE_READ_ONLY;
29296   if ((sp->file_read_only == FILE_READ_ONLY) ||
29297       (sp->user_read_only == FILE_READ_ONLY))
29298     show_lock(sp);
29299   else hide_lock(sp);
29300 
29301   if (old_name)
29302     status_report(sp, "(translated %s)", old_name);
29303 
29304   if (sound_style(ss) != SOUNDS_IN_SEPARATE_WINDOWS)
29305     {
29306       reset_controls(sp);
29307     }
29308   else
29309     {
29310       XtVaSetValues(sp->dialog,
29311 		    XmNwidth, 100,
29312 		    XmNheight, 100,
29313 		    NULL);
29314       /* this is not redundant -- apparently they're trying to ignore size resets to the "current" */
29315       /* value, but forgot that unmanage/remanage does not return to the previous size */
29316       XtVaSetValues(sp->dialog,
29317 		    XmNwidth, (Dimension)(widget_width(main_shell(ss))),
29318 		    XmNheight, (Dimension)(chan_min_y * nchans), /* bugfix thanks to Paul @pobox */
29319 		    NULL);
29320     }
29321 
29322   after_open(sp);
29323   if (free_filename) free(filename);
29324   return(sp);
29325 }
29326 
29327 
update_sound_label(snd_info * sp)29328 void update_sound_label(snd_info *sp)
29329 {
29330   if (has_widgets(sp))
29331     set_button_label(NAME_LABEL(sp), shortname_indexed(sp));
29332 }
29333 
snd_info_cleanup(snd_info * sp)29334 void snd_info_cleanup(snd_info *sp)
29335 {
29336   if (has_widgets(sp))
29337     {
29338       clear_status_area(sp);
29339       if (SYNC_BUTTON(sp))
29340 	{
29341 	  XtVaSetValues(SYNC_BUTTON(sp), XmNset, false, NULL);
29342 	  XtVaSetValues(EXPAND_RIGHT_BUTTON(sp), XmNset, false, NULL);
29343 	  XtVaSetValues(CONTRAST_RIGHT_BUTTON(sp), XmNset, false, NULL);
29344 	  XtVaSetValues(SPEED_ARROW(sp), XmNset, false, NULL);
29345 	  XtVaSetValues(FILTER_BUTTON(sp), XmNset, false, NULL);
29346 	  XtVaSetValues(REVERB_BUTTON(sp), XmNset, false, NULL);
29347 	  XmToggleButtonSetState(UNITE_BUTTON(sp), false, false);
29348 	  sp->channel_style = CHANNELS_SEPARATE;
29349 	  if (sound_style(ss) == SOUNDS_IN_NOTEBOOK)
29350 	    {
29351 	      set_label(sp->tab, "none");
29352 	      XmChangeColor(sp->tab, ss->graph_color);
29353 	    }
29354 	  XtUnmanageChild(SND_PANE(sp));
29355 	}
29356       if ((sp->dialog) &&
29357 	  (XtIsManaged(sp->dialog)))
29358 	XtUnmanageChild(sp->dialog);
29359     }
29360 }
29361 
29362 
reflect_file_close_in_sync(Xen hook_or_reason)29363 static Xen reflect_file_close_in_sync(Xen hook_or_reason)
29364 {
29365   int reason;
29366 #if HAVE_SCHEME
29367   reason = Xen_integer_to_C_int(s7_let_ref(s7, hook_or_reason, s7_make_symbol(s7, "reason")));
29368 #else
29369   reason = Xen_integer_to_C_int(hook_or_reason);
29370 #endif
29371   if ((reason == FILE_CLOSED) && /* snd-file.c */
29372       (ss->active_sounds == 1))
29373     {
29374       snd_info *sp;
29375       sp = any_selected_sound();
29376       if ((sp) && (sp->nchans == 1))
29377 	{
29378 	  XtUnmanageChild(SYNC_BUTTON(sp));
29379 	  attach_status_area(sp);
29380 	}
29381     }
29382   return(Xen_false);
29383 }
29384 
set_sound_pane_file_label(snd_info * sp,const char * str)29385 void set_sound_pane_file_label(snd_info *sp, const char *str)
29386 {
29387   if (!(mus_strcmp(sp->name_string, str)))
29388     {
29389       if (sp->name_string) free(sp->name_string);
29390       sp->name_string = mus_strdup(str);
29391       set_button_label(SND_NAME(sp), str); /* this causes an expose event, so it's worth minimizing */
29392     }
29393 }
29394 
29395 
color_filter_waveform(Pixel color)29396 void color_filter_waveform(Pixel color)
29397 {
29398   int i;
29399   XSetForeground(main_display(ss), ss->fltenv_data_gc, color);
29400   for (i = 0; i < ss->max_sounds; i++)
29401     {
29402       snd_info *sp;
29403       sp = ss->sounds[i];
29404       if ((sp) && (sp->inuse == SOUND_NORMAL))
29405 	display_filter_env(sp);
29406     }
29407 }
29408 
29409 
show_controls(snd_info * sp)29410 void show_controls(snd_info *sp)
29411 {
29412   Dimension hgt;
29413   XtVaGetValues(FILTER_LABEL(sp),
29414 		XmNy, &hgt,
29415 		NULL);
29416   if (XtIsManaged(CONTROLS(sp)))
29417     XtUnmanageChild(CONTROLS(sp));
29418   XtVaSetValues(CONTROLS(sp),
29419 		XmNpaneMinimum, hgt,
29420 		XmNpaneMaximum, hgt,
29421 		NULL);
29422   XtManageChild(CONTROLS(sp));
29423   XtVaSetValues(CONTROLS(sp),
29424 		XmNpaneMinimum, 1,
29425 		XmNpaneMaximum, LOTSA_PIXELS,
29426 		NULL);
29427 }
29428 
29429 
hide_controls(snd_info * sp)29430 void hide_controls(snd_info *sp)
29431 {
29432   XtUnmanageChild(CONTROLS(sp));
29433 }
29434 
29435 
showing_controls(snd_info * sp)29436 bool showing_controls(snd_info *sp)
29437 {
29438   return((bool)(XtIsManaged(CONTROLS(sp))));
29439 }
29440 
29441 
show_all_controls(void)29442 void show_all_controls(void)
29443 {
29444   int i;
29445   for (i = 0; i < ss->max_sounds; i++)
29446     {
29447       snd_info *sp;
29448       sp = ss->sounds[i];
29449       if ((sp) && (sp->inuse == SOUND_NORMAL))
29450 	show_controls(sp);
29451     }
29452 }
29453 
29454 
hide_all_controls(void)29455 void hide_all_controls(void)
29456 {
29457   int i;
29458   for (i = 0; i < ss->max_sounds; i++)
29459     {
29460       snd_info *sp;
29461       sp = ss->sounds[i];
29462       if ((sp) && (sp->inuse == SOUND_NORMAL))
29463 	hide_controls(sp);
29464     }
29465 }
29466 
29467 
control_panel_height(snd_info * sp)29468 int control_panel_height(snd_info *sp)
29469 {
29470   return(widget_height(CONTROLS(sp)));
29471 }
29472 
29473 
29474 /* -------- PROGRESS REPORT -------- */
29475 
progress_report(chan_info * cp,mus_float_t pct)29476 void progress_report(chan_info *cp, mus_float_t pct)
29477 {
29478   int which;
29479   snd_info *sp;
29480   sp = cp->sound;
29481 
29482   if ((!has_widgets(sp)) || (sp->inuse != SOUND_NORMAL)) return;
29483 
29484   which = (int)(pct * NUM_HOURGLASSES);
29485   if (which >= NUM_HOURGLASSES) which = NUM_HOURGLASSES - 1;
29486   if (which < 0) which = 0;
29487 
29488   if ((hourglasses[which]) &&
29489       (cp->chan < sp->num_progress_widgets) &&
29490       ((cp->chan == 0) ||
29491        (sp->channel_style != CHANNELS_SUPERIMPOSED)))
29492     {
29493       XtVaSetValues(PROGRESS_ICON(cp), XmNlabelPixmap, hourglasses[which], NULL);
29494       XmUpdateDisplay(PROGRESS_ICON(cp));
29495     }
29496 
29497   check_for_event();
29498 }
29499 
finish_progress_report(chan_info * cp)29500 void finish_progress_report(chan_info *cp)
29501 {
29502   snd_info *sp;
29503   sp = cp->sound;
29504 
29505   if ((!has_widgets(sp)) || (sp->inuse != SOUND_NORMAL)) return;
29506 
29507   if ((cp->chan < sp->num_progress_widgets) &&
29508       ((cp->chan == 0) ||
29509        (sp->channel_style != CHANNELS_SUPERIMPOSED)))
29510     {
29511       XtVaSetValues(PROGRESS_ICON(cp), XmNlabelPixmap, blank_pixmap, NULL);
29512       XmUpdateDisplay(PROGRESS_ICON(cp));
29513       hide_stop_sign(sp);
29514     }
29515 }
29516 
29517 
start_progress_report(chan_info * cp)29518 void start_progress_report(chan_info *cp)
29519 {
29520   snd_info *sp;
29521   sp = cp->sound;
29522 
29523   if ((!has_widgets(sp)) || (sp->inuse != SOUND_NORMAL)) return;
29524 
29525   if ((cp->chan < sp->num_progress_widgets) &&
29526       ((cp->chan == 0) ||
29527        (sp->channel_style != CHANNELS_SUPERIMPOSED)))
29528     {
29529       XtVaSetValues(PROGRESS_ICON(cp), XmNlabelPixmap, hourglasses[0], NULL);
29530       XmUpdateDisplay(PROGRESS_ICON(cp));
29531       show_stop_sign(sp);
29532     }
29533 }
29534 
29535 
29536 
reflect_sound_selection(snd_info * sp)29537 void reflect_sound_selection(snd_info *sp)
29538 {
29539   /* sp is the newly selected sound, ss->selected_sound is the previous one */
29540   snd_info *osp = NULL;
29541 
29542   if (ss->selected_sound != NO_SELECTION)
29543     osp = ss->sounds[ss->selected_sound];
29544 
29545   if ((osp) &&
29546       (sp != osp) &&
29547       (osp->inuse == SOUND_NORMAL))
29548     {
29549       XmChangeColor(SND_NAME(osp), ss->highlight_color);
29550       if (sound_style(ss) == SOUNDS_IN_NOTEBOOK)
29551 	XmChangeColor(osp->tab, ss->graph_color);
29552     }
29553 
29554   if (sp->selected_channel != NO_SELECTION)
29555     {
29556       XmChangeColor(SND_NAME(sp), ss->white);
29557       if (sound_style(ss) == SOUNDS_IN_NOTEBOOK)
29558 	{
29559 	  int page, current_page;
29560 	  XmNotebookPageStatus status;
29561 	  XmNotebookPageInfo info;
29562 	  XmChangeColor(sp->tab, ss->selected_graph_color);
29563 	  XtVaGetValues(sound_pane(ss), XmNcurrentPageNumber, &current_page, NULL);
29564 	  XtVaGetValues(sp->tab, XmNpageNumber, &page, NULL);
29565 	  if (page != current_page)
29566 	    {
29567 	      status = XmNotebookGetPageInfo(sound_pane(ss), page, &info);
29568 	      if (status == XmPAGE_FOUND)
29569 		{
29570 		  XtVaSetValues(sound_pane(ss), XmNcurrentPageNumber, page, NULL);
29571 		}
29572 	    }
29573 	}
29574     }
29575 }
29576 
29577 
29578 /* -------- controls dialog -------- */
29579 
29580 static Widget controls_dialog = NULL;
29581 enum {EXPAND_HOP, EXPAND_LENGTH, EXPAND_RAMP, EXPAND_JITTER, CONTRAST_AMP, REVERB_LOWPASS, REVERB_FEEDBACK};
29582 static Widget controls[7];
29583 
reset_all_sliders(void)29584 static void reset_all_sliders(void)
29585 {
29586   expand_control_set_hop(DEFAULT_EXPAND_CONTROL_HOP);
29587   expand_control_set_length(DEFAULT_EXPAND_CONTROL_LENGTH);
29588   expand_control_set_ramp(DEFAULT_EXPAND_CONTROL_RAMP);
29589   expand_control_set_jitter(DEFAULT_EXPAND_CONTROL_JITTER);
29590   contrast_control_set_amp(DEFAULT_CONTRAST_CONTROL_AMP);
29591   reverb_control_set_lowpass(DEFAULT_REVERB_CONTROL_LOWPASS);
29592   reverb_control_set_feedback(DEFAULT_REVERB_CONTROL_FEEDBACK);
29593 
29594   XtVaSetValues(controls[EXPAND_HOP], XmNvalue, (int)(expand_control_hop(ss) * 1000), NULL);
29595   XtVaSetValues(controls[EXPAND_LENGTH], XmNvalue, (int)(expand_control_length(ss) * 1000), NULL);
29596   XtVaSetValues(controls[EXPAND_RAMP], XmNvalue, (int)(expand_control_ramp(ss) * 1000), NULL);
29597   XtVaSetValues(controls[EXPAND_JITTER], XmNvalue, (int)(expand_control_jitter(ss) * 1000), NULL);
29598   XtVaSetValues(controls[CONTRAST_AMP], XmNvalue, (int)(contrast_control_amp(ss) * 1000), NULL);
29599   XtVaSetValues(controls[REVERB_LOWPASS], XmNvalue, (int)(reverb_control_lowpass(ss) * 1000), NULL);
29600   XtVaSetValues(controls[REVERB_FEEDBACK], XmNvalue, (int)(reverb_control_feedback(ss) * 1000), NULL);
29601 }
29602 
controls_reset_callback(Widget w,XtPointer context,XtPointer info)29603 static void controls_reset_callback(Widget w, XtPointer context, XtPointer info)
29604 {
29605   if (XmGetFocusWidget(controls_dialog) == XmMessageBoxGetChild(controls_dialog, XmDIALOG_OK_BUTTON))
29606     reset_all_sliders();
29607 }
29608 
controls_help_callback(Widget w,XtPointer context,XtPointer info)29609 static void controls_help_callback(Widget w, XtPointer context, XtPointer info)
29610 {
29611   snd_help("More controls",
29612 "This dialog controls all the otherwise hidden control-panel variables.\n\
29613 Expand-hop sets the time in seconds between successive grains.\n\
29614 Expand-length sets the length of each grain.\n\
29615 Expand-ramp sets the ramp-time in the grain envelope.\n\
29616 Expand-jitter sets the grain timing jitter.\n\
29617 Contrast-amp sets the prescaler for contrast-enhancement.\n\
29618 Reverb-lowpass sets the feedback lowpass filter coeficient.\n\
29619 Reverb-feedback sets the scaler on the feedback.",
29620 	   WITHOUT_WORD_WRAP);
29621 }
29622 
controls_quit_callback(Widget w,XtPointer context,XtPointer info)29623 static void controls_quit_callback(Widget w, XtPointer context, XtPointer info)
29624 {
29625   XtUnmanageChild(controls_dialog);
29626 }
29627 
expand_hop_callback(Widget w,XtPointer context,XtPointer info)29628 static void expand_hop_callback(Widget w, XtPointer context, XtPointer info)
29629 {
29630   XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info;
29631   expand_control_set_hop(cbs->value * 0.001);
29632 }
29633 
expand_length_callback(Widget w,XtPointer context,XtPointer info)29634 static void expand_length_callback(Widget w, XtPointer context, XtPointer info)
29635 {
29636   XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info;
29637   expand_control_set_length(cbs->value * 0.001);
29638 }
29639 
expand_ramp_callback(Widget w,XtPointer context,XtPointer info)29640 static void expand_ramp_callback(Widget w, XtPointer context, XtPointer info)
29641 {
29642   XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info;
29643   expand_control_set_ramp(cbs->value * 0.001);
29644 }
29645 
expand_jitter_callback(Widget w,XtPointer context,XtPointer info)29646 static void expand_jitter_callback(Widget w, XtPointer context, XtPointer info)
29647 {
29648   XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info;
29649   expand_control_set_jitter(cbs->value * 0.001);
29650 }
29651 
contrast_amp_callback(Widget w,XtPointer context,XtPointer info)29652 static void contrast_amp_callback(Widget w, XtPointer context, XtPointer info)
29653 {
29654   XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info;
29655   contrast_control_set_amp(cbs->value * 0.001);
29656 }
29657 
reverb_lowpass_callback(Widget w,XtPointer context,XtPointer info)29658 static void reverb_lowpass_callback(Widget w, XtPointer context, XtPointer info)
29659 {
29660   XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info;
29661   reverb_control_set_lowpass(cbs->value * 0.001);
29662 }
29663 
reverb_feedback_callback(Widget w,XtPointer context,XtPointer info)29664 static void reverb_feedback_callback(Widget w, XtPointer context, XtPointer info)
29665 {
29666   XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *)info;
29667   reverb_control_set_feedback(cbs->value * 0.001);
29668 }
29669 
make_controls_dialog(void)29670 void make_controls_dialog(void)
29671 {
29672   #define MSG_BOX(Dialog, Child) XmMessageBoxGetChild(Dialog, Child)
29673   if (!controls_dialog)
29674     {
29675       int n;
29676       Arg args[32];
29677       XmString go_away, xhelp, titlestr, xreset;
29678       Widget mainform, slider, reset_button;
29679 
29680       go_away = XmStringCreateLocalized((char *)I_GO_AWAY);
29681       xhelp = XmStringCreateLocalized((char *)I_HELP);
29682       titlestr = XmStringCreateLocalized((char *)"More controls");
29683       xreset = XmStringCreateLocalized((char *)"Reset");
29684 
29685       n = 0;
29686       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
29687       XtSetArg(args[n], XmNhelpLabelString, xhelp); n++;
29688       XtSetArg(args[n], XmNokLabelString, xreset); n++;
29689       XtSetArg(args[n], XmNcancelLabelString, go_away); n++;
29690       XtSetArg(args[n], XmNautoUnmanage, false); n++;
29691       XtSetArg(args[n], XmNdialogTitle, titlestr); n++;
29692       XtSetArg(args[n], XmNresizePolicy, XmRESIZE_GROW); n++;
29693       XtSetArg(args[n], XmNnoResize, false); n++;
29694       XtSetArg(args[n], XmNtransient, false); n++;
29695       XtSetArg(args[n], XmNwidth, 400); n++;
29696       controls_dialog = XmCreateTemplateDialog(main_shell(ss), (char *)"More controls", args, n);
29697       reset_button = MSG_BOX(controls_dialog, XmDIALOG_OK_BUTTON);
29698 
29699       XtAddCallback(controls_dialog, XmNhelpCallback,   controls_help_callback,  NULL);
29700       /* XtAddCallback(controls_dialog, XmNokCallback,  controls_reset_callback, NULL); */
29701       XtAddCallback(reset_button, XmNactivateCallback,  controls_reset_callback, NULL);
29702       XtAddCallback(controls_dialog, XmNcancelCallback, controls_quit_callback,  NULL);
29703 
29704       XmStringFree(xhelp);
29705       XmStringFree(go_away);
29706       XmStringFree(titlestr);
29707       XmStringFree(xreset);
29708 
29709       XtVaSetValues(MSG_BOX(controls_dialog, XmDIALOG_OK_BUTTON),     XmNarmColor,   ss->selection_color, NULL);
29710       XtVaSetValues(MSG_BOX(controls_dialog, XmDIALOG_HELP_BUTTON),   XmNarmColor,   ss->selection_color, NULL);
29711       XtVaSetValues(MSG_BOX(controls_dialog, XmDIALOG_CANCEL_BUTTON), XmNarmColor,   ss->selection_color, NULL);
29712       XtVaSetValues(MSG_BOX(controls_dialog, XmDIALOG_OK_BUTTON),     XmNbackground, ss->highlight_color, NULL);
29713       XtVaSetValues(MSG_BOX(controls_dialog, XmDIALOG_HELP_BUTTON),   XmNbackground, ss->highlight_color, NULL);
29714       XtVaSetValues(MSG_BOX(controls_dialog, XmDIALOG_CANCEL_BUTTON), XmNbackground, ss->highlight_color, NULL);
29715 
29716       mainform = XtVaCreateManagedWidget("formd", xmRowColumnWidgetClass, controls_dialog,
29717 					 XmNleftAttachment,   XmATTACH_FORM,
29718 					 XmNrightAttachment,  XmATTACH_FORM,
29719 					 XmNtopAttachment,    XmATTACH_FORM,
29720 					 XmNbottomAttachment, XmATTACH_WIDGET,
29721 					 XmNbottomWidget,     XmMessageBoxGetChild(controls_dialog, XmDIALOG_SEPARATOR),
29722 					 XmNorientation,      XmVERTICAL,
29723 					 NULL);
29724 
29725       titlestr = XmStringCreateLocalized((char *)"expand hop");
29726       slider = XtVaCreateManagedWidget("expand-hop", xmScaleWidgetClass, mainform,
29727 				       XmNorientation,   XmHORIZONTAL,
29728 				       XmNshowValue,     true,
29729 				       XmNminimum,       1,
29730 				       XmNmaximum,       300,
29731 				       XmNvalue,         (int)(expand_control_hop(ss) * 1000),
29732 				       XmNdecimalPoints, 3,
29733 				       XmNtitleString,   titlestr,
29734 				       XmNborderWidth,   1,
29735 				       XmNbackground,    ss->basic_color,
29736 				       NULL);
29737       XmStringFree(titlestr);
29738       XtAddCallback(slider, XmNvalueChangedCallback, expand_hop_callback, NULL);
29739       XtAddCallback(slider, XmNdragCallback, expand_hop_callback, NULL);
29740       controls[EXPAND_HOP] = slider;
29741 
29742       titlestr = XmStringCreateLocalized((char *)"expand length");
29743       slider = XtVaCreateManagedWidget("expand-length", xmScaleWidgetClass, mainform,
29744 				       XmNorientation,   XmHORIZONTAL,
29745 				       XmNshowValue,     true,
29746 				       XmNminimum,       10,
29747 				       XmNmaximum,       500,
29748 				       XmNvalue,         (int)(expand_control_length(ss) * 1000),
29749 				       XmNdecimalPoints, 3,
29750 				       XmNtitleString,   titlestr,
29751 				       XmNborderWidth,   1,
29752 				       XmNbackground,    ss->basic_color,
29753 				       NULL);
29754       XmStringFree(titlestr);
29755       XtAddCallback(slider, XmNvalueChangedCallback, expand_length_callback, NULL);
29756       XtAddCallback(slider, XmNdragCallback, expand_length_callback, NULL);
29757       controls[EXPAND_LENGTH] = slider;
29758 
29759       titlestr = XmStringCreateLocalized((char *)"expand ramp");
29760       slider = XtVaCreateManagedWidget("expand-ramp", xmScaleWidgetClass, mainform,
29761 				       XmNorientation,   XmHORIZONTAL,
29762 				       XmNshowValue,     true,
29763 				       XmNminimum,       10,
29764 				       XmNmaximum,       500,
29765 				       XmNvalue,         (int)(expand_control_ramp(ss) * 1000),
29766 				       XmNdecimalPoints, 3,
29767 				       XmNtitleString,   titlestr,
29768 				       XmNborderWidth,   1,
29769 				       XmNbackground,    ss->basic_color,
29770 				       NULL);
29771       XmStringFree(titlestr);
29772       XtAddCallback(slider, XmNvalueChangedCallback, expand_ramp_callback, NULL);
29773       XtAddCallback(slider, XmNdragCallback, expand_ramp_callback, NULL);
29774       controls[EXPAND_RAMP] = slider;
29775 
29776       titlestr = XmStringCreateLocalized((char *)"expand jitter");
29777       slider = XtVaCreateManagedWidget("expand-hop", xmScaleWidgetClass, mainform,
29778 				       XmNorientation,   XmHORIZONTAL,
29779 				       XmNshowValue,     true,
29780 				       XmNminimum,       0,
29781 				       XmNmaximum,       200,
29782 				       XmNvalue,         (int)(expand_control_jitter(ss) * 1000),
29783 				       XmNdecimalPoints, 3,
29784 				       XmNtitleString,   titlestr,
29785 				       XmNborderWidth,   1,
29786 				       XmNbackground,    ss->basic_color,
29787 				       NULL);
29788       XmStringFree(titlestr);
29789       XtAddCallback(slider, XmNvalueChangedCallback, expand_jitter_callback, NULL);
29790       XtAddCallback(slider, XmNdragCallback, expand_jitter_callback, NULL);
29791       controls[EXPAND_JITTER] = slider;
29792 
29793       titlestr = XmStringCreateLocalized((char *)"contrast amp");
29794       slider = XtVaCreateManagedWidget("contrast-amp", xmScaleWidgetClass, mainform,
29795 				       XmNorientation,   XmHORIZONTAL,
29796 				       XmNshowValue,     true,
29797 				       XmNminimum,       0,
29798 				       XmNmaximum,       2000,
29799 				       XmNvalue,         (int)(contrast_control_amp(ss) * 1000),
29800 				       XmNdecimalPoints, 3,
29801 				       XmNtitleString,   titlestr,
29802 				       XmNborderWidth,   1,
29803 				       XmNbackground,    ss->basic_color,
29804 				       NULL);
29805       XmStringFree(titlestr);
29806       XtAddCallback(slider, XmNvalueChangedCallback, contrast_amp_callback, NULL);
29807       XtAddCallback(slider, XmNdragCallback, contrast_amp_callback, NULL);
29808       controls[CONTRAST_AMP] = slider;
29809 
29810       titlestr = XmStringCreateLocalized((char *)"reverb lowpass");
29811       slider = XtVaCreateManagedWidget("reverb-lowpass", xmScaleWidgetClass, mainform,
29812 				       XmNorientation,   XmHORIZONTAL,
29813 				       XmNshowValue,     true,
29814 				       XmNminimum,       0,
29815 				       XmNmaximum,       1000,
29816 				       XmNvalue,         (int)(reverb_control_lowpass(ss) * 1000),
29817 				       XmNdecimalPoints, 3,
29818 				       XmNtitleString,   titlestr,
29819 				       XmNborderWidth,   1,
29820 				       XmNbackground,    ss->basic_color,
29821 				       NULL);
29822       XmStringFree(titlestr);
29823       XtAddCallback(slider, XmNvalueChangedCallback, reverb_lowpass_callback, NULL);
29824       XtAddCallback(slider, XmNdragCallback, reverb_lowpass_callback, NULL);
29825       controls[REVERB_LOWPASS] = slider;
29826 
29827       titlestr = XmStringCreateLocalized((char *)"reverb feedback");
29828       slider = XtVaCreateManagedWidget("reverb-feedback", xmScaleWidgetClass, mainform,
29829 				       XmNorientation,   XmHORIZONTAL,
29830 				       XmNshowValue,     true,
29831 				       XmNminimum,       0,
29832 				       XmNmaximum,       1250,
29833 				       XmNvalue,         (int)(reverb_control_feedback(ss) * 1000),
29834 				       XmNdecimalPoints, 3,
29835 				       XmNtitleString,   titlestr,
29836 				       XmNborderWidth,   1,
29837 				       XmNbackground,    ss->basic_color,
29838 				       NULL);
29839       XmStringFree(titlestr);
29840       XtAddCallback(slider, XmNvalueChangedCallback, reverb_feedback_callback, NULL);
29841       XtAddCallback(slider, XmNdragCallback, reverb_feedback_callback, NULL);
29842       controls[REVERB_FEEDBACK] = slider;
29843 
29844       set_dialog_widget(CONTROLS_DIALOG, controls_dialog);
29845     }
29846 
29847   if (!XtIsManaged(controls_dialog))
29848     XtManageChild(controls_dialog);
29849 }
29850 
29851 
29852 /* ---------------------------------------- */
29853 
g_sound_widgets(Xen snd)29854 static Xen g_sound_widgets(Xen snd)
29855 {
29856   #define H_sound_widgets "(" S_sound_widgets " :optional snd): a list of \
29857 widgets: (0)pane (1)name (2)control-panel (3)status area (4)play-button (5)filter-env (6)unite-button (7)name-label (8)name-icon (9)sync-button"
29858 
29859   snd_info *sp;
29860 
29861   Snd_assert_sound(S_sound_widgets, snd, 1);
29862 
29863   sp = get_sp(snd);
29864   if (!sp)
29865     return(snd_no_such_sound_error(S_sound_widgets, snd));
29866   if (!has_widgets(sp))
29867     return(Xen_empty_list);
29868 
29869   return(Xen_cons(Xen_wrap_widget(SND_PANE(sp)),
29870 	  Xen_cons(Xen_wrap_widget(SND_NAME(sp)),
29871            Xen_cons(Xen_wrap_widget(CONTROLS(sp)),
29872 	    Xen_cons(Xen_wrap_widget(STATUS_AREA(sp)),
29873 #if WITH_AUDIO
29874 	     Xen_cons(Xen_wrap_widget(PLAY_BUTTON(sp)),
29875 #else
29876 	     Xen_cons(Xen_false,
29877 #endif
29878 	      Xen_cons(Xen_wrap_widget(FILTER_GRAPH(sp)), /* this is the drawingarea widget */
29879 	       Xen_cons(Xen_wrap_widget(UNITE_BUTTON(sp)),
29880 		Xen_cons(Xen_false,
29881 	         Xen_cons(Xen_wrap_widget(LOCK_OR_BOMB(sp)),
29882 	          Xen_cons(Xen_wrap_widget(SYNC_BUTTON(sp)),
29883 	           Xen_empty_list)))))))))));
29884 }
29885 
29886 
29887 #define FALLBACK_FONT        "fixed"
29888 #define DEFAULT_LISTENER_FONT "9x15"
29889 #define DEFAULT_FONTLIST     "9x15"
29890 
29891 #define HIGHLIGHT_COLOR      "ivory1"
29892 #define BASIC_COLOR          "ivory2"
29893 #define POSITION_COLOR       "ivory3"
29894 #define ZOOM_COLOR           "ivory4"
29895 #define CURSOR_COLOR         "red"
29896 #define SELECTION_COLOR      "lightsteelblue1"
29897 #define ENVED_WAVEFORM_COLOR "blue"
29898 #define MIX_COLOR            "darkgray"
29899 #define GRAPH_COLOR          "white"
29900 #define SELECTED_GRAPH_COLOR "white"
29901 #define DATA_COLOR           "black"
29902 #define SELECTED_DATA_COLOR  "black"
29903 #define MARK_COLOR           "red"
29904 #define LISTENER_COLOR       "AliceBlue"
29905 #define LISTENER_TEXT_COLOR  "black"
29906 #define LIGHT_BLUE_COLOR     "lightsteelblue1"
29907 #define LIGHTER_BLUE_COLOR   "AliceBlue"
29908 #define WHITE_COLOR          "white"
29909 #define BLACK_COLOR          "black"
29910 #define GREEN_COLOR          "green2"
29911 #define RED_COLOR            "red"
29912 #define YELLOW_COLOR         "yellow"
29913 #define TEXT_FOCUS_COLOR     "white"
29914 #define FILTER_CONTROL_WAVEFORM_COLOR "blue"
29915 #define SASH_COLOR           "lightgreen"
29916 #define CHANNEL_SASH_INDENT  -10
29917 #define CHANNEL_SASH_SIZE    0
29918 /* 0 means: use Motif default size */
29919 
29920 #define POSITION_SLIDER_WIDTH 13
29921 #define ZOOM_SLIDER_WIDTH 10
29922 #if (!__linux__) && (!_LINUX__)
29923   #define TOGGLE_SIZE 0
29924 #else
29925   #define TOGGLE_SIZE 15
29926 #endif
29927 #define CHANNEL_MIN_HEIGHT 150  /* open size (set to 5 immediately thereafter) */
29928                                 /* paned window default setup is not very smart, so we force these to be this size to begin with */
29929                                 /* this number is only a first approximation -- we try not to expand below the screen */
29930                                 /* if too small (i.e. 100), the scrollbars are sometimes messed up on the initial layout */
29931 
29932 #define SASH_SIZE 16
29933 #define SASH_INDENT -20
29934 #define AUTO_RESIZE_DEFAULT 1
29935 
29936 #define INITIAL_WINDOW_WIDTH 700
29937 #define INITIAL_WINDOW_HEIGHT 300
29938 
29939 
window_close(Widget w,XtPointer context,XtPointer info)29940 static void window_close(Widget w, XtPointer context, XtPointer info)
29941 {
29942   /* this is called from the window manager close event, not (exit) or the File:Exit item */
29943   snd_exit_cleanly(EXIT_FORCED);
29944 }
29945 
29946 
29947 static XtIntervalId auto_update_proc = 0;
29948 
auto_update_check(XtPointer context,XtIntervalId * id)29949 static void auto_update_check(XtPointer context, XtIntervalId *id)
29950 {
29951   if (auto_update_interval(ss) > 0.0)
29952     {
29953       if (!(play_in_progress()))
29954 	for_each_sound(sound_not_current);
29955       auto_update_proc = XtAppAddTimeOut(main_app(ss),
29956 					 (unsigned long)(auto_update_interval(ss) * 1000),
29957 					 (XtTimerCallbackProc)auto_update_check,
29958 					 context);
29959     }
29960   else auto_update_proc = 0;
29961 }
29962 
29963 
auto_update_restart(void)29964 void auto_update_restart(void)
29965 {
29966   if (auto_update_proc == 0)
29967     auto_update_proc = XtAppAddTimeOut(main_app(ss),
29968 				       (unsigned long)(auto_update_interval(ss) * 1000),
29969 				       (XtTimerCallbackProc)auto_update_check,
29970 				       (XtPointer)NULL);
29971 }
29972 
29973 
29974 
29975 /* handle iconification */
29976 static Widget *iconify_active_dialogs = NULL;
29977 
minify_maxify_window(Widget w,XtPointer context,XEvent * event,Boolean * cont)29978 static void minify_maxify_window(Widget w, XtPointer context, XEvent *event, Boolean *cont)
29979 {
29980   XMapEvent *ev = (XMapEvent *)event;
29981   if ((!ss) || (!(ss->dialogs)))
29982     return;
29983 
29984   /* ev->type can be several things, but the ones we care about here are
29985    * MapNotify and UnmapNotify.  Snd dialogs are "windows" in X-jargon, so
29986    * when the main window is minimized (iconified), other active dialogs
29987    * aren't also closed unless we mess with them explicitly here.  We keep
29988    * a list of created dialogs, and depend on XtIsManaged to tell us which
29989    * ones need to be unmanaged. But, if the user has several "desks", a change
29990    * of desk can also generate an unmap event, and if we dismiss the dialogs,
29991    * they don't come back upon remap; if we save a list of live dialogs, they
29992    * don't return to their previous location upon being re-managed.  We
29993    * need to see just iconfication events here, but there's no way I can
29994    * see to distinguish an iconify event from a desk event (WM_STATE atom state
29995    * of property changed event is identical etc), so I'll do what I can...
29996    * This problem may be a side-effect of using non-transient dialogs:
29997    * perhaps XSetTransientFor would handle this more cleanly?
29998    *
29999    * Also, ideally we'd equalize/relative-panes upon maxify, but ICCC thinks maxify
30000    *   is the same as map (i.e. from iconified state), and the only difference
30001    *   I can see in the mwm code is the window size.
30002    *
30003    * a rumor in the air that what we need is to catch StructureNotify event, then
30004    *   check in that for UnmapNotify
30005    */
30006   if (ev->type == UnmapNotify)
30007     {
30008       Atom _NET_WM_STATE, _NET_WM_STATE_HIDDEN, actual_type;
30009       int actual_format;
30010       unsigned long nitems, bytes_after;
30011       unsigned char *prop = NULL;
30012 
30013       /* this code thanks to Tito Latini */
30014       _NET_WM_STATE = XInternAtom(main_display(ss), "_NET_WM_STATE", false);
30015       _NET_WM_STATE_HIDDEN = XInternAtom(main_display(ss), "_NET_WM_STATE_HIDDEN", false);
30016 
30017       if (XGetWindowProperty(main_display(ss), XtWindow(w), _NET_WM_STATE, 0, 1024,
30018                              false, XA_ATOM, &actual_type, &actual_format, &nitems,
30019                              &bytes_after, &prop) == Success)
30020         {
30021           Atom *atoms = (Atom *)prop;
30022           bool iconified = false;
30023 	  unsigned long i;
30024           for (i = 0; i < nitems; i++)
30025             {
30026               if (atoms[i] == _NET_WM_STATE_HIDDEN)
30027                 {
30028                   iconified = true;
30029                   break;
30030                 }
30031             }
30032           XFree(prop);
30033           if (!iconified) return;
30034         }
30035 
30036       if (iconify_active_dialogs) free(iconify_active_dialogs);
30037       iconify_active_dialogs = (Widget *)calloc(ss->num_dialogs, sizeof(Widget));
30038 
30039       {
30040 	int i;
30041 	for (i = 0; i < ss->num_dialogs; i++)
30042 	  if (ss->dialogs[i])
30043 	    {
30044 	      if (XtIsManaged(ss->dialogs[i]))
30045 		iconify_active_dialogs[i] = ss->dialogs[i];
30046 	      XtUnmanageChild(ss->dialogs[i]);
30047 	    }
30048       }
30049     }
30050   else
30051     {
30052       if (ev->type == MapNotify)
30053 	{
30054 	  if (iconify_active_dialogs)
30055 	    {
30056 	      int i;
30057 	      for (i = 0; i < ss->num_dialogs; i++)
30058 		if (iconify_active_dialogs[i])
30059 		  XtManageChild(iconify_active_dialogs[i]);
30060 
30061 	      free(iconify_active_dialogs);
30062 	      iconify_active_dialogs = NULL;
30063 	    }
30064 	}
30065     }
30066 }
30067 
30068 
30069 #ifndef _MSC_VER
30070 #include <setjmp.h>
30071 
30072 static jmp_buf top_level_jump;
30073 
30074 void top_level_catch(int ignore);
top_level_catch(int ignore)30075 void top_level_catch(int ignore)
30076 {
30077   siglongjmp(top_level_jump, 1);
30078 }
30079 #endif
30080 
30081 
30082 static char **auto_open_file_names = NULL;
30083 static int auto_open_files = 0;
30084 static bool noglob = false, noinit = false, batch = false, nostdin = false;
30085 
30086 #if HAVE_EXTENSION_LANGUAGE
30087 static XtInputId stdin_id = 0;
30088 
get_stdin_string(XtPointer context,int * fd,XtInputId * id)30089 static void get_stdin_string(XtPointer context, int *fd, XtInputId *id)
30090 {
30091   int size;
30092   ssize_t bytes;
30093   char *buf;
30094   buf = (char *)calloc(1024, sizeof(char));
30095   size = 1024;
30096   bytes = read(*fd, buf, 1024);
30097   if (bytes <= 0)
30098     {
30099       /* redirected to /dev/null?? -- apparently in kde/kfm the process is started without stdin? */
30100       XtRemoveInput(stdin_id);
30101       stdin_id = 0;
30102     }
30103   else
30104     {
30105       while (bytes == 1024)
30106 	{
30107 	  size += 1024;
30108 	  buf = (char *)realloc(buf, size);
30109 	  bytes = read(*fd, (char *)(buf + size - 1024), 1024);
30110 	}
30111       snd_eval_stdin_str(buf);
30112     }
30113   free(buf);
30114 }
30115 #endif
30116 
30117 
startup_funcs(void)30118 static void startup_funcs(void)
30119 {
30120   Atom wm_delete_window;
30121   Display *dpy;
30122   Widget shell;
30123   static int auto_open_ctr = 0;
30124 
30125   ss->file_monitor_ok = initialize_file_monitor();
30126 
30127   shell = ss->mainshell;
30128   dpy = main_display(ss);
30129 
30130 #ifndef __alpha__
30131   add_menu_drop();
30132 #endif
30133 
30134   /* trap outer-level Close for cleanup check */
30135   wm_delete_window = XmInternAtom(dpy, (char *)"WM_DELETE_WINDOW", false);
30136   XmAddWMProtocolCallback(shell, wm_delete_window, window_close, NULL);
30137   XtAddEventHandler(shell, StructureNotifyMask, false, minify_maxify_window, NULL);
30138 
30139   ss->graph_cursor = XCreateFontCursor(XtDisplay(main_shell(ss)), in_graph_cursor(ss));
30140   ss->wait_cursor = XCreateFontCursor(XtDisplay(main_shell(ss)), XC_watch);
30141   ss->bounds_cursor = XCreateFontCursor(XtDisplay(main_shell(ss)), XC_sb_h_double_arrow);
30142   ss->yaxis_cursor = XCreateFontCursor(XtDisplay(main_shell(ss)), XC_sb_v_double_arrow);
30143   ss->play_cursor = XCreateFontCursor(XtDisplay(main_shell(ss)), XC_sb_right_arrow);
30144   ss->loop_play_cursor = XCreateFontCursor(XtDisplay(main_shell(ss)), XC_sb_left_arrow);
30145 
30146 #if HAVE_EXTENSION_LANGUAGE
30147   snd_load_init_file(noglob, noinit);
30148 #endif
30149 
30150 #if (!_MSC_VER) && HAVE_EXTENSION_LANGUAGE && !__MINGW32__
30151   if (!nostdin)
30152     {
30153       signal(SIGTTIN, SIG_IGN);
30154       signal(SIGTTOU, SIG_IGN);
30155       /* these signals are sent by a shell if we start Snd as a background process,
30156        * but try to read stdin (needed to support the emacs subjob connection).  If
30157        * we don't do this, the background job is suspended when the shell sends SIGTTIN.
30158        */
30159       stdin_id = XtAppAddInput(main_app(ss),
30160 			       STDIN_FILENO,
30161 			       (XtPointer)XtInputReadMask,
30162 			       get_stdin_string,
30163 			       NULL);
30164     }
30165 #endif
30166 
30167   while (auto_open_ctr < auto_open_files)
30168     auto_open_ctr = handle_next_startup_arg(auto_open_ctr, auto_open_file_names, false, auto_open_files);
30169 
30170   if (ss->init_window_width > 0) set_widget_width(main_shell(ss), ss->init_window_width);
30171   if (ss->init_window_height > 0) set_widget_height(main_shell(ss), ss->init_window_height);
30172   if (ss->init_window_x != DEFAULT_INIT_WINDOW_X) set_widget_x(main_shell(ss), ss->init_window_x);
30173   if (ss->init_window_y != DEFAULT_INIT_WINDOW_Y) set_widget_y(main_shell(ss), ss->init_window_y);
30174 
30175   if (!ss->file_monitor_ok)
30176     {
30177       if (auto_update_interval(ss) > 0.0)
30178 	XtAppAddTimeOut(main_app(ss),
30179 			(unsigned long)(auto_update_interval(ss) * 1000),
30180 			auto_update_check,
30181 			NULL);
30182     }
30183 
30184 
30185   if ((ss->sounds) &&
30186       (ss->selected_sound == NO_SELECTION))
30187     {
30188       snd_info *sp;
30189       sp = ss->sounds[0];
30190       if ((sp) &&
30191 	  (sp->inuse == SOUND_NORMAL) &&
30192 	  (sp->selected_channel == NO_SELECTION)) /* don't clobber possible select-channel in loaded startup files */
30193 	select_channel(sp, 0);
30194     }
30195 
30196   if ((ss->init_window_height == 0) && (sound_style(ss) == SOUNDS_HORIZONTAL))
30197     set_widget_height(main_shell(ss), 200); /* otherwise it's just a title bar! */
30198 }
30199 
30200 
SetupIcon(Widget shell)30201 static void SetupIcon(Widget shell)
30202 {
30203   Display *dpy;
30204   Window root;
30205   int scr;
30206   Pixmap pix, mask;
30207   XpmAttributes attributes;
30208   dpy = XtDisplay(shell);
30209   root = DefaultRootWindow(dpy);
30210   scr = DefaultScreen(dpy);
30211   XtVaGetValues(shell, XmNdepth, &attributes.depth, XmNcolormap, &attributes.colormap, NULL);
30212   attributes.visual = DefaultVisual(dpy, scr);
30213   attributes.valuemask = XpmDepth | XpmColormap | XpmVisual;
30214   XpmCreatePixmapFromData(dpy, root, (char **)snd_icon_bits(), &pix, &mask, &attributes);
30215   if (mask) XFreePixmap(dpy, mask);
30216   XtVaSetValues(shell, XmNiconPixmap, pix, NULL);
30217 }
30218 
30219 
muffle_warning(char * name,char * type,char * klass,char * defaultp,char ** params,uint32_t * num_params)30220 static void muffle_warning(char *name, char *type, char *klass, char *defaultp, char **params, uint32_t *num_params)
30221 {
30222 }
30223 
30224 
notebook_page_changed_callback(Widget w,XtPointer context,XtPointer info)30225 static void notebook_page_changed_callback(Widget w, XtPointer context, XtPointer info)
30226 {
30227   /* if page chosen via major tab click, select that sound */
30228   XmNotebookCallbackStruct *nb = (XmNotebookCallbackStruct *)info;
30229   Widget page;
30230   if ((nb->reason == XmCR_MAJOR_TAB) && (nb->page_widget))
30231     {
30232       page = nb->page_widget;
30233       if (page)
30234 	{
30235 	  int index;
30236 	  intptr_t data;
30237 	  XtVaGetValues(page, XmNuserData, &data, NULL);
30238 	  index = (int)data;
30239 	  if ((index < ss->max_sounds) &&
30240 	      (snd_ok(ss->sounds[index])))
30241 	    {
30242 	      snd_info *sp;
30243 	      sp = ss->sounds[index];
30244 	      if (sp->selected_channel == NO_SELECTION)
30245 		select_channel(ss->sounds[index], 0);
30246 	      else select_channel(ss->sounds[index], sp->selected_channel);
30247 	    }
30248 	}
30249     }
30250 }
30251 
30252 
get_in_between_color(color_t fg,color_t bg)30253 color_t get_in_between_color(color_t fg, color_t bg)
30254 {
30255   Colormap cmap;
30256   Display *dpy;
30257   int scr;
30258   XColor fg_color, bg_color, new_color;
30259   dpy = main_display(ss);
30260   scr = DefaultScreen(dpy);
30261   cmap = DefaultColormap(dpy, scr);
30262   fg_color.flags = DoRed | DoGreen | DoBlue;
30263   fg_color.pixel = fg;
30264   XQueryColor(dpy, cmap, &fg_color);
30265   bg_color.flags = DoRed | DoGreen | DoBlue;
30266   bg_color.pixel = bg;
30267   XQueryColor(dpy, cmap, &bg_color);
30268   new_color.flags = DoRed | DoGreen | DoBlue;
30269   new_color.red = (rgb_t)((fg_color.red + (2 * bg_color.red)) / 3);
30270   new_color.green = (rgb_t)((fg_color.green + (2 * bg_color.green)) / 3);
30271   new_color.blue = (rgb_t)((fg_color.blue + (2 * bg_color.blue)) / 3);
30272   if ((XAllocColor(dpy, cmap, &new_color)) == 0)
30273     return(fg);
30274   return(new_color.pixel);
30275 }
30276 
30277 
get_color(Widget shell,const char * defined_color,const char * fallback_color,const char * second_fallback_color,bool use_white)30278 static Pixel get_color(Widget shell, const char *defined_color,
30279 		       const char *fallback_color, const char *second_fallback_color, bool use_white)
30280 {
30281   Colormap cmap;
30282   Display *dpy;
30283   int scr;
30284   XColor tmp_color, ignore;
30285 
30286   dpy = XtDisplay(shell);
30287   scr = DefaultScreen(dpy);
30288   cmap = DefaultColormap(dpy, scr);
30289   /* I suppose we could use XQueryColors and search for the closest available, or try yet again to get XCreateColormap to behave itself */
30290 
30291   if ((!XAllocNamedColor(dpy, cmap, defined_color, &tmp_color, &ignore)) &&
30292       ((!fallback_color) ||
30293        (!XAllocNamedColor(dpy, cmap, fallback_color, &tmp_color, &ignore))) &&
30294       ((!second_fallback_color) ||
30295        (!XAllocNamedColor(dpy, cmap, second_fallback_color, &tmp_color, &ignore))))
30296     {
30297       /* snd_error here causes a seg fault (it builds on mainpane which has not yet been created) */
30298       if (use_white)
30299 	{
30300 	  fprintf(stderr, "can't get color %s -- will use white\n", defined_color);
30301 	  return(WhitePixel(dpy, scr));
30302 	}
30303       else
30304 	{
30305 	  fprintf(stderr, "can't get color %s -- will use black\n", defined_color);
30306 	  return(BlackPixel(dpy, scr));
30307 	}
30308     }
30309   return(tmp_color.pixel);
30310 }
30311 
30312 
save_a_color(FILE * Fp,Display * dpy,Colormap cmap,const char * name,Pixel pix,const char * ext_name)30313 static void save_a_color(FILE *Fp, Display *dpy, Colormap cmap, const char *name, Pixel pix, const char *ext_name)
30314 {
30315 #if HAVE_EXTENSION_LANGUAGE
30316   Status lookup_ok;
30317   XColor default_color, ignore;
30318 
30319   lookup_ok = XLookupColor(dpy, cmap, name, &default_color, &ignore);
30320   if (lookup_ok)
30321     {
30322       XColor current_color;
30323       current_color.flags = DoRed | DoGreen | DoBlue;
30324       current_color.pixel = pix;
30325       XQueryColor(dpy, cmap, &current_color);
30326       if ((current_color.red != default_color.red) ||
30327 	  (current_color.green != default_color.green) ||
30328 	  (current_color.blue != default_color.blue))
30329 
30330 #if HAVE_FORTH
30331 	fprintf(Fp, "%.3f %.3f %.3f %s set-%s drop\n",
30332 		rgb_to_float(current_color.red),
30333 		rgb_to_float(current_color.green),
30334 		rgb_to_float(current_color.blue),
30335 		S_make_color,
30336 		ext_name);
30337 #else
30338 
30339 #if HAVE_SCHEME
30340 	fprintf(Fp, "(set! (%s) (%s %.3f %.3f %.3f))\n",
30341 #endif
30342 
30343 #if HAVE_RUBY
30344 	fprintf(Fp, "set_%s(%s(%.3f, %.3f, %.3f))\n",
30345 #endif
30346 		to_proc_name(ext_name),
30347 		to_proc_name(S_make_color),
30348 		rgb_to_float(current_color.red),
30349 		rgb_to_float(current_color.green),
30350 		rgb_to_float(current_color.blue));
30351 #endif
30352     }
30353 #endif
30354 }
30355 
30356 
save_colors(FILE * Fp)30357 void save_colors(FILE *Fp)
30358 {
30359   Colormap cmap;
30360   Display *dpy;
30361   int scr;
30362 
30363   dpy = XtDisplay(ss->mainshell);
30364   scr = DefaultScreen(dpy);
30365   cmap = DefaultColormap(dpy, scr);
30366 
30367   save_a_color(Fp, dpy, cmap, BASIC_COLOR,          ss->basic_color,          S_basic_color);
30368   save_a_color(Fp, dpy, cmap, CURSOR_COLOR,         ss->cursor_color,         S_cursor_color);
30369   save_a_color(Fp, dpy, cmap, DATA_COLOR,           ss->data_color,           S_data_color);
30370   save_a_color(Fp, dpy, cmap, SELECTED_DATA_COLOR,  ss->selected_data_color,  S_selected_data_color);
30371   save_a_color(Fp, dpy, cmap, HIGHLIGHT_COLOR,      ss->highlight_color,      S_highlight_color);
30372   save_a_color(Fp, dpy, cmap, POSITION_COLOR,       ss->position_color,       S_position_color);
30373   save_a_color(Fp, dpy, cmap, ZOOM_COLOR,           ss->zoom_color,           S_zoom_color);
30374   save_a_color(Fp, dpy, cmap, SELECTION_COLOR,      ss->selection_color,      S_selection_color);
30375   save_a_color(Fp, dpy, cmap, MIX_COLOR,            ss->mix_color,            S_mix_color);
30376   save_a_color(Fp, dpy, cmap, ENVED_WAVEFORM_COLOR, ss->enved_waveform_color, S_enved_waveform_color);
30377   save_a_color(Fp, dpy, cmap, LISTENER_COLOR,       ss->listener_color,       S_listener_color);
30378   save_a_color(Fp, dpy, cmap, LISTENER_TEXT_COLOR,  ss->listener_text_color,  S_listener_text_color);
30379   save_a_color(Fp, dpy, cmap, GRAPH_COLOR,          ss->graph_color,          S_graph_color);
30380   save_a_color(Fp, dpy, cmap, SELECTED_GRAPH_COLOR, ss->selected_graph_color, S_selected_graph_color);
30381   save_a_color(Fp, dpy, cmap, MARK_COLOR,           ss->mark_color,           S_mark_color);
30382   save_a_color(Fp, dpy, cmap, SASH_COLOR,           ss->sash_color,           S_sash_color);
30383   save_a_color(Fp, dpy, cmap, TEXT_FOCUS_COLOR,     ss->text_focus_color,     S_text_focus_color);
30384   save_a_color(Fp, dpy, cmap, FILTER_CONTROL_WAVEFORM_COLOR, ss->filter_control_waveform_color, S_filter_control_waveform_color);
30385 }
30386 
30387 
30388 static char *fallbacks[] = {
30389   (char *)"*fontList: " DEFAULT_FONTLIST,
30390   (char *)"*enableEtchedInMenu: True",
30391   (char *)"*enableThinThickness: True",
30392   (char *)"*enableToggleColor: True",
30393   (char *)"*enableToggleVisual: True",
30394  NULL
30395 };
30396 
30397 
snd_doit(int argc,char ** argv)30398 void snd_doit(int argc, char **argv)
30399 {
30400   XtAppContext app;
30401   Widget shell;
30402   Display *dpy;
30403   Drawable wn;
30404   Arg args[32];
30405   int i, n;
30406   Widget menu;
30407   XGCValues gv;
30408   char *app_title = NULL;
30409 
30410   int err = 0;
30411   XtSetLanguageProc(NULL, NULL, NULL);
30412 
30413   ss->channel_min_height = CHANNEL_MIN_HEIGHT;
30414   ss->Graph_Cursor = DEFAULT_GRAPH_CURSOR;
30415 
30416 #ifndef __alpha__
30417   XtSetArg(args[0], XtNwidth, INITIAL_WINDOW_WIDTH);
30418   XtSetArg(args[1], XtNheight, INITIAL_WINDOW_HEIGHT);
30419   shell = XtAppInitialize(&app, "Snd", NULL, 0, &argc, argv, fallbacks, args, 2);
30420 #else
30421   shell = XtVaOpenApplication(&app, "Snd", NULL, 0, &argc, argv, fallbacks, applicationShellWidgetClass,
30422 			      XmNallowShellResize, AUTO_RESIZE_DEFAULT,
30423 			      NULL);
30424 #endif
30425 
30426 #ifndef _MSC_VER
30427   setlocale(LC_NUMERIC, "C");
30428 #endif
30429 
30430   /* if user has *keyboardFocusPolicy: Pointer in .Xdefaults, it can screw up Snd's attempt to
30431    * keep the channel graphics window as the active widget in case of keyboard input.  So,
30432    * we try to force Snd's focus policy to be XmEXPLICIT
30433    */
30434   XtVaGetValues(shell, XmNkeyboardFocusPolicy, &err, NULL);
30435   if (err != XmEXPLICIT)
30436     XtVaSetValues(shell, XmNkeyboardFocusPolicy, XmEXPLICIT, NULL);
30437 
30438   auto_open_files = argc - 1;
30439   if (argc > 1) auto_open_file_names = (char **)(argv + 1);
30440 
30441   dpy = XtDisplay(shell);
30442 
30443   XtVaGetValues(shell, XmNtitle, &app_title, NULL);  /* perhaps caller included -title arg */
30444   if (app_title)
30445     ss->startup_title = mus_strdup(app_title);
30446   else ss->startup_title = mus_strdup("snd");
30447 
30448   for (i = 1; i < argc; i++)
30449     if ((mus_strcmp(argv[i], "-h")) ||
30450 	(mus_strcmp(argv[i], "-horizontal")) ||
30451 	(mus_strcmp(argv[i], "--horizontal")))
30452       set_sound_style(SOUNDS_HORIZONTAL);
30453     else
30454       if ((mus_strcmp(argv[i], "-v")) ||
30455 	  (mus_strcmp(argv[i], "-vertical")) ||
30456 	  (mus_strcmp(argv[i], "--vertical")))
30457 	set_sound_style(SOUNDS_VERTICAL);
30458       else
30459 	if ((mus_strcmp(argv[i], "-notebook")) ||
30460 	    (mus_strcmp(argv[i], "--notebook")))
30461 	  {
30462 	    set_sound_style(SOUNDS_IN_NOTEBOOK);
30463 	    set_auto_resize(false);
30464 	  }
30465 	else
30466 	  if ((mus_strcmp(argv[i], "-separate")) ||
30467 	      (mus_strcmp(argv[i], "--separate")))
30468 	    set_sound_style(SOUNDS_IN_SEPARATE_WINDOWS);
30469 	  else
30470 	    if (mus_strcmp(argv[i], "-noglob"))
30471 	      noglob = true;
30472 	    else
30473 	      if (mus_strcmp(argv[i], "-noinit"))
30474 		noinit = true;
30475 	      else
30476 		if (mus_strcmp(argv[i], "-nostdin"))
30477 		  nostdin = true;
30478 		else
30479 		  if ((mus_strcmp(argv[i], "-b")) ||
30480 		      (mus_strcmp(argv[i], "-batch")) ||
30481 		      (mus_strcmp(argv[i], "--batch")))
30482 		    batch = true;
30483 		  else
30484 		    if (mus_strcmp(argv[i], "--features")) /* testing (compsnd) */
30485 		      check_features_list(argv[i + 1]);
30486 
30487   ss->batch_mode = batch;
30488   if (batch) XtSetMappedWhenManaged(shell, 0);
30489 
30490   ss->zoom_slider_width = ZOOM_SLIDER_WIDTH;
30491   ss->position_slider_width = POSITION_SLIDER_WIDTH;
30492   ss->channel_sash_indent = CHANNEL_SASH_INDENT;
30493   ss->channel_sash_size = CHANNEL_SASH_SIZE;
30494   ss->sash_size = SASH_SIZE;
30495   ss->sash_indent = SASH_INDENT;
30496   ss->toggle_size = TOGGLE_SIZE;
30497   ss->click_time = (oclock_t)XtGetMultiClickTime(dpy);
30498 
30499 #if HAVE_GL
30500   {
30501     /* this taken from glxmotif.c from xjournal/sgi */
30502     XVisualInfo *vi = NULL;
30503     Colormap cmap;
30504     GLXContext cx;
30505     int dblBuf[] = {GLX_RGBA, GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None};
30506     vi = glXChooseVisual(dpy, DefaultScreen(dpy), dblBuf);
30507     if (vi)
30508       ss->gl_has_double_buffer = true;
30509     else
30510       {
30511 	int snglBuf[] = {GLX_RGBA, GLX_DEPTH_SIZE, 16, None};
30512 	ss->gl_has_double_buffer = false;
30513 	vi = glXChooseVisual(dpy, DefaultScreen(dpy), snglBuf);
30514       }
30515     if (!vi)
30516       fprintf(stderr, "%s", "no RGB visual with desired depth\n"); /* not snd_error -- shell not ready yet */
30517     else
30518       {
30519 	/* create an OpenGL rendering context */
30520 	cx = glXCreateContext(dpy, vi, /* no display list sharing */ None, /* favor direct */ GL_TRUE);
30521 	if (!cx)
30522 	  fprintf(stderr, "%s", "could not create rendering context\n");
30523 	else
30524 	  {
30525 	    /* create an X colormap since probably not using default visual */
30526 	    cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone);
30527 	    XtVaSetValues(shell, XtNvisual, vi->visual, XtNdepth, vi->depth, XtNcolormap, cmap, NULL);
30528 	    ss->cx = cx;
30529 	  }
30530 	XFree(vi);
30531       }
30532   }
30533 #endif
30534 
30535   XtAppSetWarningMsgHandler(app, muffle_warning);
30536 
30537   ss->mainapp = app;
30538   ss->mainshell = shell;
30539   ss->mdpy = dpy;
30540   ss->toolbar = NULL;
30541 
30542   ss->white =                   get_color(shell, WHITE_COLOR,             NULL, NULL, true);
30543   ss->black =                   get_color(shell, BLACK_COLOR,             NULL, NULL, false);
30544   ss->light_blue =              get_color(shell, LIGHT_BLUE_COLOR,        "blue", NULL, true);
30545   ss->lighter_blue =            get_color(shell, LIGHTER_BLUE_COLOR,      "blue", NULL, true);
30546   ss->red =                     get_color(shell, RED_COLOR,               NULL, NULL, false);
30547   ss->green =                   get_color(shell, GREEN_COLOR,             NULL, NULL, false);
30548   ss->blue =                    get_color(shell, "blue",                  NULL, NULL, false);
30549   ss->yellow =                  get_color(shell, YELLOW_COLOR,            NULL, NULL, true);
30550   ss->highlight_color =         get_color(shell, HIGHLIGHT_COLOR,         "gray90", NULL, true);
30551   ss->basic_color =             get_color(shell, BASIC_COLOR,             "gray80", "gray", true);
30552   ss->position_color =          get_color(shell, POSITION_COLOR,          "gray60", "blue", false);
30553   ss->zoom_color =              get_color(shell, ZOOM_COLOR,              "gray20", "gray", false);
30554   ss->cursor_color =            get_color(shell, CURSOR_COLOR,            NULL, NULL, false);
30555   ss->selection_color =         get_color(shell, SELECTION_COLOR,         "gray80", NULL, false);
30556   ss->mix_color =               get_color(shell, MIX_COLOR,               "red", NULL, false);
30557   ss->enved_waveform_color =    get_color(shell, ENVED_WAVEFORM_COLOR,    "red", NULL, false);
30558   ss->filter_control_waveform_color = get_color(shell, FILTER_CONTROL_WAVEFORM_COLOR, "blue", NULL, false);
30559   ss->listener_color =          get_color(shell, LISTENER_COLOR,          NULL, NULL, true);
30560   ss->listener_text_color =     get_color(shell, LISTENER_TEXT_COLOR,     NULL, NULL, false);
30561   ss->graph_color =             get_color(shell, GRAPH_COLOR,             NULL, NULL, true);
30562   ss->selected_graph_color =    get_color(shell, SELECTED_GRAPH_COLOR,    NULL, NULL, true);
30563   ss->data_color =              get_color(shell, DATA_COLOR,              NULL, NULL, false);
30564   ss->selected_data_color =     get_color(shell, SELECTED_DATA_COLOR,     NULL, NULL, false);
30565   ss->mark_color =              get_color(shell, MARK_COLOR,              "red", NULL, false);
30566   ss->sash_color =              get_color(shell, SASH_COLOR,              NULL, NULL, false);
30567   ss->text_focus_color =        get_color(shell, TEXT_FOCUS_COLOR,        NULL, NULL, true);
30568   ss->grid_color = get_in_between_color(ss->data_color, ss->graph_color);
30569   ss->selected_grid_color = get_in_between_color(ss->selected_data_color, ss->selected_graph_color);
30570 
30571 #if HAVE_SCHEME
30572   s7_symbol_set_value(s7, ss->highlight_color_symbol,      Xen_wrap_pixel(ss->highlight_color));
30573   s7_symbol_set_value(s7, ss->basic_color_symbol,          Xen_wrap_pixel(ss->basic_color));
30574   s7_symbol_set_value(s7, ss->position_color_symbol,       Xen_wrap_pixel(ss->position_color));
30575   s7_symbol_set_value(s7, ss->zoom_color_symbol,           Xen_wrap_pixel(ss->zoom_color));
30576   s7_symbol_set_value(s7, ss->cursor_color_symbol,         Xen_wrap_pixel(ss->cursor_color));
30577   s7_symbol_set_value(s7, ss->selection_color_symbol,      Xen_wrap_pixel(ss->selection_color));
30578   s7_symbol_set_value(s7, ss->mix_color_symbol,            Xen_wrap_pixel(ss->mix_color));
30579   s7_symbol_set_value(s7, ss->enved_waveform_color_symbol, Xen_wrap_pixel(ss->enved_waveform_color));
30580   s7_symbol_set_value(s7, ss->filter_control_waveform_color_symbol, Xen_wrap_pixel(ss->filter_control_waveform_color));
30581   s7_symbol_set_value(s7, ss->listener_color_symbol,       Xen_wrap_pixel(ss->listener_color));
30582   s7_symbol_set_value(s7, ss->listener_text_color_symbol,  Xen_wrap_pixel(ss->listener_text_color));
30583   s7_symbol_set_value(s7, ss->graph_color_symbol,          Xen_wrap_pixel(ss->graph_color));
30584   s7_symbol_set_value(s7, ss->selected_graph_color_symbol, Xen_wrap_pixel(ss->selected_graph_color));
30585   s7_symbol_set_value(s7, ss->data_color_symbol,           Xen_wrap_pixel(ss->data_color));
30586   s7_symbol_set_value(s7, ss->selected_data_color_symbol,  Xen_wrap_pixel(ss->selected_data_color));
30587   s7_symbol_set_value(s7, ss->mark_color_symbol,           Xen_wrap_pixel(ss->mark_color));
30588   s7_symbol_set_value(s7, ss->sash_color_symbol,           Xen_wrap_pixel(ss->sash_color));
30589   s7_symbol_set_value(s7, ss->text_focus_color_symbol,     Xen_wrap_pixel(ss->text_focus_color));
30590 #endif
30591 
30592   ss->axis_color_set = false;
30593 
30594   ss->orig_data_color = ss->data_color;
30595   ss->orig_selected_data_color = ss->selected_data_color;
30596   ss->orig_mark_color = ss->mark_color;
30597   ss->orig_mix_color = ss->mix_color;
30598   ss->orig_graph_color = ss->graph_color;
30599   ss->orig_selected_graph_color = ss->selected_graph_color;
30600   ss->orig_listener_color = ss->listener_color;
30601   ss->orig_listener_text_color = ss->listener_text_color;
30602   ss->orig_cursor_color = ss->cursor_color;
30603   ss->orig_basic_color = ss->basic_color;
30604   ss->orig_selection_color = ss->selection_color;
30605   ss->orig_zoom_color = ss->zoom_color;
30606   ss->orig_position_color = ss->position_color;
30607   ss->orig_highlight_color = ss->highlight_color;
30608 
30609   if ((!(set_peaks_font(DEFAULT_PEAKS_FONT))) &&
30610       (!(set_peaks_font(FALLBACK_FONT))))
30611     fprintf(stderr, "can't find peaks font %s", DEFAULT_PEAKS_FONT);
30612 
30613   if ((!(set_tiny_font(DEFAULT_TINY_FONT))) &&
30614       (!(set_tiny_font(FALLBACK_FONT))))
30615     fprintf(stderr, "can't find tiny font %s", DEFAULT_TINY_FONT);
30616 
30617   if ((!(set_bold_peaks_font(DEFAULT_BOLD_PEAKS_FONT))) &&
30618       (!(set_bold_peaks_font(FALLBACK_FONT))))
30619     fprintf(stderr, "can't find bold peaks font %s", DEFAULT_BOLD_PEAKS_FONT);
30620 
30621   if ((!(set_axis_label_font(DEFAULT_AXIS_LABEL_FONT))) &&
30622       (!(set_axis_label_font(FALLBACK_FONT))))
30623     fprintf(stderr, "can't find axis label font %s", DEFAULT_AXIS_LABEL_FONT);
30624 
30625   if ((!(set_axis_numbers_font(DEFAULT_AXIS_NUMBERS_FONT))) &&
30626       (!(set_axis_numbers_font(FALLBACK_FONT))))
30627     fprintf(stderr, "can't find axis numbers font %s", DEFAULT_AXIS_NUMBERS_FONT);
30628 
30629   set_listener_font(DEFAULT_LISTENER_FONT); /* we need some sort of font here! */
30630 
30631   ss->orig_axis_label_font = mus_strdup(axis_label_font(ss));
30632   ss->orig_axis_numbers_font = mus_strdup(axis_numbers_font(ss));
30633   ss->orig_peaks_font = mus_strdup(peaks_font(ss));
30634   ss->orig_bold_peaks_font = mus_strdup(bold_peaks_font(ss));
30635   ss->orig_listener_font = mus_strdup(listener_font(ss));
30636   ss->orig_tiny_font = mus_strdup(tiny_font(ss));
30637 
30638   XtVaSetValues(shell, XmNbackground, ss->basic_color, NULL);
30639 
30640   n = 0;
30641   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
30642   n = attach_all_sides(args, n);
30643   XtSetArg(args[n], XmNallowResize, true); n++;
30644   ss->mainpane = XtCreateManagedWidget("mainpane", xmFormWidgetClass, shell, args, n);
30645 
30646   menu = add_menu();
30647 
30648   n = 0;
30649   XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
30650   XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
30651   XtSetArg(args[n], XmNtopWidget, menu); n++;
30652   XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
30653   XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
30654   XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
30655   XtSetArg(args[n], XmNallowResize, true); n++;
30656   XtSetArg(args[n], XmNpaneMaximum, LOTSA_PIXELS); n++;
30657   switch (sound_style(ss))
30658     {
30659     case SOUNDS_IN_SEPARATE_WINDOWS:
30660       ss->soundpane = XtCreateManagedWidget("soundpane", xmFormWidgetClass, ss->mainpane, args, n);
30661       break;
30662 
30663     case SOUNDS_HORIZONTAL:
30664       XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
30665       ss->soundpanebox = XtCreateManagedWidget("soundpane", xmPanedWindowWidgetClass, ss->mainpane, args, n);
30666 
30667       n = 0;
30668       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
30669       XtSetArg(args[n], XmNsashHeight, ss->sash_size); n++;
30670       XtSetArg(args[n], XmNsashWidth, ss->sash_size); n++;
30671       XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
30672       XtSetArg(args[n], XmNsashIndent, ss->sash_indent); n++;
30673       ss->soundpane = XtCreateManagedWidget("soundpane", xmPanedWindowWidgetClass, ss->soundpanebox, args, n);
30674       break;
30675 
30676     case SOUNDS_VERTICAL:
30677       XtSetArg(args[n], XmNsashHeight, ss->sash_size); n++;
30678       XtSetArg(args[n], XmNsashWidth, ss->sash_size); n++;
30679       XtSetArg(args[n], XmNsashIndent, ss->sash_indent); n++;
30680       ss->soundpane = XtCreateManagedWidget("soundpane", xmPanedWindowWidgetClass, ss->mainpane, args, n);
30681       break;
30682 
30683     case SOUNDS_IN_NOTEBOOK:
30684       XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
30685       ss->soundpanebox = XtCreateManagedWidget("soundpane", xmPanedWindowWidgetClass, ss->mainpane, args, n);
30686 
30687       n = 0;
30688       XtSetArg(args[n], XmNbackground, ss->basic_color); n++;
30689       XtSetArg(args[n], XmNframeBackground, ss->zoom_color); n++;
30690       XtSetArg(args[n], XmNbindingType, XmNONE); n++;
30691       XtSetArg(args[n], XmNbackPagePlacement, XmTOP_RIGHT); n++;
30692       XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
30693       ss->soundpane = XtCreateWidget("nb", xmNotebookWidgetClass, ss->soundpanebox, args, n);
30694 
30695       {
30696 	/* get rid of the useless spinbox */
30697 	n = 0;
30698 	XtSetArg(args[n], XmNnotebookChildType, XmPAGE_SCROLLER); n++;
30699 	XtCreateWidget("scroller", xmScrollBarWidgetClass, ss->soundpane, NULL, 0);
30700       }
30701       XtManageChild(ss->soundpane);
30702       XtAddCallback(ss->soundpane, XmNpageChangedCallback, notebook_page_changed_callback, NULL);
30703       map_over_children(ss->soundpane, set_main_color_of_widget); /* appears to be a no-op */
30704       break;
30705     }
30706 
30707   SetupIcon(shell);
30708   XtRealizeWidget(shell);
30709   if (auto_resize(ss) != AUTO_RESIZE_DEFAULT)
30710     XtVaSetValues(shell, XmNallowShellResize, auto_resize(ss), NULL);
30711 
30712   wn = XtWindow(shell);
30713   gv.background = ss->graph_color;
30714   gv.foreground = ss->data_color;
30715   ss->basic_gc = XCreateGC(dpy, wn, GCForeground | GCBackground, &gv);
30716 
30717   gv.background = ss->graph_color;
30718   gv.foreground = ss->data_color;
30719   ss->combined_basic_gc = XCreateGC(dpy, wn, GCForeground | GCBackground, &gv);
30720 
30721   gv.background = ss->graph_color;
30722   gv.foreground = ss->mix_color;
30723   ss->mix_gc = XCreateGC(dpy, wn, GCForeground | GCBackground, &gv);
30724 
30725   gv.function = GXxor;
30726   gv.background = ss->graph_color;
30727   gv.foreground = (Pixel)(XOR(ss->cursor_color, gv.background));
30728   ss->cursor_gc = XCreateGC(dpy, wn, GCForeground | GCFunction, &gv);
30729 
30730   gv.function = GXxor;
30731   gv.background = ss->graph_color;
30732   gv.foreground = (Pixel)(XOR(ss->selection_color, gv.background));
30733   ss->selection_gc = XCreateGC(dpy, wn, GCForeground | GCFunction, &gv);
30734 
30735   gv.function = GXxor;
30736   gv.background = ss->graph_color;
30737   gv.foreground = (Pixel)(XOR(ss->mark_color, gv.background));
30738   ss->mark_gc = XCreateGC(dpy, wn, GCForeground | GCFunction, &gv);
30739 
30740   gv.function = GXcopy;
30741   gv.background = ss->data_color;
30742   gv.foreground = ss->graph_color;
30743   ss->erase_gc = XCreateGC(dpy, wn, GCForeground | GCBackground | GCFunction, &gv);
30744 
30745   gv.background = ss->selected_graph_color;
30746   gv.foreground = ss->selected_data_color;
30747   ss->selected_basic_gc = XCreateGC(dpy, wn, GCForeground | GCBackground, &gv);
30748 
30749   gv.function = GXxor;
30750   gv.background = ss->selected_graph_color;
30751   gv.foreground = (Pixel)(XOR(ss->cursor_color, gv.background));
30752   ss->selected_cursor_gc = XCreateGC(dpy, wn, GCForeground | GCFunction, &gv);
30753 
30754   gv.function = GXxor;
30755   gv.background = ss->selected_graph_color;
30756   gv.foreground = (Pixel)(XOR(ss->selection_color, gv.background));
30757   ss->selected_selection_gc = XCreateGC(dpy, wn, GCForeground | GCFunction, &gv);
30758 
30759   gv.function = GXxor;
30760   gv.background = ss->selected_graph_color;
30761   gv.foreground = (Pixel)(XOR(ss->mark_color, gv.background));
30762   ss->selected_mark_gc = XCreateGC(dpy, wn, GCForeground | GCFunction, &gv);
30763 
30764   gv.function = GXcopy;
30765   gv.background = ss->selected_data_color;
30766   gv.foreground = ss->selected_graph_color;
30767   ss->selected_erase_gc = XCreateGC(dpy, wn, GCForeground | GCBackground | GCFunction, &gv);
30768 
30769   gv.function = GXcopy;
30770   gv.background = ss->basic_color;
30771   gv.foreground = ss->black;
30772   ss->fltenv_basic_gc = XCreateGC(dpy, wn, GCBackground | GCForeground | GCFunction, &gv);
30773 
30774   gv.function = GXcopy;
30775   gv.background = ss->basic_color;
30776   gv.foreground = ss->filter_control_waveform_color;
30777   ss->fltenv_data_gc = XCreateGC(dpy, wn, GCBackground | GCForeground | GCFunction, &gv);
30778 
30779   initialize_colormap(); /* X11 not ours */
30780   make_icons_transparent(BASIC_COLOR);
30781 
30782   if (with_toolbar(ss)) show_toolbar();
30783 
30784 #ifndef _MSC_VER
30785   if (sigsetjmp(top_level_jump, 1))
30786     {
30787       if (!(ss->jump_ok))
30788 	snd_error_without_format("Caught top level error (will try to continue):\n");
30789       else ss->jump_ok = false;
30790     }
30791   else
30792 #endif
30793     startup_funcs(); /* snd /tmp -> segfault if this happens before the setjmp(top_level_jump)  */
30794 
30795   if (ss->startup_errors)
30796     {
30797       post_it("Error in initialization", ss->startup_errors);
30798       free(ss->startup_errors);
30799       ss->startup_errors = NULL;
30800     }
30801 
30802   XtAppMainLoop(app);
30803 }
30804 
30805 
30806 /* -------------------------------------------------------------------------------- */
30807 
Xen_wrap_2_optional_args(g_find_dialog_w,g_find_dialog)30808 Xen_wrap_2_optional_args(g_find_dialog_w, g_find_dialog)
30809 Xen_wrap_no_args(g_find_dialog_widgets_w, g_find_dialog_widgets)
30810 Xen_wrap_1_arg(reflect_file_in_enved_w, reflect_file_in_enved)
30811 Xen_wrap_no_args(g_enved_filter_w, g_enved_filter)
30812 Xen_wrap_1_arg(g_set_enved_filter_w, g_set_enved_filter)
30813 Xen_wrap_no_args(g_enved_envelope_w, g_enved_envelope)
30814 Xen_wrap_1_arg(g_set_enved_envelope_w, g_set_enved_envelope)
30815 Xen_wrap_1_arg(reflect_file_in_region_browser_w, reflect_file_in_region_browser)
30816 Xen_wrap_no_args(g_view_regions_dialog_w, g_view_regions_dialog)
30817 Xen_wrap_1_arg(mix_open_file_watcher_w, mix_open_file_watcher)
30818 Xen_wrap_1_optional_arg(insert_open_file_watcher_w, insert_open_file_watcher)
30819 Xen_wrap_1_arg(vf_open_file_watcher_w, vf_open_file_watcher)
30820 Xen_wrap_1_optional_arg(g_view_files_sort_w, g_view_files_sort)
30821 Xen_wrap_2_optional_args(g_set_view_files_sort_w, g_set_view_files_sort)
30822 Xen_wrap_2_optional_args(g_add_directory_to_view_files_list_w, g_add_directory_to_view_files_list)
30823 Xen_wrap_2_optional_args(g_add_file_to_view_files_list_w, g_add_file_to_view_files_list)
30824 Xen_wrap_2_optional_args(g_view_files_dialog_w, g_view_files_dialog)
30825 Xen_wrap_1_arg(g_view_files_amp_w, g_view_files_amp)
30826 Xen_wrap_2_args(g_view_files_set_amp_w, g_view_files_set_amp)
30827 Xen_wrap_1_arg(g_view_files_speed_w, g_view_files_speed)
30828 Xen_wrap_2_args(g_view_files_set_speed_w, g_view_files_set_speed)
30829 Xen_wrap_1_arg(g_view_files_amp_env_w, g_view_files_amp_env)
30830 Xen_wrap_2_args(g_view_files_set_amp_env_w, g_view_files_set_amp_env)
30831 Xen_wrap_1_arg(g_view_files_speed_style_w, g_view_files_speed_style)
30832 Xen_wrap_2_args(g_view_files_set_speed_style_w, g_view_files_set_speed_style)
30833 Xen_wrap_1_arg(g_view_files_selected_files_w, g_view_files_selected_files)
30834 Xen_wrap_1_arg(g_view_files_files_w, g_view_files_files)
30835 Xen_wrap_2_args(g_view_files_set_selected_files_w, g_view_files_set_selected_files)
30836 Xen_wrap_2_args(g_view_files_set_files_w, g_view_files_set_files)
30837 Xen_wrap_1_arg(g_delete_file_sorter_w, g_delete_file_sorter)
30838 Xen_wrap_2_args(g_add_file_sorter_w, g_add_file_sorter)
30839 Xen_wrap_no_args(g_menu_widgets_w, g_menu_widgets)
30840 Xen_wrap_no_args(g_listener_selection_w, g_listener_selection)
30841 Xen_wrap_no_args(g_reset_listener_cursor_w, g_reset_listener_cursor)
30842 Xen_wrap_no_args(g_goto_listener_end_w, g_goto_listener_end)
30843 Xen_wrap_2_args(g_in_w, g_in)
30844 Xen_wrap_no_args(g_graph_cursor_w, g_graph_cursor)
30845 Xen_wrap_1_arg(g_set_graph_cursor_w, g_set_graph_cursor)
30846 Xen_wrap_2_optional_args(g_channel_widgets_w, g_channel_widgets)
30847 Xen_wrap_1_arg(reflect_file_close_in_sync_w, reflect_file_close_in_sync)
30848 Xen_wrap_1_optional_arg(g_sound_widgets_w, g_sound_widgets)
30849 
30850 static void add_reflect_enved_hook(void)
30851 {
30852   Xen_add_to_hook_list(ss->snd_open_file_hook, reflect_file_in_enved_w, "enved-file-open-handler", "enved dialog's file-open-hook handler");
30853 }
30854 
add_reflect_region_hook(void)30855 static void add_reflect_region_hook(void)
30856 {
30857   Xen_add_to_hook_list(ss->snd_open_file_hook, reflect_file_in_region_browser_w, "region-dialog-open-file-watcher", "region dialog open-file-hook handler");
30858 }
30859 
add_reflect_mix_hook(void)30860 static void add_reflect_mix_hook(void)
30861 {
30862   Xen_add_to_hook_list(ss->snd_open_file_hook, mix_open_file_watcher_w, "mix-dialog-open-file-watcher", "mix dialog's open-file-hook handler");
30863 }
30864 
add_reflect_insert_hook(void)30865 static void add_reflect_insert_hook(void)
30866 {
30867   Xen_add_to_hook_list(ss->snd_open_file_hook, insert_open_file_watcher_w, "insert-dialog-open-file-watcher", "insert dialog's open-file-hook handler");
30868 }
30869 
30870 
30871 #if HAVE_SCHEME
acc_view_files_sort(s7_scheme * sc,s7_pointer args)30872 static s7_pointer acc_view_files_sort(s7_scheme *sc, s7_pointer args) {return(g_set_view_files_sort(s7_cadr(args), s7_undefined(sc)));}
acc_graph_cursor(s7_scheme * sc,s7_pointer args)30873 static s7_pointer acc_graph_cursor(s7_scheme *sc, s7_pointer args) {return(g_set_graph_cursor(s7_cadr(args)));}
30874 #endif
30875 
30876 
30877   #define H_orientation_hook S_orientation_hook " (): called whenever one of the variables associated with the orientation dialog changes"
30878   #define H_color_hook S_color_hook " (): called whenever one of the variables associated with the color dialog changes"
30879   #define H_drop_hook S_drop_hook " (name): called whenever Snd receives a drag-and-drop \
30880 event. If it returns " PROC_TRUE ", the file is not opened or mixed by Snd."
30881   #define H_view_files_select_hook S_view_files_select_hook "(dialog name): called when a file is selected in the \
30882 files list of the View Files dialog.  If it returns " PROC_TRUE ", the default action, opening the file, is omitted."
30883 
30884   #define H_mouse_leave_label_hook S_mouse_leave_label_hook " (type position label): called when the mouse leaves a file viewer or region label"
30885   #define H_mouse_leave_text_hook S_mouse_leave_text_hook " (widget): called when the mouse leaves a text widget"
30886   #define H_listener_click_hook S_listener_click_hook " (position): called when listener clicked; position is text pos of click in listener"
30887   #define H_mouse_leave_listener_hook S_mouse_leave_listener_hook " (widget): called when the mouse leaves the lisp listener pane"
30888 
30889 #if HAVE_SCHEME
30890   #define H_mouse_enter_label_hook S_mouse_enter_label_hook " (type position label): called when the mouse enters a file viewer or region label. \
30891 The 'type' is 1 for view-files, and 2 for regions. The 'position' \
30892 is the scrolled list position of the label. The label itself is 'label'. We could use the 'finfo' procedure in examp.scm \
30893 to popup file info as follows: \n\
30894 (hook-push " S_mouse_enter_label_hook "\n\
30895   (lambda (type position name)\n\
30896     (if (not (= type 2))\n\
30897         (" S_info_dialog " name (finfo name)))))\n\
30898 See also nb.scm."
30899 #endif
30900 #if HAVE_RUBY
30901   #define H_mouse_enter_label_hook S_mouse_enter_label_hook " (type position label): called when the mouse enters a file viewer or region label. \
30902 The 'type' is 1 for view-files, and 2 for regions. The 'position' \
30903 is the scrolled list position of the label. The label itself is 'label'. We could use the 'finfo' procedure in examp.rb \
30904 to popup file info as follows: \n\
30905 $mouse_enter_label_hook.add_hook!(\"finfo\") do |type, position, name|\n\
30906   if type != 2\n\
30907     " S_info_dialog "(name, finfo(name))\n\
30908   end\n\
30909 end\n\
30910 See also nb.rb."
30911 #endif
30912 #if HAVE_FORTH
30913   #define H_mouse_enter_label_hook S_mouse_enter_label_hook " (type position label): called when the mouse enters a file viewer or region label. \
30914 The 'type' is 1 for view-files, and 2 for regions. The 'position' \
30915 is the scrolled list position of the label. The label itself is 'label'. We could use the 'finfo' procedure in examp.fs \
30916 to popup file info as follows: \n\
30917 " S_mouse_enter_label_hook " lambda: <{ type position name }>\n\
30918   type 2 <> if\n\
30919     name name finfo info-dialog\n\
30920   else\n\
30921     #f\n\
30922   then\n\
30923 ; add-hook!"
30924 #endif
30925 
30926 #if HAVE_SCHEME
30927   #define H_mouse_enter_graph_hook S_mouse_enter_graph_hook " (snd chn): called when the mouse \
30928 enters the drawing area (graph pane) of the given channel.\n\
30929   (hook-push " S_mouse_enter_graph_hook "\n\
30930     (lambda (hook)\n\
30931       (" S_focus_widget " (car (" S_channel_widgets " (hook 'snd) (hook 'chn))))))"
30932 
30933   #define H_mouse_leave_graph_hook S_mouse_leave_graph_hook " (snd chn): is called when the mouse \
30934 leaves the drawing area (graph pane) of the given channel."
30935 #endif
30936 #if HAVE_RUBY
30937   #define H_mouse_enter_graph_hook S_mouse_enter_graph_hook " (snd chn): called when the mouse \
30938 enters the drawing area (graph pane) of the given channel.\n\
30939   $mouse_enter_graph_hook.add-hook!(\"focus\") do |snd chn|\n\
30940     focus_widget(channel_widgets(snd, chn)[0])\n\
30941     end"
30942 
30943   #define H_mouse_leave_graph_hook S_mouse_leave_graph_hook " (snd chn): called when the mouse \
30944 leaves the drawing area (graph pane) of the given channel."
30945 #endif
30946 #if HAVE_FORTH
30947   #define H_mouse_enter_graph_hook S_mouse_enter_graph_hook " (snd chn): called when the mouse \
30948 enters the drawing area (graph pane) of the given channel.\n\
30949 " S_mouse_enter_graph_hook " lambda: <{ snd chn }>\n\
30950   snd chn " S_channel_widgets " car " S_focus_widget "\n\
30951 ; add-hook!"
30952   #define H_mouse_leave_graph_hook S_mouse_leave_graph_hook " (snd chn): is called when the mouse \
30953 leaves the drawing area (graph pane) of the given channel."
30954 #endif
30955 
30956 #if HAVE_SCHEME
30957   #define H_mouse_enter_listener_hook S_mouse_enter_listener_hook " (widget): called when the mouse \
30958 enters the lisp listener pane:\n\
30959   (hook-push " S_mouse_enter_listener_hook "\n\
30960     (lambda (hook)\n\
30961       (" S_focus_widget " (hook 'widget))))"
30962 #endif
30963 #if HAVE_RUBY
30964   #define H_mouse_enter_listener_hook S_mouse_enter_listener_hook " (listener): called when the mouse \
30965 enters the lisp listener pane:\n\
30966   $mouse_enter_listener_hook.add-hook!(\"enter\") do |widget|\n\
30967     focus_widget(widget)\n\
30968   end"
30969 #endif
30970 #if HAVE_FORTH
30971   #define H_mouse_enter_listener_hook S_mouse_enter_listener_hook " (listener): called when the mouse \
30972 enters the lisp listener pane:\n\
30973 " S_mouse_enter_listener_hook " lambda: <{ wid }> wid " S_focus_widget " ; add-hook!"
30974 #endif
30975 
30976 #if HAVE_SCHEME
30977   #define H_mouse_enter_text_hook S_mouse_enter_text_hook " (widget): called when the mouse enters a text widget:\n\
30978 (hook-push " S_mouse_enter_text_hook "\n\
30979   (lambda (w)\n\
30980     (" S_focus_widget " w)))"
30981 #endif
30982 #if HAVE_RUBY
30983   #define H_mouse_enter_text_hook S_mouse_enter_text_hook " (widget): called when the mouse enters a text widget:\n\
30984 $mouse_enter_text_hook.add_hook!(\"enter\") do |w|\n\
30985     focus_widget(w)\n\
30986   end"
30987 #endif
30988 #if HAVE_FORTH
30989   #define H_mouse_enter_text_hook S_mouse_enter_text_hook " (widget): called when the mouse enters a text widget:\n\
30990 " S_mouse_enter_text_hook " lambda: <{ wid }> wid " S_focus_widget " ; add-hook!"
30991 #endif
30992 
30993 
g_init_motif(void)30994 void g_init_motif(void)
30995 {
30996 #if HAVE_SCHEME
30997   s7_pointer i, b, p, t, r, s, l, fnc;
30998   i = s7_make_symbol(s7, "integer?");
30999   b = s7_make_symbol(s7, "boolean?");
31000   p = s7_make_symbol(s7, "pair?");
31001   l = s7_make_symbol(s7, "list?");
31002   r = s7_make_symbol(s7, "real?");
31003   s = s7_make_symbol(s7, "string?");
31004   fnc = s7_make_symbol(s7, "procedure?");
31005   t = s7_t(s7);
31006 #endif
31007 
31008   orientation_hook =          Xen_define_hook(S_orientation_hook,          "(make-hook)", 0,                        H_orientation_hook);
31009   color_hook =                Xen_define_hook(S_color_hook,                "(make-hook)", 0,                        H_color_hook);
31010   mouse_enter_label_hook =    Xen_define_hook(S_mouse_enter_label_hook,    "(make-hook 'type 'position 'label)", 3, H_mouse_enter_label_hook);
31011   mouse_leave_label_hook =    Xen_define_hook(S_mouse_leave_label_hook,    "(make-hook 'type 'position 'label)", 3, H_mouse_leave_label_hook);
31012   view_files_select_hook =    Xen_define_hook(S_view_files_select_hook,    "(make-hook 'dialog 'name)", 2,          H_view_files_select_hook);
31013   drop_hook =                 Xen_define_hook(S_drop_hook,                 "(make-hook 'name)", 1,                  H_drop_hook);
31014   mouse_enter_listener_hook = Xen_define_hook(S_mouse_enter_listener_hook, "(make-hook 'widget)", 1,                H_mouse_enter_listener_hook);
31015   mouse_leave_listener_hook = Xen_define_hook(S_mouse_leave_listener_hook, "(make-hook 'widget)", 1,                H_mouse_leave_listener_hook);
31016   mouse_enter_text_hook =     Xen_define_hook(S_mouse_enter_text_hook,     "(make-hook 'widget)", 1,                H_mouse_enter_text_hook);
31017   mouse_leave_text_hook =     Xen_define_hook(S_mouse_leave_text_hook,     "(make-hook 'widget)", 1,                H_mouse_leave_text_hook);
31018   listener_click_hook =       Xen_define_hook(S_listener_click_hook,       "(make-hook 'position)", 1,              H_listener_click_hook);
31019   mouse_enter_graph_hook =    Xen_define_hook(S_mouse_enter_graph_hook,    "(make-hook 'snd 'chn)", 2,              H_mouse_enter_graph_hook);
31020   mouse_leave_graph_hook =    Xen_define_hook(S_mouse_leave_graph_hook,    "(make-hook 'snd 'chn)", 2,              H_mouse_leave_graph_hook);
31021 
31022 
31023   Xen_define_typed_procedure(S_find_dialog,           g_find_dialog_w,            0, 2, 0, H_find_dialog,           s7_make_signature(s7, 3, p, b, s));
31024   Xen_define_typed_procedure("find-dialog-widgets",   g_find_dialog_widgets_w,    0, 0, 0, "test function",         s7_make_signature(s7, 1, l));
31025   Xen_define_typed_procedure(S_view_regions_dialog,   g_view_regions_dialog_w,    0, 0, 0, H_view_regions_dialog,   s7_make_signature(s7, 1, p));
31026   Xen_define_typed_procedure(S_view_files_dialog,     g_view_files_dialog_w,      0, 2, 0, H_view_files_dialog,     s7_make_signature(s7, 3, p, b, b));
31027   Xen_define_typed_procedure(S_add_file_sorter,       g_add_file_sorter_w,        2, 0, 0, H_add_file_sorter,       s7_make_signature(s7, 3, i, s, fnc));
31028   Xen_define_typed_procedure(S_delete_file_sorter,    g_delete_file_sorter_w,     1, 0, 0, H_delete_file_sorter,    s7_make_signature(s7, 2, i, i));
31029   Xen_define_typed_procedure(S_menu_widgets,          g_menu_widgets_w,           0, 0, 0, H_menu_widgets,          s7_make_signature(s7, 1, p));
31030   Xen_define_typed_procedure(S_listener_selection,    g_listener_selection_w,     0, 0, 0, H_listener_selection,
31031 			     s7_make_signature(s7, 1, s7_make_signature(s7, 2, b, s)));
31032   Xen_define_typed_procedure(S_reset_listener_cursor, g_reset_listener_cursor_w,  0, 0, 0, H_reset_listener_cursor, s7_make_signature(s7, 1, b));
31033   Xen_define_typed_procedure(S_goto_listener_end,     g_goto_listener_end_w,      0, 0, 0, H_goto_listener_end,     s7_make_signature(s7, 1, i));
31034   Xen_define_typed_procedure(S_channel_widgets,       g_channel_widgets_w,        0, 2, 0, H_channel_widgets,       s7_make_signature(s7, 3, p, t, t));
31035   Xen_define_typed_procedure(S_sound_widgets,         g_sound_widgets_w,          0, 1, 0, H_sound_widgets,         s7_make_signature(s7, 2, p, t));
31036 
31037   Xen_define_typed_procedure(S_add_directory_to_view_files_list, g_add_directory_to_view_files_list_w, 1, 1, 0, H_add_directory_to_view_files_list,
31038 			     s7_make_signature(s7, 3, s, s, p));
31039   Xen_define_typed_procedure(S_add_file_to_view_files_list,      g_add_file_to_view_files_list_w,      1, 1, 0, H_add_file_to_view_files_list,
31040 			     s7_make_signature(s7, 3, s, s, p));
31041 
31042 
31043   Xen_define_typed_dilambda(S_enved_filter, g_enved_filter_w, H_enved_filter,
31044 			    S_set S_enved_filter, g_set_enved_filter_w, 0, 0, 1, 0,
31045 			    s7_make_signature(s7, 1, b), s7_make_signature(s7, 2, b, b));
31046   Xen_define_typed_dilambda(S_enved_envelope, g_enved_envelope_w, H_enved_envelope,
31047 			    S_set S_enved_envelope, g_set_enved_envelope_w, 0, 0, 1, 0,
31048 			    s7_make_signature(s7, 1, p), s7_make_signature(s7, 2, t, t));
31049 
31050   Xen_define_typed_dilambda(S_view_files_amp, g_view_files_amp_w, H_view_files_amp,
31051 			    S_set S_view_files_amp, g_view_files_set_amp_w,  1, 0, 2, 0,
31052 			    s7_make_signature(s7, 2, r, t), s7_make_signature(s7, 3, r, t, r));
31053   Xen_define_typed_dilambda(S_view_files_amp_env, g_view_files_amp_env_w, H_view_files_amp_env,
31054 			    S_set S_view_files_amp_env, g_view_files_set_amp_env_w,  1, 0, 2, 0,
31055 			    s7_make_signature(s7, 2, p, t), s7_make_signature(s7, 3, p, t, p));
31056   Xen_define_typed_dilambda(S_view_files_speed_style, g_view_files_speed_style_w, H_view_files_speed_style,
31057 			    S_set S_view_files_speed_style, g_view_files_set_speed_style_w,  1, 0, 2, 0,
31058 			    s7_make_signature(s7, 2, i, t), s7_make_signature(s7, 3, i, t, i));
31059   Xen_define_typed_dilambda(S_view_files_speed, g_view_files_speed_w, H_view_files_speed,
31060 			    S_set S_view_files_speed, g_view_files_set_speed_w,  1, 0, 2, 0,
31061 			    s7_make_signature(s7, 2, r, t), s7_make_signature(s7, 3, r, t, r));
31062   Xen_define_typed_dilambda(S_view_files_files, g_view_files_files_w, H_view_files_files,
31063 			    S_set S_view_files_files, g_view_files_set_files_w,  1, 0, 2, 0,
31064 			    s7_make_signature(s7, 2, l, t), s7_make_signature(s7, 3, l, t, l));
31065   Xen_define_typed_dilambda(S_view_files_selected_files, g_view_files_selected_files_w, H_view_files_selected_files,
31066 			    S_set S_view_files_selected_files, g_view_files_set_selected_files_w,  1, 0, 2, 0,
31067 			    s7_make_signature(s7, 2, l, t), s7_make_signature(s7, 3, l, t, l));
31068   Xen_define_typed_dilambda(S_view_files_sort, g_view_files_sort_w, H_view_files_sort,
31069 			    S_set S_view_files_sort, g_set_view_files_sort_w,  0, 1, 1, 1,
31070 			    s7_make_signature(s7, 2, i, t), s7_make_signature(s7, 3, i, t, i));
31071 
31072   Xen_define_typed_dilambda(S_graph_cursor, g_graph_cursor_w, H_graph_cursor,
31073 			    S_set S_graph_cursor, g_set_graph_cursor_w,  0, 0, 1, 0,
31074 			    s7_make_signature(s7, 1, i), s7_make_signature(s7, 2, i, i));
31075 
31076 
31077   Xen_add_to_hook_list(ss->snd_open_file_hook, vf_open_file_watcher_w, "view-files-dialog-open-file-handler", "view-files dialog open-file handler");
31078   Xen_add_to_hook_list(ss->snd_open_file_hook, reflect_file_close_in_sync_w, "sync-open-file-watcher", "sound sync open-file-hook handler");
31079 
31080   /* file-filters and file-sorters are lists from user's point of view, but I want to
31081    *   make sure they're gc-protected through add/delete/set, and want such code compatible
31082    *   with current Ruby xen macros, so I'll use an array internally.
31083    */
31084   ss->file_sorters_size = INITIAL_FILE_SORTERS_SIZE;
31085   ss->file_sorters = Xen_make_vector(ss->file_sorters_size, Xen_false);
31086   Xen_GC_protect(ss->file_sorters);
31087 
31088 
31089 #if HAVE_SCHEME
31090   s7_set_setter(s7, ss->view_files_sort_symbol, s7_make_function(s7, "[acc-" S_view_files_sort "]", acc_view_files_sort, 2, 0, false, "accessor"));
31091   top_level_let = s7_nil(s7);
31092   s7_define_variable(s7, "top-level-let",
31093                      s7_dilambda(s7, "top-level-let", g_top_level_let, 0, 0, g_set_top_level_let, 1, 0, "listener environment"));
31094   s7_set_setter(s7, ss->graph_cursor_symbol, s7_make_function(s7, "[acc-" S_graph_cursor "]", acc_graph_cursor, 2, 0, false, "accessor"));
31095   s7_set_documentation(s7, ss->graph_cursor_symbol, "*graph-cursor*: current graph cursor shape");
31096 #endif
31097 
31098   preload_best_completions();
31099   Xen_define_procedure(S_in,            g_in_w,             2, 0, 0, H_in);
31100 }
31101