home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / games / volume18 / xsokoban4 / part01 / display.c next >
C/C++ Source or Header  |  1994-02-01  |  17KB  |  580 lines

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <assert.h>
  4.  
  5. #include "externs.h"
  6. #include "globals.h"
  7. #include "defaults.h"
  8. #include "help.h"
  9.  
  10. /* mnemonic defines to help orient some of the text/line drawing, sizes */
  11. #define HELPLINE ((bit_height * MAXROW) + 30)
  12. #define STATUSLINE ((bit_height * MAXROW) + 5)
  13. #define HELP_H (bit_height * MAXROW)
  14. #define HELP_W (bit_width * MAXCOL)
  15.  
  16. /* useful globals */
  17. Display *dpy;
  18. Window win;
  19. int scr;
  20. GC gc, rgc, drgc;
  21. Atom wm_delete_window, wm_protocols;
  22. XFontStruct *finfo;
  23. unsigned int width, height, depth, bit_height, bit_width;
  24. Boolean display_alloc = False, font_alloc = False, gc_alloc = False,
  25.         pix_alloc = False;
  26. Boolean optwalls;
  27. Colormap cmap;
  28. Cursor this_curs;
  29. static Pixmap help[HELP_PAGES], floor;
  30. static Pixmap blank, work, man, saveman, goal, object, treasure, walls[NUM_WALLS];
  31. int hlpscrn = -1;
  32. char buf[500];
  33.  
  34. extern char *progname;
  35. extern char map[MAXROW+1][MAXCOL+1];
  36. extern short rows, cols, level, moves, pushes, packets, savepack;
  37. extern char *bitpath;
  38.  
  39. /* names of the fancy wall bitmap files.  If you define a set of fancy
  40.  * wall bitmaps, they must use these names
  41.  */
  42. char *wallname[] = {
  43.  "lonewall.xbm", "southwall.xbm", "westwall.xbm", "llcornerwall.xbm",
  44.  "northwall.xbm", "vertiwall.xbm", "ulcornerwall.xbm", "west_twall.xbm",
  45.  "eastwall.xbm", "lrcornerwall.xbm", "horizwall.xbm", "south_twall.xbm",
  46.  "urcornerwall.xbm", "east_twall.xbm", "north_twall.xbm", "centerwall.xbm"
  47. };
  48.  
  49. /* Do all the nasty stuff like makeing the windows, setting all the defaults
  50.  * creating all the pixmaps, loading everything, and mapping the window.
  51.  * this does NOT do the XOpenDisplay() so that the -display switch can be
  52.  * handled cleanly.
  53.  */
  54. short InitX(void)
  55. {
  56.   int i;
  57.   Boolean reverse = _false_, tmpwalls = _false_;
  58.   char *rval;
  59.   unsigned long fore, back, bord, curs, gc_mask;
  60.   XSizeHints szh;
  61.   XWMHints wmh;
  62.   XSetWindowAttributes wattr;
  63.   XClassHint clh;
  64.   XGCValues val, reval;
  65.   XTextProperty wname, iname;
  66.   XColor cfg, cbg;
  67.   Atom protocols[1];
  68.  
  69.   /* these are always needed */
  70.   scr = DefaultScreen(dpy);
  71.   cmap = DefaultColormap(dpy, scr);
  72.   depth = DefaultDepth(dpy, scr);
  73.  
  74.   /* here is where we figure out the resources and set the defaults.
  75.    * resources can be either on the command line, or in your .Xdefaults/
  76.    * .Xresources files.  They are read in and parsed in main.c, but used
  77.    * here.
  78.    */
  79.   rval = GetResource(FONT);
  80.   if(rval == (char *)0)
  81.     rval = DEF_FONT;
  82.   finfo = XLoadQueryFont(dpy, rval);
  83.   if(finfo == (XFontStruct *)0)
  84.     return E_NOFONT;
  85.   font_alloc = _true_;
  86.  
  87.   rval = GetResource(REVERSE);
  88.   if(rval != (char *)0) {
  89.     reverse = StringToBoolean(rval);
  90.   }
  91.  
  92.   if(!GetColorResource(FOREG, &fore))
  93.     fore = BlackPixel(dpy, scr);
  94.  
  95.   if(!GetColorResource(BACKG, &back))
  96.     back = WhitePixel(dpy, scr);
  97.  
  98.   if(reverse) {
  99.     unsigned long t;
  100.     t = fore;
  101.     fore = back;
  102.     back = t;
  103.   }
  104.  
  105.   if(!GetColorResource(BORDER, &bord))
  106.     bord = fore;
  107.   if(!GetColorResource(CURSOR, &curs))
  108.     curs = fore;
  109.  
  110.   bitpath = GetResource(BITDIR);
  111.   rval = GetResource(WALLS);
  112.   if(rval != (char *)0)
  113.     tmpwalls = StringToBoolean(rval);
  114.  
  115.   /* walls are funny.  if a alternate bitpath has been defined, assume
  116.    * !fancywalls unless explicitly told fancy walls.  If the default 
  117.    * bitpath is being used, you can assume fancy walls.
  118.    */
  119.   if(bitpath && !tmpwalls)
  120.     optwalls = _false_;
  121.   else
  122.     optwalls = _true_;
  123.  
  124.   width = MAXCOL * DEF_BITW;
  125.   height = MAXROW * DEF_BITH + 50;
  126.  
  127.   wmh.initial_state = NormalState;
  128.   wmh.input = True;
  129.   wmh.flags = (StateHint | InputHint);
  130.  
  131.   clh.res_class = clh.res_name = progname;
  132.  
  133.   /* Make sure the window and icon names are set */
  134.   if(!XStringListToTextProperty(&progname, 1, &wname))
  135.     return E_NOMEM;
  136.   if(!XStringListToTextProperty(&progname, 1, &iname))
  137.     return E_NOMEM;
  138.  
  139.   /* load in a cursor, and recolor it so it looks pretty */
  140.   this_curs = XCreateFontCursor(dpy, DEF_CURSOR);
  141.   cfg.pixel = curs;
  142.   cbg.pixel = back;
  143.   XQueryColor(dpy, cmap, &cfg);
  144.   XQueryColor(dpy, cmap, &cbg);
  145.   XRecolorCursor(dpy, this_curs, &cfg, &cbg);
  146.  
  147.   /* set up the funky little window attributes */
  148.   wattr.background_pixel = back;
  149.   wattr.border_pixel = bord;
  150.   wattr.backing_store = Always;
  151.   wattr.event_mask = (KeyPressMask | ExposureMask | ButtonPressMask);
  152.   wattr.cursor = this_curs;
  153.  
  154.   /* whee, create the window, we create it with NO size so that we
  155.    * can load in the bitmaps, we later resize it correctly
  156.    */
  157.   win = XCreateWindow(dpy, RootWindow(dpy, scr), 0, 0, width, height, 4,
  158.               CopyFromParent, InputOutput, CopyFromParent,
  159.                       (CWBackPixel | CWBorderPixel | CWBackingStore |
  160.                        CWEventMask | CWCursor), &wattr);
  161.  
  162.   /* this will set the bit_width and bit_height as well as loading
  163.    * in the pretty little bitmaps
  164.    */
  165.   if(LoadBitmaps() == E_NOBITMAP)
  166.     return E_NOBITMAP;
  167.   blank = XCreatePixmap(dpy, win, bit_width, bit_height, 1);
  168.   pix_alloc = _true_;
  169.  
  170.   width = MAXCOL * bit_width;
  171.   height = MAXROW * bit_height + 50;
  172.   
  173.   /* whee, resize the window with the correct size now that we know it */
  174.   XResizeWindow(dpy, win, width, height);
  175.  
  176.   /* set up the size hints, we don't want manual resizing allowed. */
  177.   szh.min_width = szh.width = szh.max_width = width;
  178.   szh.min_height = szh.height = szh.max_height = height;
  179.   szh.x = szh.y = 0;
  180.   szh.flags = (PSize | PPosition | PMinSize | PMaxSize);
  181.  
  182.   /* now SET all those hints we create above */
  183.   XSetWMNormalHints(dpy, win, &szh);
  184.   XSetWMHints(dpy, win, &wmh);
  185.   XSetClassHint(dpy, win, &clh);
  186.   XSetWMName(dpy, win, &wname);
  187.   XSetWMIconName(dpy, win, &iname);
  188.  
  189.   /* Turn on WM_DELETE_WINDOW */
  190.   wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", 0);
  191.   wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", 0);
  192.   protocols[0] = wm_delete_window;
  193.   XSetWMProtocols(dpy, win, protocols, 1);
  194.  
  195.   work = XCreatePixmap(dpy, win, width, height, depth);
  196.  
  197.   /* set up all the relevant GC's */
  198.   val.foreground = reval.background = fore;
  199.   val.background = reval.foreground = back;
  200.   val.function = reval.function = GXcopy;
  201.   val.font = reval.font = finfo->fid;
  202.   gc_mask = (GCForeground | GCBackground | GCFunction | GCFont);
  203.   gc = XCreateGC(dpy, work, gc_mask, &val);
  204.   rgc = XCreateGC(dpy, blank, gc_mask, &reval);
  205.   drgc = XCreateGC(dpy, work, gc_mask, &reval);
  206.   
  207.   /* make the help windows and the working bitmaps */
  208.   /* we need to do this down here since it requires GCs to be allocated */
  209.   for(i = 0; i < HELP_PAGES; i++)
  210.     help[i] = XCreatePixmap(dpy, win, HELP_W, HELP_H, depth);
  211.   MakeHelpWindows();
  212.   XFillRectangle(dpy, blank, rgc, 0, 0, bit_width, bit_height);
  213.  
  214.   gc_alloc = _true_;
  215.  
  216.   /* display the friendly little clear screen */
  217.   ClearScreen();
  218.   XMapWindow(dpy, win);
  219.   RedisplayScreen();
  220.   
  221.   return 0;
  222. }
  223.  
  224. /* deallocate all the memory and structures used in creating stuff */
  225. void DestroyDisplay(void)
  226. {
  227.   int i;
  228.  
  229.   /* kill the font */
  230.   if(font_alloc)
  231.     XFreeFont(dpy, finfo);
  232.  
  233.   /* destroy everything allocted right around the gcs.  Help windows are
  234.    * freed here cause they are created about the same time.  (Yes, I know
  235.    * this could cause problems, it hasn't yet.
  236.    */
  237.   if(gc_alloc) {
  238.     XFreeGC(dpy, gc);
  239.     XFreeGC(dpy, rgc);
  240.     XFreeGC(dpy, drgc);
  241.     XFreePixmap(dpy, work);
  242.     for (i = 0; i < HELP_PAGES; i++)
  243.       XFreePixmap(dpy, help[i]);
  244.   }
  245.   /* free up all the allocated pix */
  246.   if(pix_alloc) {
  247.     XFreePixmap(dpy, man);
  248.     XFreePixmap(dpy, saveman);
  249.     XFreePixmap(dpy, goal);
  250.     XFreePixmap(dpy, treasure);
  251.     XFreePixmap(dpy, object);
  252.     XFreePixmap(dpy, floor);
  253.     XFreePixmap(dpy, blank);
  254.     for(i = 0; i < NUM_WALLS; i++)
  255.       if(i == 0 || optwalls)
  256.         XFreePixmap(dpy, walls[i]);
  257.   }
  258.   /* okay.. NOW we can destroy the main window and the display */
  259.   if(display_alloc) {
  260.     XDestroyWindow(dpy, win);
  261.     XCloseDisplay(dpy);
  262.   }
  263. }
  264.  
  265. /* Load in a single bitmap.  If this bitmap is the largest in the x or
  266.  * y direction, set bit_width or bit_height appropriately.  If your pixmaps
  267.  * are of varying sizes, a bit_width by bit_height box is guaranteed to be
  268.  * able to surround all of them.
  269.  */
  270. Boolean LoadOneBitmap(char *fname, char *altname, Pixmap *pix)
  271. {
  272.   unsigned int dum1, dum2;
  273.   int dum3, dum4;
  274.   Boolean load_fail = _false_;
  275.   char buf[1024];
  276.  
  277.   if(bitpath && *bitpath) {
  278.     /* we have something to try other than the default, let's do it */
  279.     sprintf(buf, "%s/%s", bitpath, fname);
  280.     if(XReadBitmapFile(dpy, win, buf, &dum1, &dum2, pix, &dum3, &dum4) !=
  281.        BitmapSuccess) {
  282.       if(altname && *altname) {
  283.         fprintf(stderr, "%s: Cannot find '%s/%s', trying alternate.\n",
  284.                 progname, bitpath, fname);
  285.         sprintf(buf, "%s/%s", bitpath, altname);
  286.         if(XReadBitmapFile(dpy, win, buf, &dum1, &dum2, pix, &dum3, &dum4) !=
  287.            BitmapSuccess) {
  288.           load_fail = _true_;
  289.           fprintf(stderr, "%s: Cannot find '%s/%s', trying defaults.\n",
  290.                   progname, bitpath, altname);
  291.         } else {
  292.       if(dum1 > bit_width) bit_width = dum1;
  293.       if(dum2 > bit_height) bit_height = dum2;
  294.           return _true_;
  295.         }
  296.       } else {
  297.         load_fail = _true_;
  298.         fprintf(stderr, "%s: Cannot find '%s/%s', trying alternate.\n",
  299.                 progname, bitpath, fname);
  300.       }
  301.     } else {
  302.       if(dum1 > bit_width) bit_width = dum1;
  303.       if(dum2 > bit_height) bit_height = dum2;
  304.       return _true_;
  305.     }
  306.   }
  307.   assert(!bitpath || !*bitpath || load_fail);
  308.   sprintf(buf, "%s/%s", BITPATH, fname);
  309.   if(XReadBitmapFile(dpy, win, buf, &dum1, &dum2, pix, &dum3, &dum4) !=
  310.      BitmapSuccess) {
  311.       if(altname && *altname) {
  312.       fprintf(stderr, "%s: Cannot find '%s', trying alternate.\n",
  313.           progname, fname);
  314.       sprintf(buf, "%s/%s", BITPATH, fname);
  315.       if(XReadBitmapFile(dpy, win, buf, &dum1, &dum2, pix, &dum3, &dum4) !=
  316.          BitmapSuccess) {
  317.           fprintf(stderr, "%s: Cannot find '%s'!\n", progname, altname);
  318.           return _false_;
  319.       } else {
  320.           if(dum1 > bit_width) bit_width = dum1;
  321.           if(dum2 > bit_height) bit_height = dum2;
  322.           return _true_;
  323.       }
  324.       } else {
  325.       fprintf(stderr, "%s: Cannot find '%s'!\n", progname, fname);
  326.       return _false_;
  327.       }
  328.   } else {
  329.       if(dum1 > bit_width) bit_width = dum1;
  330.       if(dum2 > bit_height) bit_height = dum2;
  331.       return _true_;
  332.   }
  333. }
  334.  
  335. /* loads all the bitmaps in.. if any fail, it returns E_NOBITMAP up a level
  336.  * so the program can report the error to the user.  It tries to load in the
  337.  * alternates as well.
  338.  */
  339. short LoadBitmaps(void)
  340. {
  341.   register int i;
  342.  
  343.   if(!LoadOneBitmap("man.xbm", NULL, &man)) return E_NOBITMAP;
  344.   if(!LoadOneBitmap("saveman.xbm", "man.xbm", &saveman)) return E_NOBITMAP;
  345.   if(!LoadOneBitmap("object.xbm", NULL, &object)) return E_NOBITMAP;
  346.   if(!LoadOneBitmap("treasure.xbm", NULL, &treasure)) return E_NOBITMAP;
  347.   if(!LoadOneBitmap("goal.xbm", NULL, &goal)) return E_NOBITMAP;
  348.   if(!LoadOneBitmap("floor.xbm", NULL, &floor)) return E_NOBITMAP;
  349.  
  350.   if(optwalls) {
  351.     for(i = 0; i < NUM_WALLS; i++) {
  352.       if(!LoadOneBitmap(wallname[i], "wall.xbm", &walls[i])) return E_NOBITMAP;
  353.     }
  354.   } else {
  355.     if(!LoadOneBitmap("wall.xbm", NULL, &walls[0])) return E_NOBITMAP;
  356.   }
  357.   return 0;
  358. }
  359.  
  360. /* create and draw all the help windows in.  This is not wholly fullproff with
  361.  * the variable size bitmap code yet, as the constants to place things on the
  362.  * screen, are just that, constants.  This could most likley be reworked.
  363.  */
  364. void MakeHelpWindows(void)
  365. {
  366.   register int i;
  367.   char *title =
  368.     "    Sokoban  --  X version by Joseph L. Traub  --  Help page %d";
  369.   char *next =
  370.      "     Press Enter to exit  --   Any other key for next page.";
  371.  
  372.   for(i = 0; i < HELP_PAGES; i++) {
  373.     XFillRectangle(dpy, help[i], drgc, 0, 0, HELP_W, HELP_H);
  374.     sprintf(buf, title, (i+1));
  375.     XDrawImageString(dpy, help[i], gc, 0, 11, buf, strlen(buf));
  376.     XDrawLine(dpy, help[i], gc, 0, 17, HELP_W, 17);
  377.     XDrawLine(dpy, help[i], gc, 0, HELP_H-20, HELP_W, HELP_H-20);
  378.     XDrawImageString(dpy, help[i], gc, 2, HELP_H-7, next, strlen(next));
  379.   }
  380.   for(i = 0; help_pages[i].textline != NULL; i++) {
  381.     XDrawImageString(dpy,help[help_pages[i].page], gc,
  382.                      help_pages[i].xpos * (finfo->max_bounds.width),
  383.                      help_pages[i].ypos, help_pages[i].textline,
  384.                      strlen(help_pages[i].textline));
  385.   }
  386.   XCopyPlane(dpy, man, help[0], gc, 0, 0, bit_width, bit_height, 180, 360, 1);
  387.   XCopyPlane(dpy, goal, help[0], gc, 0, 0, bit_width, bit_height, 270, 360, 1);
  388.   XCopyPlane(dpy, walls[0], help[0], gc, 0, 0, bit_width, bit_height,
  389.          369, 360, 1);
  390.   XCopyPlane(dpy, object, help[0], gc, 0, 0, bit_width, bit_height,
  391.          477, 360, 1);
  392.   XCopyPlane(dpy, treasure, help[0], gc, 0, 0, bit_width, bit_height,
  393.          270, 400, 1);
  394.   XCopyPlane(dpy, saveman, help[0], gc, 0, 0, bit_width, bit_height,
  395.          477, 400, 1);
  396. }
  397.  
  398. /* wipe out the entire contents of the screen */
  399. void ClearScreen(void)
  400. {
  401.   register int i,j;
  402.  
  403.   XFillRectangle(dpy, work, drgc, 0, 0, width, height);
  404.   for(i = 0; i < MAXROW; i++)
  405.     for(j = 0; j < MAXCOL; j++)
  406.       XCopyPlane(dpy, floor, work, gc, 0, 0, bit_width, bit_height,
  407.                  j*bit_width, i*bit_height, 1);
  408.   XDrawLine(dpy, work, gc, 0, bit_height*MAXROW, bit_width*MAXCOL,
  409.             bit_height*MAXROW);
  410. }
  411.  
  412. /* redisplay the current screen.. Has to handle the help screens if one
  413.  * is currently active..  Copys the correct bitmaps onto the window.
  414.  */
  415. void RedisplayScreen(void)
  416. {
  417.   if(hlpscrn == -1)
  418.     XCopyArea(dpy, work, win, gc, 0, 0, width, height, 0, 0);
  419.   else
  420.     XCopyArea(dpy, help[hlpscrn], win, gc, 0, 0, HELP_W, HELP_H, 0, 0);
  421.   XFlush(dpy);
  422. }
  423.  
  424. /* Flush all X events to the screen and wait for them to get there. */
  425. void SyncScreen(void)
  426. {
  427.   XSync(dpy, 0);
  428. }
  429.  
  430. /* Draws all the neat little pictures and text onto the working pixmap
  431.  * so that RedisplayScreen is happy.
  432.  */
  433. void ShowScreen(void)
  434. {
  435.   register int i,j;
  436.  
  437.   for(i = 0; i < rows; i++)
  438.     for(j = 0; j < cols && map[i][j] != 0; j++)
  439.       MapChar(map[i][j], i, j, 0);
  440.   DisplayLevel();
  441.   DisplayPackets();
  442.   DisplaySave();
  443.   DisplayMoves();
  444.   DisplayPushes();
  445.   DisplayHelp();
  446.   RedisplayScreen();
  447. }
  448.  
  449. /* Draws a single pixmap, translating from the character map to the pixmap
  450.  * rendition. If "copy_area", also push the change through to the actual window.
  451.  */
  452. void MapChar(char c, int i, int j, Boolean copy_area)
  453. {
  454.   Pixmap this;
  455.  
  456.   this = GetObjectPixmap(i, j, c); /* i, j are passed so walls can be done */
  457.   XCopyPlane(dpy, this, work, gc, 0, 0, bit_width, bit_height, cX(j), cY(i), 1);
  458.   if (copy_area) {
  459.     XCopyArea(dpy, work, win, gc, cX(j), cY(i), bit_width, bit_height,
  460.           cX(j), cY(i));
  461.   }
  462. }
  463.  
  464. /* figures out the appropriate pixmap from the internal game representation.
  465.  * Handles fancy walls.
  466.  */
  467. Pixmap GetObjectPixmap(int i, int j, char c)
  468. {
  469.   switch(c) {
  470.     case player: return man;
  471.     case playerstore: return saveman;
  472.     case store: return goal;
  473.     case save: return treasure;
  474.     case packet: return object;
  475.     case wall:
  476.        if(optwalls) return walls[PickWall(i,j)];
  477.        else return walls[0];
  478.     case ground: return floor;
  479.     default: return blank;
  480.   }
  481. }
  482.  
  483. /* returns and index into the fancy walls array. works by assigning a value
  484.  * to each 'position'.. the type of fancy wall is computed based on how
  485.  * many neighboring walls there are.
  486.  */
  487. int PickWall(int i, int j)
  488. {
  489.   int ret = 0;
  490.  
  491.   if(i > 0 && map[i-1][j] == wall) ret += 1;
  492.   if(j < cols && map[i][j+1] == wall) ret += 2;
  493.   if(i < rows && map[i+1][j] == wall) ret += 4;
  494.   if(j > 0 && map[i][j-1] == wall) ret += 8;
  495.   return ret;
  496. }
  497.  
  498. /* Draws a string onto the working pixmap */
  499. void DrawString(int x, int y, char *text)
  500. {
  501.   int x_off, y_off;
  502.  
  503.   x_off = x * finfo->max_bounds.width;
  504.   y_off = y + finfo->ascent;
  505.  
  506.   XDrawImageString(dpy, work, gc, x_off, y_off, text, strlen(text));
  507. }
  508.  
  509. /* The following routines display various 'statusline' stuff (ie moves, pushes,
  510.  * etc) on the screen.  they are called as they are needed to be changed to
  511.  * avoid unnecessary drawing */
  512. void DisplayLevel(void)
  513. {
  514.    sprintf(buf, "Level: %3d", level);
  515.    DrawString(0, STATUSLINE, buf);
  516. }
  517.  
  518. void DisplayPackets(void)
  519. {
  520.    sprintf(buf, "Packets: %3d", packets);
  521.    DrawString(12, STATUSLINE, buf);
  522. }
  523.  
  524. void DisplaySave(void)
  525. {
  526.   sprintf(buf, "Saved: %3d", savepack);
  527.   DrawString(26, STATUSLINE, buf);
  528. }
  529.  
  530. void DisplayMoves(void)
  531. {
  532.   sprintf(buf, "Moves: %5d", moves);
  533.   DrawString(38, STATUSLINE, buf);
  534. }
  535.  
  536. void DisplayPushes(void)
  537. {
  538.   sprintf(buf, "Pushes: %3d", pushes);
  539.   DrawString(52, STATUSLINE, buf);
  540. }
  541.  
  542. void DisplayHelp(void)
  543. {
  544.   DrawString(0, HELPLINE, "Press ? for help.");
  545. }
  546.  
  547. /* Displays the first help page, and flips help pages (one per key press)
  548.  * until a return is pressed.
  549.  */
  550. void ShowHelp(void)
  551. {
  552.   int i = 0;
  553.   Boolean done = _false_;
  554.  
  555.   hlpscrn = 0;
  556.   XCopyArea(dpy, help[i], win, gc, 0, 0, HELP_W, HELP_H, 0, 0);
  557.   XFlush(dpy);
  558.   while(!done) {
  559.     done = WaitForEnter();
  560.     if(done) {
  561.       hlpscrn = -1;
  562.       return;
  563.     } else {
  564.       i = (i+1)%HELP_PAGES;
  565.       hlpscrn = i;
  566.       XCopyArea(dpy, help[i], win, gc, 0, 0, HELP_W, HELP_H, 0, 0);
  567.       XFlush(dpy);
  568.     }
  569.   }
  570. }
  571.  
  572. /* since the 'press ? for help' is ALWAYS displayed, just beep when there is
  573.  * a problem.
  574.  */
  575. void HelpMessage(void)
  576. {
  577.   XBell(dpy, 0);
  578.   RedisplayScreen();
  579. }
  580.