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