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