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