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