1 /*
2  * Copyright 2002 Red Hat Inc., Durham, North Carolina.
3  *
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation on the rights to use, copy, modify, merge,
10  * publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial
16  * portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NON-INFRINGEMENT.  IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
22  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
23  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27 
28 /*
29  * Authors:
30  *   Rickard E. (Rik) Faith <faith@redhat.com>
31  *
32  */
33 
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <X11/Intrinsic.h>
38 #include <X11/StringDefs.h>
39 #include <X11/Xaw/Form.h>
40 #include <X11/Xaw/Box.h>
41 /* #include <X11/Xaw/Paned.h> */
42 #include <X11/Xaw/Command.h>
43 #include <X11/Xaw/SimpleMenu.h>
44 #include <X11/Xaw/SmeBSB.h>
45 #include <X11/Xaw/MenuButton.h>
46 #include <X11/Xaw/Viewport.h>
47 #include <X11/Xaw/Dialog.h>
48 #include <X11/keysym.h>
49 #include "Canvas.h"
50 
51 #include "dmxparse.h"
52 #include "dmxprint.h"
53 #include "dmxlog.h"
54 
55 extern int yyparse(void);
56 extern int yydebug;
57 extern FILE *yyin;
58 
59 #define DMX_INFO "xdmxconfig v0.9\nCopyright 2002 Red Hat Inc.\n"
60 
61 #define DMX_MAIN_WIDTH    800
62 #define DMX_MAIN_HEIGHT   600
63 #define DMX_DATA_WIDTH    200
64 #define DMX_DATA_HEIGHT   200
65 #define DMX_CANVAS_WIDTH  400
66 #define DMX_CANVAS_HEIGHT 500
67 
68 extern DMXConfigEntryPtr dmxConfigEntry;
69 static DMXConfigVirtualPtr dmxConfigCurrent, dmxConfigNewVirtual;
70 static DMXConfigDisplayPtr dmxConfigCurrentDisplay, dmxConfigNewDisplay;
71 static int dmxConfigGrabbed, dmxConfigGrabbedFine;
72 static int dmxConfigGrabbedX, dmxConfigGrabbedY;
73 static char *dmxConfigFilename;
74 static GC dmxConfigGC, dmxConfigGCRev, dmxConfigGCHL;
75 static int dmxConfigGCInit = 0;
76 static Dimension dmxConfigWidgetWidth, dmxConfigWidgetHeight;
77 static Dimension dmxConfigWallWidth, dmxConfigWallHeight;
78 static double dmxConfigScaleX, dmxConfigScaleY;
79 static int dmxConfigNotSaved;
80 static enum {
81     dmxConfigStateOpen,
82     dmxConfigStateSave
83 } dmxConfigState;
84 
85 /* Global widgets */
86 static Widget canvas;
87 static Widget cnamebox, cdimbox;
88 static Widget openpopup, opendialog;
89 static Widget namebox, dimbox, rtbox, origbox;
90 static Widget okbutton, buttonpopup;
91 static Widget ecbutton, dcbutton;
92 static Widget ndbutton0, ndbutton1, edbutton, ddbutton;
93 static Widget ecpopup, ecdialog0, ecdialog1;
94 static Widget edpopup, eddialog0, eddialog1, eddialog2;
95 static Widget aboutpopup, quitpopup;
96 
97 static void
dmxConfigCanvasGCs(void)98 dmxConfigCanvasGCs(void)
99 {
100     Display *dpy = XtDisplay(canvas);
101     Window win = XtWindow(canvas);
102     XGCValues gcvals;
103     unsigned long mask;
104     Colormap colormap;
105     XColor fg, bg, hl, tmp;
106 
107     if (dmxConfigGCInit++)
108         return;
109 
110     XtVaGetValues(canvas, XtNcolormap, &colormap, NULL);
111     XAllocNamedColor(XtDisplay(canvas), colormap, "black", &bg, &tmp);
112     XAllocNamedColor(XtDisplay(canvas), colormap, "white", &fg, &tmp);
113     XAllocNamedColor(XtDisplay(canvas), colormap, "red", &hl, &tmp);
114 
115     mask = (GCFunction | GCPlaneMask | GCClipMask | GCForeground |
116             GCBackground | GCLineWidth | GCLineStyle | GCCapStyle |
117             GCFillStyle);
118 
119     /* FIXME: copy this from widget */
120     gcvals.function = GXcopy;
121     gcvals.plane_mask = AllPlanes;
122     gcvals.clip_mask = None;
123     gcvals.foreground = fg.pixel;
124     gcvals.background = bg.pixel;
125     gcvals.line_width = 0;
126     gcvals.line_style = LineSolid;
127     gcvals.cap_style = CapNotLast;
128     gcvals.fill_style = FillSolid;
129 
130     dmxConfigGC = XCreateGC(dpy, win, mask, &gcvals);
131     gcvals.foreground = hl.pixel;
132     dmxConfigGCHL = XCreateGC(dpy, win, mask, &gcvals);
133     gcvals.foreground = bg.pixel;
134     gcvals.background = fg.pixel;
135     dmxConfigGCRev = XCreateGC(dpy, win, mask, &gcvals);
136 }
137 
138 static void
dmxConfigGetDims(int * maxWidth,int * maxHeight)139 dmxConfigGetDims(int *maxWidth, int *maxHeight)
140 {
141     DMXConfigSubPtr pt;
142     DMXConfigEntryPtr e;
143 
144     *maxWidth = dmxConfigWallWidth = 0;
145     *maxHeight = dmxConfigWallHeight = 0;
146     if (!dmxConfigCurrent)
147         return;
148 
149     dmxConfigWallWidth = dmxConfigCurrent->width;
150     dmxConfigWallHeight = dmxConfigCurrent->height;
151     if (!dmxConfigWallWidth || !dmxConfigWallHeight) {
152         for (pt = dmxConfigCurrent->subentry; pt; pt = pt->next) {
153             if (pt->type == dmxConfigDisplay) {
154                 int x = pt->display->scrnWidth + pt->display->rootXOrigin;
155                 int y = pt->display->scrnHeight + pt->display->rootYOrigin;
156 
157                 if (x > dmxConfigWallWidth)
158                     dmxConfigWallWidth = x;
159                 if (y > dmxConfigWallHeight)
160                     dmxConfigWallHeight = y;
161             }
162         }
163     }
164     /* Compute maximums */
165     *maxWidth = *maxHeight = 0;
166     for (e = dmxConfigEntry; e; e = e->next) {
167         if (e->type != dmxConfigVirtual)
168             continue;
169         for (pt = e->virtual->subentry; pt; pt = pt->next) {
170             if (pt->type == dmxConfigDisplay) {
171                 int x = pt->display->scrnWidth + pt->display->rootXOrigin;
172                 int y = pt->display->scrnHeight + pt->display->rootYOrigin;
173 
174                 if (x > *maxWidth)
175                     *maxWidth = x;
176                 if (y > *maxHeight)
177                     *maxHeight = y;
178             }
179         }
180     }
181     if (dmxConfigWallWidth > *maxWidth)
182         *maxWidth = dmxConfigWallWidth;
183     if (dmxConfigWallHeight > *maxHeight)
184         *maxHeight = dmxConfigWallHeight;
185 }
186 
187 static int
scalex(int x)188 scalex(int x)
189 {
190     return (int) ((x * dmxConfigScaleX) + .5);
191 }
192 
193 static int
scaley(int y)194 scaley(int y)
195 {
196     return (int) ((y * dmxConfigScaleY) + .5);
197 }
198 
199 static int
unscalex(int x)200 unscalex(int x)
201 {
202     return (int) ((x / dmxConfigScaleX) + .5);
203 }
204 
205 static int
unscaley(int y)206 unscaley(int y)
207 {
208     return (int) ((y / dmxConfigScaleY) + .5);
209 }
210 
211 static void
dmxConfigDataUpdate(void)212 dmxConfigDataUpdate(void)
213 {
214     /* FIXME: could result in buffer overflows */
215     char cnambuf[512];
216     char cdimbuf[128];
217     char nambuf[512];
218     char dimbuf[128];
219     char rtbuf[128];
220     char offbuf[128];
221     const char *name;
222 
223     if (!dmxConfigCurrent) {
224         XtVaSetValues(cnamebox, XtNlabel, "", XtNsensitive, False, NULL);
225         XtVaSetValues(cdimbox, XtNlabel, "", XtNsensitive, False, NULL);
226         XtVaSetValues(ecbutton, XtNsensitive, False, NULL);
227         XtVaSetValues(dcbutton, XtNsensitive, False, NULL);
228         XtVaSetValues(ndbutton0, XtNsensitive, False, NULL);
229         XtVaSetValues(ndbutton1, XtNsensitive, False, NULL);
230     }
231     else {
232         name = dmxConfigCurrent->name;
233         snprintf(cnambuf, sizeof(cnambuf), "%s", name ? name : "");
234         snprintf(cdimbuf, sizeof(cdimbuf), "%dx%d",
235                  dmxConfigWallWidth, dmxConfigWallHeight);
236         XtVaSetValues(cnamebox, XtNlabel, cnambuf, XtNsensitive, True, NULL);
237         XtVaSetValues(cdimbox, XtNlabel, cdimbuf, XtNsensitive, True, NULL);
238         XtVaSetValues(ecbutton, XtNsensitive, True, NULL);
239         XtVaSetValues(dcbutton, XtNsensitive, True, NULL);
240         XtVaSetValues(ndbutton0, XtNsensitive, True, NULL);
241         XtVaSetValues(ndbutton1, XtNsensitive, True, NULL);
242     }
243 
244     if (!dmxConfigCurrentDisplay) {
245         XtVaSetValues(namebox, XtNlabel, "", XtNsensitive, False, NULL);
246         XtVaSetValues(dimbox, XtNlabel, "", XtNsensitive, False, NULL);
247         XtVaSetValues(rtbox, XtNlabel, "", XtNsensitive, False, NULL);
248         XtVaSetValues(origbox, XtNlabel, "", XtNsensitive, False, NULL);
249         XtVaSetValues(edbutton, XtNsensitive, False, NULL);
250         XtVaSetValues(ddbutton, XtNsensitive, False, NULL);
251     }
252     else {
253         name = dmxConfigCurrentDisplay->name;
254         snprintf(nambuf, sizeof(nambuf), "%s", name ? name : "");
255         snprintf(dimbuf, sizeof(dimbuf), "%dx%d%c%d%c%d",
256                  dmxConfigCurrentDisplay->scrnWidth,
257                  dmxConfigCurrentDisplay->scrnHeight,
258                  dmxConfigCurrentDisplay->scrnXSign < 0 ? '-' : '+',
259                  dmxConfigCurrentDisplay->scrnX,
260                  dmxConfigCurrentDisplay->scrnYSign < 0 ? '-' : '+',
261                  dmxConfigCurrentDisplay->scrnY);
262         snprintf(rtbuf, sizeof(dimbuf), "%dx%d%c%d%c%d",
263                  dmxConfigCurrentDisplay->rootWidth,
264                  dmxConfigCurrentDisplay->rootHeight,
265                  dmxConfigCurrentDisplay->rootXSign < 0 ? '-' : '+',
266                  dmxConfigCurrentDisplay->rootX,
267                  dmxConfigCurrentDisplay->rootYSign < 0 ? '-' : '+',
268                  dmxConfigCurrentDisplay->rootY);
269         snprintf(offbuf, sizeof(offbuf), "@%dx%d",
270                  dmxConfigCurrentDisplay->rootXOrigin,
271                  dmxConfigCurrentDisplay->rootYOrigin);
272         XtVaSetValues(namebox, XtNlabel, nambuf, XtNsensitive, True, NULL);
273         XtVaSetValues(dimbox, XtNlabel, dimbuf, XtNsensitive, True, NULL);
274         XtVaSetValues(rtbox, XtNlabel, rtbuf, XtNsensitive, True, NULL);
275         XtVaSetValues(origbox, XtNlabel, offbuf, XtNsensitive, True, NULL);
276         XtVaSetValues(edbutton, XtNsensitive, True, NULL);
277         XtVaSetValues(ddbutton, XtNsensitive, True, NULL);
278     }
279 }
280 
281 static void
dmxConfigCanvasUpdate(void)282 dmxConfigCanvasUpdate(void)
283 {
284     DMXConfigSubPtr pt;
285     Display *dpy = XtDisplay(canvas);
286     Window win = XtWindow(canvas);
287     GContext gcontext = XGContextFromGC(dmxConfigGC);
288     XFontStruct *fs;
289     int w, h;
290 
291     XFillRectangle(dpy, win, dmxConfigGCRev,
292                    0, 0, dmxConfigWidgetWidth, dmxConfigWidgetHeight);
293     dmxConfigDataUpdate();
294     if (!dmxConfigCurrent)
295         return;
296 
297     w = scalex(dmxConfigWallWidth);
298     h = scaley(dmxConfigWallHeight);
299     if (w > dmxConfigWidgetWidth - 1)
300         w = dmxConfigWidgetWidth - 1;
301     if (h > dmxConfigWidgetHeight - 1)
302         h = dmxConfigWidgetHeight - 1;
303     XDrawRectangle(dpy, win, dmxConfigGC, 0, 0, w, h);
304     fs = XQueryFont(dpy, gcontext);
305     for (pt = dmxConfigCurrent->subentry; pt; pt = pt->next) {
306         int x, y, len;
307         GC gc;
308 
309         if (pt->type != dmxConfigDisplay)
310             continue;
311         gc = (pt->display == dmxConfigCurrentDisplay
312               ? dmxConfigGCHL : dmxConfigGC);
313         x = scalex(pt->display->rootXOrigin);
314         y = scaley(pt->display->rootYOrigin);
315         w = scalex(pt->display->scrnWidth);
316         h = scaley(pt->display->scrnHeight);
317         len = pt->display->name ? strlen(pt->display->name) : 0;
318         if (x > dmxConfigWidgetWidth - 1)
319             x = dmxConfigWidgetWidth - 1;
320         if (y > dmxConfigWidgetHeight - 1)
321             y = dmxConfigWidgetHeight - 1;
322         XDrawRectangle(dpy, win, gc, x, y, w, h);
323         if (fs && len) {
324             int xo = 3, yo = fs->ascent + fs->descent + 2;
325 
326             while (len && XTextWidth(fs, pt->display->name, len) >= w - 2 * xo)
327                 --len;
328             if (len)
329                 XDrawString(dpy, win, gc, x + xo, y + yo, pt->display->name,
330                             len);
331         }
332     }
333     if (fs)
334         XFreeFontInfo(NULL, fs, 0);
335 }
336 
337 static void
dmxConfigCanvasDraw(Region region)338 dmxConfigCanvasDraw(Region region)
339 {
340     Display *dpy = XtDisplay(canvas);
341     int maxWidth, maxHeight;
342 
343     dmxConfigCanvasGCs();
344     if (region) {
345         XSetRegion(dpy, dmxConfigGC, region);
346         XSetRegion(dpy, dmxConfigGCRev, region);
347         XSetRegion(dpy, dmxConfigGCHL, region);
348     }
349     XtVaGetValues(canvas,
350                   XtNwidth, &dmxConfigWidgetWidth,
351                   XtNheight, &dmxConfigWidgetHeight, NULL);
352     dmxConfigGetDims(&maxWidth, &maxHeight);
353     dmxConfigScaleX = (double) dmxConfigWidgetWidth / maxWidth;
354     dmxConfigScaleY = (double) dmxConfigWidgetHeight / maxHeight;
355     if (dmxConfigScaleX > dmxConfigScaleY)
356         dmxConfigScaleX = dmxConfigScaleY;
357     if (dmxConfigScaleY > dmxConfigScaleX)
358         dmxConfigScaleY = dmxConfigScaleX;
359     dmxConfigCanvasUpdate();
360     if (region) {
361         XSetClipMask(dpy, dmxConfigGC, None);
362         XSetClipMask(dpy, dmxConfigGCRev, None);
363         XSetClipMask(dpy, dmxConfigGCHL, None);
364     }
365 }
366 
367 static void
dmxConfigSelectCallback(Widget w,XtPointer closure,XtPointer callData)368 dmxConfigSelectCallback(Widget w, XtPointer closure, XtPointer callData)
369 {
370     dmxConfigCurrent = closure;
371     dmxConfigVirtualPrint(stdout, dmxConfigCurrent);
372     dmxConfigCanvasDraw(NULL);
373 }
374 
375 static void
dmxConfigCopystrings(void)376 dmxConfigCopystrings(void)
377 {
378     DMXConfigEntryPtr pt;
379     DMXConfigSubPtr sub;
380 
381     if (!dmxConfigCurrent)
382         return;
383 
384     /* FIXME: this is all a per-config file
385      * memory leak */
386     for (pt = dmxConfigEntry; pt; pt = pt->next) {
387         if (pt->type == dmxConfigVirtual) {
388             pt->virtual->name = XtNewString(pt->virtual->name
389                                             ? pt->virtual->name : "");
390 
391             for (sub = pt->virtual->subentry; sub; sub = sub->next) {
392                 if (sub->type != dmxConfigDisplay)
393                     continue;
394                 sub->display->name = XtNewString(sub->display->name
395                                                  ? sub->display->name : "");
396             }
397         }
398     }
399 }
400 
401 static void
dmxConfigGetValueString(char ** d,Widget w)402 dmxConfigGetValueString(char **d, Widget w)
403 {
404     const char *tmp = XawDialogGetValueString(w);
405 
406     if (*d)
407         XtFree(*d);
408     *d = XtNewString(tmp);
409 }
410 
411 static void
dmxConfigSetupCnamemenu(void)412 dmxConfigSetupCnamemenu(void)
413 {
414     static Widget cnamemenu = NULL;
415     Widget w;
416     DMXConfigEntryPtr pt;
417 
418     if (cnamemenu)
419         XtDestroyWidget(cnamemenu);
420     cnamemenu = NULL;
421 
422     if (!dmxConfigCurrent)
423         return;
424     cnamemenu = XtVaCreatePopupShell("cnamemenu", simpleMenuWidgetClass,
425                                      cnamebox, NULL);
426 
427     for (pt = dmxConfigEntry; pt; pt = pt->next) {
428         if (pt->type == dmxConfigVirtual) {
429             w = XtVaCreateManagedWidget(pt->virtual->name
430                                         ? pt->virtual->name
431                                         : "",
432                                         smeBSBObjectClass, cnamemenu, NULL);
433             XtAddCallback(w, XtNcallback, dmxConfigSelectCallback, pt->virtual);
434         }
435     }
436 }
437 
438 static void
dmxConfigReadFile(void)439 dmxConfigReadFile(void)
440 {
441     FILE *str;
442     DMXConfigEntryPtr pt;
443 
444     if (!(str = fopen(dmxConfigFilename, "r"))) {
445         dmxLog(dmxWarning, "Unable to read configuration file %s\n",
446                dmxConfigFilename);
447         return;
448     }
449     yyin = str;
450     yydebug = 0;
451     yyparse();
452     fclose(str);
453     dmxLog(dmxInfo, "Read configuration file %s\n", dmxConfigFilename);
454 
455     for (pt = dmxConfigEntry; pt; pt = pt->next) {
456         if (pt->type == dmxConfigVirtual) {
457             dmxConfigCurrent = pt->virtual;
458             break;
459         }
460     }
461 
462     if (XtIsRealized(canvas)) {
463         dmxConfigCopystrings();
464         dmxConfigSetupCnamemenu();
465         dmxConfigCanvasDraw(NULL);
466     }
467     dmxConfigVirtualPrint(stdout, dmxConfigCurrent);
468 }
469 
470 static void
dmxConfigWriteFile(void)471 dmxConfigWriteFile(void)
472 {
473     FILE *str;
474 
475     if (!(str = fopen(dmxConfigFilename, "w"))) {
476         dmxLog(dmxWarning, "Unable to write configuration file %s\n",
477                dmxConfigFilename);
478         return;
479     }
480     dmxConfigPrint(str, dmxConfigEntry);
481     fclose(str);
482 }
483 
484 static DMXConfigDisplayPtr
dmxConfigFindDisplay(int x,int y)485 dmxConfigFindDisplay(int x, int y)
486 {
487     DMXConfigSubPtr pt;
488 
489     if (!dmxConfigCurrent)
490         return NULL;
491     for (pt = dmxConfigCurrent->subentry; pt; pt = pt->next) {
492         DMXConfigDisplayPtr d = pt->display;
493 
494         if (pt->type != dmxConfigDisplay)
495             continue;
496         if (x >= scalex(d->rootXOrigin)
497             && x <= scalex(d->rootXOrigin + d->scrnWidth)
498             && y >= scaley(d->rootYOrigin)
499             && y <= scaley(d->rootYOrigin + d->scrnHeight))
500             return d;
501     }
502     return NULL;
503 }
504 
505 static void
dmxConfigSetPopupPosition(Widget popup)506 dmxConfigSetPopupPosition(Widget popup)
507 {
508     Position x, y;
509     Window t1, t2;
510     int root_x, root_y;
511     int temp_x, temp_y;
512     unsigned int temp;
513 
514     XtRealizeWidget(popup);
515     if (!XQueryPointer(XtDisplay(popup), XtWindow(popup), &t1, &t2,
516                        &root_x, &root_y, &temp_x, &temp_y, &temp))
517         root_x = root_y = 0;
518 
519     x = root_x - 5;
520     y = root_y - 5;
521     XtVaSetValues(popup, XtNx, x, XtNy, y, NULL);
522 }
523 
524 static void
dmxConfigPlaceMenu(Widget w,XEvent * event,String * params,Cardinal * num_params)525 dmxConfigPlaceMenu(Widget w, XEvent * event,
526                    String * params, Cardinal * num_params)
527 {
528     dmxConfigSetPopupPosition(buttonpopup);
529 }
530 
531 static void
dmxConfigMove(int deltaX,int deltaY)532 dmxConfigMove(int deltaX, int deltaY)
533 {
534     dmxConfigCurrentDisplay->rootXOrigin += deltaX;
535     dmxConfigCurrentDisplay->rootYOrigin += deltaY;
536     if (dmxConfigCurrentDisplay->rootXOrigin < 0)
537         dmxConfigCurrentDisplay->rootXOrigin = 0;
538     if (dmxConfigCurrentDisplay->rootYOrigin < 0)
539         dmxConfigCurrentDisplay->rootYOrigin = 0;
540     if (dmxConfigWallWidth && dmxConfigWallHeight) {
541         if (dmxConfigCurrentDisplay->rootXOrigin >= dmxConfigWallWidth)
542             dmxConfigCurrentDisplay->rootXOrigin = dmxConfigWallWidth - 1;
543         if (dmxConfigCurrentDisplay->rootYOrigin >= dmxConfigWallHeight)
544             dmxConfigCurrentDisplay->rootYOrigin = dmxConfigWallHeight - 1;
545     }
546     dmxConfigCanvasUpdate();
547     dmxConfigNotSaved = 1;
548 }
549 
550 static void
dmxConfigCanvasInput(Widget w,XtPointer closure,XtPointer callData)551 dmxConfigCanvasInput(Widget w, XtPointer closure, XtPointer callData)
552 {
553     XEvent *e = (XEvent *) callData;
554     DMXConfigDisplayPtr display = NULL;
555 
556     switch (e->type) {
557     case ButtonPress:
558         if (e->xbutton.button == Button1) {
559             dmxConfigGrabbed = 1;
560             dmxConfigGrabbedFine = 0;
561             dmxConfigGrabbedX = e->xbutton.x;
562             dmxConfigGrabbedY = e->xbutton.y;
563         }
564         if (e->xbutton.button == Button2) {
565             dmxConfigGrabbed = 1;
566             dmxConfigGrabbedFine = 1;
567             dmxConfigGrabbedX = e->xbutton.x;
568             dmxConfigGrabbedY = e->xbutton.y;
569         }
570         break;
571     case ButtonRelease:
572         if (e->xbutton.button == Button1)
573             dmxConfigGrabbed = 0;
574         if (e->xbutton.button == Button2)
575             dmxConfigGrabbed = 0;
576         break;
577     case MotionNotify:
578         if (dmxConfigGrabbed && dmxConfigCurrentDisplay) {
579             int deltaX = e->xmotion.x - dmxConfigGrabbedX;
580             int deltaY = e->xmotion.y - dmxConfigGrabbedY;
581 
582             dmxConfigMove(dmxConfigGrabbedFine ? deltaX : unscalex(deltaX),
583                           dmxConfigGrabbedFine ? deltaY : unscaley(deltaY));
584             dmxConfigGrabbedX = e->xmotion.x;
585             dmxConfigGrabbedY = e->xmotion.y;
586         }
587         else {
588             display = dmxConfigFindDisplay(e->xmotion.x, e->xmotion.y);
589             if (display != dmxConfigCurrentDisplay) {
590                 dmxConfigCurrentDisplay = display;
591                 dmxConfigCanvasUpdate();
592             }
593         }
594         break;
595     case KeyPress:
596         switch (XLookupKeysym(&e->xkey, 0)) {
597         case XK_Right:
598             dmxConfigMove(1, 0);
599             break;
600         case XK_Left:
601             dmxConfigMove(-1, 0);
602             break;
603         case XK_Down:
604             dmxConfigMove(0, 1);
605             break;
606         case XK_Up:
607             dmxConfigMove(0, -1);
608             break;
609         }
610         break;
611     }
612 }
613 
614 static void
dmxConfigCanvasResize(Widget w,XtPointer closure,XtPointer callData)615 dmxConfigCanvasResize(Widget w, XtPointer closure, XtPointer callData)
616 {
617     dmxConfigCanvasDraw(NULL);
618 }
619 
620 static void
dmxConfigCanvasExpose(Widget w,XtPointer closure,XtPointer callData)621 dmxConfigCanvasExpose(Widget w, XtPointer closure, XtPointer callData)
622 {
623     CanvasExposeDataPtr data = (CanvasExposeDataPtr) callData;
624 
625     dmxConfigCanvasDraw(data->region);
626 }
627 
628 static void
dmxConfigOpenCallback(Widget w,XtPointer closure,XtPointer callData)629 dmxConfigOpenCallback(Widget w, XtPointer closure, XtPointer callData)
630 {
631     dmxConfigState = dmxConfigStateOpen;
632     XtVaSetValues(okbutton, XtNlabel, "Open", NULL);
633     dmxConfigSetPopupPosition(openpopup);
634     XtPopup(openpopup, XtGrabExclusive);
635 }
636 
637 static void
dmxConfigSaveCallback(Widget w,XtPointer closure,XtPointer callData)638 dmxConfigSaveCallback(Widget w, XtPointer closure, XtPointer callData)
639 {
640     dmxConfigState = dmxConfigStateSave;
641     XtVaSetValues(okbutton, XtNlabel, "Save", NULL);
642     dmxConfigSetPopupPosition(openpopup);
643     XtPopup(openpopup, XtGrabExclusive);
644 }
645 
646 static void
dmxConfigOkCallback(Widget w,XtPointer closure,XtPointer callData)647 dmxConfigOkCallback(Widget w, XtPointer closure, XtPointer callData)
648 {
649     dmxConfigGetValueString(&dmxConfigFilename, opendialog);
650     XtPopdown(openpopup);
651     if (dmxConfigState == dmxConfigStateOpen)
652         dmxConfigReadFile();
653     else
654         dmxConfigWriteFile();
655     dmxConfigNotSaved = 0;
656 }
657 
658 static void
dmxConfigCanCallback(Widget w,XtPointer closure,XtPointer callData)659 dmxConfigCanCallback(Widget w, XtPointer closure, XtPointer callData)
660 {
661     XtPopdown(openpopup);
662 }
663 
664 static void
dmxConfigECCallback(Widget w,XtPointer closure,XtPointer callData)665 dmxConfigECCallback(Widget w, XtPointer closure, XtPointer callData)
666 {
667     char buf[256];              /* RATS: Only used in snprintf */
668 
669     if (!dmxConfigCurrent)
670         return;
671     dmxConfigSetPopupPosition(ecpopup);
672     XtVaSetValues(ecdialog0, XtNvalue,
673                   dmxConfigCurrent->name ? dmxConfigCurrent->name : "", NULL);
674     snprintf(buf, sizeof(buf), "%dx%d",
675              dmxConfigCurrent->width, dmxConfigCurrent->height);
676     XtVaSetValues(ecdialog1, XtNvalue, buf, NULL);
677     XtPopup(ecpopup, XtGrabExclusive);
678 }
679 
680 static void
dmxConfigNCCallback(Widget w,XtPointer closure,XtPointer callData)681 dmxConfigNCCallback(Widget w, XtPointer closure, XtPointer callData)
682 {
683     int width = 1280 * 2, height = 1024 * 2;
684 
685     if (dmxConfigCurrent) {
686         width = dmxConfigCurrent->width;
687         height = dmxConfigCurrent->height;
688     }
689 
690     dmxConfigCurrent = dmxConfigCreateVirtual(NULL, NULL, NULL,
691                                               NULL, NULL, NULL);
692     dmxConfigNewVirtual = dmxConfigCurrent;
693     dmxConfigCurrent->width = width;
694     dmxConfigCurrent->height = height;
695     dmxConfigEntry = dmxConfigAddEntry(dmxConfigEntry, dmxConfigVirtual, NULL,
696                                        dmxConfigCurrent);
697     dmxConfigECCallback(w, closure, callData);
698 }
699 
700 static void
dmxConfigDCCallback(Widget w,XtPointer closure,XtPointer callData)701 dmxConfigDCCallback(Widget w, XtPointer closure, XtPointer callData)
702 {
703     DMXConfigEntryPtr pt;
704 
705     if (!dmxConfigEntry)
706         return;
707     if (dmxConfigEntry
708         && dmxConfigEntry->type == dmxConfigVirtual
709         && dmxConfigEntry->virtual == dmxConfigCurrent) {
710         dmxConfigEntry = dmxConfigEntry->next;
711     }
712     else {
713         for (pt = dmxConfigEntry; pt && pt->next; pt = pt->next)
714             if (pt->next->type == dmxConfigVirtual
715                 && pt->next->virtual == dmxConfigCurrent) {
716                 pt->next = pt->next->next;
717                 break;
718             }
719     }
720     dmxConfigFreeVirtual(dmxConfigCurrent);
721     dmxConfigCurrent = NULL;
722     dmxConfigCurrentDisplay = NULL;
723 
724     /* Make the first entry current */
725     for (pt = dmxConfigEntry; pt; pt = pt->next) {
726         if (pt->type == dmxConfigVirtual) {
727             dmxConfigCurrent = pt->virtual;
728             break;
729         }
730     }
731 
732     dmxConfigSetupCnamemenu();
733     dmxConfigCanvasDraw(NULL);
734 }
735 
736 static void
dmxConfigECOkCallback(Widget w,XtPointer closure,XtPointer callData)737 dmxConfigECOkCallback(Widget w, XtPointer closure, XtPointer callData)
738 {
739     const char *value;
740     char *endpt;
741 
742     dmxConfigGetValueString((char **) &dmxConfigCurrent->name, ecdialog0);
743     value = XawDialogGetValueString(ecdialog1);
744     dmxConfigCurrent->width = strtol(value, &endpt, 10);
745     dmxConfigCurrent->height = strtol(endpt + 1, NULL, 10);
746     XtPopdown(ecpopup);
747     dmxConfigCurrentDisplay = NULL;
748     dmxConfigNewVirtual = NULL;
749     dmxConfigSetupCnamemenu();
750     dmxConfigCanvasDraw(NULL);
751     dmxConfigNotSaved = 1;
752 }
753 
754 static void
dmxConfigECCanCallback(Widget w,XtPointer closure,XtPointer callData)755 dmxConfigECCanCallback(Widget w, XtPointer closure, XtPointer callData)
756 {
757     if (dmxConfigNewVirtual)
758         dmxConfigDCCallback(w, closure, callData);
759     dmxConfigNewVirtual = NULL;
760     XtPopdown(ecpopup);
761 }
762 
763 static void
dmxConfigEDCallback(Widget w,XtPointer closure,XtPointer callData)764 dmxConfigEDCallback(Widget w, XtPointer closure, XtPointer callData)
765 {
766     char buf[256];              /* RATS: Only used in snprintf */
767 
768     if (!dmxConfigCurrent || !dmxConfigCurrentDisplay)
769         return;
770     dmxConfigSetPopupPosition(edpopup);
771     XtVaSetValues(eddialog0, XtNvalue,
772                   dmxConfigCurrentDisplay->name
773                   ? dmxConfigCurrentDisplay->name : "", NULL);
774     snprintf(buf, sizeof(buf), "%dx%d%c%d%c%d",
775              dmxConfigCurrentDisplay->scrnWidth,
776              dmxConfigCurrentDisplay->scrnHeight,
777              dmxConfigCurrentDisplay->scrnXSign < 0 ? '-' : '+',
778              dmxConfigCurrentDisplay->scrnY,
779              dmxConfigCurrentDisplay->scrnYSign < 0 ? '-' : '+',
780              dmxConfigCurrentDisplay->scrnY);
781     XtVaSetValues(eddialog1, XtNvalue, buf, NULL);
782     snprintf(buf, sizeof(buf), "@%dx%d",
783              dmxConfigCurrentDisplay->rootXOrigin,
784              dmxConfigCurrentDisplay->rootYOrigin);
785     XtVaSetValues(eddialog2, XtNvalue, buf, NULL);
786     XtPopup(edpopup, XtGrabExclusive);
787 }
788 
789 static void
dmxConfigNDCallback(Widget w,XtPointer closure,XtPointer callData)790 dmxConfigNDCallback(Widget w, XtPointer closure, XtPointer callData)
791 {
792     int width = 1280, height = 1024;
793 
794     if (!dmxConfigCurrent)
795         return;
796     if (dmxConfigCurrentDisplay) {
797         width = dmxConfigCurrentDisplay->scrnWidth;
798         height = dmxConfigCurrentDisplay->scrnHeight;
799     }
800     dmxConfigCurrentDisplay = dmxConfigCreateDisplay(NULL, NULL, NULL,
801                                                      NULL, NULL);
802     dmxConfigNewDisplay = dmxConfigCurrentDisplay;
803     dmxConfigCurrentDisplay->scrnWidth = width;
804     dmxConfigCurrentDisplay->scrnHeight = height;
805 
806     dmxConfigCurrent->subentry
807         = dmxConfigAddSub(dmxConfigCurrent->subentry,
808                           dmxConfigSubDisplay(dmxConfigCurrentDisplay));
809     dmxConfigEDCallback(w, closure, callData);
810 }
811 
812 static void
dmxConfigDDCallback(Widget w,XtPointer closure,XtPointer callData)813 dmxConfigDDCallback(Widget w, XtPointer closure, XtPointer callData)
814 {
815     DMXConfigSubPtr pt;
816 
817     if (!dmxConfigCurrent || !dmxConfigCurrentDisplay)
818         return;
819     /* First */
820     if (dmxConfigCurrent->subentry
821         && dmxConfigCurrent->subentry->type == dmxConfigDisplay
822         && dmxConfigCurrent->subentry->display == dmxConfigCurrentDisplay) {
823         dmxConfigCurrent->subentry = dmxConfigCurrent->subentry->next;
824     }
825     else {
826         for (pt = dmxConfigCurrent->subentry; pt && pt->next; pt = pt->next)
827             if (pt->next->type == dmxConfigDisplay
828                 && pt->next->display == dmxConfigCurrentDisplay) {
829                 pt->next = pt->next->next;
830                 break;
831             }
832     }
833     dmxConfigFreeDisplay(dmxConfigCurrentDisplay);
834     dmxConfigCurrentDisplay = NULL;
835     dmxConfigSetupCnamemenu();
836     dmxConfigCanvasDraw(NULL);
837 }
838 
839 static void
dmxConfigAboutCallback(Widget w,XtPointer closure,XtPointer callData)840 dmxConfigAboutCallback(Widget w, XtPointer closure, XtPointer callData)
841 {
842     dmxConfigSetPopupPosition(aboutpopup);
843     XtPopup(aboutpopup, XtGrabExclusive);
844 }
845 
846 static void
dmxConfigAboutOkCallback(Widget w,XtPointer closure,XtPointer CallData)847 dmxConfigAboutOkCallback(Widget w, XtPointer closure, XtPointer CallData)
848 {
849     XtPopdown(aboutpopup);
850 }
851 
852 static void
dmxConfigQuitCallback(Widget w,XtPointer closure,XtPointer callData)853 dmxConfigQuitCallback(Widget w, XtPointer closure, XtPointer callData)
854 {
855     if (dmxConfigNotSaved) {
856         dmxConfigSetPopupPosition(quitpopup);
857         XtPopup(quitpopup, XtGrabExclusive);
858         return;
859     }
860     exit(0);
861 }
862 
863 static void
dmxConfigQuitOkCallback(Widget w,XtPointer closure,XtPointer callData)864 dmxConfigQuitOkCallback(Widget w, XtPointer closure, XtPointer callData)
865 {
866     XtPopdown(quitpopup);
867     exit(0);
868 }
869 
870 static void
dmxConfigQuitCanCallback(Widget w,XtPointer closure,XtPointer callData)871 dmxConfigQuitCanCallback(Widget w, XtPointer closure, XtPointer callData)
872 {
873     XtPopdown(quitpopup);
874 }
875 
876 static void
dmxConfigEDOkCallback(Widget w,XtPointer closure,XtPointer callData)877 dmxConfigEDOkCallback(Widget w, XtPointer closure, XtPointer callData)
878 {
879     char *value;
880     char *endpt;
881 
882     dmxConfigNewDisplay = NULL;
883     dmxConfigGetValueString((char **) &dmxConfigCurrentDisplay->name,
884                             eddialog0);
885     value = XawDialogGetValueString(eddialog1);
886     if (*value == '-' || *value == '+') {
887         dmxConfigCurrentDisplay->scrnWidth = 0;
888         dmxConfigCurrentDisplay->scrnHeight = 0;
889         endpt = value;
890     }
891     else {
892         dmxConfigCurrentDisplay->scrnWidth = strtol(value, &endpt, 10);
893         dmxConfigCurrentDisplay->scrnHeight = strtol(endpt + 1, &endpt, 10);
894     }
895     if (*endpt) {
896         dmxConfigCurrentDisplay->scrnXSign = (*endpt == '-') ? -1 : 1;
897         dmxConfigCurrentDisplay->scrnX = strtol(endpt + 1, &endpt, 10);
898         dmxConfigCurrentDisplay->scrnYSign = (*endpt == '-') ? -1 : 1;
899         dmxConfigCurrentDisplay->scrnY = strtol(endpt + 1, NULL, 10);
900     }
901     if (dmxConfigCurrentDisplay->scrnX < 0)
902         dmxConfigCurrentDisplay->scrnX = -dmxConfigCurrentDisplay->scrnX;
903     if (dmxConfigCurrentDisplay->scrnY < 0)
904         dmxConfigCurrentDisplay->scrnY = -dmxConfigCurrentDisplay->scrnY;
905     value = XawDialogGetValueString(eddialog2);
906     dmxConfigCurrentDisplay->rootXOrigin = strtol(value + 1, &endpt, 10);
907     dmxConfigCurrentDisplay->rootYOrigin = strtol(endpt + 1, NULL, 10);
908     XtPopdown(edpopup);
909     dmxConfigSetupCnamemenu();
910     dmxConfigCanvasDraw(NULL);
911     dmxConfigNotSaved = 1;
912 }
913 
914 static void
dmxConfigEDCanCallback(Widget w,XtPointer closure,XtPointer callData)915 dmxConfigEDCanCallback(Widget w, XtPointer closure, XtPointer callData)
916 {
917     if (dmxConfigNewDisplay)
918         dmxConfigDDCallback(w, closure, callData);
919     dmxConfigNewDisplay = NULL;
920     XtPopdown(edpopup);
921 }
922 
923 static void
dmxConfigOkAction(Widget w,XEvent * event,String * params,Cardinal * num_params)924 dmxConfigOkAction(Widget w, XEvent * event,
925                   String * params, Cardinal * num_params)
926 {
927     Widget p = XtParent(w);
928     Widget t;
929 
930     if (p == opendialog)
931         dmxConfigOkCallback(w, NULL, NULL);
932 
933     if (p == ecdialog0) {
934         t = XtNameToWidget(ecdialog1, "value");
935         XWarpPointer(XtDisplay(t), None, XtWindow(t), 0, 0, 0, 0, 0, 10);
936     }
937     if (p == ecdialog1)
938         dmxConfigECOkCallback(w, NULL, NULL);
939 
940     if (p == eddialog0) {
941         t = XtNameToWidget(eddialog1, "value");
942         XWarpPointer(XtDisplay(t), None, XtWindow(t), 0, 0, 0, 0, 0, 10);
943     }
944     if (p == eddialog1) {
945         t = XtNameToWidget(eddialog2, "value");
946         XWarpPointer(XtDisplay(t), None, XtWindow(t), 0, 0, 0, 0, 0, 10);
947     }
948     if (p == eddialog2)
949         dmxConfigEDOkCallback(w, NULL, NULL);
950 }
951 
952 int
main(int argc,char ** argv)953 main(int argc, char **argv)
954 {
955     XtAppContext appContext;
956     Widget toplevel;
957     Widget parent, menubox, bottombox, databox, canvasbox;
958     Widget filebutton, helpbutton;
959     Widget filemenu, openbutton, savebutton, quitbutton;
960     Widget helpmenu, aboutbutton, aboutbox, aboutok;
961     Widget quitbox, quitok, quitcan;
962     Widget ncbutton;
963     Widget canbutton;
964     Widget ecbox, ecokbutton, eccanbutton;
965     Widget edbox, edokbutton;
966     Widget edcanbutton;
967 
968     /* FIXME: add meta-i, ctrl,meta-z,v? */
969     const char *opentrans = "<Key>Return: openOk()\n\
970                                  <Key>Linefeed: openOk()\n\
971                                  Ctrl<Key>M: openOk()\n\
972                                  Ctrl<Key>J: openOk()\n\
973                                  Ctrl<Key>O: noop()\n\
974                                  Ctrl<Key>N: noop()\n\
975                                  Ctrl<Key>P: noop()";
976     const char *canvastrans =
977         "<Btn3Down>: placeMenu() XtMenuPopup(buttonpopup)";
978     XtActionsRec actiontable[] = {
979         {(char *) "openOk", dmxConfigOkAction},
980         {(char *) "placeMenu", dmxConfigPlaceMenu},
981         {(char *) "noop", NULL}
982     };
983 
984     dmxConfigFilename = XtNewString((argc >= 2) ? argv[1] : "");
985 
986     toplevel = XtVaAppInitialize(&appContext, "XDmxconfig",
987                                  NULL, 0, &argc, argv, NULL, NULL);
988 
989     /* Main boxes */
990     parent = XtVaCreateManagedWidget("parent", formWidgetClass, toplevel,
991                                      XtNorientation, XtorientVertical,
992                                      XtNwidth, DMX_MAIN_WIDTH,
993                                      XtNheight, DMX_MAIN_HEIGHT, NULL);
994     menubox = XtVaCreateManagedWidget("menubox", boxWidgetClass, parent,
995                                       XtNborderWidth, 0,
996                                       XtNorientation, XtorientHorizontal,
997                                       XtNtop, XtChainTop, NULL);
998     bottombox = XtVaCreateManagedWidget("bottombox", formWidgetClass, parent,
999                                         XtNborderWidth, 0,
1000                                         XtNfromVert, menubox,
1001                                         XtNorientation, XtorientHorizontal,
1002                                         NULL);
1003     databox = XtVaCreateManagedWidget("databox", formWidgetClass,
1004                                       bottombox,
1005                                       XtNborderWidth, 0,
1006                                       XtNhorizDistance, 0,
1007                                       XtNwidth, DMX_DATA_WIDTH,
1008                                       XtNheight, DMX_DATA_HEIGHT,
1009                                       XtNleft, XtChainLeft,
1010                                       XtNorientation, XtorientVertical, NULL);
1011 
1012     /* Data */
1013     cnamebox = XtVaCreateManagedWidget("cnamebox", menuButtonWidgetClass,
1014                                        databox,
1015                                        XtNtop, XtChainTop,
1016                                        XtNjustify, XtJustifyLeft,
1017                                        XtNwidth, DMX_DATA_WIDTH,
1018                                        XtNlabel, "",
1019                                        XtNmenuName, "cnamemenu", NULL);
1020     cdimbox = XtVaCreateManagedWidget("cdimbox", labelWidgetClass,
1021                                       databox,
1022                                       XtNfromVert, cnamebox,
1023                                       XtNjustify, XtJustifyLeft,
1024                                       XtNwidth, DMX_DATA_WIDTH,
1025                                       XtNlabel, "", NULL);
1026     namebox = XtVaCreateManagedWidget("namebox", labelWidgetClass, databox,
1027                                       XtNfromVert, cdimbox,
1028                                       XtNjustify, XtJustifyLeft,
1029                                       XtNwidth, DMX_DATA_WIDTH,
1030                                       XtNlabel, "", NULL);
1031     dimbox = XtVaCreateManagedWidget("dimbox", labelWidgetClass,
1032                                      databox,
1033                                      XtNfromVert, namebox,
1034                                      XtNjustify, XtJustifyLeft,
1035                                      XtNwidth, DMX_DATA_WIDTH,
1036                                      XtNlabel, "", NULL);
1037     rtbox = XtVaCreateManagedWidget("rtbox", labelWidgetClass,
1038                                     databox,
1039                                     XtNfromVert, dimbox,
1040                                     XtNjustify, XtJustifyLeft,
1041                                     XtNwidth, DMX_DATA_WIDTH,
1042                                     XtNlabel, "", NULL);
1043     origbox = XtVaCreateManagedWidget("origbox", labelWidgetClass,
1044                                       databox,
1045                                       XtNfromVert, rtbox,
1046                                       XtNjustify, XtJustifyLeft,
1047                                       XtNwidth, DMX_DATA_WIDTH,
1048                                       XtNlabel, "", NULL);
1049 
1050     /* Canvas */
1051     canvasbox = XtVaCreateManagedWidget("canvasbox", boxWidgetClass,
1052                                         bottombox,
1053                                         XtNborderWidth, 0,
1054                                         XtNwidth, DMX_CANVAS_WIDTH,
1055                                         XtNheight, DMX_CANVAS_HEIGHT,
1056                                         XtNfromHoriz, databox, NULL);
1057 
1058     canvas = XtVaCreateManagedWidget("canvas", canvasWidgetClass,
1059                                      canvasbox,
1060                                      XtNwidth, DMX_CANVAS_WIDTH,
1061                                      XtNheight, DMX_CANVAS_HEIGHT, NULL);
1062 
1063     /* Main menu buttons */
1064     filebutton = XtVaCreateManagedWidget("File", menuButtonWidgetClass,
1065                                          menubox,
1066                                          XtNmenuName, "filemenu", NULL);
1067     helpbutton = XtVaCreateManagedWidget("Help", menuButtonWidgetClass,
1068                                          menubox,
1069                                          XtNmenuName, "helpmenu", NULL);
1070 
1071     /* File submenu buttons */
1072     filemenu = XtVaCreatePopupShell("filemenu", simpleMenuWidgetClass,
1073                                     filebutton, NULL);
1074     openbutton = XtVaCreateManagedWidget("Open File", smeBSBObjectClass,
1075                                          filemenu, NULL);
1076     savebutton = XtVaCreateManagedWidget("Save File", smeBSBObjectClass,
1077                                          filemenu, NULL);
1078     ncbutton = XtVaCreateManagedWidget("New Global", smeBSBObjectClass,
1079                                        filemenu, NULL);
1080     ecbutton = XtVaCreateManagedWidget("Edit Global", smeBSBObjectClass,
1081                                        filemenu, NULL);
1082     dcbutton = XtVaCreateManagedWidget("Delete Global", smeBSBObjectClass,
1083                                        filemenu, NULL);
1084     ndbutton0 = XtVaCreateManagedWidget("New Display", smeBSBObjectClass,
1085                                         filemenu, NULL);
1086     quitbutton = XtVaCreateManagedWidget("Quit", smeBSBObjectClass,
1087                                          filemenu, NULL);
1088 
1089     /* Help submenu button */
1090     helpmenu = XtVaCreatePopupShell("helpmenu", simpleMenuWidgetClass,
1091                                     helpbutton, NULL);
1092     aboutbutton = XtVaCreateManagedWidget("About", smeBSBObjectClass,
1093                                           helpmenu, NULL);
1094 
1095     /* Open popup */
1096     openpopup = XtVaCreatePopupShell("openpopup", transientShellWidgetClass,
1097                                      toplevel, NULL);
1098     opendialog = XtVaCreateManagedWidget("opendialog", dialogWidgetClass,
1099                                          openpopup,
1100                                          XtNlabel, "Filename: ",
1101                                          XtNvalue, dmxConfigFilename, NULL);
1102     okbutton = XtVaCreateManagedWidget("Open", commandWidgetClass,
1103                                        opendialog, NULL);
1104     canbutton = XtVaCreateManagedWidget("Cancel", commandWidgetClass,
1105                                         opendialog, NULL);
1106 
1107     /* EC popup */
1108     ecpopup = XtVaCreatePopupShell("ecpopup", transientShellWidgetClass,
1109                                    toplevel, NULL);
1110     ecbox = XtVaCreateManagedWidget("ecbox", boxWidgetClass, ecpopup, NULL);
1111     ecdialog0 = XtVaCreateManagedWidget("ecdialog0", dialogWidgetClass,
1112                                         ecbox,
1113                                         XtNlabel, "Name:              ",
1114                                         XtNvalue, "", NULL);
1115     ecdialog1 = XtVaCreateManagedWidget("ecdialog1", dialogWidgetClass,
1116                                         ecbox,
1117                                         XtNlabel, "Dimension:         ",
1118                                         XtNvalue, "", NULL);
1119     ecokbutton = XtVaCreateManagedWidget("OK", commandWidgetClass, ecbox, NULL);
1120     eccanbutton = XtVaCreateManagedWidget("Cancel", commandWidgetClass,
1121                                           ecbox, NULL);
1122 
1123     /* ED popup */
1124     edpopup = XtVaCreatePopupShell("edpopup", transientShellWidgetClass,
1125                                    toplevel, NULL);
1126     edbox = XtVaCreateManagedWidget("edbox", boxWidgetClass, edpopup, NULL);
1127     eddialog0 = XtVaCreateManagedWidget("eddialog0", dialogWidgetClass,
1128                                         edbox,
1129                                         XtNlabel, "Display Name:      ",
1130                                         XtNvalue, "", NULL);
1131     eddialog1 = XtVaCreateManagedWidget("eddialog1", dialogWidgetClass,
1132                                         edbox,
1133                                         XtNlabel, "Geometry:          ",
1134                                         XtNvalue, "", NULL);
1135     eddialog2 = XtVaCreateManagedWidget("eddialog2", dialogWidgetClass,
1136                                         edbox,
1137                                         XtNlabel, "Offset:            ",
1138                                         XtNvalue, "", NULL);
1139     edokbutton = XtVaCreateManagedWidget("OK", commandWidgetClass, edbox, NULL);
1140     edcanbutton = XtVaCreateManagedWidget("Cancel", commandWidgetClass,
1141                                           edbox, NULL);
1142 
1143     /* About popup */
1144     aboutpopup = XtVaCreatePopupShell("aboutpopup", transientShellWidgetClass,
1145                                       toplevel, NULL);
1146     aboutbox = XtVaCreateManagedWidget("aboutbox", boxWidgetClass,
1147                                        aboutpopup, NULL);
1148     XtVaCreateManagedWidget("abouttext", labelWidgetClass,
1149                             aboutbox, XtNlabel, DMX_INFO, NULL);
1150     aboutok = XtVaCreateManagedWidget("OK", commandWidgetClass, aboutbox, NULL);
1151 
1152     /* Quit popup */
1153     quitpopup = XtVaCreatePopupShell("quitpopup", transientShellWidgetClass,
1154                                      toplevel, NULL);
1155     quitbox = XtVaCreateManagedWidget("quitbox", boxWidgetClass,
1156                                       quitpopup, NULL);
1157     XtVaCreateManagedWidget("quittext", labelWidgetClass,
1158                             quitbox,
1159                             XtNlabel,
1160                             "Changes to the configuration\n"
1161                             "been made that have not yet\n"
1162                             "been saved.  Do you want to\n"
1163                             "quit without saving?", NULL);
1164     quitok = XtVaCreateManagedWidget("Quit WITHOUT Saving",
1165                                      commandWidgetClass, quitbox, NULL);
1166     quitcan = XtVaCreateManagedWidget("Continue Editing",
1167                                       commandWidgetClass, quitbox, NULL);
1168 
1169     /* Button popup */
1170     buttonpopup = XtVaCreatePopupShell("buttonpopup", simpleMenuWidgetClass,
1171                                        toplevel, NULL);
1172     ndbutton1 = XtVaCreateManagedWidget("New Display", smeBSBObjectClass,
1173                                         buttonpopup, NULL);
1174     edbutton = XtVaCreateManagedWidget("Edit Display", smeBSBObjectClass,
1175                                        buttonpopup, NULL);
1176     ddbutton = XtVaCreateManagedWidget("Delete Display", smeBSBObjectClass,
1177                                        buttonpopup, NULL);
1178 
1179     /* Callbacks */
1180     XtAddCallback(openbutton, XtNcallback, dmxConfigOpenCallback, NULL);
1181     XtAddCallback(savebutton, XtNcallback, dmxConfigSaveCallback, NULL);
1182     XtAddCallback(okbutton, XtNcallback, dmxConfigOkCallback, NULL);
1183     XtAddCallback(canbutton, XtNcallback, dmxConfigCanCallback, NULL);
1184 
1185     XtAppAddActions(appContext, actiontable, XtNumber(actiontable));
1186     XtOverrideTranslations(canvas, XtParseTranslationTable(canvastrans));
1187     XtOverrideTranslations(XtNameToWidget(opendialog, "value"),
1188                            XtParseTranslationTable(opentrans));
1189     XtOverrideTranslations(XtNameToWidget(ecdialog0, "value"),
1190                            XtParseTranslationTable(opentrans));
1191     XtOverrideTranslations(XtNameToWidget(ecdialog1, "value"),
1192                            XtParseTranslationTable(opentrans));
1193     XtOverrideTranslations(XtNameToWidget(eddialog0, "value"),
1194                            XtParseTranslationTable(opentrans));
1195     XtOverrideTranslations(XtNameToWidget(eddialog1, "value"),
1196                            XtParseTranslationTable(opentrans));
1197     XtOverrideTranslations(XtNameToWidget(eddialog2, "value"),
1198                            XtParseTranslationTable(opentrans));
1199 
1200     XtAddCallback(ncbutton, XtNcallback, dmxConfigNCCallback, NULL);
1201     XtAddCallback(ecbutton, XtNcallback, dmxConfigECCallback, NULL);
1202     XtAddCallback(ecokbutton, XtNcallback, dmxConfigECOkCallback, NULL);
1203     XtAddCallback(eccanbutton, XtNcallback, dmxConfigECCanCallback, NULL);
1204     XtAddCallback(dcbutton, XtNcallback, dmxConfigDCCallback, NULL);
1205 
1206     XtAddCallback(ndbutton0, XtNcallback, dmxConfigNDCallback, NULL);
1207     XtAddCallback(ndbutton1, XtNcallback, dmxConfigNDCallback, NULL);
1208     XtAddCallback(edbutton, XtNcallback, dmxConfigEDCallback, NULL);
1209     XtAddCallback(ddbutton, XtNcallback, dmxConfigDDCallback, NULL);
1210     XtAddCallback(edokbutton, XtNcallback, dmxConfigEDOkCallback, NULL);
1211     XtAddCallback(edcanbutton, XtNcallback, dmxConfigEDCanCallback, NULL);
1212 
1213     XtAddCallback(aboutbutton, XtNcallback, dmxConfigAboutCallback, NULL);
1214     XtAddCallback(aboutok, XtNcallback, dmxConfigAboutOkCallback, NULL);
1215     XtAddCallback(quitok, XtNcallback, dmxConfigQuitOkCallback, NULL);
1216     XtAddCallback(quitcan, XtNcallback, dmxConfigQuitCanCallback, NULL);
1217 
1218     XtAddCallback(quitbutton, XtNcallback, dmxConfigQuitCallback, NULL);
1219 
1220     XtAddCallback(canvas, XtNcallback, dmxConfigCanvasInput, NULL);
1221     XtAddCallback(canvas, XtNcanvasExposeCallback, dmxConfigCanvasExpose, NULL);
1222     XtAddCallback(canvas, XtNcanvasResizeCallback, dmxConfigCanvasResize, NULL);
1223 
1224     if (dmxConfigFilename)
1225         dmxConfigReadFile();
1226 
1227     XtRealizeWidget(toplevel);
1228     dmxConfigCopystrings();
1229     dmxConfigSetupCnamemenu();
1230     XtAppMainLoop(appContext);
1231     return 0;
1232 }
1233