finally got pruning sorta working
[org.ibex.core.git] / src / org / ibex / plat / X11.cc
1 // Copyright 2002 Adam Megacz, see the COPYING file for licensing [LGPL]
2 // see below for copyright information on the second portion of this file
3
4 #include "POSIX.cc"
5
6 #include <X11/Xlib.h>
7 #include <X11/extensions/XShm.h>
8 #include <X11/keysymdef.h>
9 #include <X11/keysym.h>
10 #include <X11/cursorfont.h>
11 #include <X11/Xutil.h>
12 #include <X11/Xatom.h>
13 #include <X11/Xmu/StdCmap.h>
14
15 #include <java/lang/String.h>
16 #include <org/ibex/Surface.h>
17 #include <org/ibex/Picture.h>
18 #include <org/ibex/Box.h>
19 #include <org/ibex/plat/X11.h>
20 #include <org/ibex/plat/X11$X11Surface.h>
21 #include <org/ibex/plat/X11$X11Picture.h>
22 #include <org/ibex/plat/X11$X11PixelBuffer.h>
23 #include <org/ibex/util/Semaphore.h>
24 #include <org/ibex/Platform.h>
25 #include <java/lang/Long.h>
26 #include <java/util/Hashtable.h>
27 #include <org/ibex/util/Log.h>
28
29 #include <java/lang/System.h>
30 #include <java/io/PrintStream.h>
31
32 // static (per-xserver) data
33 static Visual* visual;
34 static Colormap s_colormap;
35 static XStandardColormap* colormap_info;
36 static XShmSegmentInfo shm_info;
37 static Window selectionWindow;
38 static int shm_supported = 0;
39 static int shm_pixmaps_supported;
40 static int screen_num;
41 static int colorDepth = 0;
42 static Display* display;
43 static int shm_size = 0;
44
45 #define min(a, b) ((a) < (b) ? (a) : (b))
46 #define max(a, b) ((a) < (b) ? (b) : (a))
47
48 // X11PixelBuffer //////////////////////////////////////////////////////////////////////
49
50 // ensures that the shared memory is at least size bytes; if not, allocates 3/2 * size
51 static void ensureShmSize(int size) {
52     if (size > shm_size) {
53         if (shm_size > 0) {
54             XShmDetach(display, &shm_info);
55             shmdt(shm_info.shmaddr);
56             shmctl(shm_info.shmid, IPC_RMID, 0);
57         }
58         shm_size = 3 * size / 2;
59         shm_info.shmid = shmget(IPC_PRIVATE, shm_size, IPC_CREAT | 0777 | IPC_EXCL);
60         shm_info.shmaddr = (char*)shmat(shm_info.shmid, 0, 0);
61         shm_info.readOnly = False;
62         XSync(display, False);
63         shmctl(shm_info.shmid, IPC_RMID, 0);
64         XShmAttach(display, &shm_info);
65         XSync(display, False);
66     }
67 }
68
69 void org::ibex::plat::X11$X11PixelBuffer::fastDrawPicture(org::ibex::Picture* s,
70                                                          jint dx, jint dy, jint cx1, jint cy1, jint cx2, jint cy2) {
71     org::ibex::plat::X11$X11Picture* source = (org::ibex::plat::X11$X11Picture*)s;
72
73     if (source->doublebuf->stipple != NULL) {
74         XSetClipMask(display, (*((GC*)clipped_gc)), *((Pixmap*)source->doublebuf->stipple));
75         XSetClipOrigin(display, (*((GC*)clipped_gc)), dx, dy);
76     } else {
77         XSetClipMask(display, (*((GC*)clipped_gc)), None);
78     }
79
80     XCopyArea(display,
81               *((Pixmap*)source->doublebuf->pm), (*((Pixmap*)pm)), (*((GC*)clipped_gc)),
82               cx1 - dx, cy1 - dy, cx2 - cx1, cy2 - cy1, cx1, cy1);
83 }
84
85 void org::ibex::plat::X11$X11PixelBuffer::slowDrawPicture(org::ibex::Picture* s,
86                                                          jint dx, jint dy, jint cx1, jint cy1, jint cx2, jint cy2,
87                                                          jint rgb, jboolean alphaOnly) {
88
89     org::ibex::plat::X11$X11Picture* source = (org::ibex::plat::X11$X11Picture*)s;
90     XImage* xi; 
91
92     // FASTEST: shared pixmap; twiddle bits in video ram directly
93     if (shared_pixmap) {
94         XSync(display, False);  // ensure that all pending operations have rendered
95         xi = (XImage*)fake_ximage;
96
97     // MEDIUM: write to a shared ximage, then ask the server to do the blit
98     } else if (shm_supported) {
99         xi = XShmCreateImage(display, visual, colorDepth, ZPixmap, NULL, &shm_info, cx2 - cx1, cy2 - cy1);
100         ensureShmSize(xi->bytes_per_line * xi->height);
101         xi->data = shm_info.shmaddr;
102         XShmGetImage(display, (*((Pixmap*)pm)), xi, cx1, cy1, AllPlanes);
103         
104     // SLOWEST: write to an ximage, copy it through the TCP connection, ask the server to do the blit
105     } else {
106         xi = XGetImage(display, (*((Pixmap*)pm)), cx1, cy1, cx2 - cx1, cy2 - cy1, AllPlanes, ZPixmap);
107     }
108     
109     int* sourcedata = (int*)elements(source->data);
110     for(int y=cy1; y < cy2; y++) {
111
112         char* current_pixel = (xi->data + y * xi->bytes_per_line) +
113             (shared_pixmap ? cx1 * (xi->bits_per_pixel / 8) : - 1 * cy1 * xi->bytes_per_line);
114         
115         for(int x=cx1; x < cx2; x++, current_pixel += xi->bits_per_pixel / 8) {
116             int source_x = x - dx;
117             int source_y = y - dy;
118
119             // FEATURE: be smarter here; can we do something better for the alphaonly case?
120             int sourcepixel = sourcedata[source_x + source_y * source->getWidth()];
121             int alpha = (sourcepixel & 0xFF000000) >> 24;
122             if (alphaOnly) sourcepixel = rgb;
123             int source_red = (sourcepixel & 0x00FF0000) >> 16;
124             int source_green = (sourcepixel & 0x0000FF00) >> 8;
125             int source_blue = (sourcepixel & 0x000000FF);
126             int red = 0, blue = 0, green = 0;
127             int targetpixel;
128             if (alpha == 0x00) continue;
129             if (alpha != 0xFF) {
130                 switch (xi->bits_per_pixel) {
131                 case 8: targetpixel = (int)(*current_pixel); break;
132                 case 15:
133                 case 16: targetpixel = (int)(*((uint16_t*)current_pixel)); break;
134
135                 // FIXME assumes endianness...
136                 case 24: targetpixel =
137                            (((int)*current_pixel) << 16) |
138                            (((int)*(current_pixel + 1)) << 8) |
139                            (((int)*(current_pixel + 2))); break;
140                 case 32: targetpixel = *((int*)current_pixel); break;
141                 default: org::ibex::Platform::criticalAbort(JvNewStringLatin1("ERROR: bpp not a multiple of 8!"));
142                 }
143                 targetpixel -= colormap_info->base_pixel;
144
145                 // if you're on some wierd display that isn't either RGB or BGR, that's your problem, not mine
146                 if (colormap_info->red_mult > colormap_info->green_mult && colormap_info->green_mult > colormap_info->blue_mult) {
147                     red = targetpixel / colormap_info->red_mult;
148                     green = (targetpixel - red * colormap_info->red_mult) / colormap_info->green_mult;
149                     blue = (targetpixel-red * colormap_info->red_mult-green * colormap_info->green_mult)/colormap_info->blue_mult;
150                 } else {
151                     blue = targetpixel / colormap_info->blue_mult;
152                     green = (targetpixel - blue * colormap_info->blue_mult) / colormap_info->green_mult;
153                     red = (targetpixel-blue * colormap_info->blue_mult-green * colormap_info->green_mult)/colormap_info->red_mult;
154                 }
155             }
156             red = ((source_red * (colormap_info->red_max) * alpha) + (red * 0xFF * (0xFF - alpha))) / (0xFF * 0xFF);
157             green = ((source_green * (colormap_info->green_max) * alpha)+(green * 0xFF * (0xFF - alpha))) / (0xFF * 0xFF);
158             blue = ((source_blue * (colormap_info->blue_max) * alpha) + (blue * 0xFF * (0xFF - alpha))) / (0xFF * 0xFF);
159             uint32_t destpixel =
160               (red * colormap_info->red_mult) +
161               (green * colormap_info->green_mult) +
162               (blue * colormap_info->blue_mult) +
163               colormap_info->base_pixel;
164             switch (xi->bits_per_pixel) {
165             case 8: *current_pixel = (char)(destpixel & 0xFF); break;
166             case 16: *((uint16_t*)current_pixel) = (uint16_t)destpixel; break;
167             case 24: {
168                 int offset = (int)current_pixel & 0x3;
169                 uint64_t dest = ((uint64_t)destpixel) << (8 * offset);
170                 uint64_t mask = ((uint64_t)0xffffff) << (8 * offset);
171                 uint64_t* base = (uint64_t*)(current_pixel - offset);
172                 *base = (*base & ~mask) | dest;
173                 break;
174             }
175             case 32: *((uint32_t*)current_pixel) = destpixel; break;
176             default: org::ibex::Platform::criticalAbort(JvNewStringLatin1("ERROR: bpp not a multiple of 8!"));
177             }
178         }
179     }
180     
181     if (shared_pixmap) {
182         // do nothing, we wrote directly to video memory
183         
184     } else if (shm_supported) {
185         XShmPutImage(display, (*((Pixmap*)pm)), (*((GC*)gc)), xi, 0, 0, cx1, cy1, cx2 - cx1, cy2 - cy1, False);
186         XDestroyImage(xi);
187         
188     } else {
189         XPutImage(display, (*((Pixmap*)pm)), (*((GC*)gc)), xi, 0, 0, cx1, cy1, cx2 - cx1, cy2 - cy1);
190         
191     }
192 }
193
194 void org::ibex::plat::X11$X11PixelBuffer::finalize() {
195     if (shared_pixmap) {
196         XShmSegmentInfo *sinfo = (XShmSegmentInfo*)shm_segment;
197         XShmDetach(display, sinfo);
198         shmdt(sinfo->shmaddr);
199         shmctl(sinfo->shmid, IPC_RMID, 0);
200         XDestroyImage((XImage*)fake_ximage);
201         free(sinfo);
202     }
203     if (stipple) {
204         XFreePixmap(display, *((Pixmap*)stipple));
205         free(stipple);
206     }
207     XFreePixmap(display, *((Pixmap*)pm));
208     XFreeGC(display, *((GC*)gc));
209     XFreeGC(display, *((GC*)clipped_gc));
210 }
211
212 void org::ibex::plat::X11$X11PixelBuffer::natInit() {
213     
214     if (width == 0 || height == 0) return;
215     shared_pixmap &= shm_supported & shm_pixmaps_supported; // refuse to use shared pixmaps if we don't have shm
216     pm = (gnu::gcj::RawData*)malloc(sizeof(Pixmap));
217
218     if (!shared_pixmap)
219         (*((Pixmap*)pm)) = XCreatePixmap(display, RootWindow(display, screen_num), width, height, colorDepth);
220     else {
221         XShmSegmentInfo *sinfo = (XShmSegmentInfo*)malloc(sizeof(XShmSegmentInfo));
222         shm_segment = (gnu::gcj::RawData*)sinfo;
223         ((XImage*)fake_ximage) = XShmCreateImage(display, visual, colorDepth, ZPixmap, NULL, sinfo, width, height);
224         sinfo->shmid = shmget(IPC_PRIVATE, ((XImage*)fake_ximage)->bytes_per_line * height, IPC_CREAT | 0777 | IPC_EXCL);
225         ((XImage*)fake_ximage)->data = sinfo->shmaddr = (char*)shmat(sinfo->shmid, 0, 0);
226         sinfo->readOnly = False;
227         XShmAttach(display, sinfo);
228         XSync(display, False);
229         shmctl(sinfo->shmid, IPC_RMID, 0);
230         (*((Pixmap*)pm)) = XShmCreatePixmap(display, RootWindow(display, screen_num), sinfo->shmaddr, sinfo, width, height, colorDepth);
231         XSync(display, False);
232     }
233
234     gc = (gnu::gcj::RawData*)malloc(sizeof(GC));
235     clipped_gc = (gnu::gcj::RawData*)malloc(sizeof(GC));
236     (*((GC*)gc)) = XCreateGC(display, (*((Pixmap*)pm)), 0, 0);
237     (*((GC*)clipped_gc)) = XCreateGC(display, (*((Pixmap*)pm)), 0, 0);
238     
239     XGCValues vm;
240     vm.graphics_exposures = 0;
241     XChangeGC(display, (*((GC*)gc)), GCGraphicsExposures, &vm);
242     XChangeGC(display, (*((GC*)clipped_gc)), GCGraphicsExposures, &vm);
243 }    
244
245 void org::ibex::plat::X11$X11PixelBuffer::createStipple(org::ibex::plat::X11$X11Picture* xpi) {
246
247     stipple = (gnu::gcj::RawData*)malloc(sizeof(Pixmap));
248     (*((Pixmap*)stipple)) = XCreatePixmap(display, RootWindow(display, screen_num), width, height, 1);
249
250     XImage xi;
251     xi.data = (char*)malloc((width + 1) * height);
252     xi.width = width;
253     xi.height = height;
254     xi.xoffset = 0;
255     xi.format = ZPixmap;
256     xi.bitmap_pad = 8;
257     xi.bitmap_unit = 8;
258     xi.byte_order = LSBFirst;
259     xi.depth = 1;
260     xi.bytes_per_line = (width / 8) + 1;
261     xi.bits_per_pixel = 1;
262     
263     jint* d = (jint*)elements(xpi->data);
264     memset(xi.data, 0xFF, (width + 1) * height);
265     for(int x=0; x<width; x++)
266         for (int y=0; y<height; y++)
267             xi.data[y * xi.bytes_per_line + (x/8)] &= ~(((d[x + y * width] & 0xFF000000) != 0 ? 0 : 1) << (x % 8));
268
269     GC stipple_gc = XCreateGC(display, (*((Pixmap*)stipple)), 0, 0);
270
271     XGCValues vm;
272     vm.graphics_exposures = 0;
273     XChangeGC(display, stipple_gc, GCGraphicsExposures, &vm);
274
275     XPutImage(display, (*((Pixmap*)stipple)), stipple_gc, &xi, 0, 0, 0, 0, width, height);
276 }
277
278 void org::ibex::plat::X11$X11Surface::blit(org::ibex::PixelBuffer* db, jint sx, jint sy, jint dx, jint dy, jint dx2, jint dy2) {
279     org::ibex::plat::X11$X11PixelBuffer *xdb = (org::ibex::plat::X11$X11PixelBuffer*)db;
280     XCopyArea(display, *((Pixmap*)xdb->pm), *((Window*)window), *((GC*)gc), sx, sy, dx2 - dx, dy2 - dy, dx, dy);
281     XFlush(display);
282 }
283
284 void org::ibex::plat::X11$X11PixelBuffer::fillRect (jint x, jint y, jint x2, jint y2, jint argb) {
285     
286     jint w = x2 - x;
287     jint h = y2 - y;
288
289     if (x < clipx) { w -= (clipx - x); x = clipx; }
290     if (y < clipy) { h -= (clipy - y); y = clipy; }
291     if (x + w > clipx + clipw) w = (clipx + clipw - x);
292     if (y + h > clipy + cliph) h = (cliph + clipy - y);
293
294     XSetForeground(display, (*((GC*)gc)),
295                    ((((argb & 0x00FF0000) >> 16) * colormap_info->red_max) / 0xFF) * colormap_info->red_mult + 
296                    ((((argb & 0x0000FF00) >> 8) * colormap_info->green_max) / 0xFF) * colormap_info->green_mult + 
297                    ((((argb & 0x000000FF)) * colormap_info->blue_max) / 0xFF) * colormap_info->blue_mult +
298                    colormap_info->base_pixel
299                    );
300     
301     XFillRectangle(display, (*((Pixmap*)pm)), (*((GC*)gc)), x, y, w, h);
302 }
303
304
305 // X11Surface //////////////////////////////////////////////////////////////////////
306
307 void org::ibex::plat::X11$X11Surface::setIcon(org::ibex::Picture* pic) {
308     org::ibex::plat::X11$X11Picture* p = ((org::ibex::plat::X11$X11Picture*)pic);
309     org::ibex::plat::X11$X11PixelBuffer* old_dbuf = p->doublebuf;
310     p->buildPixelBuffer(1);
311     XWMHints xwmh;
312     memset(&xwmh, 0, sizeof(XWMHints));
313     xwmh.flags |= IconPixmapHint | IconMaskHint;
314     xwmh.icon_pixmap = *((Pixmap*)p->doublebuf->pm);
315     xwmh.icon_mask = *((Pixmap*)p->doublebuf->stipple);
316     XSetWMHints(display, (*((Window*)window)), &xwmh);
317     p->doublebuf = old_dbuf;
318 }
319
320 void org::ibex::plat::X11$X11Surface::setTitleBarText(java::lang::String* s) {
321     int len = min(JvGetStringUTFLength(s), 1024);
322     char buf[len + 1];
323     JvGetStringUTFRegion(s, 0, len, buf);
324     buf[len] = '\0';
325     
326     XTextProperty tp;
327     tp.value = (unsigned char*)buf;
328     tp.nitems = len;
329     tp.encoding = XA_STRING;
330     tp.format = 8;
331     XSetTextProperty(display, (*((Window*)window)), &tp, XA_WM_NAME);
332     XSetTextProperty(display, (*((Window*)window)), &tp, XA_WM_ICON_NAME);
333 }
334
335 void org::ibex::plat::X11$X11Surface::setLimits(jint minw, jint minh, jint maxw, jint maxh) {
336     XSizeHints hints;
337     hints.min_width = minw;
338     hints.min_height = minh;
339     hints.max_width = maxw;
340     hints.max_height = maxh;
341     hints.flags = PMinSize | PMaxSize;
342     XSetWMNormalHints(display, (*((Window*)window)), &hints);
343 }
344
345 void org::ibex::plat::X11$X11Surface::_setSize (jint width, jint height) {
346     if (width <= 0 || height <= 0) return;
347     XResizeWindow(display, (*((Window*)window)), width, height);
348     XFlush(display);
349 }
350
351 void org::ibex::plat::X11$X11Surface::setLocation () { XMoveWindow(display, (*((Window*)window)), root->x, root->y); }
352 void org::ibex::plat::X11$X11Surface::toFront() { XRaiseWindow(display, (*((Window*)window))); }
353 void org::ibex::plat::X11$X11Surface::toBack() { XLowerWindow(display, (*((Window*)window))); }
354
355 void org::ibex::plat::X11$X11Surface::_dispose() {
356     // without this we get phantom messages after the window is gone
357     org::ibex::plat::X11::windowToSurfaceMap->remove(new java::lang::Long(*((Window*)window)));
358     XDestroyWindow(display, (*((Window*)window)));
359 }
360
361 void org::ibex::plat::X11$X11Surface::setInvisible(jboolean i) {
362     if (i) XUnmapWindow(display, (*((Window*)window)));
363     else XMapRaised(display, (*((Window*)window)));
364     XFlush(display);
365 }
366
367 void org::ibex::plat::X11$X11Surface::_setMinimized(jboolean b) {
368     if (b) XIconifyWindow(display, (*((Window*)window)), screen_num);
369     else XMapRaised(display, (*((Window*)window)));
370     XFlush(display);
371 }
372
373 void org::ibex::plat::X11$X11Surface::natInit() {
374     XSetWindowAttributes xswa;
375     window = (gnu::gcj::RawData*)malloc(sizeof(Window));
376     xswa.bit_gravity = NorthWestGravity;
377     xswa.colormap = s_colormap;
378     xswa.event_mask = ExposureMask | ButtonPressMask | StructureNotifyMask |
379         KeyPressMask | KeyReleaseMask | ButtonPressMask |
380         ButtonReleaseMask | EnterWindowMask | LeaveWindowMask |
381         PointerMotionMask | ButtonMotionMask | ConfigureNotify | FocusChangeMask;
382     *((Window*)window) = XCreateWindow(display, RootWindow(display, screen_num), 10, 10, 10, 10, 0,
383                                        colorDepth, InputOutput, CopyFromParent,
384                                        CWColormap | CWBitGravity | CWEventMask, &xswa);
385     
386     if (!framed) {
387         // I don't know why this works....
388         int dat[5] = { 0x2, 0xbffff804, 0x0, 0x817f560, 0x8110694 };
389         XChangeProperty(display, (*((Window*)window)),
390                         XInternAtom(display, "_MOTIF_WM_HINTS", False),
391                         XInternAtom(display, "_MOTIF_WM_HINTS", False),
392                         32, 
393                         PropModeReplace,
394                         (unsigned char*)dat,
395                         5);
396     }
397     
398     XTextProperty tp;
399     tp.value = (unsigned char*)"Ibex";
400     tp.nitems = 3;
401     tp.encoding = XA_STRING;
402     tp.format = 8;
403     XSetTextProperty(display, (*((Window*)window)), &tp, XA_WM_CLASS);
404     
405     Atom proto = XInternAtom(display, "WM_DELETE_WINDOW", False);
406     XSetWMProtocols(display, (*((Window*)window)), &proto, 1);
407     
408     XSelectInput(display, (*((Window*)window)), StructureNotifyMask);
409     org::ibex::plat::X11::windowToSurfaceMap->put(new java::lang::Long(*((Window*)window)), this);
410
411     XEvent e;
412     XMapRaised(display, (*((Window*)window)));
413     XFlush(display);
414
415     waitForCreation->block();
416     XSelectInput(display, (*((Window*)window)), xswa.event_mask);
417     XFlush(display);
418
419     gc = (gnu::gcj::RawData*)malloc(sizeof(GC));
420     *((GC*)gc) = XCreateGC(display, (*((Window*)window)), 0, 0);
421     
422     XGCValues vm;
423     vm.graphics_exposures = 0;
424     XChangeGC(display, *((GC*)gc), GCGraphicsExposures, &vm);
425 }
426
427
428 void org::ibex::plat::X11$X11Surface::dispatchEvent(gnu::gcj::RawData* ev) {
429
430     XEvent* e = (XEvent*)ev;
431     if (e->type == Expose) {
432         XExposeEvent *expose = (XExposeEvent*)(e);
433         Dirty(expose->x, expose->y, expose->width, expose->height);
434         
435     } else if (e->type == MapNotify) { Minimized(0); waitForCreation->release();
436     } else if (e->type == UnmapNotify) { Minimized(1);
437     } else if (e->type == FocusIn) { Focused(1);
438     } else if (e->type == FocusOut) { Focused(0);
439     } else if (e->type == ClientMessage) {
440         if (((XClientMessageEvent*)(e))->data.l[0] == XInternAtom(display, "WM_DELETE_WINDOW", False)) Close();
441     
442     } else if (e->type == KeyPress || e->type == KeyRelease) {
443         XKeyEvent *xbe = (XKeyEvent*)(e);
444         
445         // drop faked KeyRelease events generated by the X server's autorepeat
446         if (e->type == KeyRelease) {
447             char depressed[32];
448             XQueryKeymap(display, depressed);
449             if ((depressed[(xbe->keycode & 0xff) / 8] & (0x1 << (xbe->keycode % 8))) >> (xbe->keycode % 8)) return;
450         }
451         
452         char ss[20];
453         char* s = ss;
454         
455         unsigned int savestate = xbe->state;
456         xbe->state = xbe->state & ShiftMask;      // ignore everything except shiftmask
457         XLookupString(xbe, s, 20, NULL, NULL);
458         xbe->state = savestate;
459         
460         if (s != NULL && s[0] != '\0' && s[1] == '\0' && s[0] >= 0x20 && s[0] <= 0x7E) {
461             int i = s[0];
462             
463         } else {
464             KeySym ks = XKeycodeToKeysym(display, xbe->keycode, 0);
465             switch (ks) {
466             case XK_BackSpace: s = "back_space"; break;
467             case XK_Tab: s = "tab"; break;
468             case XK_Linefeed: s = "enter"; break;
469             case XK_Return: s = "enter"; break;
470             case XK_Scroll_Lock: s = "scroll_lock"; break;
471             case XK_Escape: s = "escape"; break;
472             case XK_Insert: s = "insert"; break;
473             case XK_Delete: s = "delete"; break;
474             case XK_Home: s = "home"; break;
475             case XK_Left: s = "left"; break;
476             case XK_Up: s = "up"; break;
477             case XK_Right: s = "right"; break;
478             case XK_Down: s = "down"; break;
479             case XK_Page_Up: s = "page_up"; break;
480             case XK_Page_Down: s = "page_down"; break;
481             case XK_End: s = "end"; break;
482             case XK_Num_Lock: s = "num_lock"; break;
483             case XK_KP_Tab: s = "tab"; break;
484             case XK_KP_Enter: s = "enter"; break;
485             case XK_KP_F1: s = "f1"; break;
486             case XK_KP_F2: s = "f2"; break;
487             case XK_KP_F3: s = "f3"; break;
488             case XK_KP_F4: s = "f4"; break;
489             case XK_KP_Home: s = "home"; break;
490             case XK_KP_Left: s = "left"; break;
491             case XK_KP_Up: s = "up"; break;
492             case XK_KP_Right: s = "right"; break;
493             case XK_KP_Down: s = "down"; break;
494             case XK_KP_Page_Up: s = "page_up"; break;
495             case XK_KP_Page_Down: s = "page_down"; break;
496             case XK_KP_End: s = "end"; break;
497             case XK_KP_Insert: s = "insert"; break;
498             case XK_KP_Delete: s = "delete"; break;
499             case XK_F1: s = "f1"; break;
500             case XK_F2: s = "f2"; break;
501             case XK_F3: s = "f3"; break;
502             case XK_F4: s = "f4"; break;
503             case XK_F5: s = "f5"; break;
504             case XK_F6: s = "f6"; break;
505             case XK_F7: s = "f7"; break;
506             case XK_F8: s = "f8"; break;
507             case XK_F9: s = "f9"; break;
508             case XK_F10: s = "f10"; break;
509             case XK_F11: s = "f11"; break;
510             case XK_F12: s = "f12"; break;
511             case XK_Shift_L: s = "shift"; break;
512             case XK_Shift_R: s = "shift"; break;
513             case XK_Control_L: s = "control"; break;
514             case XK_Control_R: s = "control"; break;
515             case XK_Meta_L: s = "alt"; break;
516             case XK_Meta_R: s = "alt"; break;
517             case XK_Alt_L: s = "alt"; break;
518             case XK_Alt_R: s = "alt"; break;
519             default: return;
520             }
521         }
522         
523         jstring s2 = JvNewStringLatin1(s);
524         if (e->type == KeyPress) KeyPressed((xbe->state & LockMask) ? s2->toUpperCase() : s2);
525         if (e->type == KeyRelease) KeyReleased(s2);
526         
527     } else if (e->type == ButtonPress) {
528         XButtonEvent* xbe = (XButtonEvent*)(e);
529         switch(xbe->button) {
530           case 4: VScroll((jfloat)-1.0); return;
531           case 5: VScroll((jfloat)1.0); return;
532           case 6: HScroll((jfloat)-1.0); return;
533           case 7: HScroll((jfloat)1.0); return;
534         }
535         if (xbe->button == 2) xbe->button = 3;
536         else if (xbe->button == 3) xbe->button = 2;
537         Press(xbe->button);
538         
539     } else if (e->type == ButtonRelease) {
540         XButtonEvent* xbe = (XButtonEvent*)(e);
541         if (xbe->button == 2) xbe->button = 3;
542         else if (xbe->button == 3) xbe->button = 2;
543         Release(xbe->button);
544         
545     } else if (e->type == MotionNotify) {
546         XMotionEvent* xme = (XMotionEvent*)(e);
547         Move(xme->x, xme->y);
548         
549     } else if (e->type == EnterNotify || e->type == LeaveNotify) {
550         XCrossingEvent* xce = (XCrossingEvent*)(e);
551         Move(xce->x, xce->y);
552         
553     } else if (e->type == ConfigureNotify) {
554         Window child;
555         int x_out, y_out;
556         XConfigureEvent* xce = (XConfigureEvent*)(e);
557         XTranslateCoordinates(display, (*((Window*)window)), RootWindow(display, screen_num), 0, 0, &x_out, &y_out, &child);
558         if (xce->width != root->width || xce->height != root->height) SizeChange(xce->width, xce->height);
559         if (x_out != root->x || y_out != root->y) PosChange(x_out, y_out);
560         
561     }
562 }
563
564 static jstring crosshair, east, hand, move, north, northeast, northwest,
565     south, southeast, southwest, text, west, wait_string;
566 static Cursor crosshair_cursor, east_cursor, hand_cursor, move_cursor, north_cursor,
567     northeast_cursor, northwest_cursor, south_cursor, southeast_cursor,
568     southwest_cursor, text_cursor, west_cursor, wait_cursor, default_cursor;
569
570 void org::ibex::plat::X11$X11Surface::syncCursor() {
571     
572     Cursor curs;
573     if (cursor->equals(crosshair)) curs = crosshair_cursor;
574     else if (cursor->equals(east)) curs = east_cursor;
575     else if (cursor->equals(hand)) curs = hand_cursor;
576     else if (cursor->equals(move)) curs = move_cursor;
577     else if (cursor->equals(north)) curs = north_cursor;
578     else if (cursor->equals(northeast)) curs = northeast_cursor;
579     else if (cursor->equals(northwest)) curs = northwest_cursor;
580     else if (cursor->equals(south)) curs = south_cursor;
581     else if (cursor->equals(southeast)) curs = southeast_cursor;
582     else if (cursor->equals(southwest)) curs = southwest_cursor;
583     else if (cursor->equals(text)) curs = text_cursor;
584     else if (cursor->equals(west)) curs = west_cursor;
585     else if (cursor->equals(wait_string)) curs = wait_cursor;
586     else curs = default_cursor;
587     
588     XDefineCursor(display, (*((Window*)window)), curs);
589 }
590
591
592
593 // X11 ///////////////////////////////////////////////////////////////////
594
595 jint org::ibex::plat::X11::_getScreenWidth() { return WidthOfScreen(DefaultScreenOfDisplay(display)); }
596 jint org::ibex::plat::X11::_getScreenHeight() { return HeightOfScreen(DefaultScreenOfDisplay(display)); }
597
598 static void dispatchSelectionEvent(XEvent* e) {
599     if (e->type == SelectionNotify) {
600         XSelectionEvent* xsn = (XSelectionEvent*)(e);
601         if (xsn->property == None) org::ibex::plat::X11::clipboard = JvNewStringLatin1("", 0);
602         else {
603             Atom returntype;
604             int returnformat;
605             unsigned long numitems;
606             unsigned char* ret;
607             unsigned long bytes_after;
608             XGetWindowProperty(display, xsn->requestor, xsn->property, 0, 4096,
609                                True, AnyPropertyType, &returntype, &returnformat,
610                                &numitems, &bytes_after, &ret);
611             org::ibex::plat::X11::clipboard =
612                 (returntype == None ? JvNewStringLatin1("", 0) : JvNewStringLatin1((char*)ret, strlen((char*)ret)));
613         }
614         org::ibex::plat::X11::waiting_for_selection_event->release();
615         
616     } else if (e->type == SelectionRequest) {
617         XSelectionRequestEvent* xsr = (XSelectionRequestEvent*)(e);
618         XSelectionEvent xsn;
619         xsn.type = SelectionNotify;
620         xsn.serial = xsr->serial;
621         xsn.send_event = True;
622         xsn.display = display;
623         xsn.requestor = xsr->requestor;
624         xsn.selection = xsr->selection;
625         xsn.target = xsr->target;
626         xsn.property = xsr->property;
627         xsn.time = xsr->time;
628         
629         int len = min(1024, JvGetStringUTFLength(org::ibex::plat::X11::clipboard));
630         char buf[len + 1];
631         JvGetStringUTFRegion(org::ibex::plat::X11::clipboard, 0, len, buf);
632         buf[len] = '\0';
633         
634         XChangeProperty(display, xsr->requestor, xsr->property, xsr->target, 8, PropModeReplace, (unsigned char*)buf, len + 1);
635         XSendEvent(display, xsr->requestor, True, 0, (XEvent*)(&xsn));
636     }        
637 }
638
639 void org::ibex::plat::X11::eventThread() {
640     XEvent e;
641     while(true) {
642         XNextEvent(display, &e);
643         if (e.type == SelectionNotify || e.type == SelectionRequest) {
644             dispatchSelectionEvent(&e);
645         } else {
646             org::ibex::plat::X11$X11Surface* surface =
647                 (org::ibex::plat::X11$X11Surface*)windowToSurfaceMap->get(new java::lang::Long(((XAnyEvent*)&e)->window));
648             if (surface != NULL) surface->dispatchEvent((gnu::gcj::RawData*)&e);
649         }
650     }
651 }
652
653 jstring org::ibex::plat::X11::_getClipBoard() {
654     XConvertSelection(display, XA_PRIMARY, XA_STRING, XInternAtom(display, "VT_SELECTION", False), selectionWindow, CurrentTime);
655     XFlush(display);
656     org::ibex::plat::X11::waiting_for_selection_event->block();
657     return clipboard;
658 }
659
660 void org::ibex::plat::X11::_setClipBoard(jstring s) {
661     clipboard = s;
662     int len = JvGetStringUTFLength(clipboard);
663     char buf[len + 1];
664     JvGetStringUTFRegion(clipboard, 0, len, buf);
665     buf[len] = '\0';
666     XSetSelectionOwner(display, XInternAtom(display, "PRIMARY", 0), selectionWindow, CurrentTime);
667 }
668
669 typedef int (X11ErrorHandler)(Display*, XErrorEvent*);
670 int errorHandler(Display* d, XErrorEvent* e) {
671     // this error handler is only installed during the initial
672     // test to see if shm is present
673     shm_supported = 0;
674 }
675
676 void org::ibex::plat::X11::natInit() {
677
678     if (!XInitThreads())
679         org::ibex::Platform::criticalAbort(JvNewStringLatin1("Your X11 libraries do not support multithreaded programs"));
680
681     char* DISPLAY = getenv("DISPLAY");
682     if (DISPLAY == NULL || strlen(DISPLAY) == 0) DISPLAY = ":0.0";
683     display = XOpenDisplay(DISPLAY);
684
685     if (display == 0)
686         org::ibex::Platform::criticalAbort(JvNewStringLatin1("Unable to connect to X11 display server"));
687
688     screen_num = XDefaultScreen(display);
689     colorDepth = (jint)(DefaultDepth(((Display*)display), 0));
690     shm_info.shmaddr = NULL;
691
692     // FIXME: SHM doesn't work on Darwin
693     //shm_supported = (XShmQueryExtension(display) == True);
694     if (shm_supported) {
695         X11ErrorHandler* oldHandler = XSetErrorHandler(errorHandler);
696         XShmSegmentInfo sinfo;
697         sinfo.shmid = shmget(IPC_PRIVATE, 1, IPC_CREAT | 0777 | IPC_EXCL);
698         sinfo.readOnly = False;
699         // if the server is remote, this will trigger the error handler
700         XShmAttach(display, &sinfo);
701         XSync(display, False);
702         XSetErrorHandler(oldHandler);
703     }
704
705     if (shm_supported)
706         shm_pixmaps_supported = (XShmPixmapFormat(display) == ZPixmap);
707     
708     crosshair = JvNewStringLatin1("crosshair");
709     east = JvNewStringLatin1("east");
710     hand = JvNewStringLatin1("hand");
711     move = JvNewStringLatin1("move");
712     north = JvNewStringLatin1("north");
713     northeast = JvNewStringLatin1("northeast");
714     northwest = JvNewStringLatin1("northwest");
715     south = JvNewStringLatin1("south");
716     southeast = JvNewStringLatin1("southeast");
717     southwest = JvNewStringLatin1("southwest");
718     text = JvNewStringLatin1("text");
719     west = JvNewStringLatin1("west");
720     wait_string = JvNewStringLatin1("wait");
721     crosshair_cursor = XCreateFontCursor(display, XC_tcross);
722     east_cursor = XCreateFontCursor(display, XC_right_side);
723     hand_cursor = XCreateFontCursor(display, XC_hand2);
724     move_cursor = XCreateFontCursor(display, XC_fleur);
725     north_cursor = XCreateFontCursor(display, XC_top_side);
726     northeast_cursor = XCreateFontCursor(display, XC_top_right_corner);
727     northwest_cursor = XCreateFontCursor(display, XC_left_side);
728     south_cursor = XCreateFontCursor(display, XC_bottom_side);
729     southeast_cursor = XCreateFontCursor(display, XC_bottom_right_corner);
730     southwest_cursor = XCreateFontCursor(display, XC_bottom_left_corner);
731     text_cursor = XCreateFontCursor(display, XC_xterm);
732     west_cursor = XCreateFontCursor(display, XC_right_side);
733     wait_cursor = XCreateFontCursor(display, XC_watch);
734     default_cursor = XCreateFontCursor(display, XC_left_ptr);
735
736     selectionWindow = XCreateWindow(display, RootWindow(display, screen_num), 0, 0, 1, 1, 0, colorDepth, InputOutput, CopyFromParent, 0, NULL);
737     visual = DefaultVisual(display, screen_num);
738     char buf[255];
739     sprintf(buf, "X11 DISPLAY: %s", XDisplayString(display));
740     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
741     sprintf(buf, "X11 SHM:     %s", shm_supported ? "enabled" : "disabled");
742     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
743     sprintf(buf, "X11 Visual:  %x %x %x bits: %i visualid: %i depth: %i",
744             visual->red_mask, visual->green_mask, visual->blue_mask, visual->bits_per_rgb, visual->visualid, colorDepth);
745     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
746
747     // FIXME: don't know why (True, False) is the best solution...
748     if(XmuLookupStandardColormap(display, screen_num, visual->visualid, colorDepth, XA_RGB_BEST_MAP, True, False) == 0)
749         org::ibex::Platform::criticalAbort(JvNewStringLatin1("ERROR: XmuLookupStandardColormap failed"));
750     
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::Platform::criticalAbort(JvNewStringLatin1("ERROR: couldn't allocate a standard colormap"));
755     if (!best_map_info->colormap)
756         org::ibex::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::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 }
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