Use XCBFlush not XCBSync
[free-sw/xcb/demo] / neko / xcbneko.c
1 /*--------------------------------------------------------------
2  *
3  *      xneko
4  *
5  *                      Original Writer:
6  *            Masayuki Koba
7  *
8  *                      Programmed by:
9  *            Masayuki Koba, 1990
10  *
11  *          Added Color, RootWindow Capability and Quit Ability:
12  *            Dan Checkoway, 7-12-94
13  *
14  *                      Converted to use ANSI C and XCB by:
15  *            Ian Osgood, 2006
16  *
17  *--------------------------------------------------------------*/
18
19 #if USING_XLIB
20 #include <X11/Xlib.h>
21 #include <X11/Xutil.h>
22 #include <X11/keysym.h>
23 #else
24 #define X_H   /* make sure we aren't using symbols from X.h */
25 #include <X11/XCB/xcb.h>
26 /*#include <X11/XCB/xcb_image.h>*/
27 #include <X11/XCB/xcb_aux.h>            /* XCBAuxGetScreen */
28 #include <X11/XCB/xcb_icccm.h>
29 #include <X11/XCB/xcb_atom.h>           /* STRING atom */
30
31 typedef enum { False, True } Bool;
32
33 #endif
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <stdio.h>
38
39 #include <unistd.h>     /* pause() */
40 #include <signal.h>
41 #include <math.h>
42 #include <sys/time.h>
43
44 #include "bitmaps/icon.xbm"
45 #include "bitmaps/cursor.xbm"
46 #include "bitmaps/cursor_mask.xbm"
47
48 #include "bitmaps/space.xbm"
49
50 #include "bitmaps/mati2.xbm"
51 #include "bitmaps/jare2.xbm"
52 #include "bitmaps/kaki1.xbm"
53 #include "bitmaps/kaki2.xbm"
54 #include "bitmaps/mati3.xbm"
55 #include "bitmaps/sleep1.xbm"
56 #include "bitmaps/sleep2.xbm"
57
58 #include "bitmaps/awake.xbm"
59
60 #include "bitmaps/up1.xbm"
61 #include "bitmaps/up2.xbm"
62 #include "bitmaps/down1.xbm"
63 #include "bitmaps/down2.xbm"
64 #include "bitmaps/left1.xbm"
65 #include "bitmaps/left2.xbm"
66 #include "bitmaps/right1.xbm"
67 #include "bitmaps/right2.xbm"
68 #include "bitmaps/upright1.xbm"
69 #include "bitmaps/upright2.xbm"
70 #include "bitmaps/upleft1.xbm"
71 #include "bitmaps/upleft2.xbm"
72 #include "bitmaps/dwleft1.xbm"
73 #include "bitmaps/dwleft2.xbm"
74 #include "bitmaps/dwright1.xbm"
75 #include "bitmaps/dwright2.xbm"
76
77 #include "bitmaps/utogi1.xbm"
78 #include "bitmaps/utogi2.xbm"
79 #include "bitmaps/dtogi1.xbm"
80 #include "bitmaps/dtogi2.xbm"
81 #include "bitmaps/ltogi1.xbm"
82 #include "bitmaps/ltogi2.xbm"
83 #include "bitmaps/rtogi1.xbm"
84 #include "bitmaps/rtogi2.xbm"
85
86 #define BITMAP_WIDTH            32
87 #define BITMAP_HEIGHT           32
88 #define WINDOW_WIDTH            320
89 #define WINDOW_HEIGHT           256
90 #define DEFAULT_BORDER          2
91 #define DEFAULT_WIN_X           1
92 #define DEFAULT_WIN_Y           1
93 #define AVAIL_KEYBUF            255
94
95 #define EVENT_MASK       ( XCBEventMaskKeyPress | XCBEventMaskButtonPress | \
96                                                    XCBEventMaskExposure | XCBEventMaskStructureNotify )
97
98 #define EVENT_MASK_ROOT  ( XCBEventMaskKeyPress | XCBEventMaskExposure )
99
100 #define MAX_TICK                9999            /* Odd Only! */
101 #define INTERVAL                125000L
102 #define NEKO_SPEED              16
103 #define IDLE_SPACE              6
104 #define NORMAL_STATE    1
105 #define DEBUG_LIST              2
106 #define DEBUG_MOVE              3
107
108 #define NEKO_STOP               0
109 #define NEKO_JARE               1
110 #define NEKO_KAKI               2
111 #define NEKO_AKUBI              3
112 #define NEKO_SLEEP              4
113 #define NEKO_AWAKE              5
114 #define NEKO_U_MOVE             6
115 #define NEKO_D_MOVE             7
116 #define NEKO_L_MOVE             8
117 #define NEKO_R_MOVE             9
118 #define NEKO_UL_MOVE    10
119 #define NEKO_UR_MOVE    11
120 #define NEKO_DL_MOVE    12
121 #define NEKO_DR_MOVE    13
122 #define NEKO_U_TOGI             14
123 #define NEKO_D_TOGI             15
124 #define NEKO_L_TOGI             16
125 #define NEKO_R_TOGI             17
126
127 #define NEKO_STOP_TIME          4
128 #define NEKO_JARE_TIME          10
129 #define NEKO_KAKI_TIME          4
130 #define NEKO_AKUBI_TIME         3
131 #define NEKO_AWAKE_TIME         3
132 #define NEKO_TOGI_TIME          10
133
134 #define PI_PER8                 ((double)3.1415926535/(double)8)
135
136 #define DIRNAMELEN              255
137
138 static int  useRoot;
139 char        *fgColor, *bgColor;
140
141 static char  *ProgramName;
142
143 /*Display        *theDisplay;*/
144 XCBConnection   *xc;
145 XCBSCREEN      *theScreen;              /* instead of macro(theDisplay, int theScreen) */
146 unsigned int   theDepth;
147 unsigned long  theBlackPixel;
148 unsigned long  theWhitePixel;
149 XCBWINDOW         theWindow;
150 XCBCURSOR         theCursor;
151
152 static unsigned int  WindowWidth;
153 static unsigned int  WindowHeight;
154 static int           WindowPointX;
155 static int           WindowPointY;
156
157 static unsigned int     BorderWidth = DEFAULT_BORDER;
158
159 long    IntervalTime = INTERVAL;
160
161 int             EventState;
162
163 int             NekoTickCount;
164 int             NekoStateCount;
165 int             NekoState;
166
167 int             MouseX;
168 int             MouseY;
169
170 int             PrevMouseX = 0;
171 int             PrevMouseY = 0;
172
173 int             NekoX;
174 int             NekoY;
175
176 int             NekoMoveDx;
177 int             NekoMoveDy;
178
179 int             NekoLastX;
180 int             NekoLastY;
181 XCBGCONTEXT             NekoLastGC;
182
183 double  NekoSpeed = (double)NEKO_SPEED;
184
185 double  SinPiPer8Times3;
186 double  SinPiPer8;
187
188 XCBPIXMAP       SpaceXbm;
189
190 XCBPIXMAP       Mati2Xbm;
191 XCBPIXMAP       Jare2Xbm;
192 XCBPIXMAP       Kaki1Xbm;
193 XCBPIXMAP       Kaki2Xbm;
194 XCBPIXMAP       Mati3Xbm;
195 XCBPIXMAP       Sleep1Xbm;
196 XCBPIXMAP       Sleep2Xbm;
197
198 XCBPIXMAP       AwakeXbm;
199
200 XCBPIXMAP       Up1Xbm;
201 XCBPIXMAP       Up2Xbm;
202 XCBPIXMAP       Down1Xbm;
203 XCBPIXMAP       Down2Xbm;
204 XCBPIXMAP       Left1Xbm;
205 XCBPIXMAP       Left2Xbm;
206 XCBPIXMAP       Right1Xbm;
207 XCBPIXMAP       Right2Xbm;
208 XCBPIXMAP       UpLeft1Xbm;
209 XCBPIXMAP       UpLeft2Xbm;
210 XCBPIXMAP       UpRight1Xbm;
211 XCBPIXMAP       UpRight2Xbm;
212 XCBPIXMAP       DownLeft1Xbm;
213 XCBPIXMAP       DownLeft2Xbm;
214 XCBPIXMAP       DownRight1Xbm;
215 XCBPIXMAP       DownRight2Xbm;
216
217 XCBPIXMAP       UpTogi1Xbm;
218 XCBPIXMAP       UpTogi2Xbm;
219 XCBPIXMAP       DownTogi1Xbm;
220 XCBPIXMAP       DownTogi2Xbm;
221 XCBPIXMAP       LeftTogi1Xbm;
222 XCBPIXMAP       LeftTogi2Xbm;
223 XCBPIXMAP       RightTogi1Xbm;
224 XCBPIXMAP       RightTogi2Xbm;
225
226 XCBGCONTEXT     SpaceGC;
227
228 XCBGCONTEXT     Mati2GC;
229 XCBGCONTEXT     Jare2GC;
230 XCBGCONTEXT     Kaki1GC;
231 XCBGCONTEXT     Kaki2GC;
232 XCBGCONTEXT     Mati3GC;
233 XCBGCONTEXT     Sleep1GC;
234 XCBGCONTEXT     Sleep2GC;
235
236 XCBGCONTEXT     AwakeGC;
237
238 XCBGCONTEXT     Up1GC;
239 XCBGCONTEXT     Up2GC;
240 XCBGCONTEXT     Down1GC;
241 XCBGCONTEXT     Down2GC;
242 XCBGCONTEXT     Left1GC;
243 XCBGCONTEXT     Left2GC;
244 XCBGCONTEXT     Right1GC;
245 XCBGCONTEXT     Right2GC;
246 XCBGCONTEXT     UpLeft1GC;
247 XCBGCONTEXT     UpLeft2GC;
248 XCBGCONTEXT     UpRight1GC;
249 XCBGCONTEXT     UpRight2GC;
250 XCBGCONTEXT     DownLeft1GC;
251 XCBGCONTEXT     DownLeft2GC;
252 XCBGCONTEXT     DownRight1GC;
253 XCBGCONTEXT     DownRight2GC;
254
255 XCBGCONTEXT     UpTogi1GC;
256 XCBGCONTEXT     UpTogi2GC;
257 XCBGCONTEXT     DownTogi1GC;
258 XCBGCONTEXT     DownTogi2GC;
259 XCBGCONTEXT     LeftTogi1GC;
260 XCBGCONTEXT     LeftTogi2GC;
261 XCBGCONTEXT     RightTogi1GC;
262 XCBGCONTEXT     RightTogi2GC;
263
264 typedef struct {
265   XCBGCONTEXT            *GCCreatePtr;
266   XCBPIXMAP        *BitmapCreatePtr;
267   char          *PixelPattern;
268   unsigned int  PixelWidth;
269   unsigned int  PixelHeight;
270 } BitmapGCData;
271
272 BitmapGCData    BitmapGCDataTable[] = {
273   { &SpaceGC, &SpaceXbm, space_bits, space_width, space_height },
274   { &Mati2GC, &Mati2Xbm, mati2_bits, mati2_width, mati2_height },
275   { &Jare2GC, &Jare2Xbm, jare2_bits, jare2_width, jare2_height },
276   { &Kaki1GC, &Kaki1Xbm, kaki1_bits, kaki1_width, kaki1_height },
277   { &Kaki2GC, &Kaki2Xbm, kaki2_bits, kaki2_width, kaki2_height },
278   { &Mati3GC, &Mati3Xbm, mati3_bits, mati3_width, mati3_height },
279   { &Sleep1GC, &Sleep1Xbm, sleep1_bits, sleep1_width, sleep1_height },
280   { &Sleep2GC, &Sleep2Xbm, sleep2_bits, sleep2_width, sleep2_height },
281   { &AwakeGC, &AwakeXbm, awake_bits, awake_width, awake_height },
282   { &Up1GC, &Up1Xbm, up1_bits, up1_width, up1_height },
283   { &Up2GC, &Up2Xbm, up2_bits, up2_width, up2_height },
284   { &Down1GC, &Down1Xbm, down1_bits, down1_width, down1_height },
285   { &Down2GC, &Down2Xbm, down2_bits, down2_width, down2_height },
286   { &Left1GC, &Left1Xbm, left1_bits, left1_width, left1_height },
287   { &Left2GC, &Left2Xbm, left2_bits, left2_width, left2_height },
288   { &Right1GC, &Right1Xbm, right1_bits, right1_width, right1_height },
289   { &Right2GC, &Right2Xbm, right2_bits, right2_width, right2_height },
290   { &UpLeft1GC, &UpLeft1Xbm, upleft1_bits, upleft1_width, upleft1_height },
291   { &UpLeft2GC, &UpLeft2Xbm, upleft2_bits, upleft2_width, upleft2_height },
292   { &UpRight1GC,
293           &UpRight1Xbm, upright1_bits, upright1_width, upright1_height },
294   { &UpRight2GC,
295       &UpRight2Xbm, upright2_bits, upright2_width, upright2_height },
296   { &DownLeft1GC, &DownLeft1Xbm, dwleft1_bits, dwleft1_width, dwleft1_height },
297   { &DownLeft2GC, &DownLeft2Xbm, dwleft2_bits, dwleft2_width, dwleft2_height },
298   { &DownRight1GC,
299           &DownRight1Xbm, dwright1_bits, dwright1_width, dwright1_height },
300   { &DownRight2GC,
301       &DownRight2Xbm, dwright2_bits, dwright2_width, dwright2_height },
302   { &UpTogi1GC, &UpTogi1Xbm, utogi1_bits, utogi1_width, utogi1_height },
303   { &UpTogi2GC, &UpTogi2Xbm, utogi2_bits, utogi2_width, utogi2_height },
304   { &DownTogi1GC, &DownTogi1Xbm, dtogi1_bits, dtogi1_width, dtogi1_height },
305   { &DownTogi2GC, &DownTogi2Xbm, dtogi2_bits, dtogi2_width, dtogi2_height },
306   { &LeftTogi1GC, &LeftTogi1Xbm, ltogi1_bits, ltogi1_width, ltogi1_height },
307   { &LeftTogi2GC, &LeftTogi2Xbm, ltogi2_bits, ltogi2_width, ltogi2_height },
308   { &RightTogi1GC,
309       &RightTogi1Xbm, rtogi1_bits, rtogi1_width, rtogi1_height },
310   { &RightTogi2GC,
311       &RightTogi2Xbm, rtogi2_bits, rtogi2_width, rtogi2_height },
312   { NULL, NULL, NULL, 0, 0 }
313 };
314
315 typedef struct {
316   XCBGCONTEXT  *TickEvenGCPtr;
317   XCBGCONTEXT  *TickOddGCPtr;
318 } Animation;
319
320 Animation  AnimationPattern[] = {
321   { &Mati2GC, &Mati2GC },               /* NekoState == NEKO_STOP */
322   { &Jare2GC, &Mati2GC },               /* NekoState == NEKO_JARE */
323   { &Kaki1GC, &Kaki2GC },               /* NekoState == NEKO_KAKI */
324   { &Mati3GC, &Mati3GC },               /* NekoState == NEKO_AKUBI */
325   { &Sleep1GC, &Sleep2GC },             /* NekoState == NEKO_SLEEP */
326   { &AwakeGC, &AwakeGC },               /* NekoState == NEKO_AWAKE */
327   { &Up1GC, &Up2GC }    ,               /* NekoState == NEKO_U_MOVE */
328   { &Down1GC, &Down2GC },               /* NekoState == NEKO_D_MOVE */
329   { &Left1GC, &Left2GC },               /* NekoState == NEKO_L_MOVE */
330   { &Right1GC, &Right2GC },             /* NekoState == NEKO_R_MOVE */
331   { &UpLeft1GC, &UpLeft2GC },           /* NekoState == NEKO_UL_MOVE */
332   { &UpRight1GC, &UpRight2GC },     /* NekoState == NEKO_UR_MOVE */
333   { &DownLeft1GC, &DownLeft2GC },       /* NekoState == NEKO_DL_MOVE */
334   { &DownRight1GC, &DownRight2GC },     /* NekoState == NEKO_DR_MOVE */
335   { &UpTogi1GC, &UpTogi2GC },           /* NekoState == NEKO_U_TOGI */
336   { &DownTogi1GC, &DownTogi2GC },       /* NekoState == NEKO_D_TOGI */
337   { &LeftTogi1GC, &LeftTogi2GC },       /* NekoState == NEKO_L_TOGI */
338   { &RightTogi1GC, &RightTogi2GC },     /* NekoState == NEKO_R_TOGI */
339 };
340
341
342 /* PutImage.c: format/unit/order conversion should move out to a library */
343 static unsigned char const _reverse_byte[0x100] = {
344         0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
345         0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
346         0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
347         0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
348         0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
349         0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
350         0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
351         0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
352         0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
353         0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
354         0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
355         0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
356         0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
357         0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
358         0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
359         0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
360         0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
361         0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
362         0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
363         0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
364         0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
365         0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
366         0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
367         0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
368         0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
369         0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
370         0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
371         0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
372         0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
373         0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
374         0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
375         0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
376 };
377
378 /* convert 1Ll <--> 4Mm */
379 static void
380 SwapBits(
381     register unsigned char *src,
382     register unsigned char *dest,
383     long srclen, long srcinc, long destinc,
384     unsigned int height)
385 {
386     register long h, n;
387     register const unsigned char *rev = _reverse_byte;
388
389     srcinc -= srclen;
390     destinc -= srclen;
391     for (h = height; --h >= 0; src += srcinc, dest += destinc)
392         for (n = srclen; --n >= 0; )
393             *dest++ = rev[*src++];
394 }
395
396 /* assumes pad is a power of 2 */
397 #define ROUNDUP(nbytes, pad) (((nbytes) + ((pad) - 1)) & ~(long)((pad) - 1))
398
399 /* CrPFBData.c and CrBFData.c (very similar) */
400 /*  if depth==1, behaves like CreateBitmapFromData */
401 XCBPIXMAP CreatePixmapFromBitmapData( XCBConnection *c,
402         XCBWINDOW window, char *data, CARD16 w, CARD16 h,
403         CARD32 fg, CARD32 bg, CARD32 depth)
404 {
405   XCBDRAWABLE drawable;
406   XCBPIXMAP bitmap = XCBPIXMAPNew( c );
407
408   drawable.window = window;
409   XCBCreatePixmap( c, depth, bitmap, drawable, w, h );
410   
411   XCBGCONTEXT gc = XCBGCONTEXTNew( c );
412   
413   CARD32 mask = (depth==1 ? 0 : XCBGCForeground | XCBGCBackground);
414   CARD32 values[] = { fg, bg };
415
416   drawable.pixmap = bitmap;
417   XCBCreateGC( c, gc, drawable, mask, values );
418   
419   /* XImage attributes: bpp=1, xoffset=0,
420        byte_order=bit_order=LSB, unit=8, pad=8,   bpl=(w+7/8) */
421
422   /*  must swap and pad the data if bit/byte_order isn't LSB (Mac) */
423   
424   /* Mac X Server: byte_order=bit_order=MSB, unit=32, padding=32 */
425   long bufLen = (w+7)/8*h;
426   BYTE buf[1024];
427   if (XCBGetSetup(c)->bitmap_format_scanline_unit == 32 &&
428       XCBGetSetup(c)->bitmap_format_bit_order == XCBImageOrderMSBFirst &&
429       XCBGetSetup(c)->image_byte_order == XCBImageOrderMSBFirst)
430   {
431     long bpl = (w+7)/8;
432     long pad = XCBGetSetup(c)->bitmap_format_scanline_pad;
433     long bpd = ROUNDUP(w, pad)>>3;
434     SwapBits((unsigned char *)data, (unsigned char *)buf, bpl, bpl, bpd, h);
435     bufLen = bpd * h;
436   }
437   else
438     memcpy(buf, data, bufLen);
439
440   /* note: CBfD uses XYPixmap, but CPfBD uses XYBitmap
441            there shouldn't be a difference when depth==1,
442            but the neko images are corrupt if using XYPixmap */
443   CARD8 format = (depth==1 ? XCBImageFormatXYPixmap : XCBImageFormatXYBitmap);
444   
445   /* PutImage.c: left_pad = (image->xoffset + req->xoffset) & (dpy->bitmap_unit-1)
446        screen->bitmap_format_scanline_unit
447        left_pad = (0 + 0) & (32 - 1) = 0 */
448
449   XCBPutImage( c, format, drawable, gc,
450         w, h, 0, 0,
451         0, 1,           /* left_pad, depth */
452         bufLen, buf);
453
454 #if DEBUG
455   XCBGenericError *error = NULL;
456   XCBSync( c, &error );
457   if (error) {
458     printf("error code %d", (int)error->error_code);
459     free(error);
460   }
461 #endif
462
463   XCBFreeGC( c, gc );
464   
465   /* later: XCBFreePixmap( c, bitmap ); */
466   return bitmap;
467 }
468
469 XCBPIXMAP CreateBitmapFromData(XCBConnection *c, XCBWINDOW window,
470         char *data, CARD16 w, CARD16 h)
471 {
472         CARD32 depth = 1;
473         return CreatePixmapFromBitmapData(c, window, data, w, h, 0, 0, depth);
474 }
475
476 void  InitBitmapAndGCs(void) {
477   BitmapGCData  *BitmapGCDataTablePtr;
478   CARD32 theGCValues[5];
479   XCBDRAWABLE drawable;   drawable.window = theWindow;
480
481   theGCValues[0] = XCBGXcopy;
482
483   theGCValues[1] = theBlackPixel;
484   theGCValues[2] = theWhitePixel;
485
486   theGCValues[3] = XCBFillStyleTiled;
487   
488   /* TODO: latency: make all the bitmaps, then all the contexts? */
489
490   for ( BitmapGCDataTablePtr = BitmapGCDataTable;
491         BitmapGCDataTablePtr->GCCreatePtr != NULL;
492         BitmapGCDataTablePtr++ ) {
493
494         *(BitmapGCDataTablePtr->BitmapCreatePtr)
495           = CreatePixmapFromBitmapData( xc, theScreen->root,
496                 BitmapGCDataTablePtr->PixelPattern,
497                 BitmapGCDataTablePtr->PixelWidth,
498                 BitmapGCDataTablePtr->PixelHeight,
499                 theBlackPixel, theWhitePixel, theScreen->root_depth);
500
501         theGCValues[4] = BitmapGCDataTablePtr->BitmapCreatePtr->xid; /* tile */
502         
503         *(BitmapGCDataTablePtr->GCCreatePtr) = XCBGCONTEXTNew( xc );
504         XCBCreateGC( xc, *(BitmapGCDataTablePtr->GCCreatePtr), drawable,
505                   XCBGCFunction | XCBGCForeground | XCBGCBackground |
506                   XCBGCFillStyle | XCBGCTile,
507                   theGCValues );
508   }
509   
510   /* later: XCBFreePixmap( c, bitmap ); */
511   /* later: XCBFreeGC( c, gc ); */
512   XCBFlush( xc );
513 }
514
515 void
516 InitScreen( char *DisplayName, char *theGeometry, char *theTitle, Bool iconicState )
517 {
518   XCBPIXMAP             theCursorSource;
519   XCBPIXMAP             theCursorMask;
520   XCBCOLORMAP           theColormap;
521   int screen;
522   
523   if ( ( xc = XCBConnect( DisplayName, &screen ) ) == NULL ) {
524         fprintf( stderr, "%s: Can't open connection", ProgramName );
525         if ( DisplayName != NULL )
526           fprintf( stderr, " %s.\n", DisplayName );
527         else
528           fprintf( stderr, ".\n" );
529         exit( 1 );
530   }
531   
532   theScreen = XCBAuxGetScreen(xc, screen);
533   if (theScreen == NULL) {
534         fprintf( stderr, "%s: Can't get default screen", ProgramName );
535         exit( 1 );
536   }
537   
538   theDepth    = theScreen->root_depth;  /* DefaultDepth */
539   theColormap = theScreen->default_colormap;
540
541   WindowPointX = DEFAULT_WIN_X;
542   WindowPointY = DEFAULT_WIN_Y;
543   WindowWidth  = WINDOW_WIDTH;
544   WindowHeight = WINDOW_HEIGHT;
545
546 #ifdef TODO  
547   int                   GeometryStatus;
548   GeometryStatus = XParseGeometry( theGeometry,
549                                                                   &WindowPointX, &WindowPointY,
550                                                                   &WindowWidth, &WindowHeight );
551 #endif
552   
553   theCursorSource = CreateBitmapFromData( xc,
554                                                                                   theScreen->root,
555                                                                                   cursor_bits,
556                                                                                   cursor_width,
557                                                                                   cursor_height );
558   
559   theCursorMask = CreateBitmapFromData( xc,
560                                                                                 theScreen->root,
561                                                                                 cursor_mask_bits,
562                                                                                 cursor_mask_width,
563                                                                                 cursor_mask_height );
564
565
566   if ( bgColor == NULL) bgColor = "white";
567   if ( fgColor == NULL) fgColor = "black";
568   
569   XCBAllocNamedColorCookie bgCookie = XCBAllocNamedColor ( xc,
570                 theColormap,  strlen(bgColor), bgColor );
571
572   XCBAllocNamedColorCookie fgCookie = XCBAllocNamedColor ( xc,
573                 theColormap,  strlen(fgColor), fgColor );
574                 
575   XCBAllocNamedColorRep *bgRep = XCBAllocNamedColorReply( xc, bgCookie, 0 );
576   if (!bgRep) {
577         fprintf( stderr,
578                         "%s: Can't allocate the background color %s.\n", ProgramName, bgColor );
579         exit( 1 );
580   }
581   theWhitePixel = bgRep->pixel;
582
583   XCBAllocNamedColorRep *fgRep = XCBAllocNamedColorReply( xc, fgCookie, 0 );
584   if (!fgRep) {
585         fprintf( stderr,
586                         "%s: Can't allocate the foreground color %s.\n", ProgramName, fgColor );
587         exit( 1 );
588   }
589   theBlackPixel = fgRep->pixel;
590   
591   theCursor = XCBCURSORNew( xc );
592   XCBCreateCursor ( xc, theCursor, theCursorSource, theCursorMask,
593         fgRep->visual_red, fgRep->visual_green, fgRep->visual_blue,
594         bgRep->visual_red, bgRep->visual_green, bgRep->visual_blue,
595         cursor_x_hot, cursor_y_hot );
596
597   free(bgRep);
598   free(fgRep);
599
600   if ( useRoot ) {
601     CARD32 rootAttributes[] = { EVENT_MASK_ROOT, theCursor.xid };
602         theWindow = theScreen->root;
603         XCBChangeWindowAttributes(xc, theWindow,
604                 XCBCWEventMask | XCBCWCursor, rootAttributes );
605   }
606   else {
607         XCBPIXMAP                theIconPixmap;
608
609         CARD32 theWindowAttributes[] = {
610                 theWhitePixel, /* background */
611                 theBlackPixel, /* border */
612                 False,         /* override_redirect */
613                 EVENT_MASK,
614                 theCursor.xid };
615
616         unsigned long theWindowMask = XCBCWBackPixel | XCBCWBorderPixel |
617           XCBCWOverrideRedirect | XCBCWEventMask | XCBCWCursor;
618         
619         theWindow = XCBWINDOWNew( xc );
620         XCBCreateWindow( xc,
621                 theDepth,
622                 theWindow,
623                 theScreen->root,
624                 WindowPointX, WindowPointY,
625                 WindowWidth, WindowHeight,
626                 BorderWidth,
627                 XCBWindowClassInputOutput,
628                 theScreen->root_visual, /* CopyFromParent */
629                 theWindowMask, theWindowAttributes );
630
631         theIconPixmap = CreateBitmapFromData( xc, theWindow,
632                                                                                   icon_bits, icon_width, icon_height );
633         
634 #ifdef TODO_ICCCM
635     /* Um... there is no function to send the hints...
636         WMHints              theWMHints;
637         WMHintsSetIconPixmap( &theHints, theIconPixmap );
638
639         if ( iconicState )
640           WMHintsSetIconic( &theHints );
641         else
642           WMHintsSetNormal( &theHints );
643     */
644         theWMHints.icon_pixmap = theIconPixmap;
645         
646         if ( iconicState )
647           theWMHints.initial_state = IconicState;
648         else
649           theWMHints.initial_state = NormalState;
650         
651         theWMHints.flags = IconPixmapHint | StateHint;
652         
653         XSetWMHints( theDisplay, theWindow, &theWMHints );
654 #endif
655
656 #ifdef TODO_ICCCM
657         /*
658         SizeHints *hints = AllocSizeHints();
659         SizeHintsSetPosition(hints, WindowPointX, WindowPointY);
660         SizeHintsSetSize(hints, WindowWidth, WindowHeight);
661         SetWMNormalHints(xc, theWindow, hints);
662         FreeSizeHints(hints);
663         */
664         XSizeHints            theSizeHints;
665
666         theSizeHints.flags = PPosition | PSize;
667         theSizeHints.x = WindowPointX;
668         theSizeHints.y = WindowPointY;
669         theSizeHints.width = WindowWidth;
670         theSizeHints.height = WindowHeight;
671         
672         XSetNormalHints( theDisplay, theWindow, &theSizeHints );
673 #endif
674
675         /* Um, why do I have to specify the encoding in this API? */
676         SetWMName( xc, theWindow, STRING, strlen(theTitle), theTitle );
677         SetWMIconName( xc, theWindow, STRING, strlen(theTitle), theTitle );
678
679         XCBMapWindow( xc, theWindow );
680
681     /* moved to the CreateWindow attribute list */
682         /* XSelectInput( theDisplay, theWindow, EVENT_MASK ); */
683
684   }
685   
686 #ifdef TODO
687   /* is this really necessary? */
688   XSetWindowBackground( theDisplay, theWindow, theWhitePixel );
689   XClearWindow( theDisplay, theWindow );
690   XFlush( theDisplay );
691
692   XCBWINDOW             theRoot;
693   XGetGeometry( theDisplay, theWindow, &theRoot,
694                            &WindowPointX, &WindowPointY, &WindowWidth, &WindowHeight,
695                            &BorderWidth, &theDepth );
696 #endif
697
698   InitBitmapAndGCs();
699
700   XCBFlush(xc);
701 }
702
703
704 void  Interval(void) {
705   pause();
706 }
707
708
709 void  TickCount(void) {
710   if ( ++NekoTickCount >= MAX_TICK )
711         NekoTickCount = 0;
712   
713   if ( NekoTickCount % 2 == 0 )
714         if ( NekoStateCount < MAX_TICK )
715           NekoStateCount++;
716 }
717
718
719 void
720 SetNekoState( int SetValue )
721 {
722   NekoTickCount = 0;
723   NekoStateCount = 0;
724   
725   NekoState = SetValue;
726   
727 #ifdef  DEBUG
728   switch ( NekoState ) {
729   case NEKO_STOP:
730   case NEKO_JARE:
731   case NEKO_KAKI:
732   case NEKO_AKUBI:
733   case NEKO_SLEEP:
734   case NEKO_U_TOGI:
735   case NEKO_D_TOGI:
736   case NEKO_L_TOGI:
737   case NEKO_R_TOGI:
738         NekoMoveDx = NekoMoveDy = 0;
739         break;
740   default:
741         break;
742   }
743 #endif
744 }
745
746 /* FillRct.c */
747 /*   Xlib does merging of requests, but the Flush and frequent DrawGC changes
748      defeat this mechanism */
749
750 void
751 DrawNeko( int x, int y, XCBGCONTEXT DrawGC )
752 {
753   XCBDRAWABLE drawable;  drawable.window = theWindow;
754   XCBRECTANGLE rect = { NekoLastX, NekoLastY, BITMAP_WIDTH, BITMAP_HEIGHT };
755
756   if ( (x != NekoLastX || y != NekoLastY) && (EventState != DEBUG_LIST) )
757   {
758         XCBPolyFillRectangle( xc, drawable, SpaceGC, 1, &rect );
759         rect.x = x; rect.y = y;
760
761   }
762
763   CARD32 originMask = XCBGCTileStippleOriginX | XCBGCTileStippleOriginY;
764   CARD32 origin[2] = { x, y };
765   XCBChangeGC( xc, DrawGC, originMask, origin );
766   /* XSetTSOrigin( theDisplay, DrawGC, x, y ); */
767
768   XCBPolyFillRectangle( xc, drawable, DrawGC, 1, &rect );
769
770   XCBFlush( xc );
771
772   NekoLastX = x;
773   NekoLastY = y;
774   
775   NekoLastGC = DrawGC;
776 }
777
778
779 void  RedrawNeko(void) {
780   XCBDRAWABLE drawable;  drawable.window = theWindow;
781   XCBRECTANGLE rect = { NekoLastX, NekoLastY, BITMAP_WIDTH, BITMAP_HEIGHT };
782
783   XCBPolyFillRectangle( xc, drawable, NekoLastGC, 1, &rect );
784
785   XCBFlush( xc );
786 }
787
788
789
790 void  NekoDirection(void) {
791   int                   NewState;
792   double                LargeX, LargeY;
793   double                Length;
794   double                SinTheta;
795   
796   if ( NekoMoveDx == 0 && NekoMoveDy == 0 ) {
797         NewState = NEKO_STOP;
798   } else {
799         LargeX = (double)NekoMoveDx;
800         LargeY = (double)(-NekoMoveDy);
801         Length = sqrt( LargeX * LargeX + LargeY * LargeY );
802         SinTheta = LargeY / Length;
803         
804         if ( NekoMoveDx > 0 ) {
805           if ( SinTheta > SinPiPer8Times3 ) {
806                 NewState = NEKO_U_MOVE;
807           } else if ( ( SinTheta <= SinPiPer8Times3 )
808                                  && ( SinTheta > SinPiPer8 ) ) {
809                 NewState = NEKO_UR_MOVE;
810           } else if ( ( SinTheta <= SinPiPer8 )
811                                  && ( SinTheta > -( SinPiPer8 ) ) ) {
812                 NewState = NEKO_R_MOVE;
813           } else if ( ( SinTheta <= -( SinPiPer8 ) )
814                                  && ( SinTheta > -( SinPiPer8Times3 ) ) ) {
815                 NewState = NEKO_DR_MOVE;
816           } else {
817                 NewState = NEKO_D_MOVE;
818           }
819         } else {
820           if ( SinTheta > SinPiPer8Times3 ) {
821                 NewState = NEKO_U_MOVE;
822           } else if ( ( SinTheta <= SinPiPer8Times3 )
823                                  && ( SinTheta > SinPiPer8 ) ) {
824                 NewState = NEKO_UL_MOVE;
825           } else if ( ( SinTheta <= SinPiPer8 )
826                                  && ( SinTheta > -( SinPiPer8 ) ) ) {
827                 NewState = NEKO_L_MOVE;
828           } else if ( ( SinTheta <= -( SinPiPer8 ) )
829                                  && ( SinTheta > -( SinPiPer8Times3 ) ) ) {
830                 NewState = NEKO_DL_MOVE;
831           } else {
832                 NewState = NEKO_D_MOVE;
833           }
834         }
835   }
836   
837   if ( NekoState != NewState ) {
838         SetNekoState( NewState );
839   }
840 }
841
842
843 Bool  IsWindowOver(void) {
844   Bool  ReturnValue = False;
845   
846   if ( NekoY <= 0 ) {
847         NekoY = 0;
848         ReturnValue = True;
849   } else if ( NekoY >= WindowHeight - BITMAP_HEIGHT ) {
850         NekoY = WindowHeight - BITMAP_HEIGHT;
851         ReturnValue = True;
852   }
853   if ( NekoX <= 0 ) {
854         NekoX = 0;
855         ReturnValue = True;
856   } else if ( NekoX >= WindowWidth - BITMAP_WIDTH ) {
857         NekoX = WindowWidth - BITMAP_WIDTH;
858         ReturnValue = True;
859   }
860   
861   return( ReturnValue );
862 }
863
864
865 Bool  IsNekoDontMove(void) {
866   return( NekoX == NekoLastX  &&  NekoY == NekoLastY );
867 }
868
869
870 Bool  IsNekoMoveStart(void) {
871 #ifndef DEBUG
872   if ( (PrevMouseX >= MouseX - IDLE_SPACE
873                 && PrevMouseX <= MouseX + IDLE_SPACE) &&
874           (PrevMouseY >= MouseY - IDLE_SPACE 
875            && PrevMouseY <= MouseY + IDLE_SPACE) )
876         return( False );
877   else
878         return( True );
879 #else
880   if ( NekoMoveDx == 0 && NekoMoveDy == 0 )
881         return( False );
882   else
883         return( True );
884 #endif
885 }
886
887 #ifndef DEBUG
888 void  CalcDxDy(void) {
889   int                   RelativeX, RelativeY;
890   double                LargeX, LargeY;
891   double                DoubleLength, Length;
892   
893   /* TODO: replace query with pointer motion notification? */
894
895   XCBQueryPointerRep *reply = XCBQueryPointerReply( xc,
896         XCBQueryPointer( xc, theWindow ), NULL);
897         
898   RelativeX = reply->win_x;
899   RelativeY = reply->win_y;
900   
901   free(reply);
902
903   PrevMouseX = MouseX;
904   PrevMouseY = MouseY;
905   
906   MouseX = RelativeX;
907   MouseY = RelativeY;
908   
909   LargeX = (double)( MouseX - NekoX - BITMAP_WIDTH / 2 );
910   LargeY = (double)( MouseY - NekoY - BITMAP_HEIGHT );
911   
912   DoubleLength = LargeX * LargeX + LargeY * LargeY;
913   
914   if ( DoubleLength != (double)0 ) {
915         Length = sqrt( DoubleLength );
916         if ( Length <= NekoSpeed ) {
917           NekoMoveDx = (int)LargeX;
918           NekoMoveDy = (int)LargeY;
919         } else {
920           NekoMoveDx = (int)( ( NekoSpeed * LargeX ) / Length );
921           NekoMoveDy = (int)( ( NekoSpeed * LargeY ) / Length );
922         }
923   } else {
924         NekoMoveDx = NekoMoveDy = 0;
925   }
926 }
927 #endif
928
929 void  NekoThinkDraw(void) {
930 #ifndef DEBUG
931   CalcDxDy();
932 #endif
933
934   if ( NekoState != NEKO_SLEEP ) {
935         DrawNeko( NekoX, NekoY,
936                          NekoTickCount % 2 == 0 ?
937                          *(AnimationPattern[ NekoState ].TickEvenGCPtr) :
938                          *(AnimationPattern[ NekoState ].TickOddGCPtr) );
939   } else {
940         DrawNeko( NekoX, NekoY,
941                          NekoTickCount % 8 <= 3 ?
942                          *(AnimationPattern[ NekoState ].TickEvenGCPtr) :
943                          *(AnimationPattern[ NekoState ].TickOddGCPtr) );
944   }
945   
946   TickCount();
947   
948   switch ( NekoState ) {
949   case NEKO_STOP:
950         if ( IsNekoMoveStart() ) {
951           SetNekoState( NEKO_AWAKE );
952           break;
953         }
954         if ( NekoStateCount < NEKO_STOP_TIME ) {
955           break;
956         }
957         if ( NekoMoveDx < 0 && NekoX <= 0 ) {
958           SetNekoState( NEKO_L_TOGI );
959         } else if ( NekoMoveDx > 0 && NekoX >= WindowWidth - BITMAP_WIDTH ) {
960           SetNekoState( NEKO_R_TOGI );
961         } else if ( NekoMoveDy < 0 && NekoY <= 0 ) {
962           SetNekoState( NEKO_U_TOGI );
963         } else if ( NekoMoveDy > 0 && NekoY >= WindowHeight - BITMAP_HEIGHT ) {
964           SetNekoState( NEKO_D_TOGI );
965         } else {
966           SetNekoState( NEKO_JARE );
967         }
968         break;
969   case NEKO_JARE:
970         if ( IsNekoMoveStart() ) {
971           SetNekoState( NEKO_AWAKE );
972           break;
973         }
974         if ( NekoStateCount < NEKO_JARE_TIME ) {
975           break;
976         }
977         SetNekoState( NEKO_KAKI );
978         break;
979   case NEKO_KAKI:
980         if ( IsNekoMoveStart() ) {
981           SetNekoState( NEKO_AWAKE );
982           break;
983         }
984         if ( NekoStateCount < NEKO_KAKI_TIME ) {
985           break;
986         }
987         SetNekoState( NEKO_AKUBI );
988         break;
989   case NEKO_AKUBI:
990         if ( IsNekoMoveStart() ) {
991           SetNekoState( NEKO_AWAKE );
992           break;
993         }
994         if ( NekoStateCount < NEKO_AKUBI_TIME ) {
995           break;
996         }
997         SetNekoState( NEKO_SLEEP );
998         break;
999   case NEKO_SLEEP:
1000         if ( IsNekoMoveStart() ) {
1001           SetNekoState( NEKO_AWAKE );
1002           break;
1003         }
1004         break;
1005   case NEKO_AWAKE:
1006         if ( NekoStateCount < NEKO_AWAKE_TIME ) {
1007           break;
1008         }
1009         NekoDirection();
1010         break;
1011   case NEKO_U_MOVE:
1012   case NEKO_D_MOVE:
1013   case NEKO_L_MOVE:
1014   case NEKO_R_MOVE:
1015   case NEKO_UL_MOVE:
1016   case NEKO_UR_MOVE:
1017   case NEKO_DL_MOVE:
1018   case NEKO_DR_MOVE:
1019         NekoX += NekoMoveDx;
1020         NekoY += NekoMoveDy;
1021         NekoDirection();
1022         if ( IsWindowOver() ) {
1023           if ( IsNekoDontMove() ) {
1024                 SetNekoState( NEKO_STOP );
1025           }
1026         }
1027         break;
1028   case NEKO_U_TOGI:
1029   case NEKO_D_TOGI:
1030   case NEKO_L_TOGI:
1031   case NEKO_R_TOGI:
1032         if ( IsNekoMoveStart() ) {
1033           SetNekoState( NEKO_AWAKE );
1034           break;
1035         }
1036         if ( NekoStateCount < NEKO_TOGI_TIME ) {
1037           break;
1038         }
1039         SetNekoState( NEKO_KAKI );
1040         break;
1041   default:
1042         /* Internal Error */
1043         SetNekoState( NEKO_STOP );
1044         break;
1045   }
1046   
1047   Interval();
1048 }
1049
1050
1051 #ifdef  DEBUG
1052 void  DisplayCharacters() {
1053   int           Index;
1054   int           x, y;
1055   
1056   for ( Index = 0, x = 0, y = 0;
1057            BitmapGCDataTable[ Index ].GCCreatePtr != NULL; Index++ ) {
1058         
1059         DrawNeko( x, y, *(BitmapGCDataTable[ Index ].GCCreatePtr) );
1060         XFlush( theDisplay );
1061         
1062         x += BITMAP_WIDTH;
1063         
1064         if ( x > WindowWidth - BITMAP_WIDTH ) {
1065           x = 0;
1066           y += BITMAP_HEIGHT;
1067           if ( y > WindowHeight - BITMAP_HEIGHT) {
1068                 break;
1069           }
1070         }
1071   }
1072 }
1073
1074 #endif  /* DEBUG */
1075
1076 Bool
1077 ProcessKeyPress( XCBKeyPressEvent *theKeyEvent )
1078 {
1079 #if TODO    
1080   Bool ReturnState = True;
1081
1082   int                   Length;
1083   char          theKeyBuffer[ AVAIL_KEYBUF + 1 ];
1084     int                 theKeyBufferMaxLen = AVAIL_KEYBUF;
1085   KeySym                theKeySym;
1086   XComposeStatus        theComposeStatus;
1087
1088   Length = XLookupString( theKeyEvent,
1089                                                  theKeyBuffer, theKeyBufferMaxLen,
1090                                                  &theKeySym, &theComposeStatus );
1091
1092   if ( Length > 0 ) {
1093         switch ( theKeyBuffer[ 0 ] ) {
1094         case 'q':
1095         case 'Q':
1096           if ( theKeyEvent->state & XCBModMask1 ) {     /* META (Alt) %-!< */
1097                 ReturnState = False;
1098           }
1099           break;
1100         default:
1101           break;
1102         }
1103   }
1104 #else
1105   /* quit on any key */
1106   Bool ReturnState = False;
1107 #endif
1108
1109
1110 #ifdef  DEBUG
1111   if ( EventState == DEBUG_MOVE ) {
1112         switch ( theKeySym ) {
1113         case XK_KP_1:
1114           NekoMoveDx = -(int)( NekoSpeed / sqrt( (double)2 ) );
1115           NekoMoveDy = -NekoMoveDx;
1116           break;
1117         case XK_KP_2:
1118           NekoMoveDx = 0;
1119           NekoMoveDy = (int)NekoSpeed;
1120           break;
1121         case XK_KP_3:
1122           NekoMoveDx = (int)( NekoSpeed / sqrt( (double)2 ) );
1123           NekoMoveDy = NekoMoveDx;
1124           break;
1125         case XK_KP_4:
1126           NekoMoveDx = -(int)NekoSpeed;
1127           NekoMoveDy = 0;
1128           break;
1129         case XK_KP_5:
1130           NekoMoveDx = 0;
1131           NekoMoveDy = 0;
1132           break;
1133         case XK_KP_6:
1134           NekoMoveDx = (int)NekoSpeed;
1135           NekoMoveDy = 0;
1136           break;
1137         case XK_KP_7:
1138           NekoMoveDx = -(int)( NekoSpeed / sqrt( (double)2 ) );
1139           NekoMoveDy = NekoMoveDx;
1140           break;
1141         case XK_KP_8:
1142           NekoMoveDx = 0;
1143           NekoMoveDy = -(int)NekoSpeed;
1144           break;
1145         case XK_KP_9:
1146           NekoMoveDx = (int)( NekoSpeed / sqrt( (double)2 ) );
1147           NekoMoveDy = -NekoMoveDx;
1148           break;
1149         }
1150   }
1151 #endif
1152   
1153   return( ReturnState );
1154 }
1155
1156
1157 void  NekoAdjust(void) {
1158   if ( NekoX < 0 )
1159         NekoX = 0;
1160   else if ( NekoX > WindowWidth - BITMAP_WIDTH )
1161         NekoX = WindowWidth - BITMAP_WIDTH;
1162
1163   if ( NekoY < 0 )
1164         NekoY = 0;
1165   else if ( NekoY > WindowHeight - BITMAP_HEIGHT )
1166         NekoY = WindowHeight - BITMAP_HEIGHT;
1167 }
1168
1169 Bool  ProcessEvent(void) {
1170   XCBGenericEvent *theEvent;
1171   XCBConfigureNotifyEvent *theConfigureNotification;
1172   XCBExposeEvent *theExposure;
1173   XCBButtonPressEvent *theButtonPress;
1174   Bool  ContinueState = True;
1175   int error = 0;
1176   
1177   switch ( EventState ) {
1178   case NORMAL_STATE:
1179     while ( NULL != (theEvent = XCBPollForEvent( xc, &error )) ) {  /*while ( XCheckMaskEvent( theDisplay, EVENT_MASK, &theEvent ) ) {*/
1180           switch ( theEvent->response_type ) {
1181           case XCBConfigureNotify:
1182             theConfigureNotification = (XCBConfigureNotifyEvent *)theEvent;
1183                 WindowWidth = theConfigureNotification->width;
1184                 WindowHeight = theConfigureNotification->height;
1185                 WindowPointX = theConfigureNotification->x;
1186                 WindowPointY = theConfigureNotification->y;
1187                 BorderWidth = theConfigureNotification->border_width;
1188                 NekoAdjust();
1189                 break;
1190           case XCBExpose:
1191             theExposure = (XCBExposeEvent *)theEvent;
1192                 if ( theExposure->count == 0 )
1193                   RedrawNeko();
1194                 break;
1195           case XCBMapNotify:
1196                 RedrawNeko();
1197                 break;
1198           case XCBKeyPress:
1199                 ContinueState = ProcessKeyPress( (XCBKeyPressEvent *)theEvent );
1200                 if ( !ContinueState ) {
1201                   free(theEvent);
1202                   return( ContinueState );
1203                 }
1204                 break;
1205           case XCBButtonPress:
1206             theButtonPress = (XCBButtonPressEvent *)theEvent;
1207                 if ( theButtonPress->detail.id == 3 ) { /* xbutton.button */
1208                   free(theEvent);
1209                   return( False );
1210                 }
1211                 break;
1212           default:
1213                 /* Unknown Event */
1214                 break;
1215           }
1216           free(theEvent);
1217           if (error != 0)
1218                 return False;
1219         }
1220         break;
1221 #ifdef  DEBUG
1222   case DEBUG_LIST:
1223         XNextEvent( theDisplay, &theEvent );
1224         switch ( theEvent.type ) {
1225         case ConfigureNotify:
1226           WindowWidth = theEvent.xconfigure.width;
1227           WindowHeight = theEvent.xconfigure.height;
1228           WindowPointX = theEvent.xconfigure.x;
1229           WindowPointY = theEvent.xconfigure.y;
1230           BorderWidth = theEvent.xconfigure.border_width;
1231           break;
1232         case Expose:
1233           if ( theEvent.xexpose.count == 0 )
1234                 DisplayCharacters();
1235           break;
1236         case MapNotify:
1237           DisplayCharacters();
1238           break;
1239         case KeyPress:
1240           ContinueState = ProcessKeyPress( &theEvent );
1241           break;
1242         case ButtonPress:
1243           if ( theEvent.xbutton.button == 3 )
1244                 return( False );
1245           break;
1246         default:
1247           /* Unknown Event */
1248           break;
1249         }
1250         break;
1251   case DEBUG_MOVE:
1252         while ( XCheckMaskEvent( theDisplay, EVENT_MASK, &theEvent ) ) {
1253           switch ( theEvent.type ) {
1254           case ConfigureNotify:
1255                 WindowWidth = theEvent.xconfigure.width;
1256                 WindowHeight = theEvent.xconfigure.height;
1257                 WindowPointX = theEvent.xconfigure.x;
1258                 WindowPointY = theEvent.xconfigure.y;
1259                 BorderWidth = theEvent.xconfigure.border_width;
1260                 NekoAdjust();
1261                 break;
1262           case Expose:
1263                 if ( theEvent.xexpose.count == 0 )
1264                   RedrawNeko();
1265                 break;
1266           case MapNotify:
1267                 RedrawNeko();
1268                 break;
1269           case KeyPress:
1270                 ContinueState = ProcessKeyPress( &theEvent );
1271                 if ( !ContinueState ) {
1272                   return( ContinueState );
1273                 }
1274                 break;
1275           case ButtonPress:
1276                 if ( theEvent.xbutton.button == 3 )
1277                   return( False );
1278                 break;
1279           default:
1280                 /* Unknown Event */
1281                 break;
1282           }
1283         }
1284         break;
1285 #endif
1286   default:
1287         /* Internal Error */
1288         break;
1289   }
1290   
1291   return( ContinueState );
1292 }
1293
1294
1295 void  ProcessNeko(void) {
1296   struct itimerval      Value;
1297   
1298   EventState = NORMAL_STATE;
1299
1300   NekoX = ( WindowWidth - BITMAP_WIDTH / 2 ) / 2;
1301   NekoY = ( WindowHeight - BITMAP_HEIGHT / 2 ) / 2;
1302   
1303   NekoLastX = NekoX;
1304   NekoLastY = NekoY;
1305   
1306   SetNekoState( NEKO_STOP );
1307   
1308   timerclear( &Value.it_interval );
1309   timerclear( &Value.it_value );
1310   
1311   Value.it_interval.tv_usec = IntervalTime;
1312   Value.it_value.tv_usec = IntervalTime;
1313   
1314   setitimer( ITIMER_REAL, &Value, 0 );
1315   
1316   do {
1317         NekoThinkDraw();
1318   } while ( ProcessEvent() );
1319 }
1320
1321 #ifdef  DEBUG
1322
1323 void  NekoList() {
1324   EventState = DEBUG_LIST;
1325   
1326   fprintf( stderr, "\n" );
1327   fprintf( stderr, "G-0lMw$rI=<($7$^$9!#(Quit !D Alt-Q)\n" );
1328   fprintf( stderr, "\n" );
1329   
1330   XSelectInput( theDisplay, theWindow, EVENT_MASK );
1331   
1332   while ( ProcessEvent() );
1333 }
1334
1335
1336 void  NekoMoveTest() {
1337   struct itimerval      Value;
1338   
1339   EventState = DEBUG_MOVE;
1340   
1341   NekoX = ( WindowWidth - BITMAP_WIDTH / 2 ) / 2;
1342   NekoY = ( WindowHeight - BITMAP_HEIGHT / 2 ) / 2;
1343   
1344   NekoLastX = NekoX;
1345   NekoLastY = NekoY;
1346   
1347   SetNekoState( NEKO_STOP );
1348   
1349   timerclear( &Value.it_interval );
1350   timerclear( &Value.it_value );
1351   
1352   Value.it_interval.tv_usec = IntervalTime;
1353   Value.it_value.tv_usec = IntervalTime;
1354   
1355   setitimer( ITIMER_REAL, &Value, 0 );
1356   
1357   fprintf( stderr, "\n" );
1358   fprintf( stderr, "G-$N0\F0%F%9%H$r9T$$$^$9!#(Quit !D Alt-Q)\n" );
1359   fprintf( stderr, "\n" );
1360   fprintf( stderr, "\t%-!<%Q%C%I>e$N%F%s%-!<$GG-$r0\F0$5$;$F2<$5$$!#\n" );
1361   fprintf( stderr, "\t(M-8z$J%-!<$O#1!A#9$G$9!#)\n" );
1362   fprintf( stderr, "\n" );
1363   
1364   do {
1365         NekoThinkDraw();
1366   } while ( ProcessEvent() );
1367 }
1368
1369
1370 void  ProcessDebugMenu() {
1371   int           UserSelectNo = 0;
1372   char  UserAnswer[ BUFSIZ ];
1373   
1374   fprintf( stderr, "\n" );
1375   fprintf( stderr, "!Zxneko %G%P%C%0%a%K%e!<![\n" );
1376   
1377   while ( !( UserSelectNo >= 1 && UserSelectNo <= 2 ) ) {
1378         fprintf( stderr, "\n" );
1379         fprintf( stderr, "\t1)!!G-%-%c%i%/%?!<0lMwI=<(\n" );
1380         fprintf( stderr, "\t2)!!G-0\F0%F%9%H\n" );
1381         fprintf( stderr, "\n" );
1382         fprintf( stderr, "Select: " );
1383
1384         fgets( UserAnswer, sizeof( UserAnswer ), stdin );
1385         
1386         UserSelectNo = atoi( UserAnswer );
1387         
1388         if ( !( UserSelectNo >= 1 && UserSelectNo <= 2 ) ) {
1389           fprintf( stderr, "\n" );
1390           fprintf( stderr, "@5$7$$HV9f$rA*Br$7$F2<$5$$!#\n" );
1391         }
1392   }
1393   
1394   switch ( UserSelectNo ) {
1395   case 1:
1396         NekoList();
1397         break;
1398   case 2:
1399         NekoMoveTest();
1400         break;
1401   default:
1402         /* Internal Error */
1403         break;
1404   }
1405   
1406   fprintf( stderr, "%F%9%H=*N;!#\n" );
1407   fprintf( stderr, "\n" );
1408 }
1409
1410 #endif  /* DEBUG */
1411
1412 void  NullFunction(int ignored)
1413 {
1414   /* signal( SIGALRM, NullFunction ); */
1415 }
1416
1417
1418 void  Usage(void) {
1419   fprintf( stderr,
1420                   "Usage: %s [-display <display>] [-geometry <geometry>] \\\n",
1421                   ProgramName );
1422   fprintf( stderr, "\t[-bg <background>] [-fg <foreground>] \\\n" );
1423   fprintf( stderr, "\t[-title <title>] [-name <title>] [-iconic] \\\n" );
1424   fprintf( stderr, "\t[-speed <speed>] [-time <time>] [-root] [-help]\n" );
1425 }
1426
1427
1428 Bool
1429 GetArguments( int argc, char *argv[],
1430         char *theDisplayName, char *theGeometry, char **theTitle,
1431         double *NekoSpeed, long *IntervalTime )
1432 {
1433   int           ArgCounter;
1434   Bool  iconicState;
1435   
1436   theDisplayName[ 0 ] = '\0';
1437   theGeometry[ 0 ] = '\0';
1438   
1439   iconicState = False;
1440   
1441   for ( ArgCounter = 0; ArgCounter < argc; ArgCounter++ ) {
1442         if ( strncmp( argv[ ArgCounter ], "-h", 2 ) == 0 ) {
1443           Usage();
1444           exit( 0 );
1445         } else if ( strcmp( argv[ ArgCounter ], "-display" ) == 0 ) {
1446           ArgCounter++;
1447           if ( ArgCounter < argc ) {
1448                 strcpy( theDisplayName, argv[ ArgCounter ] );
1449           } else {
1450                 fprintf( stderr, "%s: -display option error.\n", ProgramName );
1451                 exit( 1 );
1452           }
1453         } else if ( strncmp( argv[ ArgCounter ], "-geom", 5 ) == 0 ) {
1454           ArgCounter++;
1455           if ( ArgCounter < argc ) {
1456                 strcpy( theGeometry, argv[ ArgCounter ] );
1457           } else {
1458                 fprintf( stderr,
1459                                 "%s: -geometry option error.\n", ProgramName );
1460                 exit( 1 );
1461           }
1462         } else if ( ( strcmp( argv[ ArgCounter ], "-title" ) == 0 )
1463                            || ( strcmp( argv[ ArgCounter ], "-name" ) == 0 ) ) {
1464           ArgCounter++;
1465           if ( ArgCounter < argc ) {
1466             *theTitle = argv[ ArgCounter ];
1467           } else {
1468                 fprintf( stderr, "%s: -title option error.\n", ProgramName );
1469                 exit( 1 );
1470           }
1471         } else if ( strcmp( argv[ ArgCounter ], "-iconic" ) == 0 ) {
1472           iconicState = True;
1473         } else if ( strcmp( argv[ ArgCounter ], "-speed" ) == 0 ) {
1474           ArgCounter++;
1475           if ( ArgCounter < argc ) {
1476                 *NekoSpeed = atof( argv[ ArgCounter ] );
1477           } else {
1478                 fprintf( stderr, "%s: -speed option error.\n", ProgramName );
1479                 exit( 1 );
1480           }
1481         } else if ( strcmp( argv[ ArgCounter ], "-fg" ) == 0 ) {
1482           ArgCounter++;
1483           if ( ArgCounter < argc ) {
1484                 fgColor = argv[ArgCounter];
1485           } else {
1486                 fprintf( stderr, "%s: -fg option error.\n", ProgramName );
1487                 exit( 1 );
1488           }
1489         } else if ( strcmp( argv[ ArgCounter ], "-bg" ) == 0 ) {
1490           ArgCounter++;
1491           if ( ArgCounter < argc ) {
1492                 bgColor = argv[ArgCounter];
1493           } else {
1494                 fprintf( stderr, "%s: -bg option error.\n", ProgramName );
1495                 exit( 1 );
1496           }
1497         } else if ( strcmp( argv[ ArgCounter ], "-time" ) == 0 ) {
1498           ArgCounter++;
1499           if ( ArgCounter < argc ) {
1500                 *IntervalTime = atol( argv[ ArgCounter ] );
1501           } else {
1502                 fprintf( stderr, "%s: -time option error.\n", ProgramName );
1503                 exit( 1 );
1504           }
1505         } else if ( strcmp( argv[ ArgCounter ], "-root" ) == 0 ) {
1506           useRoot = 1;
1507         } else {
1508           fprintf( stderr,
1509                           "%s: Unknown option \"%s\".\n", ProgramName,
1510                           argv[ ArgCounter ] );
1511           Usage();
1512           exit( 1 );
1513         }
1514   }
1515   
1516   return( iconicState );
1517 }
1518
1519 void UndefineCursor( XCBConnection *c, XCBWINDOW w)
1520 {
1521         CARD32 none[] = { XCBNone };
1522         XCBChangeWindowAttributes( c, w, XCBCWCursor, none );
1523 }
1524
1525 int
1526 main( int argc, char *argv[] )
1527 {
1528   Bool  iconicState;
1529   char  theDisplayName[ DIRNAMELEN ];
1530   char  theGeometry[ DIRNAMELEN ];
1531   char  *theTitle = "";
1532   
1533   ProgramName = argv[ 0 ];
1534   
1535   argc--;
1536   argv++;
1537   
1538   useRoot = 0;
1539   fgColor = bgColor = (char *) NULL;
1540   
1541   iconicState = GetArguments( argc, argv, theDisplayName, theGeometry,
1542                                                          &theTitle, &NekoSpeed, &IntervalTime );
1543   
1544   if (theTitle[0] == 0) theTitle = ProgramName;
1545   InitScreen( theDisplayName, theGeometry, theTitle, iconicState );
1546   
1547   signal( SIGALRM, NullFunction );
1548   
1549   SinPiPer8Times3 = sin( PI_PER8 * (double)3 );
1550   SinPiPer8 = sin( PI_PER8 );
1551
1552 #ifndef DEBUG
1553   ProcessNeko();
1554 #else
1555   ProcessDebugMenu();
1556 #endif
1557
1558   UndefineCursor( xc, theWindow );
1559   XCBDisconnect( xc );
1560   exit( 0 );
1561 }