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