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