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