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