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