~ubuntu-branches/debian/lenny/italc/lenny

« back to all changes in this revision

Viewing changes to client/demoviewer/colour.c

  • Committer: Bazaar Package Importer
  • Author(s): Patrick Winnertz
  • Date: 2008-06-17 13:46:54 UTC
  • mfrom: (1.2.1 upstream) (4.1.1 gutsy)
  • Revision ID: james.westby@ubuntu.com-20080617134654-cl0gi4u524cv1ici
Tags: 1:1.0.9~rc3-1
* Package new upstream version
  - upstream ported the code to qt4.4 (Closes: #481974)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
3
 
 *
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.
8
 
 *
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.
13
 
 *
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,
17
 
 *  USA.
18
 
 */
19
 
 
20
 
/*
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.
23
 
 */
24
 
 
25
 
#include "demoviewer.h"
26
 
#include <limits.h>
27
 
 
28
 
 
29
 
#define INVALID_PIXEL 0xffffffff
30
 
#define MAX_CMAP_SIZE 256
31
 
#define BGR233_SIZE 256
32
 
unsigned long BGR233ToPixel[BGR233_SIZE];
33
 
 
34
 
Colormap cmap;
35
 
Visual *vis;
36
 
unsigned int visdepth, visbpp;
37
 
Bool allocColorFailed = False;
38
 
 
39
 
static int nBGR233ColoursAllocated;
40
 
 
41
 
static Bool GetPseudoColorVisualAndCmap(int depth);
42
 
static Bool GetTrueColorVisualAndCmap(int depth);
43
 
static int GetBPPForDepth(int depth);
44
 
static void SetupBGR233Map();
45
 
static void AllocateExactBGR233Colours();
46
 
static Bool AllocateBGR233Colour(int r, int g, int b);
47
 
 
48
 
 
49
 
/*
50
 
 * SetVisualAndCmap() deals with the wonderful world of X "visuals" (which are
51
 
 * equivalent to the RFB protocol's "pixel format").  Having decided on the
52
 
 * best visual, it also creates a colormap if necessary, sets the appropriate
53
 
 * resources on the toplevel widget, and sets up the myFormat structure to
54
 
 * describe the pixel format in terms that the RFB server will be able to
55
 
 * understand.
56
 
 *
57
 
 * The algorithm for deciding which visual to use is as follows:
58
 
 *
59
 
 * If forceOwnCmap is true then we try to use a PseudoColor visual - we first
60
 
 * see if there's one of the same depth as the RFB server, followed by an 8-bit
61
 
 * deep one.
62
 
 *
63
 
 * If forceTrueColour is true then we try to use a TrueColor visual - if
64
 
 * requestedDepth is set then it must be of that depth, otherwise any depth
65
 
 * will be used.
66
 
 *
67
 
 * Otherwise, we use the X server's default visual and colormap.  If this is
68
 
 * TrueColor then we just ask the RFB server for this format.  If the default
69
 
 * isn't TrueColor, or if useBGR233 is true, then we ask the RFB server for
70
 
 * BGR233 pixel format and use a lookup table to translate to the nearest
71
 
 * colours provided by the X server.
72
 
 */
73
 
 
74
 
void
75
 
SetVisualAndCmap()
76
 
{
77
 
  if (appData.forceOwnCmap) {
78
 
    if (!si.format.trueColour) {
79
 
      if (GetPseudoColorVisualAndCmap(si.format.depth))
80
 
        return;
81
 
    }
82
 
    if (GetPseudoColorVisualAndCmap(8))
83
 
      return;
84
 
    fprintf(stderr,"Couldn't find a matching PseudoColor visual.\n");
85
 
  }
86
 
 
87
 
  if (appData.forceTrueColour) {
88
 
    if (GetTrueColorVisualAndCmap(appData.requestedDepth))
89
 
      return;
90
 
    fprintf(stderr,"Couldn't find a matching TrueColor visual.\n");
91
 
  }
92
 
 
93
 
  /* just use default visual and colormap */
94
 
 
95
 
  vis = DefaultVisual(dpy,DefaultScreen(dpy));
96
 
  visdepth = DefaultDepth(dpy,DefaultScreen(dpy));
97
 
  visbpp = GetBPPForDepth(visdepth);
98
 
  cmap = DefaultColormap(dpy,DefaultScreen(dpy));
99
 
 
100
 
  if (!appData.useBGR233 && (vis->class == TrueColor)) {
101
 
 
102
 
    myFormat.bitsPerPixel = visbpp;
103
 
    myFormat.depth = visdepth;
104
 
    myFormat.trueColour = 1;
105
 
    myFormat.bigEndian = (ImageByteOrder(dpy) == MSBFirst);
106
 
    myFormat.redShift = ffs(vis->red_mask) - 1;
107
 
    myFormat.greenShift = ffs(vis->green_mask) - 1;
108
 
    myFormat.blueShift = ffs(vis->blue_mask) - 1;
109
 
    myFormat.redMax = vis->red_mask >> myFormat.redShift;
110
 
    myFormat.greenMax = vis->green_mask >> myFormat.greenShift;
111
 
    myFormat.blueMax = vis->blue_mask >> myFormat.blueShift;
112
 
 
113
 
    fprintf(stderr,
114
 
            "Using default colormap which is TrueColor.  Pixel format:\n");
115
 
    PrintPixelFormat(&myFormat);
116
 
    return;
117
 
  }
118
 
 
119
 
  appData.useBGR233 = True;
120
 
 
121
 
  myFormat.bitsPerPixel = 8;
122
 
  myFormat.depth = 8;
123
 
  myFormat.trueColour = 1;
124
 
  myFormat.bigEndian = 0;
125
 
  myFormat.redMax = 7;
126
 
  myFormat.greenMax = 7;
127
 
  myFormat.blueMax = 3;
128
 
  myFormat.redShift = 0;
129
 
  myFormat.greenShift = 3;
130
 
  myFormat.blueShift = 6;
131
 
 
132
 
  fprintf(stderr,
133
 
       "Using default colormap and translating from BGR233.  Pixel format:\n");
134
 
  PrintPixelFormat(&myFormat);
135
 
 
136
 
  SetupBGR233Map();
137
 
}
138
 
 
139
 
 
140
 
/*
141
 
 * GetPseudoColorVisualAndCmap tries to find a PseudoColor visual of the given
142
 
 * depth.  If successful it sets vis, visdepth, cmap and myFormat, and also
143
 
 * sets the appropriate resources on the toplevel widget.
144
 
 */
145
 
 
146
 
static Bool
147
 
GetPseudoColorVisualAndCmap(int depth)
148
 
{
149
 
  XVisualInfo tmpl;
150
 
  XVisualInfo *vinfo;
151
 
  int nvis;
152
 
 
153
 
  tmpl.screen = DefaultScreen(dpy);
154
 
  tmpl.depth = depth;
155
 
  tmpl.class = PseudoColor;
156
 
  tmpl.colormap_size = (1 << depth);
157
 
 
158
 
  vinfo = XGetVisualInfo(dpy,
159
 
                         VisualScreenMask|VisualDepthMask|
160
 
                         VisualClassMask|VisualColormapSizeMask,
161
 
                         &tmpl, &nvis);
162
 
 
163
 
  if (vinfo) {
164
 
    vis = vinfo[0].visual;
165
 
    visdepth = vinfo[0].depth;
166
 
    XFree(vinfo);
167
 
    visbpp = GetBPPForDepth(visdepth);
168
 
    myFormat.bitsPerPixel = visbpp;
169
 
    myFormat.depth = visdepth;
170
 
    myFormat.trueColour = 0;
171
 
    myFormat.bigEndian = (ImageByteOrder(dpy) == MSBFirst);
172
 
    myFormat.redMax = myFormat.greenMax = myFormat.blueMax = 0;
173
 
    myFormat.redShift = myFormat.greenShift = myFormat.blueShift = 0;
174
 
 
175
 
    cmap = XCreateColormap(dpy, DefaultRootWindow(dpy), vis, AllocAll);
176
 
 
177
 
    XtVaSetValues(toplevel, XtNcolormap, cmap, XtNdepth, visdepth,
178
 
                  XtNvisual, vis, NULL);
179
 
 
180
 
    if (appData.fullScreen) {
181
 
      XInstallColormap(dpy, cmap);
182
 
    }
183
 
 
184
 
    fprintf(stderr,"Using PseudoColor visual, depth %d.  Pixel format:\n",
185
 
            visdepth);
186
 
    PrintPixelFormat(&myFormat);
187
 
 
188
 
    return True;
189
 
  }
190
 
 
191
 
  return False;
192
 
}
193
 
 
194
 
 
195
 
/*
196
 
 * GetTrueColorVisualAndCmap tries to find a TrueColor visual of the given
197
 
 * depth.  If successful it sets vis, visdepth, cmap and myFormat, and also
198
 
 * sets the appropriate resources on the toplevel widget.
199
 
 */
200
 
 
201
 
static Bool
202
 
GetTrueColorVisualAndCmap(int depth)
203
 
{
204
 
  XVisualInfo tmpl;
205
 
  XVisualInfo *vinfo;
206
 
  int nvis;
207
 
  int mask = VisualScreenMask|VisualClassMask;
208
 
 
209
 
  tmpl.screen = DefaultScreen(dpy);
210
 
  tmpl.class = TrueColor;
211
 
 
212
 
  if (depth != 0) {
213
 
    tmpl.depth = depth;
214
 
    mask |= VisualDepthMask;
215
 
  }
216
 
 
217
 
  vinfo = XGetVisualInfo(dpy, mask, &tmpl, &nvis);
218
 
 
219
 
  if (vinfo) {
220
 
    vis = vinfo[0].visual;
221
 
    visdepth = vinfo[0].depth;
222
 
    XFree(vinfo);
223
 
    visbpp = GetBPPForDepth(visdepth);
224
 
    myFormat.bitsPerPixel = visbpp;
225
 
    myFormat.depth = visdepth;
226
 
    myFormat.trueColour = 1;
227
 
    myFormat.bigEndian = (ImageByteOrder(dpy) == MSBFirst);
228
 
    myFormat.redShift = ffs(vis->red_mask) - 1;
229
 
    myFormat.greenShift = ffs(vis->green_mask) - 1;
230
 
    myFormat.blueShift = ffs(vis->blue_mask) - 1;
231
 
    myFormat.redMax = vis->red_mask >> myFormat.redShift;
232
 
    myFormat.greenMax = vis->green_mask >> myFormat.greenShift;
233
 
    myFormat.blueMax = vis->blue_mask >> myFormat.blueShift;
234
 
 
235
 
    cmap = XCreateColormap(dpy, DefaultRootWindow(dpy), vis, AllocNone);
236
 
 
237
 
    XtVaSetValues(toplevel, XtNcolormap, cmap, XtNdepth, visdepth,
238
 
                  XtNvisual, vis, NULL);
239
 
 
240
 
    if (appData.fullScreen) {
241
 
      XInstallColormap(dpy, cmap);
242
 
    }
243
 
 
244
 
    fprintf(stderr,"Using TrueColor visual, depth %d.  Pixel format:\n",
245
 
            visdepth);
246
 
    PrintPixelFormat(&myFormat);
247
 
 
248
 
    return True;
249
 
  }
250
 
 
251
 
  return False;
252
 
}
253
 
 
254
 
 
255
 
/*
256
 
 * GetBPPForDepth looks through the "pixmap formats" to find the bits-per-pixel
257
 
 * for the given depth.
258
 
 */
259
 
 
260
 
static int
261
 
GetBPPForDepth(int depth)
262
 
{
263
 
  XPixmapFormatValues *format;
264
 
  int nformats;
265
 
  int i;
266
 
  int bpp;
267
 
 
268
 
  format = XListPixmapFormats(dpy, &nformats);
269
 
 
270
 
  for (i = 0; i < nformats; i++) {
271
 
    if (format[i].depth == depth)
272
 
      break;
273
 
  }
274
 
 
275
 
  if (i == nformats) {
276
 
    fprintf(stderr,"no pixmap format for depth %d???\n", depth);
277
 
    exit(1);
278
 
  }
279
 
 
280
 
  bpp = format[i].bits_per_pixel;
281
 
 
282
 
  XFree(format);
283
 
 
284
 
  if (bpp != 1 && bpp != 8 && bpp != 16 && bpp != 32) {
285
 
    fprintf(stderr,"Can't cope with %d bits-per-pixel.  Sorry.\n", bpp);
286
 
    exit(1);
287
 
  }
288
 
 
289
 
  return bpp;
290
 
}
291
 
 
292
 
 
293
 
 
294
 
/*
295
 
 * SetupBGR233Map() sets up the BGR233ToPixel array.
296
 
 *
297
 
 * It calls AllocateExactBGR233Colours to allocate some exact BGR233 colours
298
 
 * (limited by space in the colormap and/or by the value of the nColours
299
 
 * resource).  If the number allocated is less than BGR233_SIZE then it fills
300
 
 * the rest in using the "nearest" colours available.  How this is done depends
301
 
 * on the value of the useSharedColours resource.  If it's false, we use only
302
 
 * colours from the exact BGR233 colours we've just allocated.  If it's true,
303
 
 * then we also use other clients' "shared" colours available in the colormap.
304
 
 */
305
 
 
306
 
static void
307
 
SetupBGR233Map()
308
 
{
309
 
  int r, g, b;
310
 
  long i;
311
 
  unsigned long nearestPixel = 0;
312
 
  int cmapSize;
313
 
  XColor cmapEntry[MAX_CMAP_SIZE];
314
 
  Bool exactBGR233[MAX_CMAP_SIZE];
315
 
  Bool shared[MAX_CMAP_SIZE];
316
 
  Bool usedAsNearest[MAX_CMAP_SIZE];
317
 
  int nSharedUsed = 0;
318
 
 
319
 
  if (visdepth > 8) {
320
 
    appData.nColours = 256; /* ignore nColours setting for > 8-bit deep */
321
 
  }
322
 
 
323
 
  for (i = 0; i < BGR233_SIZE; i++) {
324
 
    BGR233ToPixel[i] = INVALID_PIXEL;
325
 
  }
326
 
 
327
 
  AllocateExactBGR233Colours();
328
 
 
329
 
  fprintf(stderr,"Got %d exact BGR233 colours out of %d\n",
330
 
          nBGR233ColoursAllocated, appData.nColours);
331
 
 
332
 
  if (nBGR233ColoursAllocated < BGR233_SIZE) {
333
 
 
334
 
    if (visdepth > 8) { /* shouldn't get here */
335
 
      fprintf(stderr,"Error: couldn't allocate BGR233 colours even though "
336
 
              "depth is %d\n", visdepth);
337
 
      exit(1);
338
 
    }
339
 
 
340
 
    cmapSize = (1 << visdepth);
341
 
 
342
 
    for (i = 0; i < cmapSize; i++) {
343
 
      cmapEntry[i].pixel = i;
344
 
      exactBGR233[i] = False;
345
 
      shared[i] = False;
346
 
      usedAsNearest[i] = False;
347
 
    }
348
 
 
349
 
    XQueryColors(dpy, cmap, cmapEntry, cmapSize);
350
 
 
351
 
    /* mark all our exact BGR233 pixels */
352
 
 
353
 
    for (i = 0; i < BGR233_SIZE; i++) {
354
 
      if (BGR233ToPixel[i] != INVALID_PIXEL)
355
 
        exactBGR233[BGR233ToPixel[i]] = True;
356
 
    }
357
 
 
358
 
    if (appData.useSharedColours) {
359
 
 
360
 
      /* Try to find existing shared colours.  This is harder than it sounds
361
 
         because XQueryColors doesn't tell us whether colours are shared,
362
 
         private or unallocated.  What we do is go through the colormap and for
363
 
         each pixel try to allocate exactly its RGB values.  If this returns a
364
 
         different pixel then it's definitely either a private or unallocated
365
 
         pixel, so no use to us.  If it returns us the same pixel again, then
366
 
         it's likely that it's a shared colour - however, it is possible that
367
 
         it was actually an unallocated pixel, which we've now allocated.  We
368
 
         minimise this possibility by going through the pixels in reverse order
369
 
         - this helps becuse the X server allocates new pixels from the lowest
370
 
         number up, so it should only be a problem for the lowest unallocated
371
 
         pixel.  Got that? */
372
 
 
373
 
      for (i = cmapSize-1; i >= 0; i--) {
374
 
        if (!exactBGR233[i] &&
375
 
            XAllocColor(dpy, cmap, &cmapEntry[i])) {
376
 
 
377
 
          if (cmapEntry[i].pixel == i) {
378
 
 
379
 
            shared[i] = True; /* probably shared */
380
 
 
381
 
          } else {
382
 
 
383
 
            /* "i" is either unallocated or private.  We have now unnecessarily
384
 
               allocated cmapEntry[i].pixel.  Free it. */
385
 
 
386
 
            XFreeColors(dpy, cmap, &cmapEntry[i].pixel, 1, 0);
387
 
          }
388
 
        }
389
 
      }
390
 
    }
391
 
 
392
 
    /* Now fill in the nearest colours */
393
 
 
394
 
    for (r = 0; r < 8; r++) {
395
 
      for (g = 0; g < 8; g++) {
396
 
        for (b = 0; b < 4; b++) {
397
 
          if (BGR233ToPixel[(b<<6) | (g<<3) | r] == INVALID_PIXEL) {
398
 
 
399
 
            unsigned long minDistance = ULONG_MAX;
400
 
 
401
 
            for (i = 0; i < cmapSize; i++) {
402
 
              if (exactBGR233[i] || shared[i]) {
403
 
                unsigned long distance
404
 
                  = (abs(cmapEntry[i].red - r * 65535 / 7)
405
 
                     + abs(cmapEntry[i].green - g * 65535 / 7)
406
 
                     + abs(cmapEntry[i].blue - b * 65535 / 3));
407
 
 
408
 
                if (distance < minDistance) {
409
 
                  minDistance = distance;
410
 
                  nearestPixel = i;
411
 
                }
412
 
              }
413
 
            }
414
 
 
415
 
            BGR233ToPixel[(b<<6) | (g<<3) | r] = nearestPixel;
416
 
            if (shared[nearestPixel] && !usedAsNearest[nearestPixel])
417
 
              nSharedUsed++;
418
 
            usedAsNearest[nearestPixel] = True;
419
 
          }
420
 
        }
421
 
      }
422
 
    }
423
 
 
424
 
    /* Tidy up shared colours which we allocated but aren't going to use */
425
 
 
426
 
    for (i = 0; i < cmapSize; i++) {
427
 
      if (shared[i] && !usedAsNearest[i]) {
428
 
          XFreeColors(dpy, cmap, (unsigned long *)&i, 1, 0);
429
 
      }
430
 
    }
431
 
 
432
 
    fprintf(stderr,"Using %d existing shared colours\n", nSharedUsed);
433
 
  }
434
 
}
435
 
 
436
 
 
437
 
/*
438
 
 * AllocateExactBGR233Colours() attempts to allocate each of the colours in the
439
 
 * BGR233 colour cube, stopping when an allocation fails.  The order it does
440
 
 * this in is such that we should get a fairly well spread subset of the cube,
441
 
 * however many allocations are made.  There's probably a neater algorithm for
442
 
 * doing this, but it's not obvious to me anyway.  The way this algorithm works
443
 
 * is:
444
 
 *
445
 
 * At each stage, we introduce a new value for one of the primaries, and
446
 
 * allocate all the colours with the new value of that primary and all previous
447
 
 * values of the other two primaries.  We start with r=0 as the "new" value
448
 
 * for r, and g=0, b=0 as the "previous" values of g and b.  So we get:
449
 
 *
450
 
 * New primary value   Previous values of other primaries   Colours allocated
451
 
 * -----------------   ----------------------------------   -----------------
452
 
 * r=0                 g=0       b=0                        r0 g0 b0
453
 
 * g=7                 r=0       b=0                        r0 g7 b0
454
 
 * b=3                 r=0       g=0,7                      r0 g0 b3
455
 
 *                                                          r0 g7 b3
456
 
 * r=7                 g=0,7     b=0,3                      r7 g0 b0
457
 
 *                                                          r7 g0 b3
458
 
 *                                                          r7 g7 b0
459
 
 *                                                          r7 g7 b3
460
 
 * g=3                 r=0,7     b=0,3                      r0 g3 b0
461
 
 *                                                          r0 g3 b3
462
 
 *                                                          r7 g3 b0
463
 
 *                                                          r7 g3 b3
464
 
 * ....etc.
465
 
 * */
466
 
 
467
 
static void
468
 
AllocateExactBGR233Colours()
469
 
{
470
 
  int rv[] = {0,7,3,5,1,6,2,4};
471
 
  int gv[] = {0,7,3,5,1,6,2,4};
472
 
  int bv[] = {0,3,1,2};
473
 
  int rn = 0;
474
 
  int gn = 1;
475
 
  int bn = 1;
476
 
  int ri, gi, bi;
477
 
 
478
 
  nBGR233ColoursAllocated = 0;
479
 
 
480
 
  while (1) {
481
 
    if (rn == 8)
482
 
      break;
483
 
 
484
 
    ri = rn;
485
 
    for (gi = 0; gi < gn; gi++) {
486
 
      for (bi = 0; bi < bn; bi++) {
487
 
        if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
488
 
          return;
489
 
      }
490
 
    }
491
 
    rn++;
492
 
 
493
 
    if (gn == 8)
494
 
      break;
495
 
 
496
 
    gi = gn;
497
 
    for (ri = 0; ri < rn; ri++) {
498
 
      for (bi = 0; bi < bn; bi++) {
499
 
        if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
500
 
          return;
501
 
      }
502
 
    }
503
 
    gn++;
504
 
 
505
 
    if (bn < 4) {
506
 
 
507
 
      bi = bn;
508
 
      for (ri = 0; ri < rn; ri++) {
509
 
        for (gi = 0; gi < gn; gi++) {
510
 
          if (!AllocateBGR233Colour(rv[ri], gv[gi], bv[bi]))
511
 
            return;
512
 
        }
513
 
      }
514
 
      bn++;
515
 
    }
516
 
  }
517
 
}
518
 
 
519
 
 
520
 
/*
521
 
 * AllocateBGR233Colour() attempts to allocate the given BGR233 colour as a
522
 
 * shared colormap entry, storing its pixel value in the BGR233ToPixel array.
523
 
 * r is from 0 to 7, g from 0 to 7 and b from 0 to 3.  It fails either when the
524
 
 * allocation fails or when we would exceed the number of colours specified in
525
 
 * the nColours resource.
526
 
 */
527
 
 
528
 
static Bool
529
 
AllocateBGR233Colour(int r, int g, int b)
530
 
{
531
 
  XColor c;
532
 
 
533
 
  if (nBGR233ColoursAllocated >= appData.nColours)
534
 
    return False;
535
 
 
536
 
  c.red = r * 65535 / 7;
537
 
  c.green = g * 65535 / 7;
538
 
  c.blue = b * 65535 / 3;
539
 
 
540
 
  if (!XAllocColor(dpy, cmap, &c))
541
 
    return False;
542
 
 
543
 
  BGR233ToPixel[(b<<6) | (g<<3) | r] = c.pixel;
544
 
 
545
 
  nBGR233ColoursAllocated++;
546
 
 
547
 
  return True;
548
 
}