kwin Library API Documentation

quartz.cpp

00001 /* 00002 * 00003 * Gallium-Quartz KWin client 00004 * 00005 * Copyright 2001 00006 * Karol Szwed <gallium@kde.org> 00007 * http://gallium.n3.net/ 00008 * 00009 * Based on the KDE default client. 00010 * 00011 * Includes mini titlebars for ToolWindow Support. 00012 * Button positions are now customizable. 00013 * 00014 */ 00015 00016 #include <kconfig.h> 00017 #include <kdrawutil.h> 00018 #include <kglobal.h> 00019 #include <klocale.h> 00020 #include <kpixmapeffect.h> 00021 #include <qbitmap.h> 00022 #include <qcursor.h> 00023 #include <qdrawutil.h> 00024 #include <qimage.h> 00025 #include <qlabel.h> 00026 #include <qlayout.h> 00027 #include <qtooltip.h> 00028 #include <qapplication.h> 00029 00030 #include "quartz.h" 00031 00032 00033 namespace Quartz { 00034 00035 static const unsigned char iconify_bits[] = { 00036 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 00037 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; 00038 00039 static const unsigned char close_bits[] = { 00040 0x00, 0x00, 0x86, 0x01, 0xcc, 0x00, 0x78, 0x00, 0x30, 0x00, 0x78, 0x00, 00041 0xcc, 0x00, 0x86, 0x01, 0x00, 0x00, 0x00, 0x00}; 00042 00043 static const unsigned char maximize_bits[] = { 00044 0xff, 0x01, 0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 00045 0x01, 0x01, 0x01, 0x01, 0xff, 0x01, 0x00, 0x00}; 00046 00047 static const unsigned char minmax_bits[] = { 00048 0xfc, 0x00, 0xfc, 0x00, 0x84, 0x00, 0xbf, 0x00, 0xbf, 0x00, 0xe1, 0x00, 00049 0x21, 0x00, 0x21, 0x00, 0x3f, 0x00, 0x00, 0x00}; 00050 00051 static const unsigned char question_bits[] = { 00052 0x00, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 00053 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00}; 00054 00055 static const unsigned char pindown_white_bits[] = { 00056 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x1f, 0xa0, 0x03, 00057 0xb0, 0x01, 0x30, 0x01, 0xf0, 0x00, 0x70, 0x00, 0x20, 0x00, 0x00, 0x00, 00058 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 00059 00060 static const unsigned char pindown_gray_bits[] = { 00061 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 00062 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x80, 0x07, 0xc0, 0x03, 0xe0, 0x01, 00063 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 00064 00065 static const unsigned char pindown_dgray_bits[] = { 00066 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x10, 0x70, 0x20, 0x50, 0x20, 00067 0x48, 0x30, 0xc8, 0x38, 0x08, 0x1f, 0x08, 0x18, 0x10, 0x1c, 0x10, 0x0e, 00068 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 00069 00070 static const unsigned char pinup_white_bits[] = { 00071 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x11, 00072 0x3f, 0x15, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00073 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 00074 00075 static const unsigned char pinup_gray_bits[] = { 00076 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00077 0x80, 0x0a, 0xbf, 0x0a, 0x80, 0x15, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 00078 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 00079 00080 static const unsigned char pinup_dgray_bits[] = { 00081 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x40, 0x31, 0x40, 0x2e, 00082 0x40, 0x20, 0x40, 0x20, 0x7f, 0x2a, 0x40, 0x3f, 0xc0, 0x31, 0xc0, 0x20, 00083 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 00084 00085 static const unsigned char above_on_bits[] = { 00086 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0x30, 0x00, 0xfc, 0x00, 0x78, 0x00, 00087 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 00088 00089 static const unsigned char above_off_bits[] = { 00090 0x30, 0x00, 0x78, 0x00, 0xfc, 0x00, 0x30, 0x00, 0xfe, 0x01, 0xfe, 0x01, 00091 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 00092 00093 static const unsigned char below_on_bits[] = { 00094 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x78, 0x00, 0xfc, 0x00, 00095 0x30, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0x00, 0x00}; 00096 00097 static const unsigned char below_off_bits[] = { 00098 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 00099 0x30, 0x00, 0xfc, 0x00, 0x78, 0x00, 0x30, 0x00}; 00100 00101 static const unsigned char shade_on_bits[] = { 00102 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0x02, 0x01, 0x02, 0x01, 00103 0x02, 0x01, 0x02, 0x01, 0xfe, 0x01, 0x00, 0x00}; 00104 00105 static const unsigned char shade_off_bits[] = { 00106 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, 00107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 00108 00109 00111 00112 // Titlebar button positions 00113 bool onAllDesktopsButtonOnLeft = true; 00114 bool coloredFrame = true; 00115 00116 KPixmap* titleBlocks = NULL; 00117 KPixmap* ititleBlocks = NULL; 00118 KPixmap* pinDownPix = NULL; 00119 KPixmap* pinUpPix = NULL; 00120 KPixmap* ipinDownPix = NULL; 00121 KPixmap* ipinUpPix = NULL; 00122 static int normalTitleHeight; 00123 static int toolTitleHeight; 00124 static int borderWidth; 00125 00126 bool quartz_initialized = false; 00127 QuartzHandler* clientHandler; 00128 00130 00131 00132 QuartzHandler::QuartzHandler() 00133 { 00134 quartz_initialized = false; 00135 readConfig(); 00136 createPixmaps(); 00137 quartz_initialized = true; 00138 } 00139 00140 00141 QuartzHandler::~QuartzHandler() 00142 { 00143 quartz_initialized = false; 00144 freePixmaps(); 00145 } 00146 00147 00148 KDecoration* QuartzHandler::createDecoration( KDecorationBridge* bridge ) 00149 { 00150 return new QuartzClient( bridge, this ); 00151 } 00152 00153 00154 bool QuartzHandler::reset(unsigned long changed) 00155 { 00156 quartz_initialized = false; 00157 freePixmaps(); 00158 readConfig(); 00159 createPixmaps(); 00160 quartz_initialized = true; 00161 00162 // Do we need to "hit the wooden hammer" ? 00163 bool needHardReset = true; 00164 if (changed & SettingColors) 00165 { 00166 needHardReset = false; 00167 } 00168 00169 if (needHardReset) { 00170 return true; 00171 } else { 00172 resetDecorations(changed); 00173 return false; 00174 } 00175 return true; 00176 } 00177 00178 00179 void QuartzHandler::readConfig() 00180 { 00181 KConfig conf("kwinquartzrc"); 00182 conf.setGroup("General"); 00183 coloredFrame = conf.readBoolEntry( "UseTitleBarBorderColors", true ); 00184 00185 // A small hack to make the on all desktops button look nicer 00186 onAllDesktopsButtonOnLeft = KDecoration::options()->titleButtonsLeft().contains( 'S' ); 00187 if ( QApplication::reverseLayout() ) 00188 onAllDesktopsButtonOnLeft = !onAllDesktopsButtonOnLeft; 00189 switch(options()->preferredBorderSize(this)) { 00190 case BorderLarge: 00191 borderWidth = 8; 00192 break; 00193 case BorderVeryLarge: 00194 borderWidth = 12; 00195 break; 00196 case BorderHuge: 00197 borderWidth = 18; 00198 break; 00199 case BorderVeryHuge: 00200 borderWidth = 27; 00201 break; 00202 case BorderOversized: 00203 borderWidth = 40; 00204 break; 00205 case BorderTiny: 00206 case BorderNormal: 00207 default: 00208 borderWidth = 4; 00209 } 00210 00211 normalTitleHeight = QFontMetrics(options()->font(true)).height(); 00212 if (normalTitleHeight < 18) normalTitleHeight = 18; 00213 if (normalTitleHeight < borderWidth) normalTitleHeight = borderWidth; 00214 00215 toolTitleHeight = QFontMetrics(options()->font(true, true)).height(); 00216 if (toolTitleHeight < 12) toolTitleHeight = 12; 00217 if (toolTitleHeight < borderWidth) toolTitleHeight = borderWidth; 00218 } 00219 00220 00221 // This does the colour transition magic. (You say "Oh, is that it?") 00222 // This may be made configurable at a later stage 00223 void QuartzHandler::drawBlocks( KPixmap *pi, KPixmap &p, const QColor &c1, const QColor &c2 ) 00224 { 00225 QPainter px; 00226 00227 px.begin( pi ); 00228 00229 // Draw a background gradient first 00230 KPixmapEffect::gradient(p, c1, c2, KPixmapEffect::HorizontalGradient); 00231 00232 int factor = (pi->height()-2)/4; 00233 int square = factor - (factor+2)/4; 00234 00235 int x = pi->width() - 5*factor - square; 00236 int y = (pi->height() - 4*factor)/2; 00237 00238 px.fillRect( x, y, square, square, c1.light(120) ); 00239 px.fillRect( x, y+factor, square, square, c1 ); 00240 px.fillRect( x, y+2*factor, square, square, c1.light(110) ); 00241 px.fillRect( x, y+3*factor, square, square, c1 ); 00242 00243 px.fillRect( x+factor, y, square, square, c1.light(110) ); 00244 px.fillRect( x+factor, y+factor, square, square, c2.light(110) ); 00245 px.fillRect( x+factor, y+2*factor, square, square, c1.light(120) ); 00246 px.fillRect( x+factor, y+3*factor, square, square, c2.light(130) ); 00247 00248 px.fillRect( x+2*factor, y+factor, square, square, c1.light(110) ); 00249 px.fillRect( x+2*factor, y+2*factor, square, square, c2.light(120) ); 00250 px.fillRect( x+2*factor, y+3*factor, square, square, c2.light(150) ); 00251 00252 px.fillRect( x+3*factor, y, square, square, c1.dark(110) ); 00253 px.fillRect( x+3*factor, y+2*factor, square, square, c2.light(120) ); 00254 px.fillRect( x+3*factor, y+3*factor, square, square, c1.dark(120) ); 00255 00256 px.fillRect( x+4*factor, y+factor, square, square, c1.light(110) ); 00257 px.fillRect( x+4*factor, y+3*factor, square, square, c1.dark(110) ); 00258 00259 px.fillRect( x+5*factor, y+2*factor, square, square, c2.light(120)); 00260 px.fillRect( x+5*factor, y+3*factor, square, square, c2.light(110) ); 00261 } 00262 00263 00264 // This paints the button pixmaps upon loading the style. 00265 void QuartzHandler::createPixmaps() 00266 { 00267 // Obtain titlebar blend colours, and create the block stuff on pixmaps. 00268 QColorGroup g2 = options()->colorGroup(ColorTitleBlend, true); 00269 QColor c2 = g2.background(); 00270 g2 = options()->colorGroup(ColorTitleBar, true ); 00271 QColor c = g2.background().light(130); 00272 00273 titleBlocks = new KPixmap(); 00274 titleBlocks->resize( normalTitleHeight*25/18, normalTitleHeight ); 00275 drawBlocks( titleBlocks, *titleBlocks, c, c2 ); 00276 00277 g2 = options()->colorGroup(ColorTitleBlend, false); 00278 c2 = g2.background(); 00279 g2 = options()->colorGroup(ColorTitleBar, false ); 00280 c = g2.background().light(130); 00281 00282 ititleBlocks = new KPixmap(); 00283 ititleBlocks->resize( normalTitleHeight*25/18, normalTitleHeight ); 00284 drawBlocks( ititleBlocks, *ititleBlocks, c, c2 ); 00285 00286 // Set the on all desktops pin pixmaps; 00287 QColorGroup g; 00288 QPainter p; 00289 00290 g = options()->colorGroup( onAllDesktopsButtonOnLeft ? ColorTitleBar : ColorTitleBlend, true ); 00291 c = onAllDesktopsButtonOnLeft ? g.background().light(130) : g.background(); 00292 g2 = options()->colorGroup( ColorButtonBg, true ); 00293 00294 pinUpPix = new KPixmap(); 00295 pinUpPix->resize(16, 16); 00296 p.begin( pinUpPix ); 00297 p.fillRect( 0, 0, 16, 16, c); 00298 kColorBitmaps( &p, g2, 0, 1, 16, 16, true, pinup_white_bits, 00299 pinup_gray_bits, NULL, NULL, pinup_dgray_bits, NULL ); 00300 p.end(); 00301 00302 pinDownPix = new KPixmap(); 00303 pinDownPix->resize(16, 16); 00304 p.begin( pinDownPix ); 00305 p.fillRect( 0, 0, 16, 16, c); 00306 kColorBitmaps( &p, g2, 0, 1, 16, 16, true, pindown_white_bits, 00307 pindown_gray_bits, NULL, NULL, pindown_dgray_bits, NULL ); 00308 p.end(); 00309 00310 00311 // Inactive pins 00312 g = options()->colorGroup( onAllDesktopsButtonOnLeft ? ColorTitleBar : ColorTitleBlend, false ); 00313 c = onAllDesktopsButtonOnLeft ? g.background().light(130) : g.background(); 00314 g2 = options()->colorGroup( ColorButtonBg, false ); 00315 00316 ipinUpPix = new KPixmap(); 00317 ipinUpPix->resize(16, 16); 00318 p.begin( ipinUpPix ); 00319 p.fillRect( 0, 0, 16, 16, c); 00320 kColorBitmaps( &p, g2, 0, 1, 16, 16, true, pinup_white_bits, 00321 pinup_gray_bits, NULL, NULL, pinup_dgray_bits, NULL ); 00322 p.end(); 00323 00324 ipinDownPix = new KPixmap(); 00325 ipinDownPix->resize(16, 16); 00326 p.begin( ipinDownPix ); 00327 p.fillRect( 0, 0, 16, 16, c); 00328 kColorBitmaps( &p, g2, 0, 1, 16, 16, true, pindown_white_bits, 00329 pindown_gray_bits, NULL, NULL, pindown_dgray_bits, NULL ); 00330 p.end(); 00331 } 00332 00333 00334 void QuartzHandler::freePixmaps() 00335 { 00336 delete titleBlocks; 00337 delete ititleBlocks; 00338 00339 // On all desktops pin images 00340 delete pinUpPix; 00341 delete ipinUpPix; 00342 delete pinDownPix; 00343 delete ipinDownPix; 00344 } 00345 00346 00347 QValueList< QuartzHandler::BorderSize > QuartzHandler::borderSizes() const 00348 { // the list must be sorted 00349 return QValueList< BorderSize >() << BorderNormal << BorderLarge << 00350 BorderVeryLarge << BorderHuge << BorderVeryHuge << BorderOversized; 00351 } 00352 00353 00354 QuartzButton::QuartzButton(QuartzClient *parent, const char *name, bool largeButton, 00355 bool isLeftButton, bool isOnAllDesktopsButton, const unsigned char *bitmap, 00356 const QString& tip, const int realizeBtns) 00357 : QButton(parent->widget(), name), 00358 last_button(NoButton) 00359 { 00360 setTipText(tip); 00361 setCursor(ArrowCursor); 00362 00363 // Eliminate any possible background flicker 00364 setBackgroundMode( QWidget::NoBackground ); 00365 setToggleButton( isOnAllDesktopsButton ); 00366 00367 realizeButtons = realizeBtns; 00368 00369 deco = NULL; 00370 large = largeButton; 00371 if ( QApplication::reverseLayout() ) 00372 isLeft = !isLeftButton; 00373 else 00374 isLeft = isLeftButton; 00375 isOnAllDesktops = isOnAllDesktopsButton; 00376 client = parent; 00377 00378 if ( large ) 00379 setFixedSize(normalTitleHeight-2, normalTitleHeight-2); 00380 else 00381 setFixedSize(toolTitleHeight-2, toolTitleHeight-2); 00382 00383 if(bitmap) 00384 setBitmap(bitmap); 00385 } 00386 00387 00388 QuartzButton::~QuartzButton() 00389 { 00390 delete deco; 00391 } 00392 00393 00394 QSize QuartzButton::sizeHint() const 00395 { 00396 if ( large ) 00397 return( QSize(normalTitleHeight-2, normalTitleHeight-2) ); 00398 else 00399 return( QSize(toolTitleHeight-2, toolTitleHeight-2) ); 00400 } 00401 00402 00403 void QuartzButton::setBitmap(const unsigned char *bitmap) 00404 { 00405 delete deco; 00406 00407 deco = new QBitmap(10, 10, bitmap, true); 00408 deco->setMask( *deco ); 00409 repaint( false ); 00410 } 00411 00412 00413 void QuartzButton::setTipText(const QString &tip) { 00414 if(KDecoration::options()->showTooltips()) { 00415 QToolTip::remove(this ); 00416 QToolTip::add(this, tip ); 00417 } 00418 } 00419 00420 00421 void QuartzButton::drawButton(QPainter *p) 00422 { 00423 // Never paint if the pixmaps have not been created 00424 if (!quartz_initialized) 00425 return; 00426 00427 QColor c; 00428 00429 if (isLeft) 00430 c = KDecoration::options()->color(KDecoration::ColorTitleBar, client->isActive()).light(130); 00431 else 00432 c = KDecoration::options()->color(KDecoration::ColorTitleBlend, client->isActive()); 00433 00434 // Fill the button background with an appropriate color 00435 p->fillRect(0, 0, width(), height(), c ); 00436 00437 // If we have a decoration bitmap, then draw that 00438 // otherwise we paint a menu button (with mini icon), or a onAllDesktops button. 00439 if( deco ) 00440 { 00441 int xOff = (width()-10)/2; 00442 int yOff = (height()-10)/2; 00443 p->setPen( Qt::black ); 00444 p->drawPixmap(isDown() ? xOff+2: xOff+1, isDown() ? yOff+2 : yOff+1, *deco); 00445 p->setPen( KDecoration::options()->color(KDecoration::ColorButtonBg, client->isActive()).light(150) ); 00446 p->drawPixmap(isDown() ? xOff+1: xOff, isDown() ? yOff+1 : yOff, *deco); 00447 } else 00448 { 00449 QPixmap btnpix; 00450 int Offset = 0; 00451 00452 if (isOnAllDesktops) 00453 { 00454 if (isDown()) 00455 Offset = 1; 00456 00457 // Select the right onAllDesktops button to paint 00458 if (client->isActive()) 00459 btnpix = isOn() ? *pinDownPix : *pinUpPix; 00460 else 00461 btnpix = isOn() ? *ipinDownPix : *ipinUpPix; 00462 00463 } else 00464 btnpix = client->icon().pixmap( QIconSet::Small, QIconSet::Normal); 00465 00466 // Shrink the miniIcon for tiny titlebars. 00467 if ( height() < 16) 00468 { 00469 QPixmap tmpPix; 00470 00471 // Smooth scale the image 00472 tmpPix.convertFromImage( btnpix.convertToImage().smoothScale(height(), height())); 00473 p->drawPixmap( 0, 0, tmpPix ); 00474 } else { 00475 Offset += (height() - 16)/2; 00476 p->drawPixmap( Offset, Offset, btnpix ); 00477 } 00478 } 00479 } 00480 00481 00482 // Make the protected member public 00483 void QuartzButton::turnOn( bool isOn ) 00484 { 00485 if ( isToggleButton() ) 00486 setOn( isOn ); 00487 } 00488 00489 00490 void QuartzButton::mousePressEvent( QMouseEvent* e ) 00491 { 00492 last_button = e->button(); 00493 QMouseEvent me( e->type(), e->pos(), e->globalPos(), 00494 (e->button()&realizeButtons)?LeftButton:NoButton, e->state() ); 00495 QButton::mousePressEvent( &me ); 00496 } 00497 00498 00499 void QuartzButton::mouseReleaseEvent( QMouseEvent* e ) 00500 { 00501 last_button = e->button(); 00502 QMouseEvent me( e->type(), e->pos(), e->globalPos(), 00503 (e->button()&realizeButtons)?LeftButton:NoButton, e->state() ); 00504 QButton::mouseReleaseEvent( &me ); 00505 } 00506 00507 00509 00510 QuartzClient::QuartzClient(KDecorationBridge* bridge, KDecorationFactory* factory) 00511 : KDecoration (bridge, factory) 00512 { 00513 } 00514 00515 00516 void QuartzClient::init() 00517 { 00518 connect( this, SIGNAL( keepAboveChanged( bool )), SLOT( keepAboveChange( bool ))); 00519 connect( this, SIGNAL( keepBelowChanged( bool )), SLOT( keepBelowChange( bool ))); 00520 00521 createMainWidget(WNoAutoErase | WStaticContents); 00522 00523 widget()->installEventFilter( this ); 00524 00525 // No flicker thanks 00526 widget()->setBackgroundMode( QWidget::NoBackground ); 00527 00528 // Set button pointers to NULL so we can track things 00529 for(int i=0; i < QuartzClient::BtnCount; i++) 00530 button[i] = NULL; 00531 00532 // Finally, toolWindows look small 00533 if ( isTool() ) { 00534 titleHeight = toolTitleHeight; 00535 largeButtons = false; 00536 } 00537 else { 00538 titleHeight = normalTitleHeight; 00539 largeButtons = true; 00540 } 00541 00542 borderSize = borderWidth; 00543 00544 // Pack the fake window window within a grid 00545 QGridLayout* g = new QGridLayout(widget(), 0, 0, 0); 00546 g->setResizeMode(QLayout::FreeResize); 00547 g->addRowSpacing(0, borderSize-1); // Top grab bar 00548 if( isPreview()) 00549 g->addWidget(new QLabel( i18n( "<center><b>Quartz</b></center>" ), widget()), 3, 1); 00550 else 00551 g->addItem(new QSpacerItem( 0, 0 ), 3, 1); // no widget in the middle 00552 00553 // without the next line, unshade flickers 00554 g->addItem( new QSpacerItem( 0, 0, QSizePolicy::Fixed, 00555 QSizePolicy::Expanding ) ); 00556 g->setRowStretch(3, 10); // Wrapped window 00557 g->addRowSpacing(2, 1); // line under titlebar 00558 g->addRowSpacing(4, borderSize); // bottom handles 00559 g->addColSpacing(0, borderSize); 00560 g->addColSpacing(2, borderSize); 00561 00562 // Pack the titlebar HBox with items 00563 hb = new QBoxLayout(0, QBoxLayout::LeftToRight, 0, 0, 0); 00564 hb->setResizeMode( QLayout::FreeResize ); 00565 g->addLayout ( hb, 1, 1 ); 00566 00567 addClientButtons( options()->titleButtonsLeft() ); 00568 00569 titlebar = new QSpacerItem( 10, titleHeight, QSizePolicy::Expanding, QSizePolicy::Minimum ); 00570 hb->addItem(titlebar); 00571 hb->addSpacing(2); 00572 00573 addClientButtons( options()->titleButtonsRight(), false ); 00574 00575 hb->addSpacing(2); 00576 } 00577 00578 void QuartzClient::reset( unsigned long changed ) 00579 { 00580 if (changed & SettingColors || changed & SettingFont) 00581 { 00582 // repaint the whole thing 00583 widget()->repaint(false); 00584 } 00585 } 00586 00587 const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask 00588 | NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask | NET::TopMenuMask 00589 | NET::UtilityMask | NET::SplashMask; 00590 00591 bool QuartzClient::isTool() 00592 { 00593 NET::WindowType type = windowType( SUPPORTED_WINDOW_TYPES_MASK ); 00594 return ((type==NET::Toolbar)||(type==NET::Utility)||(type==NET::Menu)); 00595 } 00596 00597 00598 void QuartzClient::addClientButtons( const QString& s, bool isLeft ) 00599 { 00600 if (s.length() > 0) 00601 for(unsigned int i = 0; i < s.length(); i++) 00602 { 00603 switch( s[i].latin1() ) 00604 { 00605 // Menu button 00606 case 'M': 00607 if (!button[BtnMenu]) 00608 { 00609 button[BtnMenu] = new QuartzButton(this, "menu", 00610 largeButtons, isLeft, false, NULL, i18n("Menu"), LeftButton|RightButton); 00611 connect( button[BtnMenu], SIGNAL(pressed()), 00612 this, SLOT(menuButtonPressed()) ); 00613 hb->addWidget( button[BtnMenu] ); 00614 } 00615 break; 00616 00617 // On all desktops button 00618 case 'S': 00619 if (!button[BtnOnAllDesktops]) 00620 { 00621 button[BtnOnAllDesktops] = new QuartzButton(this, "on_all_desktops", 00622 largeButtons, isLeft, true, NULL, isOnAllDesktops()?i18n("Not on all desktops"):i18n("On all desktops")); 00623 button[BtnOnAllDesktops]->turnOn( isOnAllDesktops() ); 00624 connect( button[BtnOnAllDesktops], SIGNAL(clicked()), 00625 this, SLOT(toggleOnAllDesktops()) ); 00626 hb->addSpacing(1); 00627 hb->addWidget( button[BtnOnAllDesktops] ); 00628 hb->addSpacing(1); 00629 } 00630 break; 00631 00632 // Help button 00633 case 'H': 00634 if( providesContextHelp() && (!button[BtnHelp]) ) 00635 { 00636 button[BtnHelp] = new QuartzButton(this, "help", 00637 largeButtons, isLeft, true, question_bits, i18n("Help")); 00638 connect( button[BtnHelp], SIGNAL( clicked() ), 00639 this, SLOT(showContextHelp())); 00640 hb->addWidget( button[BtnHelp] ); 00641 } 00642 break; 00643 00644 // Minimize button 00645 case 'I': 00646 if ( (!button[BtnIconify]) && isMinimizable()) 00647 { 00648 button[BtnIconify] = new QuartzButton(this, "iconify", 00649 largeButtons, isLeft, true, iconify_bits, i18n("Minimize")); 00650 connect( button[BtnIconify], SIGNAL( clicked()), 00651 this, SLOT(minimize()) ); 00652 hb->addWidget( button[BtnIconify] ); 00653 } 00654 break; 00655 00656 // Maximize button 00657 case 'A': 00658 if ( (!button[BtnMax]) && isMaximizable()) 00659 { 00660 button[BtnMax] = new QuartzButton(this, "maximize", 00661 largeButtons, isLeft, true, maximize_bits, i18n("Maximize"), LeftButton|MidButton|RightButton); 00662 connect( button[BtnMax], SIGNAL( clicked()), 00663 this, SLOT(slotMaximize()) ); 00664 hb->addWidget( button[BtnMax] ); 00665 } 00666 break; 00667 00668 // Close button 00669 case 'X': 00670 if (!button[BtnClose] && isCloseable()) 00671 { 00672 button[BtnClose] = new QuartzButton(this, "close", 00673 largeButtons, isLeft, true, close_bits, i18n("Close")); 00674 connect( button[BtnClose], SIGNAL( clicked()), 00675 this, SLOT(closeWindow()) ); 00676 hb->addWidget( button[BtnClose] ); 00677 } 00678 break; 00679 00680 // Above button 00681 case 'F': 00682 if ( (!button[BtnAbove])) 00683 { 00684 button[BtnAbove] = new QuartzButton(this, "above", 00685 largeButtons, isLeft, true, 00686 keepAbove() ? above_on_bits : above_off_bits, 00687 i18n("Keep Above Others")); 00688 connect( button[BtnAbove], SIGNAL( clicked()), 00689 this, SLOT(slotAbove()) ); 00690 hb->addWidget( button[BtnAbove] ); 00691 } 00692 break; 00693 00694 // Below button 00695 case 'B': 00696 if ( (!button[BtnBelow])) 00697 { 00698 button[BtnBelow] = new QuartzButton(this, "below", 00699 largeButtons, isLeft, true, 00700 keepBelow() ? below_on_bits : below_off_bits, 00701 i18n("Keep Below Others")); 00702 connect( button[BtnBelow], SIGNAL( clicked()), 00703 this, SLOT(slotBelow()) ); 00704 hb->addWidget( button[BtnBelow] ); 00705 } 00706 break; 00707 00708 // Shade button 00709 case 'L': 00710 if ( (!button[BtnShade]) && isShadeable()) 00711 { 00712 button[BtnShade] = new QuartzButton(this, "shade", 00713 largeButtons, isLeft, true, 00714 isSetShade() ? shade_on_bits : shade_off_bits, 00715 isSetShade() ? i18n( "Unshade" ) : i18n("Shade")); 00716 connect( button[BtnShade], SIGNAL( clicked()), 00717 this, SLOT(slotShade()) ); 00718 hb->addWidget( button[BtnShade] ); 00719 } 00720 break; 00721 } 00722 } 00723 } 00724 00725 00726 void QuartzClient::iconChange() 00727 { 00728 if (button[BtnMenu] && button[BtnMenu]->isVisible()) 00729 button[BtnMenu]->repaint(false); 00730 } 00731 00732 00733 void QuartzClient::desktopChange() 00734 { 00735 if (button[BtnOnAllDesktops]) 00736 { 00737 button[BtnOnAllDesktops]->turnOn(isOnAllDesktops()); 00738 button[BtnOnAllDesktops]->repaint(false); 00739 button[BtnOnAllDesktops]->setTipText(isOnAllDesktops() ? i18n("Not on all desktops") : i18n("On all desktops")); 00740 } 00741 } 00742 00743 00744 void QuartzClient::keepAboveChange( bool above ) 00745 { 00746 if (button[BtnAbove]) { 00747 button[BtnAbove]->setBitmap( above ? above_on_bits : above_off_bits ); 00748 button[BtnAbove]->repaint(false); 00749 } 00750 } 00751 00752 00753 void QuartzClient::keepBelowChange( bool below ) 00754 { 00755 if (button[BtnBelow]) { 00756 button[BtnBelow]->setBitmap( below ? below_on_bits : below_off_bits ); 00757 button[BtnBelow]->repaint(false); 00758 } 00759 } 00760 00761 void QuartzClient::shadeChange() 00762 { 00763 if (button[BtnShade]) { 00764 bool on = isShade(); 00765 button[BtnShade]->turnOn(on); 00766 button[BtnShade]->repaint(false); 00767 QToolTip::remove( button[BtnShade] ); 00768 QToolTip::add( button[BtnShade], on ? i18n("Unshade") : i18n("Shade")); 00769 } 00770 } 00771 00772 00773 void QuartzClient::slotMaximize() 00774 { 00775 if (button[BtnMax]) 00776 { 00777 maximize(button[BtnMax]->last_button); 00778 } 00779 } 00780 00781 00782 void QuartzClient::slotAbove() 00783 { 00784 setKeepAbove( !keepAbove()); 00785 button[BtnAbove]->turnOn(keepAbove()); 00786 button[BtnAbove]->repaint(true); 00787 } 00788 00789 00790 void QuartzClient::slotBelow() 00791 { 00792 setKeepBelow( !keepBelow()); 00793 button[BtnBelow]->turnOn(keepBelow()); 00794 button[BtnBelow]->repaint(true); 00795 } 00796 00797 00798 void QuartzClient::slotShade() 00799 { 00800 setShade( !isSetShade()); 00801 button[BtnShade]->setBitmap(isSetShade() ? shade_on_bits : shade_off_bits ); 00802 button[BtnShade]->repaint(true); 00803 } 00804 00805 00806 void QuartzClient::resizeEvent( QResizeEvent* e) 00807 { 00808 calcHiddenButtons(); 00809 00810 if (widget()->isVisibleToTLW()) 00811 { 00812 widget()->update(widget()->rect()); 00813 int dx = 0; 00814 int dy = 0; 00815 00816 if ( e->oldSize().width() != width() ) 00817 dx = 32 + QABS( e->oldSize().width() - width() ); 00818 00819 if ( e->oldSize().height() != height() ) 00820 dy = 8 + QABS( e->oldSize().height() - height() ); 00821 00822 if ( dy ) 00823 widget()->update( 0, height() - dy + 1, width(), dy ); 00824 00825 if ( dx ) 00826 { 00827 widget()->update( width() - dx + 1, 0, dx, height() ); 00828 widget()->update( QRect( QPoint(4,4), titlebar->geometry().bottomLeft() - QPoint(1,0) ) ); 00829 widget()->update( QRect( titlebar->geometry().topRight(), QPoint( width() - 4, titlebar->geometry().bottom() ) ) ); 00830 // Titlebar needs no paint event 00831 widget()->repaint(titlebar->geometry(), false); 00832 } 00833 } 00834 } 00835 00836 00837 void QuartzClient::captionChange() 00838 { 00839 widget()->repaint( titlebar->geometry(), false ); 00840 } 00841 00842 00843 // Quartz Paint magic goes here. 00844 void QuartzClient::paintEvent( QPaintEvent* ) 00845 { 00846 // Never paint if the pixmaps have not been created 00847 if (!quartz_initialized) 00848 return; 00849 00850 const bool maxFull = (maximizeMode()==MaximizeFull) && !options()->moveResizeMaximizedWindows(); 00851 00852 QColorGroup g; 00853 QPainter p(widget()); 00854 00855 // Obtain widget bounds. 00856 QRect r(widget()->rect()); 00857 int x = r.x(); 00858 int y = r.y(); 00859 int x2 = r.width() - 1; 00860 int y2 = r.height() - 1; 00861 int w = r.width(); 00862 int h = r.height(); 00863 00864 // Draw part of the frame that is the title color 00865 00866 if( coloredFrame ) 00867 g = options()->colorGroup(ColorTitleBar, isActive()); 00868 else 00869 g = options()->colorGroup(ColorFrame, isActive()); 00870 00871 // Draw outer highlights and lowlights 00872 p.setPen( g.light().light(120) ); 00873 p.drawLine( x, y, x2-1, y ); 00874 p.drawLine( x, y+1, x, y2-1 ); 00875 p.setPen( g.dark().light(120) ); 00876 p.drawLine( x2, y, x2, y2 ); 00877 p.drawLine( x, y2, x2, y2 ); 00878 00879 // Fill out the border edges 00880 QColor frameColor; 00881 if ( coloredFrame) 00882 frameColor = g.background().light(130); 00883 else 00884 frameColor = g.background(); 00885 if (borderSize > 2) { 00886 p.fillRect(x+1, y+1, w-2, borderSize-2, frameColor); // top 00887 if (!maxFull) { 00888 p.fillRect(x+1, y+h-(borderSize-1), w-2, borderSize-2, frameColor); // bottom 00889 p.fillRect(x+1, y+borderSize-1, borderSize-1, h-2*(borderSize-1), frameColor); // left 00890 p.fillRect(x+w-(borderSize), y+borderSize-1, borderSize-1, h-2*(borderSize-1), frameColor); // right 00891 } 00892 } 00893 00894 // Draw a frame around the wrapped widget. 00895 p.setPen( g.background() ); 00896 if (maxFull) { 00897 p.drawLine(x+1, y+titleHeight+(borderSize-1), w-2, y+titleHeight+(borderSize-1)); 00898 } else { 00899 p.drawRect( x+(borderSize-1), y+titleHeight+(borderSize-1), w-2*(borderSize-1), h-titleHeight-2*(borderSize-1) ); 00900 } 00901 00902 // Drawing this extra line removes non-drawn areas when shaded 00903 p.drawLine( x+borderSize, y2-borderSize, x2-borderSize, y2-borderSize); 00904 00905 // Highlight top corner 00906 p.setPen( g.light().light(160) ); 00907 p.drawPoint( x, y ); 00908 p.setPen( g.light().light(140) ); 00909 p.drawPoint( x+1, y ); 00910 p.drawPoint( x, y+1 ); 00911 00912 // Draw the title bar. 00913 // =================== 00914 r = titlebar->geometry(); 00915 00916 // Obtain titlebar blend colours 00917 QColor c1 = options()->color(ColorTitleBar, isActive() ).light(130); 00918 QColor c2 = options()->color(ColorTitleBlend, isActive() ); 00919 00920 // Create a disposable pixmap buffer for the titlebar 00921 KPixmap* titleBuffer = new KPixmap; 00922 titleBuffer->resize( maxFull?w-2:(w-2*(borderSize-1)), titleHeight ); 00923 00924 QPainter p2( titleBuffer, this ); 00925 00926 // subtract titleBlocks pixmap width and some 00927 int rightoffset = r.x()+r.width()-titleBlocks->width()-borderSize; 00928 00929 p2.fillRect( 0, 0, w, r.height(), c1 ); 00930 p2.fillRect( rightoffset, 0, maxFull?w-rightoffset:w-rightoffset-2*(borderSize-1), r.height(), c2 ); 00931 00932 // 8 bit displays will be a bit dithered, but they still look ok. 00933 if ( isActive() ) 00934 p2.drawPixmap( rightoffset, 0, *titleBlocks ); 00935 else 00936 p2.drawPixmap( rightoffset, 0, *ititleBlocks ); 00937 00938 // Draw the title text on the pixmap, and with a smaller font 00939 // for toolwindows than the default. 00940 QFont fnt; 00941 if ( largeButtons ) { 00942 fnt = options()->font(true, false); // font not small 00943 } else { 00944 fnt = options()->font(true, true); // font small 00945 fnt.setWeight( QFont::Normal ); // and disable bold 00946 } 00947 p2.setFont( fnt ); 00948 00949 p2.setPen( options()->color(ColorFont, isActive() )); 00950 p2.drawText(r.x()+4-borderSize, 0, r.width()-3, r.height(), 00951 AlignLeft | AlignVCenter, caption() ); 00952 p2.end(); 00953 00954 p.drawPixmap( maxFull?1:borderSize-1, borderSize-1, *titleBuffer ); 00955 00956 delete titleBuffer; 00957 } 00958 00959 00960 void QuartzClient::showEvent(QShowEvent *) 00961 { 00962 calcHiddenButtons(); 00963 widget()->show(); 00964 } 00965 00966 00967 void QuartzClient::mouseDoubleClickEvent( QMouseEvent * e ) 00968 { 00969 if (titlebar->geometry().contains( e->pos() ) ) 00970 titlebarDblClickOperation(); 00971 } 00972 00973 00974 void QuartzClient::maximizeChange() 00975 { 00976 if (button[BtnMax]) { 00977 button[BtnMax]->setBitmap((maximizeMode()==MaximizeFull) ? minmax_bits : maximize_bits); 00978 button[BtnMax]->setTipText((maximizeMode()==MaximizeFull) ? i18n("Restore") : i18n("Maximize")); 00979 } 00980 } 00981 00982 00983 void QuartzClient::activeChange() 00984 { 00985 for(int i=QuartzClient::BtnHelp; i < QuartzClient::BtnCount; i++) 00986 if(button[i]) 00987 button[i]->repaint(false); 00988 00989 widget()->repaint(false); 00990 } 00991 00992 00993 QuartzClient::Position QuartzClient::mousePosition(const QPoint &point) const 00994 { 00995 const int corner = 3*borderSize/2 + 18; 00996 Position pos = PositionCenter; 00997 00998 QRect r(widget()->rect()); 00999 01000 if(point.y() < (borderSize-1)) { 01001 if(point.x() < corner) return PositionTopLeft; 01002 else if(point.x() > (r.right()-corner)) return PositionTopRight; 01003 else return PositionTop; 01004 } else if(point.y() > (r.bottom()-borderSize)) { 01005 if(point.x() < corner) return PositionBottomLeft; 01006 else if(point.x() > (r.right()-corner)) return PositionBottomRight; 01007 else return PositionBottom; 01008 } else if(point.x() < borderSize) { 01009 if(point.y() < corner) return PositionTopLeft; 01010 else if(point.y() > (r.bottom()-corner)) return PositionBottomLeft; 01011 else return PositionLeft; 01012 } else if(point.x() > (r.right()-borderSize)) { 01013 if(point.y() < corner) return PositionTopRight; 01014 else if(point.y() > (r.bottom()-corner)) return PositionBottomRight; 01015 else return PositionRight; 01016 } 01017 01018 return pos; 01019 } 01020 01021 01022 void QuartzClient::borders(int& left, int& right, int& top, int& bottom) const 01023 { 01024 left = borderSize; 01025 right = borderSize; 01026 top = 1 + titleHeight + (borderSize-1); 01027 bottom = borderSize; 01028 01029 if ((maximizeMode()==MaximizeFull) && !options()->moveResizeMaximizedWindows()) { 01030 left = right = bottom = 0; 01031 top = 1 + titleHeight + (borderSize-1); 01032 } 01033 } 01034 01035 01036 void QuartzClient::resize( const QSize& s ) 01037 { 01038 widget()->resize( s ); 01039 } 01040 01041 01042 QSize QuartzClient::minimumSize() const 01043 { 01044 return widget()->minimumSize(); 01045 } 01046 01047 01048 // The hiding button while shrinking, show button while expanding magic 01049 void QuartzClient::calcHiddenButtons() 01050 { 01051 //Hide buttons in this order: 01052 //Shade, Below, Above, OnAllDesktops, Help, Maximize, Menu, Minimize, Close. 01053 QuartzButton* btnArray[] = { button[BtnShade], button[BtnBelow], button[BtnAbove], 01054 button[BtnOnAllDesktops], button[BtnHelp], button[BtnMax], 01055 button[BtnMenu], button[BtnIconify], button[BtnClose] }; 01056 const int buttons_cnt = sizeof( btnArray ) / sizeof( btnArray[ 0 ] ); 01057 01058 int minwidth = largeButtons ? 180 : 140; // Start hiding buttons at this width 01059 int btn_width = largeButtons ? 16 : 10; 01060 int current_width = width(); 01061 int count = 0; 01062 int i; 01063 01064 // Find out how many buttons we have to hide. 01065 while (current_width < minwidth) 01066 { 01067 current_width += btn_width; 01068 count++; 01069 } 01070 01071 // Bound the number of buttons to hide 01072 if (count > buttons_cnt) count = buttons_cnt; 01073 01074 // Hide the required buttons... 01075 for(i = 0; i < count; i++) 01076 { 01077 if (btnArray[i] && btnArray[i]->isVisible() ) 01078 btnArray[i]->hide(); 01079 } 01080 01081 // Show the rest of the buttons... 01082 for(i = count; i < buttons_cnt; i++) 01083 { 01084 if (btnArray[i] && (!btnArray[i]->isVisible()) ) 01085 btnArray[i]->show(); 01086 } 01087 } 01088 01089 01090 // Make sure the menu button follows double click conventions set in kcontrol 01091 void QuartzClient::menuButtonPressed() 01092 { 01093 QRect menuRect = button[BtnMenu]->rect(); 01094 QPoint menuTop ( menuRect.topLeft() ); 01095 QPoint menuBottom ( menuRect.bottomRight() ); 01096 menuTop += QPoint(-1, 2); 01097 menuBottom += QPoint(1, 2); 01098 menuTop = button[BtnMenu]->mapToGlobal( menuTop ); 01099 menuBottom = button[BtnMenu]->mapToGlobal( menuBottom ); 01100 KDecorationFactory* f = factory(); 01101 showWindowMenu(QRect(menuTop, menuBottom)); 01102 if( !f->exists( this )) // 'this' was destroyed 01103 return; 01104 button[BtnMenu]->setDown(false); 01105 } 01106 01107 bool QuartzClient::eventFilter( QObject* o, QEvent* e ) 01108 { 01109 if( o != widget()) 01110 return false; 01111 switch( e->type()) 01112 { 01113 case QEvent::Resize: 01114 resizeEvent(static_cast< QResizeEvent* >( e ) ); 01115 return true; 01116 case QEvent::Paint: 01117 paintEvent(static_cast< QPaintEvent* >( e ) ); 01118 return true; 01119 case QEvent::MouseButtonDblClick: 01120 mouseDoubleClickEvent(static_cast< QMouseEvent* >( e ) ); 01121 return true; 01122 case QEvent::MouseButtonPress: 01123 processMousePressEvent(static_cast< QMouseEvent* >( e ) ); 01124 return true; 01125 default: 01126 break; 01127 } 01128 return false; 01129 } 01130 01131 } 01132 01133 // Extended KWin plugin interface 01135 extern "C" 01136 { 01137 KDecorationFactory *create_factory() 01138 { 01139 Quartz::clientHandler = new Quartz::QuartzHandler(); 01140 return Quartz::clientHandler; 01141 } 01142 } 01143 01144 01145 01146 #include "quartz.moc" 01147 // 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:06 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003