kwin Library API Documentation

redmond.cpp

00001 /*
00002  *
00003  * Redmond KWin client
00004  *
00005  * Copyright 2001
00006  *   Karol Szwed <gallium@kde.org>
00007  *   http://gallium.n3.net/
00008  *
00009  * Based on the default KWin client.
00010  *
00011  * Updated to support toolwindows 3/2001 (KS)
00012  *
00013  */
00014 
00015 #include "redmond.h"
00016 
00017 #include <qlayout.h>
00018 #include <qdrawutil.h>
00019 #include <qdatetime.h>
00020 #include <kpixmapeffect.h>
00021 #include <kimageeffect.h>
00022 #include <kdrawutil.h>
00023 #include <klocale.h>
00024 
00025 #include <qbitmap.h>
00026 #include <qtooltip.h>
00027 #include <qimage.h>
00028 #include <qlabel.h>
00029 #include <qapplication.h>
00030 
00031 namespace Redmond {
00032 
00033 static const char *kdelogo[] = {
00034 /* columns rows colors chars-per-pixel */
00035 "16 16 8 1",
00036 "   c None",
00037 ".  c #000000",
00038 "+  c #A0A0A4",
00039 "@  c #FFFFFF",
00040 "#  c #585858",
00041 "$  c #C0C0C0",
00042 "%  c #808080",
00043 "&  c #DCDCDC",
00044 "                ",
00045 "     ..    ..   ",
00046 "    .+@.  .@#.  ",
00047 "   .@@@. .@@@#  ",
00048 "   .@@@..$@@$.  ",
00049 "   .@@@.@@@$.   ",
00050 "   .@@@%@@$.    ",
00051 "   .@@@&@@.     ",
00052 "   .@@@@@@.     ",
00053 "   .@@@$@@&.    ",
00054 "   .@@@.@@@.    ",
00055 "   .@@@.+@@@.   ",
00056 "   .@@@..$@@&.  ",
00057 "   .@@%. .@@@.  ",
00058 "   ....   ...   ",
00059 "                "};
00060 
00061 static unsigned char iconify_bits[] = {
00062   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00063   0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00};
00064 
00065 static unsigned char close_bits[] = {
00066   0x00, 0x00, 0x86, 0x01, 0xcc, 0x00, 0x78, 0x00, 0x30, 0x00, 0x78, 0x00,
00067   0xcc, 0x00, 0x86, 0x01, 0x00, 0x00, 0x00, 0x00};
00068 
00069 static unsigned char maximize_bits[] = {
00070   0xff, 0x01, 0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
00071   0x01, 0x01, 0x01, 0x01, 0xff, 0x01, 0x00, 0x00};
00072 
00073 static unsigned char minmax_bits[] = {
00074   0xfc, 0x00, 0xfc, 0x00, 0x84, 0x00, 0xbf, 0x00, 0xbf, 0x00, 0xe1, 0x00,
00075   0x21, 0x00, 0x21, 0x00, 0x3f, 0x00, 0x00, 0x00};
00076 
00077 static unsigned char question_bits[] = {
00078   0x00, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00,
00079   0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00};
00080 
00081 
00082 // Up / Down titlebar button images
00083 static KPixmap *btnPix1;
00084 static KPixmap *iBtnPix1;
00085 static KPixmap *btnDownPix1;
00086 static KPixmap *iBtnDownPix1;
00087 
00088 static KPixmap *miniBtnPix1;
00089 static KPixmap *iMiniBtnPix1;
00090 static KPixmap *miniBtnDownPix1;
00091 static KPixmap *iMiniBtnDownPix1;
00092 
00093 static QPixmap *defaultMenuPix;
00094 static QColor  *btnForeground;
00095 static bool    pixmaps_created = false;
00096 
00097 static int toolTitleHeight;
00098 static int normalTitleHeight;
00099 static int borderWidth;
00100 
00101 static inline const KDecorationOptions *options()
00102 {
00103    return KDecoration::options();
00104 }
00105 
00106 static void drawButtonFrame( KPixmap *pix, const QColorGroup &g, bool sunken )
00107 {
00108     QPainter p;
00109     int x2 = pix->width() - 1;
00110     int y2 = pix->height() - 1;
00111     p.begin(pix);
00112 
00113     // titlebar button frame
00114     p.setPen( sunken ? g.dark().dark(155) : g.light());
00115     p.drawLine(0, 0, x2-1, 0);
00116     p.drawLine(0, 0, 0, y2-1);
00117 
00118     if (sunken)
00119     {
00120        p.setPen( g.mid().dark(135) );
00121        p.drawLine(1, 1, x2-2, 1);
00122        p.drawLine(1, 1, 1, y2-2);
00123     }
00124 
00125     p.setPen( sunken ? g.light() : g.mid().dark(135));
00126     p.drawLine(1, y2-1, x2-1, y2-1);
00127     p.drawLine(x2-1, 1, x2-1, y2-1);
00128 
00129     p.setPen( sunken ? g.light() : g.dark().dark(155));
00130     p.drawLine(0, y2, x2, y2);
00131     p.drawLine(x2, 0, x2, y2);
00132 }
00133 
00134 
00135 static void create_pixmaps ()
00136 {
00137     if (pixmaps_created)
00138         return;
00139 
00140     pixmaps_created = true;
00141 
00142     bool highcolor = QPixmap::defaultDepth() > 8;
00143 
00144     btnPix1 = new KPixmap;
00145     btnDownPix1 = new KPixmap;
00146     iBtnPix1 = new KPixmap;
00147     iBtnDownPix1 = new KPixmap;
00148     miniBtnPix1 = new KPixmap;
00149     miniBtnDownPix1 = new KPixmap;
00150     iMiniBtnPix1 = new KPixmap;
00151     iMiniBtnDownPix1 = new KPixmap;
00152     defaultMenuPix = new QPixmap(kdelogo);
00153 
00154     // buttons (active/inactive, sunken/unsunken)
00155     QColorGroup g = options()->colorGroup(KDecoration::ColorButtonBg, true);
00156     QColor c = g.background();
00157     btnPix1->resize(normalTitleHeight, normalTitleHeight-2);
00158     btnDownPix1->resize(normalTitleHeight, normalTitleHeight-2);
00159     iBtnPix1->resize(normalTitleHeight, normalTitleHeight-2);
00160     iBtnDownPix1->resize(normalTitleHeight, normalTitleHeight-2);
00161 
00162     miniBtnPix1->resize(toolTitleHeight, toolTitleHeight);
00163     miniBtnDownPix1->resize(toolTitleHeight, toolTitleHeight);
00164     iMiniBtnPix1->resize(toolTitleHeight, toolTitleHeight);
00165     iMiniBtnDownPix1->resize(toolTitleHeight, toolTitleHeight);
00166 
00167     if (highcolor && false) {
00168         KPixmapEffect::gradient(*btnPix1, c.light(130), c.dark(130),
00169                                 KPixmapEffect::VerticalGradient);
00170         KPixmapEffect::gradient(*btnDownPix1, c.dark(130), c.light(130),
00171                                 KPixmapEffect::VerticalGradient);
00172 
00173         KPixmapEffect::gradient(*miniBtnPix1, c.light(130), c.dark(130),
00174                                 KPixmapEffect::VerticalGradient);
00175         KPixmapEffect::gradient(*miniBtnDownPix1, c.dark(130), c.light(130),
00176                                 KPixmapEffect::VerticalGradient);
00177 
00178         g = options()->colorGroup(KDecoration::ColorButtonBg, false);
00179         c = g.background();
00180         KPixmapEffect::gradient(*iBtnPix1, c.light(130), c.dark(130),
00181                                 KPixmapEffect::VerticalGradient);
00182         KPixmapEffect::gradient(*iBtnDownPix1, c.dark(130), c.light(130),
00183                                 KPixmapEffect::VerticalGradient);
00184         KPixmapEffect::gradient(*iMiniBtnPix1, c.light(130), c.dark(130),
00185                                 KPixmapEffect::VerticalGradient);
00186         KPixmapEffect::gradient(*iMiniBtnDownPix1, c.dark(130), c.light(130),
00187                                 KPixmapEffect::VerticalGradient);
00188     } else {
00189         btnPix1->fill(c.rgb());
00190         btnDownPix1->fill(c.rgb());
00191         miniBtnPix1->fill(c.rgb());
00192         miniBtnDownPix1->fill(c.rgb());
00193 
00194         g = options()->colorGroup(KDecoration::ColorButtonBg, false);
00195         c = g.background();
00196         iBtnPix1->fill(c.rgb());
00197         iBtnDownPix1->fill(c.rgb());
00198         iMiniBtnPix1->fill(c.rgb());
00199         iMiniBtnDownPix1->fill(c.rgb());
00200     }
00201 
00202     g = options()->colorGroup(KDecoration::ColorButtonBg, true);
00203     drawButtonFrame(btnPix1, g, false);
00204     drawButtonFrame(btnDownPix1, g, true);
00205     drawButtonFrame(miniBtnPix1, g, false);
00206     drawButtonFrame(miniBtnDownPix1, g, true);
00207 
00208     g = options()->colorGroup(KDecoration::ColorButtonBg, false);
00209     drawButtonFrame(iBtnPix1, g, false);
00210     drawButtonFrame(iBtnDownPix1, g, true);
00211     drawButtonFrame(iMiniBtnPix1, g, false);
00212     drawButtonFrame(iMiniBtnDownPix1, g, true);
00213 
00214     // Make sure button pixmaps contrast with the current colour scheme.
00215     if (qGray(options()->color(KDecoration::ColorButtonBg, true).rgb()) > 127)
00216         btnForeground = new QColor(Qt::black);
00217     else
00218         btnForeground = new QColor(Qt::white);
00219 }
00220 
00221 void delete_pixmaps()
00222 {
00223     delete btnPix1;
00224     delete btnDownPix1;
00225     delete iBtnPix1;
00226     delete iBtnDownPix1;
00227     delete miniBtnPix1;
00228     delete miniBtnDownPix1;
00229     delete iMiniBtnPix1;
00230     delete iMiniBtnDownPix1;
00231     delete defaultMenuPix;
00232     delete btnForeground;
00233     pixmaps_created = false;
00234 }
00235 
00236 
00237 RedmondButton::RedmondButton(RedmondDeco *parent, const char *name,
00238       const unsigned char *bitmap, bool menuButton, bool isMini, int size, const QString& tip, const int realizeBtns)
00239     : QButton(parent->widget(), name),
00240       last_button( NoButton ) 
00241 {
00242     // Eliminate background flicker
00243     setBackgroundMode( NoBackground );
00244         setCursor( arrowCursor );
00245 
00246     menuBtn = menuButton;
00247     miniBtn = isMini;
00248     client  = parent;
00249     this->size = size;
00250     realizeButtons = realizeBtns;
00251 
00252     // Use larger button for the menu, or mini-buttons for toolwindows.
00253     if ( isMini || menuButton ) {
00254         setFixedSize(size, size);
00255         resize(size, size);
00256     } else {
00257         setFixedSize(size, size-2);
00258         resize(size, size-2);
00259     }
00260 
00261     if ( bitmap ) {
00262         setBitmap(bitmap);
00263     }
00264 
00265     QToolTip::add(this, tip);
00266 }
00267 
00268 
00269 QSize RedmondButton::sizeHint() const
00270 {
00271     if ( miniBtn || menuBtn )
00272         return( QSize(size, size) );
00273     else
00274         return( QSize(size, size-2) );
00275 }
00276 
00277 
00278 void RedmondButton::reset()
00279 {
00280     repaint(false);
00281 }
00282 
00283 
00284 void RedmondButton::setBitmap(const unsigned char *bitmap)
00285 {
00286     pix.resize(0, 0);
00287     deco = QBitmap(10, 10, bitmap, true);
00288     deco.setMask(deco);
00289     repaint( false );
00290 }
00291 
00292 
00293 void RedmondButton::setPixmap( const QPixmap &p )
00294 {
00295     deco.resize(0, 0);
00296     pix = p;
00297 
00298     if (miniBtn || menuBtn)
00299         setMask(QRect(0, 0, size, size));
00300     else
00301         setMask(QRect(0, 0, size, size-2));
00302 
00303     repaint(false);
00304 }
00305 
00306 
00307 void RedmondButton::mousePressEvent( QMouseEvent* e )
00308 {
00309     last_button = e->button();
00310     QMouseEvent me(e->type(), e->pos(), e->globalPos(),
00311                    (e->button()&realizeButtons)?LeftButton:NoButton, e->state());
00312     QButton::mousePressEvent( &me );
00313 }
00314 
00315 
00316 void RedmondButton::mouseReleaseEvent( QMouseEvent* e )
00317 {
00318     last_button = e->button();
00319     QMouseEvent me ( e->type(), e->pos(), e->globalPos(),
00320                      (e->button()&realizeButtons)?LeftButton:NoButton, e->state() );
00321     QButton::mouseReleaseEvent( &me );
00322 }
00323 
00324 
00325 void RedmondButton::drawButton(QPainter *p)
00326 {
00327    if ( pix.isNull() ) {
00328       if ( client->isActive() ) {
00329          if ( isDown() )
00330             p->drawPixmap(0, 0, miniBtn ? *miniBtnDownPix1 : *btnDownPix1);
00331          else
00332             p->drawPixmap(0, 0, miniBtn ? *miniBtnPix1 : *btnPix1);
00333       } else {
00334          if ( isDown() )
00335             p->drawPixmap(0, 0, miniBtn ? *iMiniBtnDownPix1 : *iBtnDownPix1);
00336          else
00337             p->drawPixmap(0, 0, miniBtn ? *iMiniBtnPix1 : *iBtnPix1);
00338       }
00339 
00340       p->setPen( *btnForeground );
00341       int xOff = (width()-10)/2;
00342       int yOff = (height()-10)/2;
00343       p->drawPixmap(isDown() ? xOff+1: xOff, isDown() ? yOff+1 : yOff, deco);
00344    } else {
00345       p->fillRect(0, 0, width(), height(),
00346             options()->color(KDecoration::ColorTitleBar, client->isActive()));
00347 
00348       if ( menuBtn && size < 16) {
00349          QPixmap tmpPix;
00350 
00351          // Smooth scale the menu button pixmap
00352          tmpPix.convertFromImage(
00353          pix.convertToImage().smoothScale(size, size));
00354 
00355          p->drawPixmap( 0, 0, tmpPix );
00356       } else {
00357          int xOff = (width() -pix.width() )/2;
00358          int yOff = (height()-pix.height())/2;
00359          p->drawPixmap(xOff, yOff, pix );
00360       }
00361    }
00362 }
00363 
00364 
00365 RedmondDeco::RedmondDeco(KDecorationBridge *b, KDecorationFactory *f)
00366     : KDecoration(b, f)
00367 {
00368 }
00369 
00370 void RedmondDeco::init()
00371 {
00372     createMainWidget(WResizeNoErase);
00373     widget()->installEventFilter(this);
00374 
00375     widget()->setBackgroundMode(NoBackground);
00376 //  bool reverse = QApplication::reverseLayout();
00377 
00378 //  Finally, toolwindows look small
00379 //  if ( isTool() ) {
00380 //      titleHeight = toolTitleHeight+2;
00381 //      smallButtons = true;
00382 //  } else {
00383         titleHeight = normalTitleHeight+2;
00384         smallButtons = false;
00385 //  }
00386 
00387     lastButtonWidth = 0;
00388 
00389     QGridLayout* g = new QGridLayout(widget(), 0, 0, 0);
00390     g->setResizeMode(QLayout::FreeResize);
00391     if (isPreview()) {
00392         g->addWidget(new QLabel(i18n("<center><b>Redmond preview</b></center>"), widget()), 3, 1);
00393     } else {
00394         g->addItem(new QSpacerItem( 0, 0 ), 3, 1); // no widget in the middle
00395     }
00396 
00397     g->addRowSpacing(0, borderWidth);       // Top grab bar
00398     // without the next line, unshade flickers
00399     g->addItem(new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding));
00400     g->setRowStretch(3, 10);      // Wrapped window
00401     g->addRowSpacing(4, borderWidth);       // bottom handles
00402     g->addRowSpacing(2, 1);       // Line below title bar
00403     g->addColSpacing(0, borderWidth);
00404     g->addColSpacing(2, borderWidth);
00405 
00406     button[BtnMenu] = new RedmondButton(this, "menu", NULL, true, smallButtons, titleHeight-2, i18n("Menu"), LeftButton|RightButton);
00407     button[BtnClose] = new RedmondButton(this, "close", close_bits, false, smallButtons, titleHeight-2, i18n("Close"));
00408     button[BtnMin] = new RedmondButton(this, "iconify", iconify_bits, false, smallButtons, titleHeight-2, i18n("Minimize"));
00409     button[BtnMax] = new RedmondButton(this, "maximize", maximize_bits, false, smallButtons, titleHeight-2, i18n("Maximize"), LeftButton|MidButton|RightButton);
00410 
00411     // Connect required stuff together
00412     connect(button[BtnMenu], SIGNAL(pressed()), this, SLOT(menuButtonPressed()));
00413     connect(button[BtnClose], SIGNAL(clicked()), this, SLOT(closeWindow()));
00414     connect(button[BtnMin], SIGNAL(clicked()), this, SLOT(minimize()));
00415     connect(button[BtnMax], SIGNAL(clicked()), this, SLOT(slotMaximize()));
00416 
00417     // Pack the titleBar hbox with items
00418     hb = new QBoxLayout(0, QBoxLayout::LeftToRight, 0, 0, 0);
00419     hb->setResizeMode(QLayout::FreeResize);
00420     hb->addSpacing(2);
00421     hb->addWidget(button[BtnMenu]);
00422     titlebar = new QSpacerItem(10, titleHeight, QSizePolicy::Expanding, QSizePolicy::Minimum);
00423     hb->addItem(titlebar);
00424     hb->addSpacing(borderWidth/2);
00425 
00426     if ( providesContextHelp() ) {
00427         button[BtnHelp] = new RedmondButton(this, "help", question_bits, false, smallButtons, titleHeight-2, i18n("Help"));
00428         connect( button[BtnHelp], SIGNAL( clicked() ), this, SLOT( showContextHelp() ));
00429         hb->addWidget( button[BtnHelp] );
00430     } else {
00431         button[BtnHelp] = NULL;
00432     }
00433 
00434     hb->addWidget(button[BtnMin]);
00435     hb->addWidget(button[BtnMax]);
00436     hb->addSpacing(borderWidth/2);
00437     hb->addWidget(button[BtnClose]);
00438     hb->addSpacing(2);
00439 
00440     g->addLayout(hb, 1, 1);
00441 
00442     // Hide buttons which are not required
00443     // We can un-hide them if required later
00444     if (!isMinimizable())
00445         button[BtnMin]->hide();
00446     if (!isMaximizable())
00447         button[BtnMax]->hide();
00448     if (!isCloseable())
00449         button[BtnClose]->hide();
00450 
00451     hiddenItems = false;
00452 
00453     // Make sure that the menu button uses the correct mini-icon
00454     iconChange();
00455     widget()->layout()->activate();
00456 }
00457 
00458 
00459 void RedmondDeco::slotReset()
00460 {
00461     // 0 to 3   ( 4 buttons - Help, Max, Iconify, Close )
00462     for(int i = RedmondDeco::BtnHelp; i <= RedmondDeco::BtnClose; i++)
00463         if (button[i])
00464             button[i]->reset();
00465 
00466     // The menu is reset by iconChange()
00467 
00468     widget()->repaint( false );
00469 }
00470 
00471 
00472 void RedmondDeco::iconChange()
00473 {
00474     QPixmap miniIcon = icon().pixmap(QIconSet::Small, QIconSet::Normal);
00475 
00476     if (!miniIcon.isNull())
00477         button[BtnMenu]->setPixmap(miniIcon);
00478     else
00479         button[BtnMenu]->setPixmap(*defaultMenuPix);
00480 
00481     if (button[BtnMenu]->isVisible())
00482         button[BtnMenu]->repaint(false);
00483 }
00484 
00485 
00486 void RedmondDeco::slotMaximize()
00487 {
00488     if (button[BtnMax]) {
00489         maximize(button[BtnMax]->last_button);
00490     }
00491 }
00492 
00493 
00494 void RedmondDeco::resizeEvent(QResizeEvent *)
00495 {
00496     calcHiddenButtons();
00497 /*
00498     if (isVisibleToTLW()) {
00499         update(rect());
00500         int dx = 0;
00501         int dy = 0;
00502 
00503         if ( e->oldSize().width() != width() )
00504            dx = 32 + QABS( e->oldSize().width() -  width() );
00505 
00506         if ( e->oldSize().height() != height() )
00507            dy = 8 + QABS( e->oldSize().height() -  height() );
00508 
00509         if ( dy )
00510            update( 0, height() - dy + 1, width(), dy );
00511 
00512         if ( dx )
00513         {
00514            update( width() - dx + 1, 0, dx, height() );
00515            update( QRect( QPoint(4,4), titlebar->geometry().bottomLeft() - QPoint(1,0) ) );
00516            update( QRect( titlebar->geometry().topRight(), QPoint( width() - 4, titlebar->geometry().bottom() ) ) );
00517            // Titlebar needs no paint event
00518            QApplication::postEvent( this, new QPaintEvent( titlebar->geometry(), FALSE ) );
00519         }
00520     }
00521  */
00522 }
00523 
00524 
00525 void RedmondDeco::captionChange( const QString& )
00526 {
00527     widget()->repaint( titlebar->geometry(), false );
00528 }
00529 
00530 
00531 void RedmondDeco::paintEvent( QPaintEvent* )
00532 {
00533     bool hicolor = QPixmap::defaultDepth() > 8;
00534     int fontoffset = 1;
00535 
00536     QPainter p(widget());
00537 
00538     // Obtain widget bounds.
00539     QRect r(widget()->rect());
00540     int x = r.x();
00541     int y = r.y();
00542     int x2 = r.width()-1;
00543     int y2 = r.height()-1;
00544     int w  = r.width();
00545     int h  = r.height();
00546 
00547     // Draw part of the frame that is the frame color
00548     // ==============================================
00549     QColorGroup g = options()->colorGroup(KDecoration::ColorFrame, isActive());
00550     p.setPen( g.background() );
00551     p.drawLine( x, y, x2-1, y );
00552     p.drawLine( x, y, x, y2-1 );
00553 
00554     // Draw line under title bar
00555     p.drawLine( x+borderWidth, y+titleHeight+borderWidth, x2-borderWidth, y+titleHeight+borderWidth );
00556     // Draw a hidden line that appears during shading
00557     p.drawLine( x+borderWidth, y2-borderWidth, x2-borderWidth, y2-borderWidth );
00558 
00559     // Fill out the border edges
00560     for (int i = 1; i < borderWidth; i++)
00561         p.drawRect( x+i, y+i, w-2*i, h-2*i );
00562 
00563     // Draw highlights and lowlights
00564     p.setPen(g.light());
00565     for (int i = 1; i <= borderWidth/3; i++) {
00566         p.drawLine( x+i, y+i, x2-i-1, y+i);
00567         p.drawLine( x+i, y+i, x+i, y2-i-1);
00568     }
00569 
00570     p.setPen(g.mid().dark(135));
00571     for (int i = 1; i <= borderWidth/3; i++) {
00572         p.drawLine( x2-i, y+i+1, x2-i, y2-i);
00573         p.drawLine( x+i+1, y2-i, x2-i, y2-i);
00574     }
00575 
00576     // Draw black edges
00577     p.setPen( g.dark().dark(155) );
00578     p.drawLine(x2, y, x2, y2);
00579     p.drawLine(x, y2, x2, y2);
00580 
00581     // Draw the title bar.
00582     // ===================
00583     r = titlebar->geometry();
00584     QFontMetrics fm(options()->font(true));
00585 
00586     // Obtain blend colours.
00587     QColor c1 = options()->color(KDecoration::ColorTitleBar, isActive() );
00588     QColor c2 = options()->color(KDecoration::ColorTitleBlend, isActive() );
00589 
00590     // Paint without a buffer if the colours are the same to
00591     // improve performance, and only draw gradients on hicolor displays.
00592     if ((c1 != c2) && hicolor) {
00593         // KS - Add gradient caching if needed at a later stage.
00594 
00595         // Create a disposable pixmap buffer for the title blend
00596         KPixmap* titleBuffer = new KPixmap;
00597         titleBuffer->resize(w-2*borderWidth, titleHeight);
00598 
00599         if (titleBuffer->depth() > 16) {
00600             KPixmapEffect::gradient(*titleBuffer, c1, c2,
00601                                     KPixmapEffect::HorizontalGradient);
00602         } else {
00603             // This enables dithering on 15 and 16bit displays, preventing
00604             // some pretty horrible banding effects
00605             QImage image = KImageEffect::gradient(titleBuffer->size(), c1, c2,
00606                                     KImageEffect::HorizontalGradient);
00607 
00608             titleBuffer->convertFromImage(image, Qt::OrderedDither);
00609         }
00610 
00611         QPainter p2( titleBuffer, this );
00612 
00613         // Since drawing the gradient is (relatively) slow, it is best
00614         // to draw the title text on the pixmap.
00615 
00616         // Reduce the font size and weight for toolwindows.
00617         QFont fnt = options()->font(true);
00618         if ( smallButtons ) {
00619            fnt.setPointSize( fnt.pointSize() - 2 ); // Shrink font by 2 pt.
00620            fnt.setWeight( QFont::Normal );
00621            fontoffset = 0;
00622         }
00623         p2.setFont( fnt );
00624         p2.setPen( options()->color(KDecoration::ColorFont, isActive() ));
00625         p2.drawText( r.x(), fontoffset, r.width()-3, r.height()-1,
00626                      AlignLeft | AlignVCenter, caption() );
00627         p2.end();
00628 
00629         p.drawPixmap( borderWidth, borderWidth, *titleBuffer );
00630 
00631         delete titleBuffer;
00632 
00633     } else {
00634        // Assume lower ended hardware, so don't use buffers.
00635        // Don't draw a gradient either.
00636        p.fillRect( borderWidth, borderWidth, w-2*borderWidth, titleHeight, c1 );
00637 
00638        // Draw the title text.
00639        QFont fnt = options()->font(true);
00640        if ( smallButtons )
00641        {
00642           fnt.setPointSize( fnt.pointSize() - 2 ); // Shrink font by 2 pt.
00643           fnt.setWeight( QFont::Normal );
00644           fontoffset = 0;
00645        }
00646        p.setFont( fnt );
00647        p.setPen(options()->color(KDecoration::ColorFont, isActive() ));
00648        p.drawText(r.x()+4, r.y()+fontoffset, r.width()-3, r.height()-1,
00649                   AlignLeft | AlignVCenter, caption() );
00650    }
00651 
00652 }
00653 
00654 void RedmondDeco::showEvent(QShowEvent *)
00655 {
00656     calcHiddenButtons();
00657     widget()->show();
00658 }
00659 
00660 
00661 void RedmondDeco::mouseDoubleClickEvent( QMouseEvent * e )
00662 {
00663     if (titlebar->geometry().contains( e->pos() ) )
00664        titlebarDblClickOperation();
00665 }
00666 
00667 
00668 void RedmondDeco::maximizeChange(bool m)
00669 {
00670     button[BtnMax]->setBitmap(m ? minmax_bits : maximize_bits);
00671 }
00672 
00673 void RedmondDeco::calcHiddenButtons()
00674 {
00675    // order of hiding is help, maximize, minimize, close, then menu;
00676    int minWidth = (2 + 4 + (providesContextHelp() ? 2 : 1 )) * normalTitleHeight;
00677 
00678    if (lastButtonWidth > width()) { // Shrinking
00679       lastButtonWidth = width();
00680       if (width() < minWidth) {
00681          hiddenItems = true;
00682 
00683          for(int i = RedmondDeco::BtnHelp; i <= RedmondDeco::BtnMenu; i++) {
00684             if (button[i]) {
00685                if ( !button[i]->isHidden() ) {
00686                   button[i]->hide();
00687                }
00688                minWidth -= button[i]->sizeHint().width();
00689                if (width() >= minWidth) {
00690                   return;
00691                }
00692             }
00693          }
00694       }
00695    } else {
00696       if ( hiddenItems ) { // Expanding
00697          lastButtonWidth = width();
00698          int totalSize = normalTitleHeight*3;
00699 
00700          for (int i = RedmondDeco::BtnMenu; i >= RedmondDeco::BtnHelp; i--) {
00701             if (button[i]) {
00702                if (button[i]->sizeHint().width() + totalSize <= width()) {
00703                   totalSize += button[i]->sizeHint().width();
00704                   button[i]->resize(button[i]->sizeHint());
00705                   button[i]->show();
00706                } else {
00707                   return;
00708                }
00709             }
00710          }
00711 
00712          // all items shown now
00713          hiddenItems = false;
00714       } else {
00715          lastButtonWidth = width();
00716       }
00717    }
00718 }
00719 
00720 RedmondDeco::Position RedmondDeco::mousePosition(const QPoint &p) const
00721 {
00722     Position m = PositionCenter;
00723 
00724     const int range = 14 + 3*borderWidth/2;
00725 
00726     if ( ( p.x() > borderWidth && p.x() < width() - borderWidth )
00727          && ( p.y() > borderWidth && p.y() < height() - borderWidth ) )
00728         m = PositionCenter;
00729     else if ( p.y() <= range && p.x() <= range)
00730         m = PositionTopLeft;
00731     else if ( p.y() >= height()-range && p.x() >= width()-range)
00732         m = PositionBottomRight;
00733     else if ( p.y() >= height()-range && p.x() <= range)
00734         m = PositionBottomLeft;
00735     else if ( p.y() <= range && p.x() >= width()-range)
00736         m = PositionTopRight;
00737     else if ( p.y() <= borderWidth )
00738         m = PositionTop;
00739     else if ( p.y() >= height()-borderWidth )
00740         m = PositionBottom;
00741     else if ( p.x() <= borderWidth )
00742         m = PositionLeft;
00743     else if ( p.x() >= width()-borderWidth )
00744         m = PositionRight;
00745     else
00746         m = PositionCenter;
00747 
00748     return m;
00749 }
00750 
00751 void RedmondDeco::borders(int &l, int &r, int &t, int &b) const
00752 {
00753 //  bool reverse = QApplication::reverseLayout();
00754     l = borderWidth;
00755     r = borderWidth;
00756     t = borderWidth + titlebar->geometry().height() + 1;
00757     b = borderWidth;
00758 }
00759 
00760 void RedmondDeco::resize(const QSize &s)
00761 {
00762     widget()->resize(s);
00763 }
00764 
00765 QSize RedmondDeco::minimumSize() const
00766 {
00767     return QSize(50, 50); // what's good for the goose....
00768 }
00769 
00770 void RedmondDeco::activeChange()
00771 {
00772     QPixmap miniIcon = icon().pixmap(QIconSet::Small, QIconSet::Normal);
00773     if (!miniIcon.isNull()) {
00774         button[BtnMenu]->setPixmap(miniIcon);
00775     } else {
00776         button[BtnMenu]->setPixmap(kdelogo);
00777     }
00778 
00779     // Reset the menu button ?
00780     for (int i = BtnHelp; i < BtnCount; i++) {
00781         if (button[i]) button[i]->reset();
00782     }
00783 
00784     widget()->repaint(false);
00785 }
00786 
00787 void RedmondDeco::captionChange()
00788 {
00789     widget()->repaint(titlebar->geometry(), false);
00790 }
00791 
00792 void RedmondDeco::maximizeChange()
00793 {
00794     bool m = (maximizeMode() == MaximizeFull);
00795     button[BtnMax]->setBitmap(m ? minmax_bits : maximize_bits);
00796     QToolTip::remove(button[BtnMax]);
00797     QToolTip::add(button[BtnMax], m ? i18n("Restore") : i18n("Maximize"));
00798 }
00799 
00800 void RedmondDeco::desktopChange()
00801 {
00802 }
00803 
00804 void RedmondDeco::shadeChange()
00805 {
00806 }
00807 
00808 void RedmondDeco::menuButtonPressed()
00809 {
00810     static QTime* t = NULL;
00811     static RedmondDeco* lastClient = NULL;
00812     if (t == NULL) t = new QTime;
00813     bool dbl = ( lastClient == this && t->elapsed() <= QApplication::doubleClickInterval());
00814     lastClient = this;
00815     t->start();
00816     if (!dbl) {
00817         QRect menuRect = button[BtnMenu]->rect();
00818         QPoint menuTop = QPoint(menuRect.topLeft().x()-3,
00819                          menuRect.topLeft().y());
00820         QPoint menuBottom = QPoint(menuRect.bottomRight().x()+3,
00821                          menuRect.bottomRight().y()+4);
00822                 KDecorationFactory* f = factory();
00823         showWindowMenu(QRect(button[BtnMenu]->mapToGlobal(menuTop), 
00824                     button[BtnMenu]->mapToGlobal(menuBottom)));
00825                 if( !f->exists( this )) // 'this' was destroyed
00826                     return;
00827         button[BtnMenu]->setDown(false);
00828     } else {
00829         closeWindow();
00830     }
00831 }
00832 
00833 bool RedmondDeco::eventFilter(QObject *o, QEvent *e)
00834 {
00835     if (o != widget()) { return false; }
00836     switch (e->type()) {
00837         case QEvent::Resize: {
00838             resizeEvent(static_cast<QResizeEvent *>(e));
00839             return true;
00840         }
00841         case QEvent::Paint: {
00842             paintEvent(static_cast<QPaintEvent *>(e));
00843             return true;
00844         }
00845         case QEvent::Show: {
00846             showEvent(static_cast<QShowEvent *>(e));
00847             return true;
00848         }
00849         case QEvent::MouseButtonDblClick: {
00850             mouseDoubleClickEvent(static_cast<QMouseEvent *>(e));
00851             return true;
00852         }
00853         case QEvent::MouseButtonPress: {
00854             processMousePressEvent(static_cast<QMouseEvent *>(e));
00855             return true;
00856         }
00857         default: {
00858             break;
00859         }
00860     }
00861 
00862     return false;
00863 }
00864 
00865 void RedmondDecoFactory::readConfig() {
00866     normalTitleHeight = QFontMetrics(options()->font(true)).height();
00867     toolTitleHeight = QFontMetrics(options()->font(true, true)).height();
00868     switch(options()->preferredBorderSize(this)) {
00869     case BorderLarge:
00870         borderWidth = 8;
00871         if (normalTitleHeight < 20) normalTitleHeight = 20;
00872         if (toolTitleHeight < 20) toolTitleHeight = 20;
00873         break;
00874     case BorderVeryLarge:
00875         borderWidth = 12;
00876         if (normalTitleHeight < 24) normalTitleHeight = 24;
00877         if (toolTitleHeight < 24) toolTitleHeight = 24;
00878         break;
00879     case BorderHuge:
00880         borderWidth = 18;
00881         if (normalTitleHeight < 28) normalTitleHeight = 28;
00882         if (toolTitleHeight < 28) toolTitleHeight = 28;
00883         break;
00884     case BorderVeryHuge:
00885         borderWidth = 27;
00886         if (normalTitleHeight < 33) normalTitleHeight = 33;
00887         if (toolTitleHeight < 33) toolTitleHeight = 33;
00888         break;
00889     case BorderOversized:
00890         borderWidth = 40;
00891         if (normalTitleHeight < 40) normalTitleHeight = 40;
00892         if (toolTitleHeight < 40) toolTitleHeight = 40;
00893         break;
00894     case BorderTiny:
00895     case BorderNormal:
00896     default:
00897         borderWidth = 4;
00898         if (normalTitleHeight < 16) normalTitleHeight = 16;
00899         if (toolTitleHeight < 16) toolTitleHeight = 16;
00900     }
00901 }
00902 
00903 RedmondDecoFactory::RedmondDecoFactory()
00904 {
00905     readConfig();
00906     create_pixmaps();
00907 }
00908 
00909 RedmondDecoFactory::~RedmondDecoFactory()
00910 {
00911     Redmond::delete_pixmaps();
00912 }
00913 
00914 KDecoration *RedmondDecoFactory::createDecoration( KDecorationBridge *b )
00915 {
00916     return new RedmondDeco(b, this);
00917 }
00918 
00919 bool RedmondDecoFactory::reset( unsigned long changed )
00920 {
00921     if ( changed & ( SettingFont | SettingBorder | SettingColors ) ) {
00922         delete_pixmaps();
00923         readConfig();
00924         create_pixmaps();
00925         resetDecorations(changed);
00926         return true;
00927     } else {
00928         resetDecorations(changed);
00929         return false;
00930     }
00931 }
00932 
00933 QValueList< RedmondDecoFactory::BorderSize > RedmondDecoFactory::borderSizes() const
00934 { // the list must be sorted
00935   return QValueList< BorderSize >() << BorderNormal << BorderLarge <<
00936       BorderVeryLarge <<  BorderHuge << BorderVeryHuge << BorderOversized;
00937 }
00938 
00939 }
00940 
00941 extern "C" KDE_EXPORT KDecorationFactory *create_factory()
00942 {
00943     return new Redmond::RedmondDecoFactory();
00944 }
00945 
00946 
00947 #include "redmond.moc"
00948 // vim: ts=4
KDE Logo
This file is part of the documentation for kwin Library Version 3.3.90.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Apr 5 03:59:40 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003