Fixed X11 icon color allocation (thanks Mattias!)
authorSam Lantinga <slouken@libsdl.org>
Wed, 07 Nov 2001 17:59:07 +0000
changeset 2363f09f52ac2cc
parent 235 dde0af58db4b
child 237 2fe3fbd2bff5
Fixed X11 icon color allocation (thanks Mattias!)
src/video/x11/SDL_x11video.c
src/video/x11/SDL_x11wm.c
     1.1 --- a/src/video/x11/SDL_x11video.c	Wed Nov 07 17:58:41 2001 +0000
     1.2 +++ b/src/video/x11/SDL_x11video.c	Wed Nov 07 17:59:07 2001 +0000
     1.3 @@ -501,7 +501,6 @@
     1.4  		if ( SDL_XPixels ) {
     1.5  			int numcolors;
     1.6  			unsigned long pixel;
     1.7 -
     1.8  			numcolors = SDL_Visual->map_entries;
     1.9  			for ( pixel=0; pixel<numcolors; ++pixel ) {
    1.10  				while ( SDL_XPixels[pixel] > 0 ) {
    1.11 @@ -1050,10 +1049,10 @@
    1.12  		c = all + best;
    1.13  		if(XAllocColor(GFX_Display, SDL_XColorMap, c)) {
    1.14  			/* got it */
    1.15 -			colors[best].r = c->red >> 8;
    1.16 -			colors[best].g = c->green >> 8;
    1.17 -			colors[best].b = c->blue >> 8;
    1.18 -			++SDL_XPixels[best];
    1.19 +			colors[c->pixel].r = c->red >> 8;
    1.20 +			colors[c->pixel].g = c->green >> 8;
    1.21 +			colors[c->pixel].b = c->blue >> 8;
    1.22 +			++SDL_XPixels[c->pixel];
    1.23  		} else {
    1.24  			/* 
    1.25  			 * The colour couldn't be allocated, probably being
    1.26 @@ -1205,12 +1204,12 @@
    1.27  		}
    1.28  		if ( SDL_iconcolors ) {
    1.29  			unsigned long pixel;
    1.30 -			int numcolors =
    1.31 -				((this->screen->format)->palette)->ncolors;
    1.32 -			for ( pixel=0; pixel<numcolors; ++pixel ) {
    1.33 -				while ( SDL_iconcolors[pixel] > 0 ) {
    1.34 -					XFreeColors(SDL_Display,
    1.35 -						SDL_DisplayColormap,&pixel,1,0);
    1.36 +			Colormap dcmap = DefaultColormap(SDL_Display,
    1.37 +							 SDL_Screen);
    1.38 +			for(pixel = 0; pixel < 256; ++pixel) {
    1.39 +				while(SDL_iconcolors[pixel] > 0) {
    1.40 +					XFreeColors(GFX_Display,
    1.41 +						    dcmap, &pixel, 1, 0);
    1.42  					--SDL_iconcolors[pixel];
    1.43  				}
    1.44  			}
     2.1 --- a/src/video/x11/SDL_x11wm.c	Wed Nov 07 17:58:41 2001 +0000
     2.2 +++ b/src/video/x11/SDL_x11wm.c	Wed Nov 07 17:59:07 2001 +0000
     2.3 @@ -40,8 +40,13 @@
     2.4  #include "SDL_x11modes_c.h"
     2.5  #include "SDL_x11wm_c.h"
     2.6  
     2.7 -/* This is necessary for working properly with Enlightenment, etc. */
     2.8 -#define USE_ICON_WINDOW
     2.9 +static Uint8 reverse_byte(Uint8 x)
    2.10 +{
    2.11 +	x = (x & 0xaa) >> 1 | (x & 0x55) << 1;
    2.12 +	x = (x & 0xcc) >> 2 | (x & 0x33) << 2;
    2.13 +	x = (x & 0xf0) >> 4 | (x & 0x0f) << 4;
    2.14 +	return x;
    2.15 +}
    2.16  
    2.17  void X11_SetIcon(_THIS, SDL_Surface *icon, Uint8 *mask)
    2.18  {
    2.19 @@ -50,46 +55,123 @@
    2.20  	XImage *icon_image;
    2.21  	Pixmap icon_pixmap;
    2.22  	Pixmap mask_pixmap;
    2.23 -#ifdef USE_ICON_WINDOW
    2.24 -	Window icon_window;
    2.25 -#endif
    2.26 -	GC GC;
    2.27 +	Window icon_window = None;
    2.28 +	GC gc;
    2.29  	XGCValues GCvalues;
    2.30 -	int i, b, dbpp;
    2.31 +	int i, dbpp;
    2.32  	SDL_Rect bounds;
    2.33 -	Uint8 *LSBmask, *color_tried;
    2.34 +	Uint8 *LSBmask;
    2.35  	Visual *dvis;
    2.36 +	char *p;
    2.37 +	int masksize;
    2.38  
    2.39 -	/* Lock the event thread, in multi-threading environments */
    2.40  	SDL_Lock_EventThread();
    2.41  
    2.42  	/* The icon must use the default visual, depth and colormap of the
    2.43  	   screen, so it might need a conversion */
    2.44 +	dvis = DefaultVisual(SDL_Display, SDL_Screen);
    2.45  	dbpp = DefaultDepth(SDL_Display, SDL_Screen);
    2.46 -	switch(dbpp) {
    2.47 -	case 15:
    2.48 -	    dbpp = 16; break;
    2.49 -	case 24:
    2.50 -	    dbpp = 32; break;
    2.51 +	for(i = 0; i < this->hidden->nvisuals; i++) {
    2.52 +		if(this->hidden->visuals[i].visual == dvis) {
    2.53 +			dbpp = this->hidden->visuals[i].bpp;
    2.54 +			break;
    2.55 +		}
    2.56  	}
    2.57 -	dvis = DefaultVisual(SDL_Display, SDL_Screen);
    2.58  
    2.59  	/* The Visual struct is supposed to be opaque but we cheat a little */
    2.60  	sicon = SDL_CreateRGBSurface(SDL_SWSURFACE, icon->w, icon->h,
    2.61  				     dbpp,
    2.62  				     dvis->red_mask, dvis->green_mask,
    2.63  				     dvis->blue_mask, 0);
    2.64 +	if ( sicon == NULL )
    2.65 +		goto done;
    2.66  
    2.67 -	if ( sicon == NULL ) {
    2.68 -		goto done;
    2.69 -	}
    2.70 -	/* If we already have allocated colours from the default colormap,
    2.71 -	   copy them */
    2.72 -	if(SDL_Visual == dvis && SDL_XColorMap == SDL_DisplayColormap
    2.73 -	   && this->screen->format->palette && sicon->format->palette) {
    2.74 -	    memcpy(sicon->format->palette->colors,
    2.75 -		   this->screen->format->palette->colors,
    2.76 -		   this->screen->format->palette->ncolors * sizeof(SDL_Color));
    2.77 +	if(dbpp == 8) {
    2.78 +		/* Default visual is 8bit; we need to allocate colours from
    2.79 +		   the default colormap */
    2.80 +		SDL_Color want[256], got[256];
    2.81 +		int nwant;
    2.82 +		Colormap dcmap;
    2.83 +		int missing;
    2.84 +		dcmap = DefaultColormap(SDL_Display, SDL_Screen);
    2.85 +		if(icon->format->palette) {
    2.86 +			/* The icon has a palette as well - we just have to
    2.87 +			   find those colours */
    2.88 +			nwant = icon->format->palette->ncolors;
    2.89 +			memcpy(want, icon->format->palette->colors,
    2.90 +			       nwant * sizeof want[0]);
    2.91 +		} else {
    2.92 +			/* try the standard 6x6x6 cube for lack of better
    2.93 +			   ideas */
    2.94 +			int r, g, b, i;
    2.95 +			for(r = i = 0; r < 256; r += 0x33)
    2.96 +				for(g = 0; g < 256; g += 0x33)
    2.97 +					for(b = 0; b < 256; b += 0x33, i++) {
    2.98 +						want[i].r = r;
    2.99 +						want[i].g = g;
   2.100 +						want[i].b = b;
   2.101 +					}
   2.102 +			nwant = 216;
   2.103 +		}
   2.104 +		if(SDL_iconcolors) {
   2.105 +			/* free already allocated colours first */
   2.106 +			unsigned long freelist[512];
   2.107 +			int nfree = 0;
   2.108 +			for(i = 0; i < 256; i++) {
   2.109 +				while(SDL_iconcolors[i]) {
   2.110 +					freelist[nfree++] = i;
   2.111 +					SDL_iconcolors[i]--;
   2.112 +				}
   2.113 +			}
   2.114 +			XFreeColors(GFX_Display, dcmap, freelist, nfree, 0);
   2.115 +		}
   2.116 +		if(!SDL_iconcolors)
   2.117 +			SDL_iconcolors = malloc(256 * sizeof *SDL_iconcolors);
   2.118 +		memset(SDL_iconcolors, 0, 256 * sizeof *SDL_iconcolors);
   2.119 +
   2.120 +		/* try to allocate the colours */
   2.121 +		memset(got, 0, sizeof got);
   2.122 +		missing = 0;
   2.123 +		for(i = 0; i < nwant; i++) {
   2.124 +			XColor c;
   2.125 +			c.red = want[i].r << 8;
   2.126 +			c.green = want[i].g << 8;
   2.127 +			c.blue = want[i].b << 8;
   2.128 +			c.flags = DoRed | DoGreen | DoBlue;
   2.129 +			if(XAllocColor(GFX_Display, dcmap, &c)) {
   2.130 +				/* got the colour */
   2.131 +				SDL_iconcolors[c.pixel]++;
   2.132 +				got[c.pixel] = want[i];
   2.133 +			} else {
   2.134 +				missing = 1;
   2.135 +			}
   2.136 +		}
   2.137 +		if(missing) {
   2.138 +			/* Some colours were apparently missing, so we just
   2.139 +			   allocate all the rest as well */
   2.140 +			XColor cols[256];
   2.141 +			for(i = 0; i < 256; i++)
   2.142 +				cols[i].pixel = i;
   2.143 +			XQueryColors(GFX_Display, dcmap, cols, 256);
   2.144 +			for(i = 0; i < 256; i++) {
   2.145 +				got[i].r = cols[i].red >> 8;
   2.146 +				got[i].g = cols[i].green >> 8;
   2.147 +				got[i].b = cols[i].blue >> 8;
   2.148 +				if(!SDL_iconcolors[i]) {
   2.149 +					if(XAllocColor(GFX_Display, dcmap,
   2.150 +							cols + i)) {
   2.151 +						SDL_iconcolors[i] = 1;
   2.152 +					} else {
   2.153 +						/* index not available */
   2.154 +						got[i].r = 0;
   2.155 +						got[i].g = 0;
   2.156 +						got[i].b = 0;
   2.157 +					}
   2.158 +				}
   2.159 +			}
   2.160 +		}
   2.161 +
   2.162 +		SDL_SetColors(sicon, got, 0, 256);
   2.163  	}
   2.164  
   2.165  	bounds.x = 0;
   2.166 @@ -99,110 +181,68 @@
   2.167  	if ( SDL_LowerBlit(icon, &bounds, sicon, &bounds) < 0 )
   2.168  		goto done;
   2.169  
   2.170 -	/* Lock down the colors used in the colormap */
   2.171 -	color_tried = NULL;
   2.172 -	if ( sicon->format->BitsPerPixel == 8 ) {
   2.173 -		SDL_Palette *palette;
   2.174 -		Uint8 *p;
   2.175 -		XColor wanted;
   2.176 -
   2.177 -		palette = sicon->format->palette;
   2.178 -		color_tried = malloc(palette->ncolors);
   2.179 -		if ( color_tried == NULL ) {
   2.180 -			goto done;
   2.181 -		}
   2.182 -		if ( SDL_iconcolors != NULL ) {
   2.183 -			free(SDL_iconcolors);
   2.184 -		}
   2.185 -		SDL_iconcolors = malloc(palette->ncolors
   2.186 -					* sizeof(*SDL_iconcolors));
   2.187 -		if ( SDL_iconcolors == NULL ) {
   2.188 -			free(color_tried);
   2.189 -			goto done;
   2.190 -		}
   2.191 -		memset(color_tried, 0, palette->ncolors);
   2.192 -		memset(SDL_iconcolors, 0,
   2.193 -		       palette->ncolors * sizeof(*SDL_iconcolors));
   2.194 -
   2.195 -		p = (Uint8 *)sicon->pixels; 
   2.196 -		for ( i = sicon->w*sicon->h; i > 0; --i, ++p ) {
   2.197 -			if ( ! color_tried[*p] ) {
   2.198 -				wanted.pixel = *p;
   2.199 -				wanted.red   = (palette->colors[*p].r<<8);
   2.200 -				wanted.green = (palette->colors[*p].g<<8);
   2.201 -				wanted.blue  = (palette->colors[*p].b<<8);
   2.202 -				wanted.flags = (DoRed|DoGreen|DoBlue);
   2.203 -				if (XAllocColor(SDL_Display,
   2.204 -						SDL_DisplayColormap, &wanted)) {
   2.205 -					++SDL_iconcolors[wanted.pixel];
   2.206 -				}
   2.207 -				color_tried[*p] = 1;
   2.208 -			}
   2.209 -		}
   2.210 -	}
   2.211 -	if ( color_tried != NULL ) {
   2.212 -		free(color_tried);
   2.213 -	}
   2.214 -
   2.215 -	/* Translate mask data to LSB order and set the icon mask */
   2.216 -	i = (sicon->w/8)*sicon->h;
   2.217 -	LSBmask = (Uint8 *)malloc(i);
   2.218 +	/* We need the mask as given, except in LSBfirst format instead of
   2.219 +	   MSBfirst. Reverse the bits in each byte. */
   2.220 +	masksize = ((sicon->w + 7) >> 3) * sicon->h;
   2.221 +	LSBmask = malloc(masksize);
   2.222  	if ( LSBmask == NULL ) {
   2.223  		goto done;
   2.224  	}
   2.225 -	memset(LSBmask, 0, i);
   2.226 -	while ( --i >= 0 ) {
   2.227 -		for ( b=0; b<8; ++b )
   2.228 -			LSBmask[i] |= (((mask[i]>>b)&0x01)<<(7-b));
   2.229 -	}
   2.230 +	memset(LSBmask, 0, masksize);
   2.231 +	for(i = 0; i < masksize; i++)
   2.232 +		LSBmask[i] = reverse_byte(mask[i]);
   2.233  	mask_pixmap = XCreatePixmapFromBitmapData(SDL_Display, WMwindow,
   2.234 -		          (char *)LSBmask, sicon->w, sicon->h, 1L, 0L, 1);
   2.235 +						  (char *)LSBmask,
   2.236 +						  sicon->w, sicon->h,
   2.237 +						  1L, 0L, 1);
   2.238  
   2.239  	/* Transfer the image to an X11 pixmap */
   2.240  	icon_image = XCreateImage(SDL_Display,
   2.241 -			DefaultVisual(SDL_Display, SDL_Screen),
   2.242 -			DefaultDepth(SDL_Display, SDL_Screen),
   2.243 -			ZPixmap, 0, (char *)sicon->pixels, sicon->w, sicon->h,
   2.244 -			((sicon->format)->BytesPerPixel == 3) ? 32 :
   2.245 -				(sicon->format)->BytesPerPixel*8, 0);
   2.246 +				  DefaultVisual(SDL_Display, SDL_Screen),
   2.247 +				  DefaultDepth(SDL_Display, SDL_Screen),
   2.248 +				  ZPixmap, 0, sicon->pixels,
   2.249 +				  sicon->w, sicon->h,
   2.250 +				  32, 0);
   2.251  	icon_pixmap = XCreatePixmap(SDL_Display, SDL_Root, sicon->w, sicon->h,
   2.252 -			DefaultDepth(SDL_Display, SDL_Screen));
   2.253 -	GC = XCreateGC(SDL_Display, icon_pixmap, 0, &GCvalues);
   2.254 -	XPutImage(SDL_Display, icon_pixmap, GC, icon_image,
   2.255 -					0, 0, 0, 0, sicon->w, sicon->h);
   2.256 -	XFreeGC(SDL_Display, GC);
   2.257 +				    DefaultDepth(SDL_Display, SDL_Screen));
   2.258 +	gc = XCreateGC(SDL_Display, icon_pixmap, 0, &GCvalues);
   2.259 +	XPutImage(SDL_Display, icon_pixmap, gc, icon_image,
   2.260 +		  0, 0, 0, 0, sicon->w, sicon->h);
   2.261 +	XFreeGC(SDL_Display, gc);
   2.262  	XDestroyImage(icon_image);
   2.263  	free(LSBmask);
   2.264  	sicon->pixels = NULL;
   2.265  
   2.266 -#ifdef USE_ICON_WINDOW
   2.267 -	/* Create an icon window and set the pixmap as its background */
   2.268 -	icon_window = XCreateSimpleWindow(SDL_Display, SDL_Root,
   2.269 -					0, 0, sicon->w, sicon->h, 0,
   2.270 -					CopyFromParent, CopyFromParent);
   2.271 -	XSetWindowBackgroundPixmap(SDL_Display, icon_window, icon_pixmap);
   2.272 -	XClearWindow(SDL_Display, icon_window);
   2.273 -#endif
   2.274 +	/* Some buggy window managers (some versions of Enlightenment, it
   2.275 +	   seems) need an icon window *and* icon pixmap to work properly, while
   2.276 +	   it screws up others. The default is only to use a pixmap. */
   2.277 +	p = getenv("SDL_VIDEO_X11_ICONWIN");
   2.278 +	if(p && *p) {
   2.279 +		icon_window = XCreateSimpleWindow(SDL_Display, SDL_Root,
   2.280 +						  0, 0, sicon->w, sicon->h, 0,
   2.281 +						  CopyFromParent,
   2.282 +						  CopyFromParent);
   2.283 +		XSetWindowBackgroundPixmap(SDL_Display, icon_window,
   2.284 +					   icon_pixmap);
   2.285 +		XClearWindow(SDL_Display, icon_window);
   2.286 +	}
   2.287  
   2.288  	/* Set the window icon to the icon pixmap (and icon window) */
   2.289  	wmhints = XAllocWMHints();
   2.290  	wmhints->flags = (IconPixmapHint | IconMaskHint);
   2.291  	wmhints->icon_pixmap = icon_pixmap;
   2.292  	wmhints->icon_mask = mask_pixmap;
   2.293 -#ifdef USE_ICON_WINDOW
   2.294 -	wmhints->flags |= IconWindowHint;
   2.295 -	wmhints->icon_window = icon_window;
   2.296 -#endif
   2.297 +	if(icon_window != None) {
   2.298 +		wmhints->flags |= IconWindowHint;
   2.299 +		wmhints->icon_window = icon_window;
   2.300 +	}
   2.301  	XSetWMHints(SDL_Display, WMwindow, wmhints);
   2.302  	XFree(wmhints);
   2.303  	XSync(SDL_Display, False);
   2.304  
   2.305    done:
   2.306  	SDL_Unlock_EventThread();
   2.307 -	if ( sicon != NULL ) {
   2.308 -		SDL_FreeSurface(sicon);
   2.309 -	}
   2.310 -	return;
   2.311 +	SDL_FreeSurface(sicon);
   2.312  }
   2.313  
   2.314  void X11_SetCaption(_THIS, const char *title, const char *icon)
   2.315 @@ -241,7 +281,7 @@
   2.316  
   2.317  SDL_GrabMode X11_GrabInputNoLock(_THIS, SDL_GrabMode mode)
   2.318  {
   2.319 -	int numtries, result;
   2.320 +	int result;
   2.321  
   2.322  	if ( this->screen == NULL ) {
   2.323  		return(SDL_GRAB_OFF);