1/*
2
3Copyright (c) 1991  X Consortium
4
5Permission is hereby granted, free of charge, to any person obtaining
6a copy of this software and associated documentation files (the
7"Software"), to deal in the Software without restriction, including
8without limitation the rights to use, copy, modify, merge, publish,
9distribute, sublicense, and/or sell copies of the Software, and to
10permit persons to whom the Software is furnished to do so, subject to
11the following conditions:
12
13The above copyright notice and this permission notice shall be included
14in all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
20OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22OTHER DEALINGS IN THE SOFTWARE.
23
24Except as contained in this notice, the name of the X Consortium shall
25not be used in advertising or otherwise to promote the sale, use or
26other dealings in this Software without prior written authorization
27from the X Consortium.
28
29*/
30
31/* xgc
32**
33** main.c
34**
35** Contains the bare minimum necessary to oversee the whole operation.
36*/
37
38#include <X11/Intrinsic.h>
39#include <X11/StringDefs.h>
40#include <X11/Xaw/Form.h>
41#include <X11/Xaw/Command.h>
42#include <X11/Xaw/AsciiText.h>
43#include <X11/Shell.h>
44#include <stdio.h>
45#include <stdlib.h>
46
47#include "xgc.h"
48#define DEFINE_TILE
49#include "tile"
50
51static void fill_up_commandform(Widget);
52static void quit(void);
53static void quitAction(Widget, XEvent *, String *, Cardinal *);
54static void clear_test_window(void);
55static void clear_result_window(void);
56static void set_foreground_and_background(void);
57
58/* The three columns in the XgcData arrays are:
59**   name: the name of the toggle button
60**   text: the corresponding text in the xgc syntax
61**   code: the integer that the text corresponds to, for sending stuff
62**         to X calls, etc.
63*/
64
65static XgcData FunctionData[NUM_FUNCTIONS] = {
66  {"clear",        "clear",        GXclear},
67  {"and",          "and",          GXand},
68  {"andReverse",   "andReverse",   GXandReverse},
69  {"copy",         "copy",         GXcopy},
70  {"andInverted",  "andInverted",  GXandInverted},
71  {"noop",         "noop",         GXnoop},
72  {"xor",          "xor",          GXxor},
73  {"or",           "or",           GXor},
74  {"nor",          "nor",          GXnor},
75  {"equiv",        "equiv",        GXequiv},
76  {"invert",       "invert",       GXinvert},
77  {"orReverse",    "orReverse",    GXorReverse},
78  {"copyInverted", "copyInverted", GXcopyInverted},
79  {"orInverted",   "orInverted",   GXorInverted},
80  {"nand",         "nand",         GXnand},
81  {"set",          "set",          GXset}
82};
83
84/* The two rows in the XgcStuff structure are:
85**   name of label, xgc syntax text, # of toggles, # of columns of toggles
86**     (0 columns means 1 row, as many columns as necessary)
87**   appropriate XgcData
88*/
89
90XgcStuff FunctionStuff = {
91  {"Function","function",NUM_FUNCTIONS,4},
92  FunctionData
93};
94
95static XgcData TestData[NUM_TESTS] = {
96  {"Copy Area",          "CopyArea",      CopyArea},
97  {"Copy Plane",         "CopyPlane",     CopyPlane},
98  {"Points",             "PolyPoint",     PolyPoint},
99  {"Lines",              "PolyLine",      PolyLine},
100  {"Segments",           "PolySegment",   PolySegment},
101  {"Rectangles",         "PolyRectangle", PolyRectangle},
102  {"Arcs",               "PolyArc",       PolyArc},
103  {"(Filled Polygons)",  "FillPolygon",   FillPolygon},
104  {"Filled Rectangles",  "PolyFillRect",  PolyFillRect},
105  {"Filled Arcs",        "PolyFillArc",   PolyFillArc},
106  {"Put Image",          "PutImage",      PutImage},
107  {"(Get Image)",        "GetImage",      GetImage},
108  {"Text 8",             "PolyText8",     PolyText8},
109  {"Image Text 8",       "ImageText8",    ImageText8},
110  {"Text 16",            "PolyText16",    PolyText16},
111  {"Image Text 16",      "ImageText16",   ImageText16}
112};
113
114XgcStuff TestStuff = {
115  {"Test","test",NUM_TESTS,2},
116  TestData
117};
118
119static XgcData LinestyleData[NUM_LINESTYLES] = {
120  {"Solid",      "Solid",       LineSolid},
121  {"OnOffDash",  "OnOffDash",   LineOnOffDash},
122  {"DoubleDash", "DoubleDash",  LineDoubleDash}
123};
124
125XgcStuff LinestyleStuff = {
126  {"LineStyle","linestyle",NUM_LINESTYLES,0},
127  LinestyleData
128};
129
130static XgcData CapstyleData[NUM_CAPSTYLES] = {
131  {"NotLast",    "NotLast",     CapNotLast},
132  {"Butt",       "Butt",        CapButt},
133  {"Round",      "Round",       CapRound},
134  {"Projecting", "Projecting",  CapProjecting}
135};
136
137XgcStuff CapstyleStuff = {
138  {"CapStyle","capstyle",NUM_CAPSTYLES,2},
139  CapstyleData
140};
141
142static XgcData JoinstyleData[NUM_JOINSTYLES] = {
143  {"Miter",   "Miter",   JoinMiter},
144  {"Round",   "Round",   JoinRound},
145  {"Bevel",   "Bevel",   JoinBevel}
146};
147
148XgcStuff JoinstyleStuff = {
149  {"JoinStyle","joinstyle",NUM_JOINSTYLES,0},
150  JoinstyleData
151};
152
153static XgcData FillstyleData[NUM_FILLSTYLES] = {
154  {"Solid",          "Solid",          FillSolid},
155  {"Tiled",          "Tiled",          FillTiled},
156  {"Stippled",       "Stippled",       FillStippled},
157  {"OpaqueStippled", "OpaqueStippled", FillOpaqueStippled}
158};
159
160XgcStuff FillstyleStuff = {
161  {"FillStyle","fillstyle",NUM_FILLSTYLES,2},
162  FillstyleData
163};
164
165static XgcData FillruleData[NUM_FILLRULES] = {
166  {"EvenOdd",  "EvenOdd",  EvenOddRule},
167  {"Winding",  "Winding",  WindingRule}
168};
169
170XgcStuff FillruleStuff = {
171  {"FillRule","fillrule",NUM_FILLRULES,0},
172  FillruleData
173};
174
175static XgcData ArcmodeData[NUM_ARCMODES] = {
176  {"Chord",    "Chord",    ArcChord},
177 {"PieSlice", "PieSlice", ArcPieSlice}
178};
179
180XgcStuff ArcmodeStuff = {
181  {"ArcMode","arcmode",NUM_ARCMODES,0},
182  ArcmodeData
183};
184
185/* Pointers to all the Xgcstuffs so we can run them through a loop */
186
187static XgcStuff *Everything[8] = {
188  &FunctionStuff,
189  &LinestyleStuff,
190  &CapstyleStuff,
191  &JoinstyleStuff,
192  &FillstyleStuff,
193  &FillruleStuff,
194  &ArcmodeStuff,
195  &TestStuff
196};
197
198#ifdef notdef
199int fildes[2];			/* for pipe */
200FILE *outend;
201#endif
202
203XStuff X;			/* GC stuff plus some global variables */
204Boolean recording = FALSE;	/* Whether we're recording into a file */
205XtAppContext appcontext;	/* To make Xt happy */
206static Atom wm_delete_window;
207static XtActionsRec actions[] = {
208    {"quit",	quitAction}
209};
210
211static Widget bigdaddy;		/* the top level widget */
212       Widget topform;		/* form surrounding the whole thing */
213       Widget GCform;		/* form in which you choose the GC */
214static Widget Testform;		/* form in which you choose the test */
215       Widget testchoiceform;   /* form inside that */
216  ChoiceDesc *testchoicedesc;	/* record of what widgets are in the
217				   test choice form */
218static Widget commandform;	/* form with run, quit, clear, etc. */
219       Widget test;		/* where the test is run */
220       Widget result;           /* where the results are displayed */
221static Widget runbutton;	/* command for running */
222static Widget clearbutton;	/* command for clearing the test window */
223       Widget recordbutton;	/* start/stop recording */
224static Widget playbackbutton;	/* playback from file */
225static Widget keyinputbutton;	/* start reading from keyboard */
226static Widget GCchoices[NUMCHOICES]; /* all the forms that contain stuff
227				        for changing GC's*/
228  ChoiceDesc *GCdescs[NUMCHOICES]; /* record of the widgets inside
229				      the choice widgets */
230       Widget planemaskchoice;	/* form for choosing the plane mask */
231       Widget dashlistchoice;	/* form for choosing the dash list */
232static Widget linewidthchoice;	/* form for choosing line width */
233       Widget linewidthtext;	/* text widget within that */
234static Widget fontchoice;	/* form for choosing the font */
235       Widget fonttext;		/* text widget within that */
236static Widget foregroundchoice;	/* form for choosing foreground */
237       Widget foregroundtext;	/* text widget within that */
238static Widget backgroundchoice;	/* form for choosing background */
239       Widget backgroundtext;	/* text widget within that */
240static Widget percentchoice;	/* form for choosing percentage of test */
241
242/* main(argc.argv)
243** ---------------
244** Initializes the toolkit, initializes data, puts up the widgets,
245** starts the event loop.
246*/
247
248int
249main(int argc, char *argv[])
250{
251  static Arg shellargs[] = {
252    {XtNinput, 	      (XtArgVal) True}
253  };
254
255  static Arg testformargs[] = {
256    {XtNfromVert,     (XtArgVal) NULL} /* put it under GCform */
257  };
258
259  static Arg commandformargs[] = {
260    {XtNfromVert,    (XtArgVal) NULL}, /* put it under GCform */
261    {XtNfromHoriz,   (XtArgVal) NULL}  /* and to the right of Testform */
262  };
263
264  static Arg testargs[] = {
265    {XtNheight,     (XtArgVal) 400},
266    {XtNwidth,      (XtArgVal) 400},
267    {XtNfromHoriz,  (XtArgVal) NULL} /* put it to the right of GCform */
268  };
269
270  static Arg resultargs[] = {
271    {XtNheight,     (XtArgVal) 50},
272    {XtNwidth,      (XtArgVal) 400},
273    {XtNfromHoriz,  (XtArgVal) NULL}, /* put it to the right of GCform */
274    {XtNfromVert,   (XtArgVal) NULL} /* and under test */
275  };
276
277  static Arg gcchoiceargs[] = {
278    {XtNfromVert,    (XtArgVal) NULL}, /* put it under the one above it */
279    {XtNfromHoriz,   (XtArgVal) NULL}, /* and next to that one */
280    {XtNborderWidth, (XtArgVal) 0}     /* no ugly borders */
281  };
282
283  static Arg testchoiceargs[] = {
284    {XtNborderWidth, (XtArgVal) 0}
285  };
286
287  int i;			/* counter */
288
289  /* Open the pipe */
290
291#ifdef notdef
292  pipe(fildes);
293  outend = fdopen(fildes[0],"r");
294#endif
295
296  /* Initialize toolkit stuff */
297
298  XtSetLanguageProc(NULL, (XtLanguageProc) NULL, NULL);
299
300  bigdaddy = XtAppInitialize(&appcontext, "Xgc", (XrmOptionDescList) NULL,
301			     (Cardinal) 0, &argc, argv, (String *) NULL,
302			     shellargs, XtNumber(shellargs));
303  X.dpy = XtDisplay(bigdaddy);
304  XtAppAddActions(appcontext, actions, XtNumber(actions));
305  XtOverrideTranslations
306      (bigdaddy, XtParseTranslationTable("<Message>WM_PROTOCOLS: quit()"));
307
308  /* Initialize GC stuff */
309
310  X.scr = DefaultScreenOfDisplay(X.dpy);
311  X.gc = XCreateGC(X.dpy,RootWindowOfScreen(X.scr),0,(XGCValues *) NULL);
312  X.miscgc = XCreateGC(X.dpy,RootWindowOfScreen(X.scr),0,(XGCValues *) NULL);
313
314  /* Find out what the foreground & background are, and update the GC
315  ** accordingly */
316
317  set_foreground_and_background();
318
319  topform = XtCreateManagedWidget("topform",formWidgetClass,bigdaddy,
320				  NULL,0);
321
322  GCform = XtCreateManagedWidget("GCform",formWidgetClass,topform,
323				NULL,0);
324
325  /* create all the GCchoices forms */
326
327  for (i=0;i<NUMCHOICES;++i) {
328    if (i==0)			/* on top */
329      gcchoiceargs[0].value = (XtArgVal) NULL;
330    else			/* under the last one */
331      gcchoiceargs[0].value = (XtArgVal) GCchoices[i-1];
332
333    GCchoices[i] = XtCreateManagedWidget(Everything[i]->choice.text,
334					 formWidgetClass,GCform,
335					 gcchoiceargs,XtNumber(gcchoiceargs));
336
337    /* now fill up that form */
338    GCdescs[i] = create_choice(GCchoices[i],Everything[i]);
339  }
340
341  /* put the planemask choice under the bottom GC choice */
342  gcchoiceargs[0].value = (XtArgVal) GCchoices[NUMCHOICES-1];
343  planemaskchoice = XtCreateManagedWidget("planemask",formWidgetClass,GCform,
344				  gcchoiceargs,XtNumber(gcchoiceargs));
345  /* fill it up */
346  create_planemask_choice(planemaskchoice);
347
348  /* put the dashlist choice under the planemask choice */
349  gcchoiceargs[0].value = (XtArgVal) planemaskchoice;
350  dashlistchoice = XtCreateManagedWidget("dashlist",formWidgetClass,GCform,
351				  gcchoiceargs,XtNumber(gcchoiceargs));
352  /* fill it up */
353  create_dashlist_choice(dashlistchoice);
354
355  /* put the linewidth choice under the dashlist choice */
356  gcchoiceargs[0].value = (XtArgVal) dashlistchoice;
357  linewidthchoice = XtCreateManagedWidget("linewidth",formWidgetClass,GCform,
358				  gcchoiceargs,XtNumber(gcchoiceargs));
359  /* fill it up */
360  linewidthtext = create_text_choice(linewidthchoice,TLineWidth,2,30);
361
362  /* put the font choice under the linewidth choice */
363  gcchoiceargs[0].value = (XtArgVal) linewidthchoice;
364  fontchoice = XtCreateManagedWidget("font",formWidgetClass,GCform,
365				     gcchoiceargs,XtNumber(gcchoiceargs));
366  /* fill it up */
367  fonttext = create_text_choice(fontchoice,TFont,80,300);
368
369  gcchoiceargs[0].value = (XtArgVal) fontchoice;
370  foregroundchoice = XtCreateManagedWidget("foreground",formWidgetClass,GCform,
371				   gcchoiceargs,XtNumber(gcchoiceargs));
372  foregroundtext = create_text_choice(foregroundchoice,TForeground,9,50);
373  /* FIXME 9 characters may not be the proper choice; really it
374   * should understand a more proper pixel specification... */
375
376  gcchoiceargs[1].value = (XtArgVal) foregroundchoice;
377  backgroundchoice = XtCreateManagedWidget("background",formWidgetClass,GCform,
378				   gcchoiceargs,XtNumber(gcchoiceargs));
379  backgroundtext = create_text_choice(backgroundchoice,TBackground,9,50);
380
381  gcchoiceargs[1].value = (XtArgVal) NULL;
382  gcchoiceargs[0].value = (XtArgVal) foregroundchoice;
383  percentchoice = XtCreateManagedWidget("testpercent",formWidgetClass,GCform,
384				 gcchoiceargs,XtNumber(gcchoiceargs));
385  X.percent = 1.0;
386  create_testfrac_choice(percentchoice);
387
388  /* make all the labels inside the choices line up nicely */
389  line_up_labels(GCdescs,(int) XtNumber(GCdescs));
390
391  /* put the test form under the GC form */
392  testformargs[0].value = (XtArgVal) GCform;
393  Testform = XtCreateManagedWidget("Testform",formWidgetClass,topform,
394				   testformargs,XtNumber(testformargs));
395
396  testchoiceform = XtCreateManagedWidget("testchoiceform",formWidgetClass,
397			     Testform,testchoiceargs,XtNumber(testchoiceargs));
398  testchoicedesc = create_choice(testchoiceform,Everything[CTest]);
399
400  commandformargs[0].value = (XtArgVal) GCform;
401  commandformargs[1].value = (XtArgVal) Testform;
402  commandform = XtCreateManagedWidget("commandform",formWidgetClass,topform,
403			      commandformargs,XtNumber(commandformargs));
404
405  /* Put the appropriate command buttons in the command form */
406
407  fill_up_commandform(commandform);
408
409  testargs[2].value = (XtArgVal) GCform;    /* to the right of */
410  test = XtCreateManagedWidget("test",widgetClass,topform,
411			       testargs,XtNumber(testargs));
412
413  resultargs[2].value = (XtArgVal) GCform; /* to the right of */
414  resultargs[3].value = (XtArgVal) test; /* under */
415  result = XtCreateManagedWidget("result",asciiTextWidgetClass,topform,
416				 resultargs,XtNumber(resultargs));
417
418  /* Now realize all the widgets */
419
420  XtRealizeWidget(bigdaddy);
421
422  /* Now do things we couldn't do until we had a window available */
423
424  X.win = XtWindow(test);
425  X.tile = XCreatePixmap(X.dpy,X.win,tile_width,tile_height,
426			 DefaultDepthOfScreen(X.scr));
427
428  X.tile = XCreatePixmapFromBitmapData(X.dpy,X.win,
429				       (char *)tile_bits,tile_width,
430				       tile_height,Black,White,
431				       DefaultDepthOfScreen(X.scr));
432  X.stipple = XCreateBitmapFromData(X.dpy,X.win,(char *)tile_bits,tile_width,
433				    tile_height);
434
435  XSetStipple(X.dpy,X.gc,X.stipple);
436  XSetStipple(X.dpy,X.miscgc,X.stipple);
437
438  GC_change_foreground(X.foreground,TRUE);
439  GC_change_background(X.background,TRUE);
440
441  wm_delete_window = XInternAtom(X.dpy, "WM_DELETE_WINDOW", False);
442  (void) XSetWMProtocols(X.dpy, XtWindow(bigdaddy), &wm_delete_window, 1);
443
444  /* Act like the user picked the first choice in each group */
445
446  choose_defaults(GCdescs,(int)XtNumber(GCdescs));
447  choose_defaults(&testchoicedesc,1);
448
449  /* Loop forever, dealing with events */
450
451  XtAppMainLoop(appcontext);
452
453  return 0;
454}
455
456/* fill_up_commandform(w)
457** ----------------------
458** Put the appropriate command buttons in the command form (w).
459*/
460
461static void
462fill_up_commandform(Widget w)
463{
464  static XtCallbackRec runcallbacklist[] = {
465    {(XtCallbackProc) run_test,  NULL},
466    {NULL,                       NULL}
467  };
468
469  static XtCallbackRec quitcallbacklist[] = {
470    {(XtCallbackProc) quit,      NULL},
471    {NULL,                       NULL}
472  };
473
474  static XtCallbackRec clearcallbacklist[] = {
475    {(XtCallbackProc) clear_test_window,    NULL},
476    {(XtCallbackProc) clear_result_window,  NULL},
477    {NULL,                                  NULL}
478  };
479
480  static XtCallbackRec playbackcallbacklist[] = {
481    {(XtCallbackProc) start_playback,       NULL},
482    {NULL,                                  NULL}
483  };
484
485  static XtCallbackRec keyinputcallbacklist[] = {
486    {(XtCallbackProc) read_from_keyboard,   NULL},
487    {NULL,                                  NULL}
488  };
489
490  static XtCallbackRec recordcallbacklist[] = {
491    {(XtCallbackProc) toggle_recordbutton,  NULL},
492    {NULL,                                  NULL}
493  };
494
495  static Arg runargs[] = {
496    {XtNcallback,    (XtArgVal) NULL}
497  };
498
499  static Arg clearargs[] = {
500    {XtNcallback,    (XtArgVal) NULL},
501    {XtNfromVert,    (XtArgVal) NULL}, /* put it under runbutton */
502    {XtNvertDistance,(XtArgVal) 10}
503  };
504
505  static Arg recordargs[] = {
506    {XtNcallback,    (XtArgVal) NULL},
507    {XtNfromVert,    (XtArgVal) NULL}, /* put it under clearbutton */
508    {XtNvertDistance,(XtArgVal) 10},
509    {XtNresizable,   (XtArgVal) True} /* so we can change the name */
510  };
511
512  static Arg playbackargs[] = {
513    {XtNcallback,    (XtArgVal) NULL},
514    {XtNfromVert,    (XtArgVal) NULL} /* put it under recordbutton */
515  };
516
517  static Arg keyinputargs[] = {
518    {XtNcallback,     (XtArgVal) NULL},
519    {XtNfromVert,    (XtArgVal) NULL} /* put it under playbackbutton */
520  };
521
522  static Arg quitargs[] = {
523    {XtNcallback,    (XtArgVal) NULL},
524    {XtNfromVert,    (XtArgVal) NULL}, /* put it under keyinputbutton */
525    {XtNvertDistance,(XtArgVal) 10}
526  };
527
528  runargs[0].value = (XtArgVal) runcallbacklist;
529  runbutton = XtCreateManagedWidget("Run",commandWidgetClass,
530			      w,runargs,XtNumber(runargs));
531
532  clearargs[0].value = (XtArgVal) clearcallbacklist;
533  clearargs[1].value = (XtArgVal) runbutton; /* under */
534  clearbutton = XtCreateManagedWidget("Clear window",commandWidgetClass,
535         		      w,clearargs,XtNumber(clearargs));
536
537  recordargs[0].value = (XtArgVal) recordcallbacklist;
538  recordargs[1].value = (XtArgVal) clearbutton;	/* under */
539  recordbutton = XtCreateManagedWidget("Record",commandWidgetClass,
540			      w,recordargs,XtNumber(recordargs));
541
542  playbackargs[0].value = (XtArgVal) playbackcallbacklist;
543  playbackargs[1].value = (XtArgVal) recordbutton; /* under */
544  playbackbutton = XtCreateManagedWidget("Playback",commandWidgetClass,
545			      w,playbackargs,XtNumber(playbackargs));
546
547  keyinputargs[0].value = (XtArgVal) keyinputcallbacklist;
548  keyinputargs[1].value = (XtArgVal) playbackbutton;
549  keyinputbutton = XtCreateManagedWidget("Read Input",commandWidgetClass,
550			      w,keyinputargs,XtNumber(keyinputargs));
551
552  quitargs[0].value = (XtArgVal) quitcallbacklist;
553  quitargs[1].value = (XtArgVal) keyinputbutton; /* under */
554  (void) XtCreateManagedWidget("Quit",commandWidgetClass,
555			       w,quitargs,XtNumber(quitargs));
556
557}
558/* quit()
559** ------
560** Leave the program nicely.
561*/
562
563static void
564quit(void)
565{
566  close_file_if_recording();
567  exit(0);
568}
569
570static void quitAction(Widget w, XEvent *e, String *p, Cardinal *n)
571{
572    if (e->type == ClientMessage && e->xclient.data.l[0] != wm_delete_window)
573	XBell(XtDisplay(w), 0);
574    else
575	quit();
576}
577
578/* clear_test_window()
579** -------------------
580** Clear the test window.
581*/
582
583static void
584clear_test_window(void)
585{
586  XClearWindow(X.dpy,XtWindow(test));
587}
588
589/* clear_result_window()
590** ---------------------
591** Clear the result window.
592*/
593
594static void
595clear_result_window(void)
596{
597  set_text(result, "");
598}
599
600/* set_foreground_and_background()
601** -------------------------------
602** Finds the user-specified foreground and background by querying
603** the resource manager, and sets state accordingly.  Also specifies
604** the initial font for text tests.
605*/
606
607static void
608set_foreground_and_background(void)
609{
610  X.gcv.foreground = X.foreground = 0;
611  X.gcv.background = X.background = 0xffffffff;
612
613  X.fontname = "6x10";
614  GC_change_font(X.fontname,FALSE);
615}
616