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