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 */
31 typedef enum { False, True } Bool;
39 #include <unistd.h> /* pause() */
44 #include "bitmaps/icon.xbm"
45 #include "bitmaps/cursor.xbm"
46 #include "bitmaps/cursor_mask.xbm"
48 #include "bitmaps/space.xbm"
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"
58 #include "bitmaps/awake.xbm"
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"
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"
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
95 #define EVENT_MASK ( XCBEventMaskKeyPress | XCBEventMaskButtonPress | \
96 XCBEventMaskExposure | XCBEventMaskStructureNotify )
98 #define EVENT_MASK_ROOT ( XCBEventMaskKeyPress | XCBEventMaskExposure )
100 #define MAX_TICK 9999 /* Odd Only! */
101 #define INTERVAL 125000L
102 #define NEKO_SPEED 16
104 #define NORMAL_STATE 1
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
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
134 #define PI_PER8 ((double)3.1415926535/(double)8)
136 #define DIRNAMELEN 255
139 char *fgColor, *bgColor;
141 static char *ProgramName;
143 /*Display *theDisplay;*/
145 XCBSCREEN *theScreen; /* instead of macro(theDisplay, int theScreen) */
146 unsigned int theDepth;
147 unsigned long theBlackPixel;
148 unsigned long theWhitePixel;
152 static unsigned int WindowWidth;
153 static unsigned int WindowHeight;
154 static int WindowPointX;
155 static int WindowPointY;
157 static unsigned int BorderWidth = DEFAULT_BORDER;
159 long IntervalTime = INTERVAL;
181 XCBGCONTEXT NekoLastGC;
183 double NekoSpeed = (double)NEKO_SPEED;
185 double SinPiPer8Times3;
208 XCBPIXMAP UpLeft1Xbm;
209 XCBPIXMAP UpLeft2Xbm;
210 XCBPIXMAP UpRight1Xbm;
211 XCBPIXMAP UpRight2Xbm;
212 XCBPIXMAP DownLeft1Xbm;
213 XCBPIXMAP DownLeft2Xbm;
214 XCBPIXMAP DownRight1Xbm;
215 XCBPIXMAP DownRight2Xbm;
217 XCBPIXMAP UpTogi1Xbm;
218 XCBPIXMAP UpTogi2Xbm;
219 XCBPIXMAP DownTogi1Xbm;
220 XCBPIXMAP DownTogi2Xbm;
221 XCBPIXMAP LeftTogi1Xbm;
222 XCBPIXMAP LeftTogi2Xbm;
223 XCBPIXMAP RightTogi1Xbm;
224 XCBPIXMAP RightTogi2Xbm;
233 XCBGCONTEXT Sleep1GC;
234 XCBGCONTEXT Sleep2GC;
244 XCBGCONTEXT Right1GC;
245 XCBGCONTEXT Right2GC;
246 XCBGCONTEXT UpLeft1GC;
247 XCBGCONTEXT UpLeft2GC;
248 XCBGCONTEXT UpRight1GC;
249 XCBGCONTEXT UpRight2GC;
250 XCBGCONTEXT DownLeft1GC;
251 XCBGCONTEXT DownLeft2GC;
252 XCBGCONTEXT DownRight1GC;
253 XCBGCONTEXT DownRight2GC;
255 XCBGCONTEXT UpTogi1GC;
256 XCBGCONTEXT UpTogi2GC;
257 XCBGCONTEXT DownTogi1GC;
258 XCBGCONTEXT DownTogi2GC;
259 XCBGCONTEXT LeftTogi1GC;
260 XCBGCONTEXT LeftTogi2GC;
261 XCBGCONTEXT RightTogi1GC;
262 XCBGCONTEXT RightTogi2GC;
265 XCBGCONTEXT *GCCreatePtr;
266 XCBPIXMAP *BitmapCreatePtr;
268 unsigned int PixelWidth;
269 unsigned int PixelHeight;
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 },
293 &UpRight1Xbm, upright1_bits, upright1_width, upright1_height },
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 },
299 &DownRight1Xbm, dwright1_bits, dwright1_width, dwright1_height },
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 },
309 &RightTogi1Xbm, rtogi1_bits, rtogi1_width, rtogi1_height },
311 &RightTogi2Xbm, rtogi2_bits, rtogi2_width, rtogi2_height },
312 { NULL, NULL, NULL, 0, 0 }
316 XCBGCONTEXT *TickEvenGCPtr;
317 XCBGCONTEXT *TickOddGCPtr;
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 */
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
378 /* convert 1Ll <--> 4Mm */
381 register unsigned char *src,
382 register unsigned char *dest,
383 long srclen, long srcinc, long destinc,
387 register const unsigned char *rev = _reverse_byte;
391 for (h = height; --h >= 0; src += srcinc, dest += destinc)
392 for (n = srclen; --n >= 0; )
393 *dest++ = rev[*src++];
396 /* assumes pad is a power of 2 */
397 #define ROUNDUP(nbytes, pad) (((nbytes) + ((pad) - 1)) & ~(long)((pad) - 1))
399 /* CrPFBData.c and CrBFData.c (very similar) */
400 /* if depth==1, behaves like CreateBitmapFromData */
401 XCBPIXMAP CreatePixmapFromBitmapData( XCBConnection *c,
402 XCBWINDOW window, char *data, CARD16 w, CARD16 h,
403 CARD32 fg, CARD32 bg, CARD32 depth)
405 XCBDRAWABLE drawable;
406 XCBPIXMAP bitmap = XCBPIXMAPNew( c );
408 drawable.window = window;
409 XCBCreatePixmap( c, depth, bitmap, drawable, w, h );
411 XCBGCONTEXT gc = XCBGCONTEXTNew( c );
413 CARD32 mask = (depth==1 ? 0 : XCBGCForeground | XCBGCBackground);
414 CARD32 values[] = { fg, bg };
416 drawable.pixmap = bitmap;
417 XCBCreateGC( c, gc, drawable, mask, values );
419 /* XImage attributes: bpp=1, xoffset=0,
420 byte_order=bit_order=LSB, unit=8, pad=8, bpl=(w+7/8) */
422 /* must swap and pad the data if bit/byte_order isn't LSB (Mac) */
424 /* Mac X Server: byte_order=bit_order=MSB, unit=32, padding=32 */
425 long bufLen = (w+7)/8*h;
427 if (XCBGetSetup(c)->bitmap_format_scanline_unit == 32 &&
428 XCBGetSetup(c)->bitmap_format_bit_order == XCBImageOrderMSBFirst &&
429 XCBGetSetup(c)->image_byte_order == XCBImageOrderMSBFirst)
432 long pad = XCBGetSetup(c)->bitmap_format_scanline_pad;
433 long bpd = ROUNDUP(w, pad)>>3;
434 SwapBits((unsigned char *)data, (unsigned char *)buf, bpl, bpl, bpd, h);
438 memcpy(buf, data, bufLen);
440 /* note: CBfD uses XYPixmap, but CPfBD uses XYBitmap
441 there shouldn't be a difference when depth==1,
442 but the neko images are corrupt if using XYPixmap */
443 CARD8 format = (depth==1 ? XCBImageFormatXYPixmap : XCBImageFormatXYBitmap);
445 /* PutImage.c: left_pad = (image->xoffset + req->xoffset) & (dpy->bitmap_unit-1)
446 screen->bitmap_format_scanline_unit
447 left_pad = (0 + 0) & (32 - 1) = 0 */
449 XCBPutImage( c, format, drawable, gc,
451 0, 1, /* left_pad, depth */
455 XCBGenericError *error = NULL;
456 XCBSync( c, &error );
458 printf("error code %d", (int)error->error_code);
465 /* later: XCBFreePixmap( c, bitmap ); */
469 XCBPIXMAP CreateBitmapFromData(XCBConnection *c, XCBWINDOW window,
470 char *data, CARD16 w, CARD16 h)
473 return CreatePixmapFromBitmapData(c, window, data, w, h, 0, 0, depth);
476 void InitBitmapAndGCs(void) {
477 BitmapGCData *BitmapGCDataTablePtr;
478 CARD32 theGCValues[5];
479 XCBDRAWABLE drawable; drawable.window = theWindow;
481 theGCValues[0] = XCBGXcopy;
483 theGCValues[1] = theBlackPixel;
484 theGCValues[2] = theWhitePixel;
486 theGCValues[3] = XCBFillStyleTiled;
488 /* TODO: latency: make all the bitmaps, then all the contexts? */
490 for ( BitmapGCDataTablePtr = BitmapGCDataTable;
491 BitmapGCDataTablePtr->GCCreatePtr != NULL;
492 BitmapGCDataTablePtr++ ) {
494 *(BitmapGCDataTablePtr->BitmapCreatePtr)
495 = CreatePixmapFromBitmapData( xc, theScreen->root,
496 BitmapGCDataTablePtr->PixelPattern,
497 BitmapGCDataTablePtr->PixelWidth,
498 BitmapGCDataTablePtr->PixelHeight,
499 theBlackPixel, theWhitePixel, theScreen->root_depth);
501 theGCValues[4] = BitmapGCDataTablePtr->BitmapCreatePtr->xid; /* tile */
503 *(BitmapGCDataTablePtr->GCCreatePtr) = XCBGCONTEXTNew( xc );
504 XCBCreateGC( xc, *(BitmapGCDataTablePtr->GCCreatePtr), drawable,
505 XCBGCFunction | XCBGCForeground | XCBGCBackground |
506 XCBGCFillStyle | XCBGCTile,
510 /* later: XCBFreePixmap( c, bitmap ); */
511 /* later: XCBFreeGC( c, gc ); */
516 InitScreen( char *DisplayName, char *theGeometry, char *theTitle, Bool iconicState )
518 XCBPIXMAP theCursorSource;
519 XCBPIXMAP theCursorMask;
520 XCBCOLORMAP theColormap;
523 if ( ( xc = XCBConnect( DisplayName, &screen ) ) == NULL ) {
524 fprintf( stderr, "%s: Can't open connection", ProgramName );
525 if ( DisplayName != NULL )
526 fprintf( stderr, " %s.\n", DisplayName );
528 fprintf( stderr, ".\n" );
532 theScreen = XCBAuxGetScreen(xc, screen);
533 if (theScreen == NULL) {
534 fprintf( stderr, "%s: Can't get default screen", ProgramName );
538 theDepth = theScreen->root_depth; /* DefaultDepth */
539 theColormap = theScreen->default_colormap;
541 WindowPointX = DEFAULT_WIN_X;
542 WindowPointY = DEFAULT_WIN_Y;
543 WindowWidth = WINDOW_WIDTH;
544 WindowHeight = WINDOW_HEIGHT;
548 GeometryStatus = XParseGeometry( theGeometry,
549 &WindowPointX, &WindowPointY,
550 &WindowWidth, &WindowHeight );
553 theCursorSource = CreateBitmapFromData( xc,
559 theCursorMask = CreateBitmapFromData( xc,
563 cursor_mask_height );
566 if ( bgColor == NULL) bgColor = "white";
567 if ( fgColor == NULL) fgColor = "black";
569 XCBAllocNamedColorCookie bgCookie = XCBAllocNamedColor ( xc,
570 theColormap, strlen(bgColor), bgColor );
572 XCBAllocNamedColorCookie fgCookie = XCBAllocNamedColor ( xc,
573 theColormap, strlen(fgColor), fgColor );
575 XCBAllocNamedColorRep *bgRep = XCBAllocNamedColorReply( xc, bgCookie, 0 );
578 "%s: Can't allocate the background color %s.\n", ProgramName, bgColor );
581 theWhitePixel = bgRep->pixel;
583 XCBAllocNamedColorRep *fgRep = XCBAllocNamedColorReply( xc, fgCookie, 0 );
586 "%s: Can't allocate the foreground color %s.\n", ProgramName, fgColor );
589 theBlackPixel = fgRep->pixel;
591 theCursor = XCBCURSORNew( xc );
592 XCBCreateCursor ( xc, theCursor, theCursorSource, theCursorMask,
593 fgRep->visual_red, fgRep->visual_green, fgRep->visual_blue,
594 bgRep->visual_red, bgRep->visual_green, bgRep->visual_blue,
595 cursor_x_hot, cursor_y_hot );
601 CARD32 rootAttributes[] = { EVENT_MASK_ROOT, theCursor.xid };
602 theWindow = theScreen->root;
603 XCBChangeWindowAttributes(xc, theWindow,
604 XCBCWEventMask | XCBCWCursor, rootAttributes );
607 XCBPIXMAP theIconPixmap;
609 CARD32 theWindowAttributes[] = {
610 theWhitePixel, /* background */
611 theBlackPixel, /* border */
612 False, /* override_redirect */
616 unsigned long theWindowMask = XCBCWBackPixel | XCBCWBorderPixel |
617 XCBCWOverrideRedirect | XCBCWEventMask | XCBCWCursor;
619 theWindow = XCBWINDOWNew( xc );
624 WindowPointX, WindowPointY,
625 WindowWidth, WindowHeight,
627 XCBWindowClassInputOutput,
628 theScreen->root_visual, /* CopyFromParent */
629 theWindowMask, theWindowAttributes );
631 theIconPixmap = CreateBitmapFromData( xc, theWindow,
632 icon_bits, icon_width, icon_height );
635 /* Um... there is no function to send the hints...
637 WMHintsSetIconPixmap( &theHints, theIconPixmap );
640 WMHintsSetIconic( &theHints );
642 WMHintsSetNormal( &theHints );
644 theWMHints.icon_pixmap = theIconPixmap;
647 theWMHints.initial_state = IconicState;
649 theWMHints.initial_state = NormalState;
651 theWMHints.flags = IconPixmapHint | StateHint;
653 XSetWMHints( theDisplay, theWindow, &theWMHints );
658 SizeHints *hints = AllocSizeHints();
659 SizeHintsSetPosition(hints, WindowPointX, WindowPointY);
660 SizeHintsSetSize(hints, WindowWidth, WindowHeight);
661 SetWMNormalHints(xc, theWindow, hints);
662 FreeSizeHints(hints);
664 XSizeHints theSizeHints;
666 theSizeHints.flags = PPosition | PSize;
667 theSizeHints.x = WindowPointX;
668 theSizeHints.y = WindowPointY;
669 theSizeHints.width = WindowWidth;
670 theSizeHints.height = WindowHeight;
672 XSetNormalHints( theDisplay, theWindow, &theSizeHints );
675 /* Um, why do I have to specify the encoding in this API? */
676 SetWMName( xc, theWindow, STRING, strlen(theTitle), theTitle );
677 SetWMIconName( xc, theWindow, STRING, strlen(theTitle), theTitle );
679 XCBMapWindow( xc, theWindow );
681 /* moved to the CreateWindow attribute list */
682 /* XSelectInput( theDisplay, theWindow, EVENT_MASK ); */
687 /* is this really necessary? */
688 XSetWindowBackground( theDisplay, theWindow, theWhitePixel );
689 XClearWindow( theDisplay, theWindow );
690 XFlush( theDisplay );
693 XGetGeometry( theDisplay, theWindow, &theRoot,
694 &WindowPointX, &WindowPointY, &WindowWidth, &WindowHeight,
695 &BorderWidth, &theDepth );
704 void Interval(void) {
709 void TickCount(void) {
710 if ( ++NekoTickCount >= MAX_TICK )
713 if ( NekoTickCount % 2 == 0 )
714 if ( NekoStateCount < MAX_TICK )
720 SetNekoState( int SetValue )
725 NekoState = SetValue;
728 switch ( NekoState ) {
738 NekoMoveDx = NekoMoveDy = 0;
747 /* Xlib does merging of requests, but the Sync and frequent DrawGC changes
748 defeat this mechanism */
751 DrawNeko( int x, int y, XCBGCONTEXT DrawGC )
753 XCBDRAWABLE drawable; drawable.window = theWindow;
754 XCBRECTANGLE rect = { NekoLastX, NekoLastY, BITMAP_WIDTH, BITMAP_HEIGHT };
756 if ( (x != NekoLastX || y != NekoLastY) && (EventState != DEBUG_LIST) )
758 XCBPolyFillRectangle( xc, drawable, SpaceGC, 1, &rect );
759 rect.x = x; rect.y = y;
763 CARD32 originMask = XCBGCTileStippleOriginX | XCBGCTileStippleOriginY;
764 CARD32 origin[2] = { x, y };
765 XCBChangeGC( xc, DrawGC, originMask, origin );
766 /* XSetTSOrigin( theDisplay, DrawGC, x, y ); */
768 XCBPolyFillRectangle( xc, drawable, DrawGC, 1, &rect );
779 void RedrawNeko(void) {
780 XCBDRAWABLE drawable; drawable.window = theWindow;
781 XCBRECTANGLE rect = { NekoLastX, NekoLastY, BITMAP_WIDTH, BITMAP_HEIGHT };
783 XCBPolyFillRectangle( xc, drawable, NekoLastGC, 1, &rect );
790 void NekoDirection(void) {
792 double LargeX, LargeY;
796 if ( NekoMoveDx == 0 && NekoMoveDy == 0 ) {
797 NewState = NEKO_STOP;
799 LargeX = (double)NekoMoveDx;
800 LargeY = (double)(-NekoMoveDy);
801 Length = sqrt( LargeX * LargeX + LargeY * LargeY );
802 SinTheta = LargeY / Length;
804 if ( NekoMoveDx > 0 ) {
805 if ( SinTheta > SinPiPer8Times3 ) {
806 NewState = NEKO_U_MOVE;
807 } else if ( ( SinTheta <= SinPiPer8Times3 )
808 && ( SinTheta > SinPiPer8 ) ) {
809 NewState = NEKO_UR_MOVE;
810 } else if ( ( SinTheta <= SinPiPer8 )
811 && ( SinTheta > -( SinPiPer8 ) ) ) {
812 NewState = NEKO_R_MOVE;
813 } else if ( ( SinTheta <= -( SinPiPer8 ) )
814 && ( SinTheta > -( SinPiPer8Times3 ) ) ) {
815 NewState = NEKO_DR_MOVE;
817 NewState = NEKO_D_MOVE;
820 if ( SinTheta > SinPiPer8Times3 ) {
821 NewState = NEKO_U_MOVE;
822 } else if ( ( SinTheta <= SinPiPer8Times3 )
823 && ( SinTheta > SinPiPer8 ) ) {
824 NewState = NEKO_UL_MOVE;
825 } else if ( ( SinTheta <= SinPiPer8 )
826 && ( SinTheta > -( SinPiPer8 ) ) ) {
827 NewState = NEKO_L_MOVE;
828 } else if ( ( SinTheta <= -( SinPiPer8 ) )
829 && ( SinTheta > -( SinPiPer8Times3 ) ) ) {
830 NewState = NEKO_DL_MOVE;
832 NewState = NEKO_D_MOVE;
837 if ( NekoState != NewState ) {
838 SetNekoState( NewState );
843 Bool IsWindowOver(void) {
844 Bool ReturnValue = False;
849 } else if ( NekoY >= WindowHeight - BITMAP_HEIGHT ) {
850 NekoY = WindowHeight - BITMAP_HEIGHT;
856 } else if ( NekoX >= WindowWidth - BITMAP_WIDTH ) {
857 NekoX = WindowWidth - BITMAP_WIDTH;
861 return( ReturnValue );
865 Bool IsNekoDontMove(void) {
866 return( NekoX == NekoLastX && NekoY == NekoLastY );
870 Bool IsNekoMoveStart(void) {
872 if ( (PrevMouseX >= MouseX - IDLE_SPACE
873 && PrevMouseX <= MouseX + IDLE_SPACE) &&
874 (PrevMouseY >= MouseY - IDLE_SPACE
875 && PrevMouseY <= MouseY + IDLE_SPACE) )
880 if ( NekoMoveDx == 0 && NekoMoveDy == 0 )
888 void CalcDxDy(void) {
889 int RelativeX, RelativeY;
890 double LargeX, LargeY;
891 double DoubleLength, Length;
893 /* TODO: replace query with pointer motion notification? */
895 XCBQueryPointerRep *reply = XCBQueryPointerReply( xc,
896 XCBQueryPointer( xc, theWindow ), NULL);
898 RelativeX = reply->win_x;
899 RelativeY = reply->win_y;
909 LargeX = (double)( MouseX - NekoX - BITMAP_WIDTH / 2 );
910 LargeY = (double)( MouseY - NekoY - BITMAP_HEIGHT );
912 DoubleLength = LargeX * LargeX + LargeY * LargeY;
914 if ( DoubleLength != (double)0 ) {
915 Length = sqrt( DoubleLength );
916 if ( Length <= NekoSpeed ) {
917 NekoMoveDx = (int)LargeX;
918 NekoMoveDy = (int)LargeY;
920 NekoMoveDx = (int)( ( NekoSpeed * LargeX ) / Length );
921 NekoMoveDy = (int)( ( NekoSpeed * LargeY ) / Length );
924 NekoMoveDx = NekoMoveDy = 0;
929 void NekoThinkDraw(void) {
934 if ( NekoState != NEKO_SLEEP ) {
935 DrawNeko( NekoX, NekoY,
936 NekoTickCount % 2 == 0 ?
937 *(AnimationPattern[ NekoState ].TickEvenGCPtr) :
938 *(AnimationPattern[ NekoState ].TickOddGCPtr) );
940 DrawNeko( NekoX, NekoY,
941 NekoTickCount % 8 <= 3 ?
942 *(AnimationPattern[ NekoState ].TickEvenGCPtr) :
943 *(AnimationPattern[ NekoState ].TickOddGCPtr) );
948 switch ( NekoState ) {
950 if ( IsNekoMoveStart() ) {
951 SetNekoState( NEKO_AWAKE );
954 if ( NekoStateCount < NEKO_STOP_TIME ) {
957 if ( NekoMoveDx < 0 && NekoX <= 0 ) {
958 SetNekoState( NEKO_L_TOGI );
959 } else if ( NekoMoveDx > 0 && NekoX >= WindowWidth - BITMAP_WIDTH ) {
960 SetNekoState( NEKO_R_TOGI );
961 } else if ( NekoMoveDy < 0 && NekoY <= 0 ) {
962 SetNekoState( NEKO_U_TOGI );
963 } else if ( NekoMoveDy > 0 && NekoY >= WindowHeight - BITMAP_HEIGHT ) {
964 SetNekoState( NEKO_D_TOGI );
966 SetNekoState( NEKO_JARE );
970 if ( IsNekoMoveStart() ) {
971 SetNekoState( NEKO_AWAKE );
974 if ( NekoStateCount < NEKO_JARE_TIME ) {
977 SetNekoState( NEKO_KAKI );
980 if ( IsNekoMoveStart() ) {
981 SetNekoState( NEKO_AWAKE );
984 if ( NekoStateCount < NEKO_KAKI_TIME ) {
987 SetNekoState( NEKO_AKUBI );
990 if ( IsNekoMoveStart() ) {
991 SetNekoState( NEKO_AWAKE );
994 if ( NekoStateCount < NEKO_AKUBI_TIME ) {
997 SetNekoState( NEKO_SLEEP );
1000 if ( IsNekoMoveStart() ) {
1001 SetNekoState( NEKO_AWAKE );
1006 if ( NekoStateCount < NEKO_AWAKE_TIME ) {
1019 NekoX += NekoMoveDx;
1020 NekoY += NekoMoveDy;
1022 if ( IsWindowOver() ) {
1023 if ( IsNekoDontMove() ) {
1024 SetNekoState( NEKO_STOP );
1032 if ( IsNekoMoveStart() ) {
1033 SetNekoState( NEKO_AWAKE );
1036 if ( NekoStateCount < NEKO_TOGI_TIME ) {
1039 SetNekoState( NEKO_KAKI );
1042 /* Internal Error */
1043 SetNekoState( NEKO_STOP );
1052 void DisplayCharacters() {
1056 for ( Index = 0, x = 0, y = 0;
1057 BitmapGCDataTable[ Index ].GCCreatePtr != NULL; Index++ ) {
1059 DrawNeko( x, y, *(BitmapGCDataTable[ Index ].GCCreatePtr) );
1060 XFlush( theDisplay );
1064 if ( x > WindowWidth - BITMAP_WIDTH ) {
1067 if ( y > WindowHeight - BITMAP_HEIGHT) {
1077 ProcessKeyPress( XCBKeyPressEvent *theKeyEvent )
1080 Bool ReturnState = True;
1083 char theKeyBuffer[ AVAIL_KEYBUF + 1 ];
1084 int theKeyBufferMaxLen = AVAIL_KEYBUF;
1086 XComposeStatus theComposeStatus;
1088 Length = XLookupString( theKeyEvent,
1089 theKeyBuffer, theKeyBufferMaxLen,
1090 &theKeySym, &theComposeStatus );
1093 switch ( theKeyBuffer[ 0 ] ) {
1096 if ( theKeyEvent->state & XCBModMask1 ) { /* META (Alt) %-!< */
1097 ReturnState = False;
1105 /* quit on any key */
1106 Bool ReturnState = False;
1111 if ( EventState == DEBUG_MOVE ) {
1112 switch ( theKeySym ) {
1114 NekoMoveDx = -(int)( NekoSpeed / sqrt( (double)2 ) );
1115 NekoMoveDy = -NekoMoveDx;
1119 NekoMoveDy = (int)NekoSpeed;
1122 NekoMoveDx = (int)( NekoSpeed / sqrt( (double)2 ) );
1123 NekoMoveDy = NekoMoveDx;
1126 NekoMoveDx = -(int)NekoSpeed;
1134 NekoMoveDx = (int)NekoSpeed;
1138 NekoMoveDx = -(int)( NekoSpeed / sqrt( (double)2 ) );
1139 NekoMoveDy = NekoMoveDx;
1143 NekoMoveDy = -(int)NekoSpeed;
1146 NekoMoveDx = (int)( NekoSpeed / sqrt( (double)2 ) );
1147 NekoMoveDy = -NekoMoveDx;
1153 return( ReturnState );
1157 void NekoAdjust(void) {
1160 else if ( NekoX > WindowWidth - BITMAP_WIDTH )
1161 NekoX = WindowWidth - BITMAP_WIDTH;
1165 else if ( NekoY > WindowHeight - BITMAP_HEIGHT )
1166 NekoY = WindowHeight - BITMAP_HEIGHT;
1169 Bool ProcessEvent(void) {
1170 XCBGenericEvent *theEvent;
1171 XCBConfigureNotifyEvent *theConfigureNotification;
1172 XCBExposeEvent *theExposure;
1173 XCBButtonPressEvent *theButtonPress;
1174 Bool ContinueState = True;
1177 switch ( EventState ) {
1179 while ( NULL != (theEvent = XCBPollForEvent( xc, &error )) ) { /*while ( XCheckMaskEvent( theDisplay, EVENT_MASK, &theEvent ) ) {*/
1180 switch ( theEvent->response_type ) {
1181 case XCBConfigureNotify:
1182 theConfigureNotification = (XCBConfigureNotifyEvent *)theEvent;
1183 WindowWidth = theConfigureNotification->width;
1184 WindowHeight = theConfigureNotification->height;
1185 WindowPointX = theConfigureNotification->x;
1186 WindowPointY = theConfigureNotification->y;
1187 BorderWidth = theConfigureNotification->border_width;
1191 theExposure = (XCBExposeEvent *)theEvent;
1192 if ( theExposure->count == 0 )
1199 ContinueState = ProcessKeyPress( (XCBKeyPressEvent *)theEvent );
1200 if ( !ContinueState ) {
1202 return( ContinueState );
1205 case XCBButtonPress:
1206 theButtonPress = (XCBButtonPressEvent *)theEvent;
1207 if ( theButtonPress->detail.id == 3 ) { /* xbutton.button */
1223 XNextEvent( theDisplay, &theEvent );
1224 switch ( theEvent.type ) {
1225 case ConfigureNotify:
1226 WindowWidth = theEvent.xconfigure.width;
1227 WindowHeight = theEvent.xconfigure.height;
1228 WindowPointX = theEvent.xconfigure.x;
1229 WindowPointY = theEvent.xconfigure.y;
1230 BorderWidth = theEvent.xconfigure.border_width;
1233 if ( theEvent.xexpose.count == 0 )
1234 DisplayCharacters();
1237 DisplayCharacters();
1240 ContinueState = ProcessKeyPress( &theEvent );
1243 if ( theEvent.xbutton.button == 3 )
1252 while ( XCheckMaskEvent( theDisplay, EVENT_MASK, &theEvent ) ) {
1253 switch ( theEvent.type ) {
1254 case ConfigureNotify:
1255 WindowWidth = theEvent.xconfigure.width;
1256 WindowHeight = theEvent.xconfigure.height;
1257 WindowPointX = theEvent.xconfigure.x;
1258 WindowPointY = theEvent.xconfigure.y;
1259 BorderWidth = theEvent.xconfigure.border_width;
1263 if ( theEvent.xexpose.count == 0 )
1270 ContinueState = ProcessKeyPress( &theEvent );
1271 if ( !ContinueState ) {
1272 return( ContinueState );
1276 if ( theEvent.xbutton.button == 3 )
1287 /* Internal Error */
1291 return( ContinueState );
1295 void ProcessNeko(void) {
1296 struct itimerval Value;
1298 EventState = NORMAL_STATE;
1300 NekoX = ( WindowWidth - BITMAP_WIDTH / 2 ) / 2;
1301 NekoY = ( WindowHeight - BITMAP_HEIGHT / 2 ) / 2;
1306 SetNekoState( NEKO_STOP );
1308 timerclear( &Value.it_interval );
1309 timerclear( &Value.it_value );
1311 Value.it_interval.tv_usec = IntervalTime;
1312 Value.it_value.tv_usec = IntervalTime;
1314 setitimer( ITIMER_REAL, &Value, 0 );
1318 } while ( ProcessEvent() );
1324 EventState = DEBUG_LIST;
1326 fprintf( stderr, "\n" );
1327 fprintf( stderr, "G-0lMw$rI=<($7$^$9!#(Quit !D Alt-Q)\n" );
1328 fprintf( stderr, "\n" );
1330 XSelectInput( theDisplay, theWindow, EVENT_MASK );
1332 while ( ProcessEvent() );
1336 void NekoMoveTest() {
1337 struct itimerval Value;
1339 EventState = DEBUG_MOVE;
1341 NekoX = ( WindowWidth - BITMAP_WIDTH / 2 ) / 2;
1342 NekoY = ( WindowHeight - BITMAP_HEIGHT / 2 ) / 2;
1347 SetNekoState( NEKO_STOP );
1349 timerclear( &Value.it_interval );
1350 timerclear( &Value.it_value );
1352 Value.it_interval.tv_usec = IntervalTime;
1353 Value.it_value.tv_usec = IntervalTime;
1355 setitimer( ITIMER_REAL, &Value, 0 );
1357 fprintf( stderr, "\n" );
1358 fprintf( stderr, "G-$N0\F0%F%9%H$r9T$$$^$9!#(Quit !D Alt-Q)\n" );
1359 fprintf( stderr, "\n" );
1360 fprintf( stderr, "\t%-!<%Q%C%I>e$N%F%s%-!<$GG-$r0\F0$5$;$F2<$5$$!#\n" );
1361 fprintf( stderr, "\t(M-8z$J%-!<$O#1!A#9$G$9!#)\n" );
1362 fprintf( stderr, "\n" );
1366 } while ( ProcessEvent() );
1370 void ProcessDebugMenu() {
1371 int UserSelectNo = 0;
1372 char UserAnswer[ BUFSIZ ];
1374 fprintf( stderr, "\n" );
1375 fprintf( stderr, "!Zxneko %G%P%C%0%a%K%e!<![\n" );
1377 while ( !( UserSelectNo >= 1 && UserSelectNo <= 2 ) ) {
1378 fprintf( stderr, "\n" );
1379 fprintf( stderr, "\t1)!!G-%-%c%i%/%?!<0lMwI=<(\n" );
1380 fprintf( stderr, "\t2)!!G-0\F0%F%9%H\n" );
1381 fprintf( stderr, "\n" );
1382 fprintf( stderr, "Select: " );
1384 fgets( UserAnswer, sizeof( UserAnswer ), stdin );
1386 UserSelectNo = atoi( UserAnswer );
1388 if ( !( UserSelectNo >= 1 && UserSelectNo <= 2 ) ) {
1389 fprintf( stderr, "\n" );
1390 fprintf( stderr, "@5$7$$HV9f$rA*Br$7$F2<$5$$!#\n" );
1394 switch ( UserSelectNo ) {
1402 /* Internal Error */
1406 fprintf( stderr, "%F%9%H=*N;!#\n" );
1407 fprintf( stderr, "\n" );
1412 void NullFunction(int ignored)
1414 /* signal( SIGALRM, NullFunction ); */
1420 "Usage: %s [-display <display>] [-geometry <geometry>] \\\n",
1422 fprintf( stderr, "\t[-bg <background>] [-fg <foreground>] \\\n" );
1423 fprintf( stderr, "\t[-title <title>] [-name <title>] [-iconic] \\\n" );
1424 fprintf( stderr, "\t[-speed <speed>] [-time <time>] [-root] [-help]\n" );
1429 GetArguments( int argc, char *argv[],
1430 char *theDisplayName, char *theGeometry, char **theTitle,
1431 double *NekoSpeed, long *IntervalTime )
1436 theDisplayName[ 0 ] = '\0';
1437 theGeometry[ 0 ] = '\0';
1439 iconicState = False;
1441 for ( ArgCounter = 0; ArgCounter < argc; ArgCounter++ ) {
1442 if ( strncmp( argv[ ArgCounter ], "-h", 2 ) == 0 ) {
1445 } else if ( strcmp( argv[ ArgCounter ], "-display" ) == 0 ) {
1447 if ( ArgCounter < argc ) {
1448 strcpy( theDisplayName, argv[ ArgCounter ] );
1450 fprintf( stderr, "%s: -display option error.\n", ProgramName );
1453 } else if ( strncmp( argv[ ArgCounter ], "-geom", 5 ) == 0 ) {
1455 if ( ArgCounter < argc ) {
1456 strcpy( theGeometry, argv[ ArgCounter ] );
1459 "%s: -geometry option error.\n", ProgramName );
1462 } else if ( ( strcmp( argv[ ArgCounter ], "-title" ) == 0 )
1463 || ( strcmp( argv[ ArgCounter ], "-name" ) == 0 ) ) {
1465 if ( ArgCounter < argc ) {
1466 *theTitle = argv[ ArgCounter ];
1468 fprintf( stderr, "%s: -title option error.\n", ProgramName );
1471 } else if ( strcmp( argv[ ArgCounter ], "-iconic" ) == 0 ) {
1473 } else if ( strcmp( argv[ ArgCounter ], "-speed" ) == 0 ) {
1475 if ( ArgCounter < argc ) {
1476 *NekoSpeed = atof( argv[ ArgCounter ] );
1478 fprintf( stderr, "%s: -speed option error.\n", ProgramName );
1481 } else if ( strcmp( argv[ ArgCounter ], "-fg" ) == 0 ) {
1483 if ( ArgCounter < argc ) {
1484 fgColor = argv[ArgCounter];
1486 fprintf( stderr, "%s: -fg option error.\n", ProgramName );
1489 } else if ( strcmp( argv[ ArgCounter ], "-bg" ) == 0 ) {
1491 if ( ArgCounter < argc ) {
1492 bgColor = argv[ArgCounter];
1494 fprintf( stderr, "%s: -bg option error.\n", ProgramName );
1497 } else if ( strcmp( argv[ ArgCounter ], "-time" ) == 0 ) {
1499 if ( ArgCounter < argc ) {
1500 *IntervalTime = atol( argv[ ArgCounter ] );
1502 fprintf( stderr, "%s: -time option error.\n", ProgramName );
1505 } else if ( strcmp( argv[ ArgCounter ], "-root" ) == 0 ) {
1509 "%s: Unknown option \"%s\".\n", ProgramName,
1510 argv[ ArgCounter ] );
1516 return( iconicState );
1519 void UndefineCursor( XCBConnection *c, XCBWINDOW w)
1521 CARD32 none[] = { XCBNone };
1522 XCBChangeWindowAttributes( c, w, XCBCWCursor, none );
1526 main( int argc, char *argv[] )
1529 char theDisplayName[ DIRNAMELEN ];
1530 char theGeometry[ DIRNAMELEN ];
1531 char *theTitle = "";
1533 ProgramName = argv[ 0 ];
1539 fgColor = bgColor = (char *) NULL;
1541 iconicState = GetArguments( argc, argv, theDisplayName, theGeometry,
1542 &theTitle, &NekoSpeed, &IntervalTime );
1544 if (theTitle[0] == 0) theTitle = ProgramName;
1545 InitScreen( theDisplayName, theGeometry, theTitle, iconicState );
1547 signal( SIGALRM, NullFunction );
1549 SinPiPer8Times3 = sin( PI_PER8 * (double)3 );
1550 SinPiPer8 = sin( PI_PER8 );
1558 UndefineCursor( xc, theWindow );
1559 XCBDisconnect( xc );