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