2
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
4
* This is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* (at your option) any later version.
9
* This software is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this software; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21
* colour.c - functions to deal with colour - i.e. RFB pixel formats, X visuals
22
* and colormaps. Thanks to Grant McDorman for some of the ideas used here.
25
#include "vncviewer.h"
29
#define INVALID_PIXEL 0xffffffff
30
#define MAX_CMAP_SIZE 256
31
#define BGR233_SIZE 256
32
unsigned long BGR233ToPixel[BGR233_SIZE];
36
unsigned int visdepth, visbpp;
37
Bool allocColorFailed = False;
39
static int nBGR233ColoursAllocated;
41
static int GetBPPForDepth(int depth);
42
static void SetupBGR233Map(void);
43
static void AllocateExactBGR233Colours(void);
44
static Bool AllocateBGR233Colour(int r, int g, int b);
48
* SetVisualAndCmap() deals with the wonderful world of X "visuals" (which are
49
* equivalent to the RFB protocol's "pixel format"). Having decided on the
50
* best visual, it also creates a colormap if necessary, sets the appropriate
51
* resources on the toplevel widget, and sets up the myFormat structure to
52
* describe the pixel format in terms that the RFB server will be able to
55
* The algorithm for deciding which visual to use is as follows:
57
* If forceOwnCmap is true then we try to use a PseudoColor visual - we first
58
* see if there's one of the same depth as the RFB server, followed by an 8-bit
61
* If forceTrueColour is true then we try to use a TrueColor visual - if
62
* requestedDepth is set then it must be of that depth, otherwise any depth
65
* Otherwise, we use the X server's default visual and colormap. If this is
66
* TrueColor then we just ask the RFB server for this format. If the default
67
* isn't TrueColor, or if useBGR233 is true, then we ask the RFB server for
68
* BGR233 pixel format and use a lookup table to translate to the nearest
69
* colours provided by the X server.
75
/* just use default visual and colormap */
77
vis = DefaultVisual(dpy,DefaultScreen(dpy));
78
visdepth = DefaultDepth(dpy,DefaultScreen(dpy));
79
visbpp = GetBPPForDepth(visdepth);
80
cmap = DefaultColormap(dpy,DefaultScreen(dpy));
82
if (!appData.useBGR233 && (vis->class == TrueColor)) {
84
myFormat.bitsPerPixel = visbpp;
85
myFormat.depth = visdepth;
86
myFormat.trueColour = 1;
87
myFormat.bigEndian = (ImageByteOrder(dpy) == MSBFirst);
88
myFormat.redShift = ffs(vis->red_mask) - 1;
89
myFormat.greenShift = ffs(vis->green_mask) - 1;
90
myFormat.blueShift = ffs(vis->blue_mask) - 1;
91
myFormat.redMax = vis->red_mask >> myFormat.redShift;
92
myFormat.greenMax = vis->green_mask >> myFormat.greenShift;
93
myFormat.blueMax = vis->blue_mask >> myFormat.blueShift;
96
"Using default colormap which is TrueColor. Pixel format:\n");
97
PrintPixelFormat(&myFormat);
101
appData.useBGR233 = True;
103
myFormat.bitsPerPixel = 8;
105
myFormat.trueColour = 1;
106
myFormat.bigEndian = 0;
108
myFormat.greenMax = 7;
109
myFormat.blueMax = 3;
110
myFormat.redShift = 0;
111
myFormat.greenShift = 3;
112
myFormat.blueShift = 6;
115
"Using default colormap and translating from BGR233. Pixel format:\n");
116
PrintPixelFormat(&myFormat);
123
* GetBPPForDepth looks through the "pixmap formats" to find the bits-per-pixel
124
* for the given depth.
128
GetBPPForDepth(int depth)
130
XPixmapFormatValues *format;
135
format = XListPixmapFormats(dpy, &nformats);
137
for (i = 0; i < nformats; i++) {
138
if (format[i].depth == depth)
143
fprintf(stderr,"no pixmap format for depth %d???\n", depth);
147
bpp = format[i].bits_per_pixel;
151
if (bpp != 1 && bpp != 8 && bpp != 16 && bpp != 32) {
152
fprintf(stderr,"Can't cope with %d bits-per-pixel. Sorry.\n", bpp);
162
* SetupBGR233Map() sets up the BGR233ToPixel array.
164
* It calls AllocateExactBGR233Colours to allocate some exact BGR233 colours
165
* (limited by space in the colormap and/or by the value of the nColours
166
* resource). If the number allocated is less than BGR233_SIZE then it fills
167
* the rest in using the "nearest" colours available. How this is done depends
168
* on the value of the useSharedColours resource. If it's false, we use only
169
* colours from the exact BGR233 colours we've just allocated. If it's true,
170
* then we also use other clients' "shared" colours available in the colormap.
178
unsigned long nearestPixel = 0;
180
XColor cmapEntry[MAX_CMAP_SIZE];
181
Bool exactBGR233[MAX_CMAP_SIZE];
182
Bool shared[MAX_CMAP_SIZE];
183
Bool usedAsNearest[MAX_CMAP_SIZE];
187
appData.nColours = 256; /* ignore nColours setting for > 8-bit deep */
190
for (i = 0; i < BGR233_SIZE; i++) {
191
BGR233ToPixel[i] = INVALID_PIXEL;
194
AllocateExactBGR233Colours();
196
fprintf(stderr,"Got %d exact BGR233 colours out of %d\n",
197
nBGR233ColoursAllocated, appData.nColours);
199
if (nBGR233ColoursAllocated < BGR233_SIZE) {
201
if (visdepth > 8) { /* shouldn't get here */
202
fprintf(stderr,"Error: couldn't allocate BGR233 colours even though "
203
"depth is %d\n", visdepth);
207
cmapSize = (1 << visdepth);
209
for (i = 0; i < cmapSize; i++) {
210
cmapEntry[i].pixel = i;
211
exactBGR233[i] = False;
213
usedAsNearest[i] = False;
216
XQueryColors(dpy, cmap, cmapEntry, cmapSize);
218
/* mark all our exact BGR233 pixels */
220
for (i = 0; i < BGR233_SIZE; i++) {
221
if (BGR233ToPixel[i] != INVALID_PIXEL)
222
exactBGR233[BGR233ToPixel[i]] = True;
225
if (appData.useSharedColours) {
227
/* Try to find existing shared colours. This is harder than it sounds
228
because XQueryColors doesn't tell us whether colours are shared,
229
private or unallocated. What we do is go through the colormap and for
230
each pixel try to allocate exactly its RGB values. If this returns a
231
different pixel then it's definitely either a private or unallocated
232
pixel, so no use to us. If it returns us the same pixel again, then
233
it's likely that it's a shared colour - however, it is possible that
234
it was actually an unallocated pixel, which we've now allocated. We
235
minimise this possibility by going through the pixels in reverse order
236
- this helps becuse the X server allocates new pixels from the lowest
237
number up, so it should only be a problem for the lowest unallocated
240
for (i = cmapSize-1; i >= 0; i--) {
241
if (!exactBGR233[i] &&
242
XAllocColor(dpy, cmap, &cmapEntry[i])) {
244
if (cmapEntry[i].pixel == (unsigned long) i) {
246
shared[i] = True; /* probably shared */
250
/* "i" is either unallocated or private. We have now unnecessarily
251
allocated cmapEntry[i].pixel. Free it. */
253
XFreeColors(dpy, cmap, &cmapEntry[i].pixel, 1, 0);
259
/* Now fill in the nearest colours */
261
for (r = 0; r < 8; r++) {
262
for (g = 0; g < 8; g++) {
263
for (b = 0; b < 4; b++) {
264
if (BGR233ToPixel[(b<<6) | (g<<3) | r] == INVALID_PIXEL) {
266
unsigned long minDistance = ULONG_MAX;
268
for (i = 0; i < cmapSize; i++) {
269
if (exactBGR233[i] || shared[i]) {
270
unsigned long distance
271
= (abs(cmapEntry[i].red - r * 65535 / 7)
272
+ abs(cmapEntry[i].green - g * 65535 / 7)
273
+ abs(cmapEntry[i].blue - b * 65535 / 3));
275
if (distance < minDistance) {
276
minDistance = distance;
282
BGR233ToPixel[(b<<6) | (g<<3) | r] = nearestPixel;
283
if (shared[nearestPixel] && !usedAsNearest[nearestPixel])
285
usedAsNearest[nearestPixel] = True;
291
/* Tidy up shared colours which we allocated but aren't going to use */
293
for (i = 0; i < cmapSize; i++) {
294
if (shared[i] && !usedAsNearest[i]) {
295
XFreeColors(dpy, cmap, (unsigned long *)&i, 1, 0);
299
fprintf(stderr,"Using %d existing shared colours\n", nSharedUsed);
305
* AllocateExactBGR233Colours() attempts to allocate each of the colours in the
306
* BGR233 colour cube, stopping when an allocation fails. The order it does
307
* this in is such that we should get a fairly well spread subset of the cube,
308
* however many allocations are made. There's probably a neater algorithm for
309
* doing this, but it's not obvious to me anyway. The way this algorithm works
312
* At each stage, we introduce a new value for one of the primaries, and
313
* allocate all the colours with the new value of that primary and all previous
314
* values of the other two primaries. We start with r=0 as the "new" value
315
* for r, and g=0, b=0 as the "previous" values of g and b. So we get:
317
* New primary value Previous values of other primaries Colours allocated
318
* ----------------- ---------------------------------- -----------------
319
* r=0 g=0 b=0 r0 g0 b0
320
* g=7 r=0 b=0 r0 g7 b0
321
* b=3 r=0 g=0,7 r0 g0 b3
323
* r=7 g=0,7 b=0,3 r7 g0 b0
327
* g=3 r=0,7 b=0,3 r0 g3 b0
335
AllocateExactBGR233Colours(void)
337
int rv[] = {0,7,3,5,1,6,2,4};
338
int gv[] = {0,7,3,5,1,6,2,4};
339
int bv[] = {0,3,1,2};
345
nBGR233ColoursAllocated = 0;
352
for (gi = 0; gi < gn; gi++) {
353
for (bi = 0; bi < bn; bi++) {
354
if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
364
for (ri = 0; ri < rn; ri++) {
365
for (bi = 0; bi < bn; bi++) {
366
if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
375
for (ri = 0; ri < rn; ri++) {
376
for (gi = 0; gi < gn; gi++) {
377
if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
388
* AllocateBGR233Colour() attempts to allocate the given BGR233 colour as a
389
* shared colormap entry, storing its pixel value in the BGR233ToPixel array.
390
* r is from 0 to 7, g from 0 to 7 and b from 0 to 3. It fails either when the
391
* allocation fails or when we would exceed the number of colours specified in
392
* the nColours resource.
396
AllocateBGR233Colour(int r, int g, int b)
400
if (nBGR233ColoursAllocated >= appData.nColours)
403
c.red = r * 65535 / 7;
404
c.green = g * 65535 / 7;
405
c.blue = b * 65535 / 3;
407
if (!XAllocColor(dpy, cmap, &c))
410
BGR233ToPixel[(b<<6) | (g<<3) | r] = c.pixel;
412
nBGR233ColoursAllocated++;