~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to ksplash/ksplashx/qcolor_x11.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** This file is based on sources of the Qt GUI Toolkit, used under the terms
 
4
** of the GNU General Public License version 2 (see the original copyright
 
5
** notice below).
 
6
** All further contributions to this file are (and are required to be)
 
7
** licensed under the terms of the GNU General Public License as published by
 
8
** the Free Software Foundation; either version 2 of the License, or
 
9
** (at your option) any later version.
 
10
**
 
11
** The original Qt license header follows:
 
12
** 
 
13
**
 
14
** Implementation of QColor class for X11
 
15
**
 
16
** Created : 940112
 
17
**
 
18
** Copyright (C) 1992-2000 Trolltech AS.  All rights reserved.
 
19
**
 
20
** This file is part of the kernel module of the Qt GUI Toolkit.
 
21
**
 
22
** This file may be distributed under the terms of the Q Public License
 
23
** as defined by Trolltech AS of Norway and appearing in the file
 
24
** LICENSE.QPL included in the packaging of this file.
 
25
**
 
26
** This file may be distributed and/or modified under the terms of the
 
27
** GNU General Public License version 2 as published by the Free Software
 
28
** Foundation and appearing in the file LICENSE.GPL included in the
 
29
** packaging of this file.
 
30
**
 
31
** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
 
32
** licenses for Unix/X11 may use this file in accordance with the Qt Commercial
 
33
** License Agreement provided with the Software.
 
34
**
 
35
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
36
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
37
**
 
38
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
39
**   information about Qt Commercial License Agreements.
 
40
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
41
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
42
**
 
43
** Contact info@trolltech.com if any conditions of this licensing are
 
44
** not clear to you.
 
45
**
 
46
**********************************************************************/
 
47
 
 
48
#include "qcolor.h"
 
49
#include "qcolor_p.h"
 
50
//#include "string.h"
 
51
//#include "qpaintdevice.h"
 
52
//#include "qapplication.h"
 
53
//#include "qapplication_p.h"
 
54
//#include "qt_x11_p.h"
 
55
#include "x11_defs.h"
 
56
#include "string.h"
 
57
 
 
58
int             qt_ncols_option  = 216;         // used in qcolor_x11.cpp
 
59
 
 
60
// NOT REVISED
 
61
 
 
62
/*****************************************************************************
 
63
  The color dictionary speeds up color allocation significantly for X11.
 
64
  When there are no more colors, QColor::alloc() will set the colors_avail
 
65
  flag to FALSE and try to find the nearest color.
 
66
  NOTE: From deep within the event loop, the colors_avail flag is reset to
 
67
  TRUE (calls the function qt_reset_color_avail()), because some other
 
68
  application might free its colors, thereby making them available for
 
69
  this Qt application.
 
70
 *****************************************************************************/
 
71
 
 
72
//#include "qintdict.h"
 
73
 
 
74
struct QColorData {
 
75
    uint pix;                                   // allocated pixel value
 
76
    int  context;                               // allocation context
 
77
};
 
78
 
 
79
#if 0
 
80
typedef QIntDict<QColorData> QColorDict;
 
81
typedef QIntDictIterator<QColorData> QColorDictIt;
 
82
#endif
 
83
static int      current_alloc_context = 0;      // current color alloc context
 
84
static const uint col_std_dict = 419;
 
85
static const uint col_large_dict = 18397;
 
86
 
 
87
class QColorScreenData {
 
88
public:
 
89
    QColorScreenData()
 
90
    {
 
91
//#     colorDict = 0;
 
92
        colors_avail = true;
 
93
        g_vis = 0;
 
94
        g_carr = 0;
 
95
        g_carr_fetch = true;
 
96
        g_cells = 0;
 
97
        g_our_alloc = 0;
 
98
        color_reduce = false;
 
99
    }
 
100
 
 
101
//#    QColorDict *colorDict;           // dict of allocated colors
 
102
    bool colors_avail;                  // X colors available
 
103
    bool g_truecolor;                   // truecolor visual
 
104
    Visual *g_vis;                      // visual
 
105
    XColor *g_carr;                     // color array
 
106
    bool g_carr_fetch;                  // perform XQueryColors?
 
107
    int g_cells;                        // number of entries in g_carr
 
108
    bool *g_our_alloc;                  // our allocated colors
 
109
    uint red_mask , green_mask , blue_mask;
 
110
    int red_shift, green_shift, blue_shift;
 
111
    bool color_reduce;
 
112
    int col_div_r;
 
113
    int col_div_g;
 
114
    int col_div_b;
 
115
};
 
116
 
 
117
static int screencount = 0;
 
118
static QColorScreenData **screendata = 0; // array of screendata pointers
 
119
 
 
120
 
 
121
/*
 
122
  This function is called from the event loop. It resets the colors_avail
 
123
  flag so that the application can retry to allocate read-only colors
 
124
  that other applications may have deallocated lately.
 
125
 
 
126
  The g_our_alloc and g_carr are global arrays that optimize color
 
127
  approximation when there are no more colors left to allocate.
 
128
*/
 
129
 
 
130
void qt_reset_color_avail()
 
131
{
 
132
    int i;
 
133
    for ( i = 0; i < screencount; i++ ) {
 
134
        screendata[i]->colors_avail = true;
 
135
        screendata[i]->g_carr_fetch = true;     // do XQueryColors if !colors_avail
 
136
    }
 
137
}
 
138
 
 
139
 
 
140
/*
 
141
  Finds the nearest color.
 
142
*/
 
143
 
 
144
static int find_nearest_color( int r, int g, int b, int* mindist_out,
 
145
                               QColorScreenData *sd )
 
146
{
 
147
    int mincol = -1;
 
148
    int mindist = 200000;
 
149
    int rx, gx, bx, dist;
 
150
    XColor *xc = &sd->g_carr[0];
 
151
    for ( int i=0; i<sd->g_cells; i++ ) {
 
152
        rx = r - (xc->red >> 8);
 
153
        gx = g - (xc->green >> 8);
 
154
        bx = b - (xc->blue>> 8);
 
155
        dist = rx*rx + gx*gx + bx*bx;           // calculate distance
 
156
        if ( dist < mindist ) {                 // minimal?
 
157
            mindist = dist;
 
158
            mincol = i;
 
159
        }
 
160
        xc++;
 
161
    }
 
162
    *mindist_out = mindist;
 
163
    return mincol;
 
164
}
 
165
 
 
166
 
 
167
/*****************************************************************************
 
168
  QColor misc internal functions
 
169
 *****************************************************************************/
 
170
 
 
171
static int highest_bit( uint v )
 
172
{
 
173
    int i;
 
174
    uint b = (uint)1 << 31;                     // get pos of highest bit in v
 
175
    for ( i=31; ((b & v) == 0) && i>=0;  i-- )
 
176
        b >>= 1;
 
177
    return i;
 
178
}
 
179
 
 
180
 
 
181
/*****************************************************************************
 
182
  QColor static member functions
 
183
 *****************************************************************************/
 
184
 
 
185
/*!
 
186
    Returns the maximum number of colors supported by the underlying
 
187
    window system if the window system uses a palette.
 
188
 
 
189
    Otherwise returns -1. Use numBitPlanes() to calculate the available
 
190
    colors in that case.
 
191
*/
 
192
 
 
193
int QColor::maxColors()
 
194
{
 
195
    Visual *visual = (Visual *) QPaintDevice::x11AppVisual();
 
196
    if (visual->c_class & 1)
 
197
        return QPaintDevice::x11AppCells();
 
198
    return -1;
 
199
}
 
200
 
 
201
/*!
 
202
    Returns the number of color bit planes for the underlying window
 
203
    system.
 
204
 
 
205
    The returned value is equal to the default pixmap depth.
 
206
 
 
207
    \sa QPixmap::defaultDepth()
 
208
*/
 
209
 
 
210
int QColor::numBitPlanes()
 
211
{
 
212
    return QPaintDevice::x11AppDepth();
 
213
}
 
214
 
 
215
 
 
216
/*!
 
217
    Internal initialization required for QColor.
 
218
    This function is called from the QApplication constructor.
 
219
 
 
220
    \sa cleanup()
 
221
*/
 
222
 
 
223
void QColor::initialize()
 
224
{
 
225
    static const int blackIdx = 2;
 
226
    static const int whiteIdx = 3;
 
227
 
 
228
    if ( color_init )                           // already initialized
 
229
        return;
 
230
    color_init = true;
 
231
 
 
232
    Display *dpy  = QPaintDevice::x11AppDisplay();
 
233
    int      spec = QApplication::colorSpec();
 
234
 
 
235
    screencount = ScreenCount( dpy );
 
236
    screendata = new QColorScreenData*[ screencount ];
 
237
 
 
238
    int scr = QPaintDevice::x11AppScreen();
 
239
 
 
240
    for ( scr = 0; scr < screencount; ++scr ) {
 
241
        screendata[scr] = new QColorScreenData;
 
242
        screendata[scr]->g_vis = (Visual *) QPaintDevice::x11AppVisual( scr );
 
243
        screendata[scr]->g_truecolor = screendata[scr]->g_vis->c_class == TrueColor;
 
244
 
 
245
        int          ncols= QPaintDevice::x11AppCells( scr );
 
246
 
 
247
        if ( screendata[scr]->g_truecolor ) {
 
248
            colormodel = d32;
 
249
        } else {
 
250
            colormodel = d8;
 
251
            // Create the g_our_alloc array, which remembers which color pixels
 
252
            // we allocated.
 
253
            screendata[scr]->g_cells = qMin(ncols,256);
 
254
            screendata[scr]->g_carr  = new XColor[screendata[scr]->g_cells];
 
255
            Q_CHECK_PTR( screendata[scr]->g_carr );
 
256
            memset( screendata[scr]->g_carr, 0,
 
257
                    screendata[scr]->g_cells*sizeof(XColor) );
 
258
            screendata[scr]->g_carr_fetch = true;       // run XQueryColors on demand
 
259
            screendata[scr]->g_our_alloc = new bool[screendata[scr]->g_cells];
 
260
            Q_CHECK_PTR( screendata[scr]->g_our_alloc );
 
261
            memset( screendata[scr]->g_our_alloc, false,
 
262
                    screendata[scr]->g_cells*sizeof(bool) );
 
263
            XColor *xc = &screendata[scr]->g_carr[0];
 
264
            for ( int i=0; i<screendata[scr]->g_cells; i++ ) {
 
265
                xc->pixel = i;          // g_carr[i] = color i
 
266
                xc++;
 
267
            }
 
268
        }
 
269
 
 
270
        int dictsize;
 
271
        if ( screendata[scr]->g_truecolor ) {                   // truecolor
 
272
            dictsize    = 1;                    // will not need color dict
 
273
            screendata[scr]->red_mask    = (uint)screendata[scr]->g_vis->red_mask;
 
274
            screendata[scr]->green_mask  = (uint)screendata[scr]->g_vis->green_mask;
 
275
            screendata[scr]->blue_mask   = (uint)screendata[scr]->g_vis->blue_mask;
 
276
            screendata[scr]->red_shift =
 
277
                highest_bit( screendata[scr]->red_mask ) - 7;
 
278
            screendata[scr]->green_shift =
 
279
                highest_bit( screendata[scr]->green_mask ) - 7;
 
280
            screendata[scr]->blue_shift =
 
281
                highest_bit( screendata[scr]->blue_mask ) - 7;
 
282
        } else {
 
283
            dictsize = col_std_dict;
 
284
        }
 
285
#if 0
 
286
        screendata[scr]->colorDict = new QColorDict(dictsize);  // create dictionary
 
287
        Q_CHECK_PTR( screendata[scr]->colorDict );
 
288
#endif
 
289
 
 
290
        if ( spec == (int)QApplication::ManyColor ) {
 
291
            screendata[scr]->color_reduce = true;
 
292
 
 
293
            switch ( qt_ncols_option ) {
 
294
            case 216:
 
295
                // 6:6:6
 
296
                screendata[scr]->col_div_r = screendata[scr]->col_div_g =
 
297
                screendata[scr]->col_div_b = (255/(6-1));
 
298
                break;
 
299
            default: {
 
300
                // 2:3:1 proportions, solved numerically
 
301
                if ( qt_ncols_option > 255 ) qt_ncols_option = 255;
 
302
                if ( qt_ncols_option < 1 ) qt_ncols_option = 1;
 
303
                int nr = 2;
 
304
                int ng = 2;
 
305
                int nb = 2;
 
306
                for (;;) {
 
307
                    if ( nb*2 < nr && (nb+1)*nr*ng < qt_ncols_option )
 
308
                        nb++;
 
309
                    else if ( nr*3 < ng*2 && nb*(nr+1)*ng < qt_ncols_option )
 
310
                        nr++;
 
311
                    else if ( nb*nr*(ng+1) < qt_ncols_option )
 
312
                        ng++;
 
313
                    else break;
 
314
                }
 
315
                qt_ncols_option = nr*ng*nb;
 
316
                screendata[scr]->col_div_r = (255/(nr-1));
 
317
                screendata[scr]->col_div_g = (255/(ng-1));
 
318
                screendata[scr]->col_div_b = (255/(nb-1));
 
319
            }
 
320
            }
 
321
        }
 
322
    }
 
323
 
 
324
    scr = QPaintDevice::x11AppScreen();
 
325
 
 
326
    // Initialize global color objects
 
327
    if ( QPaintDevice::x11AppDefaultVisual(scr) &&
 
328
         QPaintDevice::x11AppDefaultColormap(scr) ) {
 
329
        globalColors()[blackIdx].setPixel((uint) BlackPixel(dpy, scr));
 
330
        globalColors()[whiteIdx].setPixel((uint) WhitePixel(dpy, scr));
 
331
    } else {
 
332
        globalColors()[blackIdx].alloc(scr);
 
333
        globalColors()[whiteIdx].alloc(scr);
 
334
    }
 
335
 
 
336
#if 0 /* 0 == allocate colors on demand */
 
337
    setLazyAlloc( false );                      // allocate global colors
 
338
    ((QColor*)(&darkGray))->    alloc();
 
339
    ((QColor*)(&gray))->        alloc();
 
340
    ((QColor*)(&lightGray))->   alloc();
 
341
    ((QColor*)(&::red))->       alloc();
 
342
    ((QColor*)(&::green))->     alloc();
 
343
    ((QColor*)(&::blue))->      alloc();
 
344
    ((QColor*)(&cyan))->        alloc();
 
345
    ((QColor*)(&magenta))->     alloc();
 
346
    ((QColor*)(&yellow))->      alloc();
 
347
    ((QColor*)(&darkRed))->     alloc();
 
348
    ((QColor*)(&darkGreen))->   alloc();
 
349
    ((QColor*)(&darkBlue))->    alloc();
 
350
    ((QColor*)(&darkCyan))->    alloc();
 
351
    ((QColor*)(&darkMagenta))-> alloc();
 
352
    ((QColor*)(&darkYellow))->  alloc();
 
353
    setLazyAlloc( true );
 
354
#endif
 
355
}
 
356
 
 
357
/*!
 
358
    Internal clean up required for QColor.
 
359
    This function is called from the QApplication destructor.
 
360
 
 
361
    \sa initialize()
 
362
*/
 
363
 
 
364
void QColor::cleanup()
 
365
{
 
366
    if ( !color_init )
 
367
        return;
 
368
    color_init = false;
 
369
    int scr;
 
370
    for ( scr = 0; scr < screencount; scr++ ) {
 
371
        if ( screendata[scr]->g_carr ) {
 
372
            delete [] screendata[scr]->g_carr;
 
373
            screendata[scr]->g_carr = 0;
 
374
        }
 
375
        if ( screendata[scr]->g_our_alloc ) {
 
376
            delete [] screendata[scr]->g_our_alloc;
 
377
            screendata[scr]->g_our_alloc = 0;
 
378
        }
 
379
#if 0
 
380
        if ( screendata[scr]->colorDict ) {
 
381
            screendata[scr]->colorDict->setAutoDelete( true );
 
382
            screendata[scr]->colorDict->clear();
 
383
            delete screendata[scr]->colorDict;
 
384
            screendata[scr]->colorDict = 0;
 
385
        }
 
386
#endif
 
387
        delete screendata[scr];
 
388
        screendata[scr] = 0;
 
389
    }
 
390
    delete [] screendata;
 
391
    screendata = 0;
 
392
    screencount = 0;
 
393
}
 
394
 
 
395
 
 
396
/*****************************************************************************
 
397
  QColor member functions
 
398
 *****************************************************************************/
 
399
 
 
400
/*!
 
401
  \internal
 
402
  Allocates the color on screen \a screen.  Only used in X11.
 
403
 
 
404
  \sa alloc(), pixel()
 
405
*/
 
406
uint QColor::alloc( int screen )
 
407
{
 
408
    Display *dpy = QPaintDevice::x11AppDisplay();
 
409
    if ( screen < 0 )
 
410
        screen = QPaintDevice::x11AppScreen();
 
411
    if ( !color_init )
 
412
        return dpy ? (uint)BlackPixel(dpy, screen) : 0;
 
413
    int r = qRed(d.argb);
 
414
    int g = qGreen(d.argb);
 
415
    int b = qBlue(d.argb);
 
416
    uint pix = 0;
 
417
    QColorScreenData *sd = screendata[screen];
 
418
    if ( sd->g_truecolor ) {                    // truecolor: map to pixel
 
419
        r = sd->red_shift   > 0 ? r << sd->red_shift   : r >> -sd->red_shift;
 
420
        g = sd->green_shift > 0 ? g << sd->green_shift : g >> -sd->green_shift;
 
421
        b = sd->blue_shift  > 0 ? b << sd->blue_shift  : b >> -sd->blue_shift;
 
422
        pix = (b & sd->blue_mask) | (g & sd->green_mask) | (r & sd->red_mask)
 
423
              | ~(sd->blue_mask | sd->green_mask | sd->red_mask);
 
424
        if ( screen == QPaintDevice::x11AppScreen() )
 
425
            d.d32.pix = pix;
 
426
        return pix;
 
427
    }
 
428
#if 0
 
429
    QColorData *c = sd->colorDict->find( (long)(d.argb) );
 
430
    if ( c ) {                                  // found color in dictionary
 
431
        pix = c->pix;
 
432
        if ( screen == QPaintDevice::x11AppScreen() ) {
 
433
            d.d8.invalid = false;               // color ok
 
434
            d.d8.dirty = false;
 
435
            d.d8.pix = pix;                     // use same pixel value
 
436
            if ( c->context != current_alloc_context ) {
 
437
                c->context = 0;                 // convert to default context
 
438
                sd->g_our_alloc[pix] = true;    // reuse without XAllocColor
 
439
            }
 
440
        }
 
441
        return pix;
 
442
    }
 
443
#endif
 
444
 
 
445
    XColor col;
 
446
    col.red   = r << 8;
 
447
    col.green = g << 8;
 
448
    col.blue  = b << 8;
 
449
 
 
450
    bool try_again = false;
 
451
    bool try_alloc = !sd->color_reduce;
 
452
    int  try_count = 0;
 
453
 
 
454
    do {
 
455
        // This loop is run until we manage to either allocate or
 
456
        // find an approximate color, it stops after a few iterations.
 
457
 
 
458
        try_again = false;
 
459
 
 
460
        if ( try_alloc && sd->colors_avail &&
 
461
             XAllocColor(dpy, QPaintDevice::x11AppColormap( screen ),&col) ) {
 
462
            // We could allocate the color
 
463
            pix = (uint) col.pixel;
 
464
            if ( screen == QPaintDevice::x11AppScreen() ) {
 
465
                d.d8.pix = pix;
 
466
                d.d8.invalid = false;
 
467
                d.d8.dirty = false;
 
468
                sd->g_carr[d.d8.pix] = col;             // update color array
 
469
                if ( current_alloc_context == 0 )
 
470
                    sd->g_our_alloc[d.d8.pix] = true;   // reuse without XAllocColor
 
471
            }
 
472
        } else {
 
473
            // No available colors, or we did not want to allocate one
 
474
            int i;
 
475
            sd->colors_avail = false;           // no more available colors
 
476
            if ( sd->g_carr_fetch ) {           // refetch color array
 
477
                sd->g_carr_fetch = false;
 
478
                XQueryColors( dpy, QPaintDevice::x11AppColormap( screen ), sd->g_carr,
 
479
                              sd->g_cells );
 
480
            }
 
481
            int mindist;
 
482
            i = find_nearest_color( r, g, b, &mindist, sd );
 
483
 
 
484
            if ( mindist != 0 && !try_alloc ) {
 
485
                // Not an exact match with an existing color
 
486
                int rr = ((r+sd->col_div_r/2)/sd->col_div_r)*sd->col_div_r;
 
487
                int rg = ((g+sd->col_div_g/2)/sd->col_div_g)*sd->col_div_g;
 
488
                int rb = ((b+sd->col_div_b/2)/sd->col_div_b)*sd->col_div_b;
 
489
                int rx = rr - r;
 
490
                int gx = rg - g;
 
491
                int bx = rb - b;
 
492
                int dist = rx*rx + gx*gx + bx*bx; // calculate distance
 
493
                if ( dist < mindist ) {
 
494
                    // reduced color is closer - try to alloc it
 
495
                    r = rr;
 
496
                    g = rg;
 
497
                    b = rb;
 
498
                    col.red   = r << 8;
 
499
                    col.green = g << 8;
 
500
                    col.blue  = b << 8;
 
501
                    try_alloc = true;
 
502
                    try_again = true;
 
503
                    sd->colors_avail = true;
 
504
                    continue; // Try alloc reduced color
 
505
                }
 
506
            }
 
507
 
 
508
            if ( i == -1 ) {                    // no nearest color?!
 
509
                int unused, value;
 
510
                hsv(&unused, &unused, &value);
 
511
                if (value < 128) { // dark, use black
 
512
                    d.argb = qRgb(0,0,0);
 
513
                    pix = (uint)BlackPixel( dpy, screen );
 
514
                    if ( screen == QPaintDevice::x11AppScreen() ) {
 
515
                        d.d8.invalid = false;
 
516
                        d.d8.dirty = false;
 
517
                        d.d8.pix = pix;
 
518
                    }
 
519
                } else { // light, use white
 
520
                    d.argb = qRgb(0xff,0xff,0xff);
 
521
                    pix = (uint)WhitePixel( dpy, screen );
 
522
                    if ( screen == QPaintDevice::x11AppScreen() ) {
 
523
                        d.d8.invalid = false;
 
524
                        d.d8.dirty = false;
 
525
                        d.d8.pix = pix;
 
526
                    }
 
527
                }
 
528
                return pix;
 
529
            }
 
530
            if ( sd->g_our_alloc[i] ) {         // we've already allocated it
 
531
                ; // i == g_carr[i].pixel
 
532
            } else {
 
533
                // Try to allocate existing color
 
534
                col = sd->g_carr[i];
 
535
                if ( XAllocColor(dpy, QPaintDevice::x11AppColormap( screen ), &col) ) {
 
536
                    i = (uint)col.pixel;
 
537
                    sd->g_carr[i] = col;                // update color array
 
538
                    if ( screen == QPaintDevice::x11AppScreen() ) {
 
539
                        if ( current_alloc_context == 0 )
 
540
                            sd->g_our_alloc[i] = true;  // only in the default context
 
541
                    }
 
542
                } else {
 
543
                    // Oops, it's gone again
 
544
                    try_count++;
 
545
                    try_again    = true;
 
546
                    sd->colors_avail = true;
 
547
                    sd->g_carr_fetch = true;
 
548
                }
 
549
            }
 
550
            if ( !try_again ) {                         // got it
 
551
                pix = (uint)sd->g_carr[i].pixel;
 
552
                if ( screen == QPaintDevice::x11AppScreen() ) {
 
553
                    d.d8.invalid = false;
 
554
                    d.d8.dirty = false;
 
555
                    d.d8.pix = pix;                     // allocated X11 color
 
556
                }
 
557
            }
 
558
        }
 
559
 
 
560
    } while ( try_again && try_count < 2 );
 
561
 
 
562
    if ( try_again ) {                          // no hope of allocating color
 
563
        int unused, value;
 
564
        hsv(&unused, &unused, &value);
 
565
        if (value < 128) { // dark, use black
 
566
            d.argb = qRgb(0,0,0);
 
567
            pix = (uint)BlackPixel( dpy, screen );
 
568
            if ( screen == QPaintDevice::x11AppScreen() ) {
 
569
                d.d8.invalid = false;
 
570
                d.d8.dirty = false;
 
571
                d.d8.pix = pix;
 
572
            }
 
573
        } else { // light, use white
 
574
            d.argb = qRgb(0xff,0xff,0xff);
 
575
            pix = (uint)WhitePixel( dpy, screen );
 
576
            if ( screen == QPaintDevice::x11AppScreen() ) {
 
577
                d.d8.invalid = false;
 
578
                d.d8.dirty = false;
 
579
                d.d8.pix = pix;
 
580
            }
 
581
        }
 
582
        return pix;
 
583
    }
 
584
#if 0
 
585
    // All colors outside context 0 must go into the dictionary
 
586
    bool many = sd->colorDict->count() >= sd->colorDict->size() * 8;
 
587
    if ( many && sd->colorDict->size() == col_std_dict ) {
 
588
        sd->colorDict->resize( col_large_dict );
 
589
    }
 
590
    if ( !many || current_alloc_context != 0 ) {
 
591
        c = new QColorData;                     // insert into color dict
 
592
        Q_CHECK_PTR( c );
 
593
        c->pix     = pix;
 
594
        c->context = current_alloc_context;
 
595
        sd->colorDict->insert( (long)d.argb, c );       // store color in dict
 
596
    }
 
597
#endif
 
598
    return pix;
 
599
}
 
600
 
 
601
/*!
 
602
  Allocates the RGB color and returns the pixel value.
 
603
 
 
604
  Allocating a color means to obtain a pixel value from the RGB
 
605
  specification.  The pixel value is an index into the global color
 
606
  table, but should be considered an arbitrary platform-dependent value.
 
607
 
 
608
  The pixel() function calls alloc() if necessary, so in general you
 
609
  don't need to call this function.
 
610
 
 
611
  \sa enterAllocContext()
 
612
*/
 
613
// ### 4.0 - remove me?
 
614
uint QColor::alloc()
 
615
{
 
616
    return alloc( -1 );
 
617
}
 
618
 
 
619
/*!
 
620
    \overload
 
621
 
 
622
  Returns the pixel value for screen \a screen.
 
623
 
 
624
  This value is used by the underlying window system to refer to a color.
 
625
  It can be thought of as an index into the display hardware's color table,
 
626
  but the value is an arbitrary 32-bit value.
 
627
 
 
628
  \sa alloc()
 
629
*/
 
630
uint QColor::pixel( int screen ) const
 
631
{
 
632
    if (screen != QPaintDevice::x11AppScreen() &&
 
633
        // don't allocate color0 or color1, they have fixed pixel
 
634
        // values for all screens
 
635
        d.argb != qRgba(255, 255, 255, 1) && d.argb != qRgba(0, 0, 0, 1))
 
636
        return ((QColor*)this)->alloc( screen );
 
637
    return pixel();
 
638
}
 
639
 
 
640
#if 0
 
641
void QColor::setSystemNamedColor( const QString& name )
 
642
#else
 
643
void QColor::setSystemNamedColor( const char* name )
 
644
#endif
 
645
{
 
646
    // setSystemNamedColor should look up rgb values from the built in
 
647
    // color tables first (see qcolor_p.cpp), and failing that, use
 
648
    // the window system's interface for translating names to rgb values...
 
649
    // we do this so that things like uic can load an XPM file with named colors
 
650
    // and convert it to a png without having to use window system functions...
 
651
#if 0
 
652
    d.argb = qt_get_rgb_val( name.latin1() );
 
653
#else
 
654
    d.argb = qt_get_rgb_val( name );
 
655
#endif
 
656
    QRgb rgb;
 
657
#if 0
 
658
    if ( qt_get_named_rgb( name.latin1(), &rgb ) ) {
 
659
#else
 
660
    if ( qt_get_named_rgb( name, &rgb ) ) {
 
661
#endif
 
662
        setRgb( qRed(rgb), qGreen(rgb), qBlue(rgb) );
 
663
        if ( colormodel == d8 ) {
 
664
            d.d8.invalid = false;
 
665
            d.d8.dirty = true;
 
666
            d.d8.pix = 0;
 
667
        } else {
 
668
            alloc();
 
669
        }
 
670
    } else if ( !color_init ) {
 
671
#if defined(QT_CHECK_STATE)
 
672
        qWarning( "QColor::setSystemNamedColor: Cannot perform this operation "
 
673
                  "because QApplication does not exist" );
 
674
#endif
 
675
        // set color to invalid
 
676
        *this = QColor();
 
677
    } else {
 
678
        XColor col, hw_col;
 
679
        if ( XLookupColor(QPaintDevice::x11AppDisplay(),
 
680
#if 0
 
681
                          QPaintDevice::x11AppColormap(), name.latin1(),
 
682
#else
 
683
                          QPaintDevice::x11AppColormap(), name,
 
684
#endif
 
685
                          &col, &hw_col) ) {
 
686
            setRgb( col.red>>8, col.green>>8, col.blue>>8 );
 
687
        } else {
 
688
            // set color to invalid
 
689
            *this = QColor();
 
690
        }
 
691
    }
 
692
}
 
693
 
 
694
#define MAX_CONTEXTS 16
 
695
static int  context_stack[MAX_CONTEXTS];
 
696
static int  context_ptr = 0;
 
697
 
 
698
static void init_context_stack()
 
699
{
 
700
    static bool did_init = false;
 
701
    if ( !did_init ) {
 
702
        did_init = true;
 
703
        context_stack[0] = current_alloc_context = 0;
 
704
    }
 
705
}
 
706
 
 
707
 
 
708
/*!
 
709
    Enters a color allocation context and returns a non-zero unique
 
710
    identifier.
 
711
 
 
712
    Color allocation contexts are useful for programs that need to
 
713
    allocate many colors and throw them away later, like image
 
714
    viewers. The allocation context functions work for true color
 
715
    displays as well as for colormap displays, except that
 
716
    QColor::destroyAllocContext() does nothing for true color.
 
717
 
 
718
    Example:
 
719
    \code
 
720
    QPixmap loadPixmap( QString fileName )
 
721
    {
 
722
        static int alloc_context = 0;
 
723
        if ( alloc_context )
 
724
            QColor::destroyAllocContext( alloc_context );
 
725
        alloc_context = QColor::enterAllocContext();
 
726
        QPixmap pm( fileName );
 
727
        QColor::leaveAllocContext();
 
728
        return pm;
 
729
    }
 
730
    \endcode
 
731
 
 
732
    The example code loads a pixmap from file. It frees up all colors
 
733
    that were allocated the last time loadPixmap() was called.
 
734
 
 
735
    The initial/default context is 0. Qt keeps a list of colors
 
736
    associated with their allocation contexts. You can call
 
737
    destroyAllocContext() to get rid of all colors that were allocated
 
738
    in a specific context.
 
739
 
 
740
    Calling enterAllocContext() enters an allocation context. The
 
741
    allocation context lasts until you call leaveAllocContext().
 
742
    QColor has an internal stack of allocation contexts. Each call to
 
743
    enterAllocContex() must have a corresponding leaveAllocContext().
 
744
 
 
745
    \code
 
746
        // context 0 active
 
747
    int c1 = QColor::enterAllocContext();    // enter context c1
 
748
        // context c1 active
 
749
    int c2 = QColor::enterAllocContext();    // enter context c2
 
750
        // context c2 active
 
751
    QColor::leaveAllocContext();             // leave context c2
 
752
        // context c1 active
 
753
    QColor::leaveAllocContext();             // leave context c1
 
754
        // context 0 active
 
755
        // Now, free all colors that were allocated in context c2
 
756
    QColor::destroyAllocContext( c2 );
 
757
    \endcode
 
758
 
 
759
    You may also want to set the application's color specification.
 
760
    See QApplication::setColorSpec() for more information.
 
761
 
 
762
    \sa leaveAllocContext(), currentAllocContext(), destroyAllocContext(),
 
763
    QApplication::setColorSpec()
 
764
*/
 
765
 
 
766
int QColor::enterAllocContext()
 
767
{
 
768
    static int context_seq_no = 0;
 
769
    init_context_stack();
 
770
    if ( context_ptr+1 == MAX_CONTEXTS ) {
 
771
#if defined(QT_CHECK_STATE)
 
772
        qWarning( "QColor::enterAllocContext: Context stack overflow" );
 
773
#endif
 
774
        return 0;
 
775
    }
 
776
    current_alloc_context = context_stack[++context_ptr] = ++context_seq_no;
 
777
    return current_alloc_context;
 
778
}
 
779
 
 
780
 
 
781
/*!
 
782
    Leaves a color allocation context.
 
783
 
 
784
    See enterAllocContext() for a detailed explanation.
 
785
 
 
786
    \sa enterAllocContext(), currentAllocContext()
 
787
*/
 
788
 
 
789
void QColor::leaveAllocContext()
 
790
{
 
791
    init_context_stack();
 
792
    if ( context_ptr == 0 ) {
 
793
#if defined(QT_CHECK_STATE)
 
794
        qWarning( "QColor::leaveAllocContext: Context stack underflow" );
 
795
#endif
 
796
        return;
 
797
    }
 
798
    current_alloc_context = context_stack[--context_ptr];
 
799
}
 
800
 
 
801
 
 
802
/*!
 
803
    Returns the current color allocation context.
 
804
 
 
805
    The default context is 0.
 
806
 
 
807
    \sa enterAllocContext(), leaveAllocContext()
 
808
*/
 
809
 
 
810
int QColor::currentAllocContext()
 
811
{
 
812
    return current_alloc_context;
 
813
}
 
814
 
 
815
 
 
816
/*!
 
817
    Destroys a color allocation context, \e context.
 
818
 
 
819
    This function deallocates all colors that were allocated in the
 
820
    specified \a context. If \a context == -1, it frees up all colors
 
821
    that the application has allocated. If \a context == -2, it frees
 
822
    up all colors that the application has allocated, except those in
 
823
    the default context.
 
824
 
 
825
    The function does nothing for true color displays.
 
826
 
 
827
    \sa enterAllocContext(), alloc()
 
828
*/
 
829
 
 
830
void QColor::destroyAllocContext( int context )
 
831
{
 
832
    init_context_stack();
 
833
    if ( !color_init )
 
834
        return;
 
835
 
 
836
    int screen;
 
837
    for ( screen = 0; screen < screencount; ++screen ) {
 
838
        if ( screendata[screen]->g_truecolor )
 
839
            continue;
 
840
 
 
841
#if 1
 
842
        Q_UNUSED(context);
 
843
#else
 
844
        ulong pixels[256];
 
845
        bool freeing[256];
 
846
        memset( freeing, false, screendata[screen]->g_cells*sizeof(bool) );
 
847
        QColorData   *d;
 
848
        QColorDictIt it( *screendata[screen]->colorDict );
 
849
        int i = 0;
 
850
        uint rgbv;
 
851
        while ( (d=it.current()) ) {
 
852
            rgbv = (uint)it.currentKey();
 
853
            if ( (d->context || context==-1) &&
 
854
                 (d->context == context || context < 0) ) {
 
855
                if ( !screendata[screen]->g_our_alloc[d->pix] && !freeing[d->pix] ) {
 
856
                    // will free this color
 
857
                    pixels[i++] = d->pix;
 
858
                    freeing[d->pix] = true;
 
859
                }
 
860
                // remove from dict
 
861
                screendata[screen]->colorDict->remove( (long)rgbv );
 
862
            }
 
863
            ++it;
 
864
        }
 
865
        if ( i )
 
866
            XFreeColors( QPaintDevice::x11AppDisplay(),
 
867
                         QPaintDevice::x11AppColormap( screen ),
 
868
                         pixels, i, 0 );
 
869
#endif
 
870
    }
 
871
}