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