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::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.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Mar 5 04:41:14 2004 by doxygen 1.3.6-20040222 written by Dimitri van Heesch, © 1997-2003