summaryrefslogtreecommitdiffstats
path: root/tqtinterface/qt4/src/kernel/tqcolor_x11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tqtinterface/qt4/src/kernel/tqcolor_x11.cpp')
-rw-r--r--tqtinterface/qt4/src/kernel/tqcolor_x11.cpp1336
1 files changed, 1336 insertions, 0 deletions
diff --git a/tqtinterface/qt4/src/kernel/tqcolor_x11.cpp b/tqtinterface/qt4/src/kernel/tqcolor_x11.cpp
new file mode 100644
index 0000000..909ecbb
--- /dev/null
+++ b/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