mousewheel support on all platforms (X11,Darwin,Win32,Java14) and in the core (bug...
[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         switch(xbe->button) {
530           case 4: VScroll((jfloat)-1.0); return;
531           case 5: VScroll((jfloat)1.0); return;
532           case 6: HScroll((jfloat)-1.0); return;
533           case 7: HScroll((jfloat)1.0); return;
534         }
535         if (xbe->button == 2) xbe->button = 3;
536         else if (xbe->button == 3) xbe->button = 2;
537         Press(xbe->button);
538         
539     } else if (e->type == ButtonRelease) {
540         XButtonEvent* xbe = (XButtonEvent*)(e);
541         if (xbe->button == 2) xbe->button = 3;
542         else if (xbe->button == 3) xbe->button = 2;
543         Release(xbe->button);
544         
545     } else if (e->type == MotionNotify) {
546         XMotionEvent* xme = (XMotionEvent*)(e);
547         Move(xme->x, xme->y);
548         
549     } else if (e->type == EnterNotify || e->type == LeaveNotify) {
550         XCrossingEvent* xce = (XCrossingEvent*)(e);
551         Move(xce->x, xce->y);
552         
553     } else if (e->type == ConfigureNotify) {
554         Window child;
555         int x_out, y_out;
556         XConfigureEvent* xce = (XConfigureEvent*)(e);
557         XTranslateCoordinates(display, (*((Window*)window)), RootWindow(display, screen_num), 0, 0, &x_out, &y_out, &child);
558         if (xce->width != root->width || xce->height != root->height) SizeChange(xce->width, xce->height);
559         if (x_out != root->x || y_out != root->y) PosChange(x_out, y_out);
560         
561     }
562 }
563
564 static jstring crosshair, east, hand, move, north, northeast, northwest,
565     south, southeast, southwest, text, west, wait_string;
566 static Cursor crosshair_cursor, east_cursor, hand_cursor, move_cursor, north_cursor,
567     northeast_cursor, northwest_cursor, south_cursor, southeast_cursor,
568     southwest_cursor, text_cursor, west_cursor, wait_cursor, default_cursor;
569
570 void org::ibex::plat::X11$X11Surface::syncCursor() {
571     
572     Cursor curs;
573     if (cursor->equals(crosshair)) curs = crosshair_cursor;
574     else if (cursor->equals(east)) curs = east_cursor;
575     else if (cursor->equals(hand)) curs = hand_cursor;
576     else if (cursor->equals(move)) curs = move_cursor;
577     else if (cursor->equals(north)) curs = north_cursor;
578     else if (cursor->equals(northeast)) curs = northeast_cursor;
579     else if (cursor->equals(northwest)) curs = northwest_cursor;
580     else if (cursor->equals(south)) curs = south_cursor;
581     else if (cursor->equals(southeast)) curs = southeast_cursor;
582     else if (cursor->equals(southwest)) curs = southwest_cursor;
583     else if (cursor->equals(text)) curs = text_cursor;
584     else if (cursor->equals(west)) curs = west_cursor;
585     else if (cursor->equals(wait_string)) curs = wait_cursor;
586     else curs = default_cursor;
587     
588     XDefineCursor(display, (*((Window*)window)), curs);
589 }
590
591
592
593 // X11 ///////////////////////////////////////////////////////////////////
594
595 jint org::ibex::plat::X11::_getScreenWidth() { return WidthOfScreen(DefaultScreenOfDisplay(display)); }
596 jint org::ibex::plat::X11::_getScreenHeight() { return HeightOfScreen(DefaultScreenOfDisplay(display)); }
597
598 static void dispatchSelectionEvent(XEvent* e) {
599     if (e->type == SelectionNotify) {
600         XSelectionEvent* xsn = (XSelectionEvent*)(e);
601         if (xsn->property == None) org::ibex::plat::X11::clipboard = JvNewStringLatin1("", 0);
602         else {
603             Atom returntype;
604             int returnformat;
605             unsigned long numitems;
606             unsigned char* ret;
607             unsigned long bytes_after;
608             XGetWindowProperty(display, xsn->requestor, xsn->property, 0, 4096,
609                                True, AnyPropertyType, &returntype, &returnformat,
610                                &numitems, &bytes_after, &ret);
611             org::ibex::plat::X11::clipboard =
612                 (returntype == None ? JvNewStringLatin1("", 0) : JvNewStringLatin1((char*)ret, strlen((char*)ret)));
613         }
614         org::ibex::plat::X11::waiting_for_selection_event->release();
615         
616     } else if (e->type == SelectionRequest) {
617         XSelectionRequestEvent* xsr = (XSelectionRequestEvent*)(e);
618         XSelectionEvent xsn;
619         xsn.type = SelectionNotify;
620         xsn.serial = xsr->serial;
621         xsn.send_event = True;
622         xsn.display = display;
623         xsn.requestor = xsr->requestor;
624         xsn.selection = xsr->selection;
625         xsn.target = xsr->target;
626         xsn.property = xsr->property;
627         xsn.time = xsr->time;
628         
629         int len = min(1024, JvGetStringUTFLength(org::ibex::plat::X11::clipboard));
630         char buf[len + 1];
631         JvGetStringUTFRegion(org::ibex::plat::X11::clipboard, 0, len, buf);
632         buf[len] = '\0';
633         
634         XChangeProperty(display, xsr->requestor, xsr->property, xsr->target, 8, PropModeReplace, (unsigned char*)buf, len + 1);
635         XSendEvent(display, xsr->requestor, True, 0, (XEvent*)(&xsn));
636     }        
637 }
638
639 void org::ibex::plat::X11::eventThread() {
640     XEvent e;
641     while(true) {
642         XNextEvent(display, &e);
643         if (e.type == SelectionNotify || e.type == SelectionRequest) {
644             dispatchSelectionEvent(&e);
645         } else {
646             org::ibex::plat::X11$X11Surface* surface =
647                 (org::ibex::plat::X11$X11Surface*)windowToSurfaceMap->get(new java::lang::Long(((XAnyEvent*)&e)->window));
648             if (surface != NULL) surface->dispatchEvent((gnu::gcj::RawData*)&e);
649         }
650     }
651 }
652
653 jstring org::ibex::plat::X11::_getClipBoard() {
654     XConvertSelection(display, XA_PRIMARY, XA_STRING, XInternAtom(display, "VT_SELECTION", False), selectionWindow, CurrentTime);
655     XFlush(display);
656     org::ibex::plat::X11::waiting_for_selection_event->block();
657     return clipboard;
658 }
659
660 void org::ibex::plat::X11::_setClipBoard(jstring s) {
661     clipboard = s;
662     int len = JvGetStringUTFLength(clipboard);
663     char buf[len + 1];
664     JvGetStringUTFRegion(clipboard, 0, len, buf);
665     buf[len] = '\0';
666     XSetSelectionOwner(display, XInternAtom(display, "PRIMARY", 0), selectionWindow, CurrentTime);
667 }
668
669 typedef int (X11ErrorHandler)(Display*, XErrorEvent*);
670 int errorHandler(Display* d, XErrorEvent* e) {
671     // this error handler is only installed during the initial
672     // test to see if shm is present
673     shm_supported = 0;
674 }
675
676 void org::ibex::plat::X11::natInit() {
677
678     if (!XInitThreads())
679         org::ibex::Platform::criticalAbort(JvNewStringLatin1("Your X11 libraries do not support multithreaded programs"));
680
681     char* DISPLAY = getenv("DISPLAY");
682     if (DISPLAY == NULL || strlen(DISPLAY) == 0) DISPLAY = ":0.0";
683     display = XOpenDisplay(DISPLAY);
684
685     if (display == 0)
686         org::ibex::Platform::criticalAbort(JvNewStringLatin1("Unable to connect to X11 display server"));
687
688     screen_num = XDefaultScreen(display);
689     colorDepth = (jint)(DefaultDepth(((Display*)display), 0));
690     shm_info.shmaddr = NULL;
691
692     // FIXME: SHM doesn't work on Darwin
693     //shm_supported = (XShmQueryExtension(display) == True);
694     if (shm_supported) {
695         X11ErrorHandler* oldHandler = XSetErrorHandler(errorHandler);
696         XShmSegmentInfo sinfo;
697         sinfo.shmid = shmget(IPC_PRIVATE, 1, IPC_CREAT | 0777 | IPC_EXCL);
698         sinfo.readOnly = False;
699         // if the server is remote, this will trigger the error handler
700         XShmAttach(display, &sinfo);
701         XSync(display, False);
702         XSetErrorHandler(oldHandler);
703     }
704
705     if (shm_supported)
706         shm_pixmaps_supported = (XShmPixmapFormat(display) == ZPixmap);
707     
708     crosshair = JvNewStringLatin1("crosshair");
709     east = JvNewStringLatin1("east");
710     hand = JvNewStringLatin1("hand");
711     move = JvNewStringLatin1("move");
712     north = JvNewStringLatin1("north");
713     northeast = JvNewStringLatin1("northeast");
714     northwest = JvNewStringLatin1("northwest");
715     south = JvNewStringLatin1("south");
716     southeast = JvNewStringLatin1("southeast");
717     southwest = JvNewStringLatin1("southwest");
718     text = JvNewStringLatin1("text");
719     west = JvNewStringLatin1("west");
720     wait_string = JvNewStringLatin1("wait");
721     crosshair_cursor = XCreateFontCursor(display, XC_tcross);
722     east_cursor = XCreateFontCursor(display, XC_right_side);
723     hand_cursor = XCreateFontCursor(display, XC_hand2);
724     move_cursor = XCreateFontCursor(display, XC_fleur);
725     north_cursor = XCreateFontCursor(display, XC_top_side);
726     northeast_cursor = XCreateFontCursor(display, XC_top_right_corner);
727     northwest_cursor = XCreateFontCursor(display, XC_left_side);
728     south_cursor = XCreateFontCursor(display, XC_bottom_side);
729     southeast_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
730     southwest_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
731     text_cursor = XCreateFontCursor(display, XC_xterm);
732     west_cursor = XCreateFontCursor(display, XC_right_side);
733     wait_cursor = XCreateFontCursor(display, XC_watch);
734     default_cursor = XCreateFontCursor(display, XC_left_ptr);
735
736     selectionWindow = XCreateWindow(display, RootWindow(display, screen_num), 0, 0, 1, 1, 0, colorDepth, InputOutput, CopyFromParent, 0, NULL);
737     visual = DefaultVisual(display, screen_num);
738     char buf[255];
739     sprintf(buf, "X11 DISPLAY: %s", XDisplayString(display));
740     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
741     sprintf(buf, "X11 SHM:     %s", shm_supported ? "enabled" : "disabled");
742     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
743     sprintf(buf, "X11 Visual:  %x %x %x bits: %i visualid: %i depth: %i",
744             visual->red_mask, visual->green_mask, visual->blue_mask, visual->bits_per_rgb, visual->visualid, colorDepth);
745     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
746
747     // FIXME: don't know why (True, False) is the best solution...
748     if(XmuLookupStandardColormap(display, screen_num, visual->visualid, colorDepth, XA_RGB_BEST_MAP, True, False) == 0)
749         org::ibex::Platform::criticalAbort(JvNewStringLatin1("ERROR: XmuLookupStandardColormap failed"));
750     
751     XStandardColormap* best_map_info = NULL;
752     int count;
753     if (XGetRGBColormaps(display, RootWindow(display, screen_num), &best_map_info, &count, XA_RGB_BEST_MAP) == 0)
754         org::ibex::Platform::criticalAbort(JvNewStringLatin1("ERROR: couldn't allocate a standard colormap"));
755     if (!best_map_info->colormap)
756         org::ibex::Platform::criticalAbort(JvNewStringLatin1("ERROR: XmuLookupStandardColomap succeded, but no colormap was found on the root window"));
757     if (best_map_info->red_max == 0)
758         org::ibex::Platform::criticalAbort(JvNewStringLatin1("ERROR: standard colormap exists, but was improperly allocated"));
759     s_colormap = best_map_info->colormap;
760     colormap_info = best_map_info;
761
762     sprintf(buf, "            red_max / red_mult: %x %x", colormap_info->red_max, colormap_info->red_mult);
763     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
764     sprintf(buf, "            green_max / green_mult: %x %x", colormap_info->green_max, colormap_info->green_mult);
765     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
766     sprintf(buf, "            blue_max / blue_mult: %x %x", colormap_info->blue_max, colormap_info->blue_mult);
767     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
768     sprintf(buf, "            base_pixel: %x", colormap_info->base_pixel);
769     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
770 }
771
772
773
774 //////////////////////////////////////////////////////////////////////////////
775 //////////////////////////////////////////////////////////////////////////////
776 //////////////////////////////////////////////////////////////////////////////
777 //////////////////////////////////////////////////////////////////////////////
778 //                                                                          //
779 // Everything below this point was taken, cut-and-paste, from the           //
780 // source for libXmu. It implements the official 'standard colormap         //
781 // creation algorithm.  I made some small changes to                        //
782 // XmuDeleteStandardColormap                                                //
783 //                                                                          //
784 //////////////////////////////////////////////////////////////////////////////
785 //////////////////////////////////////////////////////////////////////////////
786 //////////////////////////////////////////////////////////////////////////////
787 //////////////////////////////////////////////////////////////////////////////
788
789 /* $Xorg: LookupCmap.c,v 1.4 2001/02/09 02:03:53 xorgcvs Exp $ */
790
791 /* 
792  
793 Copyright 1989, 1998  The Open Group
794
795 Permission to use, copy, modify, distribute, and sell this software and its
796 documentation for any purpose is hereby granted without fee, provided that
797 the above copyright notice appear in all copies and that both that
798 copyright notice and this permission notice appear in supporting
799 documentation.
800
801 The above copyright notice and this permission notice shall be included in
802 all copies or substantial portions of the Software.
803
804 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
805 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
806 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
807 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
808 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
809 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
810
811 Except as contained in this notice, the name of The Open Group shall not be
812 used in advertising or otherwise to promote the sale, use or other dealings
813 in this Software without prior written authorization from The Open Group.
814
815 */
816 /* $XFree86: xc/lib/Xmu/LookupCmap.c,v 1.8 2001/12/14 19:55:47 dawes Exp $ */
817
818 /*
819  * Author:  Donna Converse, MIT X Consortium
820  */
821
822 #include <stdio.h>
823 #include <X11/Xlib.h>
824 #include <X11/Xatom.h>
825 #include <X11/Xutil.h>
826 #include <X11/Xmu/StdCmap.h>
827 #include <stdlib.h>
828
829 /*
830  * Prototypes
831  */
832 static Status lookup(Display*, int, VisualID, Atom, XStandardColormap*, Bool);
833
834 /*
835  * To create a standard colormap if one does not currently exist, or
836  * replace the currently existing standard colormap, use 
837  * XmuLookupStandardColormap().
838  *
839  * Given a screen, a visual, and a property, XmuLookupStandardColormap()
840  * will determine the best allocation for the property under the specified
841  * visual, and determine the whether to create a new colormap or to use
842  * the default colormap of the screen.  It will call XmuStandardColormap()
843  * to create the standard colormap.
844  *
845  * If replace is true, any previous definition of the property will be 
846  * replaced.  If retain is true, the property and the colormap will be
847  * made permanent for the duration of the server session.  However,
848  * pre-existing property definitions which are not replaced cannot be made
849  * permanent by a call to XmuLookupStandardColormap(); a request to retain 
850  * resources pertains to newly created resources.
851  *
852  * Returns 0 on failure, non-zero on success.  A request to create a 
853  * standard colormap upon a visual which cannot support such a map is
854  * considered a failure.  An example of this would be requesting any
855  * standard colormap property on a monochrome visual, or, requesting an
856  * RGB_BEST_MAP on a display whose colormap size is 16.
857  */
858
859 Status
860 XmuLookupStandardColormap(Display *dpy, int screen, VisualID visualid,
861                           unsigned int depth, Atom property,
862                           Bool replace, Bool retain)
863      /*
864       * dpy             - specifies X server connection
865       * screen          - specifies screen of display
866       * visualid        - specifies the visual type
867       * depth           - specifies  the visual type
868       * property        - a standard colormap property
869       * replace         - specifies whether to replace
870       * retain          - specifies whether to retain
871       */
872 {
873     Display             *odpy;          /* original display connection */
874     XStandardColormap   *colormap;      
875     XVisualInfo         vinfo_template, *vinfo; /* visual */
876     long                vinfo_mask;
877     unsigned long       r_max, g_max, b_max;    /* allocation */
878     int                 count;  
879     Colormap            cmap;                   /* colormap ID */
880     Status              status = 0;
881
882
883     /* Match the requested visual */
884
885     vinfo_template.visualid = visualid; 
886     vinfo_template.screen = screen;
887     vinfo_template.depth = depth;
888     vinfo_mask = VisualIDMask | VisualScreenMask | VisualDepthMask;
889     if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &count)) ==
890         NULL)
891         return 0;
892
893     /* Monochrome visuals have no standard maps */
894
895     if (vinfo->colormap_size <= 2) {
896         XFree((char *) vinfo);
897         return 0;       
898     }
899
900     /* If the requested property already exists on this screen, and, 
901      * if the replace flag has not been set to true, return success.
902      * lookup() will remove a pre-existing map if replace is true.
903      */
904
905     if (lookup(dpy, screen, visualid, property, (XStandardColormap *) NULL,
906                replace) && !replace) {
907         XFree((char *) vinfo);
908         return 1;
909     }
910
911     /* Determine the best allocation for this property under the requested
912      * visualid and depth, and determine whether or not to use the default
913      * colormap of the screen.
914      */
915
916     if (!XmuGetColormapAllocation(vinfo, property, &r_max, &g_max, &b_max)) {
917         XFree((char *) vinfo);
918         return 0;
919     }
920
921     cmap = (property == XA_RGB_DEFAULT_MAP &&
922             visualid == XVisualIDFromVisual(DefaultVisual(dpy, screen)))
923         ? DefaultColormap(dpy, screen) : None;
924
925     /* If retaining resources, open a new connection to the same server */
926
927     if (retain) {
928         odpy = dpy;
929         if ((dpy = XOpenDisplay(XDisplayString(odpy))) == NULL) {
930             XFree((char *) vinfo);
931             return 0;
932         }
933     }
934
935     /* Create the standard colormap */
936
937     colormap = XmuStandardColormap(dpy, screen, visualid, depth, property,
938                                    cmap, r_max, g_max, b_max);
939
940     /* Set the standard colormap property */
941
942     if (colormap) {
943         XGrabServer(dpy);
944
945         if (lookup(dpy, screen, visualid, property, colormap, replace) &&
946             !replace) {
947             /* Someone has defined the property since we last looked.
948              * Since we will not replace it, release our own resources.
949              * If this is the default map, our allocations will be freed 
950              * when this connection closes.
951              */
952             if (colormap->killid == ReleaseByFreeingColormap)
953             XFreeColormap(dpy, colormap->colormap);
954         } else if (retain) {
955                 XSetCloseDownMode(dpy, RetainPermanent);
956         }
957         XUngrabServer(dpy);
958         XFree((char *) colormap);
959         status = 1;
960     }
961
962     if (retain)
963         XCloseDisplay(dpy);
964     XFree((char *) vinfo);
965     return status;
966 }
967
968 /***************************************************************************/
969
970 /* Lookup a standard colormap property.  If the property is RGB_DEFAULT_MAP,
971  * the visualid is used to determine whether the indicated standard colormap
972  * exists.  If the map exists and replace is true, delete the resources used
973  * by the map and remove the property.  Return true if the map exists,
974  * or did exist and was deleted; return false if the map was not found.
975  *
976  * Note that this is not the way that a Status return is normally used.
977  *
978  * If new is not NULL, new points to an XStandardColormap structure which
979  * describes a standard colormap of the specified property.  It will be made
980  * a standard colormap of the screen if none already exists, or if replace 
981  * is true.
982  */
983
984 static Status
985 lookup(Display *dpy, int screen, VisualID visualid, Atom property,
986        XStandardColormap *cnew, Bool replace)
987      /*
988       * dpy             - specifies display connection
989       * screen          - specifies screen number
990       * visualid        - specifies visualid for std map
991       * property        - specifies colormap property name
992       * cnew            - specifies a standard colormap
993       * replace         - specifies whether to replace
994       */
995 {
996     register int        i;
997     int                 count;
998     XStandardColormap   *stdcmaps, *s;
999     Window              win = RootWindow(dpy, screen);
1000
1001     /* The property does not already exist */
1002
1003     if (! XGetRGBColormaps(dpy, win, &stdcmaps, &count, property)) {
1004         if (cnew)
1005             XSetRGBColormaps(dpy, win, cnew, 1, property);
1006         return 0;
1007     }
1008
1009     /* The property exists and is not describing the RGB_DEFAULT_MAP */
1010
1011     if (property != XA_RGB_DEFAULT_MAP) {
1012         if (replace) {
1013             XmuDeleteStandardColormap(dpy, screen, property);
1014             if (cnew)
1015                 XSetRGBColormaps(dpy, win, cnew, 1, property);
1016         }
1017         XFree((char *)stdcmaps);
1018         return 1;
1019     }
1020
1021     /* The property exists and is RGB_DEFAULT_MAP */
1022     
1023     for (i=0, s=stdcmaps; (i < count) && (s->visualid != visualid); i++, s++)
1024         ;
1025
1026     /* No RGB_DEFAULT_MAP property matches the given visualid */
1027
1028     if (i == count) {
1029         if (cnew) {
1030             XStandardColormap   *m, *maps;
1031
1032             s = (XStandardColormap *) malloc((unsigned) ((count+1) * sizeof
1033                                               (XStandardColormap)));
1034
1035             for (i = 0, m = s, maps = stdcmaps; i < count; i++, m++, maps++) {
1036                 m->colormap   = maps->colormap;
1037                 m->red_max    = maps->red_max;
1038                 m->red_mult   = maps->red_mult;
1039                 m->green_max  = maps->green_max;
1040                 m->green_mult = maps->green_mult;
1041                 m->blue_max   = maps->blue_max;
1042                 m->blue_mult  = maps->blue_mult;
1043                 m->base_pixel = maps->base_pixel;
1044                 m->visualid   = maps->visualid;
1045                 m->killid     = maps->killid;
1046             }
1047             m->colormap   = cnew->colormap;
1048             m->red_max    = cnew->red_max;
1049             m->red_mult   = cnew->red_mult;
1050             m->green_max  = cnew->green_max;
1051             m->green_mult = cnew->green_mult;
1052             m->blue_max   = cnew->blue_max;
1053             m->blue_mult  = cnew->blue_mult;
1054             m->base_pixel = cnew->base_pixel;
1055             m->visualid   = cnew->visualid;
1056             m->killid     = cnew->killid;
1057
1058             XSetRGBColormaps(dpy, win, s, ++count, property);
1059             free((char *) s);
1060         }
1061         XFree((char *) stdcmaps);
1062         return 0;
1063     }
1064
1065     /* Found an RGB_DEFAULT_MAP property with a matching visualid */
1066
1067     if (replace) {
1068         /* Free old resources first - we may need them, particularly in 
1069          * the default colormap of the screen.  However, because of this,
1070          * it is possible that we will destroy the old resource and fail 
1071          * to create a new one if XmuStandardColormap() fails.
1072          */
1073
1074         if (count == 1) {
1075             XmuDeleteStandardColormap(dpy, screen, property);
1076             if (cnew)
1077                 XSetRGBColormaps(dpy, win, cnew, 1, property);
1078         }
1079         else {
1080             XStandardColormap   *map;
1081
1082             /* s still points to the matching standard colormap */
1083
1084             if (s->killid == ReleaseByFreeingColormap) {
1085                 if ((s->colormap != None) &&
1086                     (s->colormap != DefaultColormap(dpy, screen)))
1087                     XFreeColormap(dpy, s->colormap);
1088             }
1089             else if (s->killid != None)
1090                 XKillClient(dpy, s->killid);
1091
1092             map = (cnew) ? cnew : stdcmaps + --count;
1093
1094             s->colormap   = map->colormap;
1095             s->red_max    = map->red_max;
1096             s->red_mult   = map->red_mult;
1097             s->green_max  = map->green_max;
1098             s->green_mult = map->green_mult;
1099             s->blue_max   = map->blue_max;
1100             s->blue_mult  = map->blue_mult;
1101             s->visualid   = map->visualid;
1102             s->killid     = map->killid;
1103
1104             XSetRGBColormaps(dpy, win, stdcmaps, count, property);
1105         }
1106     }
1107     XFree((char *) stdcmaps);
1108     return 1;
1109 }
1110
1111 /* $Xorg: CmapAlloc.c,v 1.4 2001/02/09 02:03:51 xorgcvs Exp $ */
1112
1113 /* 
1114
1115 Copyright 1989, 1994, 1998  The Open Group
1116
1117 Permission to use, copy, modify, distribute, and sell this software and its
1118 documentation for any purpose is hereby granted without fee, provided that
1119 the above copyright notice appear in all copies and that both that
1120 copyright notice and this permission notice appear in supporting
1121 documentation.
1122
1123 The above copyright notice and this permission notice shall be included in
1124 all copies or substantial portions of the Software.
1125
1126 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1127 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1128 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1129 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1130 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1131 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1132
1133 Except as contained in this notice, the name of The Open Group shall not be
1134 used in advertising or otherwise to promote the sale, use or other dealings
1135 in this Software without prior written authorization from The Open Group.
1136
1137 */
1138 /* $XFree86: xc/lib/Xmu/CmapAlloc.c,v 1.7 2001/12/14 19:55:35 dawes Exp $ */
1139
1140 /*
1141  * Author:  Donna Converse, MIT X Consortium
1142  */
1143
1144 #include <X11/Xlib.h>
1145 #include <X11/Xatom.h>
1146 #include <X11/Xutil.h>
1147 #include <X11/Xmu/StdCmap.h>
1148 #include <stdio.h>
1149
1150 #define lowbit(x) ((x) & (~(x) + 1))
1151
1152 /*
1153  * Prototypes
1154  */
1155 static void best_allocation(XVisualInfo*, unsigned long*, unsigned long*,
1156                             unsigned long*);
1157 static int default_allocation(XVisualInfo*, unsigned long*,
1158                               unsigned long*, unsigned long*);
1159 static void gray_allocation(int, unsigned long*, unsigned long*,
1160                             unsigned long*);
1161 static int icbrt(int);
1162 static int icbrt_with_bits(int, int);
1163 static int icbrt_with_guess(int, int);
1164
1165 /* To determine the best allocation of reds, greens, and blues in a 
1166  * standard colormap, use XmuGetColormapAllocation.
1167  *      vinfo           specifies visual information for a chosen visual
1168  *      property        specifies one of the standard colormap property names
1169  *      red_max         returns maximum red value 
1170  *      green_max       returns maximum green value
1171  *      blue_max        returns maximum blue value
1172  *
1173  * XmuGetColormapAllocation returns 0 on failure, non-zero on success.
1174  * It is assumed that the visual is appropriate for the colormap property.
1175  */
1176
1177 Status
1178 XmuGetColormapAllocation(XVisualInfo *vinfo, Atom property,
1179                          unsigned long *red_max,
1180                          unsigned long *green_max,
1181                          unsigned long *blue_max)
1182 {
1183     Status      status = 1;
1184
1185     if (vinfo->colormap_size <= 2)
1186         return 0;
1187
1188     switch (property)
1189     {
1190       case XA_RGB_DEFAULT_MAP:
1191         status = default_allocation(vinfo, red_max, green_max, blue_max);
1192         break;
1193       case XA_RGB_BEST_MAP:
1194         best_allocation(vinfo, red_max, green_max, blue_max);
1195         break;
1196       case XA_RGB_GRAY_MAP:
1197         gray_allocation(vinfo->colormap_size, red_max, green_max, blue_max);
1198         break;
1199       case XA_RGB_RED_MAP:
1200         *red_max = vinfo->colormap_size - 1;
1201         *green_max = *blue_max = 0;
1202         break;
1203       case XA_RGB_GREEN_MAP:
1204         *green_max = vinfo->colormap_size - 1;
1205         *red_max = *blue_max = 0;
1206         break;
1207       case XA_RGB_BLUE_MAP:
1208         *blue_max = vinfo->colormap_size - 1;
1209         *red_max = *green_max = 0;
1210         break;
1211       default:
1212         status = 0;
1213     }
1214     return status;
1215 }
1216
1217 /****************************************************************************/
1218 /* Determine the appropriate color allocations of a gray scale.
1219  *
1220  * Keith Packard, MIT X Consortium
1221  */
1222
1223 static void
1224 gray_allocation(int n, unsigned long *red_max, unsigned long *green_max,
1225                 unsigned long *blue_max)
1226 {
1227     *red_max = (n * 30) / 100;
1228     *green_max = (n * 59) / 100; 
1229     *blue_max = (n * 11) / 100; 
1230     *green_max += ((n - 1) - (*red_max + *green_max + *blue_max));
1231 }
1232
1233 /****************************************************************************/
1234 /* Determine an appropriate color allocation for the RGB_DEFAULT_MAP.
1235  * If a map has less than a minimum number of definable entries, we do not
1236  * produce an allocation for an RGB_DEFAULT_MAP.  
1237  *
1238  * For 16 planes, the default colormap will have 27 each RGB; for 12 planes,
1239  * 12 each.  For 8 planes, let n = the number of colormap entries, which may
1240  * be 256 or 254.  Then, maximum red value = floor(cube_root(n - 125)) - 1.
1241  * Maximum green and maximum blue values are identical to maximum red.
1242  * This leaves at least 125 cells which clients can allocate.
1243  *
1244  * Return 0 if an allocation has been determined, non-zero otherwise.
1245  */
1246
1247 static int
1248 default_allocation(XVisualInfo *vinfo, unsigned long *red,
1249                    unsigned long *green, unsigned long *blue)
1250 {
1251     int                 ngrays;         /* number of gray cells */
1252
1253     switch (vinfo->c_class)
1254       {
1255       case PseudoColor:
1256         
1257         if (vinfo->colormap_size > 65000)
1258           /* intended for displays with 16 planes */
1259           *red = *green = *blue = (unsigned long) 27;
1260         else if (vinfo->colormap_size > 4000)
1261           /* intended for displays with 12 planes */
1262             *red = *green = *blue = (unsigned long) 12;
1263       else if (vinfo->colormap_size < 250)
1264             return 0;
1265       else
1266             /* intended for displays with 8 planes */
1267             *red = *green = *blue = (unsigned long)
1268           (icbrt(vinfo->colormap_size - 125) - 1);
1269       break;
1270       
1271     case DirectColor:
1272       
1273         if (vinfo->colormap_size < 10)
1274             return 0;
1275         *red = *green = *blue = vinfo->colormap_size / 2 - 1;
1276         break;
1277
1278       case TrueColor:
1279
1280         *red = vinfo->red_mask / lowbit(vinfo->red_mask);
1281         *green = vinfo->green_mask / lowbit(vinfo->green_mask);
1282         *blue = vinfo->blue_mask / lowbit(vinfo->blue_mask);
1283         break;
1284
1285       case GrayScale:
1286
1287         if (vinfo->colormap_size > 65000)
1288             ngrays = 4096;
1289         else if (vinfo->colormap_size > 4000)
1290             ngrays = 512;
1291         else if (vinfo->colormap_size < 250)
1292             return 0;
1293         else
1294             ngrays = 12;
1295         gray_allocation(ngrays, red, green, blue);
1296         break;
1297         
1298       default:
1299         return 0;
1300     }
1301     return 1;
1302 }
1303
1304 /****************************************************************************/
1305 /* Determine an appropriate color allocation for the RGB_BEST_MAP.
1306  *
1307  * For a DirectColor or TrueColor visual, the allocation is determined
1308  * by the red_mask, green_mask, and blue_mask members of the visual info.
1309  *
1310  * Otherwise, if the colormap size is an integral power of 2, determine
1311  * the allocation according to the number of bits given to each color,
1312  * with green getting more than red, and red more than blue, if there
1313  * are to be inequities in the distribution.  If the colormap size is
1314  * not an integral power of 2, let n = the number of colormap entries.
1315  * Then maximum red value = floor(cube_root(n)) - 1;
1316  *      maximum blue value = floor(cube_root(n)) - 1;
1317  *      maximum green value = n / ((# red values) * (# blue values)) - 1;
1318  * Which, on a GPX, allows for 252 entries in the best map, out of 254
1319  * defineable colormap entries.
1320  */
1321  
1322 static void
1323 best_allocation(XVisualInfo *vinfo, unsigned long *red, unsigned long *green,
1324                 unsigned long *blue)
1325 {
1326
1327     if (vinfo->c_class == DirectColor ||        vinfo->c_class == TrueColor)
1328     {
1329         *red = vinfo->red_mask;
1330         while ((*red & 01) == 0)
1331             *red >>= 1;
1332         *green = vinfo->green_mask;
1333         while ((*green & 01) == 0)
1334             *green >>=1;
1335         *blue = vinfo->blue_mask;
1336         while ((*blue & 01) == 0)
1337             *blue >>= 1;
1338     }
1339     else
1340     {
1341         register int bits, n;
1342         
1343         /* Determine n such that n is the least integral power of 2 which is
1344          * greater than or equal to the number of entries in the colormap.
1345          */
1346         n = 1;
1347         bits = 0;
1348         while (vinfo->colormap_size > n)
1349         {
1350             n = n << 1;
1351             bits++;
1352         }
1353         
1354         /* If the number of entries in the colormap is a power of 2, determine
1355          * the allocation by "dealing" the bits, first to green, then red, then
1356          * blue.  If not, find the maximum integral red, green, and blue values
1357          * which, when multiplied together, do not exceed the number of 
1358
1359          * colormap entries.
1360          */
1361         if (n == vinfo->colormap_size)
1362         {
1363             register int r, g, b;
1364             b = bits / 3;
1365             g = b + ((bits % 3) ? 1 : 0);
1366             r = b + (((bits % 3) == 2) ? 1 : 0);
1367             *red = 1 << r;
1368             *green = 1 << g;
1369             *blue = 1 << b;
1370         }
1371         else
1372         {
1373             *red = icbrt_with_bits(vinfo->colormap_size, bits);
1374             *blue = *red;       
1375             *green = (vinfo->colormap_size / ((*red) * (*blue)));
1376         }
1377         (*red)--;
1378         (*green)--;
1379         (*blue)--;
1380     }
1381     return;
1382 }
1383
1384 /*
1385  * integer cube roots by Newton's method
1386  *
1387  * Stephen Gildea, MIT X Consortium, July 1991
1388  */
1389
1390 static int
1391 icbrt(int a)
1392 {
1393     register int bits = 0;
1394     register unsigned n = a;
1395
1396     while (n)
1397     {
1398         bits++;
1399         n >>= 1;
1400     }
1401     return icbrt_with_bits(a, bits);
1402 }
1403
1404
1405 static int
1406 icbrt_with_bits(int a, int bits)
1407      /* bits - log 2 of a */
1408 {
1409     return icbrt_with_guess(a, a>>2*bits/3);
1410 }
1411
1412 #ifdef _X_ROOT_STATS
1413 int icbrt_loopcount;
1414 #endif
1415
1416 /* Newton's Method:  x_n+1 = x_n - ( f(x_n) / f'(x_n) ) */
1417
1418 /* for cube roots, x^3 - a = 0,  x_new = x - 1/3 (x - a/x^2) */
1419
1420 /*
1421  * Quick and dirty cube roots.  Nothing fancy here, just Newton's method.
1422  * Only works for positive integers (since that's all we need).
1423  * We actually return floor(cbrt(a)) because that's what we need here, too.
1424  */
1425
1426 static int
1427 icbrt_with_guess(int a, int guess)
1428 {
1429     register int delta;
1430
1431 #ifdef _X_ROOT_STATS
1432     icbrt_loopcount = 0;
1433 #endif
1434     if (a <= 0)
1435         return 0;
1436     if (guess < 1)
1437         guess = 1;
1438
1439     do {
1440 #ifdef _X_ROOT_STATS
1441         icbrt_loopcount++;
1442 #endif
1443         delta = (guess - a/(guess*guess))/3;
1444 #ifdef DEBUG
1445         printf("pass %d: guess=%d, delta=%d\n", icbrt_loopcount, guess, delta);
1446 #endif
1447         guess -= delta;
1448     } while (delta != 0);
1449
1450     if (guess*guess*guess > a)
1451         guess--;
1452
1453     return guess;
1454 }
1455
1456
1457 /* $Xorg: StdCmap.c,v 1.4 2001/02/09 02:03:53 xorgcvs Exp $ */
1458
1459 /* 
1460
1461 Copyright 1989, 1998  The Open Group
1462
1463 Permission to use, copy, modify, distribute, and sell this software and its
1464 documentation for any purpose is hereby granted without fee, provided that
1465 the above copyright notice appear in all copies and that both that
1466 copyright notice and this permission notice appear in supporting
1467 documentation.
1468
1469 The above copyright notice and this permission notice shall be included in
1470 all copies or substantial portions of the Software.
1471
1472 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1473 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1474 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1475 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1476 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1477 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1478
1479 Except as contained in this notice, the name of The Open Group shall not be
1480 used in advertising or otherwise to promote the sale, use or other dealings
1481 in this Software without prior written authorization from The Open Group.
1482
1483 */
1484 /* $XFree86: xc/lib/Xmu/StdCmap.c,v 1.6 2001/12/14 19:55:48 dawes Exp $ */
1485
1486 /*
1487  * Author:  Donna Converse, MIT X Consortium
1488  */
1489
1490 #include <stdio.h>
1491 #include <X11/Xlib.h>
1492 #include <X11/Xatom.h>
1493 #include <X11/Xutil.h>
1494 #include <X11/Xmu/StdCmap.h>
1495
1496 #define lowbit(x) ((x) & (~(x) + 1))
1497
1498 /*
1499  * Prototypes
1500  */
1501 /* argument restrictions */
1502 static Status valid_args(XVisualInfo*, unsigned long, unsigned long,
1503                          unsigned long, Atom);
1504
1505 /*
1506  * To create any one standard colormap, use XmuStandardColormap().
1507  *
1508  * Create a standard colormap for the given screen, visualid, and visual
1509  * depth, with the given red, green, and blue maximum values, with the
1510  * given standard property name.  Return a pointer to an XStandardColormap
1511  * structure which describes the newly created colormap, upon success.
1512  * Upon failure, return NULL.
1513  * 
1514  * XmuStandardColormap() calls XmuCreateColormap() to create the map.
1515  *
1516  * Resources created by this function are not made permanent; that is the
1517  * caller's responsibility.
1518  */
1519
1520 XStandardColormap *
1521 XmuStandardColormap(Display *dpy, int screen, VisualID visualid,
1522                     unsigned int depth, Atom property, Colormap cmap,
1523                     unsigned long red_max, unsigned long green_max,
1524                     unsigned long blue_max)
1525      /*
1526       * dpy                             - specifies X server connection
1527       * screen                          - specifies display screen
1528       * visualid                        - identifies the visual type
1529       * depth                           - identifies the visual type
1530       * property                        - a standard colormap property
1531       * cmap                            - specifies colormap ID or None
1532       * red_max, green_max, blue_max    - allocations
1533       */
1534 {
1535     XStandardColormap   *stdcmap;
1536     Status              status;
1537     XVisualInfo         vinfo_template, *vinfo;
1538     long                vinfo_mask;
1539     int                 n;
1540
1541     /* Match the required visual information to an actual visual */
1542     vinfo_template.visualid = visualid; 
1543     vinfo_template.screen = screen;
1544     vinfo_template.depth = depth;
1545     vinfo_mask = VisualIDMask | VisualScreenMask | VisualDepthMask;
1546     if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &n)) == NULL)
1547         return 0;
1548
1549     /* Check the validity of the combination of visual characteristics,
1550      * allocation, and colormap property.  Create an XStandardColormap
1551      * structure.
1552      */
1553
1554     if (! valid_args(vinfo, red_max, green_max, blue_max, property)
1555         || ((stdcmap = XAllocStandardColormap()) == NULL)) {
1556         XFree((char *) vinfo);
1557         return 0;
1558     }
1559
1560     /* Fill in the XStandardColormap structure */
1561
1562     if (cmap == DefaultColormap(dpy, screen)) {
1563         /* Allocating out of the default map, cannot use XFreeColormap() */
1564         Window win = XCreateWindow(dpy, RootWindow(dpy, screen), 1, 1, 1, 1,
1565                                    0, 0, InputOnly, vinfo->visual,
1566                                    (unsigned long) 0,
1567                                    (XSetWindowAttributes *)NULL);
1568         stdcmap->killid  = (XID) XCreatePixmap(dpy, win, 1, 1, depth);
1569         XDestroyWindow(dpy, win);
1570         stdcmap->colormap = cmap;
1571     } else {
1572         stdcmap->killid = ReleaseByFreeingColormap;
1573         stdcmap->colormap = XCreateColormap(dpy, RootWindow(dpy, screen),
1574                                             vinfo->visual, AllocNone);
1575     }
1576     stdcmap->red_max = red_max;
1577     stdcmap->green_max = green_max;
1578     stdcmap->blue_max = blue_max;
1579     if (property == XA_RGB_GRAY_MAP) 
1580         stdcmap->red_mult = stdcmap->green_mult = stdcmap->blue_mult = 1;
1581     else if (vinfo->c_class == TrueColor || vinfo->c_class == DirectColor) {
1582         stdcmap->red_mult = lowbit(vinfo->red_mask);
1583         stdcmap->green_mult = lowbit(vinfo->green_mask);
1584         stdcmap->blue_mult = lowbit(vinfo->blue_mask);
1585     } else {
1586         stdcmap->red_mult = (red_max > 0)
1587             ? (green_max + 1) * (blue_max + 1) : 0;
1588         stdcmap->green_mult = (green_max > 0) ? blue_max + 1 : 0;
1589         stdcmap->blue_mult = (blue_max > 0) ? 1 : 0;
1590     }
1591     stdcmap->base_pixel = 0;                    /* base pixel may change */
1592     stdcmap->visualid = vinfo->visualid;
1593
1594     /* Make the colormap */
1595
1596     status = XmuCreateColormap(dpy, stdcmap);
1597
1598     /* Clean up */
1599
1600     XFree((char *) vinfo);
1601     if (!status) {
1602
1603         /* Free the colormap or the pixmap, if we created one */
1604         if (stdcmap->killid == ReleaseByFreeingColormap)
1605             XFreeColormap(dpy, stdcmap->colormap);
1606         else if (stdcmap->killid != None)
1607             XFreePixmap(dpy, stdcmap->killid);
1608         
1609         XFree((char *) stdcmap);
1610         return (XStandardColormap *) NULL;
1611     }
1612     return stdcmap;
1613 }
1614
1615 /****************************************************************************/
1616 static Status
1617 valid_args(XVisualInfo *vinfo, unsigned long red_max, unsigned long green_max,
1618            unsigned long blue_max, Atom property)
1619      /*
1620       * vinfo                           - specifies visual
1621       * red_max, green_max, blue_max    - specifies alloc
1622       * property                        - specifies property name
1623       */
1624 {
1625     unsigned long       ncolors;        /* number of colors requested */
1626
1627     /* Determine that the number of colors requested is <= map size */
1628
1629     if ((vinfo->c_class == DirectColor) || (vinfo->c_class == TrueColor)) {
1630         unsigned long mask;
1631
1632         mask = vinfo->red_mask;
1633         while (!(mask & 1))
1634             mask >>= 1;
1635         if (red_max > mask)
1636             return 0;
1637         mask = vinfo->green_mask;
1638         while (!(mask & 1))
1639             mask >>= 1;
1640         if (green_max > mask)
1641             return 0;
1642         mask = vinfo->blue_mask;
1643         while (!(mask & 1))
1644             mask >>= 1;
1645         if (blue_max > mask)
1646             return 0;
1647     } else if (property == XA_RGB_GRAY_MAP) {
1648         ncolors = red_max + green_max + blue_max + 1;
1649         if (ncolors > vinfo->colormap_size)
1650             return 0;
1651     } else {
1652         ncolors = (red_max + 1) * (green_max + 1) * (blue_max + 1);
1653         if (ncolors > vinfo->colormap_size)
1654             return 0;
1655     }
1656     
1657     /* Determine that the allocation and visual make sense for the property */
1658
1659     switch (property)
1660     {
1661       case XA_RGB_DEFAULT_MAP:
1662         if (red_max == 0 || green_max == 0 || blue_max == 0)
1663             return 0;
1664         break;
1665       case XA_RGB_RED_MAP:
1666         if (red_max == 0)
1667             return 0;
1668         break;
1669       case XA_RGB_GREEN_MAP:
1670         if (green_max == 0)
1671             return 0;
1672         break;
1673       case XA_RGB_BLUE_MAP:     
1674         if (blue_max == 0)
1675             return 0;
1676         break;
1677       case XA_RGB_BEST_MAP:
1678         if (red_max == 0 || green_max == 0 || blue_max == 0)
1679             return 0;
1680         break;
1681       case XA_RGB_GRAY_MAP:
1682         if (red_max == 0 || blue_max == 0 || green_max == 0)
1683             return 0;
1684         break;
1685       default:
1686         return 0;
1687     }
1688     return 1;
1689 }
1690
1691
1692 /* $Xorg: CrCmap.c,v 1.4 2001/02/09 02:03:51 xorgcvs Exp $ */
1693
1694 /* 
1695
1696 Copyright 1989, 1998  The Open Group
1697
1698 Permission to use, copy, modify, distribute, and sell this software and its
1699 documentation for any purpose is hereby granted without fee, provided that
1700 the above copyright notice appear in all copies and that both that
1701 copyright notice and this permission notice appear in supporting
1702 documentation.
1703
1704 The above copyright notice and this permission notice shall be included in
1705 all copies or substantial portions of the Software.
1706
1707 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1708 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1709 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1710 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1711 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1712 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1713
1714 Except as contained in this notice, the name of The Open Group shall not be
1715 used in advertising or otherwise to promote the sale, use or other dealings
1716 in this Software without prior written authorization from The Open Group.
1717
1718 */
1719 /* $XFree86: xc/lib/Xmu/CrCmap.c,v 3.7 2001/12/14 19:55:36 dawes Exp $ */
1720
1721 /*
1722  * Author:  Donna Converse, MIT X Consortium
1723  */
1724
1725 /*
1726  * CreateCmap.c - given a standard colormap description, make the map.
1727  */
1728
1729 #include <stdio.h>
1730 #include <stdlib.h>
1731 #include <X11/Xlib.h>
1732 #include <X11/Xutil.h>
1733 #include <X11/Xmu/StdCmap.h>
1734
1735 /*
1736  * Prototypes
1737  */
1738 /* allocate entire map Read Only */
1739 static int ROmap(Display*, Colormap, unsigned long[], int, int);
1740
1741 /* allocate a cell, prefer Read Only */
1742 static Status ROorRWcell(Display*, Colormap, unsigned long[], int,
1743                          XColor*, unsigned long);
1744
1745 /* allocate a cell Read Write */
1746 static Status RWcell(Display*, Colormap, XColor*, XColor*, unsigned long*);
1747
1748 /* for quicksort */
1749 static int compare(_Xconst void*, _Xconst void*);
1750
1751 /* find contiguous sequence of cells */
1752 static Status contiguous(unsigned long[], int, int, unsigned long, int*, int*);
1753
1754 /* frees resources before quitting */
1755 static void free_cells(Display*, Colormap, unsigned long[], int, int);
1756
1757 /* create a map in a RO visual type */
1758 static Status readonly_map(Display*, XVisualInfo*, XStandardColormap*);
1759
1760 /* create a map in a RW visual type */
1761 static Status readwrite_map(Display*, XVisualInfo*, XStandardColormap*);
1762
1763 #define lowbit(x) ((x) & (~(x) + 1))
1764 #define TRUEMATCH(mult,max,mask) \
1765     (colormap->max * colormap->mult <= vinfo->mask && \
1766      lowbit(vinfo->mask) == colormap->mult)
1767
1768 /*
1769  * To create any one colormap which is described by an XStandardColormap
1770  * structure, use XmuCreateColormap().
1771  *
1772  * Return 0 on failure, non-zero on success.
1773  * Resources created by this function are not made permanent.
1774  * No argument error checking is provided.  Use at your own risk.
1775  *
1776  * All colormaps are created with read only allocations, with the exception
1777  * of read only allocations of colors in the default map or otherwise
1778  * which fail to return the expected pixel value, and these are individually 
1779  * defined as read/write allocations.  This is done so that all the cells
1780  * defined in the default map are contiguous, for use in image processing.
1781  * This typically happens with White and Black in the default map.
1782  *
1783  * Colormaps of static visuals are considered to be successfully created if
1784  * the map of the static visual matches the definition given in the
1785  * standard colormap structure.
1786  */
1787    
1788 Status
1789 XmuCreateColormap(Display *dpy, XStandardColormap *colormap)
1790      /* dpy      - specifies the connection under which the map is created
1791       * colormap - specifies the map to be created, and returns, particularly
1792       *            if the map is created as a subset of the default colormap
1793       *            of the screen, the base_pixel of the map.
1794                                          */
1795 {
1796     XVisualInfo         vinfo_template; /* template visual information */
1797     XVisualInfo         *vinfo;         /* matching visual information */
1798     XVisualInfo         *vpointer;      /* for freeing the entire list */
1799     long                vinfo_mask;     /* specifies the visual mask value */
1800     int                 n;              /* number of matching visuals */
1801     int                 status;         
1802
1803     vinfo_template.visualid = colormap->visualid;
1804     vinfo_mask = VisualIDMask;
1805     if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &n)) == NULL)
1806         return 0;
1807
1808     /* A visual id may be valid on multiple screens.  Also, there may 
1809      * be multiple visuals with identical visual ids at different depths.  
1810      * If the colormap is the Default Colormap, use the Default Visual.
1811      * Otherwise, arbitrarily, use the deepest visual.
1812      */
1813     vpointer = vinfo;
1814     if (n > 1)
1815     {
1816         register int    i;
1817         register int    screen_number;
1818         Bool            def_cmap;
1819
1820         def_cmap = False;
1821         for (screen_number = ScreenCount(dpy); --screen_number >= 0; )
1822             if (colormap->colormap == DefaultColormap(dpy, screen_number)) {
1823                 def_cmap = True;
1824                 break;
1825             }
1826
1827         if (def_cmap) {
1828             for (i=0; i < n; i++, vinfo++) {
1829                 if (vinfo->visual == DefaultVisual(dpy, screen_number))
1830                         break;
1831             }
1832         } else {
1833             int                 maxdepth = 0;
1834             XVisualInfo         *v = NULL;
1835
1836             for (i=0; i < n; i++, vinfo++)
1837                 if (vinfo->depth > maxdepth) {
1838                     maxdepth = vinfo->depth;
1839                     v = vinfo;
1840                 }
1841             vinfo = v;
1842         }
1843     }
1844
1845     if (vinfo->c_class == PseudoColor || vinfo->c_class == DirectColor ||
1846         vinfo->c_class == GrayScale)
1847         status = readwrite_map(dpy, vinfo, colormap);
1848     else if (vinfo->c_class == TrueColor)
1849         status = TRUEMATCH(red_mult, red_max, red_mask) &&
1850                  TRUEMATCH(green_mult, green_max, green_mask) &&
1851                  TRUEMATCH(blue_mult, blue_max, blue_mask);
1852     else 
1853         status = readonly_map(dpy, vinfo, colormap);
1854     
1855     XFree((char *) vpointer);
1856     return status;
1857 }
1858
1859 /****************************************************************************/
1860 static Status
1861 readwrite_map(Display *dpy, XVisualInfo *vinfo, XStandardColormap *colormap)
1862 {
1863     register unsigned long i, n;        /* index counters */
1864     unsigned long       ncolors;        /* number of colors to be defined */
1865     int                 npixels;        /* number of pixels allocated R/W */
1866     int                 first_index;    /* first index of pixels to use */
1867     int                 remainder;      /* first index of remainder */
1868     XColor              color;          /* the definition of a color */
1869     unsigned long       *pixels;        /* array of colormap pixels */
1870     unsigned long       delta;
1871
1872     
1873     /* Determine ncolors, the number of colors to be defined.
1874      * Insure that 1 < ncolors <= the colormap size.
1875      */
1876     if (vinfo->c_class == DirectColor) {
1877         ncolors = colormap->red_max;
1878         if (colormap->green_max > ncolors)
1879             ncolors = colormap->green_max;
1880         if (colormap->blue_max > ncolors)
1881             ncolors = colormap->blue_max;
1882         ncolors++;
1883         delta = lowbit(vinfo->red_mask) +
1884                 lowbit(vinfo->green_mask) +
1885                 lowbit(vinfo->blue_mask);
1886     } else {
1887         ncolors = colormap->red_max * colormap->red_mult +
1888                   colormap->green_max * colormap->green_mult +
1889                   colormap->blue_max * colormap->blue_mult + 1;
1890         delta = 1;
1891     }
1892     if (ncolors <= 1 || (int) ncolors > vinfo->colormap_size)   return 0;
1893
1894     /* Allocate Read/Write as much of the colormap as we can possibly get.
1895      * Then insure that the pixels we were allocated are given in 
1896      * monotonically increasing order, using a quicksort.  Next, insure
1897      * that our allocation includes a subset of contiguous pixels at least
1898      * as long as the number of colors to be defined.  Now we know that 
1899      * these conditions are met:
1900      *  1) There are no free cells in the colormap.
1901      *  2) We have a contiguous sequence of pixels, monotonically 
1902      *     increasing, of length >= the number of colors requested.
1903      *
1904      * One cell at a time, we will free, compute the next color value, 
1905      * then allocate read only.  This takes a long time.
1906      * This is done to insure that cells are allocated read only in the
1907      * contiguous order which we prefer.  If the server has a choice of
1908      * cells to grant to an allocation request, the server may give us any
1909      * cell, so that is why we do these slow gymnastics.
1910      */
1911
1912     if ((pixels = (unsigned long *) calloc((unsigned) vinfo->colormap_size,
1913                                       sizeof(unsigned long))) == NULL)
1914         return 0;
1915
1916     if ((npixels = ROmap(dpy, colormap->colormap, pixels,
1917                            vinfo->colormap_size, ncolors)) == 0) {
1918         free((char *) pixels);
1919         return 0;
1920     }
1921
1922     qsort((char *) pixels, npixels, sizeof(unsigned long), compare);
1923
1924     if (!contiguous(pixels, npixels, ncolors, delta, &first_index, &remainder))
1925     {
1926         /* can't find enough contiguous cells, give up */
1927         XFreeColors(dpy, colormap->colormap, pixels, npixels,
1928                     (unsigned long) 0);
1929         free((char *) pixels);
1930         return 0;
1931     }
1932     colormap->base_pixel = pixels[first_index];
1933
1934     /* construct a gray map */
1935     if (colormap->red_mult == 1 && colormap->green_mult == 1 &&
1936         colormap->blue_mult == 1)
1937         for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
1938         {
1939             color.pixel = n;
1940             color.blue = color.green = color.red =
1941                 (unsigned short) ((i * 65535) / (colormap->red_max +
1942                                                  colormap->green_max +
1943                                                  colormap->blue_max));
1944
1945             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
1946                              first_index + i))
1947                 return 0;
1948         }
1949
1950     /* construct a red ramp map */
1951     else if (colormap->green_max == 0 && colormap->blue_max == 0)
1952         for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
1953         {
1954             color.pixel = n;
1955             color.red = (unsigned short) ((i * 65535) / colormap->red_max);
1956             color.green = color.blue = 0;
1957
1958             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
1959                              first_index + i))
1960                 return 0;
1961         }
1962
1963     /* construct a green ramp map */
1964     else if (colormap->red_max == 0 && colormap->blue_max == 0)
1965         for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
1966         {
1967             color.pixel = n;
1968             color.green = (unsigned short) ((i * 65535) / colormap->green_max);
1969             color.red = color.blue = 0;
1970
1971             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
1972                              first_index + i))
1973                 return 0;
1974         }
1975
1976     /* construct a blue ramp map */
1977     else if (colormap->red_max == 0 && colormap->green_max == 0)
1978         for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
1979         {
1980             color.pixel = n;
1981             color.blue = (unsigned short) ((i * 65535) / colormap->blue_max);
1982             color.red = color.green = 0;
1983
1984             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
1985                              first_index + i))
1986                 return 0;
1987         }
1988
1989     /* construct a standard red green blue cube map */
1990     else
1991     {
1992 #define calc(max,mult) (((n / colormap->mult) % \
1993                          (colormap->max + 1)) * 65535) / colormap->max
1994
1995         for (n=0, i=0; i < ncolors; i++, n += delta)
1996         {
1997             color.pixel = n + colormap->base_pixel;
1998             color.red = calc(red_max, red_mult);
1999             color.green = calc(green_max, green_mult);
2000             color.blue = calc(blue_max, blue_mult);
2001             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
2002                              first_index + i))
2003                 return 0;
2004         }
2005 #undef calc
2006     }
2007     /* We have a read-only map defined.  Now free unused cells,
2008      * first those occuring before the contiguous sequence begins,
2009      * then any following the contiguous sequence.
2010      */
2011
2012     if (first_index)
2013         XFreeColors(dpy, colormap->colormap, pixels, first_index, 
2014                     (unsigned long) 0);
2015     if (remainder)
2016         XFreeColors(dpy, colormap->colormap,
2017                     &(pixels[first_index + ncolors]), remainder,
2018                     (unsigned long) 0);
2019
2020     free((char *) pixels);
2021     return 1;
2022 }
2023
2024
2025 /****************************************************************************/
2026 static int
2027 ROmap(Display *dpy, Colormap cmap, unsigned long pixels[], int m, int n)
2028      /*
2029       * dpy     - the X server connection
2030       * cmap    - specifies colormap ID
2031       * pixels  - returns pixel allocations
2032       * m       - specifies colormap size
2033       * n       - specifies number of colors
2034       */
2035 {
2036     register int        p;
2037
2038     /* first try to allocate the entire colormap */
2039     if (XAllocColorCells(dpy, cmap, 1, (unsigned long *) NULL, 
2040                          (unsigned) 0, pixels, (unsigned) m))
2041         return m;
2042
2043     /* Allocate all available cells in the colormap, using a binary
2044      * algorithm to discover how many cells we can allocate in the colormap.
2045      */
2046     m--;
2047     while (n <= m) {
2048         p = n + ((m - n + 1) / 2);
2049         if (XAllocColorCells(dpy, cmap, 1, (unsigned long *) NULL,
2050                              (unsigned) 0, pixels, (unsigned) p)) {
2051             if (p == m)
2052                 return p;
2053             else {
2054                 XFreeColors(dpy, cmap, pixels, p, (unsigned long) 0);
2055                 n = p;
2056             }
2057         }
2058         else
2059             m = p - 1;
2060     }
2061     return 0;
2062 }
2063       
2064
2065 /****************************************************************************/
2066 static Status
2067 contiguous(unsigned long pixels[], int npixels, int ncolors,
2068            unsigned long delta, int *first, int *rem)
2069      /* pixels  - specifies allocated pixels
2070       * npixels - specifies count of alloc'd pixels
2071       * ncolors - specifies needed sequence length
2072       * delta   - between pixels
2073       * first   - returns first index of sequence
2074       * rem     - returns first index after sequence, or 0, if none follow
2075       */
2076 {
2077     register int i = 1;         /* walking index into the pixel array */
2078     register int count = 1;     /* length of sequence discovered so far */
2079
2080     *first = 0;
2081     if (npixels == ncolors) {
2082         *rem = 0;
2083         return 1;
2084     }
2085     *rem = npixels - 1;
2086     while (count < ncolors && ncolors - count <= *rem)
2087     {
2088         if (pixels[i-1] + delta == pixels[i])
2089             count++;
2090         else {
2091             count = 1;
2092             *first = i;
2093         }
2094         i++;
2095         (*rem)--;
2096     }
2097     if (count != ncolors)
2098         return 0;
2099     return 1;
2100 }
2101
2102
2103 /****************************************************************************/
2104 static Status
2105 ROorRWcell(Display *dpy, Colormap cmap, unsigned long pixels[],
2106            int npixels, XColor *color, unsigned long p)
2107 {
2108     unsigned long       pixel;
2109     XColor              request;
2110
2111     /* Free the read/write allocation of one cell in the colormap.
2112      * Request a read only allocation of one cell in the colormap.
2113      * If the read only allocation cannot be granted, give up, because
2114      * there must be no free cells in the colormap.
2115      * If the read only allocation is granted, but gives us a cell which
2116      * is not the one that we just freed, it is probably the case that
2117      * we are trying allocate White or Black or some other color which
2118      * already has a read-only allocation in the map.  So we try to 
2119      * allocate the previously freed cell with a read/write allocation,
2120      * because we want contiguous cells for image processing algorithms.
2121      */
2122      
2123     pixel = color->pixel;
2124     request.red = color->red;
2125     request.green = color->green;
2126     request.blue = color->blue;
2127
2128     XFreeColors(dpy, cmap, &pixel, 1, (unsigned long) 0);
2129     if (! XAllocColor(dpy, cmap, color) 
2130         || (color->pixel != pixel &&
2131             (!RWcell(dpy, cmap, color, &request, &pixel)))) 
2132     {
2133         free_cells(dpy, cmap, pixels, npixels, (int)p);
2134         return 0;
2135     }
2136     return 1;
2137 }
2138
2139
2140 /****************************************************************************/
2141 static void
2142 free_cells(Display *dpy, Colormap cmap, unsigned long pixels[],
2143            int npixels, int p)
2144      /*
2145       * pixels  - to be freed
2146       * npixels - original number allocated
2147       */
2148 {
2149     /* One of the npixels allocated has already been freed.
2150      * p is the index of the freed pixel.
2151      * First free the pixels preceeding p, and there are p of them;
2152      * then free the pixels following p, there are npixels - p - 1 of them.
2153      */
2154     XFreeColors(dpy, cmap, pixels, p, (unsigned long) 0);
2155     XFreeColors(dpy, cmap, &(pixels[p+1]), npixels - p - 1, (unsigned long) 0);
2156     free((char *) pixels);
2157 }
2158
2159
2160 /****************************************************************************/
2161 static Status
2162 RWcell(Display *dpy, Colormap cmap, XColor *color, XColor *request,
2163        unsigned long *pixel)
2164 {
2165     unsigned long       n = *pixel;
2166
2167     XFreeColors(dpy, cmap, &(color->pixel), 1, (unsigned long)0);
2168     if (! XAllocColorCells(dpy, cmap, (Bool) 0, (unsigned long *) NULL,
2169                            (unsigned) 0, pixel, (unsigned) 1))
2170         return 0;
2171     if (*pixel != n)
2172     {
2173         XFreeColors(dpy, cmap, pixel, 1, (unsigned long) 0);
2174         return 0;
2175     }
2176     color->pixel = *pixel;
2177     color->flags = DoRed | DoGreen | DoBlue;
2178     color->red = request->red;
2179     color->green = request->green;
2180     color->blue = request->blue;
2181     XStoreColors(dpy, cmap, color, 1);
2182     return 1;
2183 }
2184
2185
2186 /****************************************************************************/
2187 static int
2188 compare(_Xconst void *e1, _Xconst void *e2)
2189 {
2190   return ((int)(*(long *)e1 - *(long *)e2));
2191 }
2192
2193
2194 /****************************************************************************/
2195 static Status
2196 readonly_map(Display *dpy, XVisualInfo *vinfo, XStandardColormap *colormap)
2197 {
2198     int                 i, last_pixel;
2199     XColor              color;
2200
2201     last_pixel = (colormap->red_max + 1) * (colormap->green_max + 1) * 
2202         (colormap->blue_max + 1) + colormap->base_pixel - 1;
2203
2204     for(i=colormap->base_pixel; i <= last_pixel; i++) {
2205
2206         color.pixel = (unsigned long) i;
2207         color.red = (unsigned short)
2208             (((i/colormap->red_mult) * 65535) / colormap->red_max);
2209
2210         if (vinfo->c_class == StaticColor) {
2211             color.green = (unsigned short)
2212                 ((((i/colormap->green_mult) % (colormap->green_max + 1)) *
2213                   65535) / colormap->green_max);
2214             color.blue = (unsigned short)
2215                 (((i%colormap->green_mult) * 65535) / colormap->blue_max);
2216         }
2217         else    /* vinfo->c_class == GrayScale, old style allocation XXX */
2218             color.green = color.blue = color.red;
2219
2220         XAllocColor(dpy, colormap->colormap, &color);
2221         if (color.pixel != (unsigned long) i)
2222             return 0;
2223     }
2224     return 1;
2225 }
2226
2227
2228 /* $Xorg: DelCmap.c,v 1.4 2001/02/09 02:03:52 xorgcvs Exp $ */
2229
2230 /* 
2231  
2232 Copyright 1989, 1998  The Open Group
2233
2234 Permission to use, copy, modify, distribute, and sell this software and its
2235 documentation for any purpose is hereby granted without fee, provided that
2236 the above copyright notice appear in all copies and that both that
2237 copyright notice and this permission notice appear in supporting
2238 documentation.
2239
2240 The above copyright notice and this permission notice shall be included in
2241 all copies or substantial portions of the Software.
2242
2243 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2244 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2245 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
2246 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
2247 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2248 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2249
2250 Except as contained in this notice, the name of The Open Group shall not be
2251 used in advertising or otherwise to promote the sale, use or other dealings
2252 in this Software without prior written authorization from The Open Group.
2253
2254 */
2255 /* $XFree86: xc/lib/Xmu/DelCmap.c,v 1.7 2001/12/14 19:55:40 dawes Exp $ */
2256
2257 /*
2258  * Author:  Donna Converse, MIT X Consortium
2259  */
2260
2261 #include <X11/Xlib.h>
2262 #include <X11/Xutil.h>
2263 #include <X11/Xmu/StdCmap.h>
2264
2265 int ignoreErrorHandler(Display* d, XErrorEvent* e) { }
2266
2267 /* To remove any standard colormap property, use XmuDeleteStandardColormap().
2268  * XmuDeleteStandardColormap() will remove the specified property from the
2269  * specified screen, releasing any resources used by the colormap(s) of the
2270  * property if possible.
2271  */
2272
2273 void
2274 XmuDeleteStandardColormap(Display *dpy, int screen, Atom property)
2275      /* dpy;            - specifies the X server to connect to
2276       * screen          - specifies the screen of the display
2277       * property        - specifies the standard colormap property
2278       */
2279 {
2280     XStandardColormap   *stdcmaps, *s;
2281     int                 count = 0;
2282
2283     if (XGetRGBColormaps(dpy, RootWindow(dpy, screen), &stdcmaps, &count,
2284                          property))
2285         {
2286             for (s=stdcmaps; count > 0; count--, s++) {
2287                 if ((s->killid == ReleaseByFreeingColormap) &&
2288                     (s->colormap != None) &&
2289                     (s->colormap != DefaultColormap(dpy, screen))) {
2290
2291                     // UGLY HACK written in by Adam Megacz -- sometimes s->colormap isn't valid, so we do some shuffling
2292                     X11ErrorHandler* oldHandler = XSetErrorHandler(ignoreErrorHandler);
2293                     XSync(dpy, False);
2294                     XFreeColormap(dpy, s->colormap);
2295                     XSync(dpy, False);
2296                     XSetErrorHandler(oldHandler);
2297                     XSync(dpy, False);
2298
2299                 } else if (s->killid != None) {
2300                     XKillClient(dpy, s->killid);
2301                 }
2302             }
2303             XDeleteProperty(dpy, RootWindow(dpy, screen), property);
2304             XFree((char *) stdcmaps);
2305             XSync(dpy, False);
2306         }
2307 }
2308