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     button[BtnShade]->setBitmap(isSetShade() ? shade_on_bits : shade_off_bits );
01005     button[BtnShade]->repaint(true);
01006 }
01007 
01008 void KDEDefaultClient::resizeEvent( QResizeEvent* e)
01009 {
01010     doShape();
01011     calcHiddenButtons();
01012 
01013     if ( widget()->isShown())
01014     {
01015         widget()->update( widget()->rect());
01016 #if 1 // what's the point of this, when paintEvent() repaints everything anyway?
01017         int dx = 0;
01018         int dy = 0;
01019 
01020         if ( e->oldSize().width() != width() )
01021            dx = 32 + QABS( e->oldSize().width() -  width() );
01022 
01023         if ( e->oldSize().height() != height() )
01024            dy = 8 + QABS( e->oldSize().height() -  height() );
01025 
01026         if ( dy )
01027            widget()->update( 0, height() - dy + 1, width(), dy );
01028 
01029         if ( dx )
01030         {
01031            widget()->update( width() - dx + 1, 0, dx, height() );
01032            widget()->update( QRect( QPoint(4,4), titlebar->geometry().bottomLeft() -
01033                     QPoint(1,0) ) );
01034            widget()->update( QRect( titlebar->geometry().topRight(), QPoint(width() - 4,
01035                           titlebar->geometry().bottom()) ) );
01036            // Titlebar needs no paint event
01037            QApplication::postEvent( widget(), new QPaintEvent(titlebar->geometry(),
01038                                      FALSE) );
01039         }
01040 #endif
01041     }
01042 }
01043 
01044 
01045 void KDEDefaultClient::captionChange()
01046 {
01047     widget()->repaint( titlebar->geometry(), false );
01048 }
01049 
01050 
01051 void KDEDefaultClient::paintEvent( QPaintEvent* )
01052 {
01053     if (!KDEDefault_initialized)
01054         return;
01055 
01056     QColorGroup g;
01057     int offset;
01058 
01059     KPixmap* upperGradient = isActive() ? aUpperGradient : iUpperGradient;
01060 
01061     QPainter p(widget());
01062 
01063     // Obtain widget bounds.
01064     QRect r(widget()->rect());
01065     int x = r.x();
01066     int y = r.y();
01067     int x2 = r.width() - 1;
01068     int y2 = r.height() - 1;
01069     int w  = r.width();
01070     int h  = r.height();
01071 
01072     // Determine where to place the extended left titlebar
01073     int leftFrameStart = (h > 42) ? y+titleHeight+26: y+titleHeight;
01074 
01075     // Determine where to make the titlebar color transition
01076     r = titlebar->geometry();
01077     int rightOffset = r.x()+r.width()+1;
01078 
01079     // Create a disposable pixmap buffer for the titlebar
01080     // very early before drawing begins so there is no lag
01081     // during painting pixels.
01082     titleBuffer->resize( rightOffset-3, titleHeight+1 );
01083 
01084     // Draw an outer black frame
01085     p.setPen(Qt::black);
01086     p.drawRect(x,y,w,h);
01087 
01088     // Draw part of the frame that is the titlebar color
01089     g = options()->colorGroup(ColorTitleBar, isActive());
01090     p.setPen(g.light());
01091     p.drawLine(x+1, y+1, rightOffset-1, y+1);
01092     p.drawLine(x+1, y+1, x+1, leftFrameStart+borderWidth-4);
01093 
01094     // Draw titlebar colour separator line
01095     p.setPen(g.dark());
01096     p.drawLine(rightOffset-1, y+1, rightOffset-1, titleHeight+2);
01097 
01098     p.fillRect(x+2, y+titleHeight+3,
01099                borderWidth-4, leftFrameStart+borderWidth-y-titleHeight-8,
01100                options()->color(ColorTitleBar, isActive() ));
01101 
01102     // Finish drawing the titlebar extension
01103     p.setPen(Qt::black);
01104     p.drawLine(x+1, leftFrameStart+borderWidth-4, x+borderWidth-2, leftFrameStart-1);
01105     p.setPen(g.mid());
01106     p.drawLine(x+borderWidth-2, y+titleHeight+3, x+borderWidth-2, leftFrameStart-2);
01107 
01108     // Fill out the border edges
01109     g = options()->colorGroup(ColorFrame, isActive());
01110     p.setPen(g.light());
01111     p.drawLine(rightOffset, y+1, x2-1, y+1);
01112     p.drawLine(x+1, leftFrameStart+borderWidth-3, x+1, y2-1);
01113     p.setPen(g.dark());
01114     p.drawLine(x2-1, y+1, x2-1, y2-1);
01115     p.drawLine(x+1, y2-1, x2-1, y2-1);
01116 
01117     p.setPen(options()->color(ColorFrame, isActive()));
01118     QPointArray a;
01119     QBrush brush( options()->color(ColorFrame, isActive()), Qt::SolidPattern );
01120     p.setBrush( brush );                       // use solid, yellow brush
01121     a.setPoints( 4, x+2,             leftFrameStart+borderWidth-4,
01122                     x+borderWidth-2, leftFrameStart,
01123                     x+borderWidth-2, y2-2,
01124                     x+2,             y2-2);
01125     p.drawPolygon( a );
01126     p.fillRect(x2-borderWidth+2, y+titleHeight+3,
01127                borderWidth-3, y2-y-titleHeight-4,
01128                options()->color(ColorFrame, isActive() ));
01129 
01130     // Draw the bottom handle if required
01131     if (mustDrawHandle())
01132     {
01133         if(w > 50)
01134         {
01135             qDrawShadePanel(&p, x+1, y2-grabBorderWidth+2, 2*borderWidth+12, grabBorderWidth-2,
01136                             g, false, 1, &g.brush(QColorGroup::Mid));
01137             qDrawShadePanel(&p, x+2*borderWidth+13, y2-grabBorderWidth+2, w-4*borderWidth-26, grabBorderWidth-2,
01138                             g, false, 1, isActive() ?
01139                             &g.brush(QColorGroup::Background) :
01140                             &g.brush(QColorGroup::Mid));
01141             qDrawShadePanel(&p, x2-2*borderWidth-12, y2-grabBorderWidth+2, 2*borderWidth+12, grabBorderWidth-2,
01142                             g, false, 1, &g.brush(QColorGroup::Mid));
01143         } else
01144             qDrawShadePanel(&p, x+1, y2-grabBorderWidth+2, w-2, grabBorderWidth-2,
01145                             g, false, 1, isActive() ?
01146                             &g.brush(QColorGroup::Background) :
01147                             &g.brush(QColorGroup::Mid));
01148         offset = grabBorderWidth;
01149     } else
01150         {
01151             p.fillRect(x+2, y2-borderWidth+2, w-4, borderWidth-3,
01152                        options()->color(ColorFrame, isActive() ));
01153             offset = borderWidth;
01154         }
01155 
01156     // Draw a frame around the wrapped widget.
01157     p.setPen( g.dark() );
01158     p.drawRect( x+borderWidth-1, y+titleHeight+3, w-2*borderWidth+2, h-titleHeight-offset-2 );
01159 
01160     // Draw the title bar.
01161     r = titlebar->geometry();
01162 
01163     // Obtain titlebar blend colours
01164     QColor c1 = options()->color(ColorTitleBar, isActive() );
01165     QColor c2 = options()->color(ColorFrame, isActive() );
01166 
01167     // Fill with frame color behind RHS buttons
01168     p.fillRect( rightOffset, y+2, x2-rightOffset-1, titleHeight+1, c2);
01169 
01170     QPainter p2( titleBuffer, this );
01171 
01172     // Draw the titlebar gradient
01173     if (upperGradient)
01174         p2.drawTiledPixmap(0, 0, rightOffset-3, titleHeight+1, *upperGradient);
01175     else
01176         p2.fillRect(0, 0, rightOffset-3, titleHeight+1, c1);
01177 
01178     // Draw the title text on the pixmap, and with a smaller font
01179     // for toolwindows than the default.
01180     QFont fnt = options()->font(true);
01181 
01182     if ( isTool() )
01183        fnt.setPointSize( fnt.pointSize()-2 );  // Shrink font by 2pt
01184 
01185     p2.setFont( fnt );
01186 
01187     // Draw the titlebar stipple if active and available
01188     if (isActive() && titlePix)
01189     {
01190         QFontMetrics fm(fnt);
01191         int captionWidth = fm.width(caption());
01192         if (caption().isRightToLeft())
01193             p2.drawTiledPixmap( r.x(), 0, r.width()-captionWidth-4,
01194                                 titleHeight+1, *titlePix );
01195         else
01196             p2.drawTiledPixmap( r.x()+captionWidth+3, 0, r.width()-captionWidth-4,
01197                                 titleHeight+1, *titlePix );
01198     }
01199 
01200     p2.setPen( options()->color(ColorFont, isActive()) );
01201     p2.drawText(r.x(), 1, r.width()-1, r.height(),
01202         (caption().isRightToLeft() ? AlignRight : AlignLeft) | AlignVCenter,
01203         caption() );
01204 
01205     bitBlt( widget(), 2, 2, titleBuffer );
01206 
01207     p2.end();
01208 
01209     // Ensure a shaded window has no unpainted areas
01210     // Is this still needed?
01211 #if 1
01212     p.setPen(c2);
01213     p.drawLine(x+borderWidth, y+titleHeight+4, x2-borderWidth, y+titleHeight+4);
01214 #endif
01215 }
01216 
01217 
01218 void KDEDefaultClient::doShape()
01219 {
01220     QRegion mask(QRect(0, 0, width(), height()));
01221     mask -= QRect(0, 0, 1, 1);
01222     mask -= QRect(width()-1, 0, 1, 1);
01223     mask -= QRect(0, height()-1, 1, 1);
01224     mask -= QRect(width()-1, height()-1, 1, 1);
01225     setMask(mask);
01226 }
01227 
01228 
01229 void KDEDefaultClient::showEvent(QShowEvent *)
01230 {
01231     calcHiddenButtons();
01232     doShape();
01233 }
01234 
01235 
01236 void KDEDefaultClient::mouseDoubleClickEvent( QMouseEvent * e )
01237 {
01238     if (titlebar->geometry().contains( e->pos() ) )
01239                 titlebarDblClickOperation();
01240 }
01241 
01242 
01243 void KDEDefaultClient::maximizeChange()
01244 {
01245     if (button[BtnMax]) {
01246                 bool m = maximizeMode() == MaximizeFull;
01247         button[BtnMax]->setBitmap(m ? minmax_bits : maximize_bits);
01248                 QToolTip::remove( button[ BtnMax ] );
01249                 QToolTip::add( button[BtnMax], m ? i18n("Restore") : i18n("Maximize"));
01250     }
01251     spacer->changeSize(10, mustDrawHandle() ? 8 : 4,
01252             QSizePolicy::Expanding, QSizePolicy::Minimum);
01253     g->activate();
01254 }
01255 
01256 
01257 void KDEDefaultClient::activeChange()
01258 {
01259     for(int i=KDEDefaultClient::BtnHelp; i < KDEDefaultClient::BtnCount; i++)
01260         if(button[i])
01261             button[i]->repaint(false);
01262     widget()->repaint(false);
01263 }
01264 
01265 void KDEDefaultClient::shadeChange()
01266 {
01267     if (button[BtnShade]) {
01268                 bool on = isShade();
01269         button[BtnShade]->turnOn(on);
01270         button[BtnShade]->repaint(false);
01271                 QToolTip::remove( button[BtnShade] );
01272         QToolTip::add( button[BtnShade], on ? i18n("Unshade") : i18n("Shade"));
01273     }
01274 }
01275 
01276 QSize KDEDefaultClient::minimumSize() const
01277 {
01278     return QSize( 100, 50 ); // FRAME
01279 }
01280 
01281 void KDEDefaultClient::resize( const QSize& s )
01282 {
01283     widget()->resize( s );
01284 }
01285 
01286 void KDEDefaultClient::borders( int& left, int& right, int& top, int& bottom ) const
01287 { // FRAME
01288     left = right = borderWidth;
01289 //    , y+titleHeight+3, w-6, h-titleHeight-offset-6 );
01290     top = titleHeight + 4;
01291     bottom = mustDrawHandle() ? grabBorderWidth : borderWidth;
01292 }
01293 
01294 // The hiding button while shrinking, show button while expanding magic
01295 void KDEDefaultClient::calcHiddenButtons()
01296 {
01297     // Hide buttons in this order:
01298     // Shade, Below, Above, Sticky, Help, Maximize, Minimize, Close, Menu.
01299     KDEDefaultButton* btnArray[] = { button[ BtnShade ], button[ BtnBelow ],
01300                         button[ BtnAbove ], button[BtnSticky], button[BtnHelp],
01301             button[BtnMax], button[BtnIconify], button[BtnClose],
01302             button[BtnMenu] };
01303         const int buttons_cnt = sizeof( btnArray ) / sizeof( btnArray[ 0 ] );
01304 
01305     int minwidth  = largeButtons ? 10 * normalTitleHeight : 10 * toolTitleHeight; // Start hiding at this width
01306     int btn_width = largeButtons ? normalTitleHeight : toolTitleHeight;
01307     int current_width = width();
01308     int count = 0;
01309     int i;
01310 
01311     // Find out how many buttons we need to hide.
01312     while (current_width < minwidth)
01313     {
01314         current_width += btn_width;
01315         count++;
01316     }
01317 
01318     // Bound the number of buttons to hide
01319     if (count > buttons_cnt) count = buttons_cnt;
01320 
01321     // Hide the required buttons...
01322     for(i = 0; i < count; i++)
01323     {
01324         if (btnArray[i] && btnArray[i]->isVisible() )
01325             btnArray[i]->hide();
01326     }
01327 
01328     // Show the rest of the buttons...
01329     for(i = count; i < buttons_cnt; i++)
01330     {
01331         if (btnArray[i] && (!btnArray[i]->isVisible()) )
01332             btnArray[i]->show();
01333     }
01334 }
01335 
01336 
01337 KDecoration::Position KDEDefaultClient::mousePosition( const QPoint& p ) const
01338 {
01339     Position m = PositionCenter;
01340 
01341     int bottomSize = mustDrawHandle() ? grabBorderWidth : borderWidth;
01342 
01343     const int range = 14 + 3*borderWidth/2;
01344 
01345     if ( ( p.x() > borderWidth && p.x() < width() - borderWidth )
01346          && ( p.y() > 4 && p.y() < height() - bottomSize ) )
01347         m = PositionCenter;
01348     else if ( p.y() <= range && p.x() <= range)
01349         m = PositionTopLeft;
01350     else if ( p.y() >= height()-range && p.x() >= width()-range)
01351         m = PositionBottomRight;
01352     else if ( p.y() >= height()-range && p.x() <= range)
01353         m = PositionBottomLeft;
01354     else if ( p.y() <= range && p.x() >= width()-range)
01355         m = PositionTopRight;
01356     else if ( p.y() <= 4 )
01357         m = PositionTop;
01358     else if ( p.y() >= height()-bottomSize )
01359         m = PositionBottom;
01360     else if ( p.x() <= borderWidth )
01361         m = PositionLeft;
01362     else if ( p.x() >= width()-borderWidth )
01363         m = PositionRight;
01364     else
01365         m = PositionCenter;
01366 
01367     // Modify the mouse position if we are using a grab bar.
01368     if (mustDrawHandle())
01369         if (p.y() >= (height() - grabBorderWidth))
01370         {
01371             if (p.x() >= (width() - 2*borderWidth - 12))
01372                 m = PositionBottomRight;
01373             else if (p.x() <= 2*borderWidth + 12)
01374                 m = PositionBottomLeft;
01375             else
01376             m = PositionBottom;
01377         }
01378 
01379     return m;
01380 }
01381 
01382 
01383 // Make sure the menu button follows double click conventions set in kcontrol
01384 void KDEDefaultClient::menuButtonPressed()
01385 {
01386     static QTime t;
01387     static KDEDefaultClient* lastClient = NULL;
01388     bool dbl = ( lastClient == this && t.elapsed() <= QApplication::doubleClickInterval());
01389     lastClient = this;
01390     t.start();
01391 
01392     if (dbl)
01393     {
01394         m_closing = true;
01395         return;
01396     }
01397 
01398     QPoint menupoint ( button[BtnMenu]->rect().bottomLeft().x()-1,
01399                        button[BtnMenu]->rect().bottomLeft().y()+2 );
01400         KDecorationFactory* f = factory();
01401     QRect menuRect = button[BtnMenu]->rect();
01402     QPoint menutop = button[BtnMenu]->mapToGlobal(menuRect.topLeft());
01403     QPoint menubottom = button[BtnMenu]->mapToGlobal(menuRect.bottomRight());
01404     showWindowMenu(QRect(menutop, menubottom));
01405         if( !f->exists( this )) // 'this' was destroyed
01406             return;
01407     button[BtnMenu]->setDown(false);
01408 }
01409 
01410 void KDEDefaultClient::menuButtonReleased()
01411 {
01412     if (m_closing)
01413         closeWindow();
01414 }
01415 
01416 const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask
01417     | NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask | NET::TopMenuMask
01418     | NET::UtilityMask | NET::SplashMask;
01419 
01420 bool KDEDefaultClient::isTool() const
01421 {
01422     NET::WindowType type = windowType( SUPPORTED_WINDOW_TYPES_MASK );
01423     return type == NET::Toolbar || type == NET::Utility || type == NET::Menu;
01424 }
01425 
01426 
01427 bool KDEDefaultClient::eventFilter( QObject* o, QEvent* e )
01428 {
01429     if( o != widget())
01430     return false;
01431     switch( e->type())
01432     {
01433     case QEvent::Resize:
01434         resizeEvent( static_cast< QResizeEvent* >( e ));
01435         return true;
01436     case QEvent::Paint:
01437         paintEvent( static_cast< QPaintEvent* >( e ));
01438         return true;
01439     case QEvent::MouseButtonDblClick:
01440         mouseDoubleClickEvent( static_cast< QMouseEvent* >( e ));
01441         return true;
01442     case QEvent::MouseButtonPress:
01443         processMousePressEvent( static_cast< QMouseEvent* >( e ));
01444         return true;
01445     case QEvent::Show:
01446         showEvent( static_cast< QShowEvent* >( e ));
01447         return true;
01448     default:
01449         break;
01450     }
01451     return false;
01452 }
01453 
01454 
01455 } // namespace
01456 
01457 // Extended KWin plugin interface
01458 extern "C" KDecorationFactory* create_factory()
01459 {
01460     return new Default::KDEDefaultHandler();
01461 }
01462 
01463 #include "kdedefault.moc"
01464 // vim: ts=4
KDE Logo
This file is part of the documentation for kwin Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Sep 25 20:35:05 2004 by doxygen 1.3.8-20040913 written by Dimitri van Heesch, © 1997-2003