kwin Library API Documentation

kdedefault.cpp

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