mass rename and rebranding from xwt to ibex - fixed to use ixt files
[org.ibex.core.git] / src / org / ibex / plat / X11.cc
1 // Copyright 2002 Adam Megacz, see the COPYING file for licensing [LGPL]
2 // see below for copyright information on the second portion of this file
3
4 #include "POSIX.cc"
5
6 #include <X11/Xlib.h>
7 #include <X11/extensions/XShm.h>
8 #include <X11/keysymdef.h>
9 #include <X11/keysym.h>
10 #include <X11/cursorfont.h>
11 #include <X11/Xutil.h>
12 #include <X11/Xatom.h>
13 #include <X11/Xmu/StdCmap.h>
14
15 #include <java/lang/String.h>
16 #include <org/ibex/Surface.h>
17 #include <org/ibex/Picture.h>
18 #include <org/ibex/Box.h>
19 #include <org/ibex/plat/X11.h>
20 #include <org/ibex/plat/X11$X11Surface.h>
21 #include <org/ibex/plat/X11$X11Picture.h>
22 #include <org/ibex/plat/X11$X11PixelBuffer.h>
23 #include <org/ibex/util/Semaphore.h>
24 #include <org/ibex/Platform.h>
25 #include <java/lang/Long.h>
26 #include <java/util/Hashtable.h>
27 #include <org/ibex/util/Log.h>
28
29 #include <java/lang/System.h>
30 #include <java/io/PrintStream.h>
31
32 // static (per-xserver) data
33 static Visual* visual;
34 static Colormap s_colormap;
35 static XStandardColormap* colormap_info;
36 static XShmSegmentInfo shm_info;
37 static Window selectionWindow;
38 static int shm_supported = 0;
39 static int shm_pixmaps_supported;
40 static int screen_num;
41 static int colorDepth = 0;
42 static Display* display;
43 static int shm_size = 0;
44
45 #define min(a, b) ((a) < (b) ? (a) : (b))
46 #define max(a, b) ((a) < (b) ? (b) : (a))
47
48 // X11PixelBuffer //////////////////////////////////////////////////////////////////////
49
50 // ensures that the shared memory is at least size bytes; if not, allocates 3/2 * size
51 static void ensureShmSize(int size) {
52     if (size > shm_size) {
53         if (shm_size > 0) {
54             XShmDetach(display, &shm_info);
55             shmdt(shm_info.shmaddr);
56             shmctl(shm_info.shmid, IPC_RMID, 0);
57         }
58         shm_size = 3 * size / 2;
59         shm_info.shmid = shmget(IPC_PRIVATE, shm_size, IPC_CREAT | 0777 | IPC_EXCL);
60         shm_info.shmaddr = (char*)shmat(shm_info.shmid, 0, 0);
61         shm_info.readOnly = False;
62         XSync(display, False);
63         shmctl(shm_info.shmid, IPC_RMID, 0);
64         XShmAttach(display, &shm_info);
65         XSync(display, False);
66     }
67 }
68
69 void org::ibex::plat::X11$X11PixelBuffer::fastDrawPicture(org::ibex::Picture* s,
70                                                          jint dx, jint dy, jint cx1, jint cy1, jint cx2, jint cy2) {
71     org::ibex::plat::X11$X11Picture* source = (org::ibex::plat::X11$X11Picture*)s;
72
73     if (source->doublebuf->stipple != NULL) {
74         XSetClipMask(display, (*((GC*)clipped_gc)), *((Pixmap*)source->doublebuf->stipple));
75         XSetClipOrigin(display, (*((GC*)clipped_gc)), dx, dy);
76     } else {
77         XSetClipMask(display, (*((GC*)clipped_gc)), None);
78     }
79
80     XCopyArea(display,
81               *((Pixmap*)source->doublebuf->pm), (*((Pixmap*)pm)), (*((GC*)clipped_gc)),
82               cx1 - dx, cy1 - dy, cx2 - cx1, cy2 - cy1, cx1, cy1);
83 }
84
85 void org::ibex::plat::X11$X11PixelBuffer::slowDrawPicture(org::ibex::Picture* s,
86                                                          jint dx, jint dy, jint cx1, jint cy1, jint cx2, jint cy2,
87                                                          jint rgb, jboolean alphaOnly) {
88
89     org::ibex::plat::X11$X11Picture* source = (org::ibex::plat::X11$X11Picture*)s;
90     XImage* xi; 
91
92     // FASTEST: shared pixmap; twiddle bits in video ram directly
93     if (shared_pixmap) {
94         XSync(display, False);  // ensure that all pending operations have rendered
95         xi = (XImage*)fake_ximage;
96
97     // MEDIUM: write to a shared ximage, then ask the server to do the blit
98     } else if (shm_supported) {
99         xi = XShmCreateImage(display, visual, colorDepth, ZPixmap, NULL, &shm_info, cx2 - cx1, cy2 - cy1);
100         ensureShmSize(xi->bytes_per_line * xi->height);
101         xi->data = shm_info.shmaddr;
102         XShmGetImage(display, (*((Pixmap*)pm)), xi, cx1, cy1, AllPlanes);
103         
104     // SLOWEST: write to an ximage, copy it through the TCP connection, ask the server to do the blit
105     } else {
106         xi = XGetImage(display, (*((Pixmap*)pm)), cx1, cy1, cx2 - cx1, cy2 - cy1, AllPlanes, ZPixmap);
107     }
108     
109     int* sourcedata = (int*)elements(source->data);
110     for(int y=cy1; y < cy2; y++) {
111
112         char* current_pixel = (xi->data + y * xi->bytes_per_line) +
113             (shared_pixmap ? cx1 * (xi->bits_per_pixel / 8) : - 1 * cy1 * xi->bytes_per_line);
114         
115         for(int x=cx1; x < cx2; x++, current_pixel += xi->bits_per_pixel / 8) {
116             int source_x = x - dx;
117             int source_y = y - dy;
118
119             // FEATURE: be smarter here; can we do something better for the alphaonly case?
120             int sourcepixel = sourcedata[source_x + source_y * source->getWidth()];
121             int alpha = (sourcepixel & 0xFF000000) >> 24;
122             if (alphaOnly) sourcepixel = rgb;
123             int source_red = (sourcepixel & 0x00FF0000) >> 16;
124             int source_green = (sourcepixel & 0x0000FF00) >> 8;
125             int source_blue = (sourcepixel & 0x000000FF);
126             int red = 0, blue = 0, green = 0;
127             int targetpixel;
128             if (alpha == 0x00) continue;
129             if (alpha != 0xFF) {
130                 switch (xi->bits_per_pixel) {
131                 case 8: targetpixel = (int)(*current_pixel); break;
132                 case 15:
133                 case 16: targetpixel = (int)(*((uint16_t*)current_pixel)); break;
134
135                 // FIXME assumes endianness...
136                 case 24: targetpixel =
137                            (((int)*current_pixel) << 16) |
138                            (((int)*(current_pixel + 1)) << 8) |
139                            (((int)*(current_pixel + 2))); break;
140                 case 32: targetpixel = *((int*)current_pixel); break;
141                 default: org::ibex::Platform::criticalAbort(JvNewStringLatin1("ERROR: bpp not a multiple of 8!"));
142                 }
143                 targetpixel -= colormap_info->base_pixel;
144
145                 // if you're on some wierd display that isn't either RGB or BGR, that's your problem, not mine
146                 if (colormap_info->red_mult > colormap_info->green_mult && colormap_info->green_mult > colormap_info->blue_mult) {
147                     red = targetpixel / colormap_info->red_mult;
148                     green = (targetpixel - red * colormap_info->red_mult) / colormap_info->green_mult;
149                     blue = (targetpixel-red * colormap_info->red_mult-green * colormap_info->green_mult)/colormap_info->blue_mult;
150                 } else {
151                     blue = targetpixel / colormap_info->blue_mult;
152                     green = (targetpixel - blue * colormap_info->blue_mult) / colormap_info->green_mult;
153                     red = (targetpixel-blue * colormap_info->blue_mult-green * colormap_info->green_mult)/colormap_info->red_mult;
154                 }
155             }
156             red = ((source_red * (colormap_info->red_max) * alpha) + (red * 0xFF * (0xFF - alpha))) / (0xFF * 0xFF);
157             green = ((source_green * (colormap_info->green_max) * alpha)+(green * 0xFF * (0xFF - alpha))) / (0xFF * 0xFF);
158             blue = ((source_blue * (colormap_info->blue_max) * alpha) + (blue * 0xFF * (0xFF - alpha))) / (0xFF * 0xFF);
159             uint32_t destpixel =
160               (red * colormap_info->red_mult) +
161               (green * colormap_info->green_mult) +
162               (blue * colormap_info->blue_mult) +
163               colormap_info->base_pixel;
164             switch (xi->bits_per_pixel) {
165             case 8: *current_pixel = (char)(destpixel & 0xFF); break;
166             case 16: *((uint16_t*)current_pixel) = (uint16_t)destpixel; break;
167             case 24: {
168                 int offset = (int)current_pixel & 0x3;
169                 uint64_t dest = ((uint64_t)destpixel) << (8 * offset);
170                 uint64_t mask = ((uint64_t)0xffffff) << (8 * offset);
171                 uint64_t* base = (uint64_t*)(current_pixel - offset);
172                 *base = (*base & ~mask) | dest;
173                 break;
174             }
175             case 32: *((uint32_t*)current_pixel) = destpixel; break;
176             default: org::ibex::Platform::criticalAbort(JvNewStringLatin1("ERROR: bpp not a multiple of 8!"));
177             }
178         }
179     }
180     
181     if (shared_pixmap) {
182         // do nothing, we wrote directly to video memory
183         
184     } else if (shm_supported) {
185         XShmPutImage(display, (*((Pixmap*)pm)), (*((GC*)gc)), xi, 0, 0, cx1, cy1, cx2 - cx1, cy2 - cy1, False);
186         XDestroyImage(xi);
187         
188     } else {
189         XPutImage(display, (*((Pixmap*)pm)), (*((GC*)gc)), xi, 0, 0, cx1, cy1, cx2 - cx1, cy2 - cy1);
190         
191     }
192 }
193
194 void org::ibex::plat::X11$X11PixelBuffer::finalize() {
195     if (shared_pixmap) {
196         XShmSegmentInfo *sinfo = (XShmSegmentInfo*)shm_segment;
197         XShmDetach(display, sinfo);
198         shmdt(sinfo->shmaddr);
199         shmctl(sinfo->shmid, IPC_RMID, 0);
200         XDestroyImage((XImage*)fake_ximage);
201         free(sinfo);
202     }
203     if (stipple) {
204         XFreePixmap(display, *((Pixmap*)stipple));
205         free(stipple);
206     }
207     XFreePixmap(display, *((Pixmap*)pm));
208     XFreeGC(display, *((GC*)gc));
209     XFreeGC(display, *((GC*)clipped_gc));
210 }
211
212 void org::ibex::plat::X11$X11PixelBuffer::natInit() {
213     
214     if (width == 0 || height == 0) return;
215     shared_pixmap &= shm_supported & shm_pixmaps_supported; // refuse to use shared pixmaps if we don't have shm
216     pm = (gnu::gcj::RawData*)malloc(sizeof(Pixmap));
217
218     if (!shared_pixmap)
219         (*((Pixmap*)pm)) = XCreatePixmap(display, RootWindow(display, screen_num), width, height, colorDepth);
220     else {
221         XShmSegmentInfo *sinfo = (XShmSegmentInfo*)malloc(sizeof(XShmSegmentInfo));
222         shm_segment = (gnu::gcj::RawData*)sinfo;
223         ((XImage*)fake_ximage) = XShmCreateImage(display, visual, colorDepth, ZPixmap, NULL, sinfo, width, height);
224         sinfo->shmid = shmget(IPC_PRIVATE, ((XImage*)fake_ximage)->bytes_per_line * height, IPC_CREAT | 0777 | IPC_EXCL);
225         ((XImage*)fake_ximage)->data = sinfo->shmaddr = (char*)shmat(sinfo->shmid, 0, 0);
226         sinfo->readOnly = False;
227         XShmAttach(display, sinfo);
228         XSync(display, False);
229         shmctl(sinfo->shmid, IPC_RMID, 0);
230         (*((Pixmap*)pm)) = XShmCreatePixmap(display, RootWindow(display, screen_num), sinfo->shmaddr, sinfo, width, height, colorDepth);
231         XSync(display, False);
232     }
233
234     gc = (gnu::gcj::RawData*)malloc(sizeof(GC));
235     clipped_gc = (gnu::gcj::RawData*)malloc(sizeof(GC));
236     (*((GC*)gc)) = XCreateGC(display, (*((Pixmap*)pm)), 0, 0);
237     (*((GC*)clipped_gc)) = XCreateGC(display, (*((Pixmap*)pm)), 0, 0);
238     
239     XGCValues vm;
240     vm.graphics_exposures = 0;
241     XChangeGC(display, (*((GC*)gc)), GCGraphicsExposures, &vm);
242     XChangeGC(display, (*((GC*)clipped_gc)), GCGraphicsExposures, &vm);
243 }    
244
245 void org::ibex::plat::X11$X11PixelBuffer::createStipple(org::ibex::plat::X11$X11Picture* xpi) {
246
247     stipple = (gnu::gcj::RawData*)malloc(sizeof(Pixmap));
248     (*((Pixmap*)stipple)) = XCreatePixmap(display, RootWindow(display, screen_num), width, height, 1);
249
250     XImage xi;
251     xi.data = (char*)malloc((width + 1) * height);
252     xi.width = width;
253     xi.height = height;
254     xi.xoffset = 0;
255     xi.format = ZPixmap;
256     xi.bitmap_pad = 8;
257     xi.bitmap_unit = 8;
258     xi.byte_order = LSBFirst;
259     xi.depth = 1;
260     xi.bytes_per_line = (width / 8) + 1;
261     xi.bits_per_pixel = 1;
262     
263     jint* d = (jint*)elements(xpi->data);
264     memset(xi.data, 0xFF, (width + 1) * height);
265     for(int x=0; x<width; x++)
266         for (int y=0; y<height; y++)
267             xi.data[y * xi.bytes_per_line + (x/8)] &= ~(((d[x + y * width] & 0xFF000000) != 0 ? 0 : 1) << (x % 8));
268
269     GC stipple_gc = XCreateGC(display, (*((Pixmap*)stipple)), 0, 0);
270
271     XGCValues vm;
272     vm.graphics_exposures = 0;
273     XChangeGC(display, stipple_gc, GCGraphicsExposures, &vm);
274
275     XPutImage(display, (*((Pixmap*)stipple)), stipple_gc, &xi, 0, 0, 0, 0, width, height);
276 }
277
278 void org::ibex::plat::X11$X11Surface::blit(org::ibex::PixelBuffer* db, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
279     org::ibex::plat::X11$X11PixelBuffer *xdb = (org::ibex::plat::X11$X11PixelBuffer*)db;
280     XCopyArea(display, *((Pixmap*)xdb->pm), *((Window*)window), *((GC*)gc), sx, sy, dx2 - dx, dy2 - dy, dx, dy);
281     XFlush(display);
282 }
283
284 void org::ibex::plat::X11$X11PixelBuffer::fillRect (jint x, jint y, jint x2, jint y2, jint argb) {
285     
286     jint w = x2 - x;
287     jint h = y2 - y;
288
289     if (x < clipx) { w -= (clipx - x); x = clipx; }
290     if (y < clipy) { h -= (clipy - y); y = clipy; }
291     if (x + w > clipx + clipw) w = (clipx + clipw - x);
292     if (y + h > clipy + cliph) h = (cliph + clipy - y);
293
294     XSetForeground(display, (*((GC*)gc)),
295                    ((((argb & 0x00FF0000) >> 16) * colormap_info->red_max) / 0xFF) * colormap_info->red_mult + 
296                    ((((argb & 0x0000FF00) >> 8) * colormap_info->green_max) / 0xFF) * colormap_info->green_mult + 
297                    ((((argb & 0x000000FF)) * colormap_info->blue_max) / 0xFF) * colormap_info->blue_mult +
298                    colormap_info->base_pixel
299                    );
300     
301     XFillRectangle(display, (*((Pixmap*)pm)), (*((GC*)gc)), x, y, w, h);
302 }
303
304
305 // X11Surface //////////////////////////////////////////////////////////////////////
306
307 void org::ibex::plat::X11$X11Surface::setIcon(org::ibex::Picture* pic) {
308     org::ibex::plat::X11$X11Picture* p = ((org::ibex::plat::X11$X11Picture*)pic);
309     org::ibex::plat::X11$X11PixelBuffer* old_dbuf = p->doublebuf;
310     p->buildPixelBuffer(1);
311     XWMHints xwmh;
312     memset(&xwmh, 0, sizeof(XWMHints));
313     xwmh.flags |= IconPixmapHint | IconMaskHint;
314     xwmh.icon_pixmap = *((Pixmap*)p->doublebuf->pm);
315     xwmh.icon_mask = *((Pixmap*)p->doublebuf->stipple);
316     XSetWMHints(display, (*((Window*)window)), &xwmh);
317     p->doublebuf = old_dbuf;
318 }
319
320 void org::ibex::plat::X11$X11Surface::setTitleBarText(java::lang::String* s) {
321     int len = min(JvGetStringUTFLength(s), 1024);
322     char buf[len + 1];
323     JvGetStringUTFRegion(s, 0, len, buf);
324     buf[len] = '\0';
325     
326     XTextProperty tp;
327     tp.value = (unsigned char*)buf;
328     tp.nitems = len;
329     tp.encoding = XA_STRING;
330     tp.format = 8;
331     XSetTextProperty(display, (*((Window*)window)), &tp, XA_WM_NAME);
332     XSetTextProperty(display, (*((Window*)window)), &tp, XA_WM_ICON_NAME);
333 }
334
335 void org::ibex::plat::X11$X11Surface::setLimits(jint minw, jint minh, jint maxw, jint maxh) {
336     XSizeHints hints;
337     hints.min_width = minw;
338     hints.min_height = minh;
339     hints.max_width = maxw;
340     hints.max_height = maxh;
341     hints.flags = PMinSize | PMaxSize;
342     XSetWMNormalHints(display, (*((Window*)window)), &hints);
343 }
344
345 void org::ibex::plat::X11$X11Surface::_setSize (jint width, jint height) {
346     if (width <= 0 || height <= 0) return;
347     XResizeWindow(display, (*((Window*)window)), width, height);
348     XFlush(display);
349 }
350
351 void org::ibex::plat::X11$X11Surface::setLocation () { XMoveWindow(display, (*((Window*)window)), root->x, root->y); }
352 void org::ibex::plat::X11$X11Surface::toFront() { XRaiseWindow(display, (*((Window*)window))); }
353 void org::ibex::plat::X11$X11Surface::toBack() { XLowerWindow(display, (*((Window*)window))); }
354
355 void org::ibex::plat::X11$X11Surface::_dispose() {
356     // without this we get phantom messages after the window is gone
357     org::ibex::plat::X11::windowToSurfaceMap->remove(new java::lang::Long(*((Window*)window)));
358     XDestroyWindow(display, (*((Window*)window)));
359 }
360
361 void org::ibex::plat::X11$X11Surface::setInvisible(jboolean i) {
362     if (i) XUnmapWindow(display, (*((Window*)window)));
363     else XMapRaised(display, (*((Window*)window)));
364     XFlush(display);
365 }
366
367 void org::ibex::plat::X11$X11Surface::_setMinimized(jboolean b) {
368     if (b) XIconifyWindow(display, (*((Window*)window)), screen_num);
369     else XMapRaised(display, (*((Window*)window)));
370     XFlush(display);
371 }
372
373 void org::ibex::plat::X11$X11Surface::natInit() {
374     XSetWindowAttributes xswa;
375     window = (gnu::gcj::RawData*)malloc(sizeof(Window));
376     xswa.bit_gravity = NorthWestGravity;
377     xswa.colormap = s_colormap;
378     xswa.event_mask = ExposureMask | ButtonPressMask | StructureNotifyMask |
379         KeyPressMask | KeyReleaseMask | ButtonPressMask |
380         ButtonReleaseMask | EnterWindowMask | LeaveWindowMask |
381         PointerMotionMask | ButtonMotionMask | ConfigureNotify | FocusChangeMask;
382     *((Window*)window) = XCreateWindow(display, RootWindow(display, screen_num), 10, 10, 10, 10, 0,
383                                        colorDepth, InputOutput, CopyFromParent,
384                                        CWColormap | CWBitGravity | CWEventMask, &xswa);
385     
386     if (!framed) {
387         // I don't know why this works....
388         int dat[5] = { 0x2, 0xbffff804, 0x0, 0x817f560, 0x8110694 };
389         XChangeProperty(display, (*((Window*)window)),
390                         XInternAtom(display, "_MOTIF_WM_HINTS", False),
391                         XInternAtom(display, "_MOTIF_WM_HINTS", False),
392                         32, 
393                         PropModeReplace,
394                         (unsigned char*)dat,
395                         5);
396     }
397     
398     XTextProperty tp;
399     tp.value = (unsigned char*)"Ibex";
400     tp.nitems = 3;
401     tp.encoding = XA_STRING;
402     tp.format = 8;
403     XSetTextProperty(display, (*((Window*)window)), &tp, XA_WM_CLASS);
404     
405     Atom proto = XInternAtom(display, "WM_DELETE_WINDOW", False);
406     XSetWMProtocols(display, (*((Window*)window)), &proto, 1);
407     
408     XSelectInput(display, (*((Window*)window)), StructureNotifyMask);
409     org::ibex::plat::X11::windowToSurfaceMap->put(new java::lang::Long(*((Window*)window)), this);
410
411     XEvent e;
412     XMapRaised(display, (*((Window*)window)));
413     XFlush(display);
414
415     waitForCreation->block();
416     XSelectInput(display, (*((Window*)window)), xswa.event_mask);
417     XFlush(display);
418
419     gc = (gnu::gcj::RawData*)malloc(sizeof(GC));
420     *((GC*)gc) = XCreateGC(display, (*((Window*)window)), 0, 0);
421     
422     XGCValues vm;
423     vm.graphics_exposures = 0;
424     XChangeGC(display, *((GC*)gc), GCGraphicsExposures, &vm);
425 }
426
427
428 void org::ibex::plat::X11$X11Surface::dispatchEvent(gnu::gcj::RawData* ev) {
429
430     XEvent* e = (XEvent*)ev;
431     if (e->type == Expose) {
432         XExposeEvent *expose = (XExposeEvent*)(e);
433         Dirty(expose->x, expose->y, expose->width, expose->height);
434         
435     } else if (e->type == MapNotify) { Minimized(0); waitForCreation->release();
436     } else if (e->type == UnmapNotify) { Minimized(1);
437     } else if (e->type == FocusIn) { Focused(1);
438     } else if (e->type == FocusOut) { Focused(0);
439     } else if (e->type == ClientMessage) {
440         if (((XClientMessageEvent*)(e))->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", False)) Close();
441     
442     } else if (e->type == KeyPress || e->type == KeyRelease) {
443         XKeyEvent *xbe = (XKeyEvent*)(e);
444         
445         // drop faked KeyRelease events generated by the X server's autorepeat
446         if (e->type == KeyRelease) {
447             char depressed[32];
448             XQueryKeymap(display, depressed);
449             if ((depressed[(xbe->keycode & 0xff) / 8] & (0x1 << (xbe->keycode % 8))) >> (xbe->keycode % 8)) return;
450         }
451         
452         char ss[20];
453         char* s = ss;
454         
455         unsigned int savestate = xbe->state;
456         xbe->state = xbe->state & ShiftMask;      // ignore everything except shiftmask
457         XLookupString(xbe, s, 20, NULL, NULL);
458         xbe->state = savestate;
459         
460         if (s != NULL && s[0] != '\0' && s[1] == '\0' && s[0] >= 0x20 && s[0] <= 0x7E) {
461             int i = s[0];
462             
463         } else {
464             KeySym ks = XKeycodeToKeysym(display, xbe->keycode, 0);
465             switch (ks) {
466             case XK_BackSpace: s = "back_space"; break;
467             case XK_Tab: s = "tab"; break;
468             case XK_Linefeed: s = "enter"; break;
469             case XK_Return: s = "enter"; break;
470             case XK_Scroll_Lock: s = "scroll_lock"; break;
471             case XK_Escape: s = "escape"; break;
472             case XK_Insert: s = "insert"; break;
473             case XK_Delete: s = "delete"; break;
474             case XK_Home: s = "home"; break;
475             case XK_Left: s = "left"; break;
476             case XK_Up: s = "up"; break;
477             case XK_Right: s = "right"; break;
478             case XK_Down: s = "down"; break;
479             case XK_Page_Up: s = "page_up"; break;
480             case XK_Page_Down: s = "page_down"; break;
481             case XK_End: s = "end"; break;
482             case XK_Num_Lock: s = "num_lock"; break;
483             case XK_KP_Tab: s = "tab"; break;
484             case XK_KP_Enter: s = "enter"; break;
485             case XK_KP_F1: s = "f1"; break;
486             case XK_KP_F2: s = "f2"; break;
487             case XK_KP_F3: s = "f3"; break;
488             case XK_KP_F4: s = "f4"; break;
489             case XK_KP_Home: s = "home"; break;
490             case XK_KP_Left: s = "left"; break;
491             case XK_KP_Up: s = "up"; break;
492             case XK_KP_Right: s = "right"; break;
493             case XK_KP_Down: s = "down"; break;
494             case XK_KP_Page_Up: s = "page_up"; break;
495             case XK_KP_Page_Down: s = "page_down"; break;
496             case XK_KP_End: s = "end"; break;
497             case XK_KP_Insert: s = "insert"; break;
498             case XK_KP_Delete: s = "delete"; break;
499             case XK_F1: s = "f1"; break;
500             case XK_F2: s = "f2"; break;
501             case XK_F3: s = "f3"; break;
502             case XK_F4: s = "f4"; break;
503             case XK_F5: s = "f5"; break;
504             case XK_F6: s = "f6"; break;
505             case XK_F7: s = "f7"; break;
506             case XK_F8: s = "f8"; break;
507             case XK_F9: s = "f9"; break;
508             case XK_F10: s = "f10"; break;
509             case XK_F11: s = "f11"; break;
510             case XK_F12: s = "f12"; break;
511             case XK_Shift_L: s = "shift"; break;
512             case XK_Shift_R: s = "shift"; break;
513             case XK_Control_L: s = "control"; break;
514             case XK_Control_R: s = "control"; break;
515             case XK_Meta_L: s = "alt"; break;
516             case XK_Meta_R: s = "alt"; break;
517             case XK_Alt_L: s = "alt"; break;
518             case XK_Alt_R: s = "alt"; break;
519             default: return;
520             }
521         }
522         
523         jstring s2 = JvNewStringLatin1(s);
524         if (e->type == KeyPress) KeyPressed((xbe->state & LockMask) ? s2->toUpperCase() : s2);
525         if (e->type == KeyRelease) KeyReleased(s2);
526         
527     } else if (e->type == ButtonPress) {
528         XButtonEvent* xbe = (XButtonEvent*)(e);
529         if (xbe->button == 2) xbe->button = 3;
530         else if (xbe->button == 3) xbe->button = 2;
531         Press(xbe->button);
532         
533     } else if (e->type == ButtonRelease) {
534         XButtonEvent* xbe = (XButtonEvent*)(e);
535         if (xbe->button == 2) xbe->button = 3;
536         else if (xbe->button == 3) xbe->button = 2;
537         Release(xbe->button);
538         
539     } else if (e->type == MotionNotify) {
540         XMotionEvent* xme = (XMotionEvent*)(e);
541         Move(xme->x, xme->y);
542         
543     } else if (e->type == EnterNotify || e->type == LeaveNotify) {
544         XCrossingEvent* xce = (XCrossingEvent*)(e);
545         Move(xce->x, xce->y);
546         
547     } else if (e->type == ConfigureNotify) {
548         Window child;
549         int x_out, y_out;
550         XConfigureEvent* xce = (XConfigureEvent*)(e);
551         XTranslateCoordinates(display, (*((Window*)window)), RootWindow(display, screen_num), 0, 0, &x_out, &y_out, &child);
552         if (xce->width != root->width || xce->height != root->height) SizeChange(xce->width, xce->height);
553         if (x_out != root->x || y_out != root->y) PosChange(x_out, y_out);
554         
555     }
556 }
557
558 static jstring crosshair, east, hand, move, north, northeast, northwest,
559     south, southeast, southwest, text, west, wait_string;
560 static Cursor crosshair_cursor, east_cursor, hand_cursor, move_cursor, north_cursor,
561     northeast_cursor, northwest_cursor, south_cursor, southeast_cursor,
562     southwest_cursor, text_cursor, west_cursor, wait_cursor, default_cursor;
563
564 void org::ibex::plat::X11$X11Surface::syncCursor() {
565     
566     Cursor curs;
567     if (cursor->equals(crosshair)) curs = crosshair_cursor;
568     else if (cursor->equals(east)) curs = east_cursor;
569     else if (cursor->equals(hand)) curs = hand_cursor;
570     else if (cursor->equals(move)) curs = move_cursor;
571     else if (cursor->equals(north)) curs = north_cursor;
572     else if (cursor->equals(northeast)) curs = northeast_cursor;
573     else if (cursor->equals(northwest)) curs = northwest_cursor;
574     else if (cursor->equals(south)) curs = south_cursor;
575     else if (cursor->equals(southeast)) curs = southeast_cursor;
576     else if (cursor->equals(southwest)) curs = southwest_cursor;
577     else if (cursor->equals(text)) curs = text_cursor;
578     else if (cursor->equals(west)) curs = west_cursor;
579     else if (cursor->equals(wait_string)) curs = wait_cursor;
580     else curs = default_cursor;
581     
582     XDefineCursor(display, (*((Window*)window)), curs);
583 }
584
585
586
587 // X11 ///////////////////////////////////////////////////////////////////
588
589 jint org::ibex::plat::X11::_getScreenWidth() { return WidthOfScreen(DefaultScreenOfDisplay(display)); }
590 jint org::ibex::plat::X11::_getScreenHeight() { return HeightOfScreen(DefaultScreenOfDisplay(display)); }
591
592 static void dispatchSelectionEvent(XEvent* e) {
593     if (e->type == SelectionNotify) {
594         XSelectionEvent* xsn = (XSelectionEvent*)(e);
595         if (xsn->property == None) org::ibex::plat::X11::clipboard = JvNewStringLatin1("", 0);
596         else {
597             Atom returntype;
598             int returnformat;
599             unsigned long numitems;
600             unsigned char* ret;
601             unsigned long bytes_after;
602             XGetWindowProperty(display, xsn->requestor, xsn->property, 0, 4096,
603                                True, AnyPropertyType, &returntype, &returnformat,
604                                &numitems, &bytes_after, &ret);
605             org::ibex::plat::X11::clipboard =
606                 (returntype == None ? JvNewStringLatin1("", 0) : JvNewStringLatin1((char*)ret, strlen((char*)ret)));
607         }
608         org::ibex::plat::X11::waiting_for_selection_event->release();
609         
610     } else if (e->type == SelectionRequest) {
611         XSelectionRequestEvent* xsr = (XSelectionRequestEvent*)(e);
612         XSelectionEvent xsn;
613         xsn.type = SelectionNotify;
614         xsn.serial = xsr->serial;
615         xsn.send_event = True;
616         xsn.display = display;
617         xsn.requestor = xsr->requestor;
618         xsn.selection = xsr->selection;
619         xsn.target = xsr->target;
620         xsn.property = xsr->property;
621         xsn.time = xsr->time;
622         
623         int len = min(1024, JvGetStringUTFLength(org::ibex::plat::X11::clipboard));
624         char buf[len + 1];
625         JvGetStringUTFRegion(org::ibex::plat::X11::clipboard, 0, len, buf);
626         buf[len] = '\0';
627         
628         XChangeProperty(display, xsr->requestor, xsr->property, xsr->target, 8, PropModeReplace, (unsigned char*)buf, len + 1);
629         XSendEvent(display, xsr->requestor, True, 0, (XEvent*)(&xsn));
630     }        
631 }
632
633 void org::ibex::plat::X11::eventThread() {
634     XEvent e;
635     while(true) {
636         XNextEvent(display, &e);
637         if (e.type == SelectionNotify || e.type == SelectionRequest) {
638             dispatchSelectionEvent(&e);
639         } else {
640             org::ibex::plat::X11$X11Surface* surface =
641                 (org::ibex::plat::X11$X11Surface*)windowToSurfaceMap->get(new java::lang::Long(((XAnyEvent*)&e)->window));
642             if (surface != NULL) surface->dispatchEvent((gnu::gcj::RawData*)&e);
643         }
644     }
645 }
646
647 jstring org::ibex::plat::X11::_getClipBoard() {
648     XConvertSelection(display, XA_PRIMARY, XA_STRING, XInternAtom(display, "VT_SELECTION", False), selectionWindow, CurrentTime);
649     XFlush(display);
650     org::ibex::plat::X11::waiting_for_selection_event->block();
651     return clipboard;
652 }
653
654 void org::ibex::plat::X11::_setClipBoard(jstring s) {
655     clipboard = s;
656     int len = JvGetStringUTFLength(clipboard);
657     char buf[len + 1];
658     JvGetStringUTFRegion(clipboard, 0, len, buf);
659     buf[len] = '\0';
660     XSetSelectionOwner(display, XInternAtom(display, "PRIMARY", 0), selectionWindow, CurrentTime);
661 }
662
663 typedef int (X11ErrorHandler)(Display*, XErrorEvent*);
664 int errorHandler(Display* d, XErrorEvent* e) {
665     // this error handler is only installed during the initial
666     // test to see if shm is present
667     shm_supported = 0;
668 }
669
670 void org::ibex::plat::X11::natInit() {
671
672     if (!XInitThreads())
673         org::ibex::Platform::criticalAbort(JvNewStringLatin1("Your X11 libraries do not support multithreaded programs"));
674
675     char* DISPLAY = getenv("DISPLAY");
676     if (DISPLAY == NULL || strlen(DISPLAY) == 0) DISPLAY = ":0.0";
677     display = XOpenDisplay(DISPLAY);
678
679     if (display == 0)
680         org::ibex::Platform::criticalAbort(JvNewStringLatin1("Unable to connect to X11 display server"));
681
682     screen_num = XDefaultScreen(display);
683     colorDepth = (jint)(DefaultDepth(((Display*)display), 0));
684     shm_info.shmaddr = NULL;
685
686     // FIXME: SHM doesn't work on Darwin
687     //shm_supported = (XShmQueryExtension(display) == True);
688     if (shm_supported) {
689         X11ErrorHandler* oldHandler = XSetErrorHandler(errorHandler);
690         XShmSegmentInfo sinfo;
691         sinfo.shmid = shmget(IPC_PRIVATE, 1, IPC_CREAT | 0777 | IPC_EXCL);
692         sinfo.readOnly = False;
693         // if the server is remote, this will trigger the error handler
694         XShmAttach(display, &sinfo);
695         XSync(display, False);
696         XSetErrorHandler(oldHandler);
697     }
698
699     if (shm_supported)
700         shm_pixmaps_supported = (XShmPixmapFormat(display) == ZPixmap);
701     
702     crosshair = JvNewStringLatin1("crosshair");
703     east = JvNewStringLatin1("east");
704     hand = JvNewStringLatin1("hand");
705     move = JvNewStringLatin1("move");
706     north = JvNewStringLatin1("north");
707     northeast = JvNewStringLatin1("northeast");
708     northwest = JvNewStringLatin1("northwest");
709     south = JvNewStringLatin1("south");
710     southeast = JvNewStringLatin1("southeast");
711     southwest = JvNewStringLatin1("southwest");
712     text = JvNewStringLatin1("text");
713     west = JvNewStringLatin1("west");
714     wait_string = JvNewStringLatin1("wait");
715     crosshair_cursor = XCreateFontCursor(display, XC_tcross);
716     east_cursor = XCreateFontCursor(display, XC_right_side);
717     hand_cursor = XCreateFontCursor(display, XC_hand2);
718     move_cursor = XCreateFontCursor(display, XC_fleur);
719     north_cursor = XCreateFontCursor(display, XC_top_side);
720     northeast_cursor = XCreateFontCursor(display, XC_top_right_corner);
721     northwest_cursor = XCreateFontCursor(display, XC_left_side);
722     south_cursor = XCreateFontCursor(display, XC_bottom_side);
723     southeast_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
724     southwest_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
725     text_cursor = XCreateFontCursor(display, XC_xterm);
726     west_cursor = XCreateFontCursor(display, XC_right_side);
727     wait_cursor = XCreateFontCursor(display, XC_watch);
728     default_cursor = XCreateFontCursor(display, XC_left_ptr);
729
730     selectionWindow = XCreateWindow(display, RootWindow(display, screen_num), 0, 0, 1, 1, 0, colorDepth, InputOutput, CopyFromParent, 0, NULL);
731     visual = DefaultVisual(display, screen_num);
732     char buf[255];
733     sprintf(buf, "X11 DISPLAY: %s", XDisplayString(display));
734     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
735     sprintf(buf, "X11 SHM:     %s", shm_supported ? "enabled" : "disabled");
736     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
737     sprintf(buf, "X11 Visual:  %x %x %x bits: %i visualid: %i depth: %i",
738             visual->red_mask, visual->green_mask, visual->blue_mask, visual->bits_per_rgb, visual->visualid, colorDepth);
739     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
740
741     // FIXME: don't know why (True, False) is the best solution...
742     if(XmuLookupStandardColormap(display, screen_num, visual->visualid, colorDepth, XA_RGB_BEST_MAP, True, False) == 0)
743         org::ibex::Platform::criticalAbort(JvNewStringLatin1("ERROR: XmuLookupStandardColormap failed"));
744     
745     XStandardColormap* best_map_info = NULL;
746     int count;
747     if (XGetRGBColormaps(display, RootWindow(display, screen_num), &best_map_info, &count, XA_RGB_BEST_MAP) == 0)
748         org::ibex::Platform::criticalAbort(JvNewStringLatin1("ERROR: couldn't allocate a standard colormap"));
749     if (!best_map_info->colormap)
750         org::ibex::Platform::criticalAbort(JvNewStringLatin1("ERROR: XmuLookupStandardColomap succeded, but no colormap was found on the root window"));
751     if (best_map_info->red_max == 0)
752         org::ibex::Platform::criticalAbort(JvNewStringLatin1("ERROR: standard colormap exists, but was improperly allocated"));
753     s_colormap = best_map_info->colormap;
754     colormap_info = best_map_info;
755
756     sprintf(buf, "            red_max / red_mult: %x %x", colormap_info->red_max, colormap_info->red_mult);
757     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
758     sprintf(buf, "            green_max / green_mult: %x %x", colormap_info->green_max, colormap_info->green_mult);
759     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
760     sprintf(buf, "            blue_max / blue_mult: %x %x", colormap_info->blue_max, colormap_info->blue_mult);
761     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
762     sprintf(buf, "            base_pixel: %x", colormap_info->base_pixel);
763     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
764 }
765
766
767
768 //////////////////////////////////////////////////////////////////////////////
769 //////////////////////////////////////////////////////////////////////////////
770 //////////////////////////////////////////////////////////////////////////////
771 //////////////////////////////////////////////////////////////////////////////
772 //                                                                          //
773 // Everything below this point was taken, cut-and-paste, from the           //
774 // source for libXmu. It implements the official 'standard colormap         //
775 // creation algorithm.  I made some small changes to                        //
776 // XmuDeleteStandardColormap                                                //
777 //                                                                          //
778 //////////////////////////////////////////////////////////////////////////////
779 //////////////////////////////////////////////////////////////////////////////
780 //////////////////////////////////////////////////////////////////////////////
781 //////////////////////////////////////////////////////////////////////////////
782
783 /* $Xorg: LookupCmap.c,v 1.4 2001/02/09 02:03:53 xorgcvs Exp $ */
784
785 /* 
786  
787 Copyright 1989, 1998  The Open Group
788
789 Permission to use, copy, modify, distribute, and sell this software and its
790 documentation for any purpose is hereby granted without fee, provided that
791 the above copyright notice appear in all copies and that both that
792 copyright notice and this permission notice appear in supporting
793 documentation.
794
795 The above copyright notice and this permission notice shall be included in
796 all copies or substantial portions of the Software.
797
798 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
799 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
800 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
801 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
802 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
803 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
804
805 Except as contained in this notice, the name of The Open Group shall not be
806 used in advertising or otherwise to promote the sale, use or other dealings
807 in this Software without prior written authorization from The Open Group.
808
809 */
810 /* $XFree86: xc/lib/Xmu/LookupCmap.c,v 1.8 2001/12/14 19:55:47 dawes Exp $ */
811
812 /*
813  * Author:  Donna Converse, MIT X Consortium
814  */
815
816 #include <stdio.h>
817 #include <X11/Xlib.h>
818 #include <X11/Xatom.h>
819 #include <X11/Xutil.h>
820 #include <X11/Xmu/StdCmap.h>
821 #include <stdlib.h>
822
823 /*
824  * Prototypes
825  */
826 static Status lookup(Display*, int, VisualID, Atom, XStandardColormap*, Bool);
827
828 /*
829  * To create a standard colormap if one does not currently exist, or
830  * replace the currently existing standard colormap, use 
831  * XmuLookupStandardColormap().
832  *
833  * Given a screen, a visual, and a property, XmuLookupStandardColormap()
834  * will determine the best allocation for the property under the specified
835  * visual, and determine the whether to create a new colormap or to use
836  * the default colormap of the screen.  It will call XmuStandardColormap()
837  * to create the standard colormap.
838  *
839  * If replace is true, any previous definition of the property will be 
840  * replaced.  If retain is true, the property and the colormap will be
841  * made permanent for the duration of the server session.  However,
842  * pre-existing property definitions which are not replaced cannot be made
843  * permanent by a call to XmuLookupStandardColormap(); a request to retain 
844  * resources pertains to newly created resources.
845  *
846  * Returns 0 on failure, non-zero on success.  A request to create a 
847  * standard colormap upon a visual which cannot support such a map is
848  * considered a failure.  An example of this would be requesting any
849  * standard colormap property on a monochrome visual, or, requesting an
850  * RGB_BEST_MAP on a display whose colormap size is 16.
851  */
852
853 Status
854 XmuLookupStandardColormap(Display *dpy, int screen, VisualID visualid,
855                           unsigned int depth, Atom property,
856                           Bool replace, Bool retain)
857      /*
858       * dpy             - specifies X server connection
859       * screen          - specifies screen of display
860       * visualid        - specifies the visual type
861       * depth           - specifies  the visual type
862       * property        - a standard colormap property
863       * replace         - specifies whether to replace
864       * retain          - specifies whether to retain
865       */
866 {
867     Display             *odpy;          /* original display connection */
868     XStandardColormap   *colormap;      
869     XVisualInfo         vinfo_template, *vinfo; /* visual */
870     long                vinfo_mask;
871     unsigned long       r_max, g_max, b_max;    /* allocation */
872     int                 count;  
873     Colormap            cmap;                   /* colormap ID */
874     Status              status = 0;
875
876
877     /* Match the requested visual */
878
879     vinfo_template.visualid = visualid; 
880     vinfo_template.screen = screen;
881     vinfo_template.depth = depth;
882     vinfo_mask = VisualIDMask | VisualScreenMask | VisualDepthMask;
883     if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &count)) ==
884         NULL)
885         return 0;
886
887     /* Monochrome visuals have no standard maps */
888
889     if (vinfo->colormap_size <= 2) {
890         XFree((char *) vinfo);
891         return 0;       
892     }
893
894     /* If the requested property already exists on this screen, and, 
895      * if the replace flag has not been set to true, return success.
896      * lookup() will remove a pre-existing map if replace is true.
897      */
898
899     if (lookup(dpy, screen, visualid, property, (XStandardColormap *) NULL,
900                replace) && !replace) {
901         XFree((char *) vinfo);
902         return 1;
903     }
904
905     /* Determine the best allocation for this property under the requested
906      * visualid and depth, and determine whether or not to use the default
907      * colormap of the screen.
908      */
909
910     if (!XmuGetColormapAllocation(vinfo, property, &r_max, &g_max, &b_max)) {
911         XFree((char *) vinfo);
912         return 0;
913     }
914
915     cmap = (property == XA_RGB_DEFAULT_MAP &&
916             visualid == XVisualIDFromVisual(DefaultVisual(dpy, screen)))
917         ? DefaultColormap(dpy, screen) : None;
918
919     /* If retaining resources, open a new connection to the same server */
920
921     if (retain) {
922         odpy = dpy;
923         if ((dpy = XOpenDisplay(XDisplayString(odpy))) == NULL) {
924             XFree((char *) vinfo);
925             return 0;
926         }
927     }
928
929     /* Create the standard colormap */
930
931     colormap = XmuStandardColormap(dpy, screen, visualid, depth, property,
932                                    cmap, r_max, g_max, b_max);
933
934     /* Set the standard colormap property */
935
936     if (colormap) {
937         XGrabServer(dpy);
938
939         if (lookup(dpy, screen, visualid, property, colormap, replace) &&
940             !replace) {
941             /* Someone has defined the property since we last looked.
942              * Since we will not replace it, release our own resources.
943              * If this is the default map, our allocations will be freed 
944              * when this connection closes.
945              */
946             if (colormap->killid == ReleaseByFreeingColormap)
947             XFreeColormap(dpy, colormap->colormap);
948         } else if (retain) {
949                 XSetCloseDownMode(dpy, RetainPermanent);
950         }
951         XUngrabServer(dpy);
952         XFree((char *) colormap);
953         status = 1;
954     }
955
956     if (retain)
957         XCloseDisplay(dpy);
958     XFree((char *) vinfo);
959     return status;
960 }
961
962 /***************************************************************************/
963
964 /* Lookup a standard colormap property.  If the property is RGB_DEFAULT_MAP,
965  * the visualid is used to determine whether the indicated standard colormap
966  * exists.  If the map exists and replace is true, delete the resources used
967  * by the map and remove the property.  Return true if the map exists,
968  * or did exist and was deleted; return false if the map was not found.
969  *
970  * Note that this is not the way that a Status return is normally used.
971  *
972  * If new is not NULL, new points to an XStandardColormap structure which
973  * describes a standard colormap of the specified property.  It will be made
974  * a standard colormap of the screen if none already exists, or if replace 
975  * is true.
976  */
977
978 static Status
979 lookup(Display *dpy, int screen, VisualID visualid, Atom property,
980        XStandardColormap *cnew, Bool replace)
981      /*
982       * dpy             - specifies display connection
983       * screen          - specifies screen number
984       * visualid        - specifies visualid for std map
985       * property        - specifies colormap property name
986       * cnew            - specifies a standard colormap
987       * replace         - specifies whether to replace
988       */
989 {
990     register int        i;
991     int                 count;
992     XStandardColormap   *stdcmaps, *s;
993     Window              win = RootWindow(dpy, screen);
994
995     /* The property does not already exist */
996
997     if (! XGetRGBColormaps(dpy, win, &stdcmaps, &count, property)) {
998         if (cnew)
999             XSetRGBColormaps(dpy, win, cnew, 1, property);
1000         return 0;
1001     }
1002
1003     /* The property exists and is not describing the RGB_DEFAULT_MAP */
1004
1005     if (property != XA_RGB_DEFAULT_MAP) {
1006         if (replace) {
1007             XmuDeleteStandardColormap(dpy, screen, property);
1008             if (cnew)
1009                 XSetRGBColormaps(dpy, win, cnew, 1, property);
1010         }
1011         XFree((char *)stdcmaps);
1012         return 1;
1013     }
1014
1015     /* The property exists and is RGB_DEFAULT_MAP */
1016     
1017     for (i=0, s=stdcmaps; (i < count) && (s->visualid != visualid); i++, s++)
1018         ;
1019
1020     /* No RGB_DEFAULT_MAP property matches the given visualid */
1021
1022     if (i == count) {
1023         if (cnew) {
1024             XStandardColormap   *m, *maps;
1025
1026             s = (XStandardColormap *) malloc((unsigned) ((count+1) * sizeof
1027                                               (XStandardColormap)));
1028
1029             for (i = 0, m = s, maps = stdcmaps; i < count; i++, m++, maps++) {
1030                 m->colormap   = maps->colormap;
1031                 m->red_max    = maps->red_max;
1032                 m->red_mult   = maps->red_mult;
1033                 m->green_max  = maps->green_max;
1034                 m->green_mult = maps->green_mult;
1035                 m->blue_max   = maps->blue_max;
1036                 m->blue_mult  = maps->blue_mult;
1037                 m->base_pixel = maps->base_pixel;
1038                 m->visualid   = maps->visualid;
1039                 m->killid     = maps->killid;
1040             }
1041             m->colormap   = cnew->colormap;
1042             m->red_max    = cnew->red_max;
1043             m->red_mult   = cnew->red_mult;
1044             m->green_max  = cnew->green_max;
1045             m->green_mult = cnew->green_mult;
1046             m->blue_max   = cnew->blue_max;
1047             m->blue_mult  = cnew->blue_mult;
1048             m->base_pixel = cnew->base_pixel;
1049             m->visualid   = cnew->visualid;
1050             m->killid     = cnew->killid;
1051
1052             XSetRGBColormaps(dpy, win, s, ++count, property);
1053             free((char *) s);
1054         }
1055         XFree((char *) stdcmaps);
1056         return 0;
1057     }
1058
1059     /* Found an RGB_DEFAULT_MAP property with a matching visualid */
1060
1061     if (replace) {
1062         /* Free old resources first - we may need them, particularly in 
1063          * the default colormap of the screen.  However, because of this,
1064          * it is possible that we will destroy the old resource and fail 
1065          * to create a new one if XmuStandardColormap() fails.
1066          */
1067
1068         if (count == 1) {
1069             XmuDeleteStandardColormap(dpy, screen, property);
1070             if (cnew)
1071                 XSetRGBColormaps(dpy, win, cnew, 1, property);
1072         }
1073         else {
1074             XStandardColormap   *map;
1075
1076             /* s still points to the matching standard colormap */
1077
1078             if (s->killid == ReleaseByFreeingColormap) {
1079                 if ((s->colormap != None) &&
1080                     (s->colormap != DefaultColormap(dpy, screen)))
1081                     XFreeColormap(dpy, s->colormap);
1082             }
1083             else if (s->killid != None)
1084                 XKillClient(dpy, s->killid);
1085
1086             map = (cnew) ? cnew : stdcmaps + --count;
1087
1088             s->colormap   = map->colormap;
1089             s->red_max    = map->red_max;
1090             s->red_mult   = map->red_mult;
1091             s->green_max  = map->green_max;
1092             s->green_mult = map->green_mult;
1093             s->blue_max   = map->blue_max;
1094             s->blue_mult  = map->blue_mult;
1095             s->visualid   = map->visualid;
1096             s->killid     = map->killid;
1097
1098             XSetRGBColormaps(dpy, win, stdcmaps, count, property);
1099         }
1100     }
1101     XFree((char *) stdcmaps);
1102     return 1;
1103 }
1104
1105 /* $Xorg: CmapAlloc.c,v 1.4 2001/02/09 02:03:51 xorgcvs Exp $ */
1106
1107 /* 
1108
1109 Copyright 1989, 1994, 1998  The Open Group
1110
1111 Permission to use, copy, modify, distribute, and sell this software and its
1112 documentation for any purpose is hereby granted without fee, provided that
1113 the above copyright notice appear in all copies and that both that
1114 copyright notice and this permission notice appear in supporting
1115 documentation.
1116
1117 The above copyright notice and this permission notice shall be included in
1118 all copies or substantial portions of the Software.
1119
1120 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1121 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1122 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1123 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1124 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1125 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1126
1127 Except as contained in this notice, the name of The Open Group shall not be
1128 used in advertising or otherwise to promote the sale, use or other dealings
1129 in this Software without prior written authorization from The Open Group.
1130
1131 */
1132 /* $XFree86: xc/lib/Xmu/CmapAlloc.c,v 1.7 2001/12/14 19:55:35 dawes Exp $ */
1133
1134 /*
1135  * Author:  Donna Converse, MIT X Consortium
1136  */
1137
1138 #include <X11/Xlib.h>
1139 #include <X11/Xatom.h>
1140 #include <X11/Xutil.h>
1141 #include <X11/Xmu/StdCmap.h>
1142 #include <stdio.h>
1143
1144 #define lowbit(x) ((x) & (~(x) + 1))
1145
1146 /*
1147  * Prototypes
1148  */
1149 static void best_allocation(XVisualInfo*, unsigned long*, unsigned long*,
1150                             unsigned long*);
1151 static int default_allocation(XVisualInfo*, unsigned long*,
1152                               unsigned long*, unsigned long*);
1153 static void gray_allocation(int, unsigned long*, unsigned long*,
1154                             unsigned long*);
1155 static int icbrt(int);
1156 static int icbrt_with_bits(int, int);
1157 static int icbrt_with_guess(int, int);
1158
1159 /* To determine the best allocation of reds, greens, and blues in a 
1160  * standard colormap, use XmuGetColormapAllocation.
1161  *      vinfo           specifies visual information for a chosen visual
1162  *      property        specifies one of the standard colormap property names
1163  *      red_max         returns maximum red value 
1164  *      green_max       returns maximum green value
1165  *      blue_max        returns maximum blue value
1166  *
1167  * XmuGetColormapAllocation returns 0 on failure, non-zero on success.
1168  * It is assumed that the visual is appropriate for the colormap property.
1169  */
1170
1171 Status
1172 XmuGetColormapAllocation(XVisualInfo *vinfo, Atom property,
1173                          unsigned long *red_max,
1174                          unsigned long *green_max,
1175                          unsigned long *blue_max)
1176 {
1177     Status      status = 1;
1178
1179     if (vinfo->colormap_size <= 2)
1180         return 0;
1181
1182     switch (property)
1183     {
1184       case XA_RGB_DEFAULT_MAP:
1185         status = default_allocation(vinfo, red_max, green_max, blue_max);
1186         break;
1187       case XA_RGB_BEST_MAP:
1188         best_allocation(vinfo, red_max, green_max, blue_max);
1189         break;
1190       case XA_RGB_GRAY_MAP:
1191         gray_allocation(vinfo->colormap_size, red_max, green_max, blue_max);
1192         break;
1193       case XA_RGB_RED_MAP:
1194         *red_max = vinfo->colormap_size - 1;
1195         *green_max = *blue_max = 0;
1196         break;
1197       case XA_RGB_GREEN_MAP:
1198         *green_max = vinfo->colormap_size - 1;
1199         *red_max = *blue_max = 0;
1200         break;
1201       case XA_RGB_BLUE_MAP:
1202         *blue_max = vinfo->colormap_size - 1;
1203         *red_max = *green_max = 0;
1204         break;
1205       default:
1206         status = 0;
1207     }
1208     return status;
1209 }
1210
1211 /****************************************************************************/
1212 /* Determine the appropriate color allocations of a gray scale.
1213  *
1214  * Keith Packard, MIT X Consortium
1215  */
1216
1217 static void
1218 gray_allocation(int n, unsigned long *red_max, unsigned long *green_max,
1219                 unsigned long *blue_max)
1220 {
1221     *red_max = (n * 30) / 100;
1222     *green_max = (n * 59) / 100; 
1223     *blue_max = (n * 11) / 100; 
1224     *green_max += ((n - 1) - (*red_max + *green_max + *blue_max));
1225 }
1226
1227 /****************************************************************************/
1228 /* Determine an appropriate color allocation for the RGB_DEFAULT_MAP.
1229  * If a map has less than a minimum number of definable entries, we do not
1230  * produce an allocation for an RGB_DEFAULT_MAP.  
1231  *
1232  * For 16 planes, the default colormap will have 27 each RGB; for 12 planes,
1233  * 12 each.  For 8 planes, let n = the number of colormap entries, which may
1234  * be 256 or 254.  Then, maximum red value = floor(cube_root(n - 125)) - 1.
1235  * Maximum green and maximum blue values are identical to maximum red.
1236  * This leaves at least 125 cells which clients can allocate.
1237  *
1238  * Return 0 if an allocation has been determined, non-zero otherwise.
1239  */
1240
1241 static int
1242 default_allocation(XVisualInfo *vinfo, unsigned long *red,
1243                    unsigned long *green, unsigned long *blue)
1244 {
1245     int                 ngrays;         /* number of gray cells */
1246
1247     switch (vinfo->c_class)
1248       {
1249       case PseudoColor:
1250         
1251         if (vinfo->colormap_size > 65000)
1252           /* intended for displays with 16 planes */
1253           *red = *green = *blue = (unsigned long) 27;
1254         else if (vinfo->colormap_size > 4000)
1255           /* intended for displays with 12 planes */
1256             *red = *green = *blue = (unsigned long) 12;
1257       else if (vinfo->colormap_size < 250)
1258             return 0;
1259       else
1260             /* intended for displays with 8 planes */
1261             *red = *green = *blue = (unsigned long)
1262           (icbrt(vinfo->colormap_size - 125) - 1);
1263       break;
1264       
1265     case DirectColor:
1266       
1267         if (vinfo->colormap_size < 10)
1268             return 0;
1269         *red = *green = *blue = vinfo->colormap_size / 2 - 1;
1270         break;
1271
1272       case TrueColor:
1273
1274         *red = vinfo->red_mask / lowbit(vinfo->red_mask);
1275         *green = vinfo->green_mask / lowbit(vinfo->green_mask);
1276         *blue = vinfo->blue_mask / lowbit(vinfo->blue_mask);
1277         break;
1278
1279       case GrayScale:
1280
1281         if (vinfo->colormap_size > 65000)
1282             ngrays = 4096;
1283         else if (vinfo->colormap_size > 4000)
1284             ngrays = 512;
1285         else if (vinfo->colormap_size < 250)
1286             return 0;
1287         else
1288             ngrays = 12;
1289         gray_allocation(ngrays, red, green, blue);
1290         break;
1291         
1292       default:
1293         return 0;
1294     }
1295     return 1;
1296 }
1297
1298 /****************************************************************************/
1299 /* Determine an appropriate color allocation for the RGB_BEST_MAP.
1300  *
1301  * For a DirectColor or TrueColor visual, the allocation is determined
1302  * by the red_mask, green_mask, and blue_mask members of the visual info.
1303  *
1304  * Otherwise, if the colormap size is an integral power of 2, determine
1305  * the allocation according to the number of bits given to each color,
1306  * with green getting more than red, and red more than blue, if there
1307  * are to be inequities in the distribution.  If the colormap size is
1308  * not an integral power of 2, let n = the number of colormap entries.
1309  * Then maximum red value = floor(cube_root(n)) - 1;
1310  *      maximum blue value = floor(cube_root(n)) - 1;
1311  *      maximum green value = n / ((# red values) * (# blue values)) - 1;
1312  * Which, on a GPX, allows for 252 entries in the best map, out of 254
1313  * defineable colormap entries.
1314  */
1315  
1316 static void
1317 best_allocation(XVisualInfo *vinfo, unsigned long *red, unsigned long *green,
1318                 unsigned long *blue)
1319 {
1320
1321     if (vinfo->c_class == DirectColor ||        vinfo->c_class == TrueColor)
1322     {
1323         *red = vinfo->red_mask;
1324         while ((*red & 01) == 0)
1325             *red >>= 1;
1326         *green = vinfo->green_mask;
1327         while ((*green & 01) == 0)
1328             *green >>=1;
1329         *blue = vinfo->blue_mask;
1330         while ((*blue & 01) == 0)
1331             *blue >>= 1;
1332     }
1333     else
1334     {
1335         register int bits, n;
1336         
1337         /* Determine n such that n is the least integral power of 2 which is
1338          * greater than or equal to the number of entries in the colormap.
1339          */
1340         n = 1;
1341         bits = 0;
1342         while (vinfo->colormap_size > n)
1343         {
1344             n = n << 1;
1345             bits++;
1346         }
1347         
1348         /* If the number of entries in the colormap is a power of 2, determine
1349          * the allocation by "dealing" the bits, first to green, then red, then
1350          * blue.  If not, find the maximum integral red, green, and blue values
1351          * which, when multiplied together, do not exceed the number of 
1352
1353          * colormap entries.
1354          */
1355         if (n == vinfo->colormap_size)
1356         {
1357             register int r, g, b;
1358             b = bits / 3;
1359             g = b + ((bits % 3) ? 1 : 0);
1360             r = b + (((bits % 3) == 2) ? 1 : 0);
1361             *red = 1 << r;
1362             *green = 1 << g;
1363             *blue = 1 << b;
1364         }
1365         else
1366         {
1367             *red = icbrt_with_bits(vinfo->colormap_size, bits);
1368             *blue = *red;       
1369             *green = (vinfo->colormap_size / ((*red) * (*blue)));
1370         }
1371         (*red)--;
1372         (*green)--;
1373         (*blue)--;
1374     }
1375     return;
1376 }
1377
1378 /*
1379  * integer cube roots by Newton's method
1380  *
1381  * Stephen Gildea, MIT X Consortium, July 1991
1382  */
1383
1384 static int
1385 icbrt(int a)
1386 {
1387     register int bits = 0;
1388     register unsigned n = a;
1389
1390     while (n)
1391     {
1392         bits++;
1393         n >>= 1;
1394     }
1395     return icbrt_with_bits(a, bits);
1396 }
1397
1398
1399 static int
1400 icbrt_with_bits(int a, int bits)
1401      /* bits - log 2 of a */
1402 {
1403     return icbrt_with_guess(a, a>>2*bits/3);
1404 }
1405
1406 #ifdef _X_ROOT_STATS
1407 int icbrt_loopcount;
1408 #endif
1409
1410 /* Newton's Method:  x_n+1 = x_n - ( f(x_n) / f'(x_n) ) */
1411
1412 /* for cube roots, x^3 - a = 0,  x_new = x - 1/3 (x - a/x^2) */
1413
1414 /*
1415  * Quick and dirty cube roots.  Nothing fancy here, just Newton's method.
1416  * Only works for positive integers (since that's all we need).
1417  * We actually return floor(cbrt(a)) because that's what we need here, too.
1418  */
1419
1420 static int
1421 icbrt_with_guess(int a, int guess)
1422 {
1423     register int delta;
1424
1425 #ifdef _X_ROOT_STATS
1426     icbrt_loopcount = 0;
1427 #endif
1428     if (a <= 0)
1429         return 0;
1430     if (guess < 1)
1431         guess = 1;
1432
1433     do {
1434 #ifdef _X_ROOT_STATS
1435         icbrt_loopcount++;
1436 #endif
1437         delta = (guess - a/(guess*guess))/3;
1438 #ifdef DEBUG
1439         printf("pass %d: guess=%d, delta=%d\n", icbrt_loopcount, guess, delta);
1440 #endif
1441         guess -= delta;
1442     } while (delta != 0);
1443
1444     if (guess*guess*guess > a)
1445         guess--;
1446
1447     return guess;
1448 }
1449
1450
1451 /* $Xorg: StdCmap.c,v 1.4 2001/02/09 02:03:53 xorgcvs Exp $ */
1452
1453 /* 
1454
1455 Copyright 1989, 1998  The Open Group
1456
1457 Permission to use, copy, modify, distribute, and sell this software and its
1458 documentation for any purpose is hereby granted without fee, provided that
1459 the above copyright notice appear in all copies and that both that
1460 copyright notice and this permission notice appear in supporting
1461 documentation.
1462
1463 The above copyright notice and this permission notice shall be included in
1464 all copies or substantial portions of the Software.
1465
1466 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1467 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1468 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1469 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1470 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1471 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1472
1473 Except as contained in this notice, the name of The Open Group shall not be
1474 used in advertising or otherwise to promote the sale, use or other dealings
1475 in this Software without prior written authorization from The Open Group.
1476
1477 */
1478 /* $XFree86: xc/lib/Xmu/StdCmap.c,v 1.6 2001/12/14 19:55:48 dawes Exp $ */
1479
1480 /*
1481  * Author:  Donna Converse, MIT X Consortium
1482  */
1483
1484 #include <stdio.h>
1485 #include <X11/Xlib.h>
1486 #include <X11/Xatom.h>
1487 #include <X11/Xutil.h>
1488 #include <X11/Xmu/StdCmap.h>
1489
1490 #define lowbit(x) ((x) & (~(x) + 1))
1491
1492 /*
1493  * Prototypes
1494  */
1495 /* argument restrictions */
1496 static Status valid_args(XVisualInfo*, unsigned long, unsigned long,
1497                          unsigned long, Atom);
1498
1499 /*
1500  * To create any one standard colormap, use XmuStandardColormap().
1501  *
1502  * Create a standard colormap for the given screen, visualid, and visual
1503  * depth, with the given red, green, and blue maximum values, with the
1504  * given standard property name.  Return a pointer to an XStandardColormap
1505  * structure which describes the newly created colormap, upon success.
1506  * Upon failure, return NULL.
1507  * 
1508  * XmuStandardColormap() calls XmuCreateColormap() to create the map.
1509  *
1510  * Resources created by this function are not made permanent; that is the
1511  * caller's responsibility.
1512  */
1513
1514 XStandardColormap *
1515 XmuStandardColormap(Display *dpy, int screen, VisualID visualid,
1516                     unsigned int depth, Atom property, Colormap cmap,
1517                     unsigned long red_max, unsigned long green_max,
1518                     unsigned long blue_max)
1519      /*
1520       * dpy                             - specifies X server connection
1521       * screen                          - specifies display screen
1522       * visualid                        - identifies the visual type
1523       * depth                           - identifies the visual type
1524       * property                        - a standard colormap property
1525       * cmap                            - specifies colormap ID or None
1526       * red_max, green_max, blue_max    - allocations
1527       */
1528 {
1529     XStandardColormap   *stdcmap;
1530     Status              status;
1531     XVisualInfo         vinfo_template, *vinfo;
1532     long                vinfo_mask;
1533     int                 n;
1534
1535     /* Match the required visual information to an actual visual */
1536     vinfo_template.visualid = visualid; 
1537     vinfo_template.screen = screen;
1538     vinfo_template.depth = depth;
1539     vinfo_mask = VisualIDMask | VisualScreenMask | VisualDepthMask;
1540     if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &n)) == NULL)
1541         return 0;
1542
1543     /* Check the validity of the combination of visual characteristics,
1544      * allocation, and colormap property.  Create an XStandardColormap
1545      * structure.
1546      */
1547
1548     if (! valid_args(vinfo, red_max, green_max, blue_max, property)
1549         || ((stdcmap = XAllocStandardColormap()) == NULL)) {
1550         XFree((char *) vinfo);
1551         return 0;
1552     }
1553
1554     /* Fill in the XStandardColormap structure */
1555
1556     if (cmap == DefaultColormap(dpy, screen)) {
1557         /* Allocating out of the default map, cannot use XFreeColormap() */
1558         Window win = XCreateWindow(dpy, RootWindow(dpy, screen), 1, 1, 1, 1,
1559                                    0, 0, InputOnly, vinfo->visual,
1560                                    (unsigned long) 0,
1561                                    (XSetWindowAttributes *)NULL);
1562         stdcmap->killid  = (XID) XCreatePixmap(dpy, win, 1, 1, depth);
1563         XDestroyWindow(dpy, win);
1564         stdcmap->colormap = cmap;
1565     } else {
1566         stdcmap->killid = ReleaseByFreeingColormap;
1567         stdcmap->colormap = XCreateColormap(dpy, RootWindow(dpy, screen),
1568                                             vinfo->visual, AllocNone);
1569     }
1570     stdcmap->red_max = red_max;
1571     stdcmap->green_max = green_max;
1572     stdcmap->blue_max = blue_max;
1573     if (property == XA_RGB_GRAY_MAP) 
1574         stdcmap->red_mult = stdcmap->green_mult = stdcmap->blue_mult = 1;
1575     else if (vinfo->c_class == TrueColor || vinfo->c_class == DirectColor) {
1576         stdcmap->red_mult = lowbit(vinfo->red_mask);
1577         stdcmap->green_mult = lowbit(vinfo->green_mask);
1578         stdcmap->blue_mult = lowbit(vinfo->blue_mask);
1579     } else {
1580         stdcmap->red_mult = (red_max > 0)
1581             ? (green_max + 1) * (blue_max + 1) : 0;
1582         stdcmap->green_mult = (green_max > 0) ? blue_max + 1 : 0;
1583         stdcmap->blue_mult = (blue_max > 0) ? 1 : 0;
1584     }
1585     stdcmap->base_pixel = 0;                    /* base pixel may change */
1586     stdcmap->visualid = vinfo->visualid;
1587
1588     /* Make the colormap */
1589
1590     status = XmuCreateColormap(dpy, stdcmap);
1591
1592     /* Clean up */
1593
1594     XFree((char *) vinfo);
1595     if (!status) {
1596
1597         /* Free the colormap or the pixmap, if we created one */
1598         if (stdcmap->killid == ReleaseByFreeingColormap)
1599             XFreeColormap(dpy, stdcmap->colormap);
1600         else if (stdcmap->killid != None)
1601             XFreePixmap(dpy, stdcmap->killid);
1602         
1603         XFree((char *) stdcmap);
1604         return (XStandardColormap *) NULL;
1605     }
1606     return stdcmap;
1607 }
1608
1609 /****************************************************************************/
1610 static Status
1611 valid_args(XVisualInfo *vinfo, unsigned long red_max, unsigned long green_max,
1612            unsigned long blue_max, Atom property)
1613      /*
1614       * vinfo                           - specifies visual
1615       * red_max, green_max, blue_max    - specifies alloc
1616       * property                        - specifies property name
1617       */
1618 {
1619     unsigned long       ncolors;        /* number of colors requested */
1620
1621     /* Determine that the number of colors requested is <= map size */
1622
1623     if ((vinfo->c_class == DirectColor) || (vinfo->c_class == TrueColor)) {
1624         unsigned long mask;
1625
1626         mask = vinfo->red_mask;
1627         while (!(mask & 1))
1628             mask >>= 1;
1629         if (red_max > mask)
1630             return 0;
1631         mask = vinfo->green_mask;
1632         while (!(mask & 1))
1633             mask >>= 1;
1634         if (green_max > mask)
1635             return 0;
1636         mask = vinfo->blue_mask;
1637         while (!(mask & 1))
1638             mask >>= 1;
1639         if (blue_max > mask)
1640             return 0;
1641     } else if (property == XA_RGB_GRAY_MAP) {
1642         ncolors = red_max + green_max + blue_max + 1;
1643         if (ncolors > vinfo->colormap_size)
1644             return 0;
1645     } else {
1646         ncolors = (red_max + 1) * (green_max + 1) * (blue_max + 1);
1647         if (ncolors > vinfo->colormap_size)
1648             return 0;
1649     }
1650     
1651     /* Determine that the allocation and visual make sense for the property */
1652
1653     switch (property)
1654     {
1655       case XA_RGB_DEFAULT_MAP:
1656         if (red_max == 0 || green_max == 0 || blue_max == 0)
1657             return 0;
1658         break;
1659       case XA_RGB_RED_MAP:
1660         if (red_max == 0)
1661             return 0;
1662         break;
1663       case XA_RGB_GREEN_MAP:
1664         if (green_max == 0)
1665             return 0;
1666         break;
1667       case XA_RGB_BLUE_MAP:     
1668         if (blue_max == 0)
1669             return 0;
1670         break;
1671       case XA_RGB_BEST_MAP:
1672         if (red_max == 0 || green_max == 0 || blue_max == 0)
1673             return 0;
1674         break;
1675       case XA_RGB_GRAY_MAP:
1676         if (red_max == 0 || blue_max == 0 || green_max == 0)
1677             return 0;
1678         break;
1679       default:
1680         return 0;
1681     }
1682     return 1;
1683 }
1684
1685
1686 /* $Xorg: CrCmap.c,v 1.4 2001/02/09 02:03:51 xorgcvs Exp $ */
1687
1688 /* 
1689
1690 Copyright 1989, 1998  The Open Group
1691
1692 Permission to use, copy, modify, distribute, and sell this software and its
1693 documentation for any purpose is hereby granted without fee, provided that
1694 the above copyright notice appear in all copies and that both that
1695 copyright notice and this permission notice appear in supporting
1696 documentation.
1697
1698 The above copyright notice and this permission notice shall be included in
1699 all copies or substantial portions of the Software.
1700
1701 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1702 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1703 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1704 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1705 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1706 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1707
1708 Except as contained in this notice, the name of The Open Group shall not be
1709 used in advertising or otherwise to promote the sale, use or other dealings
1710 in this Software without prior written authorization from The Open Group.
1711
1712 */
1713 /* $XFree86: xc/lib/Xmu/CrCmap.c,v 3.7 2001/12/14 19:55:36 dawes Exp $ */
1714
1715 /*
1716  * Author:  Donna Converse, MIT X Consortium
1717  */
1718
1719 /*
1720  * CreateCmap.c - given a standard colormap description, make the map.
1721  */
1722
1723 #include <stdio.h>
1724 #include <stdlib.h>
1725 #include <X11/Xlib.h>
1726 #include <X11/Xutil.h>
1727 #include <X11/Xmu/StdCmap.h>
1728
1729 /*
1730  * Prototypes
1731  */
1732 /* allocate entire map Read Only */
1733 static int ROmap(Display*, Colormap, unsigned long[], int, int);
1734
1735 /* allocate a cell, prefer Read Only */
1736 static Status ROorRWcell(Display*, Colormap, unsigned long[], int,
1737                          XColor*, unsigned long);
1738
1739 /* allocate a cell Read Write */
1740 static Status RWcell(Display*, Colormap, XColor*, XColor*, unsigned long*);
1741
1742 /* for quicksort */
1743 static int compare(_Xconst void*, _Xconst void*);
1744
1745 /* find contiguous sequence of cells */
1746 static Status contiguous(unsigned long[], int, int, unsigned long, int*, int*);
1747
1748 /* frees resources before quitting */
1749 static void free_cells(Display*, Colormap, unsigned long[], int, int);
1750
1751 /* create a map in a RO visual type */
1752 static Status readonly_map(Display*, XVisualInfo*, XStandardColormap*);
1753
1754 /* create a map in a RW visual type */
1755 static Status readwrite_map(Display*, XVisualInfo*, XStandardColormap*);
1756
1757 #define lowbit(x) ((x) & (~(x) + 1))
1758 #define TRUEMATCH(mult,max,mask) \
1759     (colormap->max * colormap->mult <= vinfo->mask && \
1760      lowbit(vinfo->mask) == colormap->mult)
1761
1762 /*
1763  * To create any one colormap which is described by an XStandardColormap
1764  * structure, use XmuCreateColormap().
1765  *
1766  * Return 0 on failure, non-zero on success.
1767  * Resources created by this function are not made permanent.
1768  * No argument error checking is provided.  Use at your own risk.
1769  *
1770  * All colormaps are created with read only allocations, with the exception
1771  * of read only allocations of colors in the default map or otherwise
1772  * which fail to return the expected pixel value, and these are individually 
1773  * defined as read/write allocations.  This is done so that all the cells
1774  * defined in the default map are contiguous, for use in image processing.
1775  * This typically happens with White and Black in the default map.
1776  *
1777  * Colormaps of static visuals are considered to be successfully created if
1778  * the map of the static visual matches the definition given in the
1779  * standard colormap structure.
1780  */
1781    
1782 Status
1783 XmuCreateColormap(Display *dpy, XStandardColormap *colormap)
1784      /* dpy      - specifies the connection under which the map is created
1785       * colormap - specifies the map to be created, and returns, particularly
1786       *            if the map is created as a subset of the default colormap
1787       *            of the screen, the base_pixel of the map.
1788                                          */
1789 {
1790     XVisualInfo         vinfo_template; /* template visual information */
1791     XVisualInfo         *vinfo;         /* matching visual information */
1792     XVisualInfo         *vpointer;      /* for freeing the entire list */
1793     long                vinfo_mask;     /* specifies the visual mask value */
1794     int                 n;              /* number of matching visuals */
1795     int                 status;         
1796
1797     vinfo_template.visualid = colormap->visualid;
1798     vinfo_mask = VisualIDMask;
1799     if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &n)) == NULL)
1800         return 0;
1801
1802     /* A visual id may be valid on multiple screens.  Also, there may 
1803      * be multiple visuals with identical visual ids at different depths.  
1804      * If the colormap is the Default Colormap, use the Default Visual.
1805      * Otherwise, arbitrarily, use the deepest visual.
1806      */
1807     vpointer = vinfo;
1808     if (n > 1)
1809     {
1810         register int    i;
1811         register int    screen_number;
1812         Bool            def_cmap;
1813
1814         def_cmap = False;
1815         for (screen_number = ScreenCount(dpy); --screen_number >= 0; )
1816             if (colormap->colormap == DefaultColormap(dpy, screen_number)) {
1817                 def_cmap = True;
1818                 break;
1819             }
1820
1821         if (def_cmap) {
1822             for (i=0; i < n; i++, vinfo++) {
1823                 if (vinfo->visual == DefaultVisual(dpy, screen_number))
1824                         break;
1825             }
1826         } else {
1827             int                 maxdepth = 0;
1828             XVisualInfo         *v = NULL;
1829
1830             for (i=0; i < n; i++, vinfo++)
1831                 if (vinfo->depth > maxdepth) {
1832                     maxdepth = vinfo->depth;
1833                     v = vinfo;
1834                 }
1835             vinfo = v;
1836         }
1837     }
1838
1839     if (vinfo->c_class == PseudoColor || vinfo->c_class == DirectColor ||
1840         vinfo->c_class == GrayScale)
1841         status = readwrite_map(dpy, vinfo, colormap);
1842     else if (vinfo->c_class == TrueColor)
1843         status = TRUEMATCH(red_mult, red_max, red_mask) &&
1844                  TRUEMATCH(green_mult, green_max, green_mask) &&
1845                  TRUEMATCH(blue_mult, blue_max, blue_mask);
1846     else 
1847         status = readonly_map(dpy, vinfo, colormap);
1848     
1849     XFree((char *) vpointer);
1850     return status;
1851 }
1852
1853 /****************************************************************************/
1854 static Status
1855 readwrite_map(Display *dpy, XVisualInfo *vinfo, XStandardColormap *colormap)
1856 {
1857     register unsigned long i, n;        /* index counters */
1858     unsigned long       ncolors;        /* number of colors to be defined */
1859     int                 npixels;        /* number of pixels allocated R/W */
1860     int                 first_index;    /* first index of pixels to use */
1861     int                 remainder;      /* first index of remainder */
1862     XColor              color;          /* the definition of a color */
1863     unsigned long       *pixels;        /* array of colormap pixels */
1864     unsigned long       delta;
1865
1866     
1867     /* Determine ncolors, the number of colors to be defined.
1868      * Insure that 1 < ncolors <= the colormap size.
1869      */
1870     if (vinfo->c_class == DirectColor) {
1871         ncolors = colormap->red_max;
1872         if (colormap->green_max > ncolors)
1873             ncolors = colormap->green_max;
1874         if (colormap->blue_max > ncolors)
1875             ncolors = colormap->blue_max;
1876         ncolors++;
1877         delta = lowbit(vinfo->red_mask) +
1878                 lowbit(vinfo->green_mask) +
1879                 lowbit(vinfo->blue_mask);
1880     } else {
1881         ncolors = colormap->red_max * colormap->red_mult +
1882                   colormap->green_max * colormap->green_mult +
1883                   colormap->blue_max * colormap->blue_mult + 1;
1884         delta = 1;
1885     }
1886     if (ncolors <= 1 || (int) ncolors > vinfo->colormap_size)   return 0;
1887
1888     /* Allocate Read/Write as much of the colormap as we can possibly get.
1889      * Then insure that the pixels we were allocated are given in 
1890      * monotonically increasing order, using a quicksort.  Next, insure
1891      * that our allocation includes a subset of contiguous pixels at least
1892      * as long as the number of colors to be defined.  Now we know that 
1893      * these conditions are met:
1894      *  1) There are no free cells in the colormap.
1895      *  2) We have a contiguous sequence of pixels, monotonically 
1896      *     increasing, of length >= the number of colors requested.
1897      *
1898      * One cell at a time, we will free, compute the next color value, 
1899      * then allocate read only.  This takes a long time.
1900      * This is done to insure that cells are allocated read only in the
1901      * contiguous order which we prefer.  If the server has a choice of
1902      * cells to grant to an allocation request, the server may give us any
1903      * cell, so that is why we do these slow gymnastics.
1904      */
1905
1906     if ((pixels = (unsigned long *) calloc((unsigned) vinfo->colormap_size,
1907                                       sizeof(unsigned long))) == NULL)
1908         return 0;
1909
1910     if ((npixels = ROmap(dpy, colormap->colormap, pixels,
1911                            vinfo->colormap_size, ncolors)) == 0) {
1912         free((char *) pixels);
1913         return 0;
1914     }
1915
1916     qsort((char *) pixels, npixels, sizeof(unsigned long), compare);
1917
1918     if (!contiguous(pixels, npixels, ncolors, delta, &first_index, &remainder))
1919     {
1920         /* can't find enough contiguous cells, give up */
1921         XFreeColors(dpy, colormap->colormap, pixels, npixels,
1922                     (unsigned long) 0);
1923         free((char *) pixels);
1924         return 0;
1925     }
1926     colormap->base_pixel = pixels[first_index];
1927
1928     /* construct a gray map */
1929     if (colormap->red_mult == 1 && colormap->green_mult == 1 &&
1930         colormap->blue_mult == 1)
1931         for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
1932         {
1933             color.pixel = n;
1934             color.blue = color.green = color.red =
1935                 (unsigned short) ((i * 65535) / (colormap->red_max +
1936                                                  colormap->green_max +
1937                                                  colormap->blue_max));
1938
1939             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
1940                              first_index + i))
1941                 return 0;
1942         }
1943
1944     /* construct a red ramp map */
1945     else if (colormap->green_max == 0 && colormap->blue_max == 0)
1946         for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
1947         {
1948             color.pixel = n;
1949             color.red = (unsigned short) ((i * 65535) / colormap->red_max);
1950             color.green = color.blue = 0;
1951
1952             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
1953                              first_index + i))
1954                 return 0;
1955         }
1956
1957     /* construct a green ramp map */
1958     else if (colormap->red_max == 0 && colormap->blue_max == 0)
1959         for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
1960         {
1961             color.pixel = n;
1962             color.green = (unsigned short) ((i * 65535) / colormap->green_max);
1963             color.red = color.blue = 0;
1964
1965             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
1966                              first_index + i))
1967                 return 0;
1968         }
1969
1970     /* construct a blue ramp map */
1971     else if (colormap->red_max == 0 && colormap->green_max == 0)
1972         for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
1973         {
1974             color.pixel = n;
1975             color.blue = (unsigned short) ((i * 65535) / colormap->blue_max);
1976             color.red = color.green = 0;
1977
1978             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
1979                              first_index + i))
1980                 return 0;
1981         }
1982
1983     /* construct a standard red green blue cube map */
1984     else
1985     {
1986 #define calc(max,mult) (((n / colormap->mult) % \
1987                          (colormap->max + 1)) * 65535) / colormap->max
1988
1989         for (n=0, i=0; i < ncolors; i++, n += delta)
1990         {
1991             color.pixel = n + colormap->base_pixel;
1992             color.red = calc(red_max, red_mult);
1993             color.green = calc(green_max, green_mult);
1994             color.blue = calc(blue_max, blue_mult);
1995             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
1996                              first_index + i))
1997                 return 0;
1998         }
1999 #undef calc
2000     }
2001     /* We have a read-only map defined.  Now free unused cells,
2002      * first those occuring before the contiguous sequence begins,
2003      * then any following the contiguous sequence.
2004      */
2005
2006     if (first_index)
2007         XFreeColors(dpy, colormap->colormap, pixels, first_index, 
2008                     (unsigned long) 0);
2009     if (remainder)
2010         XFreeColors(dpy, colormap->colormap,
2011                     &(pixels[first_index + ncolors]), remainder,
2012                     (unsigned long) 0);
2013
2014     free((char *) pixels);
2015     return 1;
2016 }
2017
2018
2019 /****************************************************************************/
2020 static int
2021 ROmap(Display *dpy, Colormap cmap, unsigned long pixels[], int m, int n)
2022      /*
2023       * dpy     - the X server connection
2024       * cmap    - specifies colormap ID
2025       * pixels  - returns pixel allocations
2026       * m       - specifies colormap size
2027       * n       - specifies number of colors
2028       */
2029 {
2030     register int        p;
2031
2032     /* first try to allocate the entire colormap */
2033     if (XAllocColorCells(dpy, cmap, 1, (unsigned long *) NULL, 
2034                          (unsigned) 0, pixels, (unsigned) m))
2035         return m;
2036
2037     /* Allocate all available cells in the colormap, using a binary
2038      * algorithm to discover how many cells we can allocate in the colormap.
2039      */
2040     m--;
2041     while (n <= m) {
2042         p = n + ((m - n + 1) / 2);
2043         if (XAllocColorCells(dpy, cmap, 1, (unsigned long *) NULL,
2044                              (unsigned) 0, pixels, (unsigned) p)) {
2045             if (p == m)
2046                 return p;
2047             else {
2048                 XFreeColors(dpy, cmap, pixels, p, (unsigned long) 0);
2049                 n = p;
2050             }
2051         }
2052         else
2053             m = p - 1;
2054     }
2055     return 0;
2056 }
2057       
2058
2059 /****************************************************************************/
2060 static Status
2061 contiguous(unsigned long pixels[], int npixels, int ncolors,
2062            unsigned long delta, int *first, int *rem)
2063      /* pixels  - specifies allocated pixels
2064       * npixels - specifies count of alloc'd pixels
2065       * ncolors - specifies needed sequence length
2066       * delta   - between pixels
2067       * first   - returns first index of sequence
2068       * rem     - returns first index after sequence, or 0, if none follow
2069       */
2070 {
2071     register int i = 1;         /* walking index into the pixel array */
2072     register int count = 1;     /* length of sequence discovered so far */
2073
2074     *first = 0;
2075     if (npixels == ncolors) {
2076         *rem = 0;
2077         return 1;
2078     }
2079     *rem = npixels - 1;
2080     while (count < ncolors && ncolors - count <= *rem)
2081     {
2082         if (pixels[i-1] + delta == pixels[i])
2083             count++;
2084         else {
2085             count = 1;
2086             *first = i;
2087         }
2088         i++;
2089         (*rem)--;
2090     }
2091     if (count != ncolors)
2092         return 0;
2093     return 1;
2094 }
2095
2096
2097 /****************************************************************************/
2098 static Status
2099 ROorRWcell(Display *dpy, Colormap cmap, unsigned long pixels[],
2100            int npixels, XColor *color, unsigned long p)
2101 {
2102     unsigned long       pixel;
2103     XColor              request;
2104
2105     /* Free the read/write allocation of one cell in the colormap.
2106      * Request a read only allocation of one cell in the colormap.
2107      * If the read only allocation cannot be granted, give up, because
2108      * there must be no free cells in the colormap.
2109      * If the read only allocation is granted, but gives us a cell which
2110      * is not the one that we just freed, it is probably the case that
2111      * we are trying allocate White or Black or some other color which
2112      * already has a read-only allocation in the map.  So we try to 
2113      * allocate the previously freed cell with a read/write allocation,
2114      * because we want contiguous cells for image processing algorithms.
2115      */
2116      
2117     pixel = color->pixel;
2118     request.red = color->red;
2119     request.green = color->green;
2120     request.blue = color->blue;
2121
2122     XFreeColors(dpy, cmap, &pixel, 1, (unsigned long) 0);
2123     if (! XAllocColor(dpy, cmap, color) 
2124         || (color->pixel != pixel &&
2125             (!RWcell(dpy, cmap, color, &request, &pixel)))) 
2126     {
2127         free_cells(dpy, cmap, pixels, npixels, (int)p);
2128         return 0;
2129     }
2130     return 1;
2131 }
2132
2133
2134 /****************************************************************************/
2135 static void
2136 free_cells(Display *dpy, Colormap cmap, unsigned long pixels[],
2137            int npixels, int p)
2138      /*
2139       * pixels  - to be freed
2140       * npixels - original number allocated
2141       */
2142 {
2143     /* One of the npixels allocated has already been freed.
2144      * p is the index of the freed pixel.
2145      * First free the pixels preceeding p, and there are p of them;
2146      * then free the pixels following p, there are npixels - p - 1 of them.
2147      */
2148     XFreeColors(dpy, cmap, pixels, p, (unsigned long) 0);
2149     XFreeColors(dpy, cmap, &(pixels[p+1]), npixels - p - 1, (unsigned long) 0);
2150     free((char *) pixels);
2151 }
2152
2153
2154 /****************************************************************************/
2155 static Status
2156 RWcell(Display *dpy, Colormap cmap, XColor *color, XColor *request,
2157        unsigned long *pixel)
2158 {
2159     unsigned long       n = *pixel;
2160
2161     XFreeColors(dpy, cmap, &(color->pixel), 1, (unsigned long)0);
2162     if (! XAllocColorCells(dpy, cmap, (Bool) 0, (unsigned long *) NULL,
2163                            (unsigned) 0, pixel, (unsigned) 1))
2164         return 0;
2165     if (*pixel != n)
2166     {
2167         XFreeColors(dpy, cmap, pixel, 1, (unsigned long) 0);
2168         return 0;
2169     }
2170     color->pixel = *pixel;
2171     color->flags = DoRed | DoGreen | DoBlue;
2172     color->red = request->red;
2173     color->green = request->green;
2174     color->blue = request->blue;
2175     XStoreColors(dpy, cmap, color, 1);
2176     return 1;
2177 }
2178
2179
2180 /****************************************************************************/
2181 static int
2182 compare(_Xconst void *e1, _Xconst void *e2)
2183 {
2184   return ((int)(*(long *)e1 - *(long *)e2));
2185 }
2186
2187
2188 /****************************************************************************/
2189 static Status
2190 readonly_map(Display *dpy, XVisualInfo *vinfo, XStandardColormap *colormap)
2191 {
2192     int                 i, last_pixel;
2193     XColor              color;
2194
2195     last_pixel = (colormap->red_max + 1) * (colormap->green_max + 1) * 
2196         (colormap->blue_max + 1) + colormap->base_pixel - 1;
2197
2198     for(i=colormap->base_pixel; i <= last_pixel; i++) {
2199
2200         color.pixel = (unsigned long) i;
2201         color.red = (unsigned short)
2202             (((i/colormap->red_mult) * 65535) / colormap->red_max);
2203
2204         if (vinfo->c_class == StaticColor) {
2205             color.green = (unsigned short)
2206                 ((((i/colormap->green_mult) % (colormap->green_max + 1)) *
2207                   65535) / colormap->green_max);
2208             color.blue = (unsigned short)
2209                 (((i%colormap->green_mult) * 65535) / colormap->blue_max);
2210         }
2211         else    /* vinfo->c_class == GrayScale, old style allocation XXX */
2212             color.green = color.blue = color.red;
2213
2214         XAllocColor(dpy, colormap->colormap, &color);
2215         if (color.pixel != (unsigned long) i)
2216             return 0;
2217     }
2218     return 1;
2219 }
2220
2221
2222 /* $Xorg: DelCmap.c,v 1.4 2001/02/09 02:03:52 xorgcvs Exp $ */
2223
2224 /* 
2225  
2226 Copyright 1989, 1998  The Open Group
2227
2228 Permission to use, copy, modify, distribute, and sell this software and its
2229 documentation for any purpose is hereby granted without fee, provided that
2230 the above copyright notice appear in all copies and that both that
2231 copyright notice and this permission notice appear in supporting
2232 documentation.
2233
2234 The above copyright notice and this permission notice shall be included in
2235 all copies or substantial portions of the Software.
2236
2237 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2238 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2239 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
2240 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
2241 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2242 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2243
2244 Except as contained in this notice, the name of The Open Group shall not be
2245 used in advertising or otherwise to promote the sale, use or other dealings
2246 in this Software without prior written authorization from The Open Group.
2247
2248 */
2249 /* $XFree86: xc/lib/Xmu/DelCmap.c,v 1.7 2001/12/14 19:55:40 dawes Exp $ */
2250
2251 /*
2252  * Author:  Donna Converse, MIT X Consortium
2253  */
2254
2255 #include <X11/Xlib.h>
2256 #include <X11/Xutil.h>
2257 #include <X11/Xmu/StdCmap.h>
2258
2259 int ignoreErrorHandler(Display* d, XErrorEvent* e) { }
2260
2261 /* To remove any standard colormap property, use XmuDeleteStandardColormap().
2262  * XmuDeleteStandardColormap() will remove the specified property from the
2263  * specified screen, releasing any resources used by the colormap(s) of the
2264  * property if possible.
2265  */
2266
2267 void
2268 XmuDeleteStandardColormap(Display *dpy, int screen, Atom property)
2269      /* dpy;            - specifies the X server to connect to
2270       * screen          - specifies the screen of the display
2271       * property        - specifies the standard colormap property
2272       */
2273 {
2274     XStandardColormap   *stdcmaps, *s;
2275     int                 count = 0;
2276
2277     if (XGetRGBColormaps(dpy, RootWindow(dpy, screen), &stdcmaps, &count,
2278                          property))
2279         {
2280             for (s=stdcmaps; count > 0; count--, s++) {
2281                 if ((s->killid == ReleaseByFreeingColormap) &&
2282                     (s->colormap != None) &&
2283                     (s->colormap != DefaultColormap(dpy, screen))) {
2284
2285                     // UGLY HACK written in by Adam Megacz -- sometimes s->colormap isn't valid, so we do some shuffling
2286                     X11ErrorHandler* oldHandler = XSetErrorHandler(ignoreErrorHandler);
2287                     XSync(dpy, False);
2288                     XFreeColormap(dpy, s->colormap);
2289                     XSync(dpy, False);
2290                     XSetErrorHandler(oldHandler);
2291                     XSync(dpy, False);
2292
2293                 } else if (s->killid != None) {
2294                     XKillClient(dpy, s->killid);
2295                 }
2296             }
2297             XDeleteProperty(dpy, RootWindow(dpy, screen), property);
2298             XFree((char *) stdcmaps);
2299             XSync(dpy, False);
2300         }
2301 }
2302