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