kwin Library API Documentation

laptopclient.cpp

00001 /*
00002  * Laptop KWin Decoration
00003  *
00004  * Port of this decoration to KDE 3.2, accessibility enhancement are
00005  * Copyright (c) 2003 Luciano Montanaro <mikelima@cirulla.net>
00006  */
00007 
00008 #include <kconfig.h> // up here to avoid X11 header conflict :P
00009 #include "laptopclient.h"
00010 #include <qlayout.h>
00011 #include <qdrawutil.h>
00012 #include <kpixmapeffect.h>
00013 #include <kdrawutil.h>
00014 #include <kglobal.h>
00015 #include <kapplication.h>
00016 #include <klocale.h>
00017 #include <qbitmap.h>
00018 #include <qtooltip.h>
00019 #include <qlabel.h>
00020 
00021 // Default button layout
00022 const char default_left[]  = "X";
00023 const char default_right[] = "HSIA";
00024 
00025 namespace Laptop {
00026 
00027 static const unsigned char iconify_bits[] = {
00028     0xff, 0xff, 0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18};
00029 
00030 static const unsigned char close_bits[] = {
00031     0x42, 0xe7, 0x7e, 0x3c, 0x3c, 0x7e, 0xe7, 0x42};
00032 
00033 static const unsigned char maximize_bits[] = {
00034     0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0xff, 0xff };
00035 
00036 static const unsigned char r_minmax_bits[] = {
00037     0x0c, 0x18, 0x33, 0x67, 0xcf, 0x9f, 0x3f, 0x3f};
00038 
00039 static const unsigned char l_minmax_bits[] = {
00040     0x30, 0x18, 0xcc, 0xe6, 0xf3, 0xf9, 0xfc, 0xfc};
00041 
00042 static const unsigned char question_bits[] = {
00043     0x3c, 0x66, 0x60, 0x30, 0x18, 0x00, 0x18, 0x18};
00044 
00045 static const unsigned char unsticky_bits[] = {
00046    0x3c, 0x42, 0x99, 0xbd, 0xbd, 0x99, 0x42, 0x3c};
00047 
00048 static const unsigned char sticky_bits[] = {
00049    0x3c, 0x42, 0x81, 0x81, 0x81, 0x81, 0x42, 0x3c};
00050 
00051 static QPixmap *titlePix;
00052 static KPixmap *aUpperGradient;
00053 static KPixmap *iUpperGradient;
00054 // buttons active, inactive, up, down, and 2 sizes :P
00055 static KPixmap *btnPix1;
00056 static KPixmap *iBtnPix1;
00057 static KPixmap *btnDownPix1;
00058 static KPixmap *iBtnDownPix1;
00059 static KPixmap *btnPix2;
00060 static KPixmap *btnDownPix2;
00061 static KPixmap *iBtnPix2;
00062 static KPixmap *iBtnDownPix2;
00063 static QColor btnForeground;
00064 
00065 static int titleHeight = 14;
00066 static int btnWidth1 = 17;
00067 static int btnWidth2 = 27;
00068 
00069 static int handleSize = 8;  // the resize handle size in pixels
00070 
00071 static bool pixmaps_created = false;
00072 
00073 // =====================================
00074 
00075 extern "C" KDE_EXPORT KDecorationFactory* create_factory()
00076 {
00077     return new Laptop::LaptopClientFactory();
00078 }
00079 
00080 // =====================================
00081 
00082 static inline const KDecorationOptions* options()
00083 {
00084     return KDecoration::options();
00085 }
00086 
00087 static void drawButtonFrame(KPixmap *pix, const QColorGroup &g, bool sunken)
00088 {
00089     QPainter p;
00090     int w = pix->width();
00091     int h = pix->height();
00092     int x2 = w-1;
00093     int y2 = h-1;
00094     p.begin(pix);
00095 
00096     if(sunken){
00097         qDrawShadePanel(&p, 0, 0, w, h, g, true, 2);
00098     }
00099     else{
00100         p.setPen(g.dark());
00101         p.drawRect(0, 0, w-1, h-1);
00102         p.setPen(g.light());
00103         p.drawLine(x2, 0, x2, y2);
00104         p.drawLine(0, y2, x2, y2);
00105         p.drawLine(1, 1, x2-2, 1);
00106         p.drawLine(1, 1, 1, y2-2);
00107         p.end();
00108     }
00109 }
00110 
00111 static void create_pixmaps()
00112 {
00113     if(pixmaps_created)
00114         return;
00115     pixmaps_created = true;
00116 
00117     titleHeight = QFontMetrics(options()->font(true)).height() + 2;
00118     if (titleHeight < handleSize) titleHeight = handleSize;
00119     titleHeight &= ~1; // Make title height even
00120     if (titleHeight < 14) titleHeight = 14;
00121 
00122     btnWidth1 = titleHeight + 3;
00123     btnWidth2 = 3*titleHeight/2 + 6;
00124 
00125     // titlebar
00126     QPainter p;
00127     QPainter maskPainter;
00128     int i, x, y;
00129     titlePix = new QPixmap(33, 12);
00130     QBitmap mask(33, 12);
00131     mask.fill(Qt::color0);
00132 
00133     p.begin(titlePix);
00134     maskPainter.begin(&mask);
00135     maskPainter.setPen(Qt::color1);
00136     for(i=0, y=2; i < 3; ++i, y+=4){
00137         for(x=1; x <= 33; x+=3){
00138             p.setPen(options()->color(KDecoration::ColorTitleBar, true).light(150));
00139             p.drawPoint(x, y);
00140             maskPainter.drawPoint(x, y);
00141             p.setPen(options()->color(KDecoration::ColorTitleBar, true).dark(150));
00142             p.drawPoint(x+1, y+1);
00143             maskPainter.drawPoint(x+1, y+1);
00144         }
00145     }
00146     p.end();
00147     maskPainter.end();
00148     titlePix->setMask(mask);
00149 
00150     if(QPixmap::defaultDepth() > 8){
00151         aUpperGradient = new KPixmap;
00152         aUpperGradient->resize(32, titleHeight+2);
00153         iUpperGradient = new KPixmap;
00154         iUpperGradient->resize(32, titleHeight+2);
00155         QColor bgColor = options()->color(KDecoration::ColorTitleBar, true);
00156         KPixmapEffect::gradient(*aUpperGradient,
00157                                 bgColor.light(120),
00158                                 bgColor.dark(120),
00159                                 KPixmapEffect::VerticalGradient);
00160         bgColor = options()->color(KDecoration::ColorTitleBar, false);
00161         KPixmapEffect::gradient(*iUpperGradient,
00162                                 bgColor.light(120),
00163                                 bgColor.dark(120),
00164                                 KPixmapEffect::VerticalGradient);
00165     }
00166     // buttons (active/inactive, sunken/unsunken, 2 sizes each)
00167     QColorGroup g = options()->colorGroup(KDecoration::ColorButtonBg, true);
00168     QColor c = g.background();
00169     btnPix1 = new KPixmap;
00170     btnPix1->resize(btnWidth1, titleHeight);
00171     btnDownPix1 = new KPixmap;
00172     btnDownPix1->resize(btnWidth1, titleHeight);
00173     btnPix2 = new KPixmap;
00174     btnPix2->resize(btnWidth2, titleHeight);
00175     btnDownPix2 = new KPixmap;
00176     btnDownPix2->resize(btnWidth2, titleHeight);
00177     iBtnPix1 = new KPixmap;
00178     iBtnPix1->resize(btnWidth1, titleHeight);
00179     iBtnDownPix1 = new KPixmap;
00180     iBtnDownPix1->resize(btnWidth1, titleHeight);
00181     iBtnPix2 = new KPixmap;
00182     iBtnPix2->resize(btnWidth2, titleHeight);
00183     iBtnDownPix2 = new KPixmap;
00184     iBtnDownPix2->resize(btnWidth2, titleHeight);
00185     if(QPixmap::defaultDepth() > 8){
00186         KPixmapEffect::gradient(*btnPix1, c.light(120), c.dark(130),
00187                                 KPixmapEffect::DiagonalGradient);
00188         KPixmapEffect::gradient(*btnDownPix1, c.dark(130), c.light(120),
00189                                 KPixmapEffect::DiagonalGradient);
00190         KPixmapEffect::gradient(*btnPix2, c.light(120), c.dark(130),
00191                                 KPixmapEffect::DiagonalGradient);
00192         KPixmapEffect::gradient(*btnDownPix2, c.dark(130), c.light(120),
00193                                 KPixmapEffect::DiagonalGradient);
00194         g = options()->colorGroup(KDecoration::ColorButtonBg, false);
00195         c = g.background();
00196         KPixmapEffect::gradient(*iBtnPix1, c.light(120), c.dark(130),
00197                                 KPixmapEffect::DiagonalGradient);
00198         KPixmapEffect::gradient(*iBtnDownPix1, c.dark(130), c.light(120),
00199                                 KPixmapEffect::DiagonalGradient);
00200         KPixmapEffect::gradient(*iBtnPix2, c.light(120), c.dark(130),
00201                                 KPixmapEffect::DiagonalGradient);
00202         KPixmapEffect::gradient(*iBtnDownPix2, c.dark(130), c.light(120),
00203                                 KPixmapEffect::DiagonalGradient);
00204     }
00205     else{
00206         btnPix1->fill(c.rgb());
00207         btnDownPix1->fill(c.rgb());
00208         btnPix2->fill(c.rgb());
00209         btnDownPix2->fill(c.rgb());
00210         g = options()->colorGroup(KDecoration::ColorButtonBg, false);
00211         c = g.background();
00212         iBtnPix1->fill(c.rgb());
00213         iBtnDownPix1->fill(c.rgb());
00214         iBtnPix2->fill(c.rgb());
00215         iBtnDownPix2->fill(c.rgb());
00216     }
00217     g = options()->colorGroup(KDecoration::ColorButtonBg, true);
00218     c = g.background();
00219     drawButtonFrame(btnPix1, g, false);
00220     drawButtonFrame(btnDownPix1, g, true);
00221     drawButtonFrame(btnPix2, g, false);
00222     drawButtonFrame(btnDownPix2, g, true);
00223     g = options()->colorGroup(KDecoration::ColorButtonBg, false);
00224     c = g.background();
00225     drawButtonFrame(iBtnPix1, g, false);
00226     drawButtonFrame(iBtnDownPix1, g, true);
00227     drawButtonFrame(iBtnPix2, g, false);
00228     drawButtonFrame(iBtnDownPix2, g, true);
00229 
00230     if(qGray(options()->color(KDecoration::ColorButtonBg, true).rgb()) > 128)
00231         btnForeground = Qt::black;
00232     else
00233         btnForeground = Qt::white;
00234 }
00235 
00236 static void delete_pixmaps()
00237 {
00238     delete titlePix;
00239     if(aUpperGradient){
00240         delete aUpperGradient;
00241         delete iUpperGradient;
00242         delete btnPix1;
00243         delete btnDownPix1;
00244         delete iBtnPix1;
00245         delete iBtnDownPix1;
00246         delete btnPix2;
00247         delete btnDownPix2;
00248         delete iBtnPix2;
00249         delete iBtnDownPix2;
00250     }
00251     pixmaps_created = false;
00252 }
00253 
00254 // =====================================
00255 
00256 LaptopButton::LaptopButton(int w, int h, LaptopClient *parent,
00257         const char *name, const unsigned char *bitmap,
00258         const QString& tip, const int realizeBtns)
00259     : QButton(parent->widget(), name), client(parent)
00260 {
00261     realizeButtons = realizeBtns;
00262 
00263     setCursor( arrowCursor );
00264     defaultSize = QSize(w, h);
00265     setFixedHeight(h);
00266     resize(defaultSize);
00267     if(bitmap)
00268         setBitmap(bitmap);
00269 
00270     //setBackgroundMode(QWidget::NoBackground);
00271 
00272     QToolTip::add(this, tip);
00273 }
00274 
00275 QSize LaptopButton::sizeHint() const
00276 {
00277     return(defaultSize);
00278 }
00279 
00280 void LaptopButton::reset()
00281 {
00282     repaint(false);
00283 }
00284 
00285 void LaptopButton::setBitmap(const unsigned char *bitmap)
00286 {
00287     deco = QBitmap(8, 8, bitmap, true);
00288     deco.setMask(deco);
00289     repaint();
00290 }
00291 
00292 void LaptopButton::drawButton(QPainter *p)
00293 {
00294     bool smallBtn = width() == btnWidth1;
00295     if(btnPix1){
00296         if(client->isActive()){
00297             if(isDown())
00298                 p->drawPixmap(0, 0, smallBtn ? *btnDownPix1 : *btnDownPix2);
00299             else
00300                 p->drawPixmap(0, 0, smallBtn ? *btnPix1 : *btnPix2);
00301         }
00302         else{
00303             if(isDown())
00304                 p->drawPixmap(0, 0, smallBtn ? *iBtnDownPix1 : *iBtnDownPix2);
00305             else
00306                 p->drawPixmap(0, 0, smallBtn ? *iBtnPix1 : *iBtnPix2);
00307         }
00308     }
00309     else{
00310         QColorGroup g = options()->colorGroup(KDecoration::ColorButtonBg,
00311                                             client->isActive());
00312         int w = width();
00313         int h = height();
00314         p->fillRect(1, 1, w-2, h-2, isDown() ? g.mid() : g.button());
00315         p->setPen(isDown() ? g.dark() : g.light());
00316         p->drawLine(0, 0, w-1, 0);
00317         p->drawLine(0, 0, 0, w-1);
00318         p->setPen(isDown() ? g.light() : g.dark());
00319         p->drawLine(w-1, 0, w-1, h-1);
00320         p->drawLine(0, h-1, w-1, h-1);
00321     }
00322 
00323     p->setPen(btnForeground);
00324     int xOff = (width()-8)/2;
00325     int yOff = (height()-8)/2;
00326     p->drawPixmap(isDown() ? xOff+1: xOff, isDown() ? yOff+1 : yOff, deco);
00327 }
00328 
00329 // =====================================
00330 
00331 void LaptopClient::reset(unsigned long)
00332 {
00333     for (int i=0; i<BtnTypeCount; i++) {
00334         if (button[i])
00335             button[i]->reset();
00336     }
00337     widget()->repaint();
00338 }
00339 
00340 LaptopClient::LaptopClient(KDecorationBridge *b, KDecorationFactory *f)
00341     : KDecoration(b, f)
00342 {
00343 }
00344 
00345 LaptopClient::~LaptopClient()
00346 {
00347     for (int n=0; n<BtnTypeCount; n++) {
00348         if (button[n]) delete button[n];
00349     }
00350 }
00351 
00352 void LaptopClient::init()
00353 {
00354     createMainWidget(WResizeNoErase | WStaticContents);
00355     widget()->installEventFilter(this);
00356 
00357     lastButtonWidth = 0;
00358     lastBufferWidth = 0;
00359 
00360     // XXX Check how to do this...
00361     // connect(options(), SIGNAL(resetClients()), this, SLOT(slotReset()));
00362     
00363     g = new QGridLayout(widget(), 0, 0, 0);
00364     g->setResizeMode(QLayout::FreeResize);
00365     g->addRowSpacing(0, 3);
00366     g->addRowSpacing(2, 1);
00367     if (isPreview())
00368     g->addWidget(new QLabel(i18n("<center><b>Laptop preview</b></center>"),
00369             widget()), 3, 1);
00370     else
00371     g->addItem( new QSpacerItem( 0, 0 ), 3, 1); // no widget in the middle
00372 
00373     g->setRowStretch(3, 10);
00374     spacer = new QSpacerItem(10, mustDrawHandle() ? handleSize : 4,
00375             QSizePolicy::Expanding, QSizePolicy::Minimum);
00376     g->addItem(spacer, 4, 1);
00377     g->addColSpacing(0, 4);
00378     g->addColSpacing(2, 4);
00379 
00380     int th = titleHeight;
00381     if ( isTool() )
00382     th -= 2;
00383 
00384     hb = new QBoxLayout(0, QBoxLayout::LeftToRight, 0, 0, 0);
00385     hb->setResizeMode(QLayout::FreeResize);
00386     g->addLayout( hb, 1, 1 );
00387     
00388     titlebar = new QSpacerItem(10, th, QSizePolicy::Expanding,
00389                                QSizePolicy::Minimum);    
00390     
00391     // setup titlebar buttons
00392     for (int n=0; n<BtnTypeCount; n++) button[n] = 0;
00393     addButtons(hb, th, options()->customButtonPositions() ? options()->titleButtonsLeft() : QString(default_left));
00394     hb->addSpacing(1);
00395     hb->addItem(titlebar);
00396     hb->addSpacing(1);
00397     addButtons(hb, th, options()->customButtonPositions() ? options()->titleButtonsRight() : QString(default_right));
00398 
00399     hiddenItems = false;
00400     bufferDirty = true;
00401 
00402 }
00403   
00404 void LaptopClient::addButtons(QBoxLayout *hb, int th, const QString& s)
00405 {
00406     const unsigned char *bitmap;
00407     bool m = maximizeMode() == MaximizeFull;
00408     int l_max = options()->titleButtonsLeft().find('A');
00409     QString tip;
00410     
00411     if (s.length() > 0) {
00412         for (unsigned n=0; n < s.length(); n++) {
00413             switch (s[n]) {
00414               case 'S': // Sticky button
00415                   if ((!button[BtnSticky]) && (!isTransient() || !isTool())) {
00416                      button[BtnSticky] = new LaptopButton(btnWidth1, th, this, "sticky",
00417                              NULL, isOnAllDesktops()?i18n("Not on all desktops"):i18n("On all desktops") );
00418                      if(isOnAllDesktops())
00419                          button[BtnSticky]->setBitmap(unsticky_bits);
00420                      else
00421                          button[BtnSticky]->setBitmap(sticky_bits);
00422                      connect( button[BtnSticky], SIGNAL( clicked() ), this, SLOT( toggleOnAllDesktops() ) );
00423                      hb->addWidget( button[BtnSticky]);
00424                   }
00425                   break;
00426 
00427               case 'H': // Help button
00428                   if ((!button[BtnHelp]) && providesContextHelp()) {
00429                       button[BtnHelp] = new LaptopButton(btnWidth1, th, this, "help",
00430                              question_bits, i18n("Help"));
00431                       connect(button[BtnHelp], SIGNAL( clicked() ), this, SLOT( showContextHelp() ) );
00432                       hb->addWidget(button[BtnHelp]);
00433                   }
00434                   break;
00435 
00436               case 'I': // Minimize button
00437                   if ((!button[BtnIconify]) && isMinimizable())  {
00438                       button[BtnIconify] = new LaptopButton(btnWidth2, th, this, "iconify",
00439                                                             iconify_bits, i18n("Minimize"));
00440                       connect( button[BtnIconify], SIGNAL( clicked() ), this, SLOT( minimize() ) );
00441                       hb->addWidget( button[BtnIconify]);
00442                   }
00443                   break;
00444 
00445               case 'A': // Maximize button
00446                   if ((!button[BtnMax]) && isMaximizable()) {
00447                       if (!m) {
00448                          bitmap = maximize_bits;
00449                          tip = i18n("Maximize");
00450                       } else {
00451                           if (options()->customButtonPositions() && (l_max>-1))
00452                               bitmap = l_minmax_bits;
00453                           else 
00454                               bitmap = r_minmax_bits;
00455                           tip = i18n("Restore");
00456                       }
00457                       button[BtnMax] = new LaptopButton(btnWidth2, th, this, "maximize",
00458                                                         bitmap, tip, LeftButton|MidButton|RightButton);
00459                       connect( button[BtnMax], SIGNAL( clicked() ), this, SLOT( slotMaximize() ) );
00460                       hb->addWidget( button[BtnMax]);
00461                   }
00462                   break;
00463 
00464               case 'X': // Close button
00465                   if ((!button[BtnClose]) && isCloseable()) {
00466                       button[BtnClose] = new LaptopButton(btnWidth2, th, this, "close",
00467                                                           close_bits, i18n("Close"));
00468                       connect( button[BtnClose], SIGNAL( clicked() ), this, SLOT( closeWindow() ) );
00469                       hb->addWidget( button[BtnClose]);
00470                   }
00471                   break;
00472             }
00473         }
00474     }
00475 }
00476 
00477 void LaptopClient::slotMaximize()
00478 {
00479     maximize(button[BtnMax]->last_button);
00480 }
00481 
00482 void LaptopClient::resizeEvent(QResizeEvent* e)
00483 {
00484     doShape();
00485     calcHiddenButtons();
00486     if ( widget()->isVisibleToTLW() ) {
00487     int dx = 0;
00488     int dy = 0;
00489     if ( e->oldSize().width() != width() )
00490         dx = 32 + QABS( e->oldSize().width() -  width() );
00491     if ( e->oldSize().height() != height() )
00492         dy = mustDrawHandle() ? handleSize : 4 +
00493         QABS( e->oldSize().height() -  height() );
00494     if ( dy )
00495         widget()->update( 0, height() - dy + 1, width(), dy );
00496     if ( dx ) {
00497         widget()->update( width() - dx + 1, 0, dx, height() );
00498         widget()->update( QRect( QPoint(4,4),
00499             titlebar->geometry().bottomLeft() - QPoint(1,0) ) );
00500         widget()->update( QRect( titlebar->geometry().topRight(),
00501             QPoint( width() - 4, titlebar->geometry().bottom() ) ) );
00502         widget()->update(titlebar->geometry());
00503     }
00504     }
00505 }
00506 
00507 void LaptopClient::captionChange()
00508 {
00509     bufferDirty = true;
00510     widget()->repaint(titlebar->geometry(), false);
00511 }
00512 
00513 void LaptopClient::paintEvent( QPaintEvent* )
00514 {
00515     QPainter p(widget());
00516     QColorGroup g = options()->colorGroup(KDecoration::ColorFrame, isActive());
00517 
00518     QRect r(widget()->rect());
00519     p.setPen(Qt::black);
00520     p.drawRect(r);
00521     // outer frame
00522     p.setPen(g.light());
00523     p.drawLine(r.x()+1, r.y()+1, r.right()-1, r.y()+1);
00524     p.drawLine(r.x()+1, r.y()+1, r.x()+1, r.bottom()-1);
00525     p.setPen(g.dark());
00526     p.drawLine(r.right()-1, r.y()+1, r.right()-1, r.bottom()-1);
00527     p.drawLine(r.x()+1, r.bottom()-1, r.right()-1, r.bottom()-1);
00528 
00529     int th = titleHeight;
00530     int bb = handleSize + 2; // Bottom border
00531     int bs = handleSize - 2; // inner size of bottom border
00532     if (!mustDrawHandle()) {
00533     bb = 6;
00534     bs = 0;
00535     }
00536     if ( isTool() )
00537     th -= 2;
00538 
00539     // inner rect
00540     p.drawRect(r.x() + 3, r.y() + th + 3, r.width() - 6, r.height() - th - bb);
00541 
00542     // handles
00543     if (mustDrawHandle()) {
00544     if (r.width() > 3*handleSize + 20) {
00545         int range = 8 + 3*handleSize/2;
00546         qDrawShadePanel(&p, r.x() + 1, r.bottom() - bs, range, 
00547             handleSize - 2, g, false, 1, &g.brush(QColorGroup::Mid));
00548         qDrawShadePanel(&p, r.x() + range + 1, r.bottom() - bs,
00549             r.width() - 2*range - 2, handleSize - 2, g, false, 1,
00550             isActive() ? &g.brush(QColorGroup::Background) :
00551                  &g.brush(QColorGroup::Mid));
00552         qDrawShadePanel(&p, r.right() - range, r.bottom() - bs,
00553             range, bs, g, false, 1, &g.brush(QColorGroup::Mid));
00554     } else {
00555         qDrawShadePanel(&p, r.x() + 1, r.bottom() - bs,
00556             r.width() - 2, bs, g, false, 1,
00557             isActive() ?  &g.brush(QColorGroup::Background) :
00558                   &g.brush(QColorGroup::Mid));
00559     }
00560     }
00561     r = titlebar->geometry();
00562     r.setRight(r.right()-1);
00563 
00564     if(isActive()){
00565         updateActiveBuffer();
00566         p.drawPixmap(r.x(), r.y(), activeBuffer);
00567     }
00568     else{
00569         if(iUpperGradient)
00570             p.drawTiledPixmap(r.x(), r.y(), r.width(), r.height()-1,
00571                               *iUpperGradient);
00572         else
00573             p.fillRect(r.x(), r.y(), r.width(), r.height()-1,
00574                        options()->color(KDecoration::ColorTitleBar, false));
00575 
00576         p.setFont(options()->font(false, isTool() ));
00577         QFontMetrics fm(options()->font(false));
00578         g = options()->colorGroup(KDecoration::ColorTitleBar, false);
00579         if(iUpperGradient)
00580             p.drawTiledPixmap(r.x()+((r.width()-fm.width(caption()))/2)-4,
00581                               r.y(), fm.width(caption())+8, r.height()-1,
00582                               *iUpperGradient);
00583         else
00584             p.fillRect(r.x()+((r.width()-fm.width(caption()))/2)-4, r.y(),
00585                        fm.width(caption())+8, r.height()-1,
00586                        g.brush(QColorGroup::Background));
00587         p.setPen(g.mid());
00588         p.drawLine(r.x(), r.y(), r.right(), r.y());
00589         p.drawLine(r.x(), r.y(), r.x(), r.bottom());
00590         p.setPen(g.button());
00591         p.drawLine(r.right(), r.y(), r.right(), r.bottom());
00592         p.drawLine(r.x(), r.bottom(), r.right(), r.bottom());
00593         p.setPen(options()->color(KDecoration::ColorFont, false));
00594         p.drawText(r.x(), r.y(), r.width(), r.height()-1,
00595                    AlignCenter, caption() );
00596         g = options()->colorGroup(KDecoration::ColorFrame, true);
00597         p.setPen(g.background());
00598         p.drawPoint(r.x(), r.y());
00599         p.drawPoint(r.right(), r.y());
00600         p.drawLine(r.right()+1, r.y(), r.right()+1, r.bottom());
00601     }
00602 }
00603 
00604 #define QCOORDARRLEN(x) sizeof(x)/(sizeof(QCOORD)*2)
00605 
00606 void LaptopClient::doShape()
00607 {
00608     QRegion mask(QRect(0, 0, width(), height()));
00609     mask -= QRect(0, 0, 1, 1);
00610     mask -= QRect(width()-1, 0, 1, 1);
00611     mask -= QRect(0, height()-1, 1, 1);
00612     mask -= QRect(width()-1, height()-1, 1, 1);
00613 
00614     setMask(mask);
00615 }
00616 
00617 void LaptopClient::showEvent(QShowEvent *)
00618 {
00619     doShape();
00620     widget()->repaint();
00621 }
00622 
00623 void LaptopClient::mouseDoubleClickEvent( QMouseEvent * e )
00624 {
00625     if ( e->button() == LeftButton && titlebar->geometry().contains( e->pos() ) )
00626         titlebarDblClickOperation();
00627 }
00628 
00629 bool LaptopClient::mustDrawHandle() const 
00630 { 
00631     bool drawSmallBorders = !options()->moveResizeMaximizedWindows();
00632     if (drawSmallBorders && (maximizeMode() & MaximizeVertical)) {
00633     return false;
00634     } else {
00635     return isResizable();
00636     }
00637 }
00638 
00639 void LaptopClient::iconChange()
00640 {
00641     // There is no icon support in this theme
00642 }
00643 
00644 void LaptopClient::desktopChange()
00645 {
00646     bool on = isOnAllDesktops();
00647     if(button[BtnSticky]) {
00648         button[BtnSticky]->setBitmap(on ? unsticky_bits : sticky_bits);
00649         QToolTip::remove(button[BtnSticky]);
00650         QToolTip::add(button[BtnSticky],
00651               on ? i18n("Not on all desktops") : i18n("On all desktops"));
00652     }
00653 }
00654 
00655 void LaptopClient::maximizeChange()
00656 {
00657     bool m = (maximizeMode() == MaximizeFull);
00658     int l_max = options()->titleButtonsLeft().find('A');
00659     if (button[BtnMax]) {
00660         if (!m)
00661             button[BtnMax]->setBitmap(maximize_bits); 
00662         else {        
00663             if (options()->customButtonPositions() && (l_max>-1))
00664                 button[BtnMax]->setBitmap(l_minmax_bits);
00665             else
00666                 button[BtnMax]->setBitmap(r_minmax_bits);
00667         }
00668         QToolTip::remove(button[BtnMax]);
00669         QToolTip::add(button[BtnMax], m ? i18n("Restore") : i18n("Maximize"));
00670         spacer->changeSize(10, mustDrawHandle() ? handleSize : 4,
00671             QSizePolicy::Expanding, QSizePolicy::Minimum);
00672         g->activate();
00673         doShape();
00674         widget()->repaint(false);
00675     }
00676 }
00677 
00678 void LaptopClient::activeChange()
00679 {
00680     widget()->repaint(false);
00681     int i;
00682     for(i=0; i<BtnTypeCount; i++){
00683         if(button[i])
00684             button[i]->reset();
00685     }
00686 }
00687 
00688 
00689 void LaptopClient::calcHiddenButtons()
00690 {
00691     // order of hiding is help, sticky, maximize, minimize, close;
00692     // buttons can have
00693     int minWidth = 32 + btnWidth2*3 + (providesContextHelp() ? btnWidth1*2 :
00694                                        btnWidth1);
00695 
00696     if(lastButtonWidth > width()){ // shrinking
00697         lastButtonWidth = width();
00698         if(width() < minWidth){
00699             hiddenItems = true;
00700             int i;
00701             for(i=0; i<BtnTypeCount; i++){
00702                 if(button[i]){
00703                     if( !button[i]->isHidden() ) {
00704                         button[i]->hide();
00705                     }
00706                     minWidth-=button[i]->sizeHint().width();
00707                     if(width() >= minWidth)
00708                         return;
00709                 }
00710             }
00711         }
00712     }
00713     else if(hiddenItems){ // expanding
00714         lastButtonWidth = width();
00715         int i;
00716         int totalSize=32;
00717         for(i=(BtnTypeCount-1); i>=0; --i){
00718             if(button[i]){
00719                 if(button[i]->sizeHint().width() + totalSize <= width()){
00720                     totalSize+=button[i]->sizeHint().width();
00721                     if(button[i]->isHidden() &&
00722                ( !isTransient() || i != BtnSticky ) &&
00723                ( isMinimizable() || i != BtnIconify ) &&
00724                ( isMaximizable() || ( i != BtnIconify && i != BtnSticky && i != BtnMax ) )
00725 
00726                ) {
00727                         button[i]->resize(button[i]->sizeHint());
00728                         button[i]->show();
00729                     }
00730                 }
00731                 else
00732                     return;
00733             }
00734         }
00735         // all items shown now
00736         hiddenItems = false;
00737     }
00738     else
00739         lastButtonWidth = width();
00740 }
00741 
00742 void LaptopClient::updateActiveBuffer( )
00743 {
00744     if( !bufferDirty && (lastBufferWidth == titlebar->geometry().width()))
00745         return;
00746     if ( titlebar->geometry().width() <= 0 || titlebar->geometry().height() <= 0 )
00747     return;
00748     lastBufferWidth = titlebar->geometry().width();
00749     bufferDirty = false;
00750 
00751     activeBuffer.resize(titlebar->geometry().width(),
00752                         titlebar->geometry().height());
00753     QPainter p;
00754     QRect r(0, 0, activeBuffer.width()-1, activeBuffer.height());
00755     p.begin(&activeBuffer);
00756     if(aUpperGradient){
00757         p.drawTiledPixmap(r, *aUpperGradient);
00758     }
00759     else{
00760         p.fillRect(r, options()->color(KDecoration::ColorTitleBar, true));
00761     }
00762     if(titlePix)
00763         p.drawTiledPixmap(r, *titlePix);
00764 
00765     p.setFont(options()->font(true, isTool() ));
00766     QFontMetrics fm(options()->font(true));
00767     QColorGroup g = options()->colorGroup(KDecoration::ColorTitleBar, true);
00768     if(aUpperGradient)
00769         p.drawTiledPixmap(r.x()+((r.width()-fm.width(caption()))/2)-4,
00770                           r.y(), fm.width(caption())+8, r.height()-1,
00771                           *aUpperGradient);
00772     else
00773         p.fillRect(r.x()+((r.width()-fm.width(caption()))/2)-4, 0,
00774                    fm.width(caption())+8, r.height(),
00775                    g.brush(QColorGroup::Background));
00776     p.setPen(g.mid());
00777     p.drawLine(r.x(), r.y(), r.right(), r.y());
00778     p.drawLine(r.x(), r.y(), r.x(), r.bottom());
00779     p.setPen(g.button());
00780     p.drawLine(r.right(), r.y(), r.right(), r.bottom());
00781     p.drawLine(r.x(), r.bottom(), r.right(), r.bottom());
00782     p.setPen(options()->color(KDecoration::ColorFont, true));
00783     p.drawText(r.x(), r.y(), r.width(), r.height()-1,
00784                AlignCenter, caption() );
00785     g = options()->colorGroup(KDecoration::ColorFrame, true);
00786     p.setPen(g.background());
00787     p.drawPoint(r.x(), r.y());
00788     p.drawPoint(r.right(), r.y());
00789     p.drawLine(r.right()+1, r.y(), r.right()+1, r.bottom());
00790     p.end();
00791 }
00792 
00793 LaptopClient::Position LaptopClient::mousePosition(const QPoint & p) const
00794 {
00795   Position m = PositionCenter;
00796   int range = 8 + 3*handleSize/2;
00797 
00798   if (p.y() < (height() - handleSize + 1))
00799     m = KDecoration::mousePosition(p);
00800 
00801   else {
00802     if (p.x() >= (width() - range))
00803       m = PositionBottomRight;
00804     else if (p.x() <= range)
00805       m = PositionBottomLeft;
00806     else
00807       m = PositionBottom;
00808   }
00809 
00810   return m;
00811 }
00812 
00813 void LaptopClient::borders(int &left, int &right, int &top, int &bottom) const
00814 {
00815     left = right = 4;
00816     top = titleHeight + 4;
00817     bottom = mustDrawHandle() ? handleSize : 4;
00818 }
00819 
00820 void LaptopClient::shadeChange()
00821 {
00822 }
00823 
00824 QSize LaptopClient::minimumSize() const
00825 {
00826     return QSize(4 * handleSize, handleSize);
00827 }
00828 
00829 void LaptopClient::resize(const QSize& s)
00830 {
00831     widget()->resize(s);
00832     widget()->repaint(); //there is some strange wrong repaint of the frame without
00833 }
00834 
00835 static const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask |
00836     NET::DesktopMask | NET::DockMask | NET::ToolbarMask | NET::MenuMask |
00837     NET::DialogMask | NET::OverrideMask | NET::TopMenuMask |
00838     NET::UtilityMask | NET::SplashMask;
00839 
00840 bool LaptopClient::isTransient() const
00841 {
00842     NET::WindowType type = windowType(SUPPORTED_WINDOW_TYPES_MASK);
00843     return type == NET::Dialog;
00844 }
00845 
00846 bool LaptopClient::isTool() const
00847 {
00848     NET::WindowType type = windowType(SUPPORTED_WINDOW_TYPES_MASK);
00849     return type == NET::Toolbar || type == NET::Utility || type == NET::Menu;
00850 }
00851 
00852 bool LaptopClient::eventFilter(QObject *o, QEvent *e)
00853 {
00854     if (o != widget())
00855     return false;
00856     switch (e->type()) {
00857     case QEvent::Resize:
00858     resizeEvent(static_cast< QResizeEvent* >( e ));
00859     return true;
00860     case QEvent::Paint:
00861     paintEvent(static_cast< QPaintEvent* >( e ));
00862     return true;
00863     case QEvent::MouseButtonDblClick:
00864     mouseDoubleClickEvent(static_cast< QMouseEvent* >( e ));
00865     return true;
00866     case QEvent::MouseButtonPress:
00867     processMousePressEvent(static_cast< QMouseEvent* >( e ));
00868     return true;
00869     case QEvent::Show:
00870     showEvent(static_cast< QShowEvent* >( e ));
00871     return true;
00872     default:
00873     break;
00874     }
00875     return false;
00876 }
00877 
00878 // =====================================
00879 
00880 LaptopClientFactory::LaptopClientFactory()
00881 {
00882     create_pixmaps();
00883 }
00884 
00885 LaptopClientFactory::~LaptopClientFactory()
00886 {
00887     delete_pixmaps();
00888 }
00889 
00890 KDecoration *LaptopClientFactory::createDecoration(KDecorationBridge *b)
00891 {
00892     findPreferredHandleSize();
00893     return new Laptop::LaptopClient(b, this);
00894 }
00895 
00896 bool LaptopClientFactory::reset(unsigned long /*changed*/)
00897 {
00898     findPreferredHandleSize();
00899 
00900     // TODO Do not recreate decorations if it is not needed. Look at
00901     // ModernSystem for how to do that
00902     Laptop::delete_pixmaps();
00903     Laptop::create_pixmaps();
00904     // For now just return true.
00905     return true;
00906 }
00907 
00908 bool LaptopClientFactory::supports( Ability ability )
00909 {
00910     switch( ability )
00911     {
00912         case AbilityAnnounceButtons:
00913         case AbilityButtonOnAllDesktops:
00914         case AbilityButtonHelp:
00915         case AbilityButtonMinimize:
00916         case AbilityButtonMaximize:
00917         case AbilityButtonClose:
00918             return true;
00919         default:
00920             return false;
00921     };
00922 }
00923 
00924 QValueList< LaptopClientFactory::BorderSize >
00925 LaptopClientFactory::borderSizes() const
00926 {
00927     // the list must be sorted
00928     return QValueList< BorderSize >() << BorderNormal << BorderLarge <<
00929     BorderVeryLarge <<  BorderHuge << BorderVeryHuge << BorderOversized;
00930 }
00931 
00932 void LaptopClientFactory::findPreferredHandleSize()
00933 {
00934     switch (options()->preferredBorderSize(this)) {
00935     case KDecoration::BorderLarge:
00936     handleSize = 11;
00937     break;
00938     case KDecoration::BorderVeryLarge:
00939     handleSize = 16;
00940     break;
00941     case KDecoration::BorderHuge:
00942     handleSize = 24;
00943     break;
00944     case KDecoration::BorderVeryHuge:
00945     handleSize = 32;
00946     break;
00947     case KDecoration::BorderOversized:
00948     handleSize = 40;
00949     break;
00950     case KDecoration::BorderTiny:
00951     case KDecoration::BorderNormal:
00952     default:
00953     handleSize = 8;
00954     }
00955 }
00956 
00957 } // Laptop namespace
00958 
00959 #include "laptopclient.moc"
00960 
00961 // vim: sw=4
KDE Logo
This file is part of the documentation for kwin Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Jun 13 19:28:01 2006 by doxygen 1.4.3 written by Dimitri van Heesch, © 1997-2003