propagated renaming fixes to .cc files
[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 <X11/Xlib.h>
5 #include <X11/extensions/XShm.h>
6 #include <X11/keysymdef.h>
7 #include <X11/keysym.h>
8 #include <X11/cursorfont.h>
9 #include <X11/Xutil.h>
10 #include <X11/Xatom.h>
11 #include <X11/Xmu/StdCmap.h>
12
13 #include <java/lang/String.h>
14 #include <org/ibex/graphics/Surface.h>
15 #include <org/ibex/graphics/Picture.h>
16 #include <org/ibex/core/Box.h>
17 #include <org/ibex/plat/X11.h>
18 #include <org/ibex/plat/X11$X11Surface.h>
19 #include <org/ibex/plat/X11$X11Picture.h>
20 #include <org/ibex/plat/X11$X11PixelBuffer.h>
21 #include <org/ibex/util/Semaphore.h>
22 #include <org/ibex/plat/Platform.h>
23 #include <java/lang/Long.h>
24 #include <java/util/Hashtable.h>
25 #include <org/ibex/util/Log.h>
26
27 #include <java/lang/System.h>
28 #include <java/io/PrintStream.h>
29
30 #include "POSIX.cc"
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::graphics::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::graphics::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::plat::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::plat::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::graphics::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::graphics::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 = 4;
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::plat::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::plat::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::plat::Platform::criticalAbort(JvNewStringLatin1("ERROR: XmuLookupStandardColormap failed"));
750     XStandardColormap* best_map_info = NULL;
751     int count;
752     if (XGetRGBColormaps(display, RootWindow(display, screen_num), &best_map_info, &count, XA_RGB_BEST_MAP) == 0)
753         org::ibex::plat::Platform::criticalAbort(JvNewStringLatin1("ERROR: couldn't allocate a standard colormap"));
754     if (!best_map_info->colormap)
755         org::ibex::plat::Platform::criticalAbort(JvNewStringLatin1("ERROR: XmuLookupStandardColomap succeded, but no colormap was found on the root window"));
756     if (best_map_info->red_max == 0)
757         org::ibex::plat::Platform::criticalAbort(JvNewStringLatin1("ERROR: standard colormap exists, but was improperly allocated"));
758     s_colormap = best_map_info->colormap;
759     colormap_info = best_map_info;
760
761     sprintf(buf, "            red_max / red_mult: %x %x", colormap_info->red_max, colormap_info->red_mult);
762     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
763     sprintf(buf, "            green_max / green_mult: %x %x", colormap_info->green_max, colormap_info->green_mult);
764     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
765     sprintf(buf, "            blue_max / blue_mult: %x %x", colormap_info->blue_max, colormap_info->blue_mult);
766     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
767     sprintf(buf, "            base_pixel: %x", colormap_info->base_pixel);
768     org::ibex::util::Log::info(this->getClass(), JvNewStringLatin1(buf));
769 }
770
771 #include "WINGs/WINGs.h"
772 jstring org::ibex::plat::X11::_fileDialog(jstring suggestedFileName, jboolean write) {
773   int argc = 1;
774   char* argv[2];
775   argv[0] = "Ibex";
776   argv[1] = NULL;
777   // FIXME see WINGs/Tests/filedialog.c for more info... need an icon
778   WMInitializeApplication("Ibex", &argc, argv);
779   WMScreen *scr = WMCreateSimpleApplicationScreen(display);
780   int len = min(1024, JvGetStringUTFLength(suggestedFileName));
781   char buf[len + 1];
782   JvGetStringUTFRegion(suggestedFileName, 0, len, buf);
783   buf[len] = '\0';
784   if (write) {
785     WMSavePanel *sPanel;
786     sPanel = WMGetSavePanel(scr);
787     if (WMRunModalFilePanelForDirectory(sPanel, NULL, buf, /*title*/ NULL, NULL) != True) return NULL;
788     return JvNewStringLatin1(WMGetFilePanelFileName(sPanel));
789   } else {
790     WMOpenPanel *oPanel;
791     oPanel = WMGetOpenPanel(scr);
792     if (WMRunModalFilePanelForDirectory(oPanel, NULL, buf, /*title*/ NULL, NULL) != True) return NULL;
793     return JvNewStringLatin1(WMGetFilePanelFileName(oPanel));
794   }
795   return NULL;
796 }
797
798 //////////////////////////////////////////////////////////////////////////////
799 //////////////////////////////////////////////////////////////////////////////
800 //////////////////////////////////////////////////////////////////////////////
801 //////////////////////////////////////////////////////////////////////////////
802 //                                                                          //
803 // Everything below this point was taken, cut-and-paste, from the           //
804 // source for libXmu. It implements the official 'standard colormap         //
805 // creation algorithm.  I made some small changes to                        //
806 // XmuDeleteStandardColormap                                                //
807 //                                                                          //
808 //////////////////////////////////////////////////////////////////////////////
809 //////////////////////////////////////////////////////////////////////////////
810 //////////////////////////////////////////////////////////////////////////////
811 //////////////////////////////////////////////////////////////////////////////
812
813 /* $Xorg: LookupCmap.c,v 1.4 2001/02/09 02:03:53 xorgcvs Exp $ */
814
815 /* 
816  
817 Copyright 1989, 1998  The Open Group
818
819 Permission to use, copy, modify, distribute, and sell this software and its
820 documentation for any purpose is hereby granted without fee, provided that
821 the above copyright notice appear in all copies and that both that
822 copyright notice and this permission notice appear in supporting
823 documentation.
824
825 The above copyright notice and this permission notice shall be included in
826 all copies or substantial portions of the Software.
827
828 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
829 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
830 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
831 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
832 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
833 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
834
835 Except as contained in this notice, the name of The Open Group shall not be
836 used in advertising or otherwise to promote the sale, use or other dealings
837 in this Software without prior written authorization from The Open Group.
838
839 */
840 /* $XFree86: xc/lib/Xmu/LookupCmap.c,v 1.8 2001/12/14 19:55:47 dawes Exp $ */
841
842 /*
843  * Author:  Donna Converse, MIT X Consortium
844  */
845
846 #include <stdio.h>
847 #include <X11/Xlib.h>
848 #include <X11/Xatom.h>
849 #include <X11/Xutil.h>
850 #include <X11/Xmu/StdCmap.h>
851 #include <stdlib.h>
852
853 /*
854  * Prototypes
855  */
856 static Status lookup(Display*, int, VisualID, Atom, XStandardColormap*, Bool);
857
858 /*
859  * To create a standard colormap if one does not currently exist, or
860  * replace the currently existing standard colormap, use 
861  * XmuLookupStandardColormap().
862  *
863  * Given a screen, a visual, and a property, XmuLookupStandardColormap()
864  * will determine the best allocation for the property under the specified
865  * visual, and determine the whether to create a new colormap or to use
866  * the default colormap of the screen.  It will call XmuStandardColormap()
867  * to create the standard colormap.
868  *
869  * If replace is true, any previous definition of the property will be 
870  * replaced.  If retain is true, the property and the colormap will be
871  * made permanent for the duration of the server session.  However,
872  * pre-existing property definitions which are not replaced cannot be made
873  * permanent by a call to XmuLookupStandardColormap(); a request to retain 
874  * resources pertains to newly created resources.
875  *
876  * Returns 0 on failure, non-zero on success.  A request to create a 
877  * standard colormap upon a visual which cannot support such a map is
878  * considered a failure.  An example of this would be requesting any
879  * standard colormap property on a monochrome visual, or, requesting an
880  * RGB_BEST_MAP on a display whose colormap size is 16.
881  */
882
883 Status
884 XmuLookupStandardColormap(Display *dpy, int screen, VisualID visualid,
885                           unsigned int depth, Atom property,
886                           Bool replace, Bool retain)
887      /*
888       * dpy             - specifies X server connection
889       * screen          - specifies screen of display
890       * visualid        - specifies the visual type
891       * depth           - specifies  the visual type
892       * property        - a standard colormap property
893       * replace         - specifies whether to replace
894       * retain          - specifies whether to retain
895       */
896 {
897     Display             *odpy;          /* original display connection */
898     XStandardColormap   *colormap;      
899     XVisualInfo         vinfo_template, *vinfo; /* visual */
900     long                vinfo_mask;
901     unsigned long       r_max, g_max, b_max;    /* allocation */
902     int                 count;  
903     Colormap            cmap;                   /* colormap ID */
904     Status              status = 0;
905
906
907     /* Match the requested visual */
908
909     vinfo_template.visualid = visualid; 
910     vinfo_template.screen = screen;
911     vinfo_template.depth = depth;
912     vinfo_mask = VisualIDMask | VisualScreenMask | VisualDepthMask;
913     if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &count)) ==
914         NULL)
915         return 0;
916
917     /* Monochrome visuals have no standard maps */
918
919     if (vinfo->colormap_size <= 2) {
920         XFree((char *) vinfo);
921         return 0;       
922     }
923
924     /* If the requested property already exists on this screen, and, 
925      * if the replace flag has not been set to true, return success.
926      * lookup() will remove a pre-existing map if replace is true.
927      */
928
929     if (lookup(dpy, screen, visualid, property, (XStandardColormap *) NULL,
930                replace) && !replace) {
931         XFree((char *) vinfo);
932         return 1;
933     }
934
935     /* Determine the best allocation for this property under the requested
936      * visualid and depth, and determine whether or not to use the default
937      * colormap of the screen.
938      */
939
940     if (!XmuGetColormapAllocation(vinfo, property, &r_max, &g_max, &b_max)) {
941         XFree((char *) vinfo);
942         return 0;
943     }
944
945     cmap = (property == XA_RGB_DEFAULT_MAP &&
946             visualid == XVisualIDFromVisual(DefaultVisual(dpy, screen)))
947         ? DefaultColormap(dpy, screen) : None;
948
949     /* If retaining resources, open a new connection to the same server */
950
951     if (retain) {
952         odpy = dpy;
953         if ((dpy = XOpenDisplay(XDisplayString(odpy))) == NULL) {
954             XFree((char *) vinfo);
955             return 0;
956         }
957     }
958
959     /* Create the standard colormap */
960
961     colormap = XmuStandardColormap(dpy, screen, visualid, depth, property,
962                                    cmap, r_max, g_max, b_max);
963
964     /* Set the standard colormap property */
965
966     if (colormap) {
967         XGrabServer(dpy);
968
969         if (lookup(dpy, screen, visualid, property, colormap, replace) &&
970             !replace) {
971             /* Someone has defined the property since we last looked.
972              * Since we will not replace it, release our own resources.
973              * If this is the default map, our allocations will be freed 
974              * when this connection closes.
975              */
976             if (colormap->killid == ReleaseByFreeingColormap)
977             XFreeColormap(dpy, colormap->colormap);
978         } else if (retain) {
979                 XSetCloseDownMode(dpy, RetainPermanent);
980         }
981         XUngrabServer(dpy);
982         XFree((char *) colormap);
983         status = 1;
984     }
985
986     if (retain)
987         XCloseDisplay(dpy);
988     XFree((char *) vinfo);
989     return status;
990 }
991
992 /***************************************************************************/
993
994 /* Lookup a standard colormap property.  If the property is RGB_DEFAULT_MAP,
995  * the visualid is used to determine whether the indicated standard colormap
996  * exists.  If the map exists and replace is true, delete the resources used
997  * by the map and remove the property.  Return true if the map exists,
998  * or did exist and was deleted; return false if the map was not found.
999  *
1000  * Note that this is not the way that a Status return is normally used.
1001  *
1002  * If new is not NULL, new points to an XStandardColormap structure which
1003  * describes a standard colormap of the specified property.  It will be made
1004  * a standard colormap of the screen if none already exists, or if replace 
1005  * is true.
1006  */
1007
1008 static Status
1009 lookup(Display *dpy, int screen, VisualID visualid, Atom property,
1010        XStandardColormap *cnew, Bool replace)
1011      /*
1012       * dpy             - specifies display connection
1013       * screen          - specifies screen number
1014       * visualid        - specifies visualid for std map
1015       * property        - specifies colormap property name
1016       * cnew            - specifies a standard colormap
1017       * replace         - specifies whether to replace
1018       */
1019 {
1020     register int        i;
1021     int                 count;
1022     XStandardColormap   *stdcmaps, *s;
1023     Window              win = RootWindow(dpy, screen);
1024
1025     /* The property does not already exist */
1026
1027     if (! XGetRGBColormaps(dpy, win, &stdcmaps, &count, property)) {
1028         if (cnew)
1029             XSetRGBColormaps(dpy, win, cnew, 1, property);
1030         return 0;
1031     }
1032
1033     /* The property exists and is not describing the RGB_DEFAULT_MAP */
1034
1035     if (property != XA_RGB_DEFAULT_MAP) {
1036         if (replace) {
1037             XmuDeleteStandardColormap(dpy, screen, property);
1038             if (cnew)
1039                 XSetRGBColormaps(dpy, win, cnew, 1, property);
1040         }
1041         XFree((char *)stdcmaps);
1042         return 1;
1043     }
1044
1045     /* The property exists and is RGB_DEFAULT_MAP */
1046     
1047     for (i=0, s=stdcmaps; (i < count) && (s->visualid != visualid); i++, s++)
1048         ;
1049
1050     /* No RGB_DEFAULT_MAP property matches the given visualid */
1051
1052     if (i == count) {
1053         if (cnew) {
1054             XStandardColormap   *m, *maps;
1055
1056             s = (XStandardColormap *) malloc((unsigned) ((count+1) * sizeof
1057                                               (XStandardColormap)));
1058
1059             for (i = 0, m = s, maps = stdcmaps; i < count; i++, m++, maps++) {
1060                 m->colormap   = maps->colormap;
1061                 m->red_max    = maps->red_max;
1062                 m->red_mult   = maps->red_mult;
1063                 m->green_max  = maps->green_max;
1064                 m->green_mult = maps->green_mult;
1065                 m->blue_max   = maps->blue_max;
1066                 m->blue_mult  = maps->blue_mult;
1067                 m->base_pixel = maps->base_pixel;
1068                 m->visualid   = maps->visualid;
1069                 m->killid     = maps->killid;
1070             }
1071             m->colormap   = cnew->colormap;
1072             m->red_max    = cnew->red_max;
1073             m->red_mult   = cnew->red_mult;
1074             m->green_max  = cnew->green_max;
1075             m->green_mult = cnew->green_mult;
1076             m->blue_max   = cnew->blue_max;
1077             m->blue_mult  = cnew->blue_mult;
1078             m->base_pixel = cnew->base_pixel;
1079             m->visualid   = cnew->visualid;
1080             m->killid     = cnew->killid;
1081
1082             XSetRGBColormaps(dpy, win, s, ++count, property);
1083             free((char *) s);
1084         }
1085         XFree((char *) stdcmaps);
1086         return 0;
1087     }
1088
1089     /* Found an RGB_DEFAULT_MAP property with a matching visualid */
1090
1091     if (replace) {
1092         /* Free old resources first - we may need them, particularly in 
1093          * the default colormap of the screen.  However, because of this,
1094          * it is possible that we will destroy the old resource and fail 
1095          * to create a new one if XmuStandardColormap() fails.
1096          */
1097
1098         if (count == 1) {
1099             XmuDeleteStandardColormap(dpy, screen, property);
1100             if (cnew)
1101                 XSetRGBColormaps(dpy, win, cnew, 1, property);
1102         }
1103         else {
1104             XStandardColormap   *map;
1105
1106             /* s still points to the matching standard colormap */
1107
1108             if (s->killid == ReleaseByFreeingColormap) {
1109                 if ((s->colormap != None) &&
1110                     (s->colormap != DefaultColormap(dpy, screen)))
1111                     XFreeColormap(dpy, s->colormap);
1112             }
1113             else if (s->killid != None)
1114                 XKillClient(dpy, s->killid);
1115
1116             map = (cnew) ? cnew : stdcmaps + --count;
1117
1118             s->colormap   = map->colormap;
1119             s->red_max    = map->red_max;
1120             s->red_mult   = map->red_mult;
1121             s->green_max  = map->green_max;
1122             s->green_mult = map->green_mult;
1123             s->blue_max   = map->blue_max;
1124             s->blue_mult  = map->blue_mult;
1125             s->visualid   = map->visualid;
1126             s->killid     = map->killid;
1127
1128             XSetRGBColormaps(dpy, win, stdcmaps, count, property);
1129         }
1130     }
1131     XFree((char *) stdcmaps);
1132     return 1;
1133 }
1134
1135 /* $Xorg: CmapAlloc.c,v 1.4 2001/02/09 02:03:51 xorgcvs Exp $ */
1136
1137 /* 
1138
1139 Copyright 1989, 1994, 1998  The Open Group
1140
1141 Permission to use, copy, modify, distribute, and sell this software and its
1142 documentation for any purpose is hereby granted without fee, provided that
1143 the above copyright notice appear in all copies and that both that
1144 copyright notice and this permission notice appear in supporting
1145 documentation.
1146
1147 The above copyright notice and this permission notice shall be included in
1148 all copies or substantial portions of the Software.
1149
1150 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1151 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1152 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1153 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1154 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1155 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1156
1157 Except as contained in this notice, the name of The Open Group shall not be
1158 used in advertising or otherwise to promote the sale, use or other dealings
1159 in this Software without prior written authorization from The Open Group.
1160
1161 */
1162 /* $XFree86: xc/lib/Xmu/CmapAlloc.c,v 1.7 2001/12/14 19:55:35 dawes Exp $ */
1163
1164 /*
1165  * Author:  Donna Converse, MIT X Consortium
1166  */
1167
1168 #include <X11/Xlib.h>
1169 #include <X11/Xatom.h>
1170 #include <X11/Xutil.h>
1171 #include <X11/Xmu/StdCmap.h>
1172 #include <stdio.h>
1173
1174 #define lowbit(x) ((x) & (~(x) + 1))
1175
1176 /*
1177  * Prototypes
1178  */
1179 static void best_allocation(XVisualInfo*, unsigned long*, unsigned long*,
1180                             unsigned long*);
1181 static int default_allocation(XVisualInfo*, unsigned long*,
1182                               unsigned long*, unsigned long*);
1183 static void gray_allocation(int, unsigned long*, unsigned long*,
1184                             unsigned long*);
1185 static int icbrt(int);
1186 static int icbrt_with_bits(int, int);
1187 static int icbrt_with_guess(int, int);
1188
1189 /* To determine the best allocation of reds, greens, and blues in a 
1190  * standard colormap, use XmuGetColormapAllocation.
1191  *      vinfo           specifies visual information for a chosen visual
1192  *      property        specifies one of the standard colormap property names
1193  *      red_max         returns maximum red value 
1194  *      green_max       returns maximum green value
1195  *      blue_max        returns maximum blue value
1196  *
1197  * XmuGetColormapAllocation returns 0 on failure, non-zero on success.
1198  * It is assumed that the visual is appropriate for the colormap property.
1199  */
1200
1201 Status
1202 XmuGetColormapAllocation(XVisualInfo *vinfo, Atom property,
1203                          unsigned long *red_max,
1204                          unsigned long *green_max,
1205                          unsigned long *blue_max)
1206 {
1207     Status      status = 1;
1208
1209     if (vinfo->colormap_size <= 2)
1210         return 0;
1211
1212     switch (property)
1213     {
1214       case XA_RGB_DEFAULT_MAP:
1215         status = default_allocation(vinfo, red_max, green_max, blue_max);
1216         break;
1217       case XA_RGB_BEST_MAP:
1218         best_allocation(vinfo, red_max, green_max, blue_max);
1219         break;
1220       case XA_RGB_GRAY_MAP:
1221         gray_allocation(vinfo->colormap_size, red_max, green_max, blue_max);
1222         break;
1223       case XA_RGB_RED_MAP:
1224         *red_max = vinfo->colormap_size - 1;
1225         *green_max = *blue_max = 0;
1226         break;
1227       case XA_RGB_GREEN_MAP:
1228         *green_max = vinfo->colormap_size - 1;
1229         *red_max = *blue_max = 0;
1230         break;
1231       case XA_RGB_BLUE_MAP:
1232         *blue_max = vinfo->colormap_size - 1;
1233         *red_max = *green_max = 0;
1234         break;
1235       default:
1236         status = 0;
1237     }
1238     return status;
1239 }
1240
1241 /****************************************************************************/
1242 /* Determine the appropriate color allocations of a gray scale.
1243  *
1244  * Keith Packard, MIT X Consortium
1245  */
1246
1247 static void
1248 gray_allocation(int n, unsigned long *red_max, unsigned long *green_max,
1249                 unsigned long *blue_max)
1250 {
1251     *red_max = (n * 30) / 100;
1252     *green_max = (n * 59) / 100; 
1253     *blue_max = (n * 11) / 100; 
1254     *green_max += ((n - 1) - (*red_max + *green_max + *blue_max));
1255 }
1256
1257 /****************************************************************************/
1258 /* Determine an appropriate color allocation for the RGB_DEFAULT_MAP.
1259  * If a map has less than a minimum number of definable entries, we do not
1260  * produce an allocation for an RGB_DEFAULT_MAP.  
1261  *
1262  * For 16 planes, the default colormap will have 27 each RGB; for 12 planes,
1263  * 12 each.  For 8 planes, let n = the number of colormap entries, which may
1264  * be 256 or 254.  Then, maximum red value = floor(cube_root(n - 125)) - 1.
1265  * Maximum green and maximum blue values are identical to maximum red.
1266  * This leaves at least 125 cells which clients can allocate.
1267  *
1268  * Return 0 if an allocation has been determined, non-zero otherwise.
1269  */
1270
1271 static int
1272 default_allocation(XVisualInfo *vinfo, unsigned long *red,
1273                    unsigned long *green, unsigned long *blue)
1274 {
1275     int                 ngrays;         /* number of gray cells */
1276
1277     switch (vinfo->c_class)
1278       {
1279       case PseudoColor:
1280         
1281         if (vinfo->colormap_size > 65000)
1282           /* intended for displays with 16 planes */
1283           *red = *green = *blue = (unsigned long) 27;
1284         else if (vinfo->colormap_size > 4000)
1285           /* intended for displays with 12 planes */
1286             *red = *green = *blue = (unsigned long) 12;
1287       else if (vinfo->colormap_size < 250)
1288             return 0;
1289       else
1290             /* intended for displays with 8 planes */
1291             *red = *green = *blue = (unsigned long)
1292           (icbrt(vinfo->colormap_size - 125) - 1);
1293       break;
1294       
1295     case DirectColor:
1296       
1297         if (vinfo->colormap_size < 10)
1298             return 0;
1299         *red = *green = *blue = vinfo->colormap_size / 2 - 1;
1300         break;
1301
1302       case TrueColor:
1303
1304         *red = vinfo->red_mask / lowbit(vinfo->red_mask);
1305         *green = vinfo->green_mask / lowbit(vinfo->green_mask);
1306         *blue = vinfo->blue_mask / lowbit(vinfo->blue_mask);
1307         break;
1308
1309       case GrayScale:
1310
1311         if (vinfo->colormap_size > 65000)
1312             ngrays = 4096;
1313         else if (vinfo->colormap_size > 4000)
1314             ngrays = 512;
1315         else if (vinfo->colormap_size < 250)
1316             return 0;
1317         else
1318             ngrays = 12;
1319         gray_allocation(ngrays, red, green, blue);
1320         break;
1321         
1322       default:
1323         return 0;
1324     }
1325     return 1;
1326 }
1327
1328 /****************************************************************************/
1329 /* Determine an appropriate color allocation for the RGB_BEST_MAP.
1330  *
1331  * For a DirectColor or TrueColor visual, the allocation is determined
1332  * by the red_mask, green_mask, and blue_mask members of the visual info.
1333  *
1334  * Otherwise, if the colormap size is an integral power of 2, determine
1335  * the allocation according to the number of bits given to each color,
1336  * with green getting more than red, and red more than blue, if there
1337  * are to be inequities in the distribution.  If the colormap size is
1338  * not an integral power of 2, let n = the number of colormap entries.
1339  * Then maximum red value = floor(cube_root(n)) - 1;
1340  *      maximum blue value = floor(cube_root(n)) - 1;
1341  *      maximum green value = n / ((# red values) * (# blue values)) - 1;
1342  * Which, on a GPX, allows for 252 entries in the best map, out of 254
1343  * defineable colormap entries.
1344  */
1345  
1346 static void
1347 best_allocation(XVisualInfo *vinfo, unsigned long *red, unsigned long *green,
1348                 unsigned long *blue)
1349 {
1350
1351     if (vinfo->c_class == DirectColor ||        vinfo->c_class == TrueColor)
1352     {
1353         *red = vinfo->red_mask;
1354         while ((*red & 01) == 0)
1355             *red >>= 1;
1356         *green = vinfo->green_mask;
1357         while ((*green & 01) == 0)
1358             *green >>=1;
1359         *blue = vinfo->blue_mask;
1360         while ((*blue & 01) == 0)
1361             *blue >>= 1;
1362     }
1363     else
1364     {
1365         register int bits, n;
1366         
1367         /* Determine n such that n is the least integral power of 2 which is
1368          * greater than or equal to the number of entries in the colormap.
1369          */
1370         n = 1;
1371         bits = 0;
1372         while (vinfo->colormap_size > n)
1373         {
1374             n = n << 1;
1375             bits++;
1376         }
1377         
1378         /* If the number of entries in the colormap is a power of 2, determine
1379          * the allocation by "dealing" the bits, first to green, then red, then
1380          * blue.  If not, find the maximum integral red, green, and blue values
1381          * which, when multiplied together, do not exceed the number of 
1382
1383          * colormap entries.
1384          */
1385         if (n == vinfo->colormap_size)
1386         {
1387             register int r, g, b;
1388             b = bits / 3;
1389             g = b + ((bits % 3) ? 1 : 0);
1390             r = b + (((bits % 3) == 2) ? 1 : 0);
1391             *red = 1 << r;
1392             *green = 1 << g;
1393             *blue = 1 << b;
1394         }
1395         else
1396         {
1397             *red = icbrt_with_bits(vinfo->colormap_size, bits);
1398             *blue = *red;       
1399             *green = (vinfo->colormap_size / ((*red) * (*blue)));
1400         }
1401         (*red)--;
1402         (*green)--;
1403         (*blue)--;
1404     }
1405     return;
1406 }
1407
1408 /*
1409  * integer cube roots by Newton's method
1410  *
1411  * Stephen Gildea, MIT X Consortium, July 1991
1412  */
1413
1414 static int
1415 icbrt(int a)
1416 {
1417     register int bits = 0;
1418     register unsigned n = a;
1419
1420     while (n)
1421     {
1422         bits++;
1423         n >>= 1;
1424     }
1425     return icbrt_with_bits(a, bits);
1426 }
1427
1428
1429 static int
1430 icbrt_with_bits(int a, int bits)
1431      /* bits - log 2 of a */
1432 {
1433     return icbrt_with_guess(a, a>>2*bits/3);
1434 }
1435
1436 #ifdef _X_ROOT_STATS
1437 int icbrt_loopcount;
1438 #endif
1439
1440 /* Newton's Method:  x_n+1 = x_n - ( f(x_n) / f'(x_n) ) */
1441
1442 /* for cube roots, x^3 - a = 0,  x_new = x - 1/3 (x - a/x^2) */
1443
1444 /*
1445  * Quick and dirty cube roots.  Nothing fancy here, just Newton's method.
1446  * Only works for positive integers (since that's all we need).
1447  * We actually return floor(cbrt(a)) because that's what we need here, too.
1448  */
1449
1450 static int
1451 icbrt_with_guess(int a, int guess)
1452 {
1453     register int delta;
1454
1455 #ifdef _X_ROOT_STATS
1456     icbrt_loopcount = 0;
1457 #endif
1458     if (a <= 0)
1459         return 0;
1460     if (guess < 1)
1461         guess = 1;
1462
1463     do {
1464 #ifdef _X_ROOT_STATS
1465         icbrt_loopcount++;
1466 #endif
1467         delta = (guess - a/(guess*guess))/3;
1468 #ifdef DEBUG
1469         printf("pass %d: guess=%d, delta=%d\n", icbrt_loopcount, guess, delta);
1470 #endif
1471         guess -= delta;
1472     } while (delta != 0);
1473
1474     if (guess*guess*guess > a)
1475         guess--;
1476
1477     return guess;
1478 }
1479
1480
1481 /* $Xorg: StdCmap.c,v 1.4 2001/02/09 02:03:53 xorgcvs Exp $ */
1482
1483 /* 
1484
1485 Copyright 1989, 1998  The Open Group
1486
1487 Permission to use, copy, modify, distribute, and sell this software and its
1488 documentation for any purpose is hereby granted without fee, provided that
1489 the above copyright notice appear in all copies and that both that
1490 copyright notice and this permission notice appear in supporting
1491 documentation.
1492
1493 The above copyright notice and this permission notice shall be included in
1494 all copies or substantial portions of the Software.
1495
1496 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1497 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1498 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1499 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1500 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1501 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1502
1503 Except as contained in this notice, the name of The Open Group shall not be
1504 used in advertising or otherwise to promote the sale, use or other dealings
1505 in this Software without prior written authorization from The Open Group.
1506
1507 */
1508 /* $XFree86: xc/lib/Xmu/StdCmap.c,v 1.6 2001/12/14 19:55:48 dawes Exp $ */
1509
1510 /*
1511  * Author:  Donna Converse, MIT X Consortium
1512  */
1513
1514 #include <stdio.h>
1515 #include <X11/Xlib.h>
1516 #include <X11/Xatom.h>
1517 #include <X11/Xutil.h>
1518 #include <X11/Xmu/StdCmap.h>
1519
1520 #define lowbit(x) ((x) & (~(x) + 1))
1521
1522 /*
1523  * Prototypes
1524  */
1525 /* argument restrictions */
1526 static Status valid_args(XVisualInfo*, unsigned long, unsigned long,
1527                          unsigned long, Atom);
1528
1529 /*
1530  * To create any one standard colormap, use XmuStandardColormap().
1531  *
1532  * Create a standard colormap for the given screen, visualid, and visual
1533  * depth, with the given red, green, and blue maximum values, with the
1534  * given standard property name.  Return a pointer to an XStandardColormap
1535  * structure which describes the newly created colormap, upon success.
1536  * Upon failure, return NULL.
1537  * 
1538  * XmuStandardColormap() calls XmuCreateColormap() to create the map.
1539  *
1540  * Resources created by this function are not made permanent; that is the
1541  * caller's responsibility.
1542  */
1543
1544 XStandardColormap *
1545 XmuStandardColormap(Display *dpy, int screen, VisualID visualid,
1546                     unsigned int depth, Atom property, Colormap cmap,
1547                     unsigned long red_max, unsigned long green_max,
1548                     unsigned long blue_max)
1549      /*
1550       * dpy                             - specifies X server connection
1551       * screen                          - specifies display screen
1552       * visualid                        - identifies the visual type
1553       * depth                           - identifies the visual type
1554       * property                        - a standard colormap property
1555       * cmap                            - specifies colormap ID or None
1556       * red_max, green_max, blue_max    - allocations
1557       */
1558 {
1559     XStandardColormap   *stdcmap;
1560     Status              status;
1561     XVisualInfo         vinfo_template, *vinfo;
1562     long                vinfo_mask;
1563     int                 n;
1564
1565     /* Match the required visual information to an actual visual */
1566     vinfo_template.visualid = visualid; 
1567     vinfo_template.screen = screen;
1568     vinfo_template.depth = depth;
1569     vinfo_mask = VisualIDMask | VisualScreenMask | VisualDepthMask;
1570     if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &n)) == NULL)
1571         return 0;
1572
1573     /* Check the validity of the combination of visual characteristics,
1574      * allocation, and colormap property.  Create an XStandardColormap
1575      * structure.
1576      */
1577
1578     if (! valid_args(vinfo, red_max, green_max, blue_max, property)
1579         || ((stdcmap = XAllocStandardColormap()) == NULL)) {
1580         XFree((char *) vinfo);
1581         return 0;
1582     }
1583
1584     /* Fill in the XStandardColormap structure */
1585
1586     if (cmap == DefaultColormap(dpy, screen)) {
1587         /* Allocating out of the default map, cannot use XFreeColormap() */
1588         Window win = XCreateWindow(dpy, RootWindow(dpy, screen), 1, 1, 1, 1,
1589                                    0, 0, InputOnly, vinfo->visual,
1590                                    (unsigned long) 0,
1591                                    (XSetWindowAttributes *)NULL);
1592         stdcmap->killid  = (XID) XCreatePixmap(dpy, win, 1, 1, depth);
1593         XDestroyWindow(dpy, win);
1594         stdcmap->colormap = cmap;
1595     } else {
1596         stdcmap->killid = ReleaseByFreeingColormap;
1597         stdcmap->colormap = XCreateColormap(dpy, RootWindow(dpy, screen),
1598                                             vinfo->visual, AllocNone);
1599     }
1600     stdcmap->red_max = red_max;
1601     stdcmap->green_max = green_max;
1602     stdcmap->blue_max = blue_max;
1603     if (property == XA_RGB_GRAY_MAP) 
1604         stdcmap->red_mult = stdcmap->green_mult = stdcmap->blue_mult = 1;
1605     else if (vinfo->c_class == TrueColor || vinfo->c_class == DirectColor) {
1606         stdcmap->red_mult = lowbit(vinfo->red_mask);
1607         stdcmap->green_mult = lowbit(vinfo->green_mask);
1608         stdcmap->blue_mult = lowbit(vinfo->blue_mask);
1609     } else {
1610         stdcmap->red_mult = (red_max > 0)
1611             ? (green_max + 1) * (blue_max + 1) : 0;
1612         stdcmap->green_mult = (green_max > 0) ? blue_max + 1 : 0;
1613         stdcmap->blue_mult = (blue_max > 0) ? 1 : 0;
1614     }
1615     stdcmap->base_pixel = 0;                    /* base pixel may change */
1616     stdcmap->visualid = vinfo->visualid;
1617
1618     /* Make the colormap */
1619
1620     status = XmuCreateColormap(dpy, stdcmap);
1621
1622     /* Clean up */
1623
1624     XFree((char *) vinfo);
1625     if (!status) {
1626
1627         /* Free the colormap or the pixmap, if we created one */
1628         if (stdcmap->killid == ReleaseByFreeingColormap)
1629             XFreeColormap(dpy, stdcmap->colormap);
1630         else if (stdcmap->killid != None)
1631             XFreePixmap(dpy, stdcmap->killid);
1632         
1633         XFree((char *) stdcmap);
1634         return (XStandardColormap *) NULL;
1635     }
1636     return stdcmap;
1637 }
1638
1639 /****************************************************************************/
1640 static Status
1641 valid_args(XVisualInfo *vinfo, unsigned long red_max, unsigned long green_max,
1642            unsigned long blue_max, Atom property)
1643      /*
1644       * vinfo                           - specifies visual
1645       * red_max, green_max, blue_max    - specifies alloc
1646       * property                        - specifies property name
1647       */
1648 {
1649     unsigned long       ncolors;        /* number of colors requested */
1650
1651     /* Determine that the number of colors requested is <= map size */
1652
1653     if ((vinfo->c_class == DirectColor) || (vinfo->c_class == TrueColor)) {
1654         unsigned long mask;
1655
1656         mask = vinfo->red_mask;
1657         while (!(mask & 1))
1658             mask >>= 1;
1659         if (red_max > mask)
1660             return 0;
1661         mask = vinfo->green_mask;
1662         while (!(mask & 1))
1663             mask >>= 1;
1664         if (green_max > mask)
1665             return 0;
1666         mask = vinfo->blue_mask;
1667         while (!(mask & 1))
1668             mask >>= 1;
1669         if (blue_max > mask)
1670             return 0;
1671     } else if (property == XA_RGB_GRAY_MAP) {
1672         ncolors = red_max + green_max + blue_max + 1;
1673         if (ncolors > vinfo->colormap_size)
1674             return 0;
1675     } else {
1676         ncolors = (red_max + 1) * (green_max + 1) * (blue_max + 1);
1677         if (ncolors > vinfo->colormap_size)
1678             return 0;
1679     }
1680     
1681     /* Determine that the allocation and visual make sense for the property */
1682
1683     switch (property)
1684     {
1685       case XA_RGB_DEFAULT_MAP:
1686         if (red_max == 0 || green_max == 0 || blue_max == 0)
1687             return 0;
1688         break;
1689       case XA_RGB_RED_MAP:
1690         if (red_max == 0)
1691             return 0;
1692         break;
1693       case XA_RGB_GREEN_MAP:
1694         if (green_max == 0)
1695             return 0;
1696         break;
1697       case XA_RGB_BLUE_MAP:     
1698         if (blue_max == 0)
1699             return 0;
1700         break;
1701       case XA_RGB_BEST_MAP:
1702         if (red_max == 0 || green_max == 0 || blue_max == 0)
1703             return 0;
1704         break;
1705       case XA_RGB_GRAY_MAP:
1706         if (red_max == 0 || blue_max == 0 || green_max == 0)
1707             return 0;
1708         break;
1709       default:
1710         return 0;
1711     }
1712     return 1;
1713 }
1714
1715
1716 /* $Xorg: CrCmap.c,v 1.4 2001/02/09 02:03:51 xorgcvs Exp $ */
1717
1718 /* 
1719
1720 Copyright 1989, 1998  The Open Group
1721
1722 Permission to use, copy, modify, distribute, and sell this software and its
1723 documentation for any purpose is hereby granted without fee, provided that
1724 the above copyright notice appear in all copies and that both that
1725 copyright notice and this permission notice appear in supporting
1726 documentation.
1727
1728 The above copyright notice and this permission notice shall be included in
1729 all copies or substantial portions of the Software.
1730
1731 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1732 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1733 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1734 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1735 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1736 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1737
1738 Except as contained in this notice, the name of The Open Group shall not be
1739 used in advertising or otherwise to promote the sale, use or other dealings
1740 in this Software without prior written authorization from The Open Group.
1741
1742 */
1743 /* $XFree86: xc/lib/Xmu/CrCmap.c,v 3.7 2001/12/14 19:55:36 dawes Exp $ */
1744
1745 /*
1746  * Author:  Donna Converse, MIT X Consortium
1747  */
1748
1749 /*
1750  * CreateCmap.c - given a standard colormap description, make the map.
1751  */
1752
1753 #include <stdio.h>
1754 #include <stdlib.h>
1755 #include <X11/Xlib.h>
1756 #include <X11/Xutil.h>
1757 #include <X11/Xmu/StdCmap.h>
1758
1759 /*
1760  * Prototypes
1761  */
1762 /* allocate entire map Read Only */
1763 static int ROmap(Display*, Colormap, unsigned long[], int, int);
1764
1765 /* allocate a cell, prefer Read Only */
1766 static Status ROorRWcell(Display*, Colormap, unsigned long[], int,
1767                          XColor*, unsigned long);
1768
1769 /* allocate a cell Read Write */
1770 static Status RWcell(Display*, Colormap, XColor*, XColor*, unsigned long*);
1771
1772 /* for quicksort */
1773 static int compare(_Xconst void*, _Xconst void*);
1774
1775 /* find contiguous sequence of cells */
1776 static Status contiguous(unsigned long[], int, int, unsigned long, int*, int*);
1777
1778 /* frees resources before quitting */
1779 static void free_cells(Display*, Colormap, unsigned long[], int, int);
1780
1781 /* create a map in a RO visual type */
1782 static Status readonly_map(Display*, XVisualInfo*, XStandardColormap*);
1783
1784 /* create a map in a RW visual type */
1785 static Status readwrite_map(Display*, XVisualInfo*, XStandardColormap*);
1786
1787 #define lowbit(x) ((x) & (~(x) + 1))
1788 #define TRUEMATCH(mult,max,mask) \
1789     (colormap->max * colormap->mult <= vinfo->mask && \
1790      lowbit(vinfo->mask) == colormap->mult)
1791
1792 /*
1793  * To create any one colormap which is described by an XStandardColormap
1794  * structure, use XmuCreateColormap().
1795  *
1796  * Return 0 on failure, non-zero on success.
1797  * Resources created by this function are not made permanent.
1798  * No argument error checking is provided.  Use at your own risk.
1799  *
1800  * All colormaps are created with read only allocations, with the exception
1801  * of read only allocations of colors in the default map or otherwise
1802  * which fail to return the expected pixel value, and these are individually 
1803  * defined as read/write allocations.  This is done so that all the cells
1804  * defined in the default map are contiguous, for use in image processing.
1805  * This typically happens with White and Black in the default map.
1806  *
1807  * Colormaps of static visuals are considered to be successfully created if
1808  * the map of the static visual matches the definition given in the
1809  * standard colormap structure.
1810  */
1811    
1812 Status
1813 XmuCreateColormap(Display *dpy, XStandardColormap *colormap)
1814      /* dpy      - specifies the connection under which the map is created
1815       * colormap - specifies the map to be created, and returns, particularly
1816       *            if the map is created as a subset of the default colormap
1817       *            of the screen, the base_pixel of the map.
1818                                          */
1819 {
1820     XVisualInfo         vinfo_template; /* template visual information */
1821     XVisualInfo         *vinfo;         /* matching visual information */
1822     XVisualInfo         *vpointer;      /* for freeing the entire list */
1823     long                vinfo_mask;     /* specifies the visual mask value */
1824     int                 n;              /* number of matching visuals */
1825     int                 status;         
1826
1827     vinfo_template.visualid = colormap->visualid;
1828     vinfo_mask = VisualIDMask;
1829     if ((vinfo = XGetVisualInfo(dpy, vinfo_mask, &vinfo_template, &n)) == NULL)
1830         return 0;
1831
1832     /* A visual id may be valid on multiple screens.  Also, there may 
1833      * be multiple visuals with identical visual ids at different depths.  
1834      * If the colormap is the Default Colormap, use the Default Visual.
1835      * Otherwise, arbitrarily, use the deepest visual.
1836      */
1837     vpointer = vinfo;
1838     if (n > 1)
1839     {
1840         register int    i;
1841         register int    screen_number;
1842         Bool            def_cmap;
1843
1844         def_cmap = False;
1845         for (screen_number = ScreenCount(dpy); --screen_number >= 0; )
1846             if (colormap->colormap == DefaultColormap(dpy, screen_number)) {
1847                 def_cmap = True;
1848                 break;
1849             }
1850
1851         if (def_cmap) {
1852             for (i=0; i < n; i++, vinfo++) {
1853                 if (vinfo->visual == DefaultVisual(dpy, screen_number))
1854                         break;
1855             }
1856         } else {
1857             int                 maxdepth = 0;
1858             XVisualInfo         *v = NULL;
1859
1860             for (i=0; i < n; i++, vinfo++)
1861                 if (vinfo->depth > maxdepth) {
1862                     maxdepth = vinfo->depth;
1863                     v = vinfo;
1864                 }
1865             vinfo = v;
1866         }
1867     }
1868
1869     if (vinfo->c_class == PseudoColor || vinfo->c_class == DirectColor ||
1870         vinfo->c_class == GrayScale)
1871         status = readwrite_map(dpy, vinfo, colormap);
1872     else if (vinfo->c_class == TrueColor)
1873         status = TRUEMATCH(red_mult, red_max, red_mask) &&
1874                  TRUEMATCH(green_mult, green_max, green_mask) &&
1875                  TRUEMATCH(blue_mult, blue_max, blue_mask);
1876     else 
1877         status = readonly_map(dpy, vinfo, colormap);
1878     
1879     XFree((char *) vpointer);
1880     return status;
1881 }
1882
1883 /****************************************************************************/
1884 static Status
1885 readwrite_map(Display *dpy, XVisualInfo *vinfo, XStandardColormap *colormap)
1886 {
1887     register unsigned long i, n;        /* index counters */
1888     unsigned long       ncolors;        /* number of colors to be defined */
1889     int                 npixels;        /* number of pixels allocated R/W */
1890     int                 first_index;    /* first index of pixels to use */
1891     int                 remainder;      /* first index of remainder */
1892     XColor              color;          /* the definition of a color */
1893     unsigned long       *pixels;        /* array of colormap pixels */
1894     unsigned long       delta;
1895
1896     
1897     /* Determine ncolors, the number of colors to be defined.
1898      * Insure that 1 < ncolors <= the colormap size.
1899      */
1900     if (vinfo->c_class == DirectColor) {
1901         ncolors = colormap->red_max;
1902         if (colormap->green_max > ncolors)
1903             ncolors = colormap->green_max;
1904         if (colormap->blue_max > ncolors)
1905             ncolors = colormap->blue_max;
1906         ncolors++;
1907         delta = lowbit(vinfo->red_mask) +
1908                 lowbit(vinfo->green_mask) +
1909                 lowbit(vinfo->blue_mask);
1910     } else {
1911         ncolors = colormap->red_max * colormap->red_mult +
1912                   colormap->green_max * colormap->green_mult +
1913                   colormap->blue_max * colormap->blue_mult + 1;
1914         delta = 1;
1915     }
1916     if (ncolors <= 1 || (int) ncolors > vinfo->colormap_size)   return 0;
1917
1918     /* Allocate Read/Write as much of the colormap as we can possibly get.
1919      * Then insure that the pixels we were allocated are given in 
1920      * monotonically increasing order, using a quicksort.  Next, insure
1921      * that our allocation includes a subset of contiguous pixels at least
1922      * as long as the number of colors to be defined.  Now we know that 
1923      * these conditions are met:
1924      *  1) There are no free cells in the colormap.
1925      *  2) We have a contiguous sequence of pixels, monotonically 
1926      *     increasing, of length >= the number of colors requested.
1927      *
1928      * One cell at a time, we will free, compute the next color value, 
1929      * then allocate read only.  This takes a long time.
1930      * This is done to insure that cells are allocated read only in the
1931      * contiguous order which we prefer.  If the server has a choice of
1932      * cells to grant to an allocation request, the server may give us any
1933      * cell, so that is why we do these slow gymnastics.
1934      */
1935
1936     if ((pixels = (unsigned long *) calloc((unsigned) vinfo->colormap_size,
1937                                       sizeof(unsigned long))) == NULL)
1938         return 0;
1939
1940     if ((npixels = ROmap(dpy, colormap->colormap, pixels,
1941                            vinfo->colormap_size, ncolors)) == 0) {
1942         free((char *) pixels);
1943         return 0;
1944     }
1945
1946     qsort((char *) pixels, npixels, sizeof(unsigned long), compare);
1947
1948     if (!contiguous(pixels, npixels, ncolors, delta, &first_index, &remainder))
1949     {
1950         /* can't find enough contiguous cells, give up */
1951         XFreeColors(dpy, colormap->colormap, pixels, npixels,
1952                     (unsigned long) 0);
1953         free((char *) pixels);
1954         return 0;
1955     }
1956     colormap->base_pixel = pixels[first_index];
1957
1958     /* construct a gray map */
1959     if (colormap->red_mult == 1 && colormap->green_mult == 1 &&
1960         colormap->blue_mult == 1)
1961         for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
1962         {
1963             color.pixel = n;
1964             color.blue = color.green = color.red =
1965                 (unsigned short) ((i * 65535) / (colormap->red_max +
1966                                                  colormap->green_max +
1967                                                  colormap->blue_max));
1968
1969             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
1970                              first_index + i))
1971                 return 0;
1972         }
1973
1974     /* construct a red ramp map */
1975     else if (colormap->green_max == 0 && colormap->blue_max == 0)
1976         for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
1977         {
1978             color.pixel = n;
1979             color.red = (unsigned short) ((i * 65535) / colormap->red_max);
1980             color.green = color.blue = 0;
1981
1982             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
1983                              first_index + i))
1984                 return 0;
1985         }
1986
1987     /* construct a green ramp map */
1988     else if (colormap->red_max == 0 && colormap->blue_max == 0)
1989         for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
1990         {
1991             color.pixel = n;
1992             color.green = (unsigned short) ((i * 65535) / colormap->green_max);
1993             color.red = color.blue = 0;
1994
1995             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
1996                              first_index + i))
1997                 return 0;
1998         }
1999
2000     /* construct a blue ramp map */
2001     else if (colormap->red_max == 0 && colormap->green_max == 0)
2002         for (n=colormap->base_pixel, i=0; i < ncolors; i++, n += delta)
2003         {
2004             color.pixel = n;
2005             color.blue = (unsigned short) ((i * 65535) / colormap->blue_max);
2006             color.red = color.green = 0;
2007
2008             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
2009                              first_index + i))
2010                 return 0;
2011         }
2012
2013     /* construct a standard red green blue cube map */
2014     else
2015     {
2016 #define calc(max,mult) (((n / colormap->mult) % \
2017                          (colormap->max + 1)) * 65535) / colormap->max
2018
2019         for (n=0, i=0; i < ncolors; i++, n += delta)
2020         {
2021             color.pixel = n + colormap->base_pixel;
2022             color.red = calc(red_max, red_mult);
2023             color.green = calc(green_max, green_mult);
2024             color.blue = calc(blue_max, blue_mult);
2025             if (! ROorRWcell(dpy, colormap->colormap, pixels, npixels, &color,
2026                              first_index + i))
2027                 return 0;
2028         }
2029 #undef calc
2030     }
2031     /* We have a read-only map defined.  Now free unused cells,
2032      * first those occuring before the contiguous sequence begins,
2033      * then any following the contiguous sequence.
2034      */
2035
2036     if (first_index)
2037         XFreeColors(dpy, colormap->colormap, pixels, first_index, 
2038                     (unsigned long) 0);
2039     if (remainder)
2040         XFreeColors(dpy, colormap->colormap,
2041                     &(pixels[first_index + ncolors]), remainder,
2042                     (unsigned long) 0);
2043
2044     free((char *) pixels);
2045     return 1;
2046 }
2047
2048
2049 /****************************************************************************/
2050 static int
2051 ROmap(Display *dpy, Colormap cmap, unsigned long pixels[], int m, int n)
2052      /*
2053       * dpy     - the X server connection
2054       * cmap    - specifies colormap ID
2055       * pixels  - returns pixel allocations
2056       * m       - specifies colormap size
2057       * n       - specifies number of colors
2058       */
2059 {
2060     register int        p;
2061
2062     /* first try to allocate the entire colormap */
2063     if (XAllocColorCells(dpy, cmap, 1, (unsigned long *) NULL, 
2064                          (unsigned) 0, pixels, (unsigned) m))
2065         return m;
2066
2067     /* Allocate all available cells in the colormap, using a binary
2068      * algorithm to discover how many cells we can allocate in the colormap.
2069      */
2070     m--;
2071     while (n <= m) {
2072         p = n + ((m - n + 1) / 2);
2073         if (XAllocColorCells(dpy, cmap, 1, (unsigned long *) NULL,
2074                              (unsigned) 0, pixels, (unsigned) p)) {
2075             if (p == m)
2076                 return p;
2077             else {
2078                 XFreeColors(dpy, cmap, pixels, p, (unsigned long) 0);
2079                 n = p;
2080             }
2081         }
2082         else
2083             m = p - 1;
2084     }
2085     return 0;
2086 }
2087       
2088
2089 /****************************************************************************/
2090 static Status
2091 contiguous(unsigned long pixels[], int npixels, int ncolors,
2092            unsigned long delta, int *first, int *rem)
2093      /* pixels  - specifies allocated pixels
2094       * npixels - specifies count of alloc'd pixels
2095       * ncolors - specifies needed sequence length
2096       * delta   - between pixels
2097       * first   - returns first index of sequence
2098       * rem     - returns first index after sequence, or 0, if none follow
2099       */
2100 {
2101     register int i = 1;         /* walking index into the pixel array */
2102     register int count = 1;     /* length of sequence discovered so far */
2103
2104     *first = 0;
2105     if (npixels == ncolors) {
2106         *rem = 0;
2107         return 1;
2108     }
2109     *rem = npixels - 1;
2110     while (count < ncolors && ncolors - count <= *rem)
2111     {
2112         if (pixels[i-1] + delta == pixels[i])
2113             count++;
2114         else {
2115             count = 1;
2116             *first = i;
2117         }
2118         i++;
2119         (*rem)--;
2120     }
2121     if (count != ncolors)
2122         return 0;
2123     return 1;
2124 }
2125
2126
2127 /****************************************************************************/
2128 static Status
2129 ROorRWcell(Display *dpy, Colormap cmap, unsigned long pixels[],
2130            int npixels, XColor *color, unsigned long p)
2131 {
2132     unsigned long       pixel;
2133     XColor              request;
2134
2135     /* Free the read/write allocation of one cell in the colormap.
2136      * Request a read only allocation of one cell in the colormap.
2137      * If the read only allocation cannot be granted, give up, because
2138      * there must be no free cells in the colormap.
2139      * If the read only allocation is granted, but gives us a cell which
2140      * is not the one that we just freed, it is probably the case that
2141      * we are trying allocate White or Black or some other color which
2142      * already has a read-only allocation in the map.  So we try to 
2143      * allocate the previously freed cell with a read/write allocation,
2144      * because we want contiguous cells for image processing algorithms.
2145      */
2146      
2147     pixel = color->pixel;
2148     request.red = color->red;
2149     request.green = color->green;
2150     request.blue = color->blue;
2151
2152     XFreeColors(dpy, cmap, &pixel, 1, (unsigned long) 0);
2153     if (! XAllocColor(dpy, cmap, color) 
2154         || (color->pixel != pixel &&
2155             (!RWcell(dpy, cmap, color, &request, &pixel)))) 
2156     {
2157         free_cells(dpy, cmap, pixels, npixels, (int)p);
2158         return 0;
2159     }
2160     return 1;
2161 }
2162
2163
2164 /****************************************************************************/
2165 static void
2166 free_cells(Display *dpy, Colormap cmap, unsigned long pixels[],
2167            int npixels, int p)
2168      /*
2169       * pixels  - to be freed
2170       * npixels - original number allocated
2171       */
2172 {
2173     /* One of the npixels allocated has already been freed.
2174      * p is the index of the freed pixel.
2175      * First free the pixels preceeding p, and there are p of them;
2176      * then free the pixels following p, there are npixels - p - 1 of them.
2177      */
2178     XFreeColors(dpy, cmap, pixels, p, (unsigned long) 0);
2179     XFreeColors(dpy, cmap, &(pixels[p+1]), npixels - p - 1, (unsigned long) 0);
2180     free((char *) pixels);
2181 }
2182
2183
2184 /****************************************************************************/
2185 static Status
2186 RWcell(Display *dpy, Colormap cmap, XColor *color, XColor *request,
2187        unsigned long *pixel)
2188 {
2189     unsigned long       n = *pixel;
2190
2191     XFreeColors(dpy, cmap, &(color->pixel), 1, (unsigned long)0);
2192     if (! XAllocColorCells(dpy, cmap, (Bool) 0, (unsigned long *) NULL,
2193                            (unsigned) 0, pixel, (unsigned) 1))
2194         return 0;
2195     if (*pixel != n)
2196     {
2197         XFreeColors(dpy, cmap, pixel, 1, (unsigned long) 0);
2198         return 0;
2199     }
2200     color->pixel = *pixel;
2201     color->flags = DoRed | DoGreen | DoBlue;
2202     color->red = request->red;
2203     color->green = request->green;
2204     color->blue = request->blue;
2205     XStoreColors(dpy, cmap, color, 1);
2206     return 1;
2207 }
2208
2209
2210 /****************************************************************************/
2211 static int
2212 compare(_Xconst void *e1, _Xconst void *e2)
2213 {
2214   return ((int)(*(long *)e1 - *(long *)e2));
2215 }
2216
2217
2218 /****************************************************************************/
2219 static Status
2220 readonly_map(Display *dpy, XVisualInfo *vinfo, XStandardColormap *colormap)
2221 {
2222     int                 i, last_pixel;
2223     XColor              color;
2224
2225     last_pixel = (colormap->red_max + 1) * (colormap->green_max + 1) * 
2226         (colormap->blue_max + 1) + colormap->base_pixel - 1;
2227
2228     for(i=colormap->base_pixel; i <= last_pixel; i++) {
2229
2230         color.pixel = (unsigned long) i;
2231         color.red = (unsigned short)
2232             (((i/colormap->red_mult) * 65535) / colormap->red_max);
2233
2234         if (vinfo->c_class == StaticColor) {
2235             color.green = (unsigned short)
2236                 ((((i/colormap->green_mult) % (colormap->green_max + 1)) *
2237                   65535) / colormap->green_max);
2238             color.blue = (unsigned short)
2239                 (((i%colormap->green_mult) * 65535) / colormap->blue_max);
2240         }
2241         else    /* vinfo->c_class == GrayScale, old style allocation XXX */
2242             color.green = color.blue = color.red;
2243
2244         XAllocColor(dpy, colormap->colormap, &color);
2245         if (color.pixel != (unsigned long) i)
2246             return 0;
2247     }
2248     return 1;
2249 }
2250
2251
2252 /* $Xorg: DelCmap.c,v 1.4 2001/02/09 02:03:52 xorgcvs Exp $ */
2253
2254 /* 
2255  
2256 Copyright 1989, 1998  The Open Group
2257
2258 Permission to use, copy, modify, distribute, and sell this software and its
2259 documentation for any purpose is hereby granted without fee, provided that
2260 the above copyright notice appear in all copies and that both that
2261 copyright notice and this permission notice appear in supporting
2262 documentation.
2263
2264 The above copyright notice and this permission notice shall be included in
2265 all copies or substantial portions of the Software.
2266
2267 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2268 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2269 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
2270 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
2271 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2272 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2273
2274 Except as contained in this notice, the name of The Open Group shall not be
2275 used in advertising or otherwise to promote the sale, use or other dealings
2276 in this Software without prior written authorization from The Open Group.
2277
2278 */
2279 /* $XFree86: xc/lib/Xmu/DelCmap.c,v 1.7 2001/12/14 19:55:40 dawes Exp $ */
2280
2281 /*
2282  * Author:  Donna Converse, MIT X Consortium
2283  */
2284
2285 #include <X11/Xlib.h>
2286 #include <X11/Xutil.h>
2287 #include <X11/Xmu/StdCmap.h>
2288
2289 int ignoreErrorHandler(Display* d, XErrorEvent* e) { }
2290
2291 /* To remove any standard colormap property, use XmuDeleteStandardColormap().
2292  * XmuDeleteStandardColormap() will remove the specified property from the
2293  * specified screen, releasing any resources used by the colormap(s) of the
2294  * property if possible.
2295  */
2296
2297 void
2298 XmuDeleteStandardColormap(Display *dpy, int screen, Atom property)
2299      /* dpy;            - specifies the X server to connect to
2300       * screen          - specifies the screen of the display
2301       * property        - specifies the standard colormap property
2302       */
2303 {
2304     XStandardColormap   *stdcmaps, *s;
2305     int                 count = 0;
2306
2307     if (XGetRGBColormaps(dpy, RootWindow(dpy, screen), &stdcmaps, &count,
2308                          property))
2309         {
2310             for (s=stdcmaps; count > 0; count--, s++) {
2311                 if ((s->killid == ReleaseByFreeingColormap) &&
2312                     (s->colormap != None) &&
2313                     (s->colormap != DefaultColormap(dpy, screen))) {
2314
2315                     // UGLY HACK written in by Adam Megacz -- sometimes s->colormap isn't valid, so we do some shuffling
2316                     X11ErrorHandler* oldHandler = XSetErrorHandler(ignoreErrorHandler);
2317                     XSync(dpy, False);
2318                     XFreeColormap(dpy, s->colormap);
2319                     XSync(dpy, False);
2320                     XSetErrorHandler(oldHandler);
2321                     XSync(dpy, False);
2322
2323                 } else if (s->killid != None) {
2324                     XKillClient(dpy, s->killid);
2325                 }
2326             }
2327             XDeleteProperty(dpy, RootWindow(dpy, screen), property);
2328             XFree((char *) stdcmaps);
2329             XSync(dpy, False);
2330         }
2331 }
2332
2333