neko: -root works
[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  theFgPixel;
147 unsigned long  theBgPixel;
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] = theFgPixel;
491   theGCValues[2] = theBgPixel;
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                 theFgPixel, theBgPixel, 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   /* mouse cursor is always black and white */
596   XCBAllocNamedColorCookie blackCookie = XCBAllocNamedColor ( xc,
597                 theColormap,  strlen("black"), "black" );
598   XCBAllocNamedColorCookie whiteCookie = XCBAllocNamedColor ( xc,
599                 theColormap,  strlen("white"), "white" );
600                 
601   XCBAllocNamedColorRep *bgRep = XCBAllocNamedColorReply( xc, bgCookie, 0 );
602   if (!bgRep) {
603         fprintf( stderr,
604                         "%s: Can't allocate the background color %s.\n", ProgramName, bgColor );
605         exit( 1 );
606   }
607   theBgPixel = bgRep->pixel;
608
609   XCBAllocNamedColorRep *fgRep = XCBAllocNamedColorReply( xc, fgCookie, 0 );
610   if (!fgRep) {
611         fprintf( stderr,
612                         "%s: Can't allocate the foreground color %s.\n", ProgramName, fgColor );
613         exit( 1 );
614   }
615   theFgPixel = fgRep->pixel;
616
617   XCBAllocNamedColorRep *blackRep = XCBAllocNamedColorReply( xc, blackCookie, 0 );
618   if (!blackRep) {
619         fprintf( stderr,
620                         "%s: Can't allocate the black color.\n", ProgramName );
621         exit( 1 );
622   }
623   XCBAllocNamedColorRep *whiteRep = XCBAllocNamedColorReply( xc, whiteCookie, 0 );
624   if (!whiteRep) {
625         fprintf( stderr,
626                         "%s: Can't allocate the white color.\n", ProgramName );
627         exit( 1 );
628   }
629   
630   theCursor = XCBCURSORNew( xc );
631   XCBCreateCursor ( xc, theCursor, theCursorSource, theCursorMask,
632         blackRep->visual_red, blackRep->visual_green, blackRep->visual_blue,
633         whiteRep->visual_red, whiteRep->visual_green, whiteRep->visual_blue,
634         cursor_x_hot, cursor_y_hot );
635
636   free(bgRep);
637   free(fgRep);
638   free(blackRep);
639   free(whiteRep);
640
641   if ( useRoot ) {
642     CARD32 rootAttributes[] = { theBgPixel, EVENT_MASK_ROOT, theCursor.xid };
643         theWindow = theScreen->root;
644         XCBChangeWindowAttributes(xc, theWindow,
645                 XCBCWBackPixel | XCBCWEventMask | XCBCWCursor, rootAttributes );
646         
647         /* XClearWindow: clear area with all dimensions 0 */
648         XCBClearArea( xc, False, theWindow, 0, 0, 0, 0 );
649         
650         XCBDRAWABLE d = { theWindow };
651         XCBGetGeometryRep *geometry = XCBGetGeometryReply( xc,
652           XCBGetGeometry( xc, d ), NULL);
653         if (geometry) {
654           /* only width & height are used by the program */
655           WindowWidth  = geometry->width;
656           WindowHeight = geometry->height;
657           free(geometry);
658         }
659         
660         /* TODO: grab key Alt-Q to quit gracefully? */
661   }
662   else {
663         XCBPIXMAP                theIconPixmap;
664
665         CARD32 theWindowAttributes[] = {
666                 theBgPixel,    /* background */
667                 theFgPixel,    /* border */
668                 False,         /* override_redirect */
669                 EVENT_MASK,
670                 theCursor.xid };
671
672         unsigned long theWindowMask = XCBCWBackPixel | XCBCWBorderPixel |
673           XCBCWOverrideRedirect | XCBCWEventMask | XCBCWCursor;
674         
675         theWindow = XCBWINDOWNew( xc );
676         XCBCreateWindow( xc,
677                 theDepth,
678                 theWindow,
679                 theScreen->root,
680                 WindowPointX, WindowPointY,
681                 WindowWidth, WindowHeight,
682                 BorderWidth,
683                 XCBWindowClassInputOutput,
684                 theScreen->root_visual, /* CopyFromParent */
685                 theWindowMask, theWindowAttributes );
686
687         /* new: obey the window-delete protocol, look for XCBClientMessage */
688         deleteWindowAtom = GetAtom(xc, "WM_DELETE_WINDOW");
689         SetWMProtocols( xc, theWindow, 1, &deleteWindowAtom );
690
691         theIconPixmap = CreateBitmapFromData( xc, theWindow,
692                                                                                   icon_bits, icon_width, icon_height );
693 #ifdef TODO_ICCCM
694         theWMHints.icon_pixmap = theIconPixmap;
695         
696         if ( iconicState )
697           theWMHints.initial_state = IconicState;
698         else
699           theWMHints.initial_state = NormalState;
700         
701         theWMHints.flags = IconPixmapHint | StateHint;
702         
703         XSetWMHints( theDisplay, theWindow, &theWMHints );
704 #else
705     /* Um... there is no function to send the hints...
706         WMHints              theWMHints;
707         WMHintsSetIconPixmap( &theHints, theIconPixmap );
708
709         if ( iconicState )
710           WMHintsSetIconic( &theHints );
711         else
712           WMHintsSetNormal( &theHints );
713           
714         Now what?
715     */
716 #endif
717
718         /* why hide the structure? */
719         SizeHints *theSizeHints = AllocSizeHints();
720
721         /* need enum for second param (user specified) */
722         SizeHintsSetPosition(theSizeHints, 0, WindowPointX, WindowPointY);
723         SizeHintsSetSize(theSizeHints, 0, WindowWidth, WindowHeight);
724
725         SetWMNormalHints(xc, theWindow, theSizeHints);
726
727         FreeSizeHints(theSizeHints);
728
729         /* Um, why do I have to specify the encoding in this API? */
730         SetWMName( xc, theWindow, STRING, strlen(theTitle), theTitle );
731         SetWMIconName( xc, theWindow, STRING, strlen(theTitle), theTitle );
732
733         XCBMapWindow( xc, theWindow );
734
735   }
736   
737   InitBitmapAndGCs();
738
739   XCBFlush(xc);
740
741   /* latency: ask for keysyms now, and receive them later */
742   theKeySyms = XCBKeySymbolsAlloc( xc );
743
744   /* later: XCBKeySymbolsFree( keysyms ); */
745   /* later: XCBRefreshKeyboardMapping ( keysyms, mappingEvent ); */
746 }
747
748
749 void  Interval(void) {
750   pause();
751 }
752
753
754 void  TickCount(void) {
755   if ( ++NekoTickCount >= MAX_TICK )
756         NekoTickCount = 0;
757   
758   if ( NekoTickCount % 2 == 0 )
759         if ( NekoStateCount < MAX_TICK )
760           NekoStateCount++;
761 }
762
763
764 void
765 SetNekoState( int SetValue )
766 {
767   NekoTickCount = 0;
768   NekoStateCount = 0;
769   
770   NekoState = SetValue;
771   
772 #ifdef  DEBUG
773   switch ( NekoState ) {
774   case NEKO_STOP:
775   case NEKO_JARE:
776   case NEKO_KAKI:
777   case NEKO_AKUBI:
778   case NEKO_SLEEP:
779   case NEKO_U_TOGI:
780   case NEKO_D_TOGI:
781   case NEKO_L_TOGI:
782   case NEKO_R_TOGI:
783         NekoMoveDx = NekoMoveDy = 0;
784         break;
785   default:
786         break;
787   }
788 #endif
789 }
790
791 /* FillRct.c */
792 /*   Xlib does merging of requests, but the Flush and frequent DrawGC changes
793      defeat this mechanism */
794
795 void
796 DrawNeko( int x, int y, XCBGCONTEXT DrawGC )
797 {
798   XCBDRAWABLE drawable;  drawable.window = theWindow;
799   XCBRECTANGLE rect = { NekoLastX, NekoLastY, BITMAP_WIDTH, BITMAP_HEIGHT };
800
801   if ( (x != NekoLastX || y != NekoLastY) && (EventState != DEBUG_LIST) )
802   {
803         XCBPolyFillRectangle( xc, drawable, SpaceGC, 1, &rect );
804         rect.x = x; rect.y = y;
805
806   }
807
808   CARD32 originMask = XCBGCTileStippleOriginX | XCBGCTileStippleOriginY;
809   CARD32 origin[2] = { x, y };
810   XCBChangeGC( xc, DrawGC, originMask, origin );
811   /* XSetTSOrigin( theDisplay, DrawGC, x, y ); */
812
813   XCBPolyFillRectangle( xc, drawable, DrawGC, 1, &rect );
814
815   XCBFlush( xc );
816
817   NekoLastX = x;
818   NekoLastY = y;
819   
820   NekoLastGC = DrawGC;
821 }
822
823
824 void  RedrawNeko(void) {
825   XCBDRAWABLE drawable;  drawable.window = theWindow;
826   XCBRECTANGLE rect = { NekoLastX, NekoLastY, BITMAP_WIDTH, BITMAP_HEIGHT };
827
828   XCBPolyFillRectangle( xc, drawable, NekoLastGC, 1, &rect );
829
830   XCBFlush( xc );
831 }
832
833
834
835 void  NekoDirection(void) {
836   int                   NewState;
837   double                LargeX, LargeY;
838   double                Length;
839   double                SinTheta;
840   
841   if ( NekoMoveDx == 0 && NekoMoveDy == 0 ) {
842         NewState = NEKO_STOP;
843   } else {
844         LargeX = (double)NekoMoveDx;
845         LargeY = (double)(-NekoMoveDy);
846         Length = sqrt( LargeX * LargeX + LargeY * LargeY );
847         SinTheta = LargeY / Length;
848         
849         if ( NekoMoveDx > 0 ) {
850           if ( SinTheta > SinPiPer8Times3 ) {
851                 NewState = NEKO_U_MOVE;
852           } else if ( ( SinTheta <= SinPiPer8Times3 )
853                                  && ( SinTheta > SinPiPer8 ) ) {
854                 NewState = NEKO_UR_MOVE;
855           } else if ( ( SinTheta <= SinPiPer8 )
856                                  && ( SinTheta > -( SinPiPer8 ) ) ) {
857                 NewState = NEKO_R_MOVE;
858           } else if ( ( SinTheta <= -( SinPiPer8 ) )
859                                  && ( SinTheta > -( SinPiPer8Times3 ) ) ) {
860                 NewState = NEKO_DR_MOVE;
861           } else {
862                 NewState = NEKO_D_MOVE;
863           }
864         } else {
865           if ( SinTheta > SinPiPer8Times3 ) {
866                 NewState = NEKO_U_MOVE;
867           } else if ( ( SinTheta <= SinPiPer8Times3 )
868                                  && ( SinTheta > SinPiPer8 ) ) {
869                 NewState = NEKO_UL_MOVE;
870           } else if ( ( SinTheta <= SinPiPer8 )
871                                  && ( SinTheta > -( SinPiPer8 ) ) ) {
872                 NewState = NEKO_L_MOVE;
873           } else if ( ( SinTheta <= -( SinPiPer8 ) )
874                                  && ( SinTheta > -( SinPiPer8Times3 ) ) ) {
875                 NewState = NEKO_DL_MOVE;
876           } else {
877                 NewState = NEKO_D_MOVE;
878           }
879         }
880   }
881   
882   if ( NekoState != NewState ) {
883         SetNekoState( NewState );
884   }
885 }
886
887
888 Bool  IsWindowOver(void) {
889   Bool  ReturnValue = False;
890   
891   if ( NekoY <= 0 ) {
892         NekoY = 0;
893         ReturnValue = True;
894   } else if ( NekoY >= WindowHeight - BITMAP_HEIGHT ) {
895         NekoY = WindowHeight - BITMAP_HEIGHT;
896         ReturnValue = True;
897   }
898   if ( NekoX <= 0 ) {
899         NekoX = 0;
900         ReturnValue = True;
901   } else if ( NekoX >= WindowWidth - BITMAP_WIDTH ) {
902         NekoX = WindowWidth - BITMAP_WIDTH;
903         ReturnValue = True;
904   }
905   
906   return( ReturnValue );
907 }
908
909
910 Bool  IsNekoDontMove(void) {
911   return( NekoX == NekoLastX  &&  NekoY == NekoLastY );
912 }
913
914
915 Bool  IsNekoMoveStart(void) {
916 #ifndef DEBUG
917   if ( (PrevMouseX >= MouseX - IDLE_SPACE
918                 && PrevMouseX <= MouseX + IDLE_SPACE) &&
919           (PrevMouseY >= MouseY - IDLE_SPACE 
920            && PrevMouseY <= MouseY + IDLE_SPACE) )
921         return( False );
922   else
923         return( True );
924 #else
925   if ( NekoMoveDx == 0 && NekoMoveDy == 0 )
926         return( False );
927   else
928         return( True );
929 #endif
930 }
931
932 #ifndef DEBUG
933 void  CalcDxDy(void) {
934   int                   RelativeX, RelativeY;
935   double                LargeX, LargeY;
936   double                DoubleLength, Length;
937   
938   /* TODO: replace query with pointer motion notification? */
939
940   XCBQueryPointerRep *reply = XCBQueryPointerReply( xc,
941         XCBQueryPointer( xc, theWindow ), NULL);
942         
943   RelativeX = reply->win_x;
944   RelativeY = reply->win_y;
945   
946   free(reply);
947
948   PrevMouseX = MouseX;
949   PrevMouseY = MouseY;
950   
951   MouseX = RelativeX;
952   MouseY = RelativeY;
953   
954   LargeX = (double)( MouseX - NekoX - BITMAP_WIDTH / 2 );
955   LargeY = (double)( MouseY - NekoY - BITMAP_HEIGHT );
956   
957   DoubleLength = LargeX * LargeX + LargeY * LargeY;
958   
959   if ( DoubleLength != (double)0 ) {
960         Length = sqrt( DoubleLength );
961         if ( Length <= NekoSpeed ) {
962           NekoMoveDx = (int)LargeX;
963           NekoMoveDy = (int)LargeY;
964         } else {
965           NekoMoveDx = (int)( ( NekoSpeed * LargeX ) / Length );
966           NekoMoveDy = (int)( ( NekoSpeed * LargeY ) / Length );
967         }
968   } else {
969         NekoMoveDx = NekoMoveDy = 0;
970   }
971 }
972 #endif
973
974 void  NekoThinkDraw(void) {
975 #ifndef DEBUG
976   CalcDxDy();
977 #endif
978
979   if ( NekoState != NEKO_SLEEP ) {
980         DrawNeko( NekoX, NekoY,
981                          NekoTickCount % 2 == 0 ?
982                          *(AnimationPattern[ NekoState ].TickEvenGCPtr) :
983                          *(AnimationPattern[ NekoState ].TickOddGCPtr) );
984   } else {
985         DrawNeko( NekoX, NekoY,
986                          NekoTickCount % 8 <= 3 ?
987                          *(AnimationPattern[ NekoState ].TickEvenGCPtr) :
988                          *(AnimationPattern[ NekoState ].TickOddGCPtr) );
989   }
990   
991   TickCount();
992   
993   switch ( NekoState ) {
994   case NEKO_STOP:
995         if ( IsNekoMoveStart() ) {
996           SetNekoState( NEKO_AWAKE );
997           break;
998         }
999         if ( NekoStateCount < NEKO_STOP_TIME ) {
1000           break;
1001         }
1002         if ( NekoMoveDx < 0 && NekoX <= 0 ) {
1003           SetNekoState( NEKO_L_TOGI );
1004         } else if ( NekoMoveDx > 0 && NekoX >= WindowWidth - BITMAP_WIDTH ) {
1005           SetNekoState( NEKO_R_TOGI );
1006         } else if ( NekoMoveDy < 0 && NekoY <= 0 ) {
1007           SetNekoState( NEKO_U_TOGI );
1008         } else if ( NekoMoveDy > 0 && NekoY >= WindowHeight - BITMAP_HEIGHT ) {
1009           SetNekoState( NEKO_D_TOGI );
1010         } else {
1011           SetNekoState( NEKO_JARE );
1012         }
1013         break;
1014   case NEKO_JARE:
1015         if ( IsNekoMoveStart() ) {
1016           SetNekoState( NEKO_AWAKE );
1017           break;
1018         }
1019         if ( NekoStateCount < NEKO_JARE_TIME ) {
1020           break;
1021         }
1022         SetNekoState( NEKO_KAKI );
1023         break;
1024   case NEKO_KAKI:
1025         if ( IsNekoMoveStart() ) {
1026           SetNekoState( NEKO_AWAKE );
1027           break;
1028         }
1029         if ( NekoStateCount < NEKO_KAKI_TIME ) {
1030           break;
1031         }
1032         SetNekoState( NEKO_AKUBI );
1033         break;
1034   case NEKO_AKUBI:
1035         if ( IsNekoMoveStart() ) {
1036           SetNekoState( NEKO_AWAKE );
1037           break;
1038         }
1039         if ( NekoStateCount < NEKO_AKUBI_TIME ) {
1040           break;
1041         }
1042         SetNekoState( NEKO_SLEEP );
1043         break;
1044   case NEKO_SLEEP:
1045         if ( IsNekoMoveStart() ) {
1046           SetNekoState( NEKO_AWAKE );
1047           break;
1048         }
1049         break;
1050   case NEKO_AWAKE:
1051         if ( NekoStateCount < NEKO_AWAKE_TIME ) {
1052           break;
1053         }
1054         NekoDirection();
1055         break;
1056   case NEKO_U_MOVE:
1057   case NEKO_D_MOVE:
1058   case NEKO_L_MOVE:
1059   case NEKO_R_MOVE:
1060   case NEKO_UL_MOVE:
1061   case NEKO_UR_MOVE:
1062   case NEKO_DL_MOVE:
1063   case NEKO_DR_MOVE:
1064         NekoX += NekoMoveDx;
1065         NekoY += NekoMoveDy;
1066         NekoDirection();
1067         if ( IsWindowOver() ) {
1068           if ( IsNekoDontMove() ) {
1069                 SetNekoState( NEKO_STOP );
1070           }
1071         }
1072         break;
1073   case NEKO_U_TOGI:
1074   case NEKO_D_TOGI:
1075   case NEKO_L_TOGI:
1076   case NEKO_R_TOGI:
1077         if ( IsNekoMoveStart() ) {
1078           SetNekoState( NEKO_AWAKE );
1079           break;
1080         }
1081         if ( NekoStateCount < NEKO_TOGI_TIME ) {
1082           break;
1083         }
1084         SetNekoState( NEKO_KAKI );
1085         break;
1086   default:
1087         /* Internal Error */
1088         SetNekoState( NEKO_STOP );
1089         break;
1090   }
1091   
1092   Interval();
1093 }
1094
1095
1096 #ifdef  DEBUG
1097 void  DisplayCharacters() {
1098   int           Index;
1099   int           x, y;
1100   
1101   for ( Index = 0, x = 0, y = 0;
1102            BitmapGCDataTable[ Index ].GCCreatePtr != NULL; Index++ ) {
1103         
1104         DrawNeko( x, y, *(BitmapGCDataTable[ Index ].GCCreatePtr) );
1105         XFlush( theDisplay );
1106         
1107         x += BITMAP_WIDTH;
1108         
1109         if ( x > WindowWidth - BITMAP_WIDTH ) {
1110           x = 0;
1111           y += BITMAP_HEIGHT;
1112           if ( y > WindowHeight - BITMAP_HEIGHT) {
1113                 break;
1114           }
1115         }
1116   }
1117 }
1118
1119 #endif  /* DEBUG */
1120
1121 Bool
1122 ProcessKeyPress( XCBKeyPressEvent *theKeyEvent )
1123 {
1124   Bool ReturnState = True;
1125
1126   /* quit on Meta-Q (Alt-Q) */
1127   XCBKEYSYM theKeySym;
1128
1129   /* last param is "int col". What? add enumeration to xcb_keysyms.h */
1130   theKeySym = XCBKeyPressLookupKeysym( theKeySyms, theKeyEvent, 1 );
1131
1132   /* KeySym XK_Q == 'Q' */
1133   if (theKeySym.id == 'Q' && (theKeyEvent->state & XCBModMask1))
1134     ReturnState = False;
1135
1136 #ifdef  DEBUG
1137   if ( EventState == DEBUG_MOVE ) {
1138         switch ( theKeySym ) {
1139         case XK_KP_1:
1140           NekoMoveDx = -(int)( NekoSpeed / sqrt( (double)2 ) );
1141           NekoMoveDy = -NekoMoveDx;
1142           break;
1143         case XK_KP_2:
1144           NekoMoveDx = 0;
1145           NekoMoveDy = (int)NekoSpeed;
1146           break;
1147         case XK_KP_3:
1148           NekoMoveDx = (int)( NekoSpeed / sqrt( (double)2 ) );
1149           NekoMoveDy = NekoMoveDx;
1150           break;
1151         case XK_KP_4:
1152           NekoMoveDx = -(int)NekoSpeed;
1153           NekoMoveDy = 0;
1154           break;
1155         case XK_KP_5:
1156           NekoMoveDx = 0;
1157           NekoMoveDy = 0;
1158           break;
1159         case XK_KP_6:
1160           NekoMoveDx = (int)NekoSpeed;
1161           NekoMoveDy = 0;
1162           break;
1163         case XK_KP_7:
1164           NekoMoveDx = -(int)( NekoSpeed / sqrt( (double)2 ) );
1165           NekoMoveDy = NekoMoveDx;
1166           break;
1167         case XK_KP_8:
1168           NekoMoveDx = 0;
1169           NekoMoveDy = -(int)NekoSpeed;
1170           break;
1171         case XK_KP_9:
1172           NekoMoveDx = (int)( NekoSpeed / sqrt( (double)2 ) );
1173           NekoMoveDy = -NekoMoveDx;
1174           break;
1175         }
1176   }
1177 #endif
1178   
1179   return( ReturnState );
1180 }
1181
1182
1183 void  NekoAdjust(void) {
1184   if ( NekoX < 0 )
1185         NekoX = 0;
1186   else if ( NekoX > WindowWidth - BITMAP_WIDTH )
1187         NekoX = WindowWidth - BITMAP_WIDTH;
1188
1189   if ( NekoY < 0 )
1190         NekoY = 0;
1191   else if ( NekoY > WindowHeight - BITMAP_HEIGHT )
1192         NekoY = WindowHeight - BITMAP_HEIGHT;
1193 }
1194
1195 int IsDeleteMessage(XCBClientMessageEvent *msg)
1196 {
1197         return msg->data.data32[0] == deleteWindowAtom.xid;
1198 }
1199
1200 Bool  ProcessEvent(void) {
1201   XCBGenericEvent *theEvent;
1202   XCBConfigureNotifyEvent *theConfigureNotification;
1203   XCBExposeEvent *theExposure;
1204   XCBButtonPressEvent *theButtonPress;
1205   Bool  ContinueState = True;
1206   int error = 0;
1207   
1208   switch ( EventState ) {
1209   case NORMAL_STATE:
1210     while ( ContinueState &&
1211             NULL != (theEvent = XCBPollForEvent( xc, &error )) ) {  /*while ( XCheckMaskEvent( theDisplay, EVENT_MASK, &theEvent ) ) {*/
1212           switch ( theEvent->response_type & 0x7f ) {
1213           case XCBConfigureNotify:
1214             theConfigureNotification = (XCBConfigureNotifyEvent *)theEvent;
1215                 WindowWidth = theConfigureNotification->width;
1216                 WindowHeight = theConfigureNotification->height;
1217                 WindowPointX = theConfigureNotification->x;
1218                 WindowPointY = theConfigureNotification->y;
1219                 BorderWidth = theConfigureNotification->border_width;
1220                 NekoAdjust();
1221                 break;
1222           case XCBExpose:
1223             theExposure = (XCBExposeEvent *)theEvent;
1224                 if ( theExposure->count == 0 )
1225                   RedrawNeko();
1226                 break;
1227           case XCBMapNotify:
1228                 RedrawNeko();
1229                 break;
1230           case XCBKeyPress:
1231                 ContinueState = ProcessKeyPress( (XCBKeyPressEvent *)theEvent );
1232                 break;
1233           case XCBButtonPress:
1234             theButtonPress = (XCBButtonPressEvent *)theEvent;
1235                 ContinueState = ( theButtonPress->detail.id != 3 );     /* xbutton.button */
1236                 break;
1237           /* new: handle ClientMessage */
1238           case XCBClientMessage:
1239             ContinueState = !IsDeleteMessage((XCBClientMessageEvent *)theEvent);
1240             break;
1241           default:
1242                 /* Unknown Event */
1243                 /*printf("event type:%x\n", (int)theEvent->response_type);*/
1244                 break;
1245           }
1246           free(theEvent);
1247           if (error != 0)
1248                 return False;
1249         } /* end while */
1250         break;
1251 #ifdef  DEBUG
1252   case DEBUG_LIST:
1253         XNextEvent( theDisplay, &theEvent );
1254         switch ( theEvent.type ) {
1255         case ConfigureNotify:
1256           WindowWidth = theEvent.xconfigure.width;
1257           WindowHeight = theEvent.xconfigure.height;
1258           WindowPointX = theEvent.xconfigure.x;
1259           WindowPointY = theEvent.xconfigure.y;
1260           BorderWidth = theEvent.xconfigure.border_width;
1261           break;
1262         case Expose:
1263           if ( theEvent.xexpose.count == 0 )
1264                 DisplayCharacters();
1265           break;
1266         case MapNotify:
1267           DisplayCharacters();
1268           break;
1269         case KeyPress:
1270           ContinueState = ProcessKeyPress( &theEvent );
1271           break;
1272         case ButtonPress:
1273           if ( theEvent.xbutton.button == 3 )
1274                 return( False );
1275           break;
1276         default:
1277           /* Unknown Event */
1278           break;
1279         }
1280         break;
1281   case DEBUG_MOVE:
1282         while ( XCheckMaskEvent( theDisplay, EVENT_MASK, &theEvent ) ) {
1283           switch ( theEvent.type ) {
1284           case ConfigureNotify:
1285                 WindowWidth = theEvent.xconfigure.width;
1286                 WindowHeight = theEvent.xconfigure.height;
1287                 WindowPointX = theEvent.xconfigure.x;
1288                 WindowPointY = theEvent.xconfigure.y;
1289                 BorderWidth = theEvent.xconfigure.border_width;
1290                 NekoAdjust();
1291                 break;
1292           case Expose:
1293                 if ( theEvent.xexpose.count == 0 )
1294                   RedrawNeko();
1295                 break;
1296           case MapNotify:
1297                 RedrawNeko();
1298                 break;
1299           case KeyPress:
1300                 ContinueState = ProcessKeyPress( &theEvent );
1301                 if ( !ContinueState ) {
1302                   return( ContinueState );
1303                 }
1304                 break;
1305           case ButtonPress:
1306                 if ( theEvent.xbutton.button == 3 )
1307                   return( False );
1308                 break;
1309           default:
1310                 /* Unknown Event */
1311                 break;
1312           }
1313         }
1314         break;
1315 #endif
1316   default:
1317         /* Internal Error */
1318         break;
1319   }
1320   
1321   return( ContinueState );
1322 }
1323
1324
1325 void  ProcessNeko(void) {
1326   struct itimerval      Value;
1327   
1328   EventState = NORMAL_STATE;
1329
1330   NekoX = ( WindowWidth - BITMAP_WIDTH / 2 ) / 2;
1331   NekoY = ( WindowHeight - BITMAP_HEIGHT / 2 ) / 2;
1332   
1333   NekoLastX = NekoX;
1334   NekoLastY = NekoY;
1335   
1336   SetNekoState( NEKO_STOP );
1337   
1338   timerclear( &Value.it_interval );
1339   timerclear( &Value.it_value );
1340   
1341   Value.it_interval.tv_usec = IntervalTime;
1342   Value.it_value.tv_usec = IntervalTime;
1343   
1344   setitimer( ITIMER_REAL, &Value, 0 );
1345   
1346   do {
1347         NekoThinkDraw();
1348   } while ( ProcessEvent() );
1349 }
1350
1351 #ifdef  DEBUG
1352
1353 void  NekoList() {
1354   EventState = DEBUG_LIST;
1355   
1356   fprintf( stderr, "\n" );
1357   fprintf( stderr, "G-0lMw$rI=<($7$^$9!#(Quit !D Alt-Q)\n" );
1358   fprintf( stderr, "\n" );
1359   
1360   XSelectInput( theDisplay, theWindow, EVENT_MASK );
1361   
1362   while ( ProcessEvent() );
1363 }
1364
1365
1366 void  NekoMoveTest() {
1367   struct itimerval      Value;
1368   
1369   EventState = DEBUG_MOVE;
1370   
1371   NekoX = ( WindowWidth - BITMAP_WIDTH / 2 ) / 2;
1372   NekoY = ( WindowHeight - BITMAP_HEIGHT / 2 ) / 2;
1373   
1374   NekoLastX = NekoX;
1375   NekoLastY = NekoY;
1376   
1377   SetNekoState( NEKO_STOP );
1378   
1379   timerclear( &Value.it_interval );
1380   timerclear( &Value.it_value );
1381   
1382   Value.it_interval.tv_usec = IntervalTime;
1383   Value.it_value.tv_usec = IntervalTime;
1384   
1385   setitimer( ITIMER_REAL, &Value, 0 );
1386   
1387   fprintf( stderr, "\n" );
1388   fprintf( stderr, "G-$N0\F0%F%9%H$r9T$$$^$9!#(Quit !D Alt-Q)\n" );
1389   fprintf( stderr, "\n" );
1390   fprintf( stderr, "\t%-!<%Q%C%I>e$N%F%s%-!<$GG-$r0\F0$5$;$F2<$5$$!#\n" );
1391   fprintf( stderr, "\t(M-8z$J%-!<$O#1!A#9$G$9!#)\n" );
1392   fprintf( stderr, "\n" );
1393   
1394   do {
1395         NekoThinkDraw();
1396   } while ( ProcessEvent() );
1397 }
1398
1399
1400 void  ProcessDebugMenu() {
1401   int           UserSelectNo = 0;
1402   char  UserAnswer[ BUFSIZ ];
1403   
1404   fprintf( stderr, "\n" );
1405   fprintf( stderr, "!Zxneko %G%P%C%0%a%K%e!<![\n" );
1406   
1407   while ( !( UserSelectNo >= 1 && UserSelectNo <= 2 ) ) {
1408         fprintf( stderr, "\n" );
1409         fprintf( stderr, "\t1)!!G-%-%c%i%/%?!<0lMwI=<(\n" );
1410         fprintf( stderr, "\t2)!!G-0\F0%F%9%H\n" );
1411         fprintf( stderr, "\n" );
1412         fprintf( stderr, "Select: " );
1413
1414         fgets( UserAnswer, sizeof( UserAnswer ), stdin );
1415         
1416         UserSelectNo = atoi( UserAnswer );
1417         
1418         if ( !( UserSelectNo >= 1 && UserSelectNo <= 2 ) ) {
1419           fprintf( stderr, "\n" );
1420           fprintf( stderr, "@5$7$$HV9f$rA*Br$7$F2<$5$$!#\n" );
1421         }
1422   }
1423   
1424   switch ( UserSelectNo ) {
1425   case 1:
1426         NekoList();
1427         break;
1428   case 2:
1429         NekoMoveTest();
1430         break;
1431   default:
1432         /* Internal Error */
1433         break;
1434   }
1435   
1436   fprintf( stderr, "%F%9%H=*N;!#\n" );
1437   fprintf( stderr, "\n" );
1438 }
1439
1440 #endif  /* DEBUG */
1441
1442 void  NullFunction(int ignored)
1443 {
1444   /* signal( SIGALRM, NullFunction ); */
1445 }
1446
1447
1448 void  Usage(void) {
1449   fprintf( stderr,
1450                   "Usage: %s [-display <display>] [-geometry <geometry>] \\\n",
1451                   ProgramName );
1452   fprintf( stderr, "\t[-bg <background>] [-fg <foreground>] \\\n" );
1453   fprintf( stderr, "\t[-title <title>] [-name <title>] [-iconic] \\\n" );
1454   fprintf( stderr, "\t[-speed <speed>] [-time <time>] [-root] [-help]\n" );
1455 }
1456
1457
1458 Bool
1459 GetArguments( int argc, char *argv[],
1460         char *theDisplayName, char *theGeometry, char **theTitle,
1461         double *NekoSpeed, long *IntervalTime )
1462 {
1463   int           ArgCounter;
1464   Bool  iconicState;
1465   
1466   theDisplayName[ 0 ] = '\0';
1467   theGeometry[ 0 ] = '\0';
1468   
1469   iconicState = False;
1470   
1471   for ( ArgCounter = 0; ArgCounter < argc; ArgCounter++ ) {
1472         if ( strncmp( argv[ ArgCounter ], "-h", 2 ) == 0 ) {
1473           Usage();
1474           exit( 0 );
1475         } else if ( strcmp( argv[ ArgCounter ], "-display" ) == 0 ) {
1476           ArgCounter++;
1477           if ( ArgCounter < argc ) {
1478                 strcpy( theDisplayName, argv[ ArgCounter ] );
1479           } else {
1480                 fprintf( stderr, "%s: -display option error.\n", ProgramName );
1481                 exit( 1 );
1482           }
1483         } else if ( strncmp( argv[ ArgCounter ], "-geom", 5 ) == 0 ) {
1484           ArgCounter++;
1485           if ( ArgCounter < argc ) {
1486                 strcpy( theGeometry, argv[ ArgCounter ] );
1487           } else {
1488                 fprintf( stderr,
1489                                 "%s: -geometry option error.\n", ProgramName );
1490                 exit( 1 );
1491           }
1492         } else if ( ( strcmp( argv[ ArgCounter ], "-title" ) == 0 )
1493                            || ( strcmp( argv[ ArgCounter ], "-name" ) == 0 ) ) {
1494           ArgCounter++;
1495           if ( ArgCounter < argc ) {
1496             *theTitle = argv[ ArgCounter ];
1497           } else {
1498                 fprintf( stderr, "%s: -title option error.\n", ProgramName );
1499                 exit( 1 );
1500           }
1501         } else if ( strcmp( argv[ ArgCounter ], "-iconic" ) == 0 ) {
1502           iconicState = True;
1503         } else if ( strcmp( argv[ ArgCounter ], "-speed" ) == 0 ) {
1504           ArgCounter++;
1505           if ( ArgCounter < argc ) {
1506                 *NekoSpeed = atof( argv[ ArgCounter ] );
1507           } else {
1508                 fprintf( stderr, "%s: -speed option error.\n", ProgramName );
1509                 exit( 1 );
1510           }
1511         } else if ( strcmp( argv[ ArgCounter ], "-fg" ) == 0 ) {
1512           ArgCounter++;
1513           if ( ArgCounter < argc ) {
1514                 fgColor = argv[ArgCounter];
1515           } else {
1516                 fprintf( stderr, "%s: -fg option error.\n", ProgramName );
1517                 exit( 1 );
1518           }
1519         } else if ( strcmp( argv[ ArgCounter ], "-bg" ) == 0 ) {
1520           ArgCounter++;
1521           if ( ArgCounter < argc ) {
1522                 bgColor = argv[ArgCounter];
1523           } else {
1524                 fprintf( stderr, "%s: -bg option error.\n", ProgramName );
1525                 exit( 1 );
1526           }
1527         } else if ( strcmp( argv[ ArgCounter ], "-time" ) == 0 ) {
1528           ArgCounter++;
1529           if ( ArgCounter < argc ) {
1530                 *IntervalTime = atol( argv[ ArgCounter ] );
1531           } else {
1532                 fprintf( stderr, "%s: -time option error.\n", ProgramName );
1533                 exit( 1 );
1534           }
1535         } else if ( strcmp( argv[ ArgCounter ], "-root" ) == 0 ) {
1536           useRoot = 1;
1537         } else {
1538           fprintf( stderr,
1539                           "%s: Unknown option \"%s\".\n", ProgramName,
1540                           argv[ ArgCounter ] );
1541           Usage();
1542           exit( 1 );
1543         }
1544   }
1545   
1546   return( iconicState );
1547 }
1548
1549 void UndefineCursor( XCBConnection *c, XCBWINDOW w)
1550 {
1551         CARD32 none[] = { XCBNone };
1552         XCBChangeWindowAttributes( c, w, XCBCWCursor, none );
1553 }
1554
1555 int
1556 main( int argc, char *argv[] )
1557 {
1558   Bool  iconicState;
1559   char  theDisplayName[ DIRNAMELEN ];
1560   char  theGeometry[ DIRNAMELEN ];
1561   char  *theTitle = "";
1562   
1563   ProgramName = argv[ 0 ];
1564   
1565   argc--;
1566   argv++;
1567   
1568   useRoot = 0;
1569   fgColor = bgColor = (char *) NULL;
1570   
1571   iconicState = GetArguments( argc, argv, theDisplayName, theGeometry,
1572                                                          &theTitle, &NekoSpeed, &IntervalTime );
1573   
1574   if (theTitle[0] == 0) theTitle = ProgramName;
1575   InitScreen( theDisplayName, theGeometry, theTitle, iconicState );
1576   
1577   signal( SIGALRM, NullFunction );
1578   
1579   SinPiPer8Times3 = sin( PI_PER8 * (double)3 );
1580   SinPiPer8 = sin( PI_PER8 );
1581
1582 #ifndef DEBUG
1583   ProcessNeko();
1584 #else
1585   ProcessDebugMenu();
1586 #endif
1587
1588   UndefineCursor( xc, theWindow );
1589   XCBDisconnect( xc );
1590   exit( 0 );
1591 }