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