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 Fri Aug 13 21:47:05 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003