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