kwin Library API Documentation

kdedefault.cpp

00001 /*
00002  *
00003  *  KDE2 Default KWin client
00004  *
00005  *  Copyright (C) 1999, 2001 Daniel Duley <mosfet@kde.org>
00006  *  Matthias Ettrich <ettrich@kde.org>
00007  *  Karol Szwed <gallium@kde.org>
00008  *
00009  *  Draws mini titlebars for tool windows.
00010  *  Many features are now customizable.
00011  */
00012 
00013 #include "kdedefault.h"
00014 
00015 #include <kconfig.h>
00016 #include <kglobal.h>
00017 #include <kpixmapeffect.h>
00018 #include <kimageeffect.h>
00019 #include <kdrawutil.h>
00020 #include <klocale.h>
00021 #include <qlayout.h>
00022 #include <qdrawutil.h>
00023 #include <qbitmap.h>
00024 #include <qimage.h>
00025 #include <qtooltip.h>
00026 #include <qapplication.h>
00027 #include <qlabel.h>
00028 #include <kdebug.h>
00029 
00030 namespace Default
00031 {
00032 
00033 static const unsigned char iconify_bits[] = {
00034   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x78, 0x00, 0x78, 0x00,
00035   0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00036 
00037 static const unsigned char close_bits[] = {
00038   0x00, 0x00, 0x84, 0x00, 0xce, 0x01, 0xfc, 0x00, 0x78, 0x00, 0x78, 0x00,
00039   0xfc, 0x00, 0xce, 0x01, 0x84, 0x00, 0x00, 0x00};
00040 
00041 static const unsigned char maximize_bits[] = {
00042   0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0x86, 0x01, 0x86, 0x01, 0x86, 0x01,
00043   0x86, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0x00, 0x00};
00044 
00045 static const unsigned char minmax_bits[] = {
00046   0x7f, 0x00, 0x7f, 0x00, 0x63, 0x00, 0xfb, 0x03, 0xfb, 0x03, 0x1f, 0x03,
00047   0x1f, 0x03, 0x18, 0x03, 0xf8, 0x03, 0xf8, 0x03};
00048 
00049 static const unsigned char question_bits[] = {
00050   0x00, 0x00, 0x78, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0x60, 0x00, 0x30, 0x00,
00051   0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00};
00052 
00053 static const unsigned char above_on_bits[] = {
00054    0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0x30, 0x00, 0xfc, 0x00, 0x78, 0x00,
00055    0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
00056 
00057 static const unsigned char above_off_bits[] = {
00058    0x30, 0x00, 0x78, 0x00, 0xfc, 0x00, 0x30, 0x00, 0xfe, 0x01, 0xfe, 0x01,
00059    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
00060 
00061 static const unsigned char below_on_bits[] = {
00062    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x78, 0x00, 0xfc, 0x00,
00063    0x30, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0x00, 0x00 };
00064 
00065 static const unsigned char below_off_bits[] = {
00066    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01,
00067    0x30, 0x00, 0xfc, 0x00, 0x78, 0x00, 0x30, 0x00 };
00068 
00069 static const unsigned char shade_on_bits[] = {
00070    0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0x02, 0x01, 0x02, 0x01,
00071    0x02, 0x01, 0x02, 0x01, 0xfe, 0x01, 0x00, 0x00 };
00072 
00073 static const unsigned char shade_off_bits[] = {
00074    0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00,
00075    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
00076 
00077 static const unsigned char pindown_white_bits[] = {
00078   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x1f, 0xa0, 0x03,
00079   0xb0, 0x01, 0x30, 0x01, 0xf0, 0x00, 0x70, 0x00, 0x20, 0x00, 0x00, 0x00,
00080   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00081 
00082 static const unsigned char pindown_gray_bits[] = {
00083   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
00084   0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x80, 0x07, 0xc0, 0x03, 0xe0, 0x01,
00085   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00086 
00087 static const unsigned char pindown_dgray_bits[] = {
00088   0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x10, 0x70, 0x20, 0x50, 0x20,
00089   0x48, 0x30, 0xc8, 0x38, 0x08, 0x1f, 0x08, 0x18, 0x10, 0x1c, 0x10, 0x0e,
00090   0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00091 
00092 static const unsigned char pindown_mask_bits[] = {
00093   0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x1f, 0xf0, 0x3f, 0xf0, 0x3f,
00094   0xf8, 0x3f, 0xf8, 0x3f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf0, 0x1f, 0xf0, 0x0f,
00095   0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00096 
00097 static const unsigned char pinup_white_bits[] = {
00098   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x11,
00099   0x3f, 0x15, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00100   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00101 
00102 static const unsigned char pinup_gray_bits[] = {
00103   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00104   0x80, 0x0a, 0xbf, 0x0a, 0x80, 0x15, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
00105   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00106 
00107 static const unsigned char pinup_dgray_bits[] = {
00108   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x40, 0x31, 0x40, 0x2e,
00109   0x40, 0x20, 0x40, 0x20, 0x7f, 0x2a, 0x40, 0x3f, 0xc0, 0x31, 0xc0, 0x20,
00110   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00111 
00112 static const unsigned char pinup_mask_bits[] = {
00113   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0xc0, 0x31, 0xc0, 0x3f,
00114   0xff, 0x3f, 0xff, 0x3f, 0xff, 0x3f, 0xc0, 0x3f, 0xc0, 0x31, 0xc0, 0x20,
00115   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00116 
00117 // ===========================================================================
00118 
00119 static QPixmap* titlePix;
00120 static KPixmap* titleBuffer;
00121 static KPixmap* aUpperGradient;
00122 static KPixmap* iUpperGradient;
00123 
00124 static KPixmap* pinDownPix;
00125 static KPixmap* pinUpPix;
00126 static KPixmap* ipinDownPix;
00127 static KPixmap* ipinUpPix;
00128 
00129 static KPixmap* rightBtnUpPix[2];
00130 static KPixmap* rightBtnDownPix[2];
00131 static KPixmap* irightBtnUpPix[2];
00132 static KPixmap* irightBtnDownPix[2];
00133 
00134 static KPixmap* leftBtnUpPix[2];
00135 static KPixmap* leftBtnDownPix[2];
00136 static KPixmap* ileftBtnUpPix[2];
00137 static KPixmap* ileftBtnDownPix[2];
00138 
00139 static KDEDefaultHandler* clientHandler;
00140 static int  toolTitleHeight;
00141 static int  normalTitleHeight;
00142 static int borderWidth;
00143 static int grabBorderWidth;
00144 static bool KDEDefault_initialized = false;
00145 static bool useGradients;
00146 static bool showGrabBar;
00147 static bool showTitleBarStipple;
00148 
00149 
00150 // ===========================================================================
00151 
00152 KDEDefaultHandler::KDEDefaultHandler()
00153 {
00154         clientHandler = this;
00155     readConfig( false );
00156     createPixmaps();
00157     KDEDefault_initialized = true;
00158 }
00159 
00160 
00161 KDEDefaultHandler::~KDEDefaultHandler()
00162 {
00163     KDEDefault_initialized = false;
00164     freePixmaps();
00165         clientHandler = NULL;
00166 }
00167 
00168 KDecoration* KDEDefaultHandler::createDecoration( KDecorationBridge* b )
00169 {
00170         return new KDEDefaultClient( b, this );
00171 }
00172 
00173 bool KDEDefaultHandler::reset( unsigned long changed )
00174 {
00175     KDEDefault_initialized = false;
00176         changed |= readConfig( true );
00177         if( changed & SettingColors )
00178         { // pixmaps need to be recreated
00179             freePixmaps();
00180                 createPixmaps();
00181         }
00182     KDEDefault_initialized = true;
00183         bool need_recreate = ( changed & ( SettingDecoration | SettingFont | SettingButtons | SettingBorder )) != 0;
00184         if( need_recreate )  // something else than colors changed
00185             return true;
00186         resetDecorations( changed );
00187         return false;
00188 }
00189 
00190 
00191 unsigned long KDEDefaultHandler::readConfig( bool update )
00192 {
00193         unsigned long changed = 0;
00194     KConfig* conf = KGlobal::config();
00195     conf->setGroup("KDEDefault");
00196 
00197         bool new_showGrabBar        = conf->readBoolEntry("ShowGrabBar", true);
00198     bool new_showTitleBarStipple = conf->readBoolEntry("ShowTitleBarStipple", true);
00199     bool new_useGradients       = conf->readBoolEntry("UseGradients", true);
00200     int  new_titleHeight        = QFontMetrics(options()->font(true)).height();
00201     int  new_toolTitleHeight    = QFontMetrics(options()->font(true, true)).height()-2;
00202 
00203     int new_borderWidth;
00204     switch(options()->preferredBorderSize(this)) {
00205     case BorderLarge:
00206         new_borderWidth = 8;
00207         break;
00208     case BorderVeryLarge:
00209         new_borderWidth = 12;
00210         break;
00211     case BorderHuge:
00212         new_borderWidth = 18;
00213         break;
00214     case BorderVeryHuge:
00215         new_borderWidth = 27;
00216         break;
00217     case BorderOversized:
00218         new_borderWidth = 40;
00219         break;
00220     case BorderTiny:
00221     case BorderNormal:
00222     default:
00223         new_borderWidth = 4;
00224     }
00225 
00226     if (new_titleHeight < 16)              new_titleHeight = 16;
00227     if (new_titleHeight < new_borderWidth) new_titleHeight = new_borderWidth;
00228     if (new_toolTitleHeight < 12)              new_toolTitleHeight = 12;
00229     if (new_toolTitleHeight < new_borderWidth) new_toolTitleHeight = new_borderWidth;
00230 
00231         if( update )
00232         {
00233                 if( new_showGrabBar != showGrabBar
00234                     || new_titleHeight != normalTitleHeight
00235                     || new_toolTitleHeight != toolTitleHeight
00236                     || new_borderWidth != borderWidth )
00237                         changed |= SettingDecoration; // need recreating the decoration
00238                 if( new_showTitleBarStipple != showTitleBarStipple
00239                     || new_useGradients != useGradients
00240                     || new_titleHeight != normalTitleHeight
00241                     || new_toolTitleHeight != toolTitleHeight )
00242                         changed |= SettingColors; // just recreate the pixmaps and repaint
00243         }
00244 
00245         showGrabBar             = new_showGrabBar;
00246         showTitleBarStipple     = new_showTitleBarStipple;
00247         useGradients            = new_useGradients;
00248         normalTitleHeight       = new_titleHeight;
00249         toolTitleHeight         = new_toolTitleHeight;
00250         borderWidth             = new_borderWidth;
00251         grabBorderWidth         = (borderWidth > 15) ? borderWidth + 15 : 2*borderWidth;
00252         return changed;
00253 }
00254 
00255 
00256 // This paints the button pixmaps upon loading the style.
00257 void KDEDefaultHandler::createPixmaps()
00258 {
00259     bool highcolor = useGradients && (QPixmap::defaultDepth() > 8);
00260 
00261     // Make the titlebar stipple optional
00262     if (showTitleBarStipple)
00263     {
00264         QPainter p;
00265         QPainter maskPainter;
00266         int i, x, y;
00267         titlePix = new QPixmap(132, normalTitleHeight+2);
00268         QBitmap mask(132, normalTitleHeight+2);
00269         mask.fill(Qt::color0);
00270 
00271         p.begin(titlePix);
00272         maskPainter.begin(&mask);
00273         maskPainter.setPen(Qt::color1);
00274         for(i=0, y=2; i < 9; ++i, y+=4)
00275             for(x=1; x <= 132; x+=3)
00276             {
00277                 p.setPen(options()->color(ColorTitleBar, true).light(150));
00278                 p.drawPoint(x, y);
00279                 maskPainter.drawPoint(x, y);
00280                 p.setPen(options()->color(ColorTitleBar, true).dark(150));
00281                 p.drawPoint(x+1, y+1);
00282                 maskPainter.drawPoint(x+1, y+1);
00283             }
00284         maskPainter.end();
00285         p.end();
00286         titlePix->setMask(mask);
00287     } else
00288         titlePix = NULL;
00289 
00290     QColor activeTitleColor1(options()->color(ColorTitleBar,      true));
00291     QColor activeTitleColor2(options()->color(ColorTitleBlend,    true));
00292 
00293     QColor inactiveTitleColor1(options()->color(ColorTitleBar,    false));
00294     QColor inactiveTitleColor2(options()->color(ColorTitleBlend,  false));
00295 
00296     // Create titlebar gradient images if required
00297     aUpperGradient = NULL;
00298     iUpperGradient = NULL;
00299 
00300     if(highcolor)
00301     {
00302         // Create the titlebar gradients
00303         if (activeTitleColor1 != activeTitleColor2)
00304         {
00305             aUpperGradient = new KPixmap;
00306             aUpperGradient->resize(128, normalTitleHeight+2);
00307             KPixmapEffect::gradient(*aUpperGradient,
00308                 activeTitleColor1,
00309                 activeTitleColor2,
00310                 KPixmapEffect::VerticalGradient);
00311         }
00312 
00313         if (inactiveTitleColor1 != inactiveTitleColor2)
00314         {
00315             iUpperGradient = new KPixmap;
00316             iUpperGradient->resize(128, normalTitleHeight+2);
00317 
00318             KPixmapEffect::gradient(*iUpperGradient,
00319                     inactiveTitleColor1,
00320                     inactiveTitleColor2,
00321             KPixmapEffect::VerticalGradient);
00322         }
00323     }
00324 
00325     // Set the sticky pin pixmaps;
00326     QColorGroup g;
00327     QPainter p;
00328 
00329     // Active pins
00330     g = options()->colorGroup( ColorButtonBg, true );
00331     pinUpPix  = new KPixmap();
00332     pinUpPix->resize(16, 16);
00333     p.begin( pinUpPix );
00334     kColorBitmaps( &p, g, 0, 0, 16, 16, true, pinup_white_bits,
00335         pinup_gray_bits, NULL, NULL, pinup_dgray_bits, NULL );
00336     p.end();
00337     pinUpPix->setMask( QBitmap(16, 16, pinup_mask_bits, true) );
00338 
00339     pinDownPix = new KPixmap();
00340     pinDownPix->resize(16, 16);
00341     p.begin( pinDownPix );
00342     kColorBitmaps( &p, g, 0, 0, 16, 16, true, pindown_white_bits,
00343         pindown_gray_bits, NULL, NULL, pindown_dgray_bits, NULL );
00344     p.end();
00345     pinDownPix->setMask( QBitmap(16, 16, pindown_mask_bits, true) );
00346 
00347     // Inactive pins
00348     g = options()->colorGroup( ColorButtonBg, false );
00349     ipinUpPix = new KPixmap();
00350     ipinUpPix->resize(16, 16);
00351     p.begin( ipinUpPix );
00352     kColorBitmaps( &p, g, 0, 0, 16, 16, true, pinup_white_bits,
00353         pinup_gray_bits, NULL, NULL, pinup_dgray_bits, NULL );
00354     p.end();
00355     ipinUpPix->setMask( QBitmap(16, 16, pinup_mask_bits, true) );
00356 
00357     ipinDownPix = new KPixmap();
00358     ipinDownPix->resize(16, 16);
00359     p.begin( ipinDownPix );
00360     kColorBitmaps( &p, g, 0, 0, 16, 16, true, pindown_white_bits,
00361         pindown_gray_bits, NULL, NULL, pindown_dgray_bits, NULL );
00362     p.end();
00363     ipinDownPix->setMask( QBitmap(16, 16, pindown_mask_bits, true) );
00364 
00365     // Create a title buffer for flicker-free painting
00366     titleBuffer = new KPixmap();
00367 
00368     // Cache all possible button states
00369     leftBtnUpPix[true]  = new KPixmap();
00370     leftBtnUpPix[true]->resize(normalTitleHeight, normalTitleHeight);
00371     leftBtnDownPix[true]    = new KPixmap();
00372     leftBtnDownPix[true]->resize(normalTitleHeight, normalTitleHeight);
00373     ileftBtnUpPix[true] = new KPixmap();
00374     ileftBtnUpPix[true]->resize(normalTitleHeight, normalTitleHeight);
00375     ileftBtnDownPix[true]   = new KPixmap();
00376     ileftBtnDownPix[true]->resize(normalTitleHeight, normalTitleHeight);
00377 
00378     rightBtnUpPix[true]     = new KPixmap();
00379     rightBtnUpPix[true]->resize(normalTitleHeight, normalTitleHeight);
00380     rightBtnDownPix[true] = new KPixmap();
00381     rightBtnDownPix[true]->resize(normalTitleHeight, normalTitleHeight);
00382     irightBtnUpPix[true]    = new KPixmap();
00383     irightBtnUpPix[true]->resize(normalTitleHeight, normalTitleHeight);
00384     irightBtnDownPix[true] = new KPixmap();
00385     irightBtnDownPix[true]->resize(normalTitleHeight, normalTitleHeight);
00386 
00387     leftBtnUpPix[false]     = new KPixmap();
00388     leftBtnUpPix[false]->resize(toolTitleHeight, normalTitleHeight);
00389     leftBtnDownPix[false]   = new KPixmap();
00390     leftBtnDownPix[false]->resize(toolTitleHeight, normalTitleHeight);
00391     ileftBtnUpPix[false]    = new KPixmap();
00392     ileftBtnUpPix[false]->resize(normalTitleHeight, normalTitleHeight);
00393     ileftBtnDownPix[false]  = new KPixmap();
00394     ileftBtnDownPix[false]->resize(normalTitleHeight, normalTitleHeight);
00395 
00396     rightBtnUpPix[false]    = new KPixmap();
00397     rightBtnUpPix[false]->resize(toolTitleHeight, toolTitleHeight);
00398     rightBtnDownPix[false] = new KPixmap();
00399     rightBtnDownPix[false]->resize(toolTitleHeight, toolTitleHeight);
00400     irightBtnUpPix[false]   = new KPixmap();
00401     irightBtnUpPix[false]->resize(toolTitleHeight, toolTitleHeight);
00402     irightBtnDownPix[false] = new KPixmap();
00403     irightBtnDownPix[false]->resize(toolTitleHeight, toolTitleHeight);
00404 
00405     // Draw the button state pixmaps
00406     g = options()->colorGroup( ColorTitleBar, true );
00407     drawButtonBackground( leftBtnUpPix[true], g, false );
00408     drawButtonBackground( leftBtnDownPix[true], g, true );
00409     drawButtonBackground( leftBtnUpPix[false], g, false );
00410     drawButtonBackground( leftBtnDownPix[false], g, true );
00411 
00412     g = options()->colorGroup( ColorButtonBg, true );
00413     drawButtonBackground( rightBtnUpPix[true], g, false );
00414     drawButtonBackground( rightBtnDownPix[true], g, true );
00415     drawButtonBackground( rightBtnUpPix[false], g, false );
00416     drawButtonBackground( rightBtnDownPix[false], g, true );
00417 
00418     g = options()->colorGroup( ColorTitleBar, false );
00419     drawButtonBackground( ileftBtnUpPix[true], g, false );
00420     drawButtonBackground( ileftBtnDownPix[true], g, true );
00421     drawButtonBackground( ileftBtnUpPix[false], g, false );
00422     drawButtonBackground( ileftBtnDownPix[false], g, true );
00423 
00424     g = options()->colorGroup( ColorButtonBg, false );
00425     drawButtonBackground( irightBtnUpPix[true], g, false );
00426     drawButtonBackground( irightBtnDownPix[true], g, true );
00427     drawButtonBackground( irightBtnUpPix[false], g, false );
00428     drawButtonBackground( irightBtnDownPix[false], g, true );
00429 }
00430 
00431 
00432 void KDEDefaultHandler::freePixmaps()
00433 {
00434     // Free button pixmaps
00435     if (rightBtnUpPix[true])
00436         delete rightBtnUpPix[true];
00437     if(rightBtnDownPix[true])
00438         delete rightBtnDownPix[true];
00439     if (irightBtnUpPix[true])
00440         delete irightBtnUpPix[true];
00441     if (irightBtnDownPix[true])
00442         delete irightBtnDownPix[true];
00443 
00444     if (leftBtnUpPix[true])
00445         delete leftBtnUpPix[true];
00446     if(leftBtnDownPix[true])
00447         delete leftBtnDownPix[true];
00448     if (ileftBtnUpPix[true])
00449         delete ileftBtnUpPix[true];
00450     if (ileftBtnDownPix[true])
00451         delete ileftBtnDownPix[true];
00452 
00453     if (rightBtnUpPix[false])
00454         delete rightBtnUpPix[false];
00455     if(rightBtnDownPix[false])
00456         delete rightBtnDownPix[false];
00457     if (irightBtnUpPix[false])
00458         delete irightBtnUpPix[false];
00459     if (irightBtnDownPix[false])
00460         delete irightBtnDownPix[false];
00461 
00462     if (leftBtnUpPix[false])
00463         delete leftBtnUpPix[false];
00464     if(leftBtnDownPix[false])
00465         delete leftBtnDownPix[false];
00466     if (ileftBtnUpPix[false])
00467         delete ileftBtnUpPix[false];
00468     if (ileftBtnDownPix[false])
00469         delete ileftBtnDownPix[false];
00470 
00471     // Title images
00472     if (titleBuffer)
00473         delete titleBuffer;
00474     if (titlePix)
00475         delete titlePix;
00476     if (aUpperGradient)
00477         delete aUpperGradient;
00478     if (iUpperGradient)
00479         delete iUpperGradient;
00480 
00481     // Sticky pin images
00482     if (pinUpPix)
00483         delete pinUpPix;
00484     if (ipinUpPix)
00485         delete ipinUpPix;
00486     if (pinDownPix)
00487         delete pinDownPix;
00488     if (ipinDownPix)
00489         delete ipinDownPix;
00490 }
00491 
00492 
00493 void KDEDefaultHandler::drawButtonBackground(KPixmap *pix,
00494         const QColorGroup &g, bool sunken)
00495 {
00496     QPainter p;
00497     int w = pix->width();
00498     int h = pix->height();
00499     int x2 = w-1;
00500     int y2 = h-1;
00501 
00502     bool highcolor = useGradients && (QPixmap::defaultDepth() > 8);
00503     QColor c = g.background();
00504 
00505     // Fill the background with a gradient if possible
00506     if (highcolor)
00507         KPixmapEffect::gradient(*pix, c.light(130), c.dark(130),
00508                                 KPixmapEffect::VerticalGradient);
00509     else
00510         pix->fill(c);
00511 
00512     p.begin(pix);
00513     // outer frame
00514     p.setPen(g.mid());
00515     p.drawLine(0, 0, x2, 0);
00516     p.drawLine(0, 0, 0, y2);
00517     p.setPen(g.light());
00518     p.drawLine(x2, 0, x2, y2);
00519     p.drawLine(0, x2, y2, x2);
00520     p.setPen(g.dark());
00521     p.drawRect(1, 1, w-2, h-2);
00522     p.setPen(sunken ? g.mid() : g.light());
00523     p.drawLine(2, 2, x2-2, 2);
00524     p.drawLine(2, 2, 2, y2-2);
00525     p.setPen(sunken ? g.light() : g.mid());
00526     p.drawLine(x2-2, 2, x2-2, y2-2);
00527     p.drawLine(2, x2-2, y2-2, x2-2);
00528 }
00529 
00530 QValueList< KDEDefaultHandler::BorderSize > KDEDefaultHandler::borderSizes() const
00531 { // the list must be sorted
00532   return QValueList< BorderSize >() << BorderNormal << BorderLarge <<
00533       BorderVeryLarge <<  BorderHuge << BorderVeryHuge << BorderOversized;
00534 }
00535 
00536 
00537 // ===========================================================================
00538 
00539 KDEDefaultButton::KDEDefaultButton(KDEDefaultClient *parent, const char *name,
00540            bool largeButton, bool isLeftButton, bool isStickyButton,
00541            const unsigned char *bitmap, const QString& tip, const int realizeBtns )
00542     : QButton(parent->widget(), name)
00543 {
00544     realizeButtons = realizeBtns;
00545 
00546     QToolTip::add( this, tip );
00547     setCursor( arrowCursor );
00548     setBackgroundMode( QWidget::NoBackground );
00549     setToggleButton( isStickyButton );
00550 
00551     isMouseOver = false;
00552     deco        = NULL;
00553     large       = largeButton;
00554     isLeft      = isLeftButton;
00555     isSticky    = isStickyButton;
00556     client      = parent;
00557 
00558     if (large)
00559        setFixedSize(normalTitleHeight, normalTitleHeight);
00560     else
00561        setFixedSize(toolTitleHeight, toolTitleHeight);
00562 
00563     if (bitmap)
00564         setBitmap(bitmap);
00565 }
00566 
00567 
00568 KDEDefaultButton::~KDEDefaultButton()
00569 {
00570     if (deco)
00571         delete deco;
00572 }
00573 
00574 
00575 QSize KDEDefaultButton::sizeHint() const
00576 {
00577    if ( large )
00578       return( QSize(normalTitleHeight, normalTitleHeight) );
00579    else
00580       return( QSize(toolTitleHeight, toolTitleHeight) );
00581 }
00582 
00583 
00584 void KDEDefaultButton::setBitmap(const unsigned char *bitmap)
00585 {
00586     if (deco)
00587         delete deco;
00588 
00589     deco = new QBitmap(10, 10, bitmap, true);
00590     deco->setMask( *deco );
00591     repaint( false );
00592 }
00593 
00594 
00595 void KDEDefaultButton::drawButton(QPainter *p)
00596 {
00597     if (!KDEDefault_initialized)
00598         return;
00599 
00600     if (deco) {
00601         // Fill the button background with an appropriate button image
00602         KPixmap btnbg;
00603 
00604         if (isLeft) {
00605             if (isDown())
00606                 btnbg = client->isActive() ?
00607                             *leftBtnDownPix[large] : *ileftBtnDownPix[large];
00608             else
00609                 btnbg = client->isActive() ?
00610                             *leftBtnUpPix[large] : *ileftBtnUpPix[large];
00611         } else {
00612             if (isDown())
00613                 btnbg = client->isActive() ?
00614                             *rightBtnDownPix[large] : *irightBtnDownPix[large];
00615             else
00616                 btnbg = client->isActive() ?
00617                             *rightBtnUpPix[large] : *irightBtnUpPix[large];
00618         }
00619 
00620         p->drawPixmap( 0, 0, btnbg );
00621 
00622     } else if ( isLeft ) {
00623 
00624         // Fill the button background with an appropriate color/gradient
00625         // This is for sticky and menu buttons
00626         KPixmap* grad = client->isActive() ? aUpperGradient : iUpperGradient;
00627         if (!grad) {
00628             QColor c = KDecoration::options()->color(ColorTitleBar, client->isActive());
00629             p->fillRect(0, 0, width(), height(), c );
00630         } else
00631             p->drawPixmap( 0, 0, *grad, 0,1, width(), height() );
00632 
00633     } else {
00634         // Draw a plain background for menus or sticky buttons on RHS
00635         QColor c = KDecoration::options()->color(ColorFrame, client->isActive());
00636         p->fillRect(0, 0, width(), height(), c);
00637     }
00638 
00639 
00640     // If we have a decoration bitmap, then draw that
00641     // otherwise we paint a menu button (with mini icon), or a sticky button.
00642     if( deco ) {
00643         // Select the appropriate button decoration color
00644         bool darkDeco = qGray( KDecoration::options()->color(
00645                 isLeft? ColorTitleBar : ColorButtonBg,
00646                 client->isActive()).rgb() ) > 127;
00647 
00648         if (isMouseOver)
00649             p->setPen( darkDeco ? Qt::darkGray : Qt::lightGray );
00650         else
00651             p->setPen( darkDeco ? Qt::black : Qt::white );
00652 
00653         int xOff = (width()-10)/2;
00654         int yOff = (height()-10)/2;
00655         p->drawPixmap(isDown() ? xOff+1: xOff, isDown() ? yOff+1 : yOff, *deco);
00656 
00657     } else {
00658         KPixmap btnpix;
00659 
00660         if (isSticky) {
00661             if (client->isActive())
00662                 btnpix = isOn() ? *pinDownPix : *pinUpPix;
00663             else
00664                 btnpix = isOn() ? *ipinDownPix : *ipinUpPix;
00665         } else
00666             btnpix = client->icon().pixmap( QIconSet::Small, QIconSet::Normal );
00667 
00668         // Intensify the image if required
00669         if (isMouseOver) {
00670                     btnpix = KPixmapEffect::intensity(btnpix, 0.8);
00671         }
00672 
00673         // Smooth scale the pixmap for small titlebars
00674         // This is slow, but we assume this isn't done too often
00675         if ( width() < 16 ) {
00676             btnpix.convertFromImage(btnpix.convertToImage().smoothScale(12, 12));
00677             p->drawPixmap( 0, 0, btnpix );
00678         }
00679         else
00680             p->drawPixmap( width()/2-8, height()/2-8, btnpix );
00681     }
00682 }
00683 
00684 
00685 // Make the protected member public
00686 void KDEDefaultButton::turnOn( bool isOn )
00687 {
00688     if ( isToggleButton() )
00689         setOn( isOn );
00690 }
00691 
00692 
00693 void KDEDefaultButton::enterEvent(QEvent *e)
00694 {
00695     isMouseOver=true;
00696     repaint(false);
00697     QButton::enterEvent(e);
00698 }
00699 
00700 
00701 void KDEDefaultButton::leaveEvent(QEvent *e)
00702 {
00703     isMouseOver=false;
00704     repaint(false);
00705     QButton::leaveEvent(e);
00706 }
00707 
00708 
00709 void KDEDefaultButton::mousePressEvent( QMouseEvent* e )
00710 {
00711     last_button = e->button();
00712     QMouseEvent me( e->type(), e->pos(), e->globalPos(),
00713                     (e->button()&realizeButtons)?LeftButton:NoButton, e->state() );
00714     QButton::mousePressEvent( &me );
00715 }
00716 
00717 
00718 void KDEDefaultButton::mouseReleaseEvent( QMouseEvent* e )
00719 {
00720     last_button = e->button();
00721     QMouseEvent me( e->type(), e->pos(), e->globalPos(),
00722                     (e->button()&realizeButtons)?LeftButton:NoButton, e->state() );
00723     QButton::mouseReleaseEvent( &me );
00724 }
00725 
00726 
00727 // ===========================================================================
00728 
00729 KDEDefaultClient::KDEDefaultClient( KDecorationBridge* b, KDecorationFactory* f )
00730     : KDecoration( b, f ),
00731       m_closing(false)
00732 {
00733 }
00734 
00735 void KDEDefaultClient::init()
00736 {
00737     connect( this, SIGNAL( keepAboveChanged( bool )), SLOT( keepAboveChange( bool )));
00738     connect( this, SIGNAL( keepBelowChanged( bool )), SLOT( keepBelowChange( bool )));
00739 
00740     createMainWidget( WResizeNoErase | WStaticContents | WRepaintNoErase );
00741     widget()->installEventFilter( this );
00742 
00743     // No flicker thanks
00744     widget()->setBackgroundMode( QWidget::NoBackground );
00745 
00746     // Set button pointers to NULL so we can track things
00747     for(int i=0; i < KDEDefaultClient::BtnCount; i++)
00748         button[i] = NULL;
00749 
00750     // Finally, toolWindows look small
00751     if ( isTool() ) {
00752         titleHeight  = toolTitleHeight;
00753         largeButtons = false;
00754     }
00755     else {
00756         titleHeight  = normalTitleHeight;
00757         largeButtons = true;
00758     }
00759 
00760     // Pack the windowWrapper() window within a grid
00761     g = new QGridLayout(widget(), 0, 0, 0);
00762     g->setResizeMode(QLayout::FreeResize);
00763     g->addRowSpacing(0, 3);       // Top grab bar
00764     g->addRowSpacing(2, 1);       // line under titlebar
00765     if( isPreview())
00766         g->addWidget( new QLabel( i18n( "<b><center>KDE2 preview</center></b>" ), widget()), 3, 1);
00767     else
00768         g->addItem( new QSpacerItem( 0, 0 ), 3, 1); // no widget in the middle
00769 
00770     // without the next line, unshade flickers
00771     g->addItem( new QSpacerItem( 0, 0, QSizePolicy::Fixed,
00772                                  QSizePolicy::Expanding ) );
00773     g->setRowStretch(3, 10);      // Wrapped window
00774 
00775     // Determine the size of the lower grab bar
00776     spacer = new QSpacerItem(10,
00777             mustDrawHandle() ? grabBorderWidth : borderWidth,
00778             QSizePolicy::Expanding, QSizePolicy::Minimum);
00779     g->addItem(spacer, 4, 1);
00780 
00781     g->addColSpacing(0, borderWidth);
00782     g->addColSpacing(2, borderWidth);
00783 
00784     // Pack the titlebar HBox with items
00785     hb = new QBoxLayout(0, QBoxLayout::LeftToRight, 0, 0, 0 );
00786     hb->setResizeMode( QLayout::FreeResize );
00787     g->addLayout ( hb, 1, 1 );
00788 
00789     addClientButtons( options()->titleButtonsLeft() );
00790     titlebar = new QSpacerItem( 10, titleHeight, QSizePolicy::Expanding,
00791                                 QSizePolicy::Minimum );
00792     hb->addItem(titlebar);
00793     hb->addSpacing(2);
00794     addClientButtons( options()->titleButtonsRight(), false );
00795 }
00796 
00797 
00798 void KDEDefaultClient::addClientButtons( const QString& s, bool isLeft )
00799 {
00800     if (s.length() > 0)
00801         for(unsigned int i = 0; i < s.length(); i++) {
00802         switch( s[i].latin1() )
00803         {
00804             // Menu button
00805             case 'M':
00806                 if (!button[BtnMenu])
00807                 {
00808                     button[BtnMenu] = new KDEDefaultButton(this, "menu",
00809                             largeButtons, isLeft, false, NULL, i18n("Menu"), LeftButton|RightButton);
00810                     connect( button[BtnMenu], SIGNAL(pressed()),
00811                             this, SLOT(menuButtonPressed()) );
00812                     connect( button[BtnMenu], SIGNAL(released()),
00813                              this, SLOT(menuButtonReleased()));
00814                     hb->addWidget( button[BtnMenu] );
00815                 }
00816                 break;
00817 
00818             // Sticky button
00819             case 'S':
00820                 if (!button[BtnSticky])
00821                 {
00822                     button[BtnSticky] = new KDEDefaultButton(this, "sticky",
00823                             largeButtons, isLeft, true, NULL,
00824                                                         isOnAllDesktops()?i18n("Not on all desktops"):i18n("On all desktops"));
00825                     button[BtnSticky]->turnOn( isOnAllDesktops() );
00826                     connect( button[BtnSticky], SIGNAL(clicked()),
00827                             this, SLOT(toggleOnAllDesktops()) );
00828                     hb->addWidget( button[BtnSticky] );
00829                 }
00830                 break;
00831 
00832             // Help button
00833             case 'H':
00834                 if( providesContextHelp() && (!button[BtnHelp]) )
00835                 {
00836                     button[BtnHelp] = new KDEDefaultButton(this, "help",
00837                             largeButtons, isLeft, true, question_bits,
00838                             i18n("Help"));
00839                     connect( button[BtnHelp], SIGNAL( clicked() ),
00840                             this, SLOT( showContextHelp() ));
00841                     hb->addWidget( button[BtnHelp] );
00842                 }
00843                 break;
00844 
00845             // Minimize button
00846             case 'I':
00847                 if ( (!button[BtnIconify]) && isMinimizable())
00848                 {
00849                     button[BtnIconify] = new KDEDefaultButton(this, "iconify",
00850                             largeButtons, isLeft, true, iconify_bits,
00851                             i18n("Minimize"));
00852                     connect( button[BtnIconify], SIGNAL( clicked()),
00853                             this, SLOT(minimize()) );
00854                     hb->addWidget( button[BtnIconify] );
00855                 }
00856                 break;
00857 
00858             // Maximize button
00859             case 'A':
00860                 if ( (!button[BtnMax]) && isMaximizable())
00861                 {
00862                     button[BtnMax]  = new KDEDefaultButton(this, "maximize",
00863                             largeButtons, isLeft, true, maximize_bits,
00864                             i18n("Maximize"), LeftButton|MidButton|RightButton);
00865                     connect( button[BtnMax], SIGNAL( clicked()),
00866                             this, SLOT(slotMaximize()) );
00867                     hb->addWidget( button[BtnMax] );
00868                 }
00869                 break;
00870 
00871             // Close button
00872             case 'X':
00873                 if (!button[BtnClose] && isCloseable())
00874                 {
00875                     button[BtnClose] = new KDEDefaultButton(this, "close",
00876                             largeButtons, isLeft, true, close_bits,
00877                             i18n("Close"));
00878                     connect( button[BtnClose], SIGNAL( clicked()),
00879                             this, SLOT(closeWindow()) );
00880                     hb->addWidget( button[BtnClose] );
00881                 }
00882                 break;
00883 
00884             // Above button
00885             case 'F':
00886                 if ( (!button[BtnAbove]))
00887                 {
00888                     button[BtnAbove]  = new KDEDefaultButton(this, "above",
00889                             largeButtons, isLeft, true,
00890                                                         keepAbove() ? above_on_bits : above_off_bits,
00891                             i18n("Keep Above Others"));
00892                     connect( button[BtnAbove], SIGNAL( clicked()),
00893                             this, SLOT(slotAbove()) );
00894                     hb->addWidget( button[BtnAbove] );
00895                 }
00896                 break;
00897 
00898             // Below button
00899             case 'B':
00900                 if ( (!button[BtnBelow]))
00901                 {
00902                     button[BtnBelow]  = new KDEDefaultButton(this, "below",
00903                             largeButtons, isLeft, true,
00904                                                         keepBelow() ? below_on_bits : below_off_bits,
00905                             i18n("Keep Below Others"));
00906                     connect( button[BtnBelow], SIGNAL( clicked()),
00907                             this, SLOT(slotBelow()) );
00908                     hb->addWidget( button[BtnBelow] );
00909                 }
00910                 break;
00911 
00912             // Shade button
00913             case 'L':
00914                 if ( (!button[BtnShade]) && isShadeable())
00915                 {
00916                     button[BtnShade]  = new KDEDefaultButton(this, "shade",
00917                             largeButtons, isLeft, true,
00918                                                         isSetShade() ? shade_on_bits : shade_off_bits,
00919                             isSetShade() ? i18n( "Unshade" ) : i18n("Shade"));
00920                     connect( button[BtnShade], SIGNAL( clicked()),
00921                             this, SLOT(slotShade()) );
00922                     hb->addWidget( button[BtnShade] );
00923                 }
00924                 break;
00925 
00926             // Spacer item (only for non-tool windows)
00927             case '_':
00928                 if ( !isTool() )
00929                     hb->addSpacing(borderWidth/2);
00930         }
00931     }
00932 }
00933 
00934 void KDEDefaultClient::reset( unsigned long )
00935 {
00936     widget()->repaint();
00937 }
00938 
00939 bool KDEDefaultClient::mustDrawHandle() const 
00940 { 
00941     bool drawSmallBorders = !options()->moveResizeMaximizedWindows();
00942     if (drawSmallBorders && (maximizeMode() & MaximizeVertical)) {
00943         return false;
00944     } else {
00945         return showGrabBar && isResizable();
00946     }
00947 }
00948 
00949 void KDEDefaultClient::iconChange()
00950 {
00951     if (button[BtnMenu] && button[BtnMenu]->isVisible())
00952         button[BtnMenu]->repaint(false);
00953 }
00954 
00955 void KDEDefaultClient::desktopChange()
00956 {
00957     if (button[BtnSticky]) {
00958                 bool on = isOnAllDesktops();
00959         button[BtnSticky]->turnOn(on);
00960         button[BtnSticky]->repaint(false);
00961                 QToolTip::remove( button[BtnSticky] );
00962         QToolTip::add( button[BtnSticky], on ? i18n("Not on all desktops") : i18n("On all desktops"));
00963     }
00964 }
00965 
00966 void KDEDefaultClient::keepAboveChange( bool above )
00967 {
00968     if (button[BtnAbove]) {
00969         button[BtnAbove]->setBitmap( above ? above_on_bits : above_off_bits );
00970         button[BtnAbove]->repaint(false);
00971     }
00972 }
00973 
00974 void KDEDefaultClient::keepBelowChange( bool below )
00975 {
00976     if (button[BtnBelow]) {
00977         button[BtnBelow]->setBitmap( below ? below_on_bits : below_off_bits );
00978         button[BtnBelow]->repaint(false);
00979     }
00980 }
00981 
00982 void KDEDefaultClient::slotMaximize()
00983 {
00984     maximize( button[BtnMax]->last_button );
00985 }
00986 
00987 void KDEDefaultClient::slotAbove()
00988 {
00989     setKeepAbove( !keepAbove());
00990     button[BtnAbove]->turnOn(keepAbove());
00991     button[BtnAbove]->repaint(true);
00992 }
00993 
00994 void KDEDefaultClient::slotBelow()
00995 {
00996     setKeepBelow( !keepBelow());
00997     button[BtnBelow]->turnOn(keepBelow());
00998     button[BtnBelow]->repaint(true);
00999 }
01000 
01001 void KDEDefaultClient::slotShade()
01002 {
01003     setShade( !isSetShade());
01004 }
01005 
01006 void KDEDefaultClient::resizeEvent( QResizeEvent* e)
01007 {
01008     doShape();
01009     calcHiddenButtons();
01010 
01011     if ( widget()->isShown())
01012     {
01013         widget()->update( widget()->rect());
01014 #if 1 // what's the point of this, when paintEvent() repaints everything anyway?
01015         int dx = 0;
01016         int dy = 0;
01017 
01018         if ( e->oldSize().width() != width() )
01019            dx = 32 + QABS( e->oldSize().width() -  width() );
01020 
01021         if ( e->oldSize().height() != height() )
01022            dy = 8 + QABS( e->oldSize().height() -  height() );
01023 
01024         if ( dy )
01025            widget()->update( 0, height() - dy + 1, width(), dy );
01026 
01027         if ( dx )
01028         {
01029            widget()->update( width() - dx + 1, 0, dx, height() );
01030            widget()->update( QRect( QPoint(4,4), titlebar->geometry().bottomLeft() -
01031                     QPoint(1,0) ) );
01032            widget()->update( QRect( titlebar->geometry().topRight(), QPoint(width() - 4,
01033                           titlebar->geometry().bottom()) ) );
01034            // Titlebar needs no paint event
01035            QApplication::postEvent( widget(), new QPaintEvent(titlebar->geometry(),
01036                                      FALSE) );
01037         }
01038 #endif
01039     }
01040 }
01041 
01042 
01043 void KDEDefaultClient::captionChange()
01044 {
01045     widget()->repaint( titlebar->geometry(), false );
01046 }
01047 
01048 
01049 void KDEDefaultClient::paintEvent( QPaintEvent* )
01050 {
01051     if (!KDEDefault_initialized)
01052         return;
01053 
01054     QColorGroup g;
01055     int offset;
01056 
01057     KPixmap* upperGradient = isActive() ? aUpperGradient : iUpperGradient;
01058 
01059     QPainter p(widget());
01060 
01061     // Obtain widget bounds.
01062     QRect r(widget()->rect());
01063     int x = r.x();
01064     int y = r.y();
01065     int x2 = r.width() - 1;
01066     int y2 = r.height() - 1;
01067     int w  = r.width();
01068     int h  = r.height();
01069 
01070     // Determine where to place the extended left titlebar
01071     int leftFrameStart = (h > 42) ? y+titleHeight+26: y+titleHeight;
01072 
01073     // Determine where to make the titlebar color transition
01074     r = titlebar->geometry();
01075     int rightOffset = r.x()+r.width()+1;
01076 
01077     // Create a disposable pixmap buffer for the titlebar
01078     // very early before drawing begins so there is no lag
01079     // during painting pixels.
01080     titleBuffer->resize( rightOffset-3, titleHeight+1 );
01081 
01082     // Draw an outer black frame
01083     p.setPen(Qt::black);
01084     p.drawRect(x,y,w,h);
01085 
01086     // Draw part of the frame that is the titlebar color
01087     g = options()->colorGroup(ColorTitleBar, isActive());
01088     p.setPen(g.light());
01089     p.drawLine(x+1, y+1, rightOffset-1, y+1);
01090     p.drawLine(x+1, y+1, x+1, leftFrameStart+borderWidth-4);
01091 
01092     // Draw titlebar colour separator line
01093     p.setPen(g.dark());
01094     p.drawLine(rightOffset-1, y+1, rightOffset-1, titleHeight+2);
01095 
01096     p.fillRect(x+2, y+titleHeight+3,
01097                borderWidth-4, leftFrameStart+borderWidth-y-titleHeight-8,
01098                options()->color(ColorTitleBar, isActive() ));
01099 
01100     // Finish drawing the titlebar extension
01101     p.setPen(Qt::black);
01102     p.drawLine(x+1, leftFrameStart+borderWidth-4, x+borderWidth-2, leftFrameStart-1);
01103     p.setPen(g.mid());
01104     p.drawLine(x+borderWidth-2, y+titleHeight+3, x+borderWidth-2, leftFrameStart-2);
01105 
01106     // Fill out the border edges
01107     g = options()->colorGroup(ColorFrame, isActive());
01108     p.setPen(g.light());
01109     p.drawLine(rightOffset, y+1, x2-1, y+1);
01110     p.drawLine(x+1, leftFrameStart+borderWidth-3, x+1, y2-1);
01111     p.setPen(g.dark());
01112     p.drawLine(x2-1, y+1, x2-1, y2-1);
01113     p.drawLine(x+1, y2-1, x2-1, y2-1);
01114 
01115     p.setPen(options()->color(ColorFrame, isActive()));
01116     QPointArray a;
01117     QBrush brush( options()->color(ColorFrame, isActive()), Qt::SolidPattern );
01118     p.setBrush( brush );                       // use solid, yellow brush
01119     a.setPoints( 4, x+2,             leftFrameStart+borderWidth-4,
01120                     x+borderWidth-2, leftFrameStart,
01121                     x+borderWidth-2, y2-2,
01122                     x+2,             y2-2);
01123     p.drawPolygon( a );
01124     p.fillRect(x2-borderWidth+2, y+titleHeight+3,
01125                borderWidth-3, y2-y-titleHeight-4,
01126                options()->color(ColorFrame, isActive() ));
01127 
01128     // Draw the bottom handle if required
01129     if (mustDrawHandle())
01130     {
01131         if(w > 50)
01132         {
01133             qDrawShadePanel(&p, x+1, y2-grabBorderWidth+2, 2*borderWidth+12, grabBorderWidth-2,
01134                             g, false, 1, &g.brush(QColorGroup::Mid));
01135             qDrawShadePanel(&p, x+2*borderWidth+13, y2-grabBorderWidth+2, w-4*borderWidth-26, grabBorderWidth-2,
01136                             g, false, 1, isActive() ?
01137                             &g.brush(QColorGroup::Background) :
01138                             &g.brush(QColorGroup::Mid));
01139             qDrawShadePanel(&p, x2-2*borderWidth-12, y2-grabBorderWidth+2, 2*borderWidth+12, grabBorderWidth-2,
01140                             g, false, 1, &g.brush(QColorGroup::Mid));
01141         } else
01142             qDrawShadePanel(&p, x+1, y2-grabBorderWidth+2, w-2, grabBorderWidth-2,
01143                             g, false, 1, isActive() ?
01144                             &g.brush(QColorGroup::Background) :
01145                             &g.brush(QColorGroup::Mid));
01146         offset = grabBorderWidth;
01147     } else
01148         {
01149             p.fillRect(x+2, y2-borderWidth+2, w-4, borderWidth-3,
01150                        options()->color(ColorFrame, isActive() ));
01151             offset = borderWidth;
01152         }
01153 
01154     // Draw a frame around the wrapped widget.
01155     p.setPen( g.dark() );
01156     p.drawRect( x+borderWidth-1, y+titleHeight+3, w-2*borderWidth+2, h-titleHeight-offset-2 );
01157 
01158     // Draw the title bar.
01159     r = titlebar->geometry();
01160 
01161     // Obtain titlebar blend colours
01162     QColor c1 = options()->color(ColorTitleBar, isActive() );
01163     QColor c2 = options()->color(ColorFrame, isActive() );
01164 
01165     // Fill with frame color behind RHS buttons
01166     p.fillRect( rightOffset, y+2, x2-rightOffset-1, titleHeight+1, c2);
01167 
01168     QPainter p2( titleBuffer, this );
01169 
01170     // Draw the titlebar gradient
01171     if (upperGradient)
01172         p2.drawTiledPixmap(0, 0, rightOffset-3, titleHeight+1, *upperGradient);
01173     else
01174         p2.fillRect(0, 0, rightOffset-3, titleHeight+1, c1);
01175 
01176     // Draw the title text on the pixmap, and with a smaller font
01177     // for toolwindows than the default.
01178     QFont fnt = options()->font(true);
01179 
01180     if ( isTool() )
01181        fnt.setPointSize( fnt.pointSize()-2 );  // Shrink font by 2pt
01182 
01183     p2.setFont( fnt );
01184 
01185     // Draw the titlebar stipple if active and available
01186     if (isActive() && titlePix)
01187     {
01188         QFontMetrics fm(fnt);
01189         int captionWidth = fm.width(caption());
01190         if (caption().isRightToLeft())
01191             p2.drawTiledPixmap( r.x(), 0, r.width()-captionWidth-4,
01192                                 titleHeight+1, *titlePix );
01193         else
01194             p2.drawTiledPixmap( r.x()+captionWidth+3, 0, r.width()-captionWidth-4,
01195                                 titleHeight+1, *titlePix );
01196     }
01197 
01198     p2.setPen( options()->color(ColorFont, isActive()) );
01199     p2.drawText(r.x(), 1, r.width()-1, r.height(),
01200         (caption().isRightToLeft() ? AlignRight : AlignLeft) | AlignVCenter,
01201         caption() );
01202 
01203     bitBlt( widget(), 2, 2, titleBuffer );
01204 
01205     p2.end();
01206 
01207     // Ensure a shaded window has no unpainted areas
01208     // Is this still needed?
01209 #if 1
01210     p.setPen(c2);
01211     p.drawLine(x+borderWidth, y+titleHeight+4, x2-borderWidth, y+titleHeight+4);
01212 #endif
01213 }
01214 
01215 
01216 void KDEDefaultClient::doShape()
01217 {
01218     QRegion mask(QRect(0, 0, width(), height()));
01219     mask -= QRect(0, 0, 1, 1);
01220     mask -= QRect(width()-1, 0, 1, 1);
01221     mask -= QRect(0, height()-1, 1, 1);
01222     mask -= QRect(width()-1, height()-1, 1, 1);
01223     setMask(mask);
01224 }
01225 
01226 
01227 void KDEDefaultClient::showEvent(QShowEvent *)
01228 {
01229     calcHiddenButtons();
01230     doShape();
01231 }
01232 
01233 
01234 void KDEDefaultClient::mouseDoubleClickEvent( QMouseEvent * e )
01235 {
01236     if (titlebar->geometry().contains( e->pos() ) )
01237                 titlebarDblClickOperation();
01238 }
01239 
01240 
01241 void KDEDefaultClient::maximizeChange()
01242 {
01243     if (button[BtnMax]) {
01244                 bool m = maximizeMode() == MaximizeFull;
01245         button[BtnMax]->setBitmap(m ? minmax_bits : maximize_bits);
01246                 QToolTip::remove( button[ BtnMax ] );
01247                 QToolTip::add( button[BtnMax], m ? i18n("Restore") : i18n("Maximize"));
01248     }
01249     spacer->changeSize(10, mustDrawHandle() ? 8 : 4,
01250             QSizePolicy::Expanding, QSizePolicy::Minimum);
01251     g->activate();
01252 }
01253 
01254 
01255 void KDEDefaultClient::activeChange()
01256 {
01257     for(int i=KDEDefaultClient::BtnHelp; i < KDEDefaultClient::BtnCount; i++)
01258         if(button[i])
01259             button[i]->repaint(false);
01260     widget()->repaint(false);
01261 }
01262 
01263 void KDEDefaultClient::shadeChange()
01264 {
01265     if (button[BtnShade]) {
01266         bool on = isSetShade();
01267         button[BtnShade]->setBitmap( on ? shade_on_bits : shade_off_bits );
01268         button[BtnShade]->turnOn(on);
01269         button[BtnShade]->repaint(false);
01270                 QToolTip::remove( button[BtnShade] );
01271         QToolTip::add( button[BtnShade], on ? i18n("Unshade") : i18n("Shade"));
01272     }
01273 }
01274 
01275 QSize KDEDefaultClient::minimumSize() const
01276 {
01277     return QSize( 100, 50 ); // FRAME
01278 }
01279 
01280 void KDEDefaultClient::resize( const QSize& s )
01281 {
01282     widget()->resize( s );
01283 }
01284 
01285 void KDEDefaultClient::borders( int& left, int& right, int& top, int& bottom ) const
01286 { // FRAME
01287     left = right = borderWidth;
01288 //    , y+titleHeight+3, w-6, h-titleHeight-offset-6 );
01289     top = titleHeight + 4;
01290     bottom = mustDrawHandle() ? grabBorderWidth : borderWidth;
01291 }
01292 
01293 // The hiding button while shrinking, show button while expanding magic
01294 void KDEDefaultClient::calcHiddenButtons()
01295 {
01296     // Hide buttons in this order:
01297     // Shade, Below, Above, Sticky, Help, Maximize, Minimize, Close, Menu.
01298     KDEDefaultButton* btnArray[] = { button[ BtnShade ], button[ BtnBelow ],
01299                         button[ BtnAbove ], button[BtnSticky], button[BtnHelp],
01300             button[BtnMax], button[BtnIconify], button[BtnClose],
01301             button[BtnMenu] };
01302         const int buttons_cnt = sizeof( btnArray ) / sizeof( btnArray[ 0 ] );
01303 
01304     int minwidth  = largeButtons ? 10 * normalTitleHeight : 10 * toolTitleHeight; // Start hiding at this width
01305     int btn_width = largeButtons ? normalTitleHeight : toolTitleHeight;
01306     int current_width = width();
01307     int count = 0;
01308     int i;
01309 
01310     // Find out how many buttons we need to hide.
01311     while (current_width < minwidth)
01312     {
01313         current_width += btn_width;
01314         count++;
01315     }
01316 
01317     // Bound the number of buttons to hide
01318     if (count > buttons_cnt) count = buttons_cnt;
01319 
01320     // Hide the required buttons...
01321     for(i = 0; i < count; i++)
01322     {
01323         if (btnArray[i] && btnArray[i]->isVisible() )
01324             btnArray[i]->hide();
01325     }
01326 
01327     // Show the rest of the buttons...
01328     for(i = count; i < buttons_cnt; i++)
01329     {
01330         if (btnArray[i] && (!btnArray[i]->isVisible()) )
01331             btnArray[i]->show();
01332     }
01333 }
01334 
01335 
01336 KDecoration::Position KDEDefaultClient::mousePosition( const QPoint& p ) const
01337 {
01338     Position m = PositionCenter;
01339 
01340     int bottomSize = mustDrawHandle() ? grabBorderWidth : borderWidth;
01341 
01342     const int range = 14 + 3*borderWidth/2;
01343 
01344     if ( ( p.x() > borderWidth && p.x() < width() - borderWidth )
01345          && ( p.y() > 4 && p.y() < height() - bottomSize ) )
01346         m = PositionCenter;
01347     else if ( p.y() <= range && p.x() <= range)
01348         m = PositionTopLeft;
01349     else if ( p.y() >= height()-range && p.x() >= width()-range)
01350         m = PositionBottomRight;
01351     else if ( p.y() >= height()-range && p.x() <= range)
01352         m = PositionBottomLeft;
01353     else if ( p.y() <= range && p.x() >= width()-range)
01354         m = PositionTopRight;
01355     else if ( p.y() <= 4 )
01356         m = PositionTop;
01357     else if ( p.y() >= height()-bottomSize )
01358         m = PositionBottom;
01359     else if ( p.x() <= borderWidth )
01360         m = PositionLeft;
01361     else if ( p.x() >= width()-borderWidth )
01362         m = PositionRight;
01363     else
01364         m = PositionCenter;
01365 
01366     // Modify the mouse position if we are using a grab bar.
01367     if (mustDrawHandle())
01368         if (p.y() >= (height() - grabBorderWidth))
01369         {
01370             if (p.x() >= (width() - 2*borderWidth - 12))
01371                 m = PositionBottomRight;
01372             else if (p.x() <= 2*borderWidth + 12)
01373                 m = PositionBottomLeft;
01374             else
01375             m = PositionBottom;
01376         }
01377 
01378     return m;
01379 }
01380 
01381 
01382 // Make sure the menu button follows double click conventions set in kcontrol
01383 void KDEDefaultClient::menuButtonPressed()
01384 {
01385     static QTime t;
01386     static KDEDefaultClient* lastClient = NULL;
01387     bool dbl = ( lastClient == this && t.elapsed() <= QApplication::doubleClickInterval());
01388     lastClient = this;
01389     t.start();
01390 
01391     if (dbl)
01392     {
01393         m_closing = true;
01394         return;
01395     }
01396 
01397     QPoint menupoint ( button[BtnMenu]->rect().bottomLeft().x()-1,
01398                        button[BtnMenu]->rect().bottomLeft().y()+2 );
01399         KDecorationFactory* f = factory();
01400     QRect menuRect = button[BtnMenu]->rect();
01401     QPoint menutop = button[BtnMenu]->mapToGlobal(menuRect.topLeft());
01402     QPoint menubottom = button[BtnMenu]->mapToGlobal(menuRect.bottomRight());
01403     showWindowMenu(QRect(menutop, menubottom));
01404         if( !f->exists( this )) // 'this' was destroyed
01405             return;
01406     button[BtnMenu]->setDown(false);
01407 }
01408 
01409 void KDEDefaultClient::menuButtonReleased()
01410 {
01411     if (m_closing)
01412         closeWindow();
01413 }
01414 
01415 const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask
01416     | NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask | NET::TopMenuMask
01417     | NET::UtilityMask | NET::SplashMask;
01418 
01419 bool KDEDefaultClient::isTool() const
01420 {
01421     NET::WindowType type = windowType( SUPPORTED_WINDOW_TYPES_MASK );
01422     return type == NET::Toolbar || type == NET::Utility || type == NET::Menu;
01423 }
01424 
01425 
01426 bool KDEDefaultClient::eventFilter( QObject* o, QEvent* e )
01427 {
01428     if( o != widget())
01429     return false;
01430     switch( e->type())
01431     {
01432     case QEvent::Resize:
01433         resizeEvent( static_cast< QResizeEvent* >( e ));
01434         return true;
01435     case QEvent::Paint:
01436         paintEvent( static_cast< QPaintEvent* >( e ));
01437         return true;
01438     case QEvent::MouseButtonDblClick:
01439         mouseDoubleClickEvent( static_cast< QMouseEvent* >( e ));
01440         return true;
01441     case QEvent::MouseButtonPress:
01442         processMousePressEvent( static_cast< QMouseEvent* >( e ));
01443         return true;
01444     case QEvent::Show:
01445         showEvent( static_cast< QShowEvent* >( e ));
01446         return true;
01447     default:
01448         break;
01449     }
01450     return false;
01451 }
01452 
01453 
01454 } // namespace
01455 
01456 // Extended KWin plugin interface
01457 extern "C" KDecorationFactory* create_factory()
01458 {
01459     return new Default::KDEDefaultHandler();
01460 }
01461 
01462 #include "kdedefault.moc"
01463 // vim: ts=4
KDE Logo
This file is part of the documentation for kwin Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Sep 8 02:43:20 2005 by doxygen 1.3.6 written by Dimitri van Heesch, © 1997-2003