kwin Library API Documentation

redmond.cpp

00001 /* 00002 * $Id: redmond.cpp,v 1.23.2.1 2004/01/21 19:16:12 giessl Exp $ 00003 * 00004 * Redmond KWin client 00005 * 00006 * Copyright 2001 00007 * Karol Szwed <gallium@kde.org> 00008 * http://gallium.n3.net/ 00009 * 00010 * Based on the default KWin client. 00011 * 00012 * Updated to support toolwindows 3/2001 (KS) 00013 * 00014 */ 00015 00016 #include "redmond.h" 00017 00018 #include <qlayout.h> 00019 #include <qdrawutil.h> 00020 #include <qdatetime.h> 00021 #include <kpixmapeffect.h> 00022 #include <kimageeffect.h> 00023 #include <kdrawutil.h> 00024 #include <klocale.h> 00025 00026 #include <qbitmap.h> 00027 #include <qtooltip.h> 00028 #include <qimage.h> 00029 #include <qlabel.h> 00030 #include <qapplication.h> 00031 00032 namespace Redmond { 00033 00034 static const char *kdelogo[] = { 00035 /* columns rows colors chars-per-pixel */ 00036 "16 16 8 1", 00037 " c None", 00038 ". c #000000", 00039 "+ c #A0A0A4", 00040 "@ c #FFFFFF", 00041 "# c #585858", 00042 "$ c #C0C0C0", 00043 "% c #808080", 00044 "& c #DCDCDC", 00045 " ", 00046 " .. .. ", 00047 " .+@. .@#. ", 00048 " .@@@. .@@@# ", 00049 " .@@@..$@@$. ", 00050 " .@@@.@@@$. ", 00051 " .@@@%@@$. ", 00052 " .@@@&@@. ", 00053 " .@@@@@@. ", 00054 " .@@@$@@&. ", 00055 " .@@@.@@@. ", 00056 " .@@@.+@@@. ", 00057 " .@@@..$@@&. ", 00058 " .@@%. .@@@. ", 00059 " .... ... ", 00060 " "}; 00061 00062 static unsigned char iconify_bits[] = { 00063 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 00064 0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00}; 00065 00066 static unsigned char close_bits[] = { 00067 0x00, 0x00, 0x86, 0x01, 0xcc, 0x00, 0x78, 0x00, 0x30, 0x00, 0x78, 0x00, 00068 0xcc, 0x00, 0x86, 0x01, 0x00, 0x00, 0x00, 0x00}; 00069 00070 static unsigned char maximize_bits[] = { 00071 0xff, 0x01, 0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 00072 0x01, 0x01, 0x01, 0x01, 0xff, 0x01, 0x00, 0x00}; 00073 00074 static unsigned char minmax_bits[] = { 00075 0xfc, 0x00, 0xfc, 0x00, 0x84, 0x00, 0xbf, 0x00, 0xbf, 0x00, 0xe1, 0x00, 00076 0x21, 0x00, 0x21, 0x00, 0x3f, 0x00, 0x00, 0x00}; 00077 00078 static unsigned char question_bits[] = { 00079 0x00, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 00080 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00}; 00081 00082 00083 // Up / Down titlebar button images 00084 static KPixmap *btnPix1; 00085 static KPixmap *iBtnPix1; 00086 static KPixmap *btnDownPix1; 00087 static KPixmap *iBtnDownPix1; 00088 00089 static KPixmap *miniBtnPix1; 00090 static KPixmap *iMiniBtnPix1; 00091 static KPixmap *miniBtnDownPix1; 00092 static KPixmap *iMiniBtnDownPix1; 00093 00094 static QPixmap *defaultMenuPix; 00095 static QColor *btnForeground; 00096 static bool pixmaps_created = false; 00097 00098 static int toolTitleHeight; 00099 static int normalTitleHeight; 00100 static int borderWidth; 00101 00102 static inline const KDecorationOptions *options() 00103 { 00104 return KDecoration::options(); 00105 } 00106 00107 static void drawButtonFrame( KPixmap *pix, const QColorGroup &g, bool sunken ) 00108 { 00109 QPainter p; 00110 int x2 = pix->width() - 1; 00111 int y2 = pix->height() - 1; 00112 p.begin(pix); 00113 00114 // titlebar button frame 00115 p.setPen( sunken ? g.dark().dark(155) : g.light()); 00116 p.drawLine(0, 0, x2-1, 0); 00117 p.drawLine(0, 0, 0, y2-1); 00118 00119 if (sunken) 00120 { 00121 p.setPen( g.mid().dark(135) ); 00122 p.drawLine(1, 1, x2-2, 1); 00123 p.drawLine(1, 1, 1, y2-2); 00124 } 00125 00126 p.setPen( sunken ? g.light() : g.mid().dark(135)); 00127 p.drawLine(1, y2-1, x2-1, y2-1); 00128 p.drawLine(x2-1, 1, x2-1, y2-1); 00129 00130 p.setPen( sunken ? g.light() : g.dark().dark(155)); 00131 p.drawLine(0, y2, x2, y2); 00132 p.drawLine(x2, 0, x2, y2); 00133 } 00134 00135 00136 static void create_pixmaps () 00137 { 00138 if (pixmaps_created) 00139 return; 00140 00141 pixmaps_created = true; 00142 00143 bool highcolor = QPixmap::defaultDepth() > 8; 00144 00145 btnPix1 = new KPixmap; 00146 btnDownPix1 = new KPixmap; 00147 iBtnPix1 = new KPixmap; 00148 iBtnDownPix1 = new KPixmap; 00149 miniBtnPix1 = new KPixmap; 00150 miniBtnDownPix1 = new KPixmap; 00151 iMiniBtnPix1 = new KPixmap; 00152 iMiniBtnDownPix1 = new KPixmap; 00153 defaultMenuPix = new QPixmap(kdelogo); 00154 00155 // buttons (active/inactive, sunken/unsunken) 00156 QColorGroup g = options()->colorGroup(KDecoration::ColorButtonBg, true); 00157 QColor c = g.background(); 00158 btnPix1->resize(normalTitleHeight, normalTitleHeight-2); 00159 btnDownPix1->resize(normalTitleHeight, normalTitleHeight-2); 00160 iBtnPix1->resize(normalTitleHeight, normalTitleHeight-2); 00161 iBtnDownPix1->resize(normalTitleHeight, normalTitleHeight-2); 00162 00163 miniBtnPix1->resize(toolTitleHeight, toolTitleHeight); 00164 miniBtnDownPix1->resize(toolTitleHeight, toolTitleHeight); 00165 iMiniBtnPix1->resize(toolTitleHeight, toolTitleHeight); 00166 iMiniBtnDownPix1->resize(toolTitleHeight, toolTitleHeight); 00167 00168 if (highcolor && false) { 00169 KPixmapEffect::gradient(*btnPix1, c.light(130), c.dark(130), 00170 KPixmapEffect::VerticalGradient); 00171 KPixmapEffect::gradient(*btnDownPix1, c.dark(130), c.light(130), 00172 KPixmapEffect::VerticalGradient); 00173 00174 KPixmapEffect::gradient(*miniBtnPix1, c.light(130), c.dark(130), 00175 KPixmapEffect::VerticalGradient); 00176 KPixmapEffect::gradient(*miniBtnDownPix1, c.dark(130), c.light(130), 00177 KPixmapEffect::VerticalGradient); 00178 00179 g = options()->colorGroup(KDecoration::ColorButtonBg, false); 00180 c = g.background(); 00181 KPixmapEffect::gradient(*iBtnPix1, c.light(130), c.dark(130), 00182 KPixmapEffect::VerticalGradient); 00183 KPixmapEffect::gradient(*iBtnDownPix1, c.dark(130), c.light(130), 00184 KPixmapEffect::VerticalGradient); 00185 KPixmapEffect::gradient(*iMiniBtnPix1, c.light(130), c.dark(130), 00186 KPixmapEffect::VerticalGradient); 00187 KPixmapEffect::gradient(*iMiniBtnDownPix1, c.dark(130), c.light(130), 00188 KPixmapEffect::VerticalGradient); 00189 } else { 00190 btnPix1->fill(c.rgb()); 00191 btnDownPix1->fill(c.rgb()); 00192 miniBtnPix1->fill(c.rgb()); 00193 miniBtnDownPix1->fill(c.rgb()); 00194 00195 g = options()->colorGroup(KDecoration::ColorButtonBg, false); 00196 c = g.background(); 00197 iBtnPix1->fill(c.rgb()); 00198 iBtnDownPix1->fill(c.rgb()); 00199 iMiniBtnPix1->fill(c.rgb()); 00200 iMiniBtnDownPix1->fill(c.rgb()); 00201 } 00202 00203 g = options()->colorGroup(KDecoration::ColorButtonBg, true); 00204 drawButtonFrame(btnPix1, g, false); 00205 drawButtonFrame(btnDownPix1, g, true); 00206 drawButtonFrame(miniBtnPix1, g, false); 00207 drawButtonFrame(miniBtnDownPix1, g, true); 00208 00209 g = options()->colorGroup(KDecoration::ColorButtonBg, false); 00210 drawButtonFrame(iBtnPix1, g, false); 00211 drawButtonFrame(iBtnDownPix1, g, true); 00212 drawButtonFrame(iMiniBtnPix1, g, false); 00213 drawButtonFrame(iMiniBtnDownPix1, g, true); 00214 00215 // Make sure button pixmaps contrast with the current colour scheme. 00216 if (qGray(options()->color(KDecoration::ColorButtonBg, true).rgb()) > 127) 00217 btnForeground = new QColor(Qt::black); 00218 else 00219 btnForeground = new QColor(Qt::white); 00220 } 00221 00222 void delete_pixmaps() 00223 { 00224 delete btnPix1; 00225 delete btnDownPix1; 00226 delete iBtnPix1; 00227 delete iBtnDownPix1; 00228 delete miniBtnPix1; 00229 delete miniBtnDownPix1; 00230 delete iMiniBtnPix1; 00231 delete iMiniBtnDownPix1; 00232 delete defaultMenuPix; 00233 delete btnForeground; 00234 pixmaps_created = false; 00235 } 00236 00237 00238 RedmondButton::RedmondButton(RedmondDeco *parent, const char *name, 00239 const unsigned char *bitmap, bool menuButton, bool isMini, int size, const QString& tip, const int realizeBtns) 00240 : QButton(parent->widget(), name) 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]->last_button == MidButton ) 00489 maximize( maximizeMode() ^ MaximizeVertical ); 00490 else if ( button[BtnMax]->last_button == RightButton ) 00491 maximize( maximizeMode() ^ MaximizeHorizontal ); 00492 else 00493 maximize( maximizeMode() == MaximizeFull ? MaximizeRestore : MaximizeFull ); 00494 } 00495 00496 00497 void RedmondDeco::resizeEvent(QResizeEvent *) 00498 { 00499 calcHiddenButtons(); 00500 /* 00501 if (isVisibleToTLW()) { 00502 update(rect()); 00503 int dx = 0; 00504 int dy = 0; 00505 00506 if ( e->oldSize().width() != width() ) 00507 dx = 32 + QABS( e->oldSize().width() - width() ); 00508 00509 if ( e->oldSize().height() != height() ) 00510 dy = 8 + QABS( e->oldSize().height() - height() ); 00511 00512 if ( dy ) 00513 update( 0, height() - dy + 1, width(), dy ); 00514 00515 if ( dx ) 00516 { 00517 update( width() - dx + 1, 0, dx, height() ); 00518 update( QRect( QPoint(4,4), titlebar->geometry().bottomLeft() - QPoint(1,0) ) ); 00519 update( QRect( titlebar->geometry().topRight(), QPoint( width() - 4, titlebar->geometry().bottom() ) ) ); 00520 // Titlebar needs no paint event 00521 QApplication::postEvent( this, new QPaintEvent( titlebar->geometry(), FALSE ) ); 00522 } 00523 } 00524 */ 00525 } 00526 00527 00528 void RedmondDeco::captionChange( const QString& ) 00529 { 00530 widget()->repaint( titlebar->geometry(), false ); 00531 } 00532 00533 00534 void RedmondDeco::paintEvent( QPaintEvent* ) 00535 { 00536 bool hicolor = QPixmap::defaultDepth() > 8; 00537 int fontoffset = 1; 00538 00539 QPainter p(widget()); 00540 00541 // Obtain widget bounds. 00542 QRect r(widget()->rect()); 00543 int x = r.x(); 00544 int y = r.y(); 00545 int x2 = r.width()-1; 00546 int y2 = r.height()-1; 00547 int w = r.width(); 00548 int h = r.height(); 00549 00550 // Draw part of the frame that is the frame color 00551 // ============================================== 00552 QColorGroup g = options()->colorGroup(KDecoration::ColorFrame, isActive()); 00553 p.setPen( g.background() ); 00554 p.drawLine( x, y, x2-1, y ); 00555 p.drawLine( x, y, x, y2-1 ); 00556 00557 // Draw line under title bar 00558 p.drawLine( x+borderWidth, y+titleHeight+borderWidth, x2-borderWidth, y+titleHeight+borderWidth ); 00559 // Draw a hidden line that appears during shading 00560 p.drawLine( x+borderWidth, y2-borderWidth, x2-borderWidth, y2-borderWidth ); 00561 00562 // Fill out the border edges 00563 for (int i = 1; i < borderWidth; i++) 00564 p.drawRect( x+i, y+i, w-2*i, h-2*i ); 00565 00566 // Draw highlights and lowlights 00567 p.setPen(g.light()); 00568 for (int i = 1; i <= borderWidth/3; i++) { 00569 p.drawLine( x+i, y+i, x2-i-1, y+i); 00570 p.drawLine( x+i, y+i, x+i, y2-i-1); 00571 } 00572 00573 p.setPen(g.mid().dark(135)); 00574 for (int i = 1; i <= borderWidth/3; i++) { 00575 p.drawLine( x2-i, y+i+1, x2-i, y2-i); 00576 p.drawLine( x+i+1, y2-i, x2-i, y2-i); 00577 } 00578 00579 // Draw black edges 00580 p.setPen( g.dark().dark(155) ); 00581 p.drawLine(x2, y, x2, y2); 00582 p.drawLine(x, y2, x2, y2); 00583 00584 // Draw the title bar. 00585 // =================== 00586 r = titlebar->geometry(); 00587 QFontMetrics fm(options()->font(true)); 00588 00589 // Obtain blend colours. 00590 QColor c1 = options()->color(KDecoration::ColorTitleBar, isActive() ); 00591 QColor c2 = options()->color(KDecoration::ColorTitleBlend, isActive() ); 00592 00593 // Paint without a buffer if the colours are the same to 00594 // improve performance, and only draw gradients on hicolor displays. 00595 if ((c1 != c2) && hicolor) { 00596 // KS - Add gradient caching if needed at a later stage. 00597 00598 // Create a disposable pixmap buffer for the title blend 00599 KPixmap* titleBuffer = new KPixmap; 00600 titleBuffer->resize(w-2*borderWidth, titleHeight); 00601 00602 if (titleBuffer->depth() > 16) { 00603 KPixmapEffect::gradient(*titleBuffer, c1, c2, 00604 KPixmapEffect::HorizontalGradient); 00605 } else { 00606 // This enables dithering on 15 and 16bit displays, preventing 00607 // some pretty horrible banding effects 00608 QImage image = KImageEffect::gradient(titleBuffer->size(), c1, c2, 00609 KImageEffect::HorizontalGradient); 00610 00611 titleBuffer->convertFromImage(image, Qt::OrderedDither); 00612 } 00613 00614 QPainter p2( titleBuffer, this ); 00615 00616 // Since drawing the gradient is (relatively) slow, it is best 00617 // to draw the title text on the pixmap. 00618 00619 // Reduce the font size and weight for toolwindows. 00620 QFont fnt = options()->font(true); 00621 if ( smallButtons ) { 00622 fnt.setPointSize( fnt.pointSize() - 2 ); // Shrink font by 2 pt. 00623 fnt.setWeight( QFont::Normal ); 00624 fontoffset = 0; 00625 } 00626 p2.setFont( fnt ); 00627 p2.setPen( options()->color(KDecoration::ColorFont, isActive() )); 00628 p2.drawText( r.x(), fontoffset, r.width()-3, r.height()-1, 00629 AlignLeft | AlignVCenter, caption() ); 00630 p2.end(); 00631 00632 p.drawPixmap( borderWidth, borderWidth, *titleBuffer ); 00633 00634 delete titleBuffer; 00635 00636 } else { 00637 // Assume lower ended hardware, so don't use buffers. 00638 // Don't draw a gradient either. 00639 p.fillRect( borderWidth, borderWidth, w-2*borderWidth, titleHeight, c1 ); 00640 00641 // Draw the title text. 00642 QFont fnt = options()->font(true); 00643 if ( smallButtons ) 00644 { 00645 fnt.setPointSize( fnt.pointSize() - 2 ); // Shrink font by 2 pt. 00646 fnt.setWeight( QFont::Normal ); 00647 fontoffset = 0; 00648 } 00649 p.setFont( fnt ); 00650 p.setPen(options()->color(KDecoration::ColorFont, isActive() )); 00651 p.drawText(r.x()+4, r.y()+fontoffset, r.width()-3, r.height()-1, 00652 AlignLeft | AlignVCenter, caption() ); 00653 } 00654 00655 } 00656 00657 void RedmondDeco::showEvent(QShowEvent *) 00658 { 00659 calcHiddenButtons(); 00660 widget()->show(); 00661 } 00662 00663 00664 void RedmondDeco::mouseDoubleClickEvent( QMouseEvent * e ) 00665 { 00666 if (titlebar->geometry().contains( e->pos() ) ) 00667 titlebarDblClickOperation(); 00668 } 00669 00670 00671 void RedmondDeco::maximizeChange(bool m) 00672 { 00673 button[BtnMax]->setBitmap(m ? minmax_bits : maximize_bits); 00674 } 00675 00676 void RedmondDeco::calcHiddenButtons() 00677 { 00678 // order of hiding is help, maximize, minimize, close, then menu; 00679 int minWidth = (2 + 4 + (providesContextHelp() ? 2 : 1 )) * normalTitleHeight; 00680 00681 if (lastButtonWidth > width()) { // Shrinking 00682 lastButtonWidth = width(); 00683 if (width() < minWidth) { 00684 hiddenItems = true; 00685 00686 for(int i = RedmondDeco::BtnHelp; i <= RedmondDeco::BtnMenu; i++) { 00687 if (button[i]) { 00688 if ( !button[i]->isHidden() ) { 00689 button[i]->hide(); 00690 } 00691 minWidth -= button[i]->sizeHint().width(); 00692 if (width() >= minWidth) { 00693 return; 00694 } 00695 } 00696 } 00697 } 00698 } else { 00699 if ( hiddenItems ) { // Expanding 00700 lastButtonWidth = width(); 00701 int totalSize = normalTitleHeight*3; 00702 00703 for (int i = RedmondDeco::BtnMenu; i >= RedmondDeco::BtnHelp; i--) { 00704 if (button[i]) { 00705 if (button[i]->sizeHint().width() + totalSize <= width()) { 00706 totalSize += button[i]->sizeHint().width(); 00707 button[i]->resize(button[i]->sizeHint()); 00708 button[i]->show(); 00709 } else { 00710 return; 00711 } 00712 } 00713 } 00714 00715 // all items shown now 00716 hiddenItems = false; 00717 } else { 00718 lastButtonWidth = width(); 00719 } 00720 } 00721 } 00722 00723 RedmondDeco::Position RedmondDeco::mousePosition(const QPoint &p) const 00724 { 00725 Position m = PositionCenter; 00726 00727 const int range = 14 + 3*borderWidth/2; 00728 00729 if ( ( p.x() > borderWidth && p.x() < width() - borderWidth ) 00730 && ( p.y() > borderWidth && p.y() < height() - borderWidth ) ) 00731 m = PositionCenter; 00732 else if ( p.y() <= range && p.x() <= range) 00733 m = PositionTopLeft; 00734 else if ( p.y() >= height()-range && p.x() >= width()-range) 00735 m = PositionBottomRight; 00736 else if ( p.y() >= height()-range && p.x() <= range) 00737 m = PositionBottomLeft; 00738 else if ( p.y() <= range && p.x() >= width()-range) 00739 m = PositionTopRight; 00740 else if ( p.y() <= borderWidth ) 00741 m = PositionTop; 00742 else if ( p.y() >= height()-borderWidth ) 00743 m = PositionBottom; 00744 else if ( p.x() <= borderWidth ) 00745 m = PositionLeft; 00746 else if ( p.x() >= width()-borderWidth ) 00747 m = PositionRight; 00748 else 00749 m = PositionCenter; 00750 00751 return m; 00752 } 00753 00754 void RedmondDeco::borders(int &l, int &r, int &t, int &b) const 00755 { 00756 // bool reverse = QApplication::reverseLayout(); 00757 l = borderWidth; 00758 r = borderWidth; 00759 t = borderWidth + titlebar->geometry().height() + 1; 00760 b = borderWidth; 00761 } 00762 00763 void RedmondDeco::resize(const QSize &s) 00764 { 00765 widget()->resize(s); 00766 } 00767 00768 QSize RedmondDeco::minimumSize() const 00769 { 00770 return QSize(50, 50); // what's good for the goose.... 00771 } 00772 00773 void RedmondDeco::activeChange() 00774 { 00775 QPixmap miniIcon = icon().pixmap(QIconSet::Small, QIconSet::Normal); 00776 if (!miniIcon.isNull()) { 00777 button[BtnMenu]->setPixmap(miniIcon); 00778 } else { 00779 button[BtnMenu]->setPixmap(kdelogo); 00780 } 00781 00782 // Reset the menu button ? 00783 for (int i = BtnHelp; i < BtnCount; i++) { 00784 if (button[i]) button[i]->reset(); 00785 } 00786 00787 widget()->repaint(false); 00788 } 00789 00790 void RedmondDeco::captionChange() 00791 { 00792 widget()->repaint(titlebar->geometry(), false); 00793 } 00794 00795 void RedmondDeco::maximizeChange() 00796 { 00797 bool m = (maximizeMode() == MaximizeFull); 00798 button[BtnMax]->setBitmap(m ? minmax_bits : maximize_bits); 00799 QToolTip::remove(button[BtnMax]); 00800 QToolTip::add(button[BtnMax], m ? i18n("Restore") : i18n("Maximize")); 00801 } 00802 00803 void RedmondDeco::desktopChange() 00804 { 00805 } 00806 00807 void RedmondDeco::shadeChange() 00808 { 00809 } 00810 00811 void RedmondDeco::menuButtonPressed() 00812 { 00813 static QTime* t = NULL; 00814 static RedmondDeco* lastClient = NULL; 00815 if (t == NULL) t = new QTime; 00816 bool dbl = ( lastClient == this && t->elapsed() <= QApplication::doubleClickInterval()); 00817 lastClient = this; 00818 t->start(); 00819 if (!dbl) { 00820 QPoint menupoint(button[BtnMenu]->rect().bottomLeft().x()-3, 00821 button[BtnMenu]->rect().bottomLeft().y()+4); 00822 KDecorationFactory* f = factory(); 00823 showWindowMenu(button[BtnMenu]->mapToGlobal(menupoint)); 00824 if( !f->exists( this )) // 'this' was destroyed 00825 return; 00826 button[BtnMenu]->setDown(false); 00827 } else { 00828 closeWindow(); 00829 } 00830 } 00831 00832 bool RedmondDeco::eventFilter(QObject *o, QEvent *e) 00833 { 00834 if (o != widget()) { return false; } 00835 switch (e->type()) { 00836 case QEvent::Resize: { 00837 resizeEvent(static_cast<QResizeEvent *>(e)); 00838 return true; 00839 } 00840 case QEvent::Paint: { 00841 paintEvent(static_cast<QPaintEvent *>(e)); 00842 return true; 00843 } 00844 case QEvent::Show: { 00845 showEvent(static_cast<QShowEvent *>(e)); 00846 return true; 00847 } 00848 case QEvent::MouseButtonDblClick: { 00849 mouseDoubleClickEvent(static_cast<QMouseEvent *>(e)); 00850 return true; 00851 } 00852 case QEvent::MouseButtonPress: { 00853 processMousePressEvent(static_cast<QMouseEvent *>(e)); 00854 return true; 00855 } 00856 default: { 00857 break; 00858 } 00859 } 00860 00861 return false; 00862 } 00863 00864 void RedmondDecoFactory::readConfig() { 00865 normalTitleHeight = QFontMetrics(options()->font(true)).height(); 00866 toolTitleHeight = QFontMetrics(options()->font(true, true)).height(); 00867 switch(options()->preferredBorderSize(this)) { 00868 case BorderLarge: 00869 borderWidth = 8; 00870 if (normalTitleHeight < 20) normalTitleHeight = 20; 00871 if (toolTitleHeight < 20) toolTitleHeight = 20; 00872 break; 00873 case BorderVeryLarge: 00874 borderWidth = 12; 00875 if (normalTitleHeight < 24) normalTitleHeight = 24; 00876 if (toolTitleHeight < 24) toolTitleHeight = 24; 00877 break; 00878 case BorderHuge: 00879 borderWidth = 18; 00880 if (normalTitleHeight < 28) normalTitleHeight = 28; 00881 if (toolTitleHeight < 28) toolTitleHeight = 28; 00882 break; 00883 case BorderVeryHuge: 00884 borderWidth = 27; 00885 if (normalTitleHeight < 33) normalTitleHeight = 33; 00886 if (toolTitleHeight < 33) toolTitleHeight = 33; 00887 break; 00888 case BorderOversized: 00889 borderWidth = 40; 00890 if (normalTitleHeight < 40) normalTitleHeight = 40; 00891 if (toolTitleHeight < 40) toolTitleHeight = 40; 00892 break; 00893 case BorderTiny: 00894 case BorderNormal: 00895 default: 00896 borderWidth = 4; 00897 if (normalTitleHeight < 16) normalTitleHeight = 16; 00898 if (toolTitleHeight < 16) toolTitleHeight = 16; 00899 } 00900 } 00901 00902 RedmondDecoFactory::RedmondDecoFactory() 00903 { 00904 readConfig(); 00905 create_pixmaps(); 00906 } 00907 00908 RedmondDecoFactory::~RedmondDecoFactory() 00909 { 00910 Redmond::delete_pixmaps(); 00911 } 00912 00913 KDecoration *RedmondDecoFactory::createDecoration( KDecorationBridge *b ) 00914 { 00915 return new RedmondDeco(b, this); 00916 } 00917 00918 bool RedmondDecoFactory::reset( unsigned long changed ) 00919 { 00920 if ( changed & ( SettingFont | SettingBorder | SettingColors ) ) { 00921 delete_pixmaps(); 00922 readConfig(); 00923 create_pixmaps(); 00924 resetDecorations(changed); 00925 return true; 00926 } else { 00927 resetDecorations(changed); 00928 return false; 00929 } 00930 } 00931 00932 QValueList< RedmondDecoFactory::BorderSize > RedmondDecoFactory::borderSizes() const 00933 { // the list must be sorted 00934 return QValueList< BorderSize >() << BorderNormal << BorderLarge << 00935 BorderVeryLarge << BorderHuge << BorderVeryHuge << BorderOversized; 00936 } 00937 00938 } 00939 00940 extern "C" KDecorationFactory *create_factory() 00941 { 00942 return new Redmond::RedmondDecoFactory(); 00943 } 00944 00945 00946 #include "redmond.moc" 00947 // vim: ts=4
KDE Logo
This file is part of the documentation for kwin Library Version 3.2.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Sep 16 15:59:32 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003