#include <X11/XCB/xcb_aux.h> /* XCBAuxGetScreen */
#include <X11/XCB/xcb_icccm.h>
#include <X11/XCB/xcb_atom.h> /* STRING atom */
+#include <X11/XCB/xcb_keysyms.h>
typedef enum { False, True } Bool;
static char *ProgramName;
-/*Display *theDisplay;*/
XCBConnection *xc;
XCBSCREEN *theScreen; /* instead of macro(theDisplay, int theScreen) */
-unsigned int theDepth;
-unsigned long theBlackPixel;
-unsigned long theWhitePixel;
+unsigned long theFgPixel;
+unsigned long theBgPixel;
XCBWINDOW theWindow;
XCBCURSOR theCursor;
+XCBKeySymbols *theKeySyms;
+XCBATOM deleteWindowAtom;
static unsigned int WindowWidth;
static unsigned int WindowHeight;
/* must swap and pad the data if bit/byte_order isn't LSB (Mac) */
/* Mac X Server: byte_order=bit_order=MSB, unit=32, padding=32 */
- long bufLen = (w+7)/8*h;
+ long bpl = (w+7)/8;
+ long pad = XCBGetSetup(c)->bitmap_format_scanline_pad;
+ long bpd = ROUNDUP(w, pad)>>3;
+ long bufLen = bpd * h;
BYTE buf[1024];
if (XCBGetSetup(c)->bitmap_format_scanline_unit == 32 &&
XCBGetSetup(c)->bitmap_format_bit_order == XCBImageOrderMSBFirst &&
XCBGetSetup(c)->image_byte_order == XCBImageOrderMSBFirst)
{
- long bpl = (w+7)/8;
- long pad = XCBGetSetup(c)->bitmap_format_scanline_pad;
- long bpd = ROUNDUP(w, pad)>>3;
- SwapBits((unsigned char *)data, (unsigned char *)buf, bpl, bpl, bpd, h);
- bufLen = bpd * h;
+ SwapBits((unsigned char *)data, buf, bpl, bpl, bpd, h);
+ }
+ else if (bpl != bpd)
+ {
+ int i;
+ BYTE *src = (BYTE *)data, *dest = buf;
+ for (i=0; i<h; i++, dest += bpd, src += bpl)
+ memcpy(dest, src, bpl);
}
else
memcpy(buf, data, bufLen);
theGCValues[0] = XCBGXcopy;
- theGCValues[1] = theBlackPixel;
- theGCValues[2] = theWhitePixel;
+ theGCValues[1] = theFgPixel;
+ theGCValues[2] = theBgPixel;
theGCValues[3] = XCBFillStyleTiled;
BitmapGCDataTablePtr->PixelPattern,
BitmapGCDataTablePtr->PixelWidth,
BitmapGCDataTablePtr->PixelHeight,
- theBlackPixel, theWhitePixel, theScreen->root_depth);
+ theFgPixel, theBgPixel, theScreen->root_depth);
theGCValues[4] = BitmapGCDataTablePtr->BitmapCreatePtr->xid; /* tile */
/* later: XCBFreePixmap( c, bitmap ); */
/* later: XCBFreeGC( c, gc ); */
- XCBFlush( xc );
+}
+
+XCBATOM
+GetAtom(XCBConnection *c, const char *atomName)
+{
+ XCBATOM atom = { XCBNone };
+ XCBInternAtomRep *r = XCBInternAtomReply(c,
+ XCBInternAtom(c, 0, strlen(atomName), atomName), NULL);
+ if (r) {
+ atom = r->atom;
+ free(r);
+ }
+ return atom;
}
void
{
XCBPIXMAP theCursorSource;
XCBPIXMAP theCursorMask;
+ unsigned int theDepth;
XCBCOLORMAP theColormap;
int screen;
XCBAllocNamedColorCookie fgCookie = XCBAllocNamedColor ( xc,
theColormap, strlen(fgColor), fgColor );
+
+ /* mouse cursor is always black and white */
+ XCBAllocNamedColorCookie blackCookie = XCBAllocNamedColor ( xc,
+ theColormap, strlen("black"), "black" );
+ XCBAllocNamedColorCookie whiteCookie = XCBAllocNamedColor ( xc,
+ theColormap, strlen("white"), "white" );
XCBAllocNamedColorRep *bgRep = XCBAllocNamedColorReply( xc, bgCookie, 0 );
if (!bgRep) {
"%s: Can't allocate the background color %s.\n", ProgramName, bgColor );
exit( 1 );
}
- theWhitePixel = bgRep->pixel;
+ theBgPixel = bgRep->pixel;
XCBAllocNamedColorRep *fgRep = XCBAllocNamedColorReply( xc, fgCookie, 0 );
if (!fgRep) {
"%s: Can't allocate the foreground color %s.\n", ProgramName, fgColor );
exit( 1 );
}
- theBlackPixel = fgRep->pixel;
+ theFgPixel = fgRep->pixel;
+
+ XCBAllocNamedColorRep *blackRep = XCBAllocNamedColorReply( xc, blackCookie, 0 );
+ if (!blackRep) {
+ fprintf( stderr,
+ "%s: Can't allocate the black color.\n", ProgramName );
+ exit( 1 );
+ }
+ XCBAllocNamedColorRep *whiteRep = XCBAllocNamedColorReply( xc, whiteCookie, 0 );
+ if (!whiteRep) {
+ fprintf( stderr,
+ "%s: Can't allocate the white color.\n", ProgramName );
+ exit( 1 );
+ }
theCursor = XCBCURSORNew( xc );
XCBCreateCursor ( xc, theCursor, theCursorSource, theCursorMask,
- fgRep->visual_red, fgRep->visual_green, fgRep->visual_blue,
- bgRep->visual_red, bgRep->visual_green, bgRep->visual_blue,
+ blackRep->visual_red, blackRep->visual_green, blackRep->visual_blue,
+ whiteRep->visual_red, whiteRep->visual_green, whiteRep->visual_blue,
cursor_x_hot, cursor_y_hot );
free(bgRep);
free(fgRep);
+ free(blackRep);
+ free(whiteRep);
if ( useRoot ) {
- CARD32 rootAttributes[] = { EVENT_MASK_ROOT, theCursor.xid };
+ CARD32 rootAttributes[] = { theBgPixel, EVENT_MASK_ROOT, theCursor.xid };
theWindow = theScreen->root;
XCBChangeWindowAttributes(xc, theWindow,
- XCBCWEventMask | XCBCWCursor, rootAttributes );
+ XCBCWBackPixel | XCBCWEventMask | XCBCWCursor, rootAttributes );
+
+ /* XClearWindow: clear area with all dimensions 0 */
+ XCBClearArea( xc, False, theWindow, 0, 0, 0, 0 );
+
+ XCBDRAWABLE d = { theWindow };
+ XCBGetGeometryRep *geometry = XCBGetGeometryReply( xc,
+ XCBGetGeometry( xc, d ), NULL);
+ if (geometry) {
+ /* only width & height are used by the program */
+ WindowWidth = geometry->width;
+ WindowHeight = geometry->height;
+ free(geometry);
+ }
+
+ /* TODO: grab key Alt-Q to quit gracefully? */
}
else {
XCBPIXMAP theIconPixmap;
CARD32 theWindowAttributes[] = {
- theWhitePixel, /* background */
- theBlackPixel, /* border */
+ theBgPixel, /* background */
+ theFgPixel, /* border */
False, /* override_redirect */
EVENT_MASK,
theCursor.xid };
theScreen->root_visual, /* CopyFromParent */
theWindowMask, theWindowAttributes );
+ /* new: obey the window-delete protocol, look for XCBClientMessage */
+ deleteWindowAtom = GetAtom(xc, "WM_DELETE_WINDOW");
+ SetWMProtocols( xc, theWindow, 1, &deleteWindowAtom );
+
theIconPixmap = CreateBitmapFromData( xc, theWindow,
icon_bits, icon_width, icon_height );
-
-#ifdef TODO_ICCCM
- /* Um... there is no function to send the hints...
- WMHints theWMHints;
- WMHintsSetIconPixmap( &theHints, theIconPixmap );
+
+ WMHints *theWMHints = AllocWMHints();
+
+ WMHintsSetIconPixmap( theWMHints, theIconPixmap );
if ( iconicState )
- WMHintsSetIconic( &theHints );
- else
- WMHintsSetNormal( &theHints );
- */
- theWMHints.icon_pixmap = theIconPixmap;
-
- if ( iconicState )
- theWMHints.initial_state = IconicState;
+ WMHintsSetIconic( theWMHints );
else
- theWMHints.initial_state = NormalState;
+ WMHintsSetNormal( theWMHints );
- theWMHints.flags = IconPixmapHint | StateHint;
+ SetWMHints( xc, theWindow, theWMHints);
- XSetWMHints( theDisplay, theWindow, &theWMHints );
-#endif
+ free( theWMHints );
-#ifdef TODO_ICCCM
- /*
- SizeHints *hints = AllocSizeHints();
- SizeHintsSetPosition(hints, WindowPointX, WindowPointY);
- SizeHintsSetSize(hints, WindowWidth, WindowHeight);
- SetWMNormalHints(xc, theWindow, hints);
- FreeSizeHints(hints);
- */
- XSizeHints theSizeHints;
-
- theSizeHints.flags = PPosition | PSize;
- theSizeHints.x = WindowPointX;
- theSizeHints.y = WindowPointY;
- theSizeHints.width = WindowWidth;
- theSizeHints.height = WindowHeight;
-
- XSetNormalHints( theDisplay, theWindow, &theSizeHints );
-#endif
+ /* why hide the structure? */
+ SizeHints *theSizeHints = AllocSizeHints();
+
+ /* need enum for second param (user specified) */
+ SizeHintsSetPosition(theSizeHints, 0, WindowPointX, WindowPointY);
+ SizeHintsSetSize(theSizeHints, 0, WindowWidth, WindowHeight);
+
+ SetWMNormalHints(xc, theWindow, theSizeHints);
+
+ FreeSizeHints(theSizeHints);
/* Um, why do I have to specify the encoding in this API? */
SetWMName( xc, theWindow, STRING, strlen(theTitle), theTitle );
XCBMapWindow( xc, theWindow );
- /* moved to the CreateWindow attribute list */
- /* XSelectInput( theDisplay, theWindow, EVENT_MASK ); */
-
}
-#ifdef TODO
- /* is this really necessary? */
- XSetWindowBackground( theDisplay, theWindow, theWhitePixel );
- XClearWindow( theDisplay, theWindow );
- XFlush( theDisplay );
-
- XCBWINDOW theRoot;
- XGetGeometry( theDisplay, theWindow, &theRoot,
- &WindowPointX, &WindowPointY, &WindowWidth, &WindowHeight,
- &BorderWidth, &theDepth );
-#endif
-
InitBitmapAndGCs();
XCBFlush(xc);
+
+ /* latency: ask for keysyms now, and receive them later */
+ theKeySyms = XCBKeySymbolsAlloc( xc );
+
+ /* later: XCBKeySymbolsFree( keysyms ); */
+ /* later: XCBRefreshKeyboardMapping ( keysyms, mappingEvent ); */
}
Bool
ProcessKeyPress( XCBKeyPressEvent *theKeyEvent )
{
-#if TODO
Bool ReturnState = True;
- int Length;
- char theKeyBuffer[ AVAIL_KEYBUF + 1 ];
- int theKeyBufferMaxLen = AVAIL_KEYBUF;
- KeySym theKeySym;
- XComposeStatus theComposeStatus;
-
- Length = XLookupString( theKeyEvent,
- theKeyBuffer, theKeyBufferMaxLen,
- &theKeySym, &theComposeStatus );
-
- if ( Length > 0 ) {
- switch ( theKeyBuffer[ 0 ] ) {
- case 'q':
- case 'Q':
- if ( theKeyEvent->state & XCBModMask1 ) { /* META (Alt) %-!< */
- ReturnState = False;
- }
- break;
- default:
- break;
- }
- }
-#else
- /* quit on any key */
- Bool ReturnState = False;
-#endif
+ /* quit on Meta-Q (Alt-Q) */
+ XCBKEYSYM theKeySym;
+ /* last param is "int col". What? add enumeration to xcb_keysyms.h */
+ theKeySym = XCBKeyPressLookupKeysym( theKeySyms, theKeyEvent, 1 );
+
+ /* KeySym XK_Q == 'Q' */
+ if (theKeySym.id == 'Q' && (theKeyEvent->state & XCBModMask1))
+ ReturnState = False;
#ifdef DEBUG
if ( EventState == DEBUG_MOVE ) {
NekoY = WindowHeight - BITMAP_HEIGHT;
}
+int IsDeleteMessage(XCBClientMessageEvent *msg)
+{
+ return msg->data.data32[0] == deleteWindowAtom.xid;
+}
+
Bool ProcessEvent(void) {
XCBGenericEvent *theEvent;
XCBConfigureNotifyEvent *theConfigureNotification;
switch ( EventState ) {
case NORMAL_STATE:
- while ( NULL != (theEvent = XCBPollForEvent( xc, &error )) ) { /*while ( XCheckMaskEvent( theDisplay, EVENT_MASK, &theEvent ) ) {*/
- switch ( theEvent->response_type ) {
+ while ( ContinueState &&
+ NULL != (theEvent = XCBPollForEvent( xc, &error )) ) { /*while ( XCheckMaskEvent( theDisplay, EVENT_MASK, &theEvent ) ) {*/
+ switch ( theEvent->response_type & 0x7f ) {
case XCBConfigureNotify:
theConfigureNotification = (XCBConfigureNotifyEvent *)theEvent;
WindowWidth = theConfigureNotification->width;
break;
case XCBKeyPress:
ContinueState = ProcessKeyPress( (XCBKeyPressEvent *)theEvent );
- if ( !ContinueState ) {
- free(theEvent);
- return( ContinueState );
- }
break;
case XCBButtonPress:
theButtonPress = (XCBButtonPressEvent *)theEvent;
- if ( theButtonPress->detail.id == 3 ) { /* xbutton.button */
- free(theEvent);
- return( False );
- }
+ ContinueState = ( theButtonPress->detail.id != 3 ); /* xbutton.button */
break;
+ /* new: handle ClientMessage */
+ case XCBClientMessage:
+ ContinueState = !IsDeleteMessage((XCBClientMessageEvent *)theEvent);
+ break;
default:
/* Unknown Event */
+ /*printf("event type:%x\n", (int)theEvent->response_type);*/
break;
}
free(theEvent);
if (error != 0)
return False;
- }
+ } /* end while */
break;
#ifdef DEBUG
case DEBUG_LIST: