comparison src/video/x11/SDL_x11wm.c @ 236:3f09f52ac2cc

Fixed X11 icon color allocation (thanks Mattias!)
author Sam Lantinga <slouken@libsdl.org>
date Wed, 07 Nov 2001 17:59:07 +0000
parents 1b387dc653d0
children 7c09c9e3b0c7
comparison
equal deleted inserted replaced
235:dde0af58db4b 236:3f09f52ac2cc
38 #include "SDL_events_c.h" 38 #include "SDL_events_c.h"
39 #include "SDL_pixels_c.h" 39 #include "SDL_pixels_c.h"
40 #include "SDL_x11modes_c.h" 40 #include "SDL_x11modes_c.h"
41 #include "SDL_x11wm_c.h" 41 #include "SDL_x11wm_c.h"
42 42
43 /* This is necessary for working properly with Enlightenment, etc. */ 43 static Uint8 reverse_byte(Uint8 x)
44 #define USE_ICON_WINDOW 44 {
45 x = (x & 0xaa) >> 1 | (x & 0x55) << 1;
46 x = (x & 0xcc) >> 2 | (x & 0x33) << 2;
47 x = (x & 0xf0) >> 4 | (x & 0x0f) << 4;
48 return x;
49 }
45 50
46 void X11_SetIcon(_THIS, SDL_Surface *icon, Uint8 *mask) 51 void X11_SetIcon(_THIS, SDL_Surface *icon, Uint8 *mask)
47 { 52 {
48 SDL_Surface *sicon; 53 SDL_Surface *sicon;
49 XWMHints *wmhints; 54 XWMHints *wmhints;
50 XImage *icon_image; 55 XImage *icon_image;
51 Pixmap icon_pixmap; 56 Pixmap icon_pixmap;
52 Pixmap mask_pixmap; 57 Pixmap mask_pixmap;
53 #ifdef USE_ICON_WINDOW 58 Window icon_window = None;
54 Window icon_window; 59 GC gc;
55 #endif
56 GC GC;
57 XGCValues GCvalues; 60 XGCValues GCvalues;
58 int i, b, dbpp; 61 int i, dbpp;
59 SDL_Rect bounds; 62 SDL_Rect bounds;
60 Uint8 *LSBmask, *color_tried; 63 Uint8 *LSBmask;
61 Visual *dvis; 64 Visual *dvis;
62 65 char *p;
63 /* Lock the event thread, in multi-threading environments */ 66 int masksize;
67
64 SDL_Lock_EventThread(); 68 SDL_Lock_EventThread();
65 69
66 /* The icon must use the default visual, depth and colormap of the 70 /* The icon must use the default visual, depth and colormap of the
67 screen, so it might need a conversion */ 71 screen, so it might need a conversion */
72 dvis = DefaultVisual(SDL_Display, SDL_Screen);
68 dbpp = DefaultDepth(SDL_Display, SDL_Screen); 73 dbpp = DefaultDepth(SDL_Display, SDL_Screen);
69 switch(dbpp) { 74 for(i = 0; i < this->hidden->nvisuals; i++) {
70 case 15: 75 if(this->hidden->visuals[i].visual == dvis) {
71 dbpp = 16; break; 76 dbpp = this->hidden->visuals[i].bpp;
72 case 24: 77 break;
73 dbpp = 32; break; 78 }
74 } 79 }
75 dvis = DefaultVisual(SDL_Display, SDL_Screen);
76 80
77 /* The Visual struct is supposed to be opaque but we cheat a little */ 81 /* The Visual struct is supposed to be opaque but we cheat a little */
78 sicon = SDL_CreateRGBSurface(SDL_SWSURFACE, icon->w, icon->h, 82 sicon = SDL_CreateRGBSurface(SDL_SWSURFACE, icon->w, icon->h,
79 dbpp, 83 dbpp,
80 dvis->red_mask, dvis->green_mask, 84 dvis->red_mask, dvis->green_mask,
81 dvis->blue_mask, 0); 85 dvis->blue_mask, 0);
82 86 if ( sicon == NULL )
83 if ( sicon == NULL ) {
84 goto done; 87 goto done;
85 } 88
86 /* If we already have allocated colours from the default colormap, 89 if(dbpp == 8) {
87 copy them */ 90 /* Default visual is 8bit; we need to allocate colours from
88 if(SDL_Visual == dvis && SDL_XColorMap == SDL_DisplayColormap 91 the default colormap */
89 && this->screen->format->palette && sicon->format->palette) { 92 SDL_Color want[256], got[256];
90 memcpy(sicon->format->palette->colors, 93 int nwant;
91 this->screen->format->palette->colors, 94 Colormap dcmap;
92 this->screen->format->palette->ncolors * sizeof(SDL_Color)); 95 int missing;
96 dcmap = DefaultColormap(SDL_Display, SDL_Screen);
97 if(icon->format->palette) {
98 /* The icon has a palette as well - we just have to
99 find those colours */
100 nwant = icon->format->palette->ncolors;
101 memcpy(want, icon->format->palette->colors,
102 nwant * sizeof want[0]);
103 } else {
104 /* try the standard 6x6x6 cube for lack of better
105 ideas */
106 int r, g, b, i;
107 for(r = i = 0; r < 256; r += 0x33)
108 for(g = 0; g < 256; g += 0x33)
109 for(b = 0; b < 256; b += 0x33, i++) {
110 want[i].r = r;
111 want[i].g = g;
112 want[i].b = b;
113 }
114 nwant = 216;
115 }
116 if(SDL_iconcolors) {
117 /* free already allocated colours first */
118 unsigned long freelist[512];
119 int nfree = 0;
120 for(i = 0; i < 256; i++) {
121 while(SDL_iconcolors[i]) {
122 freelist[nfree++] = i;
123 SDL_iconcolors[i]--;
124 }
125 }
126 XFreeColors(GFX_Display, dcmap, freelist, nfree, 0);
127 }
128 if(!SDL_iconcolors)
129 SDL_iconcolors = malloc(256 * sizeof *SDL_iconcolors);
130 memset(SDL_iconcolors, 0, 256 * sizeof *SDL_iconcolors);
131
132 /* try to allocate the colours */
133 memset(got, 0, sizeof got);
134 missing = 0;
135 for(i = 0; i < nwant; i++) {
136 XColor c;
137 c.red = want[i].r << 8;
138 c.green = want[i].g << 8;
139 c.blue = want[i].b << 8;
140 c.flags = DoRed | DoGreen | DoBlue;
141 if(XAllocColor(GFX_Display, dcmap, &c)) {
142 /* got the colour */
143 SDL_iconcolors[c.pixel]++;
144 got[c.pixel] = want[i];
145 } else {
146 missing = 1;
147 }
148 }
149 if(missing) {
150 /* Some colours were apparently missing, so we just
151 allocate all the rest as well */
152 XColor cols[256];
153 for(i = 0; i < 256; i++)
154 cols[i].pixel = i;
155 XQueryColors(GFX_Display, dcmap, cols, 256);
156 for(i = 0; i < 256; i++) {
157 got[i].r = cols[i].red >> 8;
158 got[i].g = cols[i].green >> 8;
159 got[i].b = cols[i].blue >> 8;
160 if(!SDL_iconcolors[i]) {
161 if(XAllocColor(GFX_Display, dcmap,
162 cols + i)) {
163 SDL_iconcolors[i] = 1;
164 } else {
165 /* index not available */
166 got[i].r = 0;
167 got[i].g = 0;
168 got[i].b = 0;
169 }
170 }
171 }
172 }
173
174 SDL_SetColors(sicon, got, 0, 256);
93 } 175 }
94 176
95 bounds.x = 0; 177 bounds.x = 0;
96 bounds.y = 0; 178 bounds.y = 0;
97 bounds.w = icon->w; 179 bounds.w = icon->w;
98 bounds.h = icon->h; 180 bounds.h = icon->h;
99 if ( SDL_LowerBlit(icon, &bounds, sicon, &bounds) < 0 ) 181 if ( SDL_LowerBlit(icon, &bounds, sicon, &bounds) < 0 )
100 goto done; 182 goto done;
101 183
102 /* Lock down the colors used in the colormap */ 184 /* We need the mask as given, except in LSBfirst format instead of
103 color_tried = NULL; 185 MSBfirst. Reverse the bits in each byte. */
104 if ( sicon->format->BitsPerPixel == 8 ) { 186 masksize = ((sicon->w + 7) >> 3) * sicon->h;
105 SDL_Palette *palette; 187 LSBmask = malloc(masksize);
106 Uint8 *p;
107 XColor wanted;
108
109 palette = sicon->format->palette;
110 color_tried = malloc(palette->ncolors);
111 if ( color_tried == NULL ) {
112 goto done;
113 }
114 if ( SDL_iconcolors != NULL ) {
115 free(SDL_iconcolors);
116 }
117 SDL_iconcolors = malloc(palette->ncolors
118 * sizeof(*SDL_iconcolors));
119 if ( SDL_iconcolors == NULL ) {
120 free(color_tried);
121 goto done;
122 }
123 memset(color_tried, 0, palette->ncolors);
124 memset(SDL_iconcolors, 0,
125 palette->ncolors * sizeof(*SDL_iconcolors));
126
127 p = (Uint8 *)sicon->pixels;
128 for ( i = sicon->w*sicon->h; i > 0; --i, ++p ) {
129 if ( ! color_tried[*p] ) {
130 wanted.pixel = *p;
131 wanted.red = (palette->colors[*p].r<<8);
132 wanted.green = (palette->colors[*p].g<<8);
133 wanted.blue = (palette->colors[*p].b<<8);
134 wanted.flags = (DoRed|DoGreen|DoBlue);
135 if (XAllocColor(SDL_Display,
136 SDL_DisplayColormap, &wanted)) {
137 ++SDL_iconcolors[wanted.pixel];
138 }
139 color_tried[*p] = 1;
140 }
141 }
142 }
143 if ( color_tried != NULL ) {
144 free(color_tried);
145 }
146
147 /* Translate mask data to LSB order and set the icon mask */
148 i = (sicon->w/8)*sicon->h;
149 LSBmask = (Uint8 *)malloc(i);
150 if ( LSBmask == NULL ) { 188 if ( LSBmask == NULL ) {
151 goto done; 189 goto done;
152 } 190 }
153 memset(LSBmask, 0, i); 191 memset(LSBmask, 0, masksize);
154 while ( --i >= 0 ) { 192 for(i = 0; i < masksize; i++)
155 for ( b=0; b<8; ++b ) 193 LSBmask[i] = reverse_byte(mask[i]);
156 LSBmask[i] |= (((mask[i]>>b)&0x01)<<(7-b));
157 }
158 mask_pixmap = XCreatePixmapFromBitmapData(SDL_Display, WMwindow, 194 mask_pixmap = XCreatePixmapFromBitmapData(SDL_Display, WMwindow,
159 (char *)LSBmask, sicon->w, sicon->h, 1L, 0L, 1); 195 (char *)LSBmask,
196 sicon->w, sicon->h,
197 1L, 0L, 1);
160 198
161 /* Transfer the image to an X11 pixmap */ 199 /* Transfer the image to an X11 pixmap */
162 icon_image = XCreateImage(SDL_Display, 200 icon_image = XCreateImage(SDL_Display,
163 DefaultVisual(SDL_Display, SDL_Screen), 201 DefaultVisual(SDL_Display, SDL_Screen),
164 DefaultDepth(SDL_Display, SDL_Screen), 202 DefaultDepth(SDL_Display, SDL_Screen),
165 ZPixmap, 0, (char *)sicon->pixels, sicon->w, sicon->h, 203 ZPixmap, 0, sicon->pixels,
166 ((sicon->format)->BytesPerPixel == 3) ? 32 : 204 sicon->w, sicon->h,
167 (sicon->format)->BytesPerPixel*8, 0); 205 32, 0);
168 icon_pixmap = XCreatePixmap(SDL_Display, SDL_Root, sicon->w, sicon->h, 206 icon_pixmap = XCreatePixmap(SDL_Display, SDL_Root, sicon->w, sicon->h,
169 DefaultDepth(SDL_Display, SDL_Screen)); 207 DefaultDepth(SDL_Display, SDL_Screen));
170 GC = XCreateGC(SDL_Display, icon_pixmap, 0, &GCvalues); 208 gc = XCreateGC(SDL_Display, icon_pixmap, 0, &GCvalues);
171 XPutImage(SDL_Display, icon_pixmap, GC, icon_image, 209 XPutImage(SDL_Display, icon_pixmap, gc, icon_image,
172 0, 0, 0, 0, sicon->w, sicon->h); 210 0, 0, 0, 0, sicon->w, sicon->h);
173 XFreeGC(SDL_Display, GC); 211 XFreeGC(SDL_Display, gc);
174 XDestroyImage(icon_image); 212 XDestroyImage(icon_image);
175 free(LSBmask); 213 free(LSBmask);
176 sicon->pixels = NULL; 214 sicon->pixels = NULL;
177 215
178 #ifdef USE_ICON_WINDOW 216 /* Some buggy window managers (some versions of Enlightenment, it
179 /* Create an icon window and set the pixmap as its background */ 217 seems) need an icon window *and* icon pixmap to work properly, while
180 icon_window = XCreateSimpleWindow(SDL_Display, SDL_Root, 218 it screws up others. The default is only to use a pixmap. */
181 0, 0, sicon->w, sicon->h, 0, 219 p = getenv("SDL_VIDEO_X11_ICONWIN");
182 CopyFromParent, CopyFromParent); 220 if(p && *p) {
183 XSetWindowBackgroundPixmap(SDL_Display, icon_window, icon_pixmap); 221 icon_window = XCreateSimpleWindow(SDL_Display, SDL_Root,
184 XClearWindow(SDL_Display, icon_window); 222 0, 0, sicon->w, sicon->h, 0,
185 #endif 223 CopyFromParent,
224 CopyFromParent);
225 XSetWindowBackgroundPixmap(SDL_Display, icon_window,
226 icon_pixmap);
227 XClearWindow(SDL_Display, icon_window);
228 }
186 229
187 /* Set the window icon to the icon pixmap (and icon window) */ 230 /* Set the window icon to the icon pixmap (and icon window) */
188 wmhints = XAllocWMHints(); 231 wmhints = XAllocWMHints();
189 wmhints->flags = (IconPixmapHint | IconMaskHint); 232 wmhints->flags = (IconPixmapHint | IconMaskHint);
190 wmhints->icon_pixmap = icon_pixmap; 233 wmhints->icon_pixmap = icon_pixmap;
191 wmhints->icon_mask = mask_pixmap; 234 wmhints->icon_mask = mask_pixmap;
192 #ifdef USE_ICON_WINDOW 235 if(icon_window != None) {
193 wmhints->flags |= IconWindowHint; 236 wmhints->flags |= IconWindowHint;
194 wmhints->icon_window = icon_window; 237 wmhints->icon_window = icon_window;
195 #endif 238 }
196 XSetWMHints(SDL_Display, WMwindow, wmhints); 239 XSetWMHints(SDL_Display, WMwindow, wmhints);
197 XFree(wmhints); 240 XFree(wmhints);
198 XSync(SDL_Display, False); 241 XSync(SDL_Display, False);
199 242
200 done: 243 done:
201 SDL_Unlock_EventThread(); 244 SDL_Unlock_EventThread();
202 if ( sicon != NULL ) { 245 SDL_FreeSurface(sicon);
203 SDL_FreeSurface(sicon);
204 }
205 return;
206 } 246 }
207 247
208 void X11_SetCaption(_THIS, const char *title, const char *icon) 248 void X11_SetCaption(_THIS, const char *title, const char *icon)
209 { 249 {
210 XTextProperty titleprop, iconprop; 250 XTextProperty titleprop, iconprop;
239 return(result); 279 return(result);
240 } 280 }
241 281
242 SDL_GrabMode X11_GrabInputNoLock(_THIS, SDL_GrabMode mode) 282 SDL_GrabMode X11_GrabInputNoLock(_THIS, SDL_GrabMode mode)
243 { 283 {
244 int numtries, result; 284 int result;
245 285
246 if ( this->screen == NULL ) { 286 if ( this->screen == NULL ) {
247 return(SDL_GRAB_OFF); 287 return(SDL_GRAB_OFF);
248 } 288 }
249 if ( ! SDL_Window ) { 289 if ( ! SDL_Window ) {