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 bool KDEDefaultHandler::supports( Ability ability )
00537 {
00538     switch( ability )
00539         {
00540         case AbilityAnnounceButtons:
00541         case AbilityButtonMenu:
00542         case AbilityButtonOnAllDesktops:
00543         case AbilityButtonSpacer:
00544         case AbilityButtonHelp:
00545         case AbilityButtonMinimize:
00546         case AbilityButtonMaximize:
00547         case AbilityButtonClose:
00548         case AbilityButtonAboveOthers:
00549         case AbilityButtonBelowOthers:
00550         case AbilityButtonShade:
00551             return true;
00552         default:
00553             return false;
00554         };
00555 }
00556 
00557 // ===========================================================================
00558 
00559 KDEDefaultButton::KDEDefaultButton(KDEDefaultClient *parent, const char *name,
00560            bool largeButton, bool isLeftButton, bool isStickyButton,
00561            const unsigned char *bitmap, const QString& tip, const int realizeBtns )
00562     : QButton(parent->widget(), name)
00563 {
00564     realizeButtons = realizeBtns;
00565 
00566     QToolTip::add( this, tip );
00567     setCursor( arrowCursor );
00568     setBackgroundMode( QWidget::NoBackground );
00569     setToggleButton( isStickyButton );
00570 
00571     isMouseOver = false;
00572     deco        = NULL;
00573     large       = largeButton;
00574     isLeft      = isLeftButton;
00575     isSticky    = isStickyButton;
00576     client      = parent;
00577 
00578     if (large)
00579        setFixedSize(normalTitleHeight, normalTitleHeight);
00580     else
00581        setFixedSize(toolTitleHeight, toolTitleHeight);
00582 
00583     if (bitmap)
00584         setBitmap(bitmap);
00585 }
00586 
00587 
00588 KDEDefaultButton::~KDEDefaultButton()
00589 {
00590     if (deco)
00591         delete deco;
00592 }
00593 
00594 
00595 QSize KDEDefaultButton::sizeHint() const
00596 {
00597    if ( large )
00598       return( QSize(normalTitleHeight, normalTitleHeight) );
00599    else
00600       return( QSize(toolTitleHeight, toolTitleHeight) );
00601 }
00602 
00603 
00604 void KDEDefaultButton::setBitmap(const unsigned char *bitmap)
00605 {
00606     if (deco)
00607         delete deco;
00608 
00609     deco = new QBitmap(10, 10, bitmap, true);
00610     deco->setMask( *deco );
00611     repaint( false );
00612 }
00613 
00614 
00615 void KDEDefaultButton::drawButton(QPainter *p)
00616 {
00617     if (!KDEDefault_initialized)
00618         return;
00619 
00620     if (deco) {
00621         // Fill the button background with an appropriate button image
00622         KPixmap btnbg;
00623 
00624         if (isLeft) {
00625             if (isDown())
00626                 btnbg = client->isActive() ?
00627                             *leftBtnDownPix[large] : *ileftBtnDownPix[large];
00628             else
00629                 btnbg = client->isActive() ?
00630                             *leftBtnUpPix[large] : *ileftBtnUpPix[large];
00631         } else {
00632             if (isDown())
00633                 btnbg = client->isActive() ?
00634                             *rightBtnDownPix[large] : *irightBtnDownPix[large];
00635             else
00636                 btnbg = client->isActive() ?
00637                             *rightBtnUpPix[large] : *irightBtnUpPix[large];
00638         }
00639 
00640         p->drawPixmap( 0, 0, btnbg );
00641 
00642     } else if ( isLeft ) {
00643 
00644         // Fill the button background with an appropriate color/gradient
00645         // This is for sticky and menu buttons
00646         KPixmap* grad = client->isActive() ? aUpperGradient : iUpperGradient;
00647         if (!grad) {
00648             QColor c = KDecoration::options()->color(ColorTitleBar, client->isActive());
00649             p->fillRect(0, 0, width(), height(), c );
00650         } else
00651             p->drawPixmap( 0, 0, *grad, 0,1, width(), height() );
00652 
00653     } else {
00654         // Draw a plain background for menus or sticky buttons on RHS
00655         QColor c = KDecoration::options()->color(ColorFrame, client->isActive());
00656         p->fillRect(0, 0, width(), height(), c);
00657     }
00658 
00659 
00660     // If we have a decoration bitmap, then draw that
00661     // otherwise we paint a menu button (with mini icon), or a sticky button.
00662     if( deco ) {
00663         // Select the appropriate button decoration color
00664         bool darkDeco = qGray( KDecoration::options()->color(
00665                 isLeft? ColorTitleBar : ColorButtonBg,
00666                 client->isActive()).rgb() ) > 127;
00667 
00668         if (isMouseOver)
00669             p->setPen( darkDeco ? Qt::darkGray : Qt::lightGray );
00670         else
00671             p->setPen( darkDeco ? Qt::black : Qt::white );
00672 
00673         int xOff = (width()-10)/2;
00674         int yOff = (height()-10)/2;
00675         p->drawPixmap(isDown() ? xOff+1: xOff, isDown() ? yOff+1 : yOff, *deco);
00676 
00677     } else {
00678         KPixmap btnpix;
00679 
00680         if (isSticky) {
00681             if (client->isActive())
00682                 btnpix = isOn() ? *pinDownPix : *pinUpPix;
00683             else
00684                 btnpix = isOn() ? *ipinDownPix : *ipinUpPix;
00685         } else
00686             btnpix = client->icon().pixmap( QIconSet::Small, QIconSet::Normal );
00687 
00688         // Intensify the image if required
00689         if (isMouseOver) {
00690                     btnpix = KPixmapEffect::intensity(btnpix, 0.8);
00691         }
00692 
00693         // Smooth scale the pixmap for small titlebars
00694         // This is slow, but we assume this isn't done too often
00695         if ( width() < 16 ) {
00696             btnpix.convertFromImage(btnpix.convertToImage().smoothScale(12, 12));
00697             p->drawPixmap( 0, 0, btnpix );
00698         }
00699         else
00700             p->drawPixmap( width()/2-8, height()/2-8, btnpix );
00701     }
00702 }
00703 
00704 
00705 // Make the protected member public
00706 void KDEDefaultButton::turnOn( bool isOn )
00707 {
00708     if ( isToggleButton() )
00709         setOn( isOn );
00710 }
00711 
00712 
00713 void KDEDefaultButton::enterEvent(QEvent *e)
00714 {
00715     isMouseOver=true;
00716     repaint(false);
00717     QButton::enterEvent(e);
00718 }
00719 
00720 
00721 void KDEDefaultButton::leaveEvent(QEvent *e)
00722 {
00723     isMouseOver=false;
00724     repaint(false);
00725     QButton::leaveEvent(e);
00726 }
00727 
00728 
00729 void KDEDefaultButton::mousePressEvent( QMouseEvent* e )
00730 {
00731     last_button = e->button();
00732     QMouseEvent me( e->type(), e->pos(), e->globalPos(),
00733                     (e->button()&realizeButtons)?LeftButton:NoButton, e->state() );
00734     QButton::mousePressEvent( &me );
00735 }
00736 
00737 
00738 void KDEDefaultButton::mouseReleaseEvent( QMouseEvent* e )
00739 {
00740     last_button = e->button();
00741     QMouseEvent me( e->type(), e->pos(), e->globalPos(),
00742                     (e->button()&realizeButtons)?LeftButton:NoButton, e->state() );
00743     QButton::mouseReleaseEvent( &me );
00744 }
00745 
00746 
00747 // ===========================================================================
00748 
00749 KDEDefaultClient::KDEDefaultClient( KDecorationBridge* b, KDecorationFactory* f )
00750     : KDecoration( b, f ),
00751       m_closing(false)
00752 {
00753 }
00754 
00755 void KDEDefaultClient::init()
00756 {
00757     connect( this, SIGNAL( keepAboveChanged( bool )), SLOT( keepAboveChange( bool )));
00758     connect( this, SIGNAL( keepBelowChanged( bool )), SLOT( keepBelowChange( bool )));
00759 
00760     createMainWidget( WResizeNoErase | WStaticContents | WRepaintNoErase );
00761     widget()->installEventFilter( this );
00762 
00763     // No flicker thanks
00764     widget()->setBackgroundMode( QWidget::NoBackground );
00765 
00766     // Set button pointers to NULL so we can track things
00767     for(int i=0; i < KDEDefaultClient::BtnCount; i++)
00768         button[i] = NULL;
00769 
00770     // Finally, toolWindows look small
00771     if ( isTool() ) {
00772         titleHeight  = toolTitleHeight;
00773         largeButtons = false;
00774     }
00775     else {
00776         titleHeight  = normalTitleHeight;
00777         largeButtons = true;
00778     }
00779 
00780     // Pack the windowWrapper() window within a grid
00781     g = new QGridLayout(widget(), 0, 0, 0);
00782     g->setResizeMode(QLayout::FreeResize);
00783     g->addRowSpacing(0, 3);       // Top grab bar
00784     g->addRowSpacing(2, 1);       // line under titlebar
00785     if( isPreview())
00786         g->addWidget( new QLabel( i18n( "<b><center>KDE2 preview</center></b>" ), widget()), 3, 1);
00787     else
00788         g->addItem( new QSpacerItem( 0, 0 ), 3, 1); // no widget in the middle
00789 
00790     // without the next line, unshade flickers
00791     g->addItem( new QSpacerItem( 0, 0, QSizePolicy::Fixed,
00792                                  QSizePolicy::Expanding ) );
00793     g->setRowStretch(3, 10);      // Wrapped window
00794 
00795     // Determine the size of the lower grab bar
00796     spacer = new QSpacerItem(10,
00797             mustDrawHandle() ? grabBorderWidth : borderWidth,
00798             QSizePolicy::Expanding, QSizePolicy::Minimum);
00799     g->addItem(spacer, 4, 1);
00800 
00801     g->addColSpacing(0, borderWidth);
00802     g->addColSpacing(2, borderWidth);
00803 
00804     // Pack the titlebar HBox with items
00805     hb = new QBoxLayout(0, QBoxLayout::LeftToRight, 0, 0, 0 );
00806     hb->setResizeMode( QLayout::FreeResize );
00807     g->addLayout ( hb, 1, 1 );
00808 
00809     addClientButtons( options()->titleButtonsLeft() );
00810     titlebar = new QSpacerItem( 10, titleHeight, QSizePolicy::Expanding,
00811                                 QSizePolicy::Minimum );
00812     hb->addItem(titlebar);
00813     hb->addSpacing(2);
00814     addClientButtons( options()->titleButtonsRight(), false );
00815 }
00816 
00817 
00818 void KDEDefaultClient::addClientButtons( const QString& s, bool isLeft )
00819 {
00820     if (s.length() > 0)
00821         for(unsigned int i = 0; i < s.length(); i++) {
00822         switch( s[i].latin1() )
00823         {
00824             // Menu button
00825             case 'M':
00826                 if (!button[BtnMenu])
00827                 {
00828                     button[BtnMenu] = new KDEDefaultButton(this, "menu",
00829                             largeButtons, isLeft, false, NULL, i18n("Menu"), LeftButton|RightButton);
00830                     connect( button[BtnMenu], SIGNAL(pressed()),
00831                             this, SLOT(menuButtonPressed()) );
00832                     connect( button[BtnMenu], SIGNAL(released()),
00833                              this, SLOT(menuButtonReleased()));
00834                     hb->addWidget( button[BtnMenu] );
00835                 }
00836                 break;
00837 
00838             // Sticky button
00839             case 'S':
00840                 if (!button[BtnSticky])
00841                 {
00842                     button[BtnSticky] = new KDEDefaultButton(this, "sticky",
00843                             largeButtons, isLeft, true, NULL,
00844                                                         isOnAllDesktops()?i18n("Not on all desktops"):i18n("On all desktops"));
00845                     button[BtnSticky]->turnOn( isOnAllDesktops() );
00846                     connect( button[BtnSticky], SIGNAL(clicked()),
00847                             this, SLOT(toggleOnAllDesktops()) );
00848                     hb->addWidget( button[BtnSticky] );
00849                 }
00850                 break;
00851 
00852             // Help button
00853             case 'H':
00854                 if( providesContextHelp() && (!button[BtnHelp]) )
00855                 {
00856                     button[BtnHelp] = new KDEDefaultButton(this, "help",
00857                             largeButtons, isLeft, true, question_bits,
00858                             i18n("Help"));
00859                     connect( button[BtnHelp], SIGNAL( clicked() ),
00860                             this, SLOT( showContextHelp() ));
00861                     hb->addWidget( button[BtnHelp] );
00862                 }
00863                 break;
00864 
00865             // Minimize button
00866             case 'I':
00867                 if ( (!button[BtnIconify]) && isMinimizable())
00868                 {
00869                     button[BtnIconify] = new KDEDefaultButton(this, "iconify",
00870                             largeButtons, isLeft, true, iconify_bits,
00871                             i18n("Minimize"));
00872                     connect( button[BtnIconify], SIGNAL( clicked()),
00873                             this, SLOT(minimize()) );
00874                     hb->addWidget( button[BtnIconify] );
00875                 }
00876                 break;
00877 
00878             // Maximize button
00879             case 'A':
00880                 if ( (!button[BtnMax]) && isMaximizable())
00881                 {
00882                     button[BtnMax]  = new KDEDefaultButton(this, "maximize",
00883                             largeButtons, isLeft, true, maximize_bits,
00884                             i18n("Maximize"), LeftButton|MidButton|RightButton);
00885                     connect( button[BtnMax], SIGNAL( clicked()),
00886                             this, SLOT(slotMaximize()) );
00887                     hb->addWidget( button[BtnMax] );
00888                 }
00889                 break;
00890 
00891             // Close button
00892             case 'X':
00893                 if (!button[BtnClose] && isCloseable())
00894                 {
00895                     button[BtnClose] = new KDEDefaultButton(this, "close",
00896                             largeButtons, isLeft, true, close_bits,
00897                             i18n("Close"));
00898                     connect( button[BtnClose], SIGNAL( clicked()),
00899                             this, SLOT(closeWindow()) );
00900                     hb->addWidget( button[BtnClose] );
00901                 }
00902                 break;
00903 
00904             // Above button
00905             case 'F':
00906                 if ( (!button[BtnAbove]))
00907                 {
00908                     button[BtnAbove]  = new KDEDefaultButton(this, "above",
00909                             largeButtons, isLeft, true,
00910                                                         keepAbove() ? above_on_bits : above_off_bits,
00911                             i18n("Keep Above Others"));
00912                     connect( button[BtnAbove], SIGNAL( clicked()),
00913                             this, SLOT(slotAbove()) );
00914                     hb->addWidget( button[BtnAbove] );
00915                 }
00916                 break;
00917 
00918             // Below button
00919             case 'B':
00920                 if ( (!button[BtnBelow]))
00921                 {
00922                     button[BtnBelow]  = new KDEDefaultButton(this, "below",
00923                             largeButtons, isLeft, true,
00924                                                         keepBelow() ? below_on_bits : below_off_bits,
00925                             i18n("Keep Below Others"));
00926                     connect( button[BtnBelow], SIGNAL( clicked()),
00927                             this, SLOT(slotBelow()) );
00928                     hb->addWidget( button[BtnBelow] );
00929                 }
00930                 break;
00931 
00932             // Shade button
00933             case 'L':
00934                 if ( (!button[BtnShade]) && isShadeable())
00935                 {
00936                     button[BtnShade]  = new KDEDefaultButton(this, "shade",
00937                             largeButtons, isLeft, true,
00938                                                         isSetShade() ? shade_on_bits : shade_off_bits,
00939                             isSetShade() ? i18n( "Unshade" ) : i18n("Shade"));
00940                     connect( button[BtnShade], SIGNAL( clicked()),
00941                             this, SLOT(slotShade()) );
00942                     hb->addWidget( button[BtnShade] );
00943                 }
00944                 break;
00945 
00946             // Spacer item (only for non-tool windows)
00947             case '_':
00948                 if ( !isTool() )
00949                     hb->addSpacing(borderWidth/2);
00950         }
00951     }
00952 }
00953 
00954 void KDEDefaultClient::reset( unsigned long )
00955 {
00956     widget()->repaint();
00957 }
00958 
00959 bool KDEDefaultClient::mustDrawHandle() const 
00960 { 
00961     bool drawSmallBorders = !options()->moveResizeMaximizedWindows();
00962     if (drawSmallBorders && (maximizeMode() & MaximizeVertical)) {
00963         return false;
00964     } else {
00965         return showGrabBar && isResizable();
00966     }
00967 }
00968 
00969 void KDEDefaultClient::iconChange()
00970 {
00971     if (button[BtnMenu] && button[BtnMenu]->isVisible())
00972         button[BtnMenu]->repaint(false);
00973 }
00974 
00975 void KDEDefaultClient::desktopChange()
00976 {
00977     if (button[BtnSticky]) {
00978                 bool on = isOnAllDesktops();
00979         button[BtnSticky]->turnOn(on);
00980         button[BtnSticky]->repaint(false);
00981                 QToolTip::remove( button[BtnSticky] );
00982         QToolTip::add( button[BtnSticky], on ? i18n("Not on all desktops") : i18n("On all desktops"));
00983     }
00984 }
00985 
00986 void KDEDefaultClient::keepAboveChange( bool above )
00987 {
00988     if (button[BtnAbove]) {
00989         button[BtnAbove]->setBitmap( above ? above_on_bits : above_off_bits );
00990         button[BtnAbove]->repaint(false);
00991     }
00992 }
00993 
00994 void KDEDefaultClient::keepBelowChange( bool below )
00995 {
00996     if (button[BtnBelow]) {
00997         button[BtnBelow]->setBitmap( below ? below_on_bits : below_off_bits );
00998         button[BtnBelow]->repaint(false);
00999     }
01000 }
01001 
01002 void KDEDefaultClient::slotMaximize()
01003 {
01004     maximize( button[BtnMax]->last_button );
01005 }
01006 
01007 void KDEDefaultClient::slotAbove()
01008 {
01009     setKeepAbove( !keepAbove());
01010     button[BtnAbove]->turnOn(keepAbove());
01011     button[BtnAbove]->repaint(true);
01012 }
01013 
01014 void KDEDefaultClient::slotBelow()
01015 {
01016     setKeepBelow( !keepBelow());
01017     button[BtnBelow]->turnOn(keepBelow());
01018     button[BtnBelow]->repaint(true);
01019 }
01020 
01021 void KDEDefaultClient::slotShade()
01022 {
01023     setShade( !isSetShade());
01024 }
01025 
01026 void KDEDefaultClient::resizeEvent( QResizeEvent* e)
01027 {
01028     doShape();
01029     calcHiddenButtons();
01030 
01031     if ( widget()->isShown())
01032     {
01033         widget()->update( widget()->rect());
01034 #if 1 // what's the point of this, when paintEvent() repaints everything anyway?
01035         int dx = 0;
01036         int dy = 0;
01037 
01038         if ( e->oldSize().width() != width() )
01039            dx = 32 + QABS( e->oldSize().width() -  width() );
01040 
01041         if ( e->oldSize().height() != height() )
01042            dy = 8 + QABS( e->oldSize().height() -  height() );
01043 
01044         if ( dy )
01045            widget()->update( 0, height() - dy + 1, width(), dy );
01046 
01047         if ( dx )
01048         {
01049            widget()->update( width() - dx + 1, 0, dx, height() );
01050            widget()->update( QRect( QPoint(4,4), titlebar->geometry().bottomLeft() -
01051                     QPoint(1,0) ) );
01052            widget()->update( QRect( titlebar->geometry().topRight(), QPoint(width() - 4,
01053                           titlebar->geometry().bottom()) ) );
01054            // Titlebar needs no paint event
01055            QApplication::postEvent( widget(), new QPaintEvent(titlebar->geometry(),
01056                                      FALSE) );
01057         }
01058 #endif
01059     }
01060 }
01061 
01062 
01063 void KDEDefaultClient::captionChange()
01064 {
01065     widget()->repaint( titlebar->geometry(), false );
01066 }
01067 
01068 
01069 void KDEDefaultClient::paintEvent( QPaintEvent* )
01070 {
01071     if (!KDEDefault_initialized)
01072         return;
01073 
01074     QColorGroup g;
01075     int offset;
01076 
01077     KPixmap* upperGradient = isActive() ? aUpperGradient : iUpperGradient;
01078 
01079     QPainter p(widget());
01080 
01081     // Obtain widget bounds.
01082     QRect r(widget()->rect());
01083     int x = r.x();
01084     int y = r.y();
01085     int x2 = r.width() - 1;
01086     int y2 = r.height() - 1;
01087     int w  = r.width();
01088     int h  = r.height();
01089 
01090     // Determine where to place the extended left titlebar
01091     int leftFrameStart = (h > 42) ? y+titleHeight+26: y+titleHeight;
01092 
01093     // Determine where to make the titlebar color transition
01094     r = titlebar->geometry();
01095     int rightOffset = r.x()+r.width()+1;
01096 
01097     // Create a disposable pixmap buffer for the titlebar
01098     // very early before drawing begins so there is no lag
01099     // during painting pixels.
01100     titleBuffer->resize( rightOffset-3, titleHeight+1 );
01101 
01102     // Draw an outer black frame
01103     p.setPen(Qt::black);
01104     p.drawRect(x,y,w,h);
01105 
01106     // Draw part of the frame that is the titlebar color
01107     g = options()->colorGroup(ColorTitleBar, isActive());
01108     p.setPen(g.light());
01109     p.drawLine(x+1, y+1, rightOffset-1, y+1);
01110     p.drawLine(x+1, y+1, x+1, leftFrameStart+borderWidth-4);
01111 
01112     // Draw titlebar colour separator line
01113     p.setPen(g.dark());
01114     p.drawLine(rightOffset-1, y+1, rightOffset-1, titleHeight+2);
01115 
01116     p.fillRect(x+2, y+titleHeight+3,
01117                borderWidth-4, leftFrameStart+borderWidth-y-titleHeight-8,
01118                options()->color(ColorTitleBar, isActive() ));
01119 
01120     // Finish drawing the titlebar extension
01121     p.setPen(Qt::black);
01122     p.drawLine(x+1, leftFrameStart+borderWidth-4, x+borderWidth-2, leftFrameStart-1);
01123     p.setPen(g.mid());
01124     p.drawLine(x+borderWidth-2, y+titleHeight+3, x+borderWidth-2, leftFrameStart-2);
01125 
01126     // Fill out the border edges
01127     g = options()->colorGroup(ColorFrame, isActive());
01128     p.setPen(g.light());
01129     p.drawLine(rightOffset, y+1, x2-1, y+1);
01130     p.drawLine(x+1, leftFrameStart+borderWidth-3, x+1, y2-1);
01131     p.setPen(g.dark());
01132     p.drawLine(x2-1, y+1, x2-1, y2-1);
01133     p.drawLine(x+1, y2-1, x2-1, y2-1);
01134 
01135     p.setPen(options()->color(ColorFrame, isActive()));
01136     QPointArray a;
01137     QBrush brush( options()->color(ColorFrame, isActive()), Qt::SolidPattern );
01138     p.setBrush( brush );                       // use solid, yellow brush
01139     a.setPoints( 4, x+2,             leftFrameStart+borderWidth-4,
01140                     x+borderWidth-2, leftFrameStart,
01141                     x+borderWidth-2, y2-2,
01142                     x+2,             y2-2);
01143     p.drawPolygon( a );
01144     p.fillRect(x2-borderWidth+2, y+titleHeight+3,
01145                borderWidth-3, y2-y-titleHeight-4,
01146                options()->color(ColorFrame, isActive() ));
01147 
01148     // Draw the bottom handle if required
01149     if (mustDrawHandle())
01150     {
01151         if(w > 50)
01152         {
01153             qDrawShadePanel(&p, x+1, y2-grabBorderWidth+2, 2*borderWidth+12, grabBorderWidth-2,
01154                             g, false, 1, &g.brush(QColorGroup::Mid));
01155             qDrawShadePanel(&p, x+2*borderWidth+13, y2-grabBorderWidth+2, w-4*borderWidth-26, grabBorderWidth-2,
01156                             g, false, 1, isActive() ?
01157                             &g.brush(QColorGroup::Background) :
01158                             &g.brush(QColorGroup::Mid));
01159             qDrawShadePanel(&p, x2-2*borderWidth-12, y2-grabBorderWidth+2, 2*borderWidth+12, grabBorderWidth-2,
01160                             g, false, 1, &g.brush(QColorGroup::Mid));
01161         } else
01162             qDrawShadePanel(&p, x+1, y2-grabBorderWidth+2, w-2, grabBorderWidth-2,
01163                             g, false, 1, isActive() ?
01164                             &g.brush(QColorGroup::Background) :
01165                             &g.brush(QColorGroup::Mid));
01166         offset = grabBorderWidth;
01167     } else
01168         {
01169             p.fillRect(x+2, y2-borderWidth+2, w-4, borderWidth-3,
01170                        options()->color(ColorFrame, isActive() ));
01171             offset = borderWidth;
01172         }
01173 
01174     // Draw a frame around the wrapped widget.
01175     p.setPen( g.dark() );
01176     p.drawRect( x+borderWidth-1, y+titleHeight+3, w-2*borderWidth+2, h-titleHeight-offset-2 );
01177 
01178     // Draw the title bar.
01179     r = titlebar->geometry();
01180 
01181     // Obtain titlebar blend colours
01182     QColor c1 = options()->color(ColorTitleBar, isActive() );
01183     QColor c2 = options()->color(ColorFrame, isActive() );
01184 
01185     // Fill with frame color behind RHS buttons
01186     p.fillRect( rightOffset, y+2, x2-rightOffset-1, titleHeight+1, c2);
01187 
01188     QPainter p2( titleBuffer, this );
01189 
01190     // Draw the titlebar gradient
01191     if (upperGradient)
01192         p2.drawTiledPixmap(0, 0, rightOffset-3, titleHeight+1, *upperGradient);
01193     else
01194         p2.fillRect(0, 0, rightOffset-3, titleHeight+1, c1);
01195 
01196     // Draw the title text on the pixmap, and with a smaller font
01197     // for toolwindows than the default.
01198     QFont fnt = options()->font(true);
01199 
01200     if ( isTool() )
01201        fnt.setPointSize( fnt.pointSize()-2 );  // Shrink font by 2pt
01202 
01203     p2.setFont( fnt );
01204 
01205     // Draw the titlebar stipple if active and available
01206     if (isActive() && titlePix)
01207     {
01208         QFontMetrics fm(fnt);
01209         int captionWidth = fm.width(caption());
01210         if (caption().isRightToLeft())
01211             p2.drawTiledPixmap( r.x(), 0, r.width()-captionWidth-4,
01212                                 titleHeight+1, *titlePix );
01213         else
01214             p2.drawTiledPixmap( r.x()+captionWidth+3, 0, r.width()-captionWidth-4,
01215                                 titleHeight+1, *titlePix );
01216     }
01217 
01218     p2.setPen( options()->color(ColorFont, isActive()) );
01219     p2.drawText(r.x(), 1, r.width()-1, r.height(),
01220         (caption().isRightToLeft() ? AlignRight : AlignLeft) | AlignVCenter,
01221         caption() );
01222 
01223     bitBlt( widget(), 2, 2, titleBuffer );
01224 
01225     p2.end();
01226 
01227     // Ensure a shaded window has no unpainted areas
01228     // Is this still needed?
01229 #if 1
01230     p.setPen(c2);
01231     p.drawLine(x+borderWidth, y+titleHeight+4, x2-borderWidth, y+titleHeight+4);
01232 #endif
01233 }
01234 
01235 
01236 void KDEDefaultClient::doShape()
01237 {
01238     QRegion mask(QRect(0, 0, width(), height()));
01239     mask -= QRect(0, 0, 1, 1);
01240     mask -= QRect(width()-1, 0, 1, 1);
01241     mask -= QRect(0, height()-1, 1, 1);
01242     mask -= QRect(width()-1, height()-1, 1, 1);
01243     setMask(mask);
01244 }
01245 
01246 
01247 void KDEDefaultClient::showEvent(QShowEvent *)
01248 {
01249     calcHiddenButtons();
01250     doShape();
01251 }
01252 
01253 
01254 void KDEDefaultClient::mouseDoubleClickEvent( QMouseEvent * e )
01255 {
01256     if (titlebar->geometry().contains( e->pos() ) )
01257                 titlebarDblClickOperation();
01258 }
01259 
01260 
01261 void KDEDefaultClient::maximizeChange()
01262 {
01263     if (button[BtnMax]) {
01264                 bool m = maximizeMode() == MaximizeFull;
01265         button[BtnMax]->setBitmap(m ? minmax_bits : maximize_bits);
01266                 QToolTip::remove( button[ BtnMax ] );
01267                 QToolTip::add( button[BtnMax], m ? i18n("Restore") : i18n("Maximize"));
01268     }
01269     spacer->changeSize(10, mustDrawHandle() ? 8 : 4,
01270             QSizePolicy::Expanding, QSizePolicy::Minimum);
01271     g->activate();
01272 }
01273 
01274 
01275 void KDEDefaultClient::activeChange()
01276 {
01277     for(int i=KDEDefaultClient::BtnHelp; i < KDEDefaultClient::BtnCount; i++)
01278         if(button[i])
01279             button[i]->repaint(false);
01280     widget()->repaint(false);
01281 }
01282 
01283 void KDEDefaultClient::shadeChange()
01284 {
01285     if (button[BtnShade]) {
01286         bool on = isSetShade();
01287         button[BtnShade]->setBitmap( on ? shade_on_bits : shade_off_bits );
01288         button[BtnShade]->turnOn(on);
01289         button[BtnShade]->repaint(false);
01290                 QToolTip::remove( button[BtnShade] );
01291         QToolTip::add( button[BtnShade], on ? i18n("Unshade") : i18n("Shade"));
01292     }
01293 }
01294 
01295 QSize KDEDefaultClient::minimumSize() const
01296 {
01297     return QSize( 100, 50 ); // FRAME
01298 }
01299 
01300 void KDEDefaultClient::resize( const QSize& s )
01301 {
01302     widget()->resize( s );
01303 }
01304 
01305 void KDEDefaultClient::borders( int& left, int& right, int& top, int& bottom ) const
01306 { // FRAME
01307     left = right = borderWidth;
01308 //    , y+titleHeight+3, w-6, h-titleHeight-offset-6 );
01309     top = titleHeight + 4;
01310     bottom = mustDrawHandle() ? grabBorderWidth : borderWidth;
01311 }
01312 
01313 // The hiding button while shrinking, show button while expanding magic
01314 void KDEDefaultClient::calcHiddenButtons()
01315 {
01316     // Hide buttons in this order:
01317     // Shade, Below, Above, Sticky, Help, Maximize, Minimize, Close, Menu.
01318     KDEDefaultButton* btnArray[] = { button[ BtnShade ], button[ BtnBelow ],
01319                         button[ BtnAbove ], button[BtnSticky], button[BtnHelp],
01320             button[BtnMax], button[BtnIconify], button[BtnClose],
01321             button[BtnMenu] };
01322         const int buttons_cnt = sizeof( btnArray ) / sizeof( btnArray[ 0 ] );
01323 
01324     int minwidth  = largeButtons ? 10 * normalTitleHeight : 10 * toolTitleHeight; // Start hiding at this width
01325     int btn_width = largeButtons ? normalTitleHeight : toolTitleHeight;
01326     int current_width = width();
01327     int count = 0;
01328     int i;
01329 
01330     // Find out how many buttons we need to hide.
01331     while (current_width < minwidth)
01332     {
01333         current_width += btn_width;
01334         count++;
01335     }
01336 
01337     // Bound the number of buttons to hide
01338     if (count > buttons_cnt) count = buttons_cnt;
01339 
01340     // Hide the required buttons...
01341     for(i = 0; i < count; i++)
01342     {
01343         if (btnArray[i] && btnArray[i]->isVisible() )
01344             btnArray[i]->hide();
01345     }
01346 
01347     // Show the rest of the buttons...
01348     for(i = count; i < buttons_cnt; i++)
01349     {
01350         if (btnArray[i] && (!btnArray[i]->isVisible()) )
01351             btnArray[i]->show();
01352     }
01353 }
01354 
01355 
01356 KDecoration::Position KDEDefaultClient::mousePosition( const QPoint& p ) const
01357 {
01358     Position m = PositionCenter;
01359 
01360     int bottomSize = mustDrawHandle() ? grabBorderWidth : borderWidth;
01361 
01362     const int range = 14 + 3*borderWidth/2;
01363 
01364     if ( ( p.x() > borderWidth && p.x() < width() - borderWidth )
01365          && ( p.y() > 4 && p.y() < height() - bottomSize ) )
01366         m = PositionCenter;
01367     else if ( p.y() <= range && p.x() <= range)
01368         m = PositionTopLeft;
01369     else if ( p.y() >= height()-range && p.x() >= width()-range)
01370         m = PositionBottomRight;
01371     else if ( p.y() >= height()-range && p.x() <= range)
01372         m = PositionBottomLeft;
01373     else if ( p.y() <= range && p.x() >= width()-range)
01374         m = PositionTopRight;
01375     else if ( p.y() <= 4 )
01376         m = PositionTop;
01377     else if ( p.y() >= height()-bottomSize )
01378         m = PositionBottom;
01379     else if ( p.x() <= borderWidth )
01380         m = PositionLeft;
01381     else if ( p.x() >= width()-borderWidth )
01382         m = PositionRight;
01383     else
01384         m = PositionCenter;
01385 
01386     // Modify the mouse position if we are using a grab bar.
01387     if (mustDrawHandle())
01388         if (p.y() >= (height() - grabBorderWidth))
01389         {
01390             if (p.x() >= (width() - 2*borderWidth - 12))
01391                 m = PositionBottomRight;
01392             else if (p.x() <= 2*borderWidth + 12)
01393                 m = PositionBottomLeft;
01394             else
01395             m = PositionBottom;
01396         }
01397 
01398     return m;
01399 }
01400 
01401 
01402 // Make sure the menu button follows double click conventions set in kcontrol
01403 void KDEDefaultClient::menuButtonPressed()
01404 {
01405     static QTime t;
01406     static KDEDefaultClient* lastClient = NULL;
01407     bool dbl = ( lastClient == this && t.elapsed() <= QApplication::doubleClickInterval());
01408     lastClient = this;
01409     t.start();
01410 
01411     if (dbl)
01412     {
01413         m_closing = true;
01414         return;
01415     }
01416 
01417     QPoint menupoint ( button[BtnMenu]->rect().bottomLeft().x()-1,
01418                        button[BtnMenu]->rect().bottomLeft().y()+2 );
01419         KDecorationFactory* f = factory();
01420     QRect menuRect = button[BtnMenu]->rect();
01421     QPoint menutop = button[BtnMenu]->mapToGlobal(menuRect.topLeft());
01422     QPoint menubottom = button[BtnMenu]->mapToGlobal(menuRect.bottomRight());
01423     showWindowMenu(QRect(menutop, menubottom));
01424         if( !f->exists( this )) // 'this' was destroyed
01425             return;
01426     button[BtnMenu]->setDown(false);
01427 }
01428 
01429 void KDEDefaultClient::menuButtonReleased()
01430 {
01431     if (m_closing)
01432         closeWindow();
01433 }
01434 
01435 const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask
01436     | NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask | NET::TopMenuMask
01437     | NET::UtilityMask | NET::SplashMask;
01438 
01439 bool KDEDefaultClient::isTool() const
01440 {
01441     NET::WindowType type = windowType( SUPPORTED_WINDOW_TYPES_MASK );
01442     return type == NET::Toolbar || type == NET::Utility || type == NET::Menu;
01443 }
01444 
01445 
01446 bool KDEDefaultClient::eventFilter( QObject* o, QEvent* e )
01447 {
01448     if( o != widget())
01449     return false;
01450     switch( e->type())
01451     {
01452     case QEvent::Resize:
01453         resizeEvent( static_cast< QResizeEvent* >( e ));
01454         return true;
01455     case QEvent::Paint:
01456         paintEvent( static_cast< QPaintEvent* >( e ));
01457         return true;
01458     case QEvent::MouseButtonDblClick:
01459         mouseDoubleClickEvent( static_cast< QMouseEvent* >( e ));
01460         return true;
01461     case QEvent::MouseButtonPress:
01462         processMousePressEvent( static_cast< QMouseEvent* >( e ));
01463         return true;
01464     case QEvent::Show:
01465         showEvent( static_cast< QShowEvent* >( e ));
01466         return true;
01467     default:
01468         break;
01469     }
01470     return false;
01471 }
01472 
01473 
01474 } // namespace
01475 
01476 // Extended KWin plugin interface
01477 extern "C" KDE_EXPORT KDecorationFactory* create_factory()
01478 {
01479     return new Default::KDEDefaultHandler();
01480 }
01481 
01482 #include "kdedefault.moc"
01483 // vim: ts=4
KDE Logo
This file is part of the documentation for kwin Library Version 3.4.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Jun 14 01:19:57 2006 by doxygen 1.4.0 written by Dimitri van Heesch, © 1997-2003