home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Games / mosaic / x11.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  27.5 KB  |  1,227 lines

  1. /*
  2.  * x11.c
  3.  * kirk johnson
  4.  * october 1990
  5.  */
  6.  
  7. #include <X11/Xlib.h>
  8. #include <X11/Xutil.h>
  9. #include <X11/cursorfont.h>
  10. #include "mosaic.h"
  11. #include "x11.h"
  12. #include "patchlevel.h"
  13.  
  14. #define BufSize       (256)
  15.  
  16. #define BoundVarVal(var, min, max) \
  17. {                                  \
  18.   if ((var) < (min))               \
  19.     (var) = (min);                 \
  20.   else if ((var) > (max))          \
  21.     (var) = (max);                 \
  22. }
  23.  
  24. typedef unsigned long Pixel;
  25. typedef XFontStruct   XFS;
  26.  
  27. static void   GetDisplayName();
  28. static void   GetResourceOptions();
  29. static int    IsTrue();
  30. static char  *strdup();
  31. static void   GetCmdLineOptions();
  32. static void   Help();
  33. static void   doKey();
  34. static void   doMotion();
  35. static void   doBoardExpose();
  36. static void   doHelpExpose();
  37. static void   doNextExpose();
  38. static void   doMainExpose();
  39. static void   doHighExpose();
  40. static void   doButtonPress();
  41. static Pixel  GetColor();
  42. static Window GetWindow();
  43. static Pixmap MakePixmap();
  44. static void   SetCursor();
  45. static void   TopWindowStuff();
  46. static void   AddEventHandler();
  47. static void (*GetEventHandler())();
  48.  
  49. static char  buf[BufSize];
  50. static char *TileBits[4];
  51.  
  52. static char *dpyname;        /* display name */
  53. static int   mono;        /* mono mode flag */
  54. static int   solid;        /* solid mode flag */
  55. static int   expert;        /* expert mode flag */
  56. static int   gwidth;        /* gutter width */
  57. static int   bwidth;        /* border width */
  58. static char *fgname;        /* fg color name */
  59. static char *bgname;        /* bg color name */
  60. static char *bdname;        /* border color name */
  61. static char *cname[4];        /* tile color names */
  62. static char *fntname;        /* font name */
  63.  
  64. static Display *dpy;        /* display connection */
  65. static int      scrn;        /* screen number */
  66. static Window   root;        /* root window */
  67. static Visual  *visl;        /* visual */
  68. static Colormap cmap;        /* colormap */
  69. static int      dpth;        /* display depth */
  70. static GC       gc;        /* graphics context */
  71.  
  72. static Pixel  fore;        /* foreground color */
  73. static Pixel  back;        /* background color */
  74. static Pixel  brdr;        /* border color */
  75. static Pixel  tilec[4];        /* tile colors */
  76. static Pixmap tilep[4];        /* tile pixmaps */
  77. static XFS   *font;        /* text font */
  78.  
  79. static Window mainw;        /* main window */
  80. static Window boardw;        /* board window */
  81. static Window helpw;        /* help window */
  82. static Window nextw;        /* next piece window */
  83. static Window scoresw;        /* high scores window */
  84.  
  85. static int crow = 0;        /* controller position */
  86. static int ccol = 0;
  87.  
  88. static int scoresvis;        /* high scores visible? */
  89. static int helpvis;        /* help window visible? */
  90.  
  91. static int swidth;        /* width of score text area */
  92. static int hswidth;        /* width of high score window */
  93.  
  94.  
  95. void InitDisplay(argc, argv)
  96.      int    argc;
  97.      char **argv;
  98. {
  99.   int    i;
  100.   int    w, h;
  101.   int    x, y;
  102.  
  103.   /* set standard defaults */
  104.   dpyname  = NULL;        /* default to DISPLAY */
  105.   expert   = False;        /* default to novice mode */
  106.   mono     = False;        /* default to color (if possible) */
  107.   solid    = False;        /* default to patterned tiles */
  108.   gwidth   = DfltGutterWidth;    /* gutter width */
  109.   bwidth   = DfltBorderWidth;    /* border width */
  110.   fgname   = DfltForeName;    /* foreground color name */
  111.   bgname   = DfltBackName;    /* background color name */
  112.   bdname   = DfltBrdrName;    /* border color name */
  113.   cname[0] = DfltC0Name;    /* color 0 name */
  114.   cname[1] = DfltC1Name;    /* color 1 name */
  115.   cname[2] = DfltC2Name;    /* color 2 name */
  116.   cname[3] = DfltC3Name;    /* color 3 name */
  117.   fntname  = DfltFontName;    /* font name */
  118.  
  119.   GetDisplayName(argc, argv);
  120.  
  121.   /* general X11 setup */
  122.   dpy = XOpenDisplay(dpyname);
  123.   if (dpy == NULL)
  124.   {
  125.     sprintf(buf, "unable to open display \"%s\"", dpyname);
  126.     fatal(buf);
  127.   }
  128.   scrn = DefaultScreen(dpy);
  129.   root = RootWindow(dpy, scrn);
  130.   visl = DefaultVisual(dpy, scrn);
  131.   cmap = DefaultColormap(dpy, scrn);
  132.   dpth = DefaultDepth(dpy, scrn);
  133.  
  134.   GetResourceOptions();
  135.  
  136.   /*
  137.    * if running with a StaticGray or GrayScale
  138.    * display class, default to mono mode
  139.    */
  140.   switch (visl->class)
  141.   {
  142.   case StaticGray:
  143.   case GrayScale:
  144.     mono = True;
  145.     break;
  146.   }
  147.  
  148.   GetCmdLineOptions(argc, argv);
  149.  
  150.   /* check for mono mode */
  151.   if (mono)
  152.   {
  153.     bdname = fgname;
  154.     for (i=0; i<4; i++)
  155.       cname[i] = fgname;
  156.   }
  157.  
  158. #ifdef DEBUG
  159.   /* debug: color names */
  160.   fflush(stdout);
  161.   fprintf(stderr, "%s: color names\n", AppName);
  162.   fprintf(stderr, "  fgname %s\n", fgname);
  163.   fprintf(stderr, "  bgname %s\n", bgname);
  164.   fprintf(stderr, "  bdname %s\n", bdname);
  165.   fprintf(stderr, "  c0name %s\n", cname[0]);
  166.   fprintf(stderr, "  c1name %s\n", cname[1]);
  167.   fprintf(stderr, "  c2name %s\n", cname[2]);
  168.   fprintf(stderr, "  c3name %s\n", cname[3]);
  169.   fprintf(stderr, "\n");
  170.   fflush(stderr);
  171. #endif /* DEBUG */
  172.  
  173.   /* color allocation */
  174.   fore = GetColor(fgname);
  175.   back = GetColor(bgname);
  176.   brdr = GetColor(bdname);
  177.   for (i=0; i<4; i++)
  178.     tilec[i] = GetColor(cname[i]);
  179.  
  180.   /* graphics context */
  181.   gc = XCreateGC(dpy, root, 0, NULL);
  182.   XSetState(dpy, gc, fore, back, GXcopy, AllPlanes);
  183.  
  184.   /* select the tile patterns */
  185.   if (solid)
  186.   {
  187.     TileBits[0] = zerobits;
  188.     TileBits[1] = solidbits;
  189.     TileBits[2] = solidbits;
  190.     TileBits[3] = solidbits;
  191.   }
  192.   else
  193.   {
  194.     TileBits[0] = zerobits;
  195.     TileBits[1] = onebits;
  196.     TileBits[2] = twobits;
  197.     TileBits[3] = threebits;
  198.   }
  199.  
  200.   /* build the tiles */
  201.   for (i=0; i<4; i++)
  202.     tilep[i] = MakePixmap(TileBits[i], TileSize, TileSize, tilec[i], back);
  203.  
  204.   /* fonts */
  205.   font = XLoadQueryFont(dpy, fntname);
  206.   if (font == NULL)
  207.   {
  208.     sprintf(buf, "unable to load font \"%s\"", fntname);
  209.     fatal(buf);
  210.   }
  211.  
  212.   swidth  = XTextWidth(font, MaxPossibleScore, strlen(MaxPossibleScore));
  213.   swidth += TileSize + (gwidth*4);
  214.  
  215.   /* main window */
  216.   w  = (gwidth*4) + (bwidth*2) + (TileSize*BoardSize);
  217.   h  = (gwidth*4) + (bwidth*2) + (TileSize*BoardSize);
  218.   w += gwidth + swidth;
  219.   h += gwidth + font->ascent + font->descent;
  220.   mainw = GetWindow(root, 0, 0, w, h, bwidth);
  221.   SetCursor(mainw, MainCurs);
  222.   XSelectInput(dpy, mainw, PointerMotionMask|KeyPressMask|ExposureMask);
  223.   AddEventHandler(mainw, MotionNotify, doMotion);
  224.   AddEventHandler(mainw, KeyPress, doKey);
  225.   AddEventHandler(mainw, Expose, doMainExpose);
  226.  
  227.   /* playing board window */
  228.   x = gwidth;
  229.   y = gwidth;
  230.   w = (gwidth*2) + (TileSize*BoardSize);
  231.   h = (gwidth*2) + (TileSize*BoardSize);
  232.   boardw = GetWindow(mainw, x, y, w, h, bwidth);
  233.   SetCursor(boardw, BoardCurs);
  234.   XSelectInput(dpy, boardw, ExposureMask|ButtonPressMask);
  235.   AddEventHandler(boardw, Expose, doBoardExpose);
  236.   AddEventHandler(boardw, ButtonPress, doButtonPress);
  237.   XMapWindow(dpy, boardw);
  238.  
  239.   /* help window */
  240.   w = (TileSize*(BoardSize-6)) + (gwidth*2);
  241.   h = NHelpLines*(font->ascent + font->descent) + (gwidth*2);
  242.   x = ((TileSize*BoardSize + gwidth*2) - (w + bwidth*2)) / 2;
  243.   y = ((TileSize*BoardSize + gwidth*2) - (h + bwidth*2)) / 2;
  244.   helpw = GetWindow(boardw, x, y, w, h, bwidth);
  245.   XSelectInput(dpy, helpw, ExposureMask);
  246.   AddEventHandler(helpw, Expose, doHelpExpose);
  247.  
  248.   /* if we're in "expert" mode, don't map the silly help window initially */
  249.   if (expert)
  250.   {
  251.     helpvis = False;
  252.   }
  253.   else
  254.   {
  255.     XMapWindow(dpy, helpw);
  256.     helpvis = True;
  257.   }
  258.  
  259.   /* next piece window */
  260.   x = (gwidth*4) + (bwidth*2) + (TileSize*BoardSize);
  261.   y = gwidth;
  262.   w = (gwidth*2) + (TileSize*2);
  263.   h = (gwidth*2) + (TileSize*2);
  264.   nextw = GetWindow(mainw, x, y, w, h, bwidth);
  265.   XSelectInput(dpy, nextw, ExposureMask);
  266.   AddEventHandler(nextw, Expose, doNextExpose);
  267.   XMapWindow(dpy, nextw);
  268.  
  269.   /* scores window */
  270.   hswidth  = XTextWidth(font, HighScoreTitle, strlen(HighScoreTitle));
  271.   hswidth += 2*gwidth;
  272.   w  = font->max_bounds.width * MaxUnameLen;
  273.   w += XTextWidth(font, MaxPossibleScore, strlen(MaxPossibleScore));
  274.   w += 3*gwidth;
  275.   if (hswidth > w)
  276.     w = hswidth;
  277.   else
  278.     hswidth = w;
  279.   h = (NHighScores+2)*(font->ascent + font->descent) + 2*gwidth;
  280.   scoresw = GetWindow(root, 0, 0, w, h, bwidth);
  281.   SetCursor(scoresw, MainCurs);
  282.   XSelectInput(dpy, scoresw, KeyPressMask|ExposureMask);
  283.   AddEventHandler(scoresw, KeyPress, doKey);
  284.   AddEventHandler(scoresw, Expose, doHighExpose);
  285.   scoresvis = False;
  286.  
  287.   /* various magic incantations (window manager) */
  288.   TopWindowStuff(mainw, MainWindowName);
  289.   TopWindowStuff(scoresw, ScoresWindowName);
  290.  
  291.   /* map the main window */
  292.   XMapWindow(dpy, mainw);
  293. }
  294.  
  295.  
  296. static void GetDisplayName(argc, argv)
  297.      int    argc;
  298.      char **argv;
  299. {
  300.   int i;
  301.  
  302.   /* get display name from command line */ 
  303.   for (i=1; i<argc; i++)
  304.     if (strcmp(argv[i], "-display") == 0)
  305.     {
  306.       i += 1;
  307.       if (i < argc)
  308.     dpyname = argv[i];
  309.       else
  310.     Help("no display arg provided");
  311.     }
  312. }
  313.  
  314.  
  315. static void GetResourceOptions()
  316. {
  317.   char *tmp;
  318.  
  319.   tmp = XGetDefault(dpy, AppName, "Mono");
  320.   if (tmp != NULL)
  321.     mono = IsTrue(tmp);
  322.  
  323.   tmp = XGetDefault(dpy, AppName, "Solid");
  324.   if (tmp != NULL)
  325.     solid = IsTrue(tmp);
  326.  
  327.   tmp = XGetDefault(dpy, AppName, "Expert");
  328.   if (tmp != NULL)
  329.     expert = IsTrue(tmp);
  330.  
  331.   tmp = XGetDefault(dpy, AppName, "GutterWidth");
  332.   if (tmp != NULL)
  333.   {
  334.     sscanf(tmp, "%d", &gwidth);
  335.     if (gwidth < 0)
  336.       fatal("gutterwidth must be non-negative");
  337.   }
  338.   
  339.   tmp = XGetDefault(dpy, AppName, "BorderWidth");
  340.   if (tmp != NULL)
  341.   {
  342.     sscanf(tmp, "%d", &bwidth);
  343.     if (bwidth < 0)
  344.       fatal("borderwidth must be non-negative");
  345.   }
  346.   
  347.   tmp = XGetDefault(dpy, AppName, "Foreground");
  348.   if (tmp != NULL)
  349.     fgname = strdup(tmp);
  350.  
  351.   tmp = XGetDefault(dpy, AppName, "Background");
  352.   if (tmp != NULL)
  353.     bgname = strdup(tmp);
  354.  
  355.   tmp = XGetDefault(dpy, AppName, "BorderColor");
  356.   if (tmp != NULL)
  357.     bdname = strdup(tmp);
  358.  
  359.   tmp = XGetDefault(dpy, AppName, "Color0");
  360.   if (tmp != NULL)
  361.     cname[0] = strdup(tmp);
  362.  
  363.   tmp = XGetDefault(dpy, AppName, "Color1");
  364.   if (tmp != NULL)
  365.     cname[1] = strdup(tmp);
  366.  
  367.   tmp = XGetDefault(dpy, AppName, "Color2");
  368.   if (tmp != NULL)
  369.     cname[2] = strdup(tmp);
  370.  
  371.   tmp = XGetDefault(dpy, AppName, "Color3");
  372.   if (tmp != NULL)
  373.     cname[3] = strdup(tmp);
  374.  
  375.   tmp = XGetDefault(dpy, AppName, "Font");
  376.   if (tmp != NULL)
  377.     fntname = strdup(tmp);
  378. }
  379.  
  380.  
  381. static int IsTrue(s)
  382.      char *s;
  383. {
  384.   return ((strcasecmp(s, "true") == 0) ||
  385.       (strcasecmp(s, "on") == 0) ||
  386.       (strcasecmp(s, "yes") == 0));
  387. }
  388.  
  389.  
  390. static char *strdup(s)
  391.      char *s;
  392. {
  393.   char *rslt;
  394.  
  395.   rslt = (char *) malloc(sizeof(char) * (strlen(s) + 1));
  396.   if (rslt == NULL)
  397.     fatal("unable to malloc");
  398.  
  399.   strcpy(rslt, s);
  400.  
  401.   return rslt;
  402. }
  403.  
  404.  
  405. static void GetCmdLineOptions(argc, argv)
  406.      int    argc;
  407.      char **argv;
  408. {
  409.   int i;
  410.  
  411.   /* get options from command line */
  412.   for (i=1; i<argc; i++)
  413.     if (strcmp(argv[i], "-display") == 0)
  414.     {
  415.       /* already got the display name */
  416.       i += 1;
  417.     }
  418.     else if (strcmp(argv[i], "-expert") == 0)
  419.     {
  420.       /* run in "expert" mode */
  421.       expert = True;
  422.     }
  423.     else if (strcmp(argv[i], "-color") == 0)
  424.     {
  425.       /* try to use colors */
  426.       mono = False;
  427.     }
  428.     else if (strcmp(argv[i], "-mono") == 0)
  429.     {
  430.       /* skip the colors */
  431.       mono = True;
  432.     }
  433.     else if (strcmp(argv[i], "-patterns") == 0)
  434.     {
  435.       /* use patterned tiles */
  436.       solid = False;
  437.     }
  438.     else if (strcmp(argv[i], "-solid") == 0)
  439.     {
  440.       /* use solid tiles */
  441.       solid = True;
  442.     }
  443.     else if (strcmp(argv[i], "-gw") == 0)
  444.     {
  445.       /* get gutter width from next arg */
  446.       i += 1;
  447.       if (i < argc)
  448.     sscanf(argv[i], "%d", &gwidth);
  449.       else
  450.     Help("no gutterwidth arg provided");
  451.  
  452.       /* ensure the gutter width is non-negative */
  453.       if (gwidth < 0)
  454.     fatal("gutterwidth must be non-negative");
  455.     }
  456.     else if (strcmp(argv[i], "-bw") == 0)
  457.     {
  458.       /* get border width from next arg */
  459.       i += 1;
  460.       if (i < argc)
  461.     sscanf(argv[i], "%d", &bwidth);
  462.       else
  463.     Help("no borderwidth arg provided");
  464.  
  465.       /* ensure the border width is non-negative */
  466.       if (bwidth < 0)
  467.     fatal("borderwidth must be non-negative");
  468.     }
  469.     else if (strcmp(argv[i], "-fg") == 0)
  470.     {
  471.       /* get foreground color name from next arg */
  472.       i += 1;
  473.       if (i < argc)
  474.     fgname = argv[i];
  475.       else
  476.     Help("no foreground arg provided");
  477.     }
  478.     else if (strcmp(argv[i], "-bg") == 0)
  479.     {
  480.       /* get background color name from next arg */
  481.       i += 1;
  482.       if (i < argc)
  483.     bgname = argv[i];
  484.       else
  485.     Help("no background arg provided");
  486.     }
  487.     else if (strcmp(argv[i], "-bd") == 0)
  488.     {
  489.       /* get border color name from next arg */
  490.       i += 1;
  491.       if (i < argc)
  492.     bdname = argv[i];
  493.       else
  494.     Help("no bordercolor arg provided");
  495.     }
  496.     else if (strcmp(argv[i], "-c0") == 0)
  497.     {
  498.       /* get color 0 name from next arg */
  499.       i += 1;
  500.       if (i < argc)
  501.     cname[0] = argv[i];
  502.       else
  503.     Help("no color0 arg provided");
  504.     }
  505.     else if (strcmp(argv[i], "-c1") == 0)
  506.     {
  507.       /* get color 1 name from next arg */
  508.       i += 1;
  509.       if (i < argc)
  510.     cname[1] = argv[i];
  511.       else
  512.     Help("no color1 arg provided");
  513.     }
  514.     else if (strcmp(argv[i], "-c2") == 0)
  515.     {
  516.       /* get color 2 name from next arg */
  517.       i += 1;
  518.       if (i < argc)
  519.     cname[2] = argv[i];
  520.       else
  521.     Help("no color2 arg provided");
  522.     }
  523.     else if (strcmp(argv[i], "-c3") == 0)
  524.     {
  525.       /* get color 3 name from next arg */
  526.       i += 1;
  527.       if (i < argc)
  528.     cname[3] = argv[i];
  529.       else
  530.     Help("no color3 arg provided");
  531.     }
  532.     else if (strcmp(argv[i], "-fn") == 0)
  533.     {
  534.       /* get font name from next arg */
  535.       i += 1;
  536.       if (i < argc)
  537.     fntname = argv[i];
  538.       else
  539.     Help("no font arg provided");
  540.     }
  541.     else if (strcmp(argv[i], "-help") == 0)
  542.     {
  543.       Help(NULL);
  544.     }
  545.     else
  546.     {
  547.       sprintf(buf, "unknown option: %s", argv[i]);
  548.       Help(buf);
  549.     }
  550. }
  551.  
  552.  
  553. static void Help(msg)
  554.      char *msg;
  555. {
  556.   if (msg != NULL)
  557.     fprintf(stderr, "\n%s\n", msg);
  558.   else
  559.     fprintf(stderr, "\n%s (v %d.%d)\n", AppName, MajorVersion, MinorVersion);
  560.  
  561.   fprintf(stderr, "\ncommand line options:\n");
  562.   fprintf(stderr, "  -help           print this message\n");
  563.   fprintf(stderr, "  -display <d>    use display <d>\n");
  564.   fprintf(stderr, "  -expert         don't show quick help initially\n");
  565.   fprintf(stderr, "  -color          run in color mode\n");
  566.   fprintf(stderr, "  -mono           run in mono mode\n");
  567.   fprintf(stderr, "  -patterns       use patterned tiles\n");
  568.   fprintf(stderr, "  -solid          use solid tiles\n");
  569.   fprintf(stderr, "  -gw <n>         use gutter width of <n> pixels\n");
  570.   fprintf(stderr, "  -bw <n>         use border width of <n> pixels\n");
  571.   fprintf(stderr, "  -fg <c>         use <c> as forground color\n");
  572.   fprintf(stderr, "  -bg <c>         use <c> as background color\n");
  573.   fprintf(stderr, "  -bd <c>         use <c> as border color\n");
  574.   fprintf(stderr, "  -c0 <c>         use <c> as board color 0\n");
  575.   fprintf(stderr, "  -c1 <c>         use <c> as board color 1\n");
  576.   fprintf(stderr, "  -c2 <c>         use <c> as board color 2\n");
  577.   fprintf(stderr, "  -c3 <c>         use <c> as board color 3\n");
  578.   fprintf(stderr, "  -fn <f>         use font <f> for drawing text\n");
  579.  
  580.   fprintf(stderr, "\nSee the man page for more info.\n\n");
  581.  
  582.   exit(1);
  583. }
  584.  
  585.  
  586. void MainLoop()
  587. {
  588.   XEvent xev;
  589.   void (*handler)();
  590.  
  591.   while (1)
  592.   {
  593.     XNextEvent(dpy, &xev);
  594.     handler = GetEventHandler(&xev);
  595.     if (handler != NULL) handler(&xev);
  596.   }
  597. }
  598.  
  599.  
  600. void drawBoard()
  601. {
  602.   int r, c;
  603.  
  604.   /* redraw the tiles */
  605.   for (c=0; c<BoardSize; c++)
  606.     for (r=0; r<BoardSize; r++)
  607.       drawTile(r, c);
  608.   
  609.   /* redraw controller */
  610.   drawController();
  611. }
  612.  
  613.  
  614. void drawHelp()
  615. {
  616.   /*
  617.    * mosaic quick help
  618.    * 
  619.    * q  quit
  620.    * s  toggle high scores window visibility
  621.    * h  toggle help window visibility
  622.    * n  new game (only enabled when current game is completed)
  623.    * a  automatic -- randomly place any remaining tiles
  624.    * 
  625.    * try `man mosaic' for further info
  626.    * press `h' to hide this window
  627.    */
  628.  
  629.   int   fontsize;
  630.   int   x, y;
  631.   int   len;
  632.   char *txt;
  633.   
  634.   fontsize = font->ascent + font->descent;
  635.  
  636.   x   = 10;
  637.   y   = font->ascent + gwidth;
  638.  
  639.   y  += fontsize/2;
  640.   txt = "xtile quick help";
  641.   len = strlen(txt);
  642.   XDrawString(dpy, helpw, gc, x, y, txt, len);
  643.   y += fontsize/2;
  644.   y += fontsize;
  645.  
  646.   txt = "q";
  647.   len = strlen(txt);
  648.   XDrawString(dpy, helpw, gc, x, y, txt, len);
  649.  
  650.   txt = "quit";
  651.   len = strlen(txt);
  652.   XDrawString(dpy, helpw, gc, x+2*font->max_bounds.width, y, txt, len);
  653.   y += fontsize;
  654.  
  655.   txt = "s";
  656.   len = strlen(txt);
  657.   XDrawString(dpy, helpw, gc, x, y, txt, len);
  658.   
  659.   txt = "toggle high scores window";
  660.   len = strlen(txt);
  661.   XDrawString(dpy, helpw, gc, x+2*font->max_bounds.width, y, txt, len);
  662.   y += fontsize;
  663.  
  664.   txt = "h";
  665.   len = strlen(txt);
  666.   XDrawString(dpy, helpw, gc, x, y, txt, len);
  667.  
  668.   txt = "toggle help window";
  669.   len = strlen(txt);
  670.   XDrawString(dpy, helpw, gc, x+2*font->max_bounds.width, y, txt, len);
  671.   y += fontsize;
  672.  
  673.   txt = "n";
  674.   len = strlen(txt);
  675.   XDrawString(dpy, helpw, gc, x, y, txt, len);
  676.  
  677.   txt = "new game";
  678.   len = strlen(txt);
  679.   XDrawString(dpy, helpw, gc, x+2*font->max_bounds.width, y, txt, len);
  680.   y += fontsize;
  681.  
  682.   txt = "a";
  683.   len = strlen(txt);
  684.   XDrawString(dpy, helpw, gc, x, y, txt, len);
  685.  
  686.   txt = "automatic";
  687.   len = strlen(txt);
  688.   XDrawString(dpy, helpw, gc, x+2*font->max_bounds.width, y, txt, len);
  689.   y += fontsize;
  690.  
  691.   y += fontsize/2;
  692.   txt = "try `man xtile' for further info";
  693.   len = strlen(txt);
  694.   XDrawString(dpy, helpw, gc, x, y, txt, len);
  695.   y += fontsize;
  696.  
  697.   txt = "(press `h' to hide this window)";
  698.   len = strlen(txt);
  699.   XDrawString(dpy, helpw, gc, x, y, txt, len);
  700.   y += fontsize;
  701.   y += fontsize/2;
  702. }
  703.  
  704.  
  705. void drawTile(r, c)
  706.      int r, c;            /* tile position */
  707. {
  708.   int x, y;
  709.  
  710.   x = c * TileSize + gwidth;
  711.   y = r * TileSize + gwidth;
  712.   
  713.   XCopyArea(dpy, tilep[tile[r*BoardSize+c]], boardw, gc,
  714.         0, 0, TileSize, TileSize, x, y);
  715. }
  716.  
  717.  
  718. void drawController()
  719. {
  720.   int x, y;
  721.   
  722.   x = ccol * TileSize + gwidth;
  723.   y = crow * TileSize + gwidth;
  724.   
  725.   XDrawRectangle(dpy, boardw, gc, x, y,
  726.          TileSize*2-1, TileSize*2-1);
  727.   XDrawRectangle(dpy, boardw, gc, x+1, y+1,
  728.          TileSize*2-3, TileSize*2-3);
  729. }
  730.  
  731.  
  732. void drawNext()
  733. {
  734.   int p;
  735.   
  736.   p = (nextpiece < NPieces) ? piece[nextpiece] : 0;
  737.   
  738.   XCopyArea(dpy, tilep[p&0x03], nextw, gc, 0, 0, TileSize, TileSize,
  739.         gwidth, gwidth);
  740.   p >>= 2;
  741.   XCopyArea(dpy, tilep[p&0x03], nextw, gc, 0, 0, TileSize, TileSize,
  742.         gwidth+TileSize, gwidth);
  743.   p >>= 2;
  744.   XCopyArea(dpy, tilep[p&0x03], nextw, gc, 0, 0, TileSize, TileSize,
  745.         gwidth, gwidth+TileSize);
  746.   p >>= 2;
  747.   XCopyArea(dpy, tilep[p&0x03], nextw, gc, 0, 0, TileSize, TileSize,
  748.         gwidth+TileSize, gwidth+TileSize);
  749. }
  750.  
  751.  
  752. void drawTitle()
  753. {
  754.   int   x, y;
  755.   int   len;
  756.   char *txt;
  757.  
  758.   x   = (gwidth*2) + (bwidth) + (TileSize*BoardSize/2);
  759.   y   = (gwidth*4) + (bwidth*2) + (TileSize*BoardSize);
  760.   txt = AppName;
  761.  
  762.   len = strlen(txt);
  763.   x  -= XTextWidth(font, txt, len) / 2;
  764.   y  += font->ascent;
  765.  
  766.   XSetFont(dpy, gc, font->fid);
  767.   XDrawString(dpy, mainw, gc, x, y, txt, len);
  768. }
  769.  
  770.  
  771. void drawScore()
  772. {
  773.   int   i, total;
  774.   int   top, left;
  775.   int   xtra, len;
  776.   int   x, y;
  777.   char *txt;
  778.   char  buf[16];
  779.  
  780.   XSetFont(dpy, gc, font->fid);
  781.  
  782.   left = (gwidth*5) + (bwidth*2) + (TileSize*BoardSize);
  783.   top  = (gwidth*4) + (TileSize*4);
  784.   xtra = (TileSize - (font->ascent + font->descent)) / 2;
  785.  
  786.   txt = "to play";
  787.   len = strlen(txt);
  788.   x   = left + (swidth - XTextWidth(font, txt, len)) / 2;
  789.   y   = top + xtra + font->ascent;
  790.   XDrawString(dpy, mainw, gc, x, y, txt, len);
  791.   top += TileSize + gwidth;
  792.  
  793.   for (i=0; i<3; i++)
  794.   {
  795.     XClearArea(dpy, mainw, left, top, swidth, TileSize, False);
  796.     XCopyArea(dpy, tilep[i+1], mainw, gc, 0, 0,
  797.           TileSize, TileSize, left, top);
  798.     sprintf(buf, "%d", remain[i]);
  799.     len = strlen(buf);
  800.     x   = left + swidth - gwidth - XTextWidth(font, buf, len);
  801.     y   = top + xtra + font->ascent;
  802.     XDrawString(dpy, mainw, gc, x, y, buf, len);
  803.     top += TileSize + gwidth;
  804.   }
  805.   top += TileSize + gwidth;
  806.  
  807.   txt = "total";
  808.   len = strlen(txt);
  809.   x   = left + (swidth - XTextWidth(font, txt, len)) / 2;
  810.   y   = top + xtra + font->ascent;
  811.   XDrawString(dpy, mainw, gc, x, y, txt, len);
  812.   top += TileSize + gwidth;
  813.  
  814.   total = 0;
  815.   for (i=0; i<3; i++)
  816.   {
  817.     total += tscore[i];
  818.     XClearArea(dpy, mainw, left, top, swidth, TileSize, False);
  819.     XCopyArea(dpy, tilep[i+1], mainw, gc, 0, 0,
  820.           TileSize, TileSize, left, top);
  821.     sprintf(buf, "%d", tscore[i]);
  822.     len = strlen(buf);
  823.     x   = left + swidth - gwidth - XTextWidth(font, buf, len);
  824.     y   = top + xtra + font->ascent;
  825.     XDrawString(dpy, mainw, gc, x, y, buf, len);
  826.     top += TileSize + gwidth;
  827.   }
  828.  
  829.   XClearArea(dpy, mainw, left, top, swidth, TileSize, False);
  830.   sprintf(buf, "%d", total);
  831.   len = strlen(buf);
  832.   x   = left + swidth - gwidth - XTextWidth(font, buf, len);
  833.   y   = top + xtra + font->ascent;
  834.   XDrawString(dpy, mainw, gc, x, y, buf, len);
  835.   top += TileSize + gwidth;
  836.   top += TileSize + gwidth;
  837.  
  838.   txt = "piece";
  839.   len = strlen(txt);
  840.   x   = left + (swidth - XTextWidth(font, txt, len)) / 2;
  841.   y   = top + xtra + font->ascent;
  842.   XDrawString(dpy, mainw, gc, x, y, txt, len);
  843.   top += TileSize + gwidth;
  844.  
  845.   total = 0;
  846.   for (i=0; i<3; i++)
  847.   {
  848.     total += pscore[i];
  849.     XClearArea(dpy, mainw, left, top, swidth, TileSize, False);
  850.     XCopyArea(dpy, tilep[i+1], mainw, gc, 0, 0,
  851.           TileSize, TileSize, left, top);
  852.     sprintf(buf, "%d", pscore[i]);
  853.     len = strlen(buf);
  854.     x   = left + swidth - gwidth - XTextWidth(font, buf, len);
  855.     y   = top + xtra + font->ascent;
  856.     XDrawString(dpy, mainw, gc, x, y, buf, len);
  857.     top += TileSize + gwidth;
  858.   }
  859.  
  860.   XClearArea(dpy, mainw, left, top, swidth, TileSize, False);
  861.   sprintf(buf, "%d", total);
  862.   len = strlen(buf);
  863.   x   = left + swidth - gwidth - XTextWidth(font, buf, len);
  864.   y   = top + xtra + font->ascent;
  865.   XDrawString(dpy, mainw, gc, x, y, buf, len);
  866.   top += TileSize + gwidth;
  867. }
  868.  
  869.  
  870. void drawHighScores()
  871. {
  872.   int   i;
  873.   int   fontsize;
  874.   int   x, y;
  875.   int   len;
  876.   char *txt;
  877.  
  878.   fontsize = font->ascent + font->descent;
  879.  
  880.   txt = HighScoreTitle;
  881.   len = strlen(txt);
  882.   x   = (hswidth - XTextWidth(font, txt, len)) / 2;
  883.   y   = fontsize/2 + font->ascent + gwidth;
  884.   XDrawString(dpy, scoresw, gc, x, y, txt, len);
  885.  
  886.   y = fontsize*2 + gwidth;
  887.   for (i=0; i<NHighScores; i++)
  888.     if (highscore[i].score > 0)
  889.     {
  890.       XClearArea(dpy, scoresw, 0, y, hswidth, fontsize, False);
  891.       y += font->ascent;
  892.       
  893.       txt = highscore[i].uname;
  894.       len = strlen(txt);
  895.       XDrawString(dpy, scoresw, gc, gwidth*2, y, txt, len);
  896.       
  897.       sprintf(buf, "%d", highscore[i].score);
  898.       len = strlen(buf);
  899.       x   = hswidth - gwidth*2 - XTextWidth(font, buf, len);
  900.       XDrawString(dpy, scoresw, gc, x, y, buf, len);
  901.       
  902.       y += font->descent;
  903.     }
  904. }
  905.  
  906.  
  907. void drawAll()
  908. {
  909.   drawBoard();
  910.   drawHelp();
  911.   drawNext();
  912.   drawTitle();
  913.   drawScore();
  914.   drawHighScores();
  915. }
  916.  
  917.  
  918. static void doKey(xev)
  919.      XEvent *xev;
  920. {
  921.   if (XLookupString((XKeyEvent *) xev, buf, BufSize, NULL, NULL) > 0)
  922.     switch (buf[0])
  923.     {
  924.     case 'q':
  925.     case 'Q':
  926.       QuitGame();
  927.       break;
  928.  
  929.     case 'n':
  930.     case 'N':
  931.     case '\n':
  932.     case '\r':
  933.       if (nextpiece == NPieces)
  934.       {
  935.     InitGame();
  936.     drawAll();
  937.       }
  938.       break;
  939.  
  940.     case 's':
  941.     case 'S':
  942.       if (scoresvis)
  943.       {
  944.     XUnmapWindow(dpy, scoresw);
  945.     scoresvis = False;
  946.       }
  947.       else
  948.       {
  949.     XMapWindow(dpy, scoresw);
  950.     XRaiseWindow(dpy, scoresw);
  951.     scoresvis = True;
  952.       }
  953.       break;
  954.  
  955.     case 'h':
  956.     case 'H':
  957.       if (helpvis)
  958.       {
  959.     XUnmapWindow(dpy, helpw);
  960.     helpvis = False;
  961.       }
  962.       else
  963.       {
  964.     XMapWindow(dpy, helpw);
  965.     helpvis = True;
  966.       }
  967.       break;
  968.  
  969.     case 'a':
  970.     case 'A':
  971.       AutoPlay();
  972.       break;
  973.  
  974.     case '\f':
  975.       drawAll();
  976.       break;
  977.     }
  978. }
  979.  
  980.  
  981. static void doMotion(xev)
  982.      XEvent *xev;
  983. {
  984.   int    x, y;
  985.   Window dummyw;
  986.   int    row, col;
  987.   int    oldcr, oldcc;
  988.   int    redraw;
  989.   
  990.   /* motion event compression */
  991.   while (XCheckTypedEvent(dpy, MotionNotify, xev));
  992.  
  993.   /* convert to boardw coordinates */
  994.   XTranslateCoordinates(dpy, xev->xmotion.window, boardw,
  995.             xev->xmotion.x, xev->xmotion.y,
  996.             &x, &y, &dummyw);
  997.  
  998.   /* convert (x, y) to (row, col) */
  999.   row = (y - gwidth) / TileSize;
  1000.   BoundVarVal(row, 0, (BoardSize-1));
  1001.   col = (x - gwidth) / TileSize;
  1002.   BoundVarVal(col, 0, (BoardSize-1));
  1003.  
  1004.   /* check if redraw is necessary */
  1005.   oldcr  = crow;
  1006.   oldcc  = ccol;
  1007.   redraw = False;
  1008.   if (row < crow)
  1009.   {
  1010.     crow   = row;
  1011.     redraw = True;
  1012.   }
  1013.   else if ((row - 1) > crow)
  1014.   {
  1015.     crow   = row - 1;
  1016.     redraw = True;
  1017.   }
  1018.   if (col < ccol)
  1019.   {
  1020.     ccol   = col;
  1021.     redraw = True;
  1022.   }
  1023.   else if ((col - 1) > ccol)
  1024.   {
  1025.     ccol   = col - 1;
  1026.     redraw = True;
  1027.   }
  1028.  
  1029.   /* if necessary, redraw */
  1030.   if (redraw)
  1031.   {
  1032.     /* redraw tiles */
  1033.     drawTile(oldcr++, oldcc);
  1034.     drawTile(oldcr, oldcc++);
  1035.     drawTile(oldcr--, oldcc);
  1036.     drawTile(oldcr, oldcc--);
  1037.  
  1038.     /* draw controller at (crow, ccol) */
  1039.     drawController();
  1040.   }
  1041. }
  1042.  
  1043.  
  1044. static void doBoardExpose(xev)
  1045.      XEvent *xev;
  1046. {
  1047.   /* exposure event compression */
  1048.   while (XCheckTypedWindowEvent(dpy, boardw, Expose, xev));
  1049.  
  1050.   drawBoard();
  1051. }
  1052.  
  1053.  
  1054. static void doHelpExpose(xev)
  1055.      XEvent *xev;
  1056. {
  1057.   while (XCheckTypedWindowEvent(dpy, helpw, Expose, xev));
  1058.  
  1059.   drawHelp();
  1060. }
  1061.  
  1062.  
  1063. static void doNextExpose(xev)
  1064.      XEvent *xev;
  1065. {
  1066.   /* exposure event compression */
  1067.   while (XCheckTypedWindowEvent(dpy, nextw, Expose, xev));
  1068.  
  1069.   drawNext();
  1070. }
  1071.  
  1072.  
  1073. static void doMainExpose(xev)
  1074.      XEvent *xev;
  1075. {
  1076.   /* exposure event compression */
  1077.   while (XCheckTypedWindowEvent(dpy, mainw, Expose, xev));
  1078.  
  1079.   drawTitle();
  1080.   drawScore();
  1081. }
  1082.  
  1083.  
  1084. static void doHighExpose(xev)
  1085.      XEvent *xev;
  1086. {
  1087.   /* exposure event compression */
  1088.   while (XCheckTypedWindowEvent(dpy, scoresw, Expose, xev));
  1089.  
  1090.   drawHighScores();
  1091. }
  1092.  
  1093.  
  1094. static void doButtonPress(xev)
  1095.      XEvent *xev;
  1096. {
  1097.   if (helpvis)
  1098.   {
  1099.     XBell(dpy, 0);
  1100.   }
  1101.   else if ((nextpiece < NPieces) &&
  1102.        (DropPiece(crow, ccol, piece[nextpiece])))
  1103.   {
  1104.     nextpiece += 1;
  1105.     drawNext();
  1106.  
  1107.     if (nextpiece == NPieces)
  1108.       CheckHighScore();
  1109.   }
  1110. }
  1111.  
  1112.  
  1113. static Pixel GetColor(name)
  1114.      char *name;
  1115. {
  1116.   XColor xc;
  1117.   
  1118.   if (XParseColor(dpy, cmap, name, &xc) == 0)
  1119.   {
  1120.     sprintf(buf, "unable to parse color \"%s\"", name);
  1121.     fatal(buf);
  1122.   }
  1123.  
  1124.   if (XAllocColor(dpy, cmap, &xc) == 0)
  1125.     fatal("unable to alloc color");
  1126.  
  1127.   return xc.pixel;
  1128. }
  1129.  
  1130.  
  1131. static Window GetWindow(parent, x, y, w, h, b)
  1132.      Window parent;
  1133.      int    x, y;        /* position */
  1134.      int    w, h;        /* dimensions */
  1135.      int    b;            /* border width */
  1136. {
  1137.   return XCreateSimpleWindow(dpy, parent, x, y, w, h, b, brdr, back);
  1138. }
  1139.  
  1140.  
  1141. static Pixmap MakePixmap(bits, w, h, fg, bg)
  1142.      char *bits;
  1143.      int   w, h;
  1144.      Pixel fg, bg;
  1145. {
  1146.   return XCreatePixmapFromBitmapData(dpy, root, bits, w, h, fg, bg, dpth);
  1147. }
  1148.  
  1149.  
  1150. static void SetCursor(w, idx)
  1151.      Window w;
  1152.      int    idx;
  1153. {
  1154.   Cursor curs;
  1155.   XColor fg, bg;
  1156.  
  1157.   curs = XCreateFontCursor(dpy, idx);
  1158.  
  1159.   if (XParseColor(dpy, cmap, fgname, &fg) == 0)
  1160.   {
  1161.     sprintf(buf, "unable to parse color \"%s\"", fgname);
  1162.     fatal(buf);
  1163.   }
  1164.   if (XParseColor(dpy, cmap, bgname, &bg) == 0)
  1165.   {
  1166.     sprintf(buf, "unable to parse color \"%s\"", bgname);
  1167.     fatal(buf);
  1168.   }
  1169.  
  1170.   XRecolorCursor(dpy, curs, &fg, &bg);
  1171.   XDefineCursor(dpy, w, curs);
  1172. }
  1173.  
  1174.  
  1175. static void TopWindowStuff(w, name)
  1176.      Window w;
  1177.      char  *name;
  1178. {
  1179.   XWindowAttributes xwa;
  1180.   XSizeHints       *xsh;
  1181.  
  1182.   XGetWindowAttributes(dpy, w, &xwa);
  1183.   
  1184.   xsh = XAllocSizeHints();
  1185.   xsh->width       = xwa.width;
  1186.   xsh->height      = xwa.height;
  1187.   xsh->min_width   = xwa.width;
  1188.   xsh->min_height  = xwa.height;
  1189.   xsh->max_width   = xwa.width;
  1190.   xsh->max_height  = xwa.height;
  1191.   xsh->base_width  = xwa.width;
  1192.   xsh->base_height = xwa.height;
  1193.   xsh->flags       = (PSize|PMinSize|PMaxSize|PBaseSize);
  1194.  
  1195.   XSetWMNormalHints(dpy, w, xsh);
  1196.   XStoreName(dpy, w, name);
  1197.   XSetIconName(dpy, w, name);
  1198.  
  1199.   XFree((char *) xsh);
  1200. }
  1201.  
  1202.  
  1203. static void AddEventHandler(w, type, proc)
  1204.      Window w;
  1205.      int    type;
  1206.      void (*proc)();
  1207. {
  1208.   if (XSaveContext(dpy, w,
  1209.            (XContext) type,
  1210.            (caddr_t) proc) != 0)
  1211.     fatal("unable to XSaveContext");
  1212. }
  1213.  
  1214.  
  1215. static void (*GetEventHandler(xev))()
  1216.      XEvent *xev;
  1217. {
  1218.   void (*rslt)();
  1219.   
  1220.   if (XFindContext(dpy, xev->xany.window,
  1221.            (XContext) xev->xany.type,
  1222.            (caddr_t *) &rslt) != 0)
  1223.     rslt = NULL;
  1224.  
  1225.   return rslt;
  1226. }
  1227.