1 /*--------------------------------------------------------------
11 * Added Color, RootWindow Capability and Quit Ability:
12 * Dan Checkoway, 7-12-94
14 * Converted to use ANSI C and XCB by:
17 *--------------------------------------------------------------*/
21 #include <X11/Xutil.h>
22 #include <X11/keysym.h>
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>
32 typedef enum { False, True } Bool;
40 #include <unistd.h> /* pause() */
45 #include "bitmaps/icon.xbm"
46 #include "bitmaps/cursor.xbm"
47 #include "bitmaps/cursor_mask.xbm"
49 #include "bitmaps/space.xbm"
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"
59 #include "bitmaps/awake.xbm"
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"
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"
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
96 #define EVENT_MASK ( XCBEventMaskKeyPress | XCBEventMaskButtonPress | \
97 XCBEventMaskExposure | XCBEventMaskStructureNotify )
99 #define EVENT_MASK_ROOT ( XCBEventMaskKeyPress | XCBEventMaskExposure )
101 #define MAX_TICK 9999 /* Odd Only! */
102 #define INTERVAL 125000L
103 #define NEKO_SPEED 16
105 #define NORMAL_STATE 1
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
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
135 #define PI_PER8 ((double)3.1415926535/(double)8)
137 #define DIRNAMELEN 255
140 char *fgColor, *bgColor;
142 static char *ProgramName;
144 /*Display *theDisplay;*/
146 XCBSCREEN *theScreen; /* instead of macro(theDisplay, int theScreen) */
147 unsigned int theDepth;
148 unsigned long theBlackPixel;
149 unsigned long theWhitePixel;
152 XCBKeySymbols *theKeySyms;
154 static unsigned int WindowWidth;
155 static unsigned int WindowHeight;
156 static int WindowPointX;
157 static int WindowPointY;
159 static unsigned int BorderWidth = DEFAULT_BORDER;
161 long IntervalTime = INTERVAL;
183 XCBGCONTEXT NekoLastGC;
185 double NekoSpeed = (double)NEKO_SPEED;
187 double SinPiPer8Times3;
210 XCBPIXMAP UpLeft1Xbm;
211 XCBPIXMAP UpLeft2Xbm;
212 XCBPIXMAP UpRight1Xbm;
213 XCBPIXMAP UpRight2Xbm;
214 XCBPIXMAP DownLeft1Xbm;
215 XCBPIXMAP DownLeft2Xbm;
216 XCBPIXMAP DownRight1Xbm;
217 XCBPIXMAP DownRight2Xbm;
219 XCBPIXMAP UpTogi1Xbm;
220 XCBPIXMAP UpTogi2Xbm;
221 XCBPIXMAP DownTogi1Xbm;
222 XCBPIXMAP DownTogi2Xbm;
223 XCBPIXMAP LeftTogi1Xbm;
224 XCBPIXMAP LeftTogi2Xbm;
225 XCBPIXMAP RightTogi1Xbm;
226 XCBPIXMAP RightTogi2Xbm;
235 XCBGCONTEXT Sleep1GC;
236 XCBGCONTEXT Sleep2GC;
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;
257 XCBGCONTEXT UpTogi1GC;
258 XCBGCONTEXT UpTogi2GC;
259 XCBGCONTEXT DownTogi1GC;
260 XCBGCONTEXT DownTogi2GC;
261 XCBGCONTEXT LeftTogi1GC;
262 XCBGCONTEXT LeftTogi2GC;
263 XCBGCONTEXT RightTogi1GC;
264 XCBGCONTEXT RightTogi2GC;
267 XCBGCONTEXT *GCCreatePtr;
268 XCBPIXMAP *BitmapCreatePtr;
270 unsigned int PixelWidth;
271 unsigned int PixelHeight;
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 },
295 &UpRight1Xbm, upright1_bits, upright1_width, upright1_height },
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 },
301 &DownRight1Xbm, dwright1_bits, dwright1_width, dwright1_height },
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 },
311 &RightTogi1Xbm, rtogi1_bits, rtogi1_width, rtogi1_height },
313 &RightTogi2Xbm, rtogi2_bits, rtogi2_width, rtogi2_height },
314 { NULL, NULL, NULL, 0, 0 }
318 XCBGCONTEXT *TickEvenGCPtr;
319 XCBGCONTEXT *TickOddGCPtr;
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 */
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
380 /* convert 1Ll <--> 4Mm */
383 register unsigned char *src,
384 register unsigned char *dest,
385 long srclen, long srcinc, long destinc,
389 register const unsigned char *rev = _reverse_byte;
393 for (h = height; --h >= 0; src += srcinc, dest += destinc)
394 for (n = srclen; --n >= 0; )
395 *dest++ = rev[*src++];
398 /* assumes pad is a power of 2 */
399 #define ROUNDUP(nbytes, pad) (((nbytes) + ((pad) - 1)) & ~(long)((pad) - 1))
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)
407 XCBDRAWABLE drawable;
408 XCBPIXMAP bitmap = XCBPIXMAPNew( c );
410 drawable.window = window;
411 XCBCreatePixmap( c, depth, bitmap, drawable, w, h );
413 XCBGCONTEXT gc = XCBGCONTEXTNew( c );
415 CARD32 mask = (depth==1 ? 0 : XCBGCForeground | XCBGCBackground);
416 CARD32 values[] = { fg, bg };
418 drawable.pixmap = bitmap;
419 XCBCreateGC( c, gc, drawable, mask, values );
421 /* XImage attributes: bpp=1, xoffset=0,
422 byte_order=bit_order=LSB, unit=8, pad=8, bpl=(w+7/8) */
424 /* must swap and pad the data if bit/byte_order isn't LSB (Mac) */
426 /* Mac X Server: byte_order=bit_order=MSB, unit=32, padding=32 */
427 long bufLen = (w+7)/8*h;
429 if (XCBGetSetup(c)->bitmap_format_scanline_unit == 32 &&
430 XCBGetSetup(c)->bitmap_format_bit_order == XCBImageOrderMSBFirst &&
431 XCBGetSetup(c)->image_byte_order == XCBImageOrderMSBFirst)
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);
440 memcpy(buf, data, bufLen);
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);
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 */
451 XCBPutImage( c, format, drawable, gc,
453 0, 1, /* left_pad, depth */
457 XCBGenericError *error = NULL;
458 XCBSync( c, &error );
460 printf("error code %d", (int)error->error_code);
467 /* later: XCBFreePixmap( c, bitmap ); */
471 XCBPIXMAP CreateBitmapFromData(XCBConnection *c, XCBWINDOW window,
472 char *data, CARD16 w, CARD16 h)
475 return CreatePixmapFromBitmapData(c, window, data, w, h, 0, 0, depth);
478 void InitBitmapAndGCs(void) {
479 BitmapGCData *BitmapGCDataTablePtr;
480 CARD32 theGCValues[5];
481 XCBDRAWABLE drawable; drawable.window = theWindow;
483 theGCValues[0] = XCBGXcopy;
485 theGCValues[1] = theBlackPixel;
486 theGCValues[2] = theWhitePixel;
488 theGCValues[3] = XCBFillStyleTiled;
490 /* TODO: latency: make all the bitmaps, then all the contexts? */
492 for ( BitmapGCDataTablePtr = BitmapGCDataTable;
493 BitmapGCDataTablePtr->GCCreatePtr != NULL;
494 BitmapGCDataTablePtr++ ) {
496 *(BitmapGCDataTablePtr->BitmapCreatePtr)
497 = CreatePixmapFromBitmapData( xc, theScreen->root,
498 BitmapGCDataTablePtr->PixelPattern,
499 BitmapGCDataTablePtr->PixelWidth,
500 BitmapGCDataTablePtr->PixelHeight,
501 theBlackPixel, theWhitePixel, theScreen->root_depth);
503 theGCValues[4] = BitmapGCDataTablePtr->BitmapCreatePtr->xid; /* tile */
505 *(BitmapGCDataTablePtr->GCCreatePtr) = XCBGCONTEXTNew( xc );
506 XCBCreateGC( xc, *(BitmapGCDataTablePtr->GCCreatePtr), drawable,
507 XCBGCFunction | XCBGCForeground | XCBGCBackground |
508 XCBGCFillStyle | XCBGCTile,
512 /* later: XCBFreePixmap( c, bitmap ); */
513 /* later: XCBFreeGC( c, gc ); */
517 InitScreen( char *DisplayName, char *theGeometry, char *theTitle, Bool iconicState )
519 XCBPIXMAP theCursorSource;
520 XCBPIXMAP theCursorMask;
521 XCBCOLORMAP theColormap;
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 );
529 fprintf( stderr, ".\n" );
533 theScreen = XCBAuxGetScreen(xc, screen);
534 if (theScreen == NULL) {
535 fprintf( stderr, "%s: Can't get default screen", ProgramName );
539 theDepth = theScreen->root_depth; /* DefaultDepth */
540 theColormap = theScreen->default_colormap;
542 WindowPointX = DEFAULT_WIN_X;
543 WindowPointY = DEFAULT_WIN_Y;
544 WindowWidth = WINDOW_WIDTH;
545 WindowHeight = WINDOW_HEIGHT;
549 GeometryStatus = XParseGeometry( theGeometry,
550 &WindowPointX, &WindowPointY,
551 &WindowWidth, &WindowHeight );
554 theCursorSource = CreateBitmapFromData( xc,
560 theCursorMask = CreateBitmapFromData( xc,
564 cursor_mask_height );
567 if ( bgColor == NULL) bgColor = "white";
568 if ( fgColor == NULL) fgColor = "black";
570 XCBAllocNamedColorCookie bgCookie = XCBAllocNamedColor ( xc,
571 theColormap, strlen(bgColor), bgColor );
573 XCBAllocNamedColorCookie fgCookie = XCBAllocNamedColor ( xc,
574 theColormap, strlen(fgColor), fgColor );
576 XCBAllocNamedColorRep *bgRep = XCBAllocNamedColorReply( xc, bgCookie, 0 );
579 "%s: Can't allocate the background color %s.\n", ProgramName, bgColor );
582 theWhitePixel = bgRep->pixel;
584 XCBAllocNamedColorRep *fgRep = XCBAllocNamedColorReply( xc, fgCookie, 0 );
587 "%s: Can't allocate the foreground color %s.\n", ProgramName, fgColor );
590 theBlackPixel = fgRep->pixel;
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 );
602 CARD32 rootAttributes[] = { EVENT_MASK_ROOT, theCursor.xid };
603 theWindow = theScreen->root;
604 XCBChangeWindowAttributes(xc, theWindow,
605 XCBCWEventMask | XCBCWCursor, rootAttributes );
608 XCBPIXMAP theIconPixmap;
610 CARD32 theWindowAttributes[] = {
611 theWhitePixel, /* background */
612 theBlackPixel, /* border */
613 False, /* override_redirect */
617 unsigned long theWindowMask = XCBCWBackPixel | XCBCWBorderPixel |
618 XCBCWOverrideRedirect | XCBCWEventMask | XCBCWCursor;
620 theWindow = XCBWINDOWNew( xc );
625 WindowPointX, WindowPointY,
626 WindowWidth, WindowHeight,
628 XCBWindowClassInputOutput,
629 theScreen->root_visual, /* CopyFromParent */
630 theWindowMask, theWindowAttributes );
632 theIconPixmap = CreateBitmapFromData( xc, theWindow,
633 icon_bits, icon_width, icon_height );
636 /* Um... there is no function to send the hints...
638 WMHintsSetIconPixmap( &theHints, theIconPixmap );
641 WMHintsSetIconic( &theHints );
643 WMHintsSetNormal( &theHints );
645 theWMHints.icon_pixmap = theIconPixmap;
648 theWMHints.initial_state = IconicState;
650 theWMHints.initial_state = NormalState;
652 theWMHints.flags = IconPixmapHint | StateHint;
654 XSetWMHints( theDisplay, theWindow, &theWMHints );
659 SizeHints *hints = AllocSizeHints();
660 SizeHintsSetPosition(hints, WindowPointX, WindowPointY);
661 SizeHintsSetSize(hints, WindowWidth, WindowHeight);
662 SetWMNormalHints(xc, theWindow, hints);
663 FreeSizeHints(hints);
665 XSizeHints theSizeHints;
667 theSizeHints.flags = PPosition | PSize;
668 theSizeHints.x = WindowPointX;
669 theSizeHints.y = WindowPointY;
670 theSizeHints.width = WindowWidth;
671 theSizeHints.height = WindowHeight;
673 XSetNormalHints( theDisplay, theWindow, &theSizeHints );
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 );
680 XCBMapWindow( xc, theWindow );
682 /* moved to the CreateWindow attribute list */
683 /* XSelectInput( theDisplay, theWindow, EVENT_MASK ); */
688 /* is this really necessary? */
689 XSetWindowBackground( theDisplay, theWindow, theWhitePixel );
690 XClearWindow( theDisplay, theWindow );
691 XFlush( theDisplay );
694 XGetGeometry( theDisplay, theWindow, &theRoot,
695 &WindowPointX, &WindowPointY, &WindowWidth, &WindowHeight,
696 &BorderWidth, &theDepth );
703 /* latency: ask for keysyms now, and receive them later */
704 theKeySyms = XCBKeySymbolsAlloc( xc );
706 /* later: XCBKeySymbolsFree( keysyms ); */
707 /* later: XCBRefreshKeyboardMapping ( keysyms, mappingEvent ); */
711 void Interval(void) {
716 void TickCount(void) {
717 if ( ++NekoTickCount >= MAX_TICK )
720 if ( NekoTickCount % 2 == 0 )
721 if ( NekoStateCount < MAX_TICK )
727 SetNekoState( int SetValue )
732 NekoState = SetValue;
735 switch ( NekoState ) {
745 NekoMoveDx = NekoMoveDy = 0;
754 /* Xlib does merging of requests, but the Flush and frequent DrawGC changes
755 defeat this mechanism */
758 DrawNeko( int x, int y, XCBGCONTEXT DrawGC )
760 XCBDRAWABLE drawable; drawable.window = theWindow;
761 XCBRECTANGLE rect = { NekoLastX, NekoLastY, BITMAP_WIDTH, BITMAP_HEIGHT };
763 if ( (x != NekoLastX || y != NekoLastY) && (EventState != DEBUG_LIST) )
765 XCBPolyFillRectangle( xc, drawable, SpaceGC, 1, &rect );
766 rect.x = x; rect.y = y;
770 CARD32 originMask = XCBGCTileStippleOriginX | XCBGCTileStippleOriginY;
771 CARD32 origin[2] = { x, y };
772 XCBChangeGC( xc, DrawGC, originMask, origin );
773 /* XSetTSOrigin( theDisplay, DrawGC, x, y ); */
775 XCBPolyFillRectangle( xc, drawable, DrawGC, 1, &rect );
786 void RedrawNeko(void) {
787 XCBDRAWABLE drawable; drawable.window = theWindow;
788 XCBRECTANGLE rect = { NekoLastX, NekoLastY, BITMAP_WIDTH, BITMAP_HEIGHT };
790 XCBPolyFillRectangle( xc, drawable, NekoLastGC, 1, &rect );
797 void NekoDirection(void) {
799 double LargeX, LargeY;
803 if ( NekoMoveDx == 0 && NekoMoveDy == 0 ) {
804 NewState = NEKO_STOP;
806 LargeX = (double)NekoMoveDx;
807 LargeY = (double)(-NekoMoveDy);
808 Length = sqrt( LargeX * LargeX + LargeY * LargeY );
809 SinTheta = LargeY / Length;
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;
824 NewState = NEKO_D_MOVE;
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;
839 NewState = NEKO_D_MOVE;
844 if ( NekoState != NewState ) {
845 SetNekoState( NewState );
850 Bool IsWindowOver(void) {
851 Bool ReturnValue = False;
856 } else if ( NekoY >= WindowHeight - BITMAP_HEIGHT ) {
857 NekoY = WindowHeight - BITMAP_HEIGHT;
863 } else if ( NekoX >= WindowWidth - BITMAP_WIDTH ) {
864 NekoX = WindowWidth - BITMAP_WIDTH;
868 return( ReturnValue );
872 Bool IsNekoDontMove(void) {
873 return( NekoX == NekoLastX && NekoY == NekoLastY );
877 Bool IsNekoMoveStart(void) {
879 if ( (PrevMouseX >= MouseX - IDLE_SPACE
880 && PrevMouseX <= MouseX + IDLE_SPACE) &&
881 (PrevMouseY >= MouseY - IDLE_SPACE
882 && PrevMouseY <= MouseY + IDLE_SPACE) )
887 if ( NekoMoveDx == 0 && NekoMoveDy == 0 )
895 void CalcDxDy(void) {
896 int RelativeX, RelativeY;
897 double LargeX, LargeY;
898 double DoubleLength, Length;
900 /* TODO: replace query with pointer motion notification? */
902 XCBQueryPointerRep *reply = XCBQueryPointerReply( xc,
903 XCBQueryPointer( xc, theWindow ), NULL);
905 RelativeX = reply->win_x;
906 RelativeY = reply->win_y;
916 LargeX = (double)( MouseX - NekoX - BITMAP_WIDTH / 2 );
917 LargeY = (double)( MouseY - NekoY - BITMAP_HEIGHT );
919 DoubleLength = LargeX * LargeX + LargeY * LargeY;
921 if ( DoubleLength != (double)0 ) {
922 Length = sqrt( DoubleLength );
923 if ( Length <= NekoSpeed ) {
924 NekoMoveDx = (int)LargeX;
925 NekoMoveDy = (int)LargeY;
927 NekoMoveDx = (int)( ( NekoSpeed * LargeX ) / Length );
928 NekoMoveDy = (int)( ( NekoSpeed * LargeY ) / Length );
931 NekoMoveDx = NekoMoveDy = 0;
936 void NekoThinkDraw(void) {
941 if ( NekoState != NEKO_SLEEP ) {
942 DrawNeko( NekoX, NekoY,
943 NekoTickCount % 2 == 0 ?
944 *(AnimationPattern[ NekoState ].TickEvenGCPtr) :
945 *(AnimationPattern[ NekoState ].TickOddGCPtr) );
947 DrawNeko( NekoX, NekoY,
948 NekoTickCount % 8 <= 3 ?
949 *(AnimationPattern[ NekoState ].TickEvenGCPtr) :
950 *(AnimationPattern[ NekoState ].TickOddGCPtr) );
955 switch ( NekoState ) {
957 if ( IsNekoMoveStart() ) {
958 SetNekoState( NEKO_AWAKE );
961 if ( NekoStateCount < NEKO_STOP_TIME ) {
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 );
973 SetNekoState( NEKO_JARE );
977 if ( IsNekoMoveStart() ) {
978 SetNekoState( NEKO_AWAKE );
981 if ( NekoStateCount < NEKO_JARE_TIME ) {
984 SetNekoState( NEKO_KAKI );
987 if ( IsNekoMoveStart() ) {
988 SetNekoState( NEKO_AWAKE );
991 if ( NekoStateCount < NEKO_KAKI_TIME ) {
994 SetNekoState( NEKO_AKUBI );
997 if ( IsNekoMoveStart() ) {
998 SetNekoState( NEKO_AWAKE );
1001 if ( NekoStateCount < NEKO_AKUBI_TIME ) {
1004 SetNekoState( NEKO_SLEEP );
1007 if ( IsNekoMoveStart() ) {
1008 SetNekoState( NEKO_AWAKE );
1013 if ( NekoStateCount < NEKO_AWAKE_TIME ) {
1026 NekoX += NekoMoveDx;
1027 NekoY += NekoMoveDy;
1029 if ( IsWindowOver() ) {
1030 if ( IsNekoDontMove() ) {
1031 SetNekoState( NEKO_STOP );
1039 if ( IsNekoMoveStart() ) {
1040 SetNekoState( NEKO_AWAKE );
1043 if ( NekoStateCount < NEKO_TOGI_TIME ) {
1046 SetNekoState( NEKO_KAKI );
1049 /* Internal Error */
1050 SetNekoState( NEKO_STOP );
1059 void DisplayCharacters() {
1063 for ( Index = 0, x = 0, y = 0;
1064 BitmapGCDataTable[ Index ].GCCreatePtr != NULL; Index++ ) {
1066 DrawNeko( x, y, *(BitmapGCDataTable[ Index ].GCCreatePtr) );
1067 XFlush( theDisplay );
1071 if ( x > WindowWidth - BITMAP_WIDTH ) {
1074 if ( y > WindowHeight - BITMAP_HEIGHT) {
1084 ProcessKeyPress( XCBKeyPressEvent *theKeyEvent )
1086 Bool ReturnState = True;
1088 /* quit on Meta-Q (Alt-Q) */
1089 XCBKEYSYM theKeySym;
1091 /* last param is "int col". What? add enumeration to xcb_keysyms.h */
1092 theKeySym = XCBKeyPressLookupKeysym( theKeySyms, theKeyEvent, 1 );
1094 /* KeySym XK_Q == 'Q' */
1095 if (theKeySym.id == 'Q' && (theKeyEvent->state & XCBModMask1))
1096 ReturnState = False;
1099 if ( EventState == DEBUG_MOVE ) {
1100 switch ( theKeySym ) {
1102 NekoMoveDx = -(int)( NekoSpeed / sqrt( (double)2 ) );
1103 NekoMoveDy = -NekoMoveDx;
1107 NekoMoveDy = (int)NekoSpeed;
1110 NekoMoveDx = (int)( NekoSpeed / sqrt( (double)2 ) );
1111 NekoMoveDy = NekoMoveDx;
1114 NekoMoveDx = -(int)NekoSpeed;
1122 NekoMoveDx = (int)NekoSpeed;
1126 NekoMoveDx = -(int)( NekoSpeed / sqrt( (double)2 ) );
1127 NekoMoveDy = NekoMoveDx;
1131 NekoMoveDy = -(int)NekoSpeed;
1134 NekoMoveDx = (int)( NekoSpeed / sqrt( (double)2 ) );
1135 NekoMoveDy = -NekoMoveDx;
1141 return( ReturnState );
1145 void NekoAdjust(void) {
1148 else if ( NekoX > WindowWidth - BITMAP_WIDTH )
1149 NekoX = WindowWidth - BITMAP_WIDTH;
1153 else if ( NekoY > WindowHeight - BITMAP_HEIGHT )
1154 NekoY = WindowHeight - BITMAP_HEIGHT;
1157 Bool ProcessEvent(void) {
1158 XCBGenericEvent *theEvent;
1159 XCBConfigureNotifyEvent *theConfigureNotification;
1160 XCBExposeEvent *theExposure;
1161 XCBButtonPressEvent *theButtonPress;
1162 Bool ContinueState = True;
1165 switch ( EventState ) {
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;
1179 theExposure = (XCBExposeEvent *)theEvent;
1180 if ( theExposure->count == 0 )
1187 ContinueState = ProcessKeyPress( (XCBKeyPressEvent *)theEvent );
1188 if ( !ContinueState ) {
1190 return( ContinueState );
1193 case XCBButtonPress:
1194 theButtonPress = (XCBButtonPressEvent *)theEvent;
1195 if ( theButtonPress->detail.id == 3 ) { /* xbutton.button */
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;
1221 if ( theEvent.xexpose.count == 0 )
1222 DisplayCharacters();
1225 DisplayCharacters();
1228 ContinueState = ProcessKeyPress( &theEvent );
1231 if ( theEvent.xbutton.button == 3 )
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;
1251 if ( theEvent.xexpose.count == 0 )
1258 ContinueState = ProcessKeyPress( &theEvent );
1259 if ( !ContinueState ) {
1260 return( ContinueState );
1264 if ( theEvent.xbutton.button == 3 )
1275 /* Internal Error */
1279 return( ContinueState );
1283 void ProcessNeko(void) {
1284 struct itimerval Value;
1286 EventState = NORMAL_STATE;
1288 NekoX = ( WindowWidth - BITMAP_WIDTH / 2 ) / 2;
1289 NekoY = ( WindowHeight - BITMAP_HEIGHT / 2 ) / 2;
1294 SetNekoState( NEKO_STOP );
1296 timerclear( &Value.it_interval );
1297 timerclear( &Value.it_value );
1299 Value.it_interval.tv_usec = IntervalTime;
1300 Value.it_value.tv_usec = IntervalTime;
1302 setitimer( ITIMER_REAL, &Value, 0 );
1306 } while ( ProcessEvent() );
1312 EventState = DEBUG_LIST;
1314 fprintf( stderr, "\n" );
1315 fprintf( stderr, "G-0lMw$rI=<($7$^$9!#(Quit !D Alt-Q)\n" );
1316 fprintf( stderr, "\n" );
1318 XSelectInput( theDisplay, theWindow, EVENT_MASK );
1320 while ( ProcessEvent() );
1324 void NekoMoveTest() {
1325 struct itimerval Value;
1327 EventState = DEBUG_MOVE;
1329 NekoX = ( WindowWidth - BITMAP_WIDTH / 2 ) / 2;
1330 NekoY = ( WindowHeight - BITMAP_HEIGHT / 2 ) / 2;
1335 SetNekoState( NEKO_STOP );
1337 timerclear( &Value.it_interval );
1338 timerclear( &Value.it_value );
1340 Value.it_interval.tv_usec = IntervalTime;
1341 Value.it_value.tv_usec = IntervalTime;
1343 setitimer( ITIMER_REAL, &Value, 0 );
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" );
1354 } while ( ProcessEvent() );
1358 void ProcessDebugMenu() {
1359 int UserSelectNo = 0;
1360 char UserAnswer[ BUFSIZ ];
1362 fprintf( stderr, "\n" );
1363 fprintf( stderr, "!Zxneko %G%P%C%0%a%K%e!<![\n" );
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: " );
1372 fgets( UserAnswer, sizeof( UserAnswer ), stdin );
1374 UserSelectNo = atoi( UserAnswer );
1376 if ( !( UserSelectNo >= 1 && UserSelectNo <= 2 ) ) {
1377 fprintf( stderr, "\n" );
1378 fprintf( stderr, "@5$7$$HV9f$rA*Br$7$F2<$5$$!#\n" );
1382 switch ( UserSelectNo ) {
1390 /* Internal Error */
1394 fprintf( stderr, "%F%9%H=*N;!#\n" );
1395 fprintf( stderr, "\n" );
1400 void NullFunction(int ignored)
1402 /* signal( SIGALRM, NullFunction ); */
1408 "Usage: %s [-display <display>] [-geometry <geometry>] \\\n",
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" );
1417 GetArguments( int argc, char *argv[],
1418 char *theDisplayName, char *theGeometry, char **theTitle,
1419 double *NekoSpeed, long *IntervalTime )
1424 theDisplayName[ 0 ] = '\0';
1425 theGeometry[ 0 ] = '\0';
1427 iconicState = False;
1429 for ( ArgCounter = 0; ArgCounter < argc; ArgCounter++ ) {
1430 if ( strncmp( argv[ ArgCounter ], "-h", 2 ) == 0 ) {
1433 } else if ( strcmp( argv[ ArgCounter ], "-display" ) == 0 ) {
1435 if ( ArgCounter < argc ) {
1436 strcpy( theDisplayName, argv[ ArgCounter ] );
1438 fprintf( stderr, "%s: -display option error.\n", ProgramName );
1441 } else if ( strncmp( argv[ ArgCounter ], "-geom", 5 ) == 0 ) {
1443 if ( ArgCounter < argc ) {
1444 strcpy( theGeometry, argv[ ArgCounter ] );
1447 "%s: -geometry option error.\n", ProgramName );
1450 } else if ( ( strcmp( argv[ ArgCounter ], "-title" ) == 0 )
1451 || ( strcmp( argv[ ArgCounter ], "-name" ) == 0 ) ) {
1453 if ( ArgCounter < argc ) {
1454 *theTitle = argv[ ArgCounter ];
1456 fprintf( stderr, "%s: -title option error.\n", ProgramName );
1459 } else if ( strcmp( argv[ ArgCounter ], "-iconic" ) == 0 ) {
1461 } else if ( strcmp( argv[ ArgCounter ], "-speed" ) == 0 ) {
1463 if ( ArgCounter < argc ) {
1464 *NekoSpeed = atof( argv[ ArgCounter ] );
1466 fprintf( stderr, "%s: -speed option error.\n", ProgramName );
1469 } else if ( strcmp( argv[ ArgCounter ], "-fg" ) == 0 ) {
1471 if ( ArgCounter < argc ) {
1472 fgColor = argv[ArgCounter];
1474 fprintf( stderr, "%s: -fg option error.\n", ProgramName );
1477 } else if ( strcmp( argv[ ArgCounter ], "-bg" ) == 0 ) {
1479 if ( ArgCounter < argc ) {
1480 bgColor = argv[ArgCounter];
1482 fprintf( stderr, "%s: -bg option error.\n", ProgramName );
1485 } else if ( strcmp( argv[ ArgCounter ], "-time" ) == 0 ) {
1487 if ( ArgCounter < argc ) {
1488 *IntervalTime = atol( argv[ ArgCounter ] );
1490 fprintf( stderr, "%s: -time option error.\n", ProgramName );
1493 } else if ( strcmp( argv[ ArgCounter ], "-root" ) == 0 ) {
1497 "%s: Unknown option \"%s\".\n", ProgramName,
1498 argv[ ArgCounter ] );
1504 return( iconicState );
1507 void UndefineCursor( XCBConnection *c, XCBWINDOW w)
1509 CARD32 none[] = { XCBNone };
1510 XCBChangeWindowAttributes( c, w, XCBCWCursor, none );
1514 main( int argc, char *argv[] )
1517 char theDisplayName[ DIRNAMELEN ];
1518 char theGeometry[ DIRNAMELEN ];
1519 char *theTitle = "";
1521 ProgramName = argv[ 0 ];
1527 fgColor = bgColor = (char *) NULL;
1529 iconicState = GetArguments( argc, argv, theDisplayName, theGeometry,
1530 &theTitle, &NekoSpeed, &IntervalTime );
1532 if (theTitle[0] == 0) theTitle = ProgramName;
1533 InitScreen( theDisplayName, theGeometry, theTitle, iconicState );
1535 signal( SIGALRM, NullFunction );
1537 SinPiPer8Times3 = sin( PI_PER8 * (double)3 );
1538 SinPiPer8 = sin( PI_PER8 );
1546 UndefineCursor( xc, theWindow );
1547 XCBDisconnect( xc );