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