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