kwin Library API Documentation

b2client.cpp

00001 /* 00002 * B-II KWin Client 00003 * 00004 * Changes: 00005 * Customizable button positions by Karol Szwed <gallium@kde.org> 00006 * 00007 * Thin frame in fixed size windows, titlebar gradient support, accessibility 00008 * improvements, customizable menu double click action and button hover 00009 * effects are 00010 * Copyright (c) 2003,2004 Luciano Montanaro <mikelima@cirulla.net> 00011 */ 00012 00013 #include "b2client.h" 00014 #include <qapplication.h> 00015 #include <qlayout.h> 00016 #include <qdrawutil.h> 00017 #include <kpixmapeffect.h> 00018 #include <kimageeffect.h> 00019 #include <kicontheme.h> 00020 #include <kiconeffect.h> 00021 #include <kdrawutil.h> 00022 #include <klocale.h> 00023 #include <kconfig.h> 00024 #include <qbitmap.h> 00025 #include <qlabel.h> 00026 #include <qtooltip.h> 00027 00028 #include <X11/Xlib.h> 00029 00030 namespace B2 { 00031 00032 #include "bitmaps.h" 00033 00034 enum { 00035 Norm = 0, 00036 Hover, Down, INorm, IHover, IDown, 00037 NumStates 00038 }; 00039 00040 enum { 00041 P_CLOSE = 0, 00042 P_MAX, P_NORMALIZE, P_ICONIFY, P_PINUP, P_MENU, P_HELP, P_SHADE, P_RESIZE, 00043 P_NUM_BUTTON_TYPES 00044 }; 00045 00046 #define NUM_PIXMAPS (P_NUM_BUTTON_TYPES * NumStates) 00047 00048 static KPixmap *pixmap[NUM_PIXMAPS]; 00049 00050 // active 00051 #define PIXMAP_A(i) (pixmap[(i) * NumStates + Norm]) 00052 // active, hover 00053 #define PIXMAP_AH(i) (pixmap[(i) * NumStates + Hover]) 00054 // active, down 00055 #define PIXMAP_AD(i) (pixmap[(i) * NumStates + Down]) 00056 // inactive 00057 #define PIXMAP_I(i) (pixmap[(i) * NumStates + INorm]) 00058 // inactive, hover 00059 #define PIXMAP_IH(i) (pixmap[(i) * NumStates + IHover]) 00060 // inactive, down 00061 #define PIXMAP_ID(i) (pixmap[(i) * NumStates + IDown]) 00062 00063 static KPixmap* titleGradient[2] = {0, 0}; 00064 00065 static int thickness = 4; // Frame thickness 00066 static int buttonSize = 16; 00067 00068 enum DblClickOperation { 00069 NoOp = 0, 00070 MinimizeOp, 00071 ShadeOp, 00072 CloseOp 00073 }; 00074 00075 static DblClickOperation menu_dbl_click_op = NoOp; 00076 00077 static bool pixmaps_created = false; 00078 static bool colored_frame = false; 00079 static bool do_draw_handle = true; 00080 00081 // ===================================== 00082 00083 extern "C" KDecorationFactory* create_factory() 00084 { 00085 return new B2::B2ClientFactory(); 00086 } 00087 00088 // ===================================== 00089 00090 static inline const KDecorationOptions *options() 00091 { 00092 return KDecoration::options(); 00093 } 00094 00095 static void redraw_pixmaps(); 00096 00097 static void read_config(B2ClientFactory *f) 00098 { 00099 // Force button size to be in a reasonable range. 00100 // If the frame width is large, the button size must be large too. 00101 buttonSize = (QFontMetrics(options()->font(true)).height() + 1) & 0x3e; 00102 if (buttonSize < 16) buttonSize = 16; 00103 00104 KConfig conf("kwinb2rc"); 00105 conf.setGroup("General"); 00106 colored_frame = conf.readBoolEntry("UseTitleBarBorderColors", false); 00107 do_draw_handle = conf.readBoolEntry("DrawGrabHandle", true); 00108 QString opString = conf.readEntry("MenuButtonDoubleClickOperation", "NoOp"); 00109 if (opString == "Close") { 00110 menu_dbl_click_op = B2::CloseOp; 00111 } else if (opString == "Minimize") { 00112 menu_dbl_click_op = B2::MinimizeOp; 00113 } else if (opString == "Shade") { 00114 menu_dbl_click_op = B2::ShadeOp; 00115 } else { 00116 menu_dbl_click_op = B2::NoOp; 00117 } 00118 00119 switch (options()->preferredBorderSize(f)) { 00120 case KDecoration::BorderTiny: 00121 thickness = 2; 00122 break; 00123 case KDecoration::BorderLarge: 00124 thickness = 5; 00125 break; 00126 case KDecoration::BorderVeryLarge: 00127 thickness = 8; 00128 break; 00129 case KDecoration::BorderHuge: 00130 thickness = 12; 00131 break; 00132 case KDecoration::BorderVeryHuge: 00133 case KDecoration::BorderOversized: 00134 case KDecoration::BorderNormal: 00135 default: 00136 thickness = 4; 00137 } 00138 } 00139 00140 static void drawB2Rect(KPixmap *pix, const QColor &primary, bool down) 00141 { 00142 QPainter p(pix); 00143 QColor hColor = primary.light(150); 00144 QColor lColor = primary.dark(150); 00145 00146 if (QPixmap::defaultDepth() > 8) { 00147 if (down) 00148 KPixmapEffect::gradient(*pix, lColor, hColor, 00149 KPixmapEffect::DiagonalGradient); 00150 else 00151 KPixmapEffect::gradient(*pix, hColor, lColor, 00152 KPixmapEffect::DiagonalGradient); 00153 } 00154 else 00155 pix->fill(primary); 00156 int x2 = pix->width() - 1; 00157 int y2 = pix->height() - 1; 00158 p.setPen(down ? hColor : lColor); 00159 p.drawLine(0, 0, x2, 0); 00160 p.drawLine(0, 0, 0, y2); 00161 p.drawLine(1, x2 - 1, x2 - 1, y2 - 1); 00162 p.drawLine(x2 - 1, 1, x2 - 1, y2 - 1); 00163 p.setPen(down ? lColor : hColor); 00164 p.drawRect(1, 1, x2, y2); 00165 00166 } 00167 00168 QPixmap* kwin_get_menu_pix_hack() 00169 { 00170 //return menu_pix; FIXME 00171 return PIXMAP_A(P_MENU); 00172 } 00173 00174 static void create_pixmaps() 00175 { 00176 if (pixmaps_created) 00177 return; 00178 pixmaps_created = true; 00179 00180 int i; 00181 int bsize = buttonSize - 2; 00182 if (bsize < 16) bsize = 16; 00183 00184 for (i = 0; i < NUM_PIXMAPS; i++) { 00185 pixmap[i] = new KPixmap; 00186 switch (i / NumStates) { 00187 case P_MAX: // will be initialized by copying P_CLOSE 00188 case P_RESIZE: 00189 break; 00190 case P_ICONIFY: 00191 pixmap[i]->resize(10, 10); break; 00192 case P_SHADE: 00193 case P_CLOSE: 00194 pixmap[i]->resize(bsize, bsize); break; 00195 default: 00196 pixmap[i]->resize(16, 16); break; 00197 } 00198 } 00199 00200 // there seems to be no way to load X bitmaps from data properly, so 00201 // we need to create new ones for each mask :P 00202 QBitmap pinupMask(16, 16, pinup_mask_bits, true); 00203 PIXMAP_A(P_PINUP)->setMask(pinupMask); 00204 PIXMAP_I(P_PINUP)->setMask(pinupMask); 00205 QBitmap pindownMask(16, 16, pindown_mask_bits, true); 00206 PIXMAP_AD(P_PINUP)->setMask(pindownMask); 00207 PIXMAP_ID(P_PINUP)->setMask(pindownMask); 00208 00209 QBitmap menuMask(16, 16, menu_mask_bits, true); 00210 for (i = 0; i < NumStates; i++) 00211 pixmap[P_MENU * NumStates + i]->setMask(menuMask); 00212 00213 QBitmap helpMask(16, 16, help_mask_bits, true); 00214 for (i = 0; i < NumStates; i++) 00215 pixmap[P_HELP * NumStates + i]->setMask(helpMask); 00216 00217 QBitmap normalizeMask(16, 16, true); 00218 // draw normalize icon mask 00219 QPainter mask; 00220 mask.begin(&normalizeMask); 00221 00222 QBrush one(Qt::color1); 00223 mask.fillRect(normalizeMask.width() - 12, normalizeMask.height() - 12, 00224 12, 12, one); 00225 mask.fillRect(0, 0, 10, 10, one); 00226 mask.end(); 00227 00228 for (i = 0; i < NumStates; i++) 00229 pixmap[P_NORMALIZE * NumStates + i]->setMask(normalizeMask); 00230 00231 QBitmap shadeMask(bsize, bsize, true); 00232 mask.begin(&shadeMask); 00233 mask.fillRect(0, 0, bsize, 6, one); 00234 mask.end(); 00235 for (i = 0; i < NumStates; i++) 00236 pixmap[P_SHADE * NumStates + i]->setMask(shadeMask); 00237 00238 titleGradient[0] = 0; 00239 titleGradient[1] = 0; 00240 00241 redraw_pixmaps(); 00242 } 00243 00244 static void delete_pixmaps() 00245 { 00246 for (int i = 0; i < NUM_PIXMAPS; i++) { 00247 delete pixmap[i]; 00248 pixmap[i] = 0; 00249 } 00250 for (int i = 0; i < 2; i++) { 00251 delete titleGradient[i]; 00252 titleGradient[i] = 0; 00253 } 00254 pixmaps_created = false; 00255 } 00256 00257 // ===================================== 00258 00259 B2ClientFactory::B2ClientFactory() 00260 { 00261 read_config(this); 00262 create_pixmaps(); 00263 } 00264 00265 B2ClientFactory::~B2ClientFactory() 00266 { 00267 delete_pixmaps(); 00268 } 00269 00270 KDecoration *B2ClientFactory::createDecoration(KDecorationBridge *b) 00271 { 00272 return new B2::B2Client(b, this); 00273 } 00274 00275 bool B2ClientFactory::reset(unsigned long changed) 00276 { 00277 bool needsReset = SettingColors ? true : false; 00278 // TODO Do not recreate decorations if it is not needed. Look at 00279 // ModernSystem for how to do that 00280 read_config(this); 00281 if (changed & SettingFont) { 00282 delete_pixmaps(); 00283 create_pixmaps(); 00284 needsReset = true; 00285 } 00286 redraw_pixmaps(); 00287 // For now just return true. 00288 return needsReset; 00289 } 00290 00291 QValueList< B2ClientFactory::BorderSize > B2ClientFactory::borderSizes() const 00292 { 00293 // the list must be sorted 00294 return QValueList< BorderSize >() << BorderTiny << BorderNormal << 00295 BorderLarge << BorderVeryLarge << BorderHuge; 00296 } 00297 00298 // ===================================== 00299 00300 void B2Client::maxButtonClicked() 00301 { 00302 maximize(button[BtnMax]->last_button); 00303 } 00304 00305 void B2Client::shadeButtonClicked() 00306 { 00307 setShade(!isShade()); 00308 } 00309 00310 void B2Client::resizeButtonPressed() 00311 { 00312 performWindowOperation(ResizeOp); 00313 } 00314 00315 B2Client::B2Client(KDecorationBridge *b, KDecorationFactory *f) 00316 : KDecoration(b, f), bar_x_ofs(0), in_unobs(0) 00317 { 00318 } 00319 00320 void B2Client::init() 00321 { 00322 draw_handle = do_draw_handle; 00323 const QString tips[] = { 00324 i18n("Menu"), 00325 isOnAllDesktops() ? 00326 i18n("Not on all desktops") : i18n("On all desktops"), 00327 i18n("Minimize"), i18n("Maximize"), 00328 i18n("Close"), i18n("Help"), 00329 isShade() ? i18n("Unshade") : i18n("Shade"), 00330 i18n("Resize") 00331 }; 00332 00333 createMainWidget(WResizeNoErase | WRepaintNoErase); 00334 widget()->installEventFilter(this); 00335 00336 widget()->setBackgroundMode(NoBackground); 00337 00338 // Set button pointers to NULL so we know what has been created 00339 for (int i = 0; i < BtnCount; i++) 00340 button[i] = NULL; 00341 00342 g = new QGridLayout(widget(), 0, 0); 00343 if (isPreview()) { 00344 g->addMultiCellWidget( 00345 new QLabel(i18n("<b><center>B II preview</center></b>"), 00346 widget()), 00347 1, 1, 1, 2); 00348 } else { 00349 g->addMultiCell(new QSpacerItem(0, 0), 1, 1, 1, 2); 00350 } 00351 00352 // Left and right border width 00353 leftSpacer = new QSpacerItem(thickness, 16, 00354 QSizePolicy::Minimum, QSizePolicy::Expanding); 00355 rightSpacer = new QSpacerItem(thickness, 16, 00356 QSizePolicy::Minimum, QSizePolicy::Expanding); 00357 00358 g->addItem(leftSpacer, 1, 0); 00359 g->addColSpacing(1, 16); 00360 g->setColStretch(2, 1); 00361 g->setRowStretch(1, 1); 00362 g->addItem(rightSpacer, 1, 3); 00363 00364 // Bottom border height 00365 spacer = new QSpacerItem(10, thickness + (mustDrawHandle() ? 4 : 0), 00366 QSizePolicy::Expanding, QSizePolicy::Minimum); 00367 g->addItem(spacer, 3, 1); 00368 00369 // titlebar 00370 g->addRowSpacing(0, buttonSize + 4); 00371 00372 titlebar = new B2Titlebar(this); 00373 titlebar->setMinimumWidth(buttonSize + 4); 00374 titlebar->setFixedHeight(buttonSize + 4); 00375 00376 QBoxLayout *titleLayout = new QBoxLayout(titlebar, 00377 QBoxLayout::LeftToRight, 0, 1, 0); 00378 titleLayout->addSpacing(3); 00379 00380 if (options()->customButtonPositions()) { 00381 addButtons(options()->titleButtonsLeft(), tips, titlebar, titleLayout); 00382 titleLayout->addItem(titlebar->captionSpacer); 00383 addButtons(options()->titleButtonsRight(), tips, titlebar, titleLayout); 00384 } else { 00385 addButtons("MSH", tips, titlebar, titleLayout); 00386 titleLayout->addItem(titlebar->captionSpacer); 00387 addButtons("IAX", tips, titlebar, titleLayout); 00388 } 00389 00390 titleLayout->addSpacing(3); 00391 00392 QColor c = options()->colorGroup(KDecoration::ColorTitleBar, isActive()). 00393 color(QColorGroup::Button); 00394 00395 for (int i = 0; i < BtnCount; i++) { 00396 if (button[i]) 00397 button[i]->setBg(c); 00398 } 00399 00400 titlebar->updateGeometry(); 00401 positionButtons(); 00402 titlebar->recalcBuffer(); 00403 titlebar->installEventFilter(this); 00404 } 00405 00406 void B2Client::addButtons(const QString& s, const QString tips[], 00407 B2Titlebar* tb, QBoxLayout* titleLayout) 00408 { 00409 if (s.length() <= 0) 00410 return; 00411 00412 for (unsigned int i = 0; i < s.length(); i++) { 00413 switch (s[i].latin1()) { 00414 case 'M': // Menu button 00415 if (!button[BtnMenu]) { 00416 button[BtnMenu] = new B2Button(this, tb, tips[BtnMenu], 00417 LeftButton | RightButton); 00418 button[BtnMenu]->setPixmaps(P_MENU); 00419 button[BtnMenu]->setUseMiniIcon(); 00420 connect(button[BtnMenu], SIGNAL(pressed()), 00421 this, SLOT(menuButtonPressed())); 00422 titleLayout->addWidget(button[BtnMenu]); 00423 } 00424 break; 00425 case 'S': // Sticky button 00426 if (!button[BtnSticky]) { 00427 button[BtnSticky] = new B2Button(this, tb, tips[BtnSticky]); 00428 button[BtnSticky]->setPixmaps(P_PINUP); 00429 button[BtnSticky]->setToggle(); 00430 button[BtnSticky]->setDown(isOnAllDesktops()); 00431 connect(button[BtnSticky], SIGNAL(clicked()), 00432 this, SLOT(toggleOnAllDesktops())); 00433 titleLayout->addWidget(button[BtnSticky]); 00434 } 00435 break; 00436 case 'H': // Help button 00437 if (providesContextHelp() && (!button[BtnHelp])) { 00438 button[BtnHelp] = new B2Button(this, tb, tips[BtnHelp]); 00439 button[BtnHelp]->setPixmaps(P_HELP); 00440 connect(button[BtnHelp], SIGNAL(clicked()), 00441 this, SLOT(showContextHelp())); 00442 titleLayout->addWidget(button[BtnHelp]); 00443 } 00444 break; 00445 case 'I': // Minimize button 00446 if (isMinimizable() && (!button[BtnIconify])) { 00447 button[BtnIconify] = new B2Button(this, tb,tips[BtnIconify]); 00448 button[BtnIconify]->setPixmaps(P_ICONIFY); 00449 connect(button[BtnIconify], SIGNAL(clicked()), 00450 this, SLOT(minimize())); 00451 titleLayout->addWidget(button[BtnIconify]); 00452 } 00453 break; 00454 case 'A': // Maximize button 00455 if (isMaximizable() && (!button[BtnMax])) { 00456 button[BtnMax] = new B2Button(this, tb, tips[BtnMax], 00457 LeftButton | MidButton | RightButton); 00458 button[BtnMax]->setPixmaps(maximizeMode() == MaximizeFull ? 00459 P_NORMALIZE : P_MAX); 00460 connect(button[BtnMax], SIGNAL(clicked()), 00461 this, SLOT(maxButtonClicked())); 00462 titleLayout->addWidget(button[BtnMax]); 00463 } 00464 break; 00465 case 'X': // Close button 00466 if (isCloseable() && !button[BtnClose]) { 00467 button[BtnClose] = new B2Button(this, tb, tips[BtnClose]); 00468 button[BtnClose]->setPixmaps(P_CLOSE); 00469 connect(button[BtnClose], SIGNAL(clicked()), 00470 this, SLOT(closeWindow())); 00471 titleLayout->addWidget(button[BtnClose]); 00472 } 00473 break; 00474 case 'L': // Shade button 00475 if (isShadeable() && !button[BtnShade]) { 00476 button[BtnShade] = new B2Button(this, tb, tips[BtnShade]); 00477 button[BtnShade]->setPixmaps(P_SHADE); 00478 connect(button[BtnShade], SIGNAL(clicked()), 00479 this, SLOT(shadeButtonClicked())); 00480 titleLayout->addWidget(button[BtnShade]); 00481 } 00482 break; 00483 case 'R': // Resize button 00484 if (isResizable() && !button[BtnResize]) { 00485 button[BtnResize] = new B2Button(this, tb, tips[BtnResize]); 00486 button[BtnResize]->setPixmaps(P_RESIZE); 00487 connect(button[BtnResize], SIGNAL(pressed()), 00488 this, SLOT(resizeButtonPressed())); 00489 titleLayout->addWidget(button[BtnResize]); 00490 } 00491 break; 00492 case '_': // Additional spacing 00493 titleLayout->addSpacing(4); 00494 break; 00495 } 00496 } 00497 } 00498 00499 bool B2Client::mustDrawHandle() const 00500 { 00501 bool drawSmallBorders = !options()->moveResizeMaximizedWindows(); 00502 if (drawSmallBorders && (maximizeMode() & MaximizeVertical)) { 00503 return false; 00504 } else { 00505 return draw_handle && isResizable(); 00506 } 00507 } 00508 00509 void B2Client::iconChange() 00510 { 00511 if (button[BtnMenu]) 00512 button[BtnMenu]->repaint(false); 00513 } 00514 00515 // Gallium: New button show/hide magic for customizable 00516 // button positions. 00517 void B2Client::calcHiddenButtons() 00518 { 00519 // Hide buttons in this order: 00520 // Shade, Sticky, Help, Resize, Maximize, Minimize, Close, Menu 00521 B2Button* btnArray[] = { 00522 button[BtnShade], button[BtnSticky], button[BtnHelp], button[BtnResize], 00523 button[BtnMax], button[BtnIconify], button[BtnClose], button[BtnMenu] 00524 }; 00525 int minWidth = 120; 00526 int currentWidth = width(); 00527 int count = 0; 00528 int i; 00529 00530 // Determine how many buttons we need to hide 00531 while (currentWidth < minWidth) { 00532 currentWidth += buttonSize + 1; // Allow for spacer (extra 1pix) 00533 count++; 00534 } 00535 // Bound the number of buttons to hide 00536 if (count > BtnCount) count = BtnCount; 00537 00538 // Hide the required buttons 00539 for (i = 0; i < count; i++) { 00540 if (btnArray[i] && btnArray[i]->isVisible()) 00541 btnArray[i]->hide(); 00542 } 00543 // Show the rest of the buttons 00544 for (i = count; i < BtnCount; i++) { 00545 if (btnArray[i] && (!btnArray[i]->isVisible())) 00546 btnArray[i]->show(); 00547 } 00548 } 00549 00550 void B2Client::resizeEvent(QResizeEvent * /*e*/) 00551 { 00552 calcHiddenButtons(); 00553 titlebar->layout()->activate(); 00554 positionButtons(); 00555 00556 /* may be the resize cut off some space occupied by titlebar, which 00557 was moved, so instead of reducing it, we first try to move it */ 00558 titleMoveAbs(bar_x_ofs); 00559 doShape(); 00560 00561 widget()->repaint(); // the frame is misrendered without this 00562 } 00563 00564 void B2Client::captionChange() 00565 { 00566 positionButtons(); 00567 titleMoveAbs(bar_x_ofs); 00568 doShape(); 00569 titlebar->recalcBuffer(); 00570 titlebar->repaint(false); 00571 } 00572 00573 void B2Client::paintEvent(QPaintEvent* e) 00574 { 00575 QPainter p(widget()); 00576 00577 KDecoration::ColorType frameColorGroup = colored_frame ? 00578 KDecoration::ColorTitleBar : KDecoration::ColorFrame; 00579 00580 QRect t = titlebar->geometry(); 00581 00582 // Frame height, this is used a lot of times 00583 int fHeight = height() - t.height(); 00584 00585 // distance from the bottom border - it is different if window is resizable 00586 int bb = mustDrawHandle() ? 4 : 0; 00587 int bDepth = thickness + bb; 00588 00589 QColorGroup fillColor = options()->colorGroup(frameColorGroup, isActive()); 00590 QBrush fillBrush(options()->color(frameColorGroup, isActive())); 00591 00592 // outer frame rect 00593 p.drawRect(0, t.bottom() - thickness + 1, 00594 width(), fHeight - bb + thickness); 00595 00596 if (thickness >= 2) { 00597 // inner window rect 00598 p.drawRect(thickness - 1, t.bottom(), 00599 width() - 2 * (thickness - 1), fHeight - bDepth + 2); 00600 00601 if (thickness >= 3) { 00602 // frame shade panel 00603 qDrawShadePanel(&p, 1, t.bottom() - thickness + 2, 00604 width() - 2, fHeight - 2 - bb + thickness, fillColor, false); 00605 if (thickness == 4) { 00606 p.setPen(fillColor.background()); 00607 p.drawRect(thickness - 2, t.bottom() - 1, 00608 width() - 2 * (thickness - 2), fHeight + 4 - bDepth); 00609 } else if (thickness > 4) { 00610 qDrawShadePanel(&p, thickness - 2, 00611 t.bottom() - 1, width() - 2 * (thickness - 2), 00612 fHeight + 4 - bDepth, fillColor, true); 00613 if (thickness >= 5) { 00614 // draw frame interior 00615 p.fillRect(2, t.bottom() - thickness + 3, 00616 width() - 4, thickness - 4, fillBrush); 00617 p.fillRect(2, height() - bDepth + 2, 00618 width() - 4, thickness - 4, fillBrush); 00619 p.fillRect(2, t.bottom() - 1, 00620 thickness - 4, fHeight - bDepth + 4, fillBrush); 00621 p.fillRect(width() - thickness + 2, t.bottom() - 1, 00622 thickness - 4, fHeight - bDepth + 4, fillBrush); 00623 } 00624 } 00625 } 00626 } 00627 00628 // bottom handle rect 00629 if (mustDrawHandle()) { 00630 p.setPen(Qt::black); 00631 int hx = width() - 40; 00632 int hw = 40; 00633 00634 p.drawLine(width() - 1, height() - thickness - 4, 00635 width() - 1, height() - 1); 00636 p.drawLine(hx, height() - 1, width() - 1, height() - 1); 00637 p.drawLine(hx, height() - 4, hx, height() - 1); 00638 00639 p.fillRect(hx + 1, height() - thickness - 3, 00640 hw - 2, thickness + 2, fillBrush); 00641 00642 p.setPen(fillColor.dark()); 00643 p.drawLine(width() - 2, height() - thickness - 4, 00644 width() - 2, height() - 2); 00645 p.drawLine(hx + 1, height() - 2, width() - 2, height() - 2); 00646 00647 p.setPen(fillColor.light()); 00648 p.drawLine(hx + 1, height() - thickness - 2, 00649 hx + 1, height() - 3); 00650 p.drawLine(hx + 1, height() - thickness - 3, 00651 width() - 3, height() - thickness - 3); 00652 } 00653 00654 /* OK, we got a paint event, which means parts of us are now visible 00655 which were not before. We try the titlebar if it is currently fully 00656 obscured, and if yes, try to unobscure it, in the hope that some 00657 of the parts which we just painted were in the titlebar area. 00658 It can happen, that the titlebar, as it got the FullyObscured event 00659 had no chance of becoming partly visible. The problem is, that 00660 we now might have the space available, but the titlebar gets no 00661 visibilitinotify events until its state changes, so we just try 00662 */ 00663 if (titlebar->isFullyObscured()) { 00664 /* We first see, if our repaint contained the titlebar area */ 00665 QRegion reg(QRect(0, 0, width(), buttonSize + 4)); 00666 reg = reg.intersect(e->region()); 00667 if (!reg.isEmpty()) 00668 unobscureTitlebar(); 00669 } 00670 } 00671 00672 #define QCOORDARRLEN(x) sizeof(x) / (sizeof(QCOORD) * 2) 00673 00674 void B2Client::doShape() 00675 { 00676 QRect t = titlebar->geometry(); 00677 QRegion mask(widget()->rect()); 00678 // top to the tilebar right 00679 if (bar_x_ofs) { 00680 mask -= QRect(0, 0, bar_x_ofs, t.height() - thickness); //left from bar 00681 mask -= QRect(0, t.height() - thickness, 1, 1); //top left point 00682 } 00683 if (t.right() < width() - 1) { 00684 mask -= QRect(width() - 1, 00685 t.height() - thickness, 1, 1); //top right point 00686 mask -= QRect(t.right() + 1, 0, 00687 width() - t.right() - 1, t.height() - thickness); 00688 } 00689 mask -= QRect(width() - 1, height() - 1, 1, 1); //bottom right point 00690 if (mustDrawHandle()) { 00691 mask -= QRect(0, height() - 5, 1, 1); //bottom left point 00692 mask -= QRect(width() - 1, height() - 1, 1, 1); //bottom right point 00693 mask -= QRect(width() - 40, height() - 1, 1, 1); //handle left point 00694 mask -= QRect(0, height() - 4, width() - 40, 4); //bottom left 00695 } else { 00696 mask -= QRect(0, height() - 1, 1, 1); // bottom left point 00697 } 00698 00699 setMask(mask); 00700 } 00701 00702 void B2Client::showEvent(QShowEvent *) 00703 { 00704 calcHiddenButtons(); 00705 positionButtons(); 00706 doShape(); 00707 widget()->repaint(); 00708 titlebar->repaint(false); 00709 } 00710 00711 KDecoration::Position B2Client::mousePosition(const QPoint& p) const 00712 { 00713 const int range = 16; 00714 QRect t = titlebar->geometry(); 00715 t.setHeight(buttonSize + 4 - thickness); 00716 int ly = t.bottom(); 00717 int lx = t.right(); 00718 int bb = mustDrawHandle() ? 0 : 5; 00719 00720 if (p.x() > t.right()) { 00721 if (p.y() <= ly + range && p.x() >= width() - range) 00722 return PositionTopRight; 00723 else if (p.y() <= ly + thickness) 00724 return PositionTop; 00725 } else if (p.x() < bar_x_ofs) { 00726 if (p.y() <= ly + range && p.x() <= range) 00727 return PositionTopLeft; 00728 else if (p.y() <= ly + thickness) 00729 return PositionTop; 00730 } else if (p.y() < ly) { 00731 if (p.x() > bar_x_ofs + thickness && 00732 p.x() < lx - thickness && p.y() > thickness) 00733 return KDecoration::mousePosition(p); 00734 if (p.x() > bar_x_ofs + range && p.x() < lx - range) 00735 return PositionTop; 00736 if (p.y() <= range) { 00737 if (p.x() <= bar_x_ofs + range) 00738 return PositionTopLeft; 00739 else return PositionTopRight; 00740 } else { 00741 if (p.x() <= bar_x_ofs + range) 00742 return PositionLeft; 00743 else return PositionRight; 00744 } 00745 } 00746 00747 if (p.y() >= height() - 8 + bb) { 00748 /* the normal Client:: only wants border of 4 pixels */ 00749 if (p.x() <= range) return PositionBottomLeft; 00750 if (p.x() >= width() - range) return PositionBottomRight; 00751 return PositionBottom; 00752 } 00753 00754 return KDecoration::mousePosition(p); 00755 } 00756 00757 void B2Client::titleMoveAbs(int new_ofs) 00758 { 00759 if (new_ofs < 0) new_ofs = 0; 00760 if (new_ofs + titlebar->width() > width()) { 00761 new_ofs = width() - titlebar->width(); 00762 } 00763 if (bar_x_ofs != new_ofs) { 00764 bar_x_ofs = new_ofs; 00765 positionButtons(); 00766 doShape(); 00767 widget()->repaint(0, 0, width(), buttonSize + 4, false); 00768 titlebar->repaint(false); 00769 } 00770 } 00771 00772 void B2Client::titleMoveRel(int xdiff) 00773 { 00774 titleMoveAbs(bar_x_ofs + xdiff); 00775 } 00776 00777 void B2Client::desktopChange() 00778 { 00779 bool on = isOnAllDesktops(); 00780 if (B2Button *b = button[BtnSticky]) { 00781 b->setDown(on); 00782 QToolTip::remove(b); 00783 QToolTip::add(b, 00784 on ? i18n("Not on all desktops") : i18n("On all desktops")); 00785 } 00786 } 00787 00788 void B2Client::maximizeChange() 00789 { 00790 bool m = maximizeMode() == MaximizeFull; 00791 if (button[BtnMax]) { 00792 button[BtnMax]->setPixmaps(m ? P_NORMALIZE : P_MAX); 00793 button[BtnMax]->repaint(); 00794 QToolTip::remove(button[BtnMax]); 00795 QToolTip::add(button[BtnMax], 00796 m ? i18n("Restore") : i18n("Maximize")); 00797 } 00798 spacer->changeSize(10, thickness + (mustDrawHandle() ? 4 : 0), 00799 QSizePolicy::Expanding, QSizePolicy::Minimum); 00800 00801 g->activate(); 00802 doShape(); 00803 widget()->repaint(false); 00804 } 00805 00806 void B2Client::activeChange() 00807 { 00808 widget()->repaint(false); 00809 titlebar->repaint(false); 00810 00811 QColor c = options()->colorGroup( 00812 KDecoration::ColorTitleBar, isActive()).color(QColorGroup::Button); 00813 00814 for (int i = 0; i < BtnCount; i++) 00815 if (button[i]) { 00816 button[i]->setBg(c); 00817 button[i]->repaint(false); 00818 } 00819 } 00820 00821 void B2Client::shadeChange() 00822 { 00823 spacer->changeSize(10, thickness + (mustDrawHandle() ? 4 : 0), 00824 QSizePolicy::Expanding, QSizePolicy::Minimum); 00825 g->activate(); 00826 doShape(); 00827 if (B2Button *b = button[BtnShade]) { 00828 QToolTip::remove(b); 00829 QToolTip::add(b, isShade() ? i18n("Unshade") : i18n("Shade")); 00830 } 00831 } 00832 00833 QSize B2Client::minimumSize() const 00834 { 00835 int left, right, top, bottom; 00836 borders(left, right, top, bottom); 00837 return QSize(left + right + 2 * buttonSize, top + bottom); 00838 } 00839 00840 void B2Client::resize(const QSize& s) 00841 { 00842 widget()->resize(s); 00843 } 00844 00845 void B2Client::borders(int &left, int &right, int &top, int &bottom) const 00846 { 00847 left = right = thickness; 00848 top = buttonSize + 4; 00849 bottom = thickness + (mustDrawHandle() ? 4 : 0); 00850 } 00851 00852 void B2Client::menuButtonPressed() 00853 { 00854 static B2Client *lastClient = NULL; 00855 00856 bool dbl = (lastClient == this && 00857 time.elapsed() <= QApplication::doubleClickInterval()); 00858 lastClient = this; 00859 time.start(); 00860 if (!dbl) { 00861 KDecorationFactory* f = factory(); 00862 QRect menuRect = button[BtnMenu]->rect(); 00863 QPoint menuTop = button[BtnMenu]->mapToGlobal(menuRect.topLeft()); 00864 QPoint menuBottom = button[BtnMenu]->mapToGlobal(menuRect.bottomRight()); 00865 showWindowMenu(QRect(menuTop, menuBottom)); 00866 if (!f->exists(this)) // 'this' was destroyed 00867 return; 00868 button[BtnMenu]->setDown(false); 00869 } else { 00870 switch (menu_dbl_click_op) { 00871 case B2::MinimizeOp: 00872 minimize(); 00873 break; 00874 case B2::ShadeOp: 00875 setShade(!isShade()); 00876 break; 00877 case B2::CloseOp: 00878 closeWindow(); 00879 break; 00880 case B2::NoOp: 00881 default: 00882 break; 00883 } 00884 } 00885 } 00886 00887 void B2Client::unobscureTitlebar() 00888 { 00889 /* we just noticed, that we got obscured by other windows 00890 so we look at all windows above us (stacking_order) merging their 00891 masks, intersecting it with our titlebar area, and see if we can 00892 find a place not covered by any window */ 00893 if (in_unobs) { 00894 return; 00895 } 00896 in_unobs = 1; 00897 QRegion reg(QRect(0,0,width(), buttonSize + 4)); 00898 reg = unobscuredRegion(reg); 00899 if (!reg.isEmpty()) { 00900 // there is at least _one_ pixel from our title area, which is not 00901 // obscured, we use the first rect we find 00902 // for a first test, we use boundingRect(), later we may refine 00903 // to rect(), and search for the nearest, or biggest, or smthg. 00904 titleMoveAbs(reg.boundingRect().x()); 00905 } 00906 in_unobs = 0; 00907 } 00908 00909 static void redraw_pixmaps() 00910 { 00911 int i; 00912 QColorGroup aGrp = options()->colorGroup(KDecoration::ColorButtonBg, true); 00913 QColorGroup iGrp = options()->colorGroup(KDecoration::ColorButtonBg, false); 00914 00915 // close 00916 drawB2Rect(PIXMAP_A(P_CLOSE), aGrp.button(), false); 00917 drawB2Rect(PIXMAP_AH(P_CLOSE), aGrp.button(), true); 00918 drawB2Rect(PIXMAP_AD(P_CLOSE), aGrp.button(), true); 00919 00920 drawB2Rect(PIXMAP_I(P_CLOSE), iGrp.button(), false); 00921 drawB2Rect(PIXMAP_IH(P_CLOSE), iGrp.button(), true); 00922 drawB2Rect(PIXMAP_ID(P_CLOSE), iGrp.button(), true); 00923 00924 // shade 00925 KPixmap thinBox; 00926 thinBox.resize(buttonSize - 2, 6); 00927 for (i = 0; i < NumStates; i++) { 00928 bool is_act = (i < 2); 00929 bool is_down = ((i & 1) == 1); 00930 KPixmap *pix = pixmap[P_SHADE * NumStates + i]; 00931 QColor color = is_act ? aGrp.button() : iGrp.button(); 00932 drawB2Rect(&thinBox, color, is_down); 00933 pix->fill(Qt::black); 00934 bitBlt(pix, 0, 0, &thinBox, 00935 0, 0, thinBox.width(), thinBox.height(), Qt::CopyROP, true); 00936 } 00937 00938 // maximize 00939 for (i = 0; i < NumStates; i++) { 00940 *pixmap[P_MAX * NumStates + i] = *pixmap[P_CLOSE * NumStates + i]; 00941 pixmap[P_MAX * NumStates + i]->detach(); 00942 } 00943 00944 // normalize + iconify 00945 KPixmap smallBox; 00946 smallBox.resize(10, 10); 00947 KPixmap largeBox; 00948 largeBox.resize(12, 12); 00949 00950 for (i = 0; i < NumStates; i++) { 00951 bool is_act = (i < 3); 00952 bool is_down = (i == Down || i == IDown); 00953 KPixmap *pix = pixmap[P_NORMALIZE * NumStates + i]; 00954 drawB2Rect(&smallBox, is_act ? aGrp.button() : iGrp.button(), is_down); 00955 drawB2Rect(&largeBox, is_act ? aGrp.button() : iGrp.button(), is_down); 00956 pix->fill(options()->color(KDecoration::ColorTitleBar, is_act)); 00957 bitBlt(pix, pix->width() - 12, pix->width() - 12, &largeBox, 00958 0, 0, 12, 12, Qt::CopyROP, true); 00959 bitBlt(pix, 0, 0, &smallBox, 0, 0, 10, 10, Qt::CopyROP, true); 00960 00961 bitBlt(pixmap[P_ICONIFY * NumStates + i], 0, 0, 00962 &smallBox, 0, 0, 10, 10, Qt::CopyROP, true); 00963 } 00964 00965 // resize 00966 for (i = 0; i < NumStates; i++) { 00967 bool is_act = (i < 3); 00968 bool is_down = (i == Down || i == IDown); 00969 *pixmap[P_RESIZE * NumStates + i] = *pixmap[P_CLOSE * NumStates + i]; 00970 pixmap[P_RESIZE * NumStates + i]->detach(); 00971 drawB2Rect(&smallBox, is_act ? aGrp.button() : iGrp.button(), is_down); 00972 bitBlt(pixmap[P_RESIZE * NumStates + i], 00973 0, 0, &smallBox, 0, 0, 10, 10, Qt::CopyROP, true); 00974 } 00975 00976 00977 QPainter p; 00978 // x for close + menu + help 00979 for (int j = 0; j < 3; j++) { 00980 int pix; 00981 unsigned const char *light, *dark; 00982 switch (j) { 00983 case 0: 00984 pix = P_CLOSE; light = close_white_bits; dark = close_dgray_bits; 00985 break; 00986 case 1: 00987 pix = P_MENU; light = menu_white_bits; dark = menu_dgray_bits; 00988 break; 00989 default: 00990 pix = P_HELP; light = help_light_bits; dark = help_dark_bits; 00991 break; 00992 } 00993 int off = (pixmap[pix * NumStates]->width() - 16) / 2; 00994 for (i = 0; i < NumStates; i++) { 00995 p.begin(pixmap[pix * NumStates + i]); 00996 kColorBitmaps(&p, (i < 3) ? aGrp : iGrp, off, off, 16, 16, true, 00997 light, NULL, NULL, dark, NULL, NULL); 00998 p.end(); 00999 } 01000 } 01001 01002 // pin 01003 for (i = 0; i < NumStates; i++) { 01004 bool isDown = (i == Down || i == IDown); 01005 unsigned const char *white = isDown ? pindown_white_bits : pinup_white_bits; 01006 unsigned const char *gray = isDown ? pindown_gray_bits : pinup_gray_bits; 01007 unsigned const char *dgray =isDown ? pindown_dgray_bits : pinup_dgray_bits; 01008 p.begin(pixmap[P_PINUP * NumStates + i]); 01009 kColorBitmaps(&p, (i < 3) ? aGrp : iGrp, 0, 0, 16, 16, true, white, 01010 gray, NULL, dgray, NULL, NULL); 01011 p.end(); 01012 } 01013 01014 // Apply the hilight effect to the 'Hover' icons 01015 KIconEffect ie; 01016 QPixmap hilighted; 01017 for (i = 0; i < P_NUM_BUTTON_TYPES; i++) { 01018 int offset = i * NumStates; 01019 hilighted = ie.apply(*pixmap[offset + Norm], 01020 KIcon::Small, KIcon::ActiveState); 01021 *pixmap[offset + Hover] = hilighted; 01022 01023 hilighted = ie.apply(*pixmap[offset + INorm], 01024 KIcon::Small, KIcon::ActiveState); 01025 *pixmap[offset + IHover] = hilighted; 01026 } 01027 01028 01029 // Create the titlebar gradients 01030 if (QPixmap::defaultDepth() > 8) { 01031 QColor titleColor[4] = { 01032 options()->color(KDecoration::ColorTitleBar, true), 01033 options()->color(KDecoration::ColorFrame, true), 01034 01035 options()->color(KDecoration::ColorTitleBlend, false), 01036 options()->color(KDecoration::ColorTitleBar, false) 01037 }; 01038 01039 if (colored_frame) { 01040 titleColor[0] = options()->color(KDecoration::ColorTitleBlend, true); 01041 titleColor[1] = options()->color(KDecoration::ColorTitleBar, true); 01042 } 01043 01044 for (i = 0; i < 2; i++) { 01045 if (titleColor[2 * i] != titleColor[2 * i + 1]) { 01046 if (!titleGradient[i]) { 01047 titleGradient[i] = new KPixmap; 01048 } 01049 titleGradient[i]->resize(64, buttonSize + 3); 01050 KPixmapEffect::gradient(*titleGradient[i], 01051 titleColor[2 * i], titleColor[2 * i + 1], 01052 KPixmapEffect::VerticalGradient); 01053 } else { 01054 delete titleGradient[i]; 01055 titleGradient[i] = 0; 01056 } 01057 } 01058 } 01059 } 01060 01061 void B2Client::positionButtons() 01062 { 01063 QFontMetrics fm(options()->font(isActive())); 01064 QString cap = caption(); 01065 if (cap.length() < 5) // make sure the titlebar has sufficiently wide 01066 cap = "XXXXX"; // area for dragging the window 01067 int textLen = fm.width(cap); 01068 01069 QRect t = titlebar->captionSpacer->geometry(); 01070 int titleWidth = titlebar->width() - t.width() + textLen + 2; 01071 if (titleWidth > width()) titleWidth = width(); 01072 01073 titlebar->resize(titleWidth, buttonSize + 4); 01074 titlebar->move(bar_x_ofs, 0); 01075 } 01076 01077 // Transparent bound stuff. 01078 01079 static QRect *visible_bound; 01080 static QPointArray bound_shape; 01081 01082 bool B2Client::drawbound(const QRect& geom, bool clear) 01083 { 01084 if (clear) { 01085 if (!visible_bound) return true; 01086 } 01087 01088 if (!visible_bound) { 01089 visible_bound = new QRect(geom); 01090 QRect t = titlebar->geometry(); 01091 int frameTop = geom.top() + t.bottom(); 01092 int barLeft = geom.left() + bar_x_ofs; 01093 int barRight = barLeft + t.width() - 1; 01094 if (barRight > geom.right()) barRight = geom.right(); 01095 01096 bound_shape.putPoints(0, 8, 01097 geom.left(), frameTop, 01098 barLeft, frameTop, 01099 barLeft, geom.top(), 01100 barRight, geom.top(), 01101 barRight, frameTop, 01102 geom.right(), frameTop, 01103 geom.right(), geom.bottom(), 01104 geom.left(), geom.bottom()); 01105 } else { 01106 *visible_bound = geom; 01107 } 01108 QPainter p(workspaceWidget()); 01109 p.setPen(QPen(Qt::white, 5)); 01110 p.setRasterOp(Qt::XorROP); 01111 p.drawPolygon(bound_shape); 01112 01113 if (clear) { 01114 delete visible_bound; 01115 visible_bound = 0; 01116 } 01117 return true; 01118 } 01119 01120 bool B2Client::eventFilter(QObject *o, QEvent *e) 01121 { 01122 if (o != widget()) 01123 return false; 01124 switch (e->type()) { 01125 case QEvent::Resize: 01126 resizeEvent(static_cast< QResizeEvent* >(e)); 01127 return true; 01128 case QEvent::Paint: 01129 paintEvent(static_cast< QPaintEvent* >(e)); 01130 return true; 01131 case QEvent::MouseButtonDblClick: 01132 titlebar->mouseDoubleClickEvent(static_cast< QMouseEvent* >(e)); 01133 return true; 01134 case QEvent::MouseButtonPress: 01135 processMousePressEvent(static_cast< QMouseEvent* >(e)); 01136 return true; 01137 case QEvent::Show: 01138 showEvent(static_cast< QShowEvent* >(e)); 01139 return true; 01140 default: 01141 break; 01142 } 01143 return false; 01144 } 01145 01146 // ===================================== 01147 01148 B2Button::B2Button(B2Client *_client, QWidget *parent, 01149 const QString& tip, const int realizeBtns) 01150 : QButton(parent, 0), hover(false) 01151 { 01152 setBackgroundMode(NoBackground); 01153 setCursor(arrowCursor); 01154 realizeButtons = realizeBtns; 01155 client = _client; 01156 useMiniIcon = false; 01157 setFixedSize(buttonSize, buttonSize); 01158 QToolTip::add(this, tip); 01159 } 01160 01161 01162 QSize B2Button::sizeHint() const 01163 { 01164 return QSize(buttonSize, buttonSize); 01165 } 01166 01167 QSizePolicy B2Button::sizePolicy() const 01168 { 01169 return(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); 01170 } 01171 01172 void B2Button::drawButton(QPainter *p) 01173 { 01174 KPixmap* gradient = titleGradient[client->isActive() ? 0 : 1]; 01175 if (gradient) { 01176 p->drawTiledPixmap(0, 0, buttonSize, buttonSize, *gradient, 0, 2); 01177 } else { 01178 p->fillRect(rect(), bg); 01179 } 01180 if (useMiniIcon) { 01181 QPixmap miniIcon = client->icon().pixmap(QIconSet::Small, 01182 client->isActive() ? QIconSet::Normal : QIconSet::Disabled); 01183 p->drawPixmap((width() - miniIcon.width()) / 2, 01184 (height() - miniIcon.height()) / 2, miniIcon); 01185 } else { 01186 int type; 01187 if (client->isActive()) { 01188 if (isOn() || isDown()) 01189 type = Down; 01190 else if (hover) 01191 type = Hover; 01192 else 01193 type = Norm; 01194 } else { 01195 if (isOn() || isDown()) 01196 type = IDown; 01197 else if (hover) 01198 type = IHover; 01199 else 01200 type = INorm; 01201 } 01202 p->drawPixmap((width() - icon[type]->width()) / 2, 01203 (height() - icon[type]->height()) / 2, *icon[type]); 01204 } 01205 } 01206 01207 void B2Button::setPixmaps(int button_id) 01208 { 01209 button_id *= NumStates; 01210 for (int i = 0; i < NumStates; i++) { 01211 icon[i] = B2::pixmap[button_id + i]; 01212 } 01213 repaint(false); 01214 } 01215 01216 void B2Button::mousePressEvent(QMouseEvent * e) 01217 { 01218 last_button = e->button(); 01219 QMouseEvent me(e->type(), e->pos(), e->globalPos(), 01220 (e->button() & realizeButtons) ? LeftButton : NoButton, 01221 e->state()); 01222 QButton::mousePressEvent(&me); 01223 } 01224 01225 void B2Button::mouseReleaseEvent(QMouseEvent * e) 01226 { 01227 last_button = e->button(); 01228 QMouseEvent me(e->type(), e->pos(), e->globalPos(), 01229 (e->button() & realizeButtons) ? LeftButton : NoButton, 01230 e->state()); 01231 QButton::mouseReleaseEvent(&me); 01232 } 01233 01234 void B2Button::enterEvent(QEvent *e) 01235 { 01236 hover = true; 01237 repaint(false); 01238 QButton::enterEvent(e); 01239 } 01240 01241 void B2Button::leaveEvent(QEvent *e) 01242 { 01243 hover = false; 01244 repaint(false); 01245 QButton::leaveEvent(e); 01246 } 01247 01248 // ===================================== 01249 01250 B2Titlebar::B2Titlebar(B2Client *parent) 01251 : QWidget(parent->widget(), 0, WStyle_Customize | WRepaintNoErase), 01252 client(parent), 01253 set_x11mask(false), isfullyobscured(false), shift_move(false) 01254 { 01255 setBackgroundMode(NoBackground); 01256 captionSpacer = new QSpacerItem(buttonSize, buttonSize + 4, 01257 QSizePolicy::Expanding, QSizePolicy::Fixed); 01258 } 01259 01260 bool B2Titlebar::x11Event(XEvent *e) 01261 { 01262 if (!set_x11mask) { 01263 set_x11mask = true; 01264 XSelectInput(qt_xdisplay(), winId(), 01265 KeyPressMask | KeyReleaseMask | 01266 ButtonPressMask | ButtonReleaseMask | 01267 KeymapStateMask | 01268 ButtonMotionMask | 01269 EnterWindowMask | LeaveWindowMask | 01270 FocusChangeMask | 01271 ExposureMask | 01272 PropertyChangeMask | 01273 StructureNotifyMask | SubstructureRedirectMask | 01274 VisibilityChangeMask); 01275 } 01276 switch (e->type) { 01277 case VisibilityNotify: 01278 isfullyobscured = false; 01279 if (e->xvisibility.state == VisibilityFullyObscured) { 01280 isfullyobscured = true; 01281 client->unobscureTitlebar(); 01282 } 01283 break; 01284 default: 01285 break; 01286 } 01287 return QWidget::x11Event(e); 01288 } 01289 01290 void B2Titlebar::drawTitlebar(QPainter &p, bool state) 01291 { 01292 KPixmap* gradient = titleGradient[state ? 0 : 1]; 01293 01294 QRect t = rect(); 01295 // black titlebar frame 01296 p.setPen(Qt::black); 01297 p.drawLine(0, 0, 0, t.bottom()); 01298 p.drawLine(0, 0, t.right(), 0); 01299 p.drawLine(t.right(), 0, t.right(), t.bottom()); 01300 01301 // titlebar fill 01302 const QColorGroup cg = 01303 options()->colorGroup(KDecoration::ColorTitleBar, state); 01304 QBrush brush(cg.background()); 01305 if (gradient) brush.setPixmap(*gradient); 01306 qDrawShadeRect(&p, 1, 1, t.right() - 1, t.height() - 1, 01307 cg, false, 1, 0, &brush); 01308 01309 // and the caption 01310 p.setPen(options()->color(KDecoration::ColorFont, state)); 01311 p.setFont(options()->font(state)); 01312 t = captionSpacer->geometry(); 01313 p.drawText(t, AlignLeft | AlignVCenter, client->caption()); 01314 } 01315 01316 void B2Titlebar::recalcBuffer() 01317 { 01318 titleBuffer.resize(width(), height()); 01319 01320 QPainter p(&titleBuffer); 01321 drawTitlebar(p, true); 01322 oldTitle = caption(); 01323 } 01324 01325 void B2Titlebar::resizeEvent(QResizeEvent *) 01326 { 01327 recalcBuffer(); 01328 repaint(false); 01329 } 01330 01331 01332 void B2Titlebar::paintEvent(QPaintEvent *) 01333 { 01334 if(client->isActive()) 01335 bitBlt(this, 0, 0, &titleBuffer, 0, 0, titleBuffer.width(), 01336 titleBuffer.height(), Qt::CopyROP, true); 01337 else { 01338 QPainter p(this); 01339 drawTitlebar(p, false); 01340 } 01341 } 01342 01343 void B2Titlebar::mouseDoubleClickEvent(QMouseEvent *e) 01344 { 01345 if (e->y() < height()) { 01346 client->titlebarDblClickOperation(); 01347 } 01348 } 01349 01350 void B2Titlebar::mousePressEvent(QMouseEvent * e) 01351 { 01352 shift_move = e->state() & ShiftButton; 01353 if (shift_move) { 01354 moveOffset = e->globalPos(); 01355 } else { 01356 e->ignore(); 01357 } 01358 } 01359 01360 void B2Titlebar::mouseReleaseEvent(QMouseEvent * e) 01361 { 01362 if (shift_move) shift_move = false; 01363 else e->ignore(); 01364 } 01365 01366 void B2Titlebar::mouseMoveEvent(QMouseEvent * e) 01367 { 01368 if (shift_move) { 01369 int oldx = mapFromGlobal(moveOffset).x(); 01370 int xdiff = e->globalPos().x() - moveOffset.x(); 01371 moveOffset = e->globalPos(); 01372 if (oldx >= 0 && oldx <= rect().right()) { 01373 client->titleMoveRel(xdiff); 01374 } 01375 } else { 01376 e->ignore(); 01377 } 01378 } 01379 01380 } // namespace B2 01381 01382 #include "b2client.moc" 01383 01384 // vim: sw=4 01385
KDE Logo
This file is part of the documentation for kwin Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 13 21:47:04 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003