diff options
Diffstat (limited to 'experimental/tqtinterface/qt4/src/kernel/tqcolor_x11.cpp')
-rw-r--r-- | experimental/tqtinterface/qt4/src/kernel/tqcolor_x11.cpp | 1336 |
1 files changed, 1336 insertions, 0 deletions
diff --git a/experimental/tqtinterface/qt4/src/kernel/tqcolor_x11.cpp b/experimental/tqtinterface/qt4/src/kernel/tqcolor_x11.cpp new file mode 100644 index 000000000..909ecbb08 --- /dev/null +++ b/experimental/tqtinterface/qt4/src/kernel/tqcolor_x11.cpp @@ -0,0 +1,1336 @@ +/**************************************************************************** +** +** Implementation of TQColor class for X11 +** +** Created : 940112 +** +** Copyright (C) 2010 Timothy Pearson and (C) 1992-2008 Trolltech ASA. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file. Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "tqcolor.h" +#include "tqcolor_p.h" +#include "string.h" +#include "tqpaintdevice.h" +#include "tqapplication.h" +#include "tqapplication_p.h" +#include "tqt_x11_p.h" + +#ifdef USE_QT4 + +#include "tqintdict.h" + +static const uint col_std_dict = 419; +static const uint col_large_dict = 18397; + +struct TQColorData { + uint pix; // allocated pixel value + int context; // allocation context +}; + +typedef TQIntDict<TQColorData> TQColorDict; +typedef TQIntDictIterator<TQColorData> TQColorDictIt; + +static int current_alloc_context = 0; // current color alloc context + +class TQColorScreenData { +public: + TQColorScreenData() + { + colorDict = 0; + colors_avail = TRUE; + g_vis = 0; + g_carr = 0; + g_carr_fetch = TRUE; + g_cells = 0; + g_our_alloc = 0; + color_reduce = FALSE; + } + + TQColorDict *colorDict; // dict of allocated colors + bool colors_avail; // X colors available + bool g_truecolor; // truecolor visual + Visual *g_vis; // visual + XColor *g_carr; // color array + bool g_carr_fetch; // perform XQueryColors? + int g_cells; // number of entries in g_carr + bool *g_our_alloc; // our allocated colors + uint red_mask , green_mask , blue_mask; + int red_shift, green_shift, blue_shift; + bool color_reduce; + int col_div_r; + int col_div_g; + int col_div_b; +}; + +static int screencount = 0; +static TQColorScreenData **screendata = 0; // array of screendata pointers + +#define MAX_CONTEXTS 16 +static int context_stack[MAX_CONTEXTS]; +static int context_ptr = 0; + +static void init_context_stack() +{ + static bool did_init = FALSE; + if ( !did_init ) { + did_init = TRUE; + context_stack[0] = current_alloc_context = 0; + } +} + +/* + This function is called from the event loop. It resets the colors_avail + flag so that the application can retry to allocate read-only colors + that other applications may have deallocated lately. + + The g_our_alloc and g_carr are global arrays that optimize color + approximation when there are no more colors left to allocate. +*/ + +void qt_reset_color_avail() +{ + int i; + for ( i = 0; i < screencount; i++ ) { + screendata[i]->colors_avail = TRUE; + screendata[i]->g_carr_fetch = TRUE; // do XQueryColors if !colors_avail + } +} + +/*! + Enters a color allocation context and returns a non-zero unique + identifier. + + Color allocation contexts are useful for programs that need to + allocate many colors and throw them away later, like image + viewers. The allocation context functions work for true color + displays as well as for colormap displays, except that + TQColor::destroyAllocContext() does nothing for true color. + + Example: + \code + TQPixmap loadPixmap( TQString fileName ) + { + static int alloc_context = 0; + if ( alloc_context ) + TQColor::destroyAllocContext( alloc_context ); + alloc_context = TQColor::enterAllocContext(); + TQPixmap pm( fileName ); + TQColor::leaveAllocContext(); + return pm; + } + \endcode + + The example code loads a pixmap from file. It frees up all colors + that were allocated the last time loadPixmap() was called. + + The initial/default context is 0. TQt keeps a list of colors + associated with their allocation contexts. You can call + destroyAllocContext() to get rid of all colors that were allocated + in a specific context. + + Calling enterAllocContext() enters an allocation context. The + allocation context lasts until you call leaveAllocContext(). + TQColor has an internal stack of allocation contexts. Each call to + enterAllocContex() must have a corresponding leaveAllocContext(). + + \code + // context 0 active + int c1 = TQColor::enterAllocContext(); // enter context c1 + // context c1 active + int c2 = TQColor::enterAllocContext(); // enter context c2 + // context c2 active + TQColor::leaveAllocContext(); // leave context c2 + // context c1 active + TQColor::leaveAllocContext(); // leave context c1 + // context 0 active + // Now, free all colors that were allocated in context c2 + TQColor::destroyAllocContext( c2 ); + \endcode + + You may also want to set the application's color specification. + See TQApplication::setColorSpec() for more information. + + \sa leaveAllocContext(), currentAllocContext(), destroyAllocContext(), + TQApplication::setColorSpec() +*/ + +int TQColor::enterAllocContext() +{ + static int context_seq_no = 0; + init_context_stack(); + if ( context_ptr+1 == MAX_CONTEXTS ) { +#if defined(TQT_CHECK_STATE) + qWarning( "TQColor::enterAllocContext: Context stack overflow" ); +#endif + return 0; + } + current_alloc_context = context_stack[++context_ptr] = ++context_seq_no; + return current_alloc_context; +} + + +/*! + Leaves a color allocation context. + + See enterAllocContext() for a detailed explanation. + + \sa enterAllocContext(), currentAllocContext() +*/ + +void TQColor::leaveAllocContext() +{ + init_context_stack(); + if ( context_ptr == 0 ) { +#if defined(TQT_CHECK_STATE) + qWarning( "TQColor::leaveAllocContext: Context stack underflow" ); +#endif + return; + } + current_alloc_context = context_stack[--context_ptr]; +} + + +/*! + Returns the current color allocation context. + + The default context is 0. + + \sa enterAllocContext(), leaveAllocContext() +*/ + +int TQColor::currentAllocContext() +{ + return current_alloc_context; +} + + +/*! + Destroys a color allocation context, \e context. + + This function deallocates all colors that were allocated in the + specified \a context. If \a context == -1, it frees up all colors + that the application has allocated. If \a context == -2, it frees + up all colors that the application has allocated, except those in + the default context. + + The function does nothing for true color displays. + + \sa enterAllocContext(), alloc() +*/ + +void TQColor::destroyAllocContext( int context ) +{ + init_context_stack(); + if ( !color_init ) + return; + + int screen; + for ( screen = 0; screen < screencount; ++screen ) { + if ( screendata[screen]->g_truecolor ) + continue; + + ulong pixels[256]; + bool freeing[256]; + memset( freeing, FALSE, screendata[screen]->g_cells*sizeof(bool) ); + TQColorData *d; + TQColorDictIt it( *screendata[screen]->colorDict ); + int i = 0; + uint rgbv; + while ( (d=it.current()) ) { + rgbv = (uint)it.currentKey(); + if ( (d->context || context==-1) && + (d->context == context || context < 0) ) { + if ( !screendata[screen]->g_our_alloc[d->pix] && !freeing[d->pix] ) { + // will free this color + pixels[i++] = d->pix; + freeing[d->pix] = TRUE; + } + // remove from dict + screendata[screen]->colorDict->remove( (long)rgbv ); + } + ++it; + } + if ( i ) + XFreeColors( TQPaintDevice::x11AppDisplay(), + TQPaintDevice::x11AppColormap( screen ), + pixels, i, 0 ); + } +} + +/*! + Returns the number of color bit planes for the underlying window + system. + + The returned value is equal to the default pixmap depth. + + \sa TQPixmap::defaultDepth() +*/ + +int TQColor::numBitPlanes() +{ + return TQPaintDevice::x11AppDepth(); +} + +/* + Finds the nearest color. +*/ + +static int tqfind_nearest_color( int r, int g, int b, int* mindist_out, + TQColorScreenData *sd ) +{ + int mincol = -1; + int mindist = 200000; + int rx, gx, bx, dist; + XColor *xc = &sd->g_carr[0]; + for ( int i=0; i<sd->g_cells; i++ ) { + rx = r - (xc->red >> 8); + gx = g - (xc->green >> 8); + bx = b - (xc->blue>> 8); + dist = rx*rx + gx*gx + bx*bx; // calculate distance + if ( dist < mindist ) { // minimal? + mindist = dist; + mincol = i; + } + xc++; + } + *mindist_out = mindist; + return mincol; +} + +/*! + \internal + Allocates the color on screen \a screen. Only used in X11. + + \sa alloc(), pixel() +*/ +uint TQColor::alloc( int screen ) +{ + Display *dpy = TQPaintDevice::x11AppDisplay(); + if ( screen < 0 ) + screen = TQPaintDevice::x11AppScreen(); + if ( !color_init ) + return dpy ? (uint)BlackPixel(dpy, screen) : 0; + int r = tqRed(d.argb); + int g = tqGreen(d.argb); + int b = tqBlue(d.argb); + uint pix = 0; + TQColorScreenData *sd = screendata[screen]; + if ( sd->g_truecolor ) { // truecolor: map to pixel + r = sd->red_shift > 0 ? r << sd->red_shift : r >> -sd->red_shift; + g = sd->green_shift > 0 ? g << sd->green_shift : g >> -sd->green_shift; + b = sd->blue_shift > 0 ? b << sd->blue_shift : b >> -sd->blue_shift; + pix = (b & sd->blue_mask) | (g & sd->green_mask) | (r & sd->red_mask) + | ~(sd->blue_mask | sd->green_mask | sd->red_mask); + if ( screen == TQPaintDevice::x11AppScreen() ) + d.d32.pix = pix; + return pix; + } + TQColorData *c = sd->colorDict->tqfind( (long)(d.argb) ); + if ( c ) { // found color in dictionary + pix = c->pix; + if ( screen == TQPaintDevice::x11AppScreen() ) { + d.d8.invalid = FALSE; // color ok + d.d8.dirty = FALSE; + d.d8.pix = pix; // use same pixel value + if ( c->context != current_alloc_context ) { + c->context = 0; // convert to default context + sd->g_our_alloc[pix] = TRUE; // reuse without XAllocColor + } + } + return pix; + } + + XColor col; + col.red = r << 8; + col.green = g << 8; + col.blue = b << 8; + + bool try_again = FALSE; + bool try_alloc = !sd->color_reduce; + int try_count = 0; + + do { + // This loop is run until we manage to either allocate or + // tqfind an approximate color, it stops after a few iterations. + + try_again = FALSE; + + if ( try_alloc && sd->colors_avail && + XAllocColor(dpy, TQPaintDevice::x11AppColormap( screen ),&col) ) { + // We could allocate the color + pix = (uint) col.pixel; + if ( screen == TQPaintDevice::x11AppScreen() ) { + d.d8.pix = pix; + d.d8.invalid = FALSE; + d.d8.dirty = FALSE; + sd->g_carr[d.d8.pix] = col; // update color array + if ( current_alloc_context == 0 ) + sd->g_our_alloc[d.d8.pix] = TRUE; // reuse without XAllocColor + } + } else { + // No available colors, or we did not want to allocate one + int i; + sd->colors_avail = FALSE; // no more available colors + if ( sd->g_carr_fetch ) { // refetch color array + sd->g_carr_fetch = FALSE; + XQueryColors( dpy, TQPaintDevice::x11AppColormap( screen ), sd->g_carr, + sd->g_cells ); + } + int mindist; + i = tqfind_nearest_color( r, g, b, &mindist, sd ); + + if ( mindist != 0 && !try_alloc ) { + // Not an exact match with an existing color + int rr = ((r+sd->col_div_r/2)/sd->col_div_r)*sd->col_div_r; + int rg = ((g+sd->col_div_g/2)/sd->col_div_g)*sd->col_div_g; + int rb = ((b+sd->col_div_b/2)/sd->col_div_b)*sd->col_div_b; + int rx = rr - r; + int gx = rg - g; + int bx = rb - b; + int dist = rx*rx + gx*gx + bx*bx; // calculate distance + if ( dist < mindist ) { + // reduced color is closer - try to alloc it + r = rr; + g = rg; + b = rb; + col.red = r << 8; + col.green = g << 8; + col.blue = b << 8; + try_alloc = TRUE; + try_again = TRUE; + sd->colors_avail = TRUE; + continue; // Try alloc reduced color + } + } + + if ( i == -1 ) { // no nearest color?! + int unused, value; + hsv(&unused, &unused, &value); + if (value < 128) { // dark, use black + d.argb = tqRgb(0,0,0); + pix = (uint)BlackPixel( dpy, screen ); + if ( screen == TQPaintDevice::x11AppScreen() ) { + d.d8.invalid = FALSE; + d.d8.dirty = FALSE; + d.d8.pix = pix; + } + } else { // light, use white + d.argb = tqRgb(0xff,0xff,0xff); + pix = (uint)WhitePixel( dpy, screen ); + if ( screen == TQPaintDevice::x11AppScreen() ) { + d.d8.invalid = FALSE; + d.d8.dirty = FALSE; + d.d8.pix = pix; + } + } + return pix; + } + if ( sd->g_our_alloc[i] ) { // we've already allocated it + ; // i == g_carr[i].pixel + } else { + // Try to allocate existing color + col = sd->g_carr[i]; + if ( XAllocColor(dpy, TQPaintDevice::x11AppColormap( screen ), &col) ) { + i = (uint)col.pixel; + sd->g_carr[i] = col; // update color array + if ( screen == TQPaintDevice::x11AppScreen() ) { + if ( current_alloc_context == 0 ) + sd->g_our_alloc[i] = TRUE; // only in the default context + } + } else { + // Oops, it's gone again + try_count++; + try_again = TRUE; + sd->colors_avail = TRUE; + sd->g_carr_fetch = TRUE; + } + } + if ( !try_again ) { // got it + pix = (uint)sd->g_carr[i].pixel; + if ( screen == TQPaintDevice::x11AppScreen() ) { + d.d8.invalid = FALSE; + d.d8.dirty = FALSE; + d.d8.pix = pix; // allocated X11 color + } + } + } + + } while ( try_again && try_count < 2 ); + + if ( try_again ) { // no hope of allocating color + int unused, value; + hsv(&unused, &unused, &value); + if (value < 128) { // dark, use black + d.argb = tqRgb(0,0,0); + pix = (uint)BlackPixel( dpy, screen ); + if ( screen == TQPaintDevice::x11AppScreen() ) { + d.d8.invalid = FALSE; + d.d8.dirty = FALSE; + d.d8.pix = pix; + } + } else { // light, use white + d.argb = tqRgb(0xff,0xff,0xff); + pix = (uint)WhitePixel( dpy, screen ); + if ( screen == TQPaintDevice::x11AppScreen() ) { + d.d8.invalid = FALSE; + d.d8.dirty = FALSE; + d.d8.pix = pix; + } + } + return pix; + } + // All colors outside context 0 must go into the dictionary + bool many = sd->colorDict->count() >= sd->colorDict->size() * 8; + if ( many && sd->colorDict->size() == col_std_dict ) { + sd->colorDict->resize( col_large_dict ); + } + if ( !many || current_alloc_context != 0 ) { + c = new TQColorData; // insert into color dict + TQ_CHECK_PTR( c ); + c->pix = pix; + c->context = current_alloc_context; + sd->colorDict->insert( (long)d.argb, c ); // store color in dict + } + return pix; +} + +/*! + Allocates the RGB color and returns the pixel value. + + Allocating a color means to obtain a pixel value from the RGB + specification. The pixel value is an index into the global color + table, but should be considered an arbitrary platform-dependent value. + + The pixel() function calls alloc() if necessary, so in general you + don't need to call this function. + + \sa enterAllocContext() +*/ +// ### 4.0 - remove me? +uint TQColor::alloc() +{ + return alloc( -1 ); +} + +#else // USE_QT4 + +// NOT REVISED + +/***************************************************************************** + The color dictionary speeds up color allocation significantly for X11. + When there are no more colors, TQColor::alloc() will set the colors_avail + flag to FALSE and try to tqfind the nearest color. + NOTE: From deep within the event loop, the colors_avail flag is reset to + TRUE (calls the function qt_reset_color_avail()), because some other + application might free its colors, thereby making them available for + this TQt application. + *****************************************************************************/ + +#include "tqintdict.h" + +struct TQColorData { + uint pix; // allocated pixel value + int context; // allocation context +}; + +typedef TQIntDict<TQColorData> TQColorDict; +typedef TQIntDictIterator<TQColorData> TQColorDictIt; +static int current_alloc_context = 0; // current color alloc context +static const uint col_std_dict = 419; +static const uint col_large_dict = 18397; + +class TQColorScreenData { +public: + TQColorScreenData() + { + colorDict = 0; + colors_avail = TRUE; + g_vis = 0; + g_carr = 0; + g_carr_fetch = TRUE; + g_cells = 0; + g_our_alloc = 0; + color_reduce = FALSE; + } + + TQColorDict *colorDict; // dict of allocated colors + bool colors_avail; // X colors available + bool g_truecolor; // truecolor visual + Visual *g_vis; // visual + XColor *g_carr; // color array + bool g_carr_fetch; // perform XQueryColors? + int g_cells; // number of entries in g_carr + bool *g_our_alloc; // our allocated colors + uint red_mask , green_mask , blue_mask; + int red_shift, green_shift, blue_shift; + bool color_reduce; + int col_div_r; + int col_div_g; + int col_div_b; +}; + +static int screencount = 0; +static TQColorScreenData **screendata = 0; // array of screendata pointers + + +/* + This function is called from the event loop. It resets the colors_avail + flag so that the application can retry to allocate read-only colors + that other applications may have deallocated lately. + + The g_our_alloc and g_carr are global arrays that optimize color + approximation when there are no more colors left to allocate. +*/ + +void qt_reset_color_avail() +{ + int i; + for ( i = 0; i < screencount; i++ ) { + screendata[i]->colors_avail = TRUE; + screendata[i]->g_carr_fetch = TRUE; // do XQueryColors if !colors_avail + } +} + + +/* + Finds the nearest color. +*/ + +static int tqfind_nearest_color( int r, int g, int b, int* mindist_out, + TQColorScreenData *sd ) +{ + int mincol = -1; + int mindist = 200000; + int rx, gx, bx, dist; + XColor *xc = &sd->g_carr[0]; + for ( int i=0; i<sd->g_cells; i++ ) { + rx = r - (xc->red >> 8); + gx = g - (xc->green >> 8); + bx = b - (xc->blue>> 8); + dist = rx*rx + gx*gx + bx*bx; // calculate distance + if ( dist < mindist ) { // minimal? + mindist = dist; + mincol = i; + } + xc++; + } + *mindist_out = mindist; + return mincol; +} + + +/***************************************************************************** + TQColor misc internal functions + *****************************************************************************/ + +static int highest_bit( uint v ) +{ + int i; + uint b = (uint)1 << 31; // get pos of highest bit in v + for ( i=31; ((b & v) == 0) && i>=0; i-- ) + b >>= 1; + return i; +} + + +/***************************************************************************** + TQColor static member functions + *****************************************************************************/ + +/*! + Returns the maximum number of colors supported by the underlying + window system if the window system uses a palette. + + Otherwise returns -1. Use numBitPlanes() to calculate the available + colors in that case. +*/ + +int TQColor::maxColors() +{ + Visual *visual = (Visual *) TQPaintDevice::x11AppVisual(); + if (visual->c_class & 1) + return TQPaintDevice::x11AppCells(); + return -1; +} + +/*! + Returns the number of color bit planes for the underlying window + system. + + The returned value is equal to the default pixmap depth. + + \sa TQPixmap::defaultDepth() +*/ + +int TQColor::numBitPlanes() +{ + return TQPaintDevice::x11AppDepth(); +} + + +/*! + Internal initialization required for TQColor. + This function is called from the TQApplication constructor. + + \sa cleanup() +*/ + +void TQColor::initialize() +{ + static const int blackIdx = 2; + static const int whiteIdx = 3; + + if ( color_init ) // already initialized + return; + color_init = TRUE; + + Display *dpy = TQPaintDevice::x11AppDisplay(); + int spec = TQApplication::colorSpec(); + + screencount = ScreenCount( dpy ); + screendata = new TQColorScreenData*[ screencount ]; + + int scr; + for ( scr = 0; scr < screencount; ++scr ) { + screendata[scr] = new TQColorScreenData; + screendata[scr]->g_vis = (Visual *) TQPaintDevice::x11AppVisual( scr ); + screendata[scr]->g_truecolor = screendata[scr]->g_vis->c_class == TrueColor + || screendata[scr]->g_vis->c_class == DirectColor; + + int ncols = TQPaintDevice::x11AppCells( scr ); + + if ( screendata[scr]->g_truecolor ) { + if (scr == DefaultScreen(dpy)) + colormodel = d32; + } else { + if (scr == DefaultScreen(dpy)) + colormodel = d8; + + // Create the g_our_alloc array, which remembers which color pixels + // we allocated. + screendata[scr]->g_cells = TQMIN(ncols,256); + screendata[scr]->g_carr = new XColor[screendata[scr]->g_cells]; + TQ_CHECK_PTR( screendata[scr]->g_carr ); + memset( screendata[scr]->g_carr, 0, + screendata[scr]->g_cells*sizeof(XColor) ); + screendata[scr]->g_carr_fetch = TRUE; // run XQueryColors on demand + screendata[scr]->g_our_alloc = new bool[screendata[scr]->g_cells]; + TQ_CHECK_PTR( screendata[scr]->g_our_alloc ); + memset( screendata[scr]->g_our_alloc, FALSE, + screendata[scr]->g_cells*sizeof(bool) ); + XColor *xc = &screendata[scr]->g_carr[0]; + for ( int i=0; i<screendata[scr]->g_cells; i++ ) { + xc->pixel = i; // g_carr[i] = color i + xc++; + } + } + + int dictsize; + if ( screendata[scr]->g_truecolor ) { // truecolor + dictsize = 1; // will not need color dict + screendata[scr]->red_mask = (uint)screendata[scr]->g_vis->red_mask; + screendata[scr]->green_mask = (uint)screendata[scr]->g_vis->green_mask; + screendata[scr]->blue_mask = (uint)screendata[scr]->g_vis->blue_mask; + screendata[scr]->red_shift = + highest_bit( screendata[scr]->red_mask ) - 7; + screendata[scr]->green_shift = + highest_bit( screendata[scr]->green_mask ) - 7; + screendata[scr]->blue_shift = + highest_bit( screendata[scr]->blue_mask ) - 7; + } else { + dictsize = col_std_dict; + } + screendata[scr]->colorDict = new TQColorDict(dictsize); // create dictionary + TQ_CHECK_PTR( screendata[scr]->colorDict ); + + if ( spec == (int)TQApplication::ManyColor ) { + screendata[scr]->color_reduce = TRUE; + + switch ( qt_ncols_option ) { + case 216: + // 6:6:6 + screendata[scr]->col_div_r = screendata[scr]->col_div_g = + screendata[scr]->col_div_b = (255/(6-1)); + break; + default: { + // 2:3:1 proportions, solved numerically + if ( qt_ncols_option > 255 ) qt_ncols_option = 255; + if ( qt_ncols_option < 1 ) qt_ncols_option = 1; + int nr = 2; + int ng = 2; + int nb = 2; + for (;;) { + if ( nb*2 < nr && (nb+1)*nr*ng < qt_ncols_option ) + nb++; + else if ( nr*3 < ng*2 && nb*(nr+1)*ng < qt_ncols_option ) + nr++; + else if ( nb*nr*(ng+1) < qt_ncols_option ) + ng++; + else break; + } + qt_ncols_option = nr*ng*nb; + screendata[scr]->col_div_r = (255/(nr-1)); + screendata[scr]->col_div_g = (255/(ng-1)); + screendata[scr]->col_div_b = (255/(nb-1)); + } + } + } + } + + scr = TQPaintDevice::x11AppScreen(); + + // Initialize global color objects + if ( TQPaintDevice::x11AppDefaultVisual(scr) && + TQPaintDevice::x11AppDefaultColormap(scr) ) { + globalColors()[blackIdx].setPixel((uint) BlackPixel(dpy, scr)); + globalColors()[whiteIdx].setPixel((uint) WhitePixel(dpy, scr)); + } else { + globalColors()[blackIdx].alloc(scr); + globalColors()[whiteIdx].alloc(scr); + } + +#if 0 /* 0 == allocate colors on demand */ + setLazyAlloc( FALSE ); // allocate global colors + ((TQColor*)(&darkGray))-> alloc(); + ((TQColor*)(&gray))-> alloc(); + ((TQColor*)(&lightGray))-> alloc(); + ((TQColor*)(&::red))-> alloc(); + ((TQColor*)(&::green))-> alloc(); + ((TQColor*)(&::blue))-> alloc(); + ((TQColor*)(&cyan))-> alloc(); + ((TQColor*)(&magenta))-> alloc(); + ((TQColor*)(&yellow))-> alloc(); + ((TQColor*)(&darkRed))-> alloc(); + ((TQColor*)(&darkGreen))-> alloc(); + ((TQColor*)(&darkBlue))-> alloc(); + ((TQColor*)(&darkCyan))-> alloc(); + ((TQColor*)(&darkMagenta))-> alloc(); + ((TQColor*)(&darkYellow))-> alloc(); + setLazyAlloc( TRUE ); +#endif +} + +/*! + Internal clean up required for TQColor. + This function is called from the TQApplication destructor. + + \sa initialize() +*/ + +void TQColor::cleanup() +{ + if ( !color_init ) + return; + color_init = FALSE; + int scr; + for ( scr = 0; scr < screencount; scr++ ) { + if ( screendata[scr]->g_carr ) { + delete [] screendata[scr]->g_carr; + screendata[scr]->g_carr = 0; + } + if ( screendata[scr]->g_our_alloc ) { + delete [] screendata[scr]->g_our_alloc; + screendata[scr]->g_our_alloc = 0; + } + if ( screendata[scr]->colorDict ) { + screendata[scr]->colorDict->setAutoDelete( TRUE ); + screendata[scr]->colorDict->clear(); + delete screendata[scr]->colorDict; + screendata[scr]->colorDict = 0; + } + delete screendata[scr]; + screendata[scr] = 0; + } + delete [] screendata; + screendata = 0; + screencount = 0; +} + + +/***************************************************************************** + TQColor member functions + *****************************************************************************/ + +/*! + \internal + Allocates the color on screen \a screen. Only used in X11. + + \sa alloc(), pixel() +*/ +uint TQColor::alloc( int screen ) +{ + Display *dpy = TQPaintDevice::x11AppDisplay(); + if ( screen < 0 ) + screen = TQPaintDevice::x11AppScreen(); + if ( !color_init ) + return dpy ? (uint)BlackPixel(dpy, screen) : 0; + int r = tqRed(d.argb); + int g = tqGreen(d.argb); + int b = tqBlue(d.argb); + uint pix = 0; + TQColorScreenData *sd = screendata[screen]; + if ( sd->g_truecolor ) { // truecolor: map to pixel + r = sd->red_shift > 0 ? r << sd->red_shift : r >> -sd->red_shift; + g = sd->green_shift > 0 ? g << sd->green_shift : g >> -sd->green_shift; + b = sd->blue_shift > 0 ? b << sd->blue_shift : b >> -sd->blue_shift; + pix = (b & sd->blue_mask) | (g & sd->green_mask) | (r & sd->red_mask) + | ~(sd->blue_mask | sd->green_mask | sd->red_mask); + if ( screen == TQPaintDevice::x11AppScreen() ) + d.d32.pix = pix; + return pix; + } + TQColorData *c = sd->colorDict->tqfind( (long)(d.argb) ); + if ( c ) { // found color in dictionary + pix = c->pix; + if ( screen == TQPaintDevice::x11AppScreen() ) { + d.d8.invalid = FALSE; // color ok + d.d8.dirty = FALSE; + d.d8.pix = pix; // use same pixel value + if ( c->context != current_alloc_context ) { + c->context = 0; // convert to default context + sd->g_our_alloc[pix] = TRUE; // reuse without XAllocColor + } + } + return pix; + } + + XColor col; + col.red = r << 8; + col.green = g << 8; + col.blue = b << 8; + + bool try_again = FALSE; + bool try_alloc = !sd->color_reduce; + int try_count = 0; + + do { + // This loop is run until we manage to either allocate or + // tqfind an approximate color, it stops after a few iterations. + + try_again = FALSE; + + if ( try_alloc && sd->colors_avail && + XAllocColor(dpy, TQPaintDevice::x11AppColormap( screen ),&col) ) { + // We could allocate the color + pix = (uint) col.pixel; + if ( screen == TQPaintDevice::x11AppScreen() ) { + d.d8.pix = pix; + d.d8.invalid = FALSE; + d.d8.dirty = FALSE; + sd->g_carr[d.d8.pix] = col; // update color array + if ( current_alloc_context == 0 ) + sd->g_our_alloc[d.d8.pix] = TRUE; // reuse without XAllocColor + } + } else { + // No available colors, or we did not want to allocate one + int i; + sd->colors_avail = FALSE; // no more available colors + if ( sd->g_carr_fetch ) { // refetch color array + sd->g_carr_fetch = FALSE; + XQueryColors( dpy, TQPaintDevice::x11AppColormap( screen ), sd->g_carr, + sd->g_cells ); + } + int mindist; + i = tqfind_nearest_color( r, g, b, &mindist, sd ); + + if ( mindist != 0 && !try_alloc ) { + // Not an exact match with an existing color + int rr = ((r+sd->col_div_r/2)/sd->col_div_r)*sd->col_div_r; + int rg = ((g+sd->col_div_g/2)/sd->col_div_g)*sd->col_div_g; + int rb = ((b+sd->col_div_b/2)/sd->col_div_b)*sd->col_div_b; + int rx = rr - r; + int gx = rg - g; + int bx = rb - b; + int dist = rx*rx + gx*gx + bx*bx; // calculate distance + if ( dist < mindist ) { + // reduced color is closer - try to alloc it + r = rr; + g = rg; + b = rb; + col.red = r << 8; + col.green = g << 8; + col.blue = b << 8; + try_alloc = TRUE; + try_again = TRUE; + sd->colors_avail = TRUE; + continue; // Try alloc reduced color + } + } + + if ( i == -1 ) { // no nearest color?! + int unused, value; + hsv(&unused, &unused, &value); + if (value < 128) { // dark, use black + d.argb = tqRgb(0,0,0); + pix = (uint)BlackPixel( dpy, screen ); + if ( screen == TQPaintDevice::x11AppScreen() ) { + d.d8.invalid = FALSE; + d.d8.dirty = FALSE; + d.d8.pix = pix; + } + } else { // light, use white + d.argb = tqRgb(0xff,0xff,0xff); + pix = (uint)WhitePixel( dpy, screen ); + if ( screen == TQPaintDevice::x11AppScreen() ) { + d.d8.invalid = FALSE; + d.d8.dirty = FALSE; + d.d8.pix = pix; + } + } + return pix; + } + if ( sd->g_our_alloc[i] ) { // we've already allocated it + ; // i == g_carr[i].pixel + } else { + // Try to allocate existing color + col = sd->g_carr[i]; + if ( XAllocColor(dpy, TQPaintDevice::x11AppColormap( screen ), &col) ) { + i = (uint)col.pixel; + sd->g_carr[i] = col; // update color array + if ( screen == TQPaintDevice::x11AppScreen() ) { + if ( current_alloc_context == 0 ) + sd->g_our_alloc[i] = TRUE; // only in the default context + } + } else { + // Oops, it's gone again + try_count++; + try_again = TRUE; + sd->colors_avail = TRUE; + sd->g_carr_fetch = TRUE; + } + } + if ( !try_again ) { // got it + pix = (uint)sd->g_carr[i].pixel; + if ( screen == TQPaintDevice::x11AppScreen() ) { + d.d8.invalid = FALSE; + d.d8.dirty = FALSE; + d.d8.pix = pix; // allocated X11 color + } + } + } + + } while ( try_again && try_count < 2 ); + + if ( try_again ) { // no hope of allocating color + int unused, value; + hsv(&unused, &unused, &value); + if (value < 128) { // dark, use black + d.argb = tqRgb(0,0,0); + pix = (uint)BlackPixel( dpy, screen ); + if ( screen == TQPaintDevice::x11AppScreen() ) { + d.d8.invalid = FALSE; + d.d8.dirty = FALSE; + d.d8.pix = pix; + } + } else { // light, use white + d.argb = tqRgb(0xff,0xff,0xff); + pix = (uint)WhitePixel( dpy, screen ); + if ( screen == TQPaintDevice::x11AppScreen() ) { + d.d8.invalid = FALSE; + d.d8.dirty = FALSE; + d.d8.pix = pix; + } + } + return pix; + } + // All colors outside context 0 must go into the dictionary + bool many = sd->colorDict->count() >= sd->colorDict->size() * 8; + if ( many && sd->colorDict->size() == col_std_dict ) { + sd->colorDict->resize( col_large_dict ); + } + if ( !many || current_alloc_context != 0 ) { + c = new TQColorData; // insert into color dict + TQ_CHECK_PTR( c ); + c->pix = pix; + c->context = current_alloc_context; + sd->colorDict->insert( (long)d.argb, c ); // store color in dict + } + return pix; +} + +/*! + Allocates the RGB color and returns the pixel value. + + Allocating a color means to obtain a pixel value from the RGB + specification. The pixel value is an index into the global color + table, but should be considered an arbitrary platform-dependent value. + + The pixel() function calls alloc() if necessary, so in general you + don't need to call this function. + + \sa enterAllocContext() +*/ +// ### 4.0 - remove me? +uint TQColor::alloc() +{ + return alloc( -1 ); +} + +/*! + \overload + + Returns the pixel value for screen \a screen. + + This value is used by the underlying window system to refer to a color. + It can be thought of as an index into the display hardware's color table, + but the value is an arbitrary 32-bit value. + + \sa alloc() +*/ +uint TQColor::pixel( int screen ) const +{ + if (screen != TQPaintDevice::x11AppScreen() && + // don't allocate color0 or color1, they have fixed pixel + // values for all screens + d.argb != tqRgba(255, 255, 255, 1) && d.argb != tqRgba(0, 0, 0, 1)) + return ((TQColor*)this)->alloc( screen ); + return pixel(); +} + + +void TQColor::setSystemNamedColor( const TQString& name ) +{ + // setSystemNamedColor should look up rgb values from the built in + // color tables first (see qcolor_p.cpp), and failing that, use + // the window system's interface for translating names to rgb values... + // we do this so that things like uic can load an XPM file with named colors + // and convert it to a png without having to use window system functions... + d.argb = qt_get_rgb_val( name.latin1() ); + TQRgb rgb; + if ( qt_get_named_rgb( name.latin1(), &rgb ) ) { + setRgb( tqRed(rgb), tqGreen(rgb), tqBlue(rgb) ); + if ( colormodel == d8 ) { + d.d8.invalid = FALSE; + d.d8.dirty = TRUE; + d.d8.pix = 0; + } else { + alloc(); + } + } else if ( !color_init ) { +#if defined(TQT_CHECK_STATE) + qWarning( "TQColor::setSystemNamedColor: Cannot perform this operation " + "because TQApplication does not exist" ); +#endif + // set color to invalid + *this = TQColor(); + } else { + XColor col, hw_col; + if ( XLookupColor(TQPaintDevice::x11AppDisplay(), + TQPaintDevice::x11AppColormap(), name.latin1(), + &col, &hw_col) ) { + setRgb( col.red>>8, col.green>>8, col.blue>>8 ); + } else { + // set color to invalid + *this = TQColor(); + } + } +} + + +#define MAX_CONTEXTS 16 +static int context_stack[MAX_CONTEXTS]; +static int context_ptr = 0; + +static void init_context_stack() +{ + static bool did_init = FALSE; + if ( !did_init ) { + did_init = TRUE; + context_stack[0] = current_alloc_context = 0; + } +} + + +/*! + Enters a color allocation context and returns a non-zero unique + identifier. + + Color allocation contexts are useful for programs that need to + allocate many colors and throw them away later, like image + viewers. The allocation context functions work for true color + displays as well as for colormap displays, except that + TQColor::destroyAllocContext() does nothing for true color. + + Example: + \code + TQPixmap loadPixmap( TQString fileName ) + { + static int alloc_context = 0; + if ( alloc_context ) + TQColor::destroyAllocContext( alloc_context ); + alloc_context = TQColor::enterAllocContext(); + TQPixmap pm( fileName ); + TQColor::leaveAllocContext(); + return pm; + } + \endcode + + The example code loads a pixmap from file. It frees up all colors + that were allocated the last time loadPixmap() was called. + + The initial/default context is 0. TQt keeps a list of colors + associated with their allocation contexts. You can call + destroyAllocContext() to get rid of all colors that were allocated + in a specific context. + + Calling enterAllocContext() enters an allocation context. The + allocation context lasts until you call leaveAllocContext(). + TQColor has an internal stack of allocation contexts. Each call to + enterAllocContex() must have a corresponding leaveAllocContext(). + + \code + // context 0 active + int c1 = TQColor::enterAllocContext(); // enter context c1 + // context c1 active + int c2 = TQColor::enterAllocContext(); // enter context c2 + // context c2 active + TQColor::leaveAllocContext(); // leave context c2 + // context c1 active + TQColor::leaveAllocContext(); // leave context c1 + // context 0 active + // Now, free all colors that were allocated in context c2 + TQColor::destroyAllocContext( c2 ); + \endcode + + You may also want to set the application's color specification. + See TQApplication::setColorSpec() for more information. + + \sa leaveAllocContext(), currentAllocContext(), destroyAllocContext(), + TQApplication::setColorSpec() +*/ + +int TQColor::enterAllocContext() +{ + static int context_seq_no = 0; + init_context_stack(); + if ( context_ptr+1 == MAX_CONTEXTS ) { +#if defined(TQT_CHECK_STATE) + qWarning( "TQColor::enterAllocContext: Context stack overflow" ); +#endif + return 0; + } + current_alloc_context = context_stack[++context_ptr] = ++context_seq_no; + return current_alloc_context; +} + + +/*! + Leaves a color allocation context. + + See enterAllocContext() for a detailed explanation. + + \sa enterAllocContext(), currentAllocContext() +*/ + +void TQColor::leaveAllocContext() +{ + init_context_stack(); + if ( context_ptr == 0 ) { +#if defined(TQT_CHECK_STATE) + qWarning( "TQColor::leaveAllocContext: Context stack underflow" ); +#endif + return; + } + current_alloc_context = context_stack[--context_ptr]; +} + + +/*! + Returns the current color allocation context. + + The default context is 0. + + \sa enterAllocContext(), leaveAllocContext() +*/ + +int TQColor::currentAllocContext() +{ + return current_alloc_context; +} + + +/*! + Destroys a color allocation context, \e context. + + This function deallocates all colors that were allocated in the + specified \a context. If \a context == -1, it frees up all colors + that the application has allocated. If \a context == -2, it frees + up all colors that the application has allocated, except those in + the default context. + + The function does nothing for true color displays. + + \sa enterAllocContext(), alloc() +*/ + +void TQColor::destroyAllocContext( int context ) +{ + init_context_stack(); + if ( !color_init ) + return; + + int screen; + for ( screen = 0; screen < screencount; ++screen ) { + if ( screendata[screen]->g_truecolor ) + continue; + + ulong pixels[256]; + bool freeing[256]; + memset( freeing, FALSE, screendata[screen]->g_cells*sizeof(bool) ); + TQColorData *d; + TQColorDictIt it( *screendata[screen]->colorDict ); + int i = 0; + uint rgbv; + while ( (d=it.current()) ) { + rgbv = (uint)it.currentKey(); + if ( (d->context || context==-1) && + (d->context == context || context < 0) ) { + if ( !screendata[screen]->g_our_alloc[d->pix] && !freeing[d->pix] ) { + // will free this color + pixels[i++] = d->pix; + freeing[d->pix] = TRUE; + } + // remove from dict + screendata[screen]->colorDict->remove( (long)rgbv ); + } + ++it; + } + if ( i ) + XFreeColors( TQPaintDevice::x11AppDisplay(), + TQPaintDevice::x11AppColormap( screen ), + pixels, i, 0 ); + } +} + +#endif // USE_QT4
\ No newline at end of file |