neko: use WMHints stuff from Vincent.
[free-sw/xcb/demo] / neko / xcbneko.c
index bd7b706..b0b6311 100644 (file)
@@ -141,15 +141,14 @@ char        *fgColor, *bgColor;
 
 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;
@@ -424,17 +423,23 @@ XCBPIXMAP CreatePixmapFromBitmapData( XCBConnection *c,
   /*  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);
@@ -482,8 +487,8 @@ void  InitBitmapAndGCs(void) {
 
   theGCValues[0] = XCBGXcopy;
 
-  theGCValues[1] = theBlackPixel;
-  theGCValues[2] = theWhitePixel;
+  theGCValues[1] = theFgPixel;
+  theGCValues[2] = theBgPixel;
 
   theGCValues[3] = XCBFillStyleTiled;
   
@@ -498,7 +503,7 @@ void  InitBitmapAndGCs(void) {
                BitmapGCDataTablePtr->PixelPattern,
                BitmapGCDataTablePtr->PixelWidth,
                BitmapGCDataTablePtr->PixelHeight,
-               theBlackPixel, theWhitePixel, theScreen->root_depth);
+               theFgPixel, theBgPixel, theScreen->root_depth);
 
        theGCValues[4] = BitmapGCDataTablePtr->BitmapCreatePtr->xid; /* tile */
        
@@ -513,11 +518,25 @@ void  InitBitmapAndGCs(void) {
   /* later: XCBFreeGC( c, gc ); */
 }
 
+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
 InitScreen( char *DisplayName, char *theGeometry, char *theTitle, Bool iconicState )
 {
   XCBPIXMAP            theCursorSource;
   XCBPIXMAP            theCursorMask;
+  unsigned int   theDepth;
   XCBCOLORMAP          theColormap;
   int screen;
   
@@ -572,6 +591,12 @@ InitScreen( char *DisplayName, char *theGeometry, char *theTitle, Bool iconicSta
 
   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) {
@@ -579,7 +604,7 @@ InitScreen( char *DisplayName, char *theGeometry, char *theTitle, Bool iconicSta
                        "%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) {
@@ -587,29 +612,59 @@ InitScreen( char *DisplayName, char *theGeometry, char *theTitle, Bool iconicSta
                        "%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 };
@@ -629,49 +684,36 @@ InitScreen( char *DisplayName, char *theGeometry, char *theTitle, Bool iconicSta
                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 );
@@ -679,23 +721,8 @@ InitScreen( char *DisplayName, char *theGeometry, char *theTitle, Bool iconicSta
 
        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);
@@ -1154,6 +1181,11 @@ void  NekoAdjust(void) {
        NekoY = WindowHeight - BITMAP_HEIGHT;
 }
 
+int IsDeleteMessage(XCBClientMessageEvent *msg)
+{
+       return msg->data.data32[0] == deleteWindowAtom.xid;
+}
+
 Bool  ProcessEvent(void) {
   XCBGenericEvent *theEvent;
   XCBConfigureNotifyEvent *theConfigureNotification;
@@ -1164,8 +1196,9 @@ Bool  ProcessEvent(void) {
   
   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;
@@ -1185,26 +1218,24 @@ Bool  ProcessEvent(void) {
                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: