2
* pals.c -- $Id: pals.c 685 2003-03-08 15:26:51Z travo $
3
* palette handling for X11
5
* Copyright (c) 1998. See accompanying LEGAL file for details.
12
static int x_use_shared(p_scr *s, p_col_t color, p_col_t *pixel);
13
static void x_lose_shared(p_scr *s, p_col_t *pixels, int n);
14
static void x_all_shared(p_scr *s, XColor *map /*[256]*/);
15
static p_col_t x_best_shared(p_scr *s, p_col_t color,
17
static void x_cavailable(void *p, p_hashkey key, void *ctx);
18
static void x_list_dead(void *p, p_hashkey key, void *ctx);
19
static void x_find_dead(void *p, p_hashkey key, void *ctx);
20
static void x_mark_shared(void *p);
23
p_palette(p_win *w, p_col_t *colors, int n)
30
if (w->parent) w = w->parent; /* pixmap uses parent palette */
33
if (s->vclass==TrueColor || s->vclass==DirectColor) {
34
for (i=0 ; i<n ; i++) {
38
w->pixels[i] = (s->pixels[r]&s->rmask) |
39
(s->pixels[g]&s->gmask) | (s->pixels[b]&s->bmask);
43
} else if (s->vclass!=PseudoColor) {
44
for (i=0 ; i<n ; i++) {
48
w->pixels[i] = s->pixels[(r+g+b)/3];
52
} else if (w->rgb_pixels) {
53
for (i=0 ; i<n ; i++) {
61
w->pixels[i] = w->rgb_pixels[r+g+(g<<2)]; /* r + 5*g * 45*b */
68
p_col_t fg_pixel = s->colors[1].pixel;
69
Display *dpy = s->xdpy->dpy;
70
Visual *visual = DefaultVisual(dpy,s->scr_num);
71
int map_size = visual->map_entries;
72
if (map_size>256) map_size = 256;
75
/* this window uses default colormap (read-only shared colors) */
76
int n_old = w->n_palette;
78
/* (1) free our use of existing colors */
80
x_lose_shared(s, w->pixels, n_old);
81
for (i=0 ; i<n_old ; i++) w->pixels[i] = fg_pixel;
84
/* (2) go for it, but prudently ask in bit reversed order */
85
for (i=0 ; i<256 ; i++) {
88
if (!x_use_shared(s, colors[p], &w->pixels[p])) break;
92
/* (3) fallback if didn't get full request */
97
/* query all colors, reserving a use of all sharable colors */
99
for (nsh=0 ; nsh<256 ; nsh++) {
100
if (map[nsh].flags) break;
101
map[nsh].red = (map[nsh].red >>8)&0xff;
102
map[nsh].green = (map[nsh].green>>8)&0xff;
103
map[nsh].blue = (map[nsh].blue >>8)&0xff;
106
/* take closest sharable pixel to those requested
107
* - allocate extra uses for colors used more than once */
108
for (; i<256 ; i++) {
111
w->pixels[p] = x_best_shared(s, colors[p], map, nsh);
115
/* release shared colors we didn't ever use */
116
x_lose_shared(s, (p_col_t *)0, 0);
120
/* this window has a private colormap (read-write private colors) */
123
/* private colormaps will flash display when they are installed
124
* take two steps to minimize the annoyance:
125
* (1) be sure to allocate the 16 standard colors
126
* s->colors[0:15] the same as default cmap on screen
127
* -- x_color algorithm fails without this,
128
* done when cmap created
129
* (2) allocate palette colors from top down, since most
130
* X servers seem to pass out colors from bottom up and
131
* important permanent apps (window manager) started first
132
* -- allocate colors at bottom same as in default cmap */
133
for (i=0 ; i<map_size ; i++) used[i] = 0;
134
for (i=0 ; i<16 ; i++)
135
if (s->colors[i].pixel<map_size) used[s->colors[i].pixel] = 1;
136
for (p=map_size-1,i=0 ; p>=0 && i<n ; p--) {
137
if (used[p]) continue;
138
c.pixel = w->pixels[i] = p;
139
c.red = P_R(colors[i]) << 8;
140
c.green = P_G(colors[i]) << 8;
141
c.blue = P_B(colors[i]) << 8;
143
c.flags = DoRed | DoGreen | DoBlue;
144
XStoreColor(dpy, w->cmap, &c);
146
for (; i<240 ; i++) w->pixels[i] = fg_pixel;
148
/* restore as much of the default colormap as possible */
149
Colormap cmap = DefaultColormap(dpy,s->scr_num);
151
for (i=0 ; i<=p ; i++) map[i].pixel = i;
152
XQueryColors(dpy, cmap, map, p+1);
153
for (i=0 ; i<=p ; i++) {
154
if (used[i]) continue;
155
map[i].flags = DoRed | DoGreen | DoBlue;
156
XStoreColor(dpy, w->cmap, &map[i]);
162
if (p_signalling) p_abort();
166
x_rgb_palette(p_win *w)
168
if (w->parent) w = w->parent;
169
if (!w->rgb_pixels) {
173
if (s->vclass!=PseudoColor) return 0;
175
/* would be friendlier to translate preexisting
176
* palette, but nuking it is far simpler */
177
p_palette(w, p_595, 225);
179
pixels = s->tmp = p_malloc(sizeof(p_col_t)*256);
180
if (!pixels) return 0;
181
for (i=0 ; i<256 ; i++) pixels[i] = w->pixels[i];
183
w->rgb_pixels = pixels;
184
p_palette(w, (p_col_t *)0, 0);
189
/*------------------------------------------------------------------------*/
192
unsigned long *usepxl; /* [uses,pixel] for each pixel */
193
unsigned long nextpxl; /* index into next free usepxl pair */
194
p_hashtab *bypixel; /* returns usepxl index given pixel value */
195
p_hashtab *bycolor; /* returns usepxl index given color value */
196
/* note: bypixel hash table is unnecessary if we were guaranteed
197
* that the pixel values are <256 for PseudoColor displays,
198
* as I assume in a few places (e.g.- x_all_shared below)
199
* - nevertheless, it ensures that x_use_shared, x_lose_shared
200
* and x_nuke_shared work for all possible X servers
205
unsigned long list[256], keys[256];
215
x_use_shared(p_scr *s, p_col_t color, p_col_t *pixel)
217
x_cshared *shared = s->shared;
218
p_hashkey colkey = P_IHASH(color);
219
unsigned long *usepxl;
221
usepxl = p_hfind(shared->bycolor, colkey);
224
Display *dpy = s->xdpy->dpy;
225
Colormap cmap = DefaultColormap(dpy, s->scr_num);
228
unsigned long nextpxl = shared->nextpxl;
229
if (nextpxl>=512) return 0; /* only provide for 256 shared colors */
230
c.red = P_R(color) << 8;
231
c.green = P_G(color) << 8;
232
c.blue = P_B(color) << 8;
233
if (!XAllocColor(dpy, cmap, &c)) return 0; /* default colormap is full */
234
pixkey = P_IHASH(c.pixel);
235
usepxl = p_hfind(shared->bypixel, pixkey);
236
if (usepxl) { /* different colors may give same pixel */
237
XFreeColors(dpy, cmap, &c.pixel, 1, 0UL);
238
p_hinsert(shared->bycolor, colkey, usepxl);
240
usepxl = shared->usepxl + nextpxl;
241
shared->nextpxl = usepxl[0];
242
usepxl[0] = 0; /* this will be first use */
244
p_hinsert(shared->bypixel, pixkey, usepxl);
245
p_hinsert(shared->bycolor, colkey, usepxl);
255
x_lose_shared(p_scr *s, p_col_t *pixels, int n)
257
x_cshared *shared = s->shared;
258
unsigned long *usepxl;
259
struct x_deadpix deadpix;
263
shared = p_malloc(sizeof(x_cshared));
265
shared->bycolor = p_halloc(256);
266
shared->bypixel = p_halloc(256);
267
shared->usepxl = p_malloc(sizeof(unsigned long)*512);
268
if (!shared->bycolor || !shared->usepxl) return;
270
for (i=0 ; i<512 ; i+=2) shared->usepxl[i] = i+2;
275
usepxl = p_hfind(shared->bypixel, P_IHASH(pixels[n]));
276
if (usepxl && usepxl[0]) usepxl[0]--;
278
deadpix.shared = shared;
279
deadpix.n = deadpix.m = 0;
280
p_hiter(shared->bycolor, &x_find_dead, &deadpix);
281
for (i=0 ; i<deadpix.m ; i++)
282
p_hinsert(shared->bycolor, deadpix.keys[i], (void*)0);
283
p_hiter(shared->bypixel, &x_list_dead, &deadpix); /* also unlinks */
284
for (i=0 ; i<deadpix.n ; i++)
285
p_hinsert(shared->bypixel, P_IHASH(deadpix.list[i]), (void*)0);
287
Display *dpy = s->xdpy->dpy;
288
XFreeColors(dpy, DefaultColormap(dpy,s->scr_num),
289
deadpix.list, deadpix.n, 0UL);
294
x_all_shared(p_scr *s, XColor *map /*[256]*/)
296
x_cshared *shared = s->shared;
299
unsigned long *usepxl;
300
struct x_c2pix available;
301
Display *dpy = s->xdpy->dpy;
302
Colormap cmap = DefaultColormap(dpy,s->scr_num);
303
Visual *visual = DefaultVisual(dpy,s->scr_num);
304
int map_size = visual->map_entries;
305
if (map_size>256) map_size = 256;
307
for (i=n=0 ; i<map_size ; i++)
308
if (!p_hfind(shared->bypixel, P_IHASH(i)))
310
if (!n) return; /* we already own all shared colors */
312
XQueryColors(dpy, cmap, map, n);
313
for (i=0 ; i<n ; i++)
314
if (XAllocColor(dpy, cmap, &map[i])) {
315
/* this color is sharable, record in bypixel table
316
* -includes the standard colors */
317
usepxl = shared->usepxl + shared->nextpxl;
318
shared->nextpxl = usepxl[0];
319
usepxl[0] = 0; /* we haven't actually used it yet */
320
usepxl[1] = map[i].pixel;
321
p_hinsert(shared->bypixel, P_IHASH(map[i].pixel), usepxl);
322
if (shared->nextpxl>=512) break;
326
p_hiter(shared->bypixel, &x_cavailable, &available);
327
XQueryColors(dpy, cmap, map, available.n);
328
for (i=0 ; i<available.n ; i++) map[i].flags = 0;
329
if (i<256) map[i].flags = 1;
334
x_best_shared(p_scr *s, p_col_t color, XColor *map, int n)
336
unsigned long *usepxl;
343
for (k=j=0 ; k<n ; k++) {
344
d1 = ((tmp = map[k].red - r), tmp*tmp);
345
d1 += ((tmp = map[k].green - g), tmp*tmp);
346
d1 += ((tmp = map[k].blue - b), tmp*tmp);
347
if (d1<d0) j = k, d0 = d1;
349
usepxl = p_hfind(s->shared->bypixel, P_IHASH(map[j].pixel));
355
x_nuke_shared(p_scr *s)
357
x_cshared *shared = s->shared;
359
unsigned long *usepxl = shared->usepxl;
360
void (*noaction)(void *)= 0;
361
Display *dpy = s->xdpy->dpy;
364
p_hfree(shared->bypixel, noaction);
365
p_hfree(shared->bycolor, &x_mark_shared);
366
for (i=n=0 ; i<512 ; i+=2)
367
if (usepxl[i]==1) usepxl[n++] = usepxl[i+1];
369
XFreeColors(dpy, DefaultColormap(dpy,s->scr_num), usepxl, n, 0UL);
373
if (p_signalling) p_abort();
378
x_cavailable(void *p, p_hashkey key, void *ctx)
380
unsigned long *usepxl = p;
381
struct x_c2pix *available = ctx;
382
available->map[available->n++].pixel = usepxl[1];
387
x_list_dead(void *p, p_hashkey key, void *ctx)
389
unsigned long *usepxl = p;
391
struct x_deadpix *deadpix = ctx;
392
deadpix->list[deadpix->n++] = usepxl[1];
393
usepxl[0] = deadpix->shared->nextpxl;
394
deadpix->shared->nextpxl = usepxl - deadpix->shared->usepxl;
399
x_find_dead(void *p, p_hashkey key, void *ctx)
401
unsigned long *usepxl = p;
403
struct x_deadpix *deadpix = ctx;
404
deadpix->keys[deadpix->m++] = key;
409
x_mark_shared(void *p)
411
unsigned long *usepxl = p;
412
usepxl[0] = 1; /* 1 cannot be in nextpxl free list (always even) */