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;
145 XCBSCREEN *theScreen; /* instead of macro(theDisplay, int theScreen) */
146 unsigned long theBlackPixel;
147 unsigned long theWhitePixel;
150 XCBKeySymbols *theKeySyms;
151 XCBATOM deleteWindowAtom;
153 static unsigned int WindowWidth;
154 static unsigned int WindowHeight;
155 static int WindowPointX;
156 static int WindowPointY;
158 static unsigned int BorderWidth = DEFAULT_BORDER;
160 long IntervalTime = INTERVAL;
182 XCBGCONTEXT NekoLastGC;
184 double NekoSpeed = (double)NEKO_SPEED;
186 double SinPiPer8Times3;
209 XCBPIXMAP UpLeft1Xbm;
210 XCBPIXMAP UpLeft2Xbm;
211 XCBPIXMAP UpRight1Xbm;
212 XCBPIXMAP UpRight2Xbm;
213 XCBPIXMAP DownLeft1Xbm;
214 XCBPIXMAP DownLeft2Xbm;
215 XCBPIXMAP DownRight1Xbm;
216 XCBPIXMAP DownRight2Xbm;
218 XCBPIXMAP UpTogi1Xbm;
219 XCBPIXMAP UpTogi2Xbm;
220 XCBPIXMAP DownTogi1Xbm;
221 XCBPIXMAP DownTogi2Xbm;
222 XCBPIXMAP LeftTogi1Xbm;
223 XCBPIXMAP LeftTogi2Xbm;
224 XCBPIXMAP RightTogi1Xbm;
225 XCBPIXMAP RightTogi2Xbm;
234 XCBGCONTEXT Sleep1GC;
235 XCBGCONTEXT Sleep2GC;
245 XCBGCONTEXT Right1GC;
246 XCBGCONTEXT Right2GC;
247 XCBGCONTEXT UpLeft1GC;
248 XCBGCONTEXT UpLeft2GC;
249 XCBGCONTEXT UpRight1GC;
250 XCBGCONTEXT UpRight2GC;
251 XCBGCONTEXT DownLeft1GC;
252 XCBGCONTEXT DownLeft2GC;
253 XCBGCONTEXT DownRight1GC;
254 XCBGCONTEXT DownRight2GC;
256 XCBGCONTEXT UpTogi1GC;
257 XCBGCONTEXT UpTogi2GC;
258 XCBGCONTEXT DownTogi1GC;
259 XCBGCONTEXT DownTogi2GC;
260 XCBGCONTEXT LeftTogi1GC;
261 XCBGCONTEXT LeftTogi2GC;
262 XCBGCONTEXT RightTogi1GC;
263 XCBGCONTEXT RightTogi2GC;
266 XCBGCONTEXT *GCCreatePtr;
267 XCBPIXMAP *BitmapCreatePtr;
269 unsigned int PixelWidth;
270 unsigned int PixelHeight;
273 BitmapGCData BitmapGCDataTable[] = {
274 { &SpaceGC, &SpaceXbm, space_bits, space_width, space_height },
275 { &Mati2GC, &Mati2Xbm, mati2_bits, mati2_width, mati2_height },
276 { &Jare2GC, &Jare2Xbm, jare2_bits, jare2_width, jare2_height },
277 { &Kaki1GC, &Kaki1Xbm, kaki1_bits, kaki1_width, kaki1_height },
278 { &Kaki2GC, &Kaki2Xbm, kaki2_bits, kaki2_width, kaki2_height },
279 { &Mati3GC, &Mati3Xbm, mati3_bits, mati3_width, mati3_height },
280 { &Sleep1GC, &Sleep1Xbm, sleep1_bits, sleep1_width, sleep1_height },
281 { &Sleep2GC, &Sleep2Xbm, sleep2_bits, sleep2_width, sleep2_height },
282 { &AwakeGC, &AwakeXbm, awake_bits, awake_width, awake_height },
283 { &Up1GC, &Up1Xbm, up1_bits, up1_width, up1_height },
284 { &Up2GC, &Up2Xbm, up2_bits, up2_width, up2_height },
285 { &Down1GC, &Down1Xbm, down1_bits, down1_width, down1_height },
286 { &Down2GC, &Down2Xbm, down2_bits, down2_width, down2_height },
287 { &Left1GC, &Left1Xbm, left1_bits, left1_width, left1_height },
288 { &Left2GC, &Left2Xbm, left2_bits, left2_width, left2_height },
289 { &Right1GC, &Right1Xbm, right1_bits, right1_width, right1_height },
290 { &Right2GC, &Right2Xbm, right2_bits, right2_width, right2_height },
291 { &UpLeft1GC, &UpLeft1Xbm, upleft1_bits, upleft1_width, upleft1_height },
292 { &UpLeft2GC, &UpLeft2Xbm, upleft2_bits, upleft2_width, upleft2_height },
294 &UpRight1Xbm, upright1_bits, upright1_width, upright1_height },
296 &UpRight2Xbm, upright2_bits, upright2_width, upright2_height },
297 { &DownLeft1GC, &DownLeft1Xbm, dwleft1_bits, dwleft1_width, dwleft1_height },
298 { &DownLeft2GC, &DownLeft2Xbm, dwleft2_bits, dwleft2_width, dwleft2_height },
300 &DownRight1Xbm, dwright1_bits, dwright1_width, dwright1_height },
302 &DownRight2Xbm, dwright2_bits, dwright2_width, dwright2_height },
303 { &UpTogi1GC, &UpTogi1Xbm, utogi1_bits, utogi1_width, utogi1_height },
304 { &UpTogi2GC, &UpTogi2Xbm, utogi2_bits, utogi2_width, utogi2_height },
305 { &DownTogi1GC, &DownTogi1Xbm, dtogi1_bits, dtogi1_width, dtogi1_height },
306 { &DownTogi2GC, &DownTogi2Xbm, dtogi2_bits, dtogi2_width, dtogi2_height },
307 { &LeftTogi1GC, &LeftTogi1Xbm, ltogi1_bits, ltogi1_width, ltogi1_height },
308 { &LeftTogi2GC, &LeftTogi2Xbm, ltogi2_bits, ltogi2_width, ltogi2_height },
310 &RightTogi1Xbm, rtogi1_bits, rtogi1_width, rtogi1_height },
312 &RightTogi2Xbm, rtogi2_bits, rtogi2_width, rtogi2_height },
313 { NULL, NULL, NULL, 0, 0 }
317 XCBGCONTEXT *TickEvenGCPtr;
318 XCBGCONTEXT *TickOddGCPtr;
321 Animation AnimationPattern[] = {
322 { &Mati2GC, &Mati2GC }, /* NekoState == NEKO_STOP */
323 { &Jare2GC, &Mati2GC }, /* NekoState == NEKO_JARE */
324 { &Kaki1GC, &Kaki2GC }, /* NekoState == NEKO_KAKI */
325 { &Mati3GC, &Mati3GC }, /* NekoState == NEKO_AKUBI */
326 { &Sleep1GC, &Sleep2GC }, /* NekoState == NEKO_SLEEP */
327 { &AwakeGC, &AwakeGC }, /* NekoState == NEKO_AWAKE */
328 { &Up1GC, &Up2GC } , /* NekoState == NEKO_U_MOVE */
329 { &Down1GC, &Down2GC }, /* NekoState == NEKO_D_MOVE */
330 { &Left1GC, &Left2GC }, /* NekoState == NEKO_L_MOVE */
331 { &Right1GC, &Right2GC }, /* NekoState == NEKO_R_MOVE */
332 { &UpLeft1GC, &UpLeft2GC }, /* NekoState == NEKO_UL_MOVE */
333 { &UpRight1GC, &UpRight2GC }, /* NekoState == NEKO_UR_MOVE */
334 { &DownLeft1GC, &DownLeft2GC }, /* NekoState == NEKO_DL_MOVE */
335 { &DownRight1GC, &DownRight2GC }, /* NekoState == NEKO_DR_MOVE */
336 { &UpTogi1GC, &UpTogi2GC }, /* NekoState == NEKO_U_TOGI */
337 { &DownTogi1GC, &DownTogi2GC }, /* NekoState == NEKO_D_TOGI */
338 { &LeftTogi1GC, &LeftTogi2GC }, /* NekoState == NEKO_L_TOGI */
339 { &RightTogi1GC, &RightTogi2GC }, /* NekoState == NEKO_R_TOGI */
343 /* PutImage.c: format/unit/order conversion should move out to a library */
344 static unsigned char const _reverse_byte[0x100] = {
345 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
346 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
347 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
348 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
349 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
350 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
351 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
352 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
353 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
354 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
355 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
356 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
357 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
358 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
359 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
360 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
361 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
362 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
363 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
364 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
365 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
366 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
367 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
368 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
369 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
370 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
371 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
372 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
373 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
374 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
375 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
376 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
379 /* convert 1Ll <--> 4Mm */
382 register unsigned char *src,
383 register unsigned char *dest,
384 long srclen, long srcinc, long destinc,
388 register const unsigned char *rev = _reverse_byte;
392 for (h = height; --h >= 0; src += srcinc, dest += destinc)
393 for (n = srclen; --n >= 0; )
394 *dest++ = rev[*src++];
397 /* assumes pad is a power of 2 */
398 #define ROUNDUP(nbytes, pad) (((nbytes) + ((pad) - 1)) & ~(long)((pad) - 1))
400 /* CrPFBData.c and CrBFData.c (very similar) */
401 /* if depth==1, behaves like CreateBitmapFromData */
402 XCBPIXMAP CreatePixmapFromBitmapData( XCBConnection *c,
403 XCBWINDOW window, char *data, CARD16 w, CARD16 h,
404 CARD32 fg, CARD32 bg, CARD32 depth)
406 XCBDRAWABLE drawable;
407 XCBPIXMAP bitmap = XCBPIXMAPNew( c );
409 drawable.window = window;
410 XCBCreatePixmap( c, depth, bitmap, drawable, w, h );
412 XCBGCONTEXT gc = XCBGCONTEXTNew( c );
414 CARD32 mask = (depth==1 ? 0 : XCBGCForeground | XCBGCBackground);
415 CARD32 values[] = { fg, bg };
417 drawable.pixmap = bitmap;
418 XCBCreateGC( c, gc, drawable, mask, values );
420 /* XImage attributes: bpp=1, xoffset=0,
421 byte_order=bit_order=LSB, unit=8, pad=8, bpl=(w+7/8) */
423 /* must swap and pad the data if bit/byte_order isn't LSB (Mac) */
425 /* Mac X Server: byte_order=bit_order=MSB, unit=32, padding=32 */
426 long bufLen = (w+7)/8*h;
428 if (XCBGetSetup(c)->bitmap_format_scanline_unit == 32 &&
429 XCBGetSetup(c)->bitmap_format_bit_order == XCBImageOrderMSBFirst &&
430 XCBGetSetup(c)->image_byte_order == XCBImageOrderMSBFirst)
433 long pad = XCBGetSetup(c)->bitmap_format_scanline_pad;
434 long bpd = ROUNDUP(w, pad)>>3;
435 SwapBits((unsigned char *)data, (unsigned char *)buf, bpl, bpl, bpd, h);
439 memcpy(buf, data, bufLen);
441 /* note: CBfD uses XYPixmap, but CPfBD uses XYBitmap
442 there shouldn't be a difference when depth==1,
443 but the neko images are corrupt if using XYPixmap */
444 CARD8 format = (depth==1 ? XCBImageFormatXYPixmap : XCBImageFormatXYBitmap);
446 /* PutImage.c: left_pad = (image->xoffset + req->xoffset) & (dpy->bitmap_unit-1)
447 screen->bitmap_format_scanline_unit
448 left_pad = (0 + 0) & (32 - 1) = 0 */
450 XCBPutImage( c, format, drawable, gc,
452 0, 1, /* left_pad, depth */
456 XCBGenericError *error = NULL;
457 XCBSync( c, &error );
459 printf("error code %d", (int)error->error_code);
466 /* later: XCBFreePixmap( c, bitmap ); */
470 XCBPIXMAP CreateBitmapFromData(XCBConnection *c, XCBWINDOW window,
471 char *data, CARD16 w, CARD16 h)
474 return CreatePixmapFromBitmapData(c, window, data, w, h, 0, 0, depth);
477 void InitBitmapAndGCs(void) {
478 BitmapGCData *BitmapGCDataTablePtr;
479 CARD32 theGCValues[5];
480 XCBDRAWABLE drawable; drawable.window = theWindow;
482 theGCValues[0] = XCBGXcopy;
484 theGCValues[1] = theBlackPixel;
485 theGCValues[2] = theWhitePixel;
487 theGCValues[3] = XCBFillStyleTiled;
489 /* TODO: latency: make all the bitmaps, then all the contexts? */
491 for ( BitmapGCDataTablePtr = BitmapGCDataTable;
492 BitmapGCDataTablePtr->GCCreatePtr != NULL;
493 BitmapGCDataTablePtr++ ) {
495 *(BitmapGCDataTablePtr->BitmapCreatePtr)
496 = CreatePixmapFromBitmapData( xc, theScreen->root,
497 BitmapGCDataTablePtr->PixelPattern,
498 BitmapGCDataTablePtr->PixelWidth,
499 BitmapGCDataTablePtr->PixelHeight,
500 theBlackPixel, theWhitePixel, theScreen->root_depth);
502 theGCValues[4] = BitmapGCDataTablePtr->BitmapCreatePtr->xid; /* tile */
504 *(BitmapGCDataTablePtr->GCCreatePtr) = XCBGCONTEXTNew( xc );
505 XCBCreateGC( xc, *(BitmapGCDataTablePtr->GCCreatePtr), drawable,
506 XCBGCFunction | XCBGCForeground | XCBGCBackground |
507 XCBGCFillStyle | XCBGCTile,
511 /* later: XCBFreePixmap( c, bitmap ); */
512 /* later: XCBFreeGC( c, gc ); */
516 GetAtom(XCBConnection *c, const char *atomName)
518 XCBATOM atom = { XCBNone };
519 XCBInternAtomRep *r = XCBInternAtomReply(c,
520 XCBInternAtom(c, 0, strlen(atomName), atomName), NULL);
529 InitScreen( char *DisplayName, char *theGeometry, char *theTitle, Bool iconicState )
531 XCBPIXMAP theCursorSource;
532 XCBPIXMAP theCursorMask;
533 unsigned int theDepth;
534 XCBCOLORMAP theColormap;
537 if ( ( xc = XCBConnect( DisplayName, &screen ) ) == NULL ) {
538 fprintf( stderr, "%s: Can't open connection", ProgramName );
539 if ( DisplayName != NULL )
540 fprintf( stderr, " %s.\n", DisplayName );
542 fprintf( stderr, ".\n" );
546 theScreen = XCBAuxGetScreen(xc, screen);
547 if (theScreen == NULL) {
548 fprintf( stderr, "%s: Can't get default screen", ProgramName );
552 theDepth = theScreen->root_depth; /* DefaultDepth */
553 theColormap = theScreen->default_colormap;
555 WindowPointX = DEFAULT_WIN_X;
556 WindowPointY = DEFAULT_WIN_Y;
557 WindowWidth = WINDOW_WIDTH;
558 WindowHeight = WINDOW_HEIGHT;
562 GeometryStatus = XParseGeometry( theGeometry,
563 &WindowPointX, &WindowPointY,
564 &WindowWidth, &WindowHeight );
567 theCursorSource = CreateBitmapFromData( xc,
573 theCursorMask = CreateBitmapFromData( xc,
577 cursor_mask_height );
580 if ( bgColor == NULL) bgColor = "white";
581 if ( fgColor == NULL) fgColor = "black";
583 XCBAllocNamedColorCookie bgCookie = XCBAllocNamedColor ( xc,
584 theColormap, strlen(bgColor), bgColor );
586 XCBAllocNamedColorCookie fgCookie = XCBAllocNamedColor ( xc,
587 theColormap, strlen(fgColor), fgColor );
589 XCBAllocNamedColorRep *bgRep = XCBAllocNamedColorReply( xc, bgCookie, 0 );
592 "%s: Can't allocate the background color %s.\n", ProgramName, bgColor );
595 theWhitePixel = bgRep->pixel;
597 XCBAllocNamedColorRep *fgRep = XCBAllocNamedColorReply( xc, fgCookie, 0 );
600 "%s: Can't allocate the foreground color %s.\n", ProgramName, fgColor );
603 theBlackPixel = fgRep->pixel;
605 theCursor = XCBCURSORNew( xc );
606 XCBCreateCursor ( xc, theCursor, theCursorSource, theCursorMask,
607 fgRep->visual_red, fgRep->visual_green, fgRep->visual_blue,
608 bgRep->visual_red, bgRep->visual_green, bgRep->visual_blue,
609 cursor_x_hot, cursor_y_hot );
615 CARD32 rootAttributes[] = { EVENT_MASK_ROOT, theCursor.xid };
616 theWindow = theScreen->root;
617 XCBChangeWindowAttributes(xc, theWindow,
618 XCBCWEventMask | XCBCWCursor, rootAttributes );
621 XCBPIXMAP theIconPixmap;
623 CARD32 theWindowAttributes[] = {
624 theWhitePixel, /* background */
625 theBlackPixel, /* border */
626 False, /* override_redirect */
630 unsigned long theWindowMask = XCBCWBackPixel | XCBCWBorderPixel |
631 XCBCWOverrideRedirect | XCBCWEventMask | XCBCWCursor;
633 theWindow = XCBWINDOWNew( xc );
638 WindowPointX, WindowPointY,
639 WindowWidth, WindowHeight,
641 XCBWindowClassInputOutput,
642 theScreen->root_visual, /* CopyFromParent */
643 theWindowMask, theWindowAttributes );
645 /* new: obey the window-delete protocol, look for XCBClientMessage */
646 deleteWindowAtom = GetAtom(xc, "WM_DELETE_WINDOW");
647 SetWMProtocols( xc, theWindow, 1, &deleteWindowAtom );
649 theIconPixmap = CreateBitmapFromData( xc, theWindow,
650 icon_bits, icon_width, icon_height );
652 theWMHints.icon_pixmap = theIconPixmap;
655 theWMHints.initial_state = IconicState;
657 theWMHints.initial_state = NormalState;
659 theWMHints.flags = IconPixmapHint | StateHint;
661 XSetWMHints( theDisplay, theWindow, &theWMHints );
663 /* Um... there is no function to send the hints...
665 WMHintsSetIconPixmap( &theHints, theIconPixmap );
668 WMHintsSetIconic( &theHints );
670 WMHintsSetNormal( &theHints );
676 /* why hide the structure? */
677 SizeHints *theSizeHints = AllocSizeHints();
679 /* need enum for second param (user specified) */
680 SizeHintsSetPosition(theSizeHints, 0, WindowPointX, WindowPointY);
681 SizeHintsSetSize(theSizeHints, 0, WindowWidth, WindowHeight);
683 SetWMNormalHints(xc, theWindow, theSizeHints);
685 FreeSizeHints(theSizeHints);
687 /* Um, why do I have to specify the encoding in this API? */
688 SetWMName( xc, theWindow, STRING, strlen(theTitle), theTitle );
689 SetWMIconName( xc, theWindow, STRING, strlen(theTitle), theTitle );
691 XCBMapWindow( xc, theWindow );
696 /* is this really necessary? */
697 XSetWindowBackground( theDisplay, theWindow, theWhitePixel );
698 XClearWindow( theDisplay, theWindow );
699 XFlush( theDisplay );
702 XGetGeometry( theDisplay, theWindow, &theRoot,
703 &WindowPointX, &WindowPointY, &WindowWidth, &WindowHeight,
704 &BorderWidth, &theDepth );
711 /* latency: ask for keysyms now, and receive them later */
712 theKeySyms = XCBKeySymbolsAlloc( xc );
714 /* later: XCBKeySymbolsFree( keysyms ); */
715 /* later: XCBRefreshKeyboardMapping ( keysyms, mappingEvent ); */
719 void Interval(void) {
724 void TickCount(void) {
725 if ( ++NekoTickCount >= MAX_TICK )
728 if ( NekoTickCount % 2 == 0 )
729 if ( NekoStateCount < MAX_TICK )
735 SetNekoState( int SetValue )
740 NekoState = SetValue;
743 switch ( NekoState ) {
753 NekoMoveDx = NekoMoveDy = 0;
762 /* Xlib does merging of requests, but the Flush and frequent DrawGC changes
763 defeat this mechanism */
766 DrawNeko( int x, int y, XCBGCONTEXT DrawGC )
768 XCBDRAWABLE drawable; drawable.window = theWindow;
769 XCBRECTANGLE rect = { NekoLastX, NekoLastY, BITMAP_WIDTH, BITMAP_HEIGHT };
771 if ( (x != NekoLastX || y != NekoLastY) && (EventState != DEBUG_LIST) )
773 XCBPolyFillRectangle( xc, drawable, SpaceGC, 1, &rect );
774 rect.x = x; rect.y = y;
778 CARD32 originMask = XCBGCTileStippleOriginX | XCBGCTileStippleOriginY;
779 CARD32 origin[2] = { x, y };
780 XCBChangeGC( xc, DrawGC, originMask, origin );
781 /* XSetTSOrigin( theDisplay, DrawGC, x, y ); */
783 XCBPolyFillRectangle( xc, drawable, DrawGC, 1, &rect );
794 void RedrawNeko(void) {
795 XCBDRAWABLE drawable; drawable.window = theWindow;
796 XCBRECTANGLE rect = { NekoLastX, NekoLastY, BITMAP_WIDTH, BITMAP_HEIGHT };
798 XCBPolyFillRectangle( xc, drawable, NekoLastGC, 1, &rect );
805 void NekoDirection(void) {
807 double LargeX, LargeY;
811 if ( NekoMoveDx == 0 && NekoMoveDy == 0 ) {
812 NewState = NEKO_STOP;
814 LargeX = (double)NekoMoveDx;
815 LargeY = (double)(-NekoMoveDy);
816 Length = sqrt( LargeX * LargeX + LargeY * LargeY );
817 SinTheta = LargeY / Length;
819 if ( NekoMoveDx > 0 ) {
820 if ( SinTheta > SinPiPer8Times3 ) {
821 NewState = NEKO_U_MOVE;
822 } else if ( ( SinTheta <= SinPiPer8Times3 )
823 && ( SinTheta > SinPiPer8 ) ) {
824 NewState = NEKO_UR_MOVE;
825 } else if ( ( SinTheta <= SinPiPer8 )
826 && ( SinTheta > -( SinPiPer8 ) ) ) {
827 NewState = NEKO_R_MOVE;
828 } else if ( ( SinTheta <= -( SinPiPer8 ) )
829 && ( SinTheta > -( SinPiPer8Times3 ) ) ) {
830 NewState = NEKO_DR_MOVE;
832 NewState = NEKO_D_MOVE;
835 if ( SinTheta > SinPiPer8Times3 ) {
836 NewState = NEKO_U_MOVE;
837 } else if ( ( SinTheta <= SinPiPer8Times3 )
838 && ( SinTheta > SinPiPer8 ) ) {
839 NewState = NEKO_UL_MOVE;
840 } else if ( ( SinTheta <= SinPiPer8 )
841 && ( SinTheta > -( SinPiPer8 ) ) ) {
842 NewState = NEKO_L_MOVE;
843 } else if ( ( SinTheta <= -( SinPiPer8 ) )
844 && ( SinTheta > -( SinPiPer8Times3 ) ) ) {
845 NewState = NEKO_DL_MOVE;
847 NewState = NEKO_D_MOVE;
852 if ( NekoState != NewState ) {
853 SetNekoState( NewState );
858 Bool IsWindowOver(void) {
859 Bool ReturnValue = False;
864 } else if ( NekoY >= WindowHeight - BITMAP_HEIGHT ) {
865 NekoY = WindowHeight - BITMAP_HEIGHT;
871 } else if ( NekoX >= WindowWidth - BITMAP_WIDTH ) {
872 NekoX = WindowWidth - BITMAP_WIDTH;
876 return( ReturnValue );
880 Bool IsNekoDontMove(void) {
881 return( NekoX == NekoLastX && NekoY == NekoLastY );
885 Bool IsNekoMoveStart(void) {
887 if ( (PrevMouseX >= MouseX - IDLE_SPACE
888 && PrevMouseX <= MouseX + IDLE_SPACE) &&
889 (PrevMouseY >= MouseY - IDLE_SPACE
890 && PrevMouseY <= MouseY + IDLE_SPACE) )
895 if ( NekoMoveDx == 0 && NekoMoveDy == 0 )
903 void CalcDxDy(void) {
904 int RelativeX, RelativeY;
905 double LargeX, LargeY;
906 double DoubleLength, Length;
908 /* TODO: replace query with pointer motion notification? */
910 XCBQueryPointerRep *reply = XCBQueryPointerReply( xc,
911 XCBQueryPointer( xc, theWindow ), NULL);
913 RelativeX = reply->win_x;
914 RelativeY = reply->win_y;
924 LargeX = (double)( MouseX - NekoX - BITMAP_WIDTH / 2 );
925 LargeY = (double)( MouseY - NekoY - BITMAP_HEIGHT );
927 DoubleLength = LargeX * LargeX + LargeY * LargeY;
929 if ( DoubleLength != (double)0 ) {
930 Length = sqrt( DoubleLength );
931 if ( Length <= NekoSpeed ) {
932 NekoMoveDx = (int)LargeX;
933 NekoMoveDy = (int)LargeY;
935 NekoMoveDx = (int)( ( NekoSpeed * LargeX ) / Length );
936 NekoMoveDy = (int)( ( NekoSpeed * LargeY ) / Length );
939 NekoMoveDx = NekoMoveDy = 0;
944 void NekoThinkDraw(void) {
949 if ( NekoState != NEKO_SLEEP ) {
950 DrawNeko( NekoX, NekoY,
951 NekoTickCount % 2 == 0 ?
952 *(AnimationPattern[ NekoState ].TickEvenGCPtr) :
953 *(AnimationPattern[ NekoState ].TickOddGCPtr) );
955 DrawNeko( NekoX, NekoY,
956 NekoTickCount % 8 <= 3 ?
957 *(AnimationPattern[ NekoState ].TickEvenGCPtr) :
958 *(AnimationPattern[ NekoState ].TickOddGCPtr) );
963 switch ( NekoState ) {
965 if ( IsNekoMoveStart() ) {
966 SetNekoState( NEKO_AWAKE );
969 if ( NekoStateCount < NEKO_STOP_TIME ) {
972 if ( NekoMoveDx < 0 && NekoX <= 0 ) {
973 SetNekoState( NEKO_L_TOGI );
974 } else if ( NekoMoveDx > 0 && NekoX >= WindowWidth - BITMAP_WIDTH ) {
975 SetNekoState( NEKO_R_TOGI );
976 } else if ( NekoMoveDy < 0 && NekoY <= 0 ) {
977 SetNekoState( NEKO_U_TOGI );
978 } else if ( NekoMoveDy > 0 && NekoY >= WindowHeight - BITMAP_HEIGHT ) {
979 SetNekoState( NEKO_D_TOGI );
981 SetNekoState( NEKO_JARE );
985 if ( IsNekoMoveStart() ) {
986 SetNekoState( NEKO_AWAKE );
989 if ( NekoStateCount < NEKO_JARE_TIME ) {
992 SetNekoState( NEKO_KAKI );
995 if ( IsNekoMoveStart() ) {
996 SetNekoState( NEKO_AWAKE );
999 if ( NekoStateCount < NEKO_KAKI_TIME ) {
1002 SetNekoState( NEKO_AKUBI );
1005 if ( IsNekoMoveStart() ) {
1006 SetNekoState( NEKO_AWAKE );
1009 if ( NekoStateCount < NEKO_AKUBI_TIME ) {
1012 SetNekoState( NEKO_SLEEP );
1015 if ( IsNekoMoveStart() ) {
1016 SetNekoState( NEKO_AWAKE );
1021 if ( NekoStateCount < NEKO_AWAKE_TIME ) {
1034 NekoX += NekoMoveDx;
1035 NekoY += NekoMoveDy;
1037 if ( IsWindowOver() ) {
1038 if ( IsNekoDontMove() ) {
1039 SetNekoState( NEKO_STOP );
1047 if ( IsNekoMoveStart() ) {
1048 SetNekoState( NEKO_AWAKE );
1051 if ( NekoStateCount < NEKO_TOGI_TIME ) {
1054 SetNekoState( NEKO_KAKI );
1057 /* Internal Error */
1058 SetNekoState( NEKO_STOP );
1067 void DisplayCharacters() {
1071 for ( Index = 0, x = 0, y = 0;
1072 BitmapGCDataTable[ Index ].GCCreatePtr != NULL; Index++ ) {
1074 DrawNeko( x, y, *(BitmapGCDataTable[ Index ].GCCreatePtr) );
1075 XFlush( theDisplay );
1079 if ( x > WindowWidth - BITMAP_WIDTH ) {
1082 if ( y > WindowHeight - BITMAP_HEIGHT) {
1092 ProcessKeyPress( XCBKeyPressEvent *theKeyEvent )
1094 Bool ReturnState = True;
1096 /* quit on Meta-Q (Alt-Q) */
1097 XCBKEYSYM theKeySym;
1099 /* last param is "int col". What? add enumeration to xcb_keysyms.h */
1100 theKeySym = XCBKeyPressLookupKeysym( theKeySyms, theKeyEvent, 1 );
1102 /* KeySym XK_Q == 'Q' */
1103 if (theKeySym.id == 'Q' && (theKeyEvent->state & XCBModMask1))
1104 ReturnState = False;
1107 if ( EventState == DEBUG_MOVE ) {
1108 switch ( theKeySym ) {
1110 NekoMoveDx = -(int)( NekoSpeed / sqrt( (double)2 ) );
1111 NekoMoveDy = -NekoMoveDx;
1115 NekoMoveDy = (int)NekoSpeed;
1118 NekoMoveDx = (int)( NekoSpeed / sqrt( (double)2 ) );
1119 NekoMoveDy = NekoMoveDx;
1122 NekoMoveDx = -(int)NekoSpeed;
1130 NekoMoveDx = (int)NekoSpeed;
1134 NekoMoveDx = -(int)( NekoSpeed / sqrt( (double)2 ) );
1135 NekoMoveDy = NekoMoveDx;
1139 NekoMoveDy = -(int)NekoSpeed;
1142 NekoMoveDx = (int)( NekoSpeed / sqrt( (double)2 ) );
1143 NekoMoveDy = -NekoMoveDx;
1149 return( ReturnState );
1153 void NekoAdjust(void) {
1156 else if ( NekoX > WindowWidth - BITMAP_WIDTH )
1157 NekoX = WindowWidth - BITMAP_WIDTH;
1161 else if ( NekoY > WindowHeight - BITMAP_HEIGHT )
1162 NekoY = WindowHeight - BITMAP_HEIGHT;
1165 int IsDeleteMessage(XCBClientMessageEvent *msg)
1167 return msg->data.data32[0] == deleteWindowAtom.xid;
1170 Bool ProcessEvent(void) {
1171 XCBGenericEvent *theEvent;
1172 XCBConfigureNotifyEvent *theConfigureNotification;
1173 XCBExposeEvent *theExposure;
1174 XCBButtonPressEvent *theButtonPress;
1175 Bool ContinueState = True;
1178 switch ( EventState ) {
1180 while ( ContinueState &&
1181 NULL != (theEvent = XCBPollForEvent( xc, &error )) ) { /*while ( XCheckMaskEvent( theDisplay, EVENT_MASK, &theEvent ) ) {*/
1182 switch ( theEvent->response_type & 0x7f ) {
1183 case XCBConfigureNotify:
1184 theConfigureNotification = (XCBConfigureNotifyEvent *)theEvent;
1185 WindowWidth = theConfigureNotification->width;
1186 WindowHeight = theConfigureNotification->height;
1187 WindowPointX = theConfigureNotification->x;
1188 WindowPointY = theConfigureNotification->y;
1189 BorderWidth = theConfigureNotification->border_width;
1193 theExposure = (XCBExposeEvent *)theEvent;
1194 if ( theExposure->count == 0 )
1201 ContinueState = ProcessKeyPress( (XCBKeyPressEvent *)theEvent );
1203 case XCBButtonPress:
1204 theButtonPress = (XCBButtonPressEvent *)theEvent;
1205 ContinueState = ( theButtonPress->detail.id != 3 ); /* xbutton.button */
1207 /* new: handle ClientMessage */
1208 case XCBClientMessage:
1209 ContinueState = !IsDeleteMessage((XCBClientMessageEvent *)theEvent);
1213 /*printf("event type:%x\n", (int)theEvent->response_type);*/
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 );