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