home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / go / prog / xigcv2_8.taz / xigcv2_8 / Goban.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-08  |  45.3 KB  |  1,476 lines

  1. /* Goban.c
  2.  * S.Coffin     USWAT   7/92
  3.  *
  4.  * adapted from the below
  5.  */
  6.  
  7. /****************************************************************************************************************
  8.  *
  9.  *  Copyright (c) 1992 by Antoine Dumesnil de Maricourt. All rights reserved.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful.
  12.  *  Use and copying of this software and preparation of derivative works
  13.  *  based upon this software are permitted, so long as the following
  14.  *  conditions are met:
  15.  *       o credit to the authors is acknowledged following current
  16.  *         academic behaviour
  17.  *       o no fees or compensation are charged for use, copies, or
  18.  *         access to this software
  19.  *       o this copyright notice is included intact.
  20.  *  This software is made available AS IS, and no warranty is made about 
  21.  *  the software or its performance. 
  22.  * 
  23.  *  Bug descriptions, use reports, comments or suggestions are welcome.
  24.  *  Send them to    dumesnil@etca.fr   or to:
  25.  *       
  26.  *       Antoine de Maricourt
  27.  *       ETCA CREA-SP
  28.  *       16 bis, avenue Prieur de la Cote d'Or
  29.  *       94114 Arcueil Cedex
  30.  *       France
  31.  */
  32.  
  33. #include <X11/IntrinsicP.h>
  34. #include <X11/StringDefs.h>
  35. #include <X11/Xlib.h>
  36. #include <X11/cursorfont.h>
  37.  
  38. #include "GobanP.h"
  39.  
  40. #include "whitestone.bm"
  41. #include "blackstone.bm"
  42. #include "stonemask.bm"
  43. #include "stipple.bm"
  44. #include <stdio.h>
  45.  
  46. #define offset(field) XtOffset (GobanWidget, goban.field)
  47. static Position lastx = (-1), lasty;
  48. static GbPointState lastcolor;
  49. extern unsigned char stippleflag;
  50. static unsigned char localstipple;
  51.  
  52. static XtResource resources[] = {
  53.   { XtNautoRedisplay,
  54.     XtCAutoRedisplay,
  55.     XtRBoolean,
  56.     sizeof (Boolean),
  57.     offset (auto_redisplay),
  58.     XtRImmediate,
  59.     (caddr_t) TRUE },
  60.   { XtNviewBottom,
  61.     XtCPosition,
  62.     XtRPosition,
  63.     sizeof (Position),
  64.     offset (bottom),
  65.     XtRImmediate,
  66.     (caddr_t) 1 },
  67.   { XtNcursor,
  68.     XtCCursor,
  69.     XtRInt,
  70.     sizeof (int),
  71.     offset (cursor),
  72.     XtRImmediate,
  73.     (caddr_t) GbCBlackStone },
  74.   { XtNfont,
  75.     XtCFont,
  76.     XtRFontStruct,
  77.     sizeof (XFontStruct *),
  78.     offset (font),
  79.     XtRString,
  80.     "fixed" },
  81.   { XtNforeground,
  82.     XtCForeground,
  83.     XtRPixel,
  84.     sizeof (Pixel),
  85.     offset (foreground),
  86.     XtRString,
  87.     XtDefaultForeground },
  88.   { XtNgameSize,
  89.     XtCSize,
  90.     XtRDimension,
  91.     sizeof (Dimension),
  92.     offset (game_size),
  93.     XtRImmediate,
  94.     (caddr_t) 19 },
  95.   { XtNviewLeft,
  96.     XtCPosition,
  97.     XtRPosition,
  98.     sizeof (Position),
  99.     offset (left),
  100.     XtRImmediate,
  101.     (caddr_t) 1 },
  102.   { XtNdisplayCoordinates,
  103.     XtCDisplayCoordinates,
  104.     XtRBoolean,
  105.     sizeof (Boolean),
  106.     offset (display_coordinates),
  107.     XtRImmediate,
  108.     (caddr_t) TRUE },
  109.   { XtNpointSize,
  110.     XtCSize,
  111.     XtRDimension,
  112.     sizeof (Dimension),
  113.     offset (point_size),
  114.     XtRImmediate,
  115.     (caddr_t) 26 },
  116.   { XtNstipple,
  117.     XtCSize,
  118.     XtRBoolean,
  119.     sizeof (Boolean),
  120.     offset (stipple),
  121.     XtRImmediate,
  122.     (caddr_t) FALSE },
  123.   { XtNviewRight,
  124.     XtCPosition,
  125.     XtRPosition,
  126.     sizeof (Position),
  127.     offset (right),
  128.     XtRImmediate,
  129.     (caddr_t) 19 },
  130.   { XtNviewTop,
  131.     XtCPosition,
  132.     XtRPosition,
  133.     sizeof (Position), 
  134.     offset (top),
  135.     XtRImmediate,
  136.     (caddr_t) 19 },
  137.   { XtNwhiteStoneForeground,
  138.     XtCForeground,
  139.     XtRPixel,
  140.     sizeof (Pixel),
  141.     offset (white_fg),
  142.     XtRString,
  143.     "black" },
  144.   { XtNwhiteStoneBackground,
  145.     XtCBackground,
  146.     XtRPixel,
  147.     sizeof (Pixel),
  148.     offset (white_bg),
  149.     XtRString,
  150.     "white" },
  151.   { XtNwhiteStoneBorder,
  152.     XtCBorderColor,
  153.     XtRPixel,
  154.     sizeof (Pixel),
  155.     offset (white_bd),
  156.     XtRString,
  157.     "black" },
  158.   { XtNblackStoneForeground,
  159.     XtCForeground,
  160.     XtRPixel,
  161.     sizeof (Pixel),
  162.     offset (black_fg),
  163.     XtRString,
  164.     "white" },
  165.   { XtNblackStoneBackground,
  166.     XtCBackground,
  167.     XtRPixel,
  168.     sizeof (Pixel),
  169.     offset (black_bg),
  170.     XtRString,
  171.     "black" },
  172.   { XtNblackStoneBorder,
  173.     XtCBorderColor,
  174.     XtRPixel,
  175.     sizeof (Pixel),
  176.     offset (black_bd),
  177.     XtRString,
  178.     "black" },
  179. };
  180.  
  181. static void    ClassInitialize ();
  182. static void    Initialize      ();
  183. static void    Redisplay       ();
  184. static void    Realize         ();
  185. static void    Destroy         ();
  186. static void    Resize          ();
  187. static void    DrawPoint       ();
  188. static Boolean SetValues       ();
  189.  
  190. GobanClassRec gobanClassRec = {
  191.   { /* core fields */
  192.     /* superclass        */    (WidgetClass) &widgetClassRec,
  193.     /* class_name        */    "Goban",
  194.     /* widget_size        */    sizeof (GobanRec),
  195.     /* class_initialize        */    ClassInitialize,
  196.     /* class_part_initialize    */    NULL,
  197.     /* class_inited        */    FALSE,
  198.     /* initialize        */    Initialize,
  199.     /* initialize_hook        */    NULL,
  200.     /* realize            */    Realize,
  201.     /* actions            */    NULL,
  202.     /* num_actions        */    0,
  203.     /* resources        */    resources,
  204.     /* num_resources        */    XtNumber (resources),
  205.     /* xrm_class        */    NULLQUARK,
  206.     /* compress_motion        */    TRUE,
  207.     /* compress_exposure    */    TRUE,
  208.     /* compress_enterleave    */    TRUE,
  209.     /* visible_interest        */    FALSE,
  210.     /* destroy            */    Destroy,
  211.     /* resize            */    Resize,
  212.     /* expose            */    Redisplay,
  213.     /* set_values        */    SetValues,
  214.     /* set_values_hook        */    NULL,
  215.     /* set_values_almost    */    XtInheritSetValuesAlmost,
  216.     /* get_values_hook        */    NULL,
  217.     /* accept_focus        */    NULL,
  218.     /* version            */    XtVersion,
  219.     /* callback_private        */    NULL,
  220.     /* tm_table            */    NULL,
  221.     /* query_geometry        */    XtInheritQueryGeometry,
  222.     /* display_accelerator    */    XtInheritDisplayAccelerator,
  223.     /* extension        */    NULL
  224.   }
  225. };
  226.  
  227. WidgetClass gobanWidgetClass = (WidgetClass) &gobanClassRec;
  228.  
  229. /****************************************************************************************************************
  230.  */
  231.  
  232. void GbRedisplayBoard (w)
  233. Widget w;
  234. {
  235.   GobanWidget gw      = (GobanWidget) w;
  236.   Dimension   width   = w->core.width;
  237.   Dimension   height  = w->core.height;
  238.  
  239.   if (XtIsRealized (w))
  240.     XCopyArea (XtDisplay (w), gw->goban.picture, XtWindow (w), gw->goban.copy_gc, 0, 0, width, height, 0, 0);
  241. }
  242.  
  243. /****************************************************************************************************************
  244.  */
  245.  
  246. void GbClearBoard (w)
  247. Widget w;
  248. {
  249.   GobanWidget gw        = (GobanWidget) w;
  250.   Boolean     redisplay = gw->goban.auto_redisplay;
  251.   Position    x;
  252.   Position    y;
  253.  
  254.   gw->goban.auto_redisplay = FALSE;
  255.  
  256.   for (x = 1; x <= (Position)gw->goban.game_size; x++)
  257.     for (y = 1; y <= (Position)gw->goban.game_size; y++)
  258.       GbSetPoint( w, x, y, GbEmptyPoint, TRUE );
  259.  
  260.   gw->goban.auto_redisplay = redisplay;
  261.  
  262.   if( redisplay == TRUE ) GbRedisplayBoard( w );
  263. }
  264.  
  265. /****************************************************************************************************************
  266.  */
  267.  
  268. void GbClearMarks (w)
  269. Widget w;
  270. {
  271.   GobanWidget gw        = (GobanWidget) w;
  272.   Boolean     redisplay = gw->goban.auto_redisplay;
  273.   Position    x;
  274.   Position    y;
  275.  
  276.   gw->goban.auto_redisplay = FALSE;
  277.  
  278.   for (x = 1; x <= (Position)gw->goban.game_size; x++)
  279.     for (y = 1; y <= (Position)gw->goban.game_size; y++) {
  280.  
  281.       gw->goban.points[x][y].mark1 = 0;
  282.       gw->goban.points[x][y].mark2 = 0;
  283.       gw->goban.points[x][y].num   = 0;
  284.     
  285.       if (x >= gw->goban.left && y >= gw->goban.bottom && x <= gw->goban.right && y <= gw->goban.top)
  286.     if (gw->goban.points[x][y].free == 1)
  287.       DrawPoint (w, x, y, GbEmptyPoint, FALSE);
  288.     else
  289.       if (gw->goban.points[x][y].black == 1)
  290.         DrawPoint (w, x, y, GbBlackStone, FALSE);
  291.       else
  292.         DrawPoint (w, x, y, GbWhiteStone, FALSE);
  293.     }
  294.  
  295.   gw->goban.auto_redisplay = redisplay;
  296.  
  297.   if (redisplay == TRUE)
  298.     GbRedisplayBoard (w);
  299. }
  300.  
  301. /****************************************************************************************************************
  302.  */
  303.  
  304. /* ARGSUSED */
  305.  
  306. void GbSetPoint( w, x, y, color, flag )
  307. Widget       w;
  308. Position     x;
  309. Position     y;
  310. GbPointState color;
  311. unsigned char flag;
  312. {
  313.   GobanWidget gw = (GobanWidget) w;
  314.  
  315.   if (x >= 1 && y >= 1 && x <= (Position)gw->goban.game_size &&
  316.         y <= (Position)gw->goban.game_size) {
  317.     switch (color) {
  318.  
  319.     case GbBlackStone :
  320.       gw->goban.points[x][y].free  = 0;
  321.       gw->goban.points[x][y].black = 1;
  322.       break;
  323.  
  324.     case GbWhiteStone :
  325.       gw->goban.points[x][y].free  = 0;
  326.       gw->goban.points[x][y].black = 0;
  327.       break;
  328.  
  329.     case GbEmptyPoint :
  330.       gw->goban.points[x][y].free  = 1;
  331.       break;
  332.     }
  333.     
  334.     gw->goban.points[x][y].num   = 0;
  335.     gw->goban.points[x][y].mark1 = 0;
  336.     gw->goban.points[x][y].mark2 = 0;
  337.  
  338.     if( x >= gw->goban.left && y >= gw->goban.bottom &&
  339.     x <= gw->goban.right && y <= gw->goban.top ) {
  340.       if( lastx >= 0 ) DrawPoint( w, lastx, lasty, lastcolor, FALSE );
  341.       DrawPoint( w, x, y, color, flag );
  342.       lastx = x;
  343.       lasty = y;
  344.       lastcolor = color;
  345.     }
  346.   }
  347. }
  348.  
  349. /****************************************************************************************************************
  350.  */
  351.  
  352. /* ARGSUSED */
  353.  
  354. Boolean GbGetPositionFromStone (w, x, y)
  355. GobanWidget   w;
  356. Position     *x;
  357. Position     *y;
  358. {
  359.   if (*x >= w->goban.left && *y >= w->goban.bottom && *x <= w->goban.right && *y <= w->goban.top) {
  360.     
  361.     *x = (Position)((w->goban.x_offset + w->goban.point_size * *x) * (Position)2 + w->goban.point_size) / (Position)2;
  362.     *y = (Position)((w->goban.y_offset - w->goban.point_size * *y) * (Position)2 + w->goban.point_size) / (Position)2;
  363.     
  364.     return TRUE;
  365.   }
  366.   
  367.   else 
  368.     return FALSE;
  369. }
  370.  
  371. /****************************************************************************************************************
  372.  */
  373.  
  374. /* ARGSUSED */
  375.  
  376. Boolean GbGetStoneFromPosition (w, x, y)
  377. Widget     w;
  378. Position  *x;
  379. Position  *y;
  380. {
  381.   GobanWidget gw         = (GobanWidget) w;
  382.   Dimension   point_size = gw->goban.point_size;
  383.   Position    xmin       = gw->goban.x_offset + point_size * gw->goban.left + 1;
  384.   Position    ymin       = gw->goban.y_offset - point_size * gw->goban.top  + 1;
  385.   Position    xmax       = gw->goban.x_offset + point_size * (gw->goban.right  + 1) - 1;
  386.   Position    ymax       = gw->goban.y_offset - point_size * (gw->goban.bottom - 1) - 1;
  387.  
  388.   if (*x > xmin && *x < xmax && *y > ymin && *y < ymax) {
  389.  
  390.     *x = (Position)(*x - gw->goban.x_offset - 1) / (Position)point_size;
  391.     *y = (Position)(gw->goban.y_offset - *y + point_size + 1) / (Position)point_size;
  392.  
  393.     return TRUE;
  394.   }
  395.  
  396.   return FALSE;
  397. }
  398.  
  399. /****************************************************************************************************************
  400.  */
  401.  
  402. void GbSetNum (w, x, y, num)
  403. Widget      w;
  404. Position    x;
  405. Position    y;
  406. int         num;
  407. {
  408.   GobanWidget  gw      = (GobanWidget) w;
  409.   Display     *display = XtDisplay (w);
  410.   GC           draw_gc;
  411.   GC           undraw_gc;
  412.   XCharStruct  extent;
  413.   XExposeEvent event;
  414.   int          ascent;
  415.   int          descent;
  416.   int          direction;
  417.   int          X;
  418.   int          Y;
  419.   unsigned char         s[3];
  420.   int          len = 0;
  421.  
  422.   if (num >= 0 && num <= 999 && (int)x >= 1 && (int)y >= 1  && (int)x <= (int)gw->goban.game_size && (int)y <= (int)gw->goban.game_size) {
  423.     
  424.     gw->goban.points[x][y].num   = num;
  425.     gw->goban.points[x][y].mark1 = 0;
  426.     gw->goban.points[x][y].mark2 = 0;
  427.     
  428.     if (x >= gw->goban.left && y >= gw->goban.bottom && x <= gw->goban.right && y <= gw->goban.top) {
  429.       
  430.       if (gw->goban.points[x][y].free == 0) {
  431.     
  432.     if (num == 0) {
  433.       if (gw->goban.points[x][y].black == 1)
  434.         DrawPoint (w, x, y, GbBlackStone, FALSE);
  435.       else
  436.         DrawPoint (w, x, y, GbWhiteStone, FALSE);
  437.     }
  438.     
  439.     else {
  440.       if (gw->goban.points[x][y].black == 1) {
  441.         draw_gc   = gw->goban.black_fg_gc;
  442.         undraw_gc = gw->goban.black_bg_gc;
  443.       } else {
  444.         draw_gc   = gw->goban.white_fg_gc;
  445.         undraw_gc = gw->goban.white_bg_gc;
  446.       }
  447.       
  448.       X = (gw->goban.x_offset + gw->goban.point_size * x) * 2 + gw->goban.point_size;
  449.       Y = (gw->goban.y_offset - gw->goban.point_size * y) * 2 + gw->goban.point_size;
  450.       
  451.       if (num > 99)
  452.         s[len++] = '0' + (num % 1000) / 100;
  453.       if (num > 9)
  454.         s[len++] = '0' + (num % 100) / 10;
  455.       s[len++] = '0' + num % 10;
  456.       
  457.       XQueryTextExtents (display, XGContextFromGC (draw_gc),
  458.                  (char *)s, len, &direction, &ascent, &descent, &extent);
  459.       
  460.       if (extent.width + extent.descent + extent.ascent < (int)gw->goban.point_size - 1) {
  461.         XFillArc (display, gw->goban.picture, undraw_gc, 
  462.               (int) (X - gw->goban.point_size) / 2 + 2, (int) (Y - gw->goban.point_size) / 2 + 2, 
  463.               (unsigned int) gw->goban.point_size - 4, (unsigned int) gw->goban.point_size - 4, 
  464.               0, 360 * 64);
  465.         XDrawString (display, gw->goban.picture, draw_gc,
  466.              (X - extent.width) / 2 - extent.lbearing + 1, 
  467.              (Y + extent.ascent - extent.descent) / 2 + 1,
  468.              (char *)s, len);
  469.       }
  470.     
  471.       if (gw->goban.auto_redisplay == TRUE && XtIsRealized (w) == TRUE) {
  472.         event.x      = (int)(X - gw->goban.point_size) / 2;
  473.         event.y      = (int)(Y - gw->goban.point_size) / 2;
  474.         event.width  = gw->goban.point_size;
  475.         event.height = gw->goban.point_size;
  476.         
  477.         Redisplay (w, &event, (Region) NULL);
  478.       }
  479.     }
  480.       }
  481.     }
  482.   }
  483. }
  484.  
  485. /****************************************************************************************************************
  486.  */
  487.  
  488. void GbSetMark( w, x, y, c1, c2 )
  489.     Widget        w;
  490.     Position      x;
  491.     Position      y;
  492.     unsigned char c1;
  493.     unsigned char c2;
  494. {
  495.   GobanWidget  gw      = (GobanWidget) w;
  496.   Display     *display = XtDisplay (w);
  497.   int          len     = 0;
  498.   XCharStruct  extent;
  499.   XExposeEvent event;
  500.   int          ascent;
  501.   int          descent;
  502.   int          direction;
  503.   int          X;
  504.   int          Y;
  505.   int          radius;
  506.   unsigned char         s[2];
  507.   XSegment     segment[4];
  508.   GC           mark_gc;
  509.   GC           erase_gc;
  510.  
  511.   if( (int)x >= 1 &&
  512.       (int)y >= 1 &&
  513.       (int)x <= (int)gw->goban.game_size &&
  514.       (int)y <= (int)gw->goban.game_size) {
  515.    
  516.     if( c1 != 0 || c2 != 0 ) GbSetMark( w, x, y, 0, 0 );
  517.      
  518.     gw->goban.points[x][y].mark1 = c1;
  519.     gw->goban.points[x][y].mark2 = c2;
  520.     gw->goban.points[x][y].num   = 0;
  521.  
  522.     if( x >= gw->goban.left && y >= gw->goban.bottom &&
  523.     x <= gw->goban.right && y <= gw->goban.top) {
  524.       
  525.       if (c1 == 0 && c2 == 0) {
  526.     if (gw->goban.points[x][y].free == 0)
  527.       if (gw->goban.points[x][y].black == 1)
  528.         DrawPoint( w, x, y, GbBlackStone, FALSE );
  529.       else
  530.         DrawPoint( w, x, y, GbWhiteStone, FALSE );
  531.     else
  532.       DrawPoint( w, x, y, GbEmptyPoint, FALSE );
  533.       }
  534.       
  535.       else {
  536.     X = (gw->goban.x_offset + gw->goban.point_size * x) * 2 +
  537.             gw->goban.point_size;
  538.     Y = (gw->goban.y_offset - gw->goban.point_size * y) * 2 +
  539.             gw->goban.point_size;
  540.               
  541.     if (gw->goban.points[x][y].free == 0)
  542.       if (gw->goban.points[x][y].black == 1) {
  543.         mark_gc  = gw->goban.black_fg_gc;
  544.         erase_gc = gw->goban.black_bg_gc;
  545.       }
  546.       else {
  547.         mark_gc  = gw->goban.white_fg_gc;
  548.         erase_gc = gw->goban.white_bg_gc;
  549.       }
  550.  
  551.     else {
  552.       mark_gc  = gw->goban.foreground_gc;
  553.       erase_gc = gw->goban.background_gc;
  554.     }
  555.     
  556.     if (c1 == 0) {
  557.       radius = 10 * (int)gw->goban.point_size / 15;
  558.       
  559.       if (gw->goban.points[x][y].free == 0)
  560.           XFillArc (display, gw->goban.picture, erase_gc, 
  561.             (int) (X - gw->goban.point_size) / 2 + 2,
  562.             (int) (Y - gw->goban.point_size) / 2 + 2, 
  563.             (unsigned int) gw->goban.point_size - 4,
  564.             (unsigned int) gw->goban.point_size - 4, 
  565.             0, 360 * 64);
  566.       else
  567.         XFillArc (display, gw->goban.picture, erase_gc,
  568.               (int) (X - radius) / 2, (int) (Y - radius) / 2, 
  569.               (unsigned int) radius, (unsigned int) radius, 
  570.               0, 360 * 64);
  571.  
  572.       switch( c2 ) {
  573.         
  574.       case GbMTriangleMark :
  575.         radius -= 4;
  576.  
  577.         segment[0].x1 = (short) X / 2;
  578.         segment[0].x2 = (short) (X / 2 + (86 * radius + 100) / 200);
  579.         segment[0].y1 = (short) (Y / 2 - (radius - 1) / 2);
  580.         segment[0].y2 = (short) (Y / 2 + (radius + 4) / 4);
  581.         
  582.         segment[1].x1 = (short) segment[0].x2;
  583.         segment[1].x2 = (short) (X / 2 - (86 * radius + 100) / 200);
  584.         segment[1].y1 = (short) segment[0].y2;
  585.         segment[1].y2 = (short) (Y / 2 + (radius + 4) / 4);
  586.         
  587.         segment[2].x1 = (short) segment[1].x2;
  588.         segment[2].x2 = (short) segment[0].x1;
  589.         segment[2].y1 = (short) segment[1].y2;
  590.         segment[2].y2 = (short) segment[0].y1;
  591.  
  592.         XDrawSegments (display, gw->goban.picture, mark_gc, segment, 3);
  593.         break;
  594.  
  595.       case GbMSquareMark  :
  596.         radius = 10 * radius / 14 - 2;
  597.         
  598.         XDrawRectangle (display, gw->goban.picture, mark_gc, 
  599.                 (X - radius) / 2, (Y - radius) / 2, 
  600.                 (unsigned int) radius, (unsigned int) radius);
  601.         break;
  602.     
  603.       case GbMDCrossMark  :
  604.         radius = 10 * radius / 14 - 2;
  605.  
  606.         segment[0].x1 = (short) (X - radius) / 2;
  607.         segment[0].x2 = (short) segment[0].x1    + radius;
  608.         segment[0].y1 = (short) (Y - radius) / 2;
  609.         segment[0].y2 = (short) segment[0].y1    + radius;
  610.  
  611.         segment[1].x1 = (short) (X - radius) / 2 + radius;
  612.         segment[1].x2 = (short) segment[1].x1    - radius;
  613.         segment[1].y1 = (short) (Y - radius) / 2;
  614.         segment[1].y2 = (short) segment[1].y1    + radius;
  615.         
  616.         XDrawSegments (display, gw->goban.picture, mark_gc, segment, 2);
  617.         break;
  618.         
  619.       case GbMVCrossMark  :
  620.         radius -= 4;
  621.  
  622.         segment[0].x1 = (short) X / 2;
  623.         segment[0].x2 = (short) segment[0].x1;
  624.         segment[0].y1 = (short) (Y - radius) / 2;
  625.         segment[0].y2 = (short) segment[0].y1 + radius;
  626.  
  627.         segment[1].x1 = (short) (X - radius) / 2;
  628.         segment[1].x2 = (short) segment[1].x1 + radius;
  629.         segment[1].y1 = (short) Y / 2;
  630.         segment[1].y2 = (short) segment[1].y1;
  631.         
  632.         XDrawSegments (display, gw->goban.picture, mark_gc, segment, 2);
  633.         break;
  634.  
  635.       case GbMDiamondMark :
  636.         radius -= 4;
  637.  
  638.         segment[0].x1 = (short) X / 2;
  639.         segment[0].x2 = (short) segment[0].x1 + radius / 2;
  640.         segment[0].y1 = (short) (Y - radius) / 2;
  641.         segment[0].y2 = (short) segment[0].y1 + radius / 2;
  642.  
  643.         segment[1].x1 = (short) segment[0].x2;
  644.         segment[1].x2 = (short) segment[0].x1;
  645.         segment[1].y1 = (short) segment[0].y2;
  646.         segment[1].y2 = (short) segment[1].y1 + radius / 2;
  647.         
  648.         segment[2].x1 = (short) segment[1].x2;
  649.         segment[2].x2 = (short) segment[2].x1 - radius / 2;
  650.         segment[2].y1 = (short) segment[1].y2;
  651.         segment[2].y2 = (short) segment[1].y1;
  652.         
  653.         segment[3].x1 = (short) segment[2].x2;
  654.         segment[3].x2 = (short) segment[0].x1;
  655.         segment[3].y1 = (short) segment[2].y2;
  656.         segment[3].y2 = (short) segment[0].y1;
  657.         
  658.         XDrawSegments (display, gw->goban.picture, mark_gc, segment, 4);
  659.         break;
  660.       }
  661.     }
  662.     
  663.     else {
  664.       s[len++] = c1;
  665.       if( c2 != 0 ) s[len++] = c2;
  666.       
  667.       XQueryTextExtents (display, XGContextFromGC (mark_gc), (char *)s, len,
  668.                 &direction, &ascent, &descent, &extent);
  669.       
  670.       radius = extent.width + extent.descent + extent.ascent;
  671.       
  672.       if (radius < (int)gw->goban.point_size - 1) {
  673.         if (gw->goban.points[x][y].free == 0)
  674.           XFillArc (display, gw->goban.picture, erase_gc, 
  675.             (int) (X - gw->goban.point_size) / 2 + 2,
  676.             (int) (Y - gw->goban.point_size) / 2 + 2, 
  677.             (unsigned int) gw->goban.point_size - 4,
  678.             (unsigned int) gw->goban.point_size - 4, 
  679.             0, 360 * 64);
  680.         else
  681.           XFillArc (display, gw->goban.picture, erase_gc,
  682.             (int) (X - radius) / 2, (int) (Y - radius) / 2, 
  683.             (unsigned int) radius, (unsigned int) radius, 
  684.             0, 360 * 64);
  685.         
  686.         XDrawString (display, gw->goban.picture, mark_gc,
  687.              (X - extent.width) / 2 - extent.lbearing + 1, 
  688.              (Y + extent.ascent - extent.descent) / 2 + 1,
  689.              (char *)s, len);
  690.       }
  691.     }
  692.       
  693.     if (gw->goban.auto_redisplay == TRUE && XtIsRealized (w) == TRUE) {
  694.       event.x      = (int)(X - gw->goban.point_size) / 2;
  695.       event.y      = (int)(Y - gw->goban.point_size) / 2;
  696.       event.width  = gw->goban.point_size;
  697.       event.height = gw->goban.point_size;
  698.       
  699.       Redisplay (w, &event, (Region) NULL);
  700.     }
  701.       }
  702.     }
  703.   }
  704. }
  705.  
  706. /****************************************************************************************************************
  707.  */
  708.  
  709. /* ARGSUSED */
  710.  
  711. static void Redisplay (w, event, region)
  712. Widget        w;
  713. XExposeEvent *event;
  714. Region        region;
  715. {
  716.   GobanWidget gw     = (GobanWidget) w;
  717.   Position    x      = event->x;
  718.   Position    y      = event->y;
  719.   Dimension   width  = event->width;
  720.   Dimension   height = event->height;
  721.  
  722.   XCopyArea (XtDisplay (w), gw->goban.picture, XtWindow (w), gw->goban.copy_gc, x, y, width, height, x, y);
  723. }
  724.  
  725. /****************************************************************************************************************
  726.  */
  727.  
  728. /* ARGSUSED */
  729.  
  730. static void CvtStringToCursor (args, num_args, fromVal, toVal)
  731. XrmValuePtr   args;        /* unused */
  732. Cardinal     *num_args;    /* unused */
  733. XrmValuePtr   fromVal;
  734. XrmValuePtr   toVal;
  735. {
  736.   static int       cursor;
  737.   static XrmQuark  QWhiteStone;
  738.   static XrmQuark  QBlackStone;
  739.   XrmQuark         quark;
  740.   unsigned char             lowerName[256];
  741.   static Boolean   inited = FALSE;
  742.     
  743.   if (inited == FALSE) {
  744.     QWhiteStone  = XrmStringToQuark (XtEgbWhiteStone);
  745.     QBlackStone  = XrmStringToQuark (XtEgbBlackStone);
  746.     inited       = TRUE;
  747.   }
  748.  
  749.   XmuCopyISOLatin1Lowered  (lowerName, (String) fromVal->addr);
  750.   quark = XrmStringToQuark ((char *)lowerName);
  751.  
  752.   if (quark == QWhiteStone)
  753.     cursor = GbCWhiteStone;
  754.   else if (quark == QBlackStone)       
  755.     cursor = GbCBlackStone;
  756.   else {
  757.     toVal->size = 0;
  758.     toVal->addr = NULL;
  759.     return;
  760.   }
  761.  
  762.   toVal->size = sizeof (cursor);
  763.   toVal->addr = (caddr_t) &cursor;
  764. }
  765.  
  766. /****************************************************************************************************************
  767.  */
  768.  
  769. static void ClassInitialize()
  770. {
  771.   XtAddConverter (XtRString, XtRInt, (XtConverter) CvtStringToCursor, NULL, 0);
  772. }
  773.  
  774. /****************************************************************************************************************
  775.  */
  776.  
  777. static void InitializePixmap (w)
  778. Widget w;
  779. {
  780.   GobanWidget  gw      = (GobanWidget) w;
  781.   Display     *display = XtDisplay (w);
  782.   Drawable     window  = RootWindowOfScreen (XtScreen (w));
  783.   Dimension    width   = w->core.width;
  784.   Dimension    height  = w->core.height;
  785.  
  786.   gw->goban.board   = XCreatePixmap (display, window, width, height, (unsigned int) DefaultDepthOfScreen (XtScreen (w)));
  787.   gw->goban.picture = XCreatePixmap (display, window, width, height, (unsigned int) DefaultDepthOfScreen (XtScreen (w)));
  788. }
  789.  
  790. /****************************************************************************************************************
  791.  */
  792.  
  793. static void InitializeGC (w)
  794. Widget w;
  795. {
  796.   GobanWidget  gw      = (GobanWidget) w;
  797.   Display     *display = XtDisplay (w);
  798.   XtGCMask     mask    = GCForeground | GCBackground | GCFont;
  799.   XGCValues    values;
  800.  
  801.   values.font             = gw->goban.font->fid;
  802.   values.background       = w->core.background_pixel;
  803.  
  804.   values.foreground       = gw->goban.white_fg;
  805.   gw->goban.white_fg_gc   = XCreateGC  (display, gw->goban.picture, mask, &values);
  806.   values.foreground       = gw->goban.white_bg;
  807.   gw->goban.white_bg_gc   = XCreateGC  (display, gw->goban.picture, mask, &values);
  808.   values.foreground       = gw->goban.white_bd;
  809.   gw->goban.white_bd_gc   = XCreateGC  (display, gw->goban.picture, mask, &values);
  810.  
  811.   values.foreground       = gw->goban.black_fg;
  812.   gw->goban.black_fg_gc   = XCreateGC  (display, gw->goban.picture, mask, &values);
  813.   values.foreground       = gw->goban.black_bg;
  814.   gw->goban.black_bg_gc   = XCreateGC  (display, gw->goban.picture, mask, &values);
  815.   values.foreground       = gw->goban.black_bd;
  816.   gw->goban.black_bd_gc   = XCreateGC  (display, gw->goban.picture, mask, &values);
  817.  
  818.   values.foreground       = gw->goban.foreground;
  819.   gw->goban.foreground_gc = XCreateGC  (display, gw->goban.picture, mask, &values);
  820.   gw->goban.copy_gc       = XCreateGC  (display, gw->goban.picture, (XtGCMask) 0, (XGCValues *) NULL);
  821.  
  822.   localstipple = stippleflag;
  823.   if( !stippleflag ) {
  824.     if( gw->goban.stipple ) localstipple = TRUE;
  825.   }
  826.   else {
  827.     if( gw->goban.stipple ) localstipple = FALSE;
  828.   }
  829.  
  830.   if( localstipple ) {
  831.     values.stipple           = XCreatePixmapFromBitmapData (display,
  832.                 gw->goban.picture,
  833.                 (char *)stipple_bits, stipple_width,
  834.                 stipple_height,
  835.                 BlackPixel (display, DefaultScreen (display)),
  836.                 WhitePixel (display, DefaultScreen (display)),
  837.                 1);
  838.     values.fill_style     = FillOpaqueStippled;
  839.     mask                 |= GCStipple | GCFillStyle;
  840.   }
  841.  
  842.   values.foreground       = w->core.background_pixel;
  843.   values.background       = gw->goban.foreground;
  844.   gw->goban.background_gc = XCreateGC  (display, gw->goban.picture, mask, &values);
  845. }
  846.  
  847. /*******************************************************************/ 
  848. static void InitializeCursor (w)
  849. Widget w;
  850. {
  851.   GobanWidget  gw      = (GobanWidget) w;
  852.   Display     *display = XtDisplay (w);
  853.   Drawable     window  = RootWindowOfScreen (XtScreen (w));
  854.   Pixel        black   = BlackPixel (display, DefaultScreen (display));
  855.   Pixel        white   = WhitePixel (display, DefaultScreen (display));
  856.  
  857.   static XColor black_color = { 0,    0,     0,     0  };  /* black */
  858.   static XColor white_color = { 0, 65535, 65535, 65535 };  /* white */
  859.  
  860.   /* Some teminals invert the mask with BlackPixel and WhitePixel     */
  861.   /* should use black and white instead of 1 and 0 but depth is 1 ... */
  862.   /* will probably have trouble with some special colormaps           */
  863.  
  864.   gw->goban.white_stone = XCreatePixmapFromBitmapData
  865.     (display, window, (char *)whitestone_bits, whitestone_width, whitestone_height, 1, 0, 1);
  866.   gw->goban.black_stone = XCreatePixmapFromBitmapData
  867.     (display, window, (char *)blackstone_bits, blackstone_width, blackstone_height, 1, 0, 1);
  868.   gw->goban.mouse_mask  = XCreatePixmapFromBitmapData
  869.     (display, window, (char *)stonemask_bits , stonemask_width , stonemask_height , 1, 0, 1);
  870.  
  871.   gw->goban.white_cursor = 
  872.     XCreatePixmapCursor (display, gw->goban.white_stone, gw->goban.mouse_mask, 
  873.              &black_color, &white_color, whitestone_x_hot, whitestone_y_hot);
  874.   gw->goban.black_cursor = 
  875.     XCreatePixmapCursor (display, gw->goban.black_stone, gw->goban.mouse_mask, 
  876.              &black_color, &white_color, blackstone_x_hot, blackstone_y_hot);
  877.  
  878.   gw->goban.font_cursor  = XCreateFontCursor (display, XC_question_arrow);
  879. }
  880.   
  881. /****************************************************************************************************************
  882.  */
  883.  
  884. static void DestroyPixmap (w)
  885. Widget w;
  886. {
  887.   GobanWidget  gw      = (GobanWidget) w;
  888.   Display     *display = XtDisplay (w);
  889.  
  890.   XFreePixmap (display, gw->goban.picture);
  891.   XFreePixmap (display, gw->goban.board  );
  892. }
  893.  
  894. /****************************************************************************************************************
  895.  */
  896.  
  897. static void DestroyGC (w)
  898. Widget w;
  899. {
  900.   GobanWidget  gw      = (GobanWidget) w;
  901.   Display     *display = XtDisplay (w);
  902.  
  903.   XFreeGC (display, gw->goban.black_fg_gc  );
  904.   XFreeGC (display, gw->goban.black_bg_gc  );
  905.   XFreeGC (display, gw->goban.black_bd_gc  );
  906.   XFreeGC (display, gw->goban.white_fg_gc  );
  907.   XFreeGC (display, gw->goban.white_bg_gc  );
  908.   XFreeGC (display, gw->goban.white_bd_gc  );
  909.   XFreeGC (display, gw->goban.foreground_gc);
  910.   XFreeGC (display, gw->goban.background_gc);
  911.   XFreeGC (display, gw->goban.copy_gc      );
  912. }
  913.  
  914. /****************************************************************************************************************
  915.  */
  916.  
  917. static void Destroy (w)
  918. Widget w;
  919. {
  920.   GobanWidget  gw      = (GobanWidget) w;
  921.   Display     *display = XtDisplay (w);
  922.  
  923.   DestroyPixmap (w);
  924.   DestroyGC     (w);
  925.  
  926.   XFreePixmap (display, gw->goban.white_stone  );
  927.   XFreePixmap (display, gw->goban.black_stone  );
  928.   XFreePixmap (display, gw->goban.gray_stone   );
  929.   XFreePixmap (display, gw->goban.mouse_mask   );
  930.  
  931.   XFreeCursor (display, gw->goban.white_cursor );
  932.   XFreeCursor (display, gw->goban.black_cursor );
  933.   XFreeCursor (display, gw->goban.gray_cursor  );
  934.   XFreeCursor (display, gw->goban.font_cursor  );
  935. }
  936.  
  937. /****************************************************************************************************************
  938.  */
  939.  
  940. static void Realize (w, valuemaskp, attr)
  941. Widget                w;
  942. XtValueMask          *valuemaskp;
  943. XSetWindowAttributes *attr;
  944. {
  945.   GobanWidget  gw      = (GobanWidget) w;
  946.   
  947.   *valuemaskp |= CWCursor;
  948.  
  949.   switch (gw->goban.cursor) {
  950.   case GbCBlackStone : attr->cursor = gw->goban.black_cursor; break;
  951.   case GbCWhiteStone : attr->cursor = gw->goban.white_cursor; break;
  952.   default            : attr->cursor = gw->goban.font_cursor ; break;
  953.   }
  954.   
  955.   XtCreateWindow (w, InputOutput, (Visual *) CopyFromParent, *valuemaskp, attr);
  956. }
  957.  
  958. /****************************************************************************************************************
  959.  */
  960.  
  961. static char *stars[18] = {
  962.   "",                /*  2  */  
  963.   "",                /*  3  */  
  964.   "",                /*  4  */  
  965.   "",                /*  5  */  
  966.   "",                /*  6  */  
  967.   "",                /*  7  */  
  968.   "cccffcff",            /*  8  */    
  969.   "cccgeegcgg",            /*  9  */  
  970.   "ccchhchh",            /* 10  */  
  971.   "cccfcifcfffiicifii",        /* 11  */  
  972.   "dddiidii",            /* 12  */  
  973.   "dddjggjdjj",            /* 13  */  
  974.   "dddkkdkk",            /* 14  */  
  975.   "dddhdlhdhhhlldlhll",        /* 15  */  
  976.   "dddmmdmm",            /* 16  */  
  977.   "dddidnidiiinndninn",        /* 17  */  
  978.   "dddoodoo",            /* 18  */  
  979.   "dddjdpjdjjjppdpjpp",        /* 19  */  
  980. };
  981.  
  982. static void DrawBoard (w)
  983. Widget w;
  984. {
  985.   GobanWidget  gw         = (GobanWidget) w;
  986.   Display     *display    = XtDisplay (w);
  987.   XSegment     segment[44];
  988.   int          segc;
  989.   Position     game_size  = (Position) gw->goban.game_size;
  990.   Position     point_size = (Position) gw->goban.point_size;
  991.   Position     star_size  = 4;
  992.   Position     xbase      = gw->goban.x_offset + point_size / 2;
  993.   Position     ybase      = gw->goban.y_offset - point_size / 2;
  994.   Position     xmin       = gw->goban.x_offset + point_size * gw->goban.left + 1;
  995.   Position     ymin       = gw->goban.y_offset - point_size * gw->goban.top  + 1;
  996.   Position     xmax       = gw->goban.x_offset + point_size * (gw->goban.right  + 1) - 1;
  997.   Position     ymax       = gw->goban.y_offset - point_size * (gw->goban.bottom - 1) - 1;
  998.   char        *star;
  999.   int          x;
  1000.   int          y;
  1001.  
  1002.   XFillRectangle (display, gw->goban.board, gw->goban.background_gc, 0, 0, w->core.width, w->core.height);
  1003.  
  1004.   if (point_size > 0) {
  1005.     segc = 0;
  1006.     for (y = gw->goban.bottom - 1; y < gw->goban.top; y++, segc++) {
  1007.       segment[segc].x1 = (short) Max ((int) xbase + point_size , xmin);
  1008.       segment[segc].x2 = (short) Min ((int) xbase + point_size * game_size, xmax);
  1009.       segment[segc].y1 = (short) (ybase - point_size * y);
  1010.       segment[segc].y2 = (short) (ybase - point_size * y);
  1011.     }
  1012.     
  1013.     for (x = gw->goban.left; x <= gw->goban.right; x++, segc++) {
  1014.       segment[segc].x1 = (short) (xbase + point_size * x);
  1015.       segment[segc].x2 = (short) (xbase + point_size * x);
  1016.       segment[segc].y1 = (short) Max (ybase - point_size * (game_size - 1), ymin);
  1017.       segment[segc].y2 = (short) Min (ybase, ymax);
  1018.     }
  1019.     
  1020.     if (gw->goban.top == gw->goban.game_size) {
  1021.       segment[segc].x1 = (short) Max (xbase + point_size - 1, xmin);
  1022.       segment[segc].x2 = (short) Min (xbase + point_size * game_size + 1, xmax);
  1023.       segment[segc].y1 = (short) (ybase - point_size * (game_size - 1) - 1);
  1024.       segment[segc].y2 = (short) (ybase - point_size * (game_size - 1) - 1);
  1025.       segc++;
  1026.     }
  1027.     
  1028.     if (gw->goban.bottom == 1) {
  1029.       segment[segc].x1 = (short) Max (xbase + point_size - 1, xmin);
  1030.       segment[segc].x2 = (short) Min (xbase + point_size * game_size + 1, xmax);
  1031.       segment[segc].y1 = (short) (ybase + 1);
  1032.       segment[segc].y2 = (short) (ybase + 1);
  1033.       segc++;
  1034.     }
  1035.     
  1036.     if (gw->goban.left == 1) {
  1037.       segment[segc].x1 = (short) (xbase + point_size - 1);
  1038.       segment[segc].x2 = (short) (xbase + point_size - 1);
  1039.       segment[segc].y1 = (short) Max (ybase - point_size * (game_size - 1) - 1, ymin); 
  1040.       segment[segc].y2 = (short) Min (ybase + 1, ymax);
  1041.       segc++;
  1042.     }
  1043.     
  1044.     if (gw->goban.right == gw->goban.game_size) {
  1045.       segment[segc].x1 = (short) (xbase + point_size * game_size + 1);
  1046.       segment[segc].x2 = (short) (xbase + point_size * game_size + 1);
  1047.       segment[segc].y1 = (short) Max (ybase - point_size * (game_size - 1) - 1, ymin);
  1048.       segment[segc].y2 = (short) Min (ybase + 1, ymax);
  1049.       segc++;
  1050.     }
  1051.     
  1052.     XDrawSegments (display, gw->goban.board, gw->goban.foreground_gc, segment, segc);
  1053.     
  1054.     if (point_size > 8) {
  1055.       star_size = (point_size > 10) ? 4 : 2;
  1056.       star      = stars[game_size - 2];
  1057.       
  1058.       while (*star != '\0') {
  1059.     x = *star++ - 'a' + 1;
  1060.     y = *star++ - 'a' + 1;
  1061.     
  1062.     if (x >= gw->goban.left && x <= gw->goban.right && y >= gw->goban.bottom && y <= gw->goban.top) {
  1063.       x = gw->goban.x_offset + (point_size * (2 * x + 1)) / 2;
  1064.       y = gw->goban.y_offset - (point_size * (2 * y - 1)) / 2;
  1065.       
  1066.       XDrawArc (display, gw->goban.board, gw->goban.foreground_gc, 
  1067.             (int) x - star_size / 2, (int) y - star_size / 2, 
  1068.             (unsigned int) star_size, (unsigned int) star_size, 
  1069.             0, 64 * 360);
  1070.       XFillArc (display, gw->goban.board, gw->goban.foreground_gc, 
  1071.             (int) x - star_size / 2, (int) y - star_size / 2, 
  1072.             (unsigned int) star_size, (unsigned int) star_size, 
  1073.             0, 64 * 360);
  1074.     }
  1075.       }
  1076.     }
  1077.   }
  1078.  
  1079.   XCopyArea (display, gw->goban.board, gw->goban.picture, gw->goban.copy_gc, 0, 0, 
  1080.          w->core.width, w->core.height, 0, 0);
  1081. }
  1082.  
  1083. /****************************************************************************************************************
  1084.  */
  1085.  
  1086. static void DrawCoordinates (w)
  1087. Widget w;
  1088. {
  1089.   GobanWidget  gw         = (GobanWidget) w;
  1090.   Display     *display    = XtDisplay (w);
  1091.   XCharStruct  extent;
  1092.   int          point_size = gw->goban.point_size;
  1093.   unsigned char         s[2];
  1094.   int          len;
  1095.   int          ascent;
  1096.   int          descent;
  1097.   int          direction;
  1098.   int          xbase;
  1099.   int          ybase;
  1100.   int          x;
  1101.   int          y;
  1102.   unsigned int width;
  1103.   unsigned int height;
  1104.  
  1105.   s[0] = s[1] = '8';
  1106.   XQueryTextExtents (display, XGContextFromGC (gw->goban.foreground_gc),
  1107.              (char *)s, 2, &direction, &ascent, &descent, &extent);
  1108.  
  1109.   if ((point_size > extent.width + 2) && (point_size > extent.ascent + extent.descent + 2)) {
  1110.     xbase = 2 * gw->goban.x_offset + point_size;
  1111.     ybase = 2 * gw->goban.y_offset - point_size;
  1112.  
  1113.     if (gw->goban.display_coordinates == TRUE) {
  1114.     
  1115.       for (x = gw->goban.left; x <= gw->goban.right; x++) {
  1116.     s[0] = 'A' - 1 + ((x > 8) ? (x + 1) : x);
  1117.     XQueryTextExtents (display, XGContextFromGC (gw->goban.foreground_gc),
  1118.                (char *)s, 1, &direction, &ascent, &descent, &extent);
  1119.  
  1120.     XDrawString (display, gw->goban.board, gw->goban.foreground_gc, 
  1121.              (xbase - extent.width) / 2 + point_size * x - extent.lbearing + 1, 
  1122.              (ybase + extent.ascent - extent.descent) / 2 - point_size * gw->goban.top + 1,
  1123.              (char *)s, 1);
  1124.     XDrawString (display, gw->goban.board, gw->goban.foreground_gc, 
  1125.              (xbase - extent.width) / 2 + point_size * x - extent.lbearing + 1, 
  1126.              (ybase + extent.ascent - extent.descent) / 2 - point_size * (gw->goban.bottom - 2) + 1,
  1127.              (char *)s, 1);
  1128.       }
  1129.     }
  1130.  
  1131.     x      = gw->goban.x_offset + point_size * gw->goban.left;
  1132.     y      = gw->goban.y_offset - point_size * (gw->goban.top + 1);
  1133.     width  = point_size * (gw->goban.right - gw->goban.left + 1);
  1134.     height = point_size;
  1135.     
  1136.     if (gw->goban.display_coordinates == FALSE)
  1137.       XFillRectangle (display, gw->goban.board, gw->goban.background_gc, x, y, width, height);
  1138.     XCopyArea (display, gw->goban.board, gw->goban.picture, gw->goban.copy_gc, x, y, width, height, x, y);
  1139.  
  1140.     y      = gw->goban.y_offset - point_size * (gw->goban.bottom - 1);
  1141.  
  1142.     if (gw->goban.display_coordinates == FALSE)
  1143.       XFillRectangle (display, gw->goban.board, gw->goban.background_gc, x, y, width, height);
  1144.     XCopyArea (display, gw->goban.board, gw->goban.picture, gw->goban.copy_gc, x, y, width, height, x, y);
  1145.     
  1146.     ybase += 2 * point_size;
  1147.  
  1148.     for (y = gw->goban.bottom; y <= gw->goban.top; y++) {
  1149.       if (gw->goban.display_coordinates == TRUE) {
  1150.     len = 0;
  1151.     if (y > 9)
  1152.       s[len++] = '1';
  1153.     s[len++] = '0' + y % 10;
  1154.     XQueryTextExtents (display, XGContextFromGC (gw->goban.foreground_gc),
  1155.                (char *)s, len, &direction, &ascent, &descent,
  1156.                &extent);
  1157.  
  1158.     XDrawString (display, gw->goban.board, gw->goban.foreground_gc, 
  1159.              (xbase - extent.width) / 2 + point_size * (gw->goban.left  - 1) - extent.lbearing + 1, 
  1160.              (ybase + extent.ascent - extent.descent) / 2 - point_size * y + 1,
  1161.              (char *)s, len);
  1162.     XDrawString (display, gw->goban.board, gw->goban.foreground_gc, 
  1163.              (xbase - extent.width) / 2 + point_size * (gw->goban.right + 1) - extent.lbearing + 1, 
  1164.              (ybase + extent.ascent - extent.descent) / 2 - point_size * y + 1,
  1165.              (char *)s, len);
  1166.       }
  1167.     }
  1168.  
  1169.     x      = gw->goban.x_offset + point_size * (gw->goban.left  - 1);
  1170.     y      = gw->goban.y_offset - point_size * gw->goban.top;
  1171.     width  = point_size;
  1172.     height = point_size * (gw->goban.top - gw->goban.bottom + 1);;
  1173.     
  1174.     if (gw->goban.display_coordinates == FALSE)
  1175.       XFillRectangle (display, gw->goban.board, gw->goban.background_gc, x, y, width, height);
  1176.     XCopyArea (display, gw->goban.board, gw->goban.picture, gw->goban.copy_gc, x, y, width, height, x, y);
  1177.  
  1178.     x      = gw->goban.x_offset + point_size * (gw->goban.right + 1);
  1179.     
  1180.     if (gw->goban.display_coordinates == FALSE)
  1181.       XFillRectangle (display, gw->goban.board, gw->goban.background_gc, x, y, width, height);
  1182.     XCopyArea (display, gw->goban.board, gw->goban.picture, gw->goban.copy_gc, x, y, width, height, x, y);
  1183.   }
  1184.  
  1185. }
  1186.  
  1187. /****************************************************************************************************************
  1188.  */
  1189.  
  1190. static void InitializeSize (w)
  1191. Widget w;
  1192. {  
  1193.   GobanWidget  gw        = (GobanWidget) w;
  1194.   Position     bottom    = Min (gw->goban.bottom, gw->goban.top  );
  1195.   Position     left      = Min (gw->goban.left  , gw->goban.right);
  1196.   Position     top       = Max (gw->goban.bottom, gw->goban.top  );
  1197.   Position     right     = Max (gw->goban.left  , gw->goban.right);
  1198.   Dimension    game_size = gw->goban.game_size;
  1199.   Dimension    width;
  1200.   Dimension    height;
  1201.  
  1202.   game_size = (game_size > 1      && game_size <  20       ) ? game_size : 19;
  1203.   bottom    = (bottom    > 0      && bottom    <  (Position)game_size) ? bottom    : 1;
  1204.   left      = (left      > 0      && left      <  (Position)game_size) ? left      : 1;
  1205.   top       = (top       > bottom && top       <= (Position)game_size) ? top       : game_size;
  1206.   right     = (right     > left   && right     <= (Position)game_size) ? right     : game_size;
  1207.  
  1208.   width     = right - left   + 3;
  1209.   height    = top   - bottom + 3;
  1210.  
  1211.   if ((w->core.height == 0) && (w->core.width == 0)) {
  1212.     w->core.width  = gw->goban.point_size * width ;
  1213.     w->core.height = gw->goban.point_size * height;
  1214.   } 
  1215.  
  1216.   else 
  1217.     gw->goban.point_size = Min ((int)w->core.width / (int)width, (int)w->core.height / (int)height);
  1218.  
  1219.   gw->goban.game_size = game_size;
  1220.   gw->goban.bottom    = bottom;
  1221.   gw->goban.left      = left;
  1222.   gw->goban.top       = top;
  1223.   gw->goban.right     = right;
  1224.   gw->goban.x_offset  = (int) (w->core.width  - gw->goban.point_size * (width  + 2 * left - 2)) / 2;
  1225.   gw->goban.y_offset  = (int) (w->core.height - gw->goban.point_size * (height - 2 * top  - 2)) / 2;
  1226. }
  1227.  
  1228. /****************************************************************************************************************
  1229.  */
  1230.  
  1231. /* ARGSUSED */
  1232.  
  1233. static void Initialize (request, new)
  1234. Widget request;
  1235. Widget new;
  1236. {
  1237.     GobanWidget   gw      = (GobanWidget) new;
  1238.     gw->goban.left = 1;
  1239.     gw->goban.right = 19;
  1240.     gw->goban.top = 1;
  1241.     gw->goban.bottom = 19;
  1242.  
  1243.   InitializeSize   (new);
  1244.   InitializePixmap (new);
  1245.   InitializeGC     (new);
  1246.   InitializeCursor (new);
  1247.   DrawBoard        (new);
  1248.   DrawCoordinates  (new);
  1249.   GbClearBoard     (new);
  1250. }
  1251.  
  1252. /****************************************************************************************************************
  1253.  */
  1254.  
  1255. static void DrawPoint (w, x, y, color, flag)
  1256. Widget      w;
  1257. int         x;
  1258. int         y;
  1259. GbPointState color;
  1260. Boolean flag;    /*SC  TRUE to mark as "Last"  FALSE to just draw stone */
  1261. {
  1262.   GobanWidget   gw      = (GobanWidget) w;
  1263.   Display      *display = XtDisplay (w);
  1264.   unsigned int  size    = (unsigned int) gw->goban.point_size - 2;
  1265.   XExposeEvent  event;
  1266.   int           X, XX;
  1267.   int           Y, YY;
  1268.  
  1269.   if (size > 1) {
  1270.     X = gw->goban.x_offset + gw->goban.point_size * x + 1;
  1271.     Y = gw->goban.y_offset - gw->goban.point_size * y + 1;
  1272.     XX = X + size/4 +1;
  1273.     YY = Y + size/4 +1;
  1274.  
  1275.     
  1276.     switch (color)
  1277.       {
  1278.       case GbBlackStone :
  1279.     XFillArc (display, gw->goban.picture, gw->goban.black_bg_gc, X, Y,
  1280.             size, size, 0, 360 * 64);
  1281.     XDrawArc (display, gw->goban.picture, gw->goban.black_bd_gc, X, Y,
  1282.             size, size, 0, 360 * 64);
  1283.     if( flag ) {
  1284.        XFillArc( display, gw->goban.picture, gw->goban.black_fg_gc,
  1285.              XX, YY, size/2, size/2, 0, 360*64 );
  1286.        lastx = X;
  1287.        lasty = Y;
  1288.            lastcolor = color;
  1289.        }
  1290.  
  1291.     else XDrawArc (display, gw->goban.picture, gw->goban.black_fg_gc,
  1292.             X + (int) size / 6, Y + (int) size / 6, 
  1293.               (size * 2) / 3, (size * 2) / 3, -15 * 64, -60 * 64);
  1294.     break;
  1295.       case GbWhiteStone :
  1296.     XFillArc (display, gw->goban.picture, gw->goban.white_bg_gc, X, Y,
  1297.             size, size, 0, 360 * 64);
  1298.     XDrawArc (display, gw->goban.picture, gw->goban.white_bd_gc, X, Y,
  1299.             size, size, 0, 360 * 64);
  1300.     if( flag ) {
  1301.         XFillArc( display, gw->goban.picture, gw->goban.white_fg_gc,
  1302.             XX, YY, size/2, size/2, 0, 360*64 );
  1303.         lastx = X;
  1304.         lasty = Y;
  1305.         lastcolor = color;
  1306.     }
  1307.     else XDrawArc (display, gw->goban.picture, gw->goban.white_fg_gc,
  1308.             X + (int) size / 6, Y + (int) size / 6, 
  1309.               (size * 2) / 3, (size * 2) / 3, -15 * 64, -60 * 64);
  1310.     break;
  1311.       case GbEmptyPoint :
  1312.     XCopyArea (XtDisplay (w), gw->goban.board, gw->goban.picture,
  1313.             gw->goban.copy_gc, X, Y, gw->goban.point_size,
  1314.             gw->goban.point_size, X, Y); 
  1315.     break;
  1316.       }
  1317.     
  1318.     if (gw->goban.auto_redisplay == TRUE && XtIsRealized (w) == TRUE) {
  1319.       event.x      = X - 1;
  1320.       event.y      = Y - 1;
  1321.       event.width  = gw->goban.point_size;
  1322.       event.height = gw->goban.point_size;
  1323.  
  1324.       Redisplay (w, &event, (Region) NULL);
  1325.     }
  1326.   }
  1327. }
  1328.  
  1329. /****************************************************************************************************************
  1330.  */
  1331.  
  1332. static void RedrawStones (w)
  1333. Widget w;
  1334. {
  1335.   GobanWidget  gw         = (GobanWidget) w;
  1336.   Boolean      redisplay  = gw->goban.auto_redisplay;
  1337.   Position     x;
  1338.   Position     y;
  1339.  
  1340.   gw->goban.auto_redisplay = FALSE;
  1341.  
  1342.   for (x = gw->goban.left; x <= gw->goban.right; x++)
  1343.     for (y = gw->goban.bottom; y <= gw->goban.top; y++) {
  1344.       if (gw->goban.points[x][y].free == 0) {
  1345.     if (gw->goban.points[x][y].black == 1) {
  1346.       DrawPoint (w, x, y, GbBlackStone, FALSE);
  1347.     }
  1348.     else {
  1349.       DrawPoint (w, x, y, GbWhiteStone, FALSE);
  1350.     }
  1351.     if (gw->goban.points[x][y].num > 0)
  1352.       GbSetNum (w, x, y, (int) gw->goban.points[x][y].num);
  1353.       }
  1354.  
  1355.       if (gw->goban.points[x][y].mark1 != 0 || gw->goban.points[x][y].mark2 != 0)
  1356.     GbSetMark (w, x, y, gw->goban.points[x][y].mark1, gw->goban.points[x][y].mark2);
  1357.     }
  1358.  
  1359.   gw->goban.auto_redisplay = redisplay;
  1360.  
  1361.   if (redisplay == TRUE) GbRedisplayBoard (w);
  1362. }
  1363.  
  1364. /****************************************************************************************************************
  1365.  */
  1366.  
  1367. static void Resize (w)
  1368. Widget w;
  1369. {
  1370.   DestroyPixmap    (w);
  1371.   DestroyGC        (w);
  1372.   InitializeSize   (w);
  1373.   InitializePixmap (w);
  1374.   InitializeGC     (w);
  1375.   DrawBoard        (w);
  1376.   DrawCoordinates  (w);
  1377.   RedrawStones     (w);
  1378. }
  1379.  
  1380. /****************************************************************************************************************
  1381.  */
  1382.  
  1383. /* ARGSUSED */
  1384.  
  1385. static Boolean SetValues (current, request, new)
  1386. Widget current;
  1387. Widget request;
  1388. Widget new;
  1389. {
  1390.   GobanWidget gnew      = (GobanWidget) new;
  1391.   GobanWidget gcurrent  = (GobanWidget) current;
  1392.   Boolean     redisplay = FALSE;
  1393.  
  1394.   if (gnew->goban.point_size != gcurrent->goban.point_size)
  1395.     gnew->goban.point_size = gcurrent->goban.point_size;
  1396.  
  1397.   if (XtIsRealized (new)) {
  1398.     if (gnew->goban.cursor != gcurrent->goban.cursor) {
  1399.  
  1400.       switch (gnew->goban.cursor) {
  1401.  
  1402.       case GbCBlackStone : 
  1403.     XDefineCursor (XtDisplay (new), XtWindow (new), gnew->goban.black_cursor);
  1404.     break;
  1405.       case GbCWhiteStone : 
  1406.     XDefineCursor (XtDisplay (new), XtWindow (new), gnew->goban.white_cursor);
  1407.     break;
  1408.       default :
  1409.     XFreeCursor (XtDisplay (new), gnew->goban.font_cursor );
  1410.     gnew->goban.font_cursor = XCreateFontCursor (XtDisplay (new), (unsigned int) gnew->goban.cursor);
  1411.     XDefineCursor (XtDisplay (new), XtWindow (new), gnew->goban.font_cursor);
  1412.       }
  1413.     }
  1414.   }
  1415.  
  1416.   if (gnew->goban.game_size != gcurrent->goban.game_size) 
  1417.     if (gnew->goban.game_size > 1 && gnew->goban.game_size < 20) {
  1418.  
  1419.       gnew->goban.bottom = 1;
  1420.       gnew->goban.left   = 1;
  1421.       gnew->goban.top    = gnew->goban.game_size;
  1422.       gnew->goban.right  = gnew->goban.game_size;
  1423.       
  1424.       InitializeSize   (new);
  1425.       DrawBoard        (new);
  1426.       DrawCoordinates  (new);
  1427.       GbClearBoard     (new);
  1428.       
  1429.       redisplay = TRUE;
  1430.     }
  1431.     else
  1432.       gnew->goban.game_size = gcurrent->goban.game_size;
  1433.  
  1434.   else if (gnew->goban.top    != gcurrent->goban.top   ||
  1435.        gnew->goban.left   != gcurrent->goban.left  ||
  1436.        gnew->goban.right  != gcurrent->goban.right ||
  1437.        gnew->goban.bottom != gcurrent->goban.bottom) {
  1438.  
  1439.     InitializeSize  (new);
  1440.     DrawBoard       (new);
  1441.     DrawCoordinates (new);
  1442.     RedrawStones    (new);
  1443.  
  1444.     redisplay = TRUE;
  1445.   }
  1446.  
  1447.   else if (new->core.background_pixel != current->core.background_pixel || 
  1448.            gnew->goban.foreground     != gcurrent->goban.foreground     ||
  1449.            gnew->goban.white_fg       != gcurrent->goban.white_fg       ||
  1450.            gnew->goban.white_bg       != gcurrent->goban.white_bg       ||
  1451.            gnew->goban.white_bd       != gcurrent->goban.white_bd       ||
  1452.            gnew->goban.black_fg       != gcurrent->goban.black_fg       ||
  1453.            gnew->goban.black_bg       != gcurrent->goban.black_bg       ||
  1454.            gnew->goban.black_bd       != gcurrent->goban.black_bd       ) {
  1455.  
  1456.     DestroyGC        (new);
  1457.     InitializeGC     (new);
  1458.     DrawBoard        (new);
  1459.     DrawCoordinates  (new);
  1460.     RedrawStones     (new);
  1461.  
  1462.     redisplay = TRUE;
  1463.   }
  1464.  
  1465.   if (gnew->goban.display_coordinates != gcurrent->goban.display_coordinates) {
  1466.     DrawCoordinates (new);
  1467.  
  1468.     redisplay = TRUE;
  1469.   }
  1470.  
  1471.   return (gnew->goban.auto_redisplay == True) ? redisplay : False;
  1472. }
  1473.  
  1474. /****************************************************************************************************************
  1475.  */
  1476.