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
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
00100
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
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:
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
00201
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
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
00279
00280 read_config(this);
00281 if (changed & SettingFont) {
00282 delete_pixmaps();
00283 create_pixmaps();
00284 needsReset = true;
00285 }
00286 redraw_pixmaps();
00287
00288 return needsReset;
00289 }
00290
00291 QValueList< B2ClientFactory::BorderSize > B2ClientFactory::borderSizes() const
00292 {
00293
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
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
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
00365 spacer = new QSpacerItem(10, thickness + (mustDrawHandle() ? 4 : 0),
00366 QSizePolicy::Expanding, QSizePolicy::Minimum);
00367 g->addItem(spacer, 3, 1);
00368
00369
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':
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':
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':
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':
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':
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':
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':
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':
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 '_':
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
00516
00517 void B2Client::calcHiddenButtons()
00518 {
00519
00520
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
00531 while (currentWidth < minWidth) {
00532 currentWidth += buttonSize + 1;
00533 count++;
00534 }
00535
00536 if (count > BtnCount) count = BtnCount;
00537
00538
00539 for (i = 0; i < count; i++) {
00540 if (btnArray[i] && btnArray[i]->isVisible())
00541 btnArray[i]->hide();
00542 }
00543
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 * )
00551 {
00552 calcHiddenButtons();
00553 titlebar->layout()->activate();
00554 positionButtons();
00555
00556
00557
00558 titleMoveAbs(bar_x_ofs);
00559 doShape();
00560
00561 widget()->repaint();
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
00583 int fHeight = height() - t.height();
00584
00585
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
00593 p.drawRect(0, t.bottom() - thickness + 1,
00594 width(), fHeight - bb + thickness);
00595
00596 if (thickness >= 2) {
00597
00598 p.drawRect(thickness - 1, t.bottom(),
00599 width() - 2 * (thickness - 1), fHeight - bDepth + 2);
00600
00601 if (thickness >= 3) {
00602
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
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
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
00655
00656
00657
00658
00659
00660
00661
00662
00663 if (titlebar->isFullyObscured()) {
00664
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
00679 if (bar_x_ofs) {
00680 mask -= QRect(0, 0, bar_x_ofs, t.height() - thickness);
00681 mask -= QRect(0, t.height() - thickness, 1, 1);
00682 }
00683 if (t.right() < width() - 1) {
00684 mask -= QRect(width() - 1,
00685 t.height() - thickness, 1, 1);
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);
00690 if (mustDrawHandle()) {
00691 mask -= QRect(0, height() - 5, 1, 1);
00692 mask -= QRect(width() - 1, height() - 1, 1, 1);
00693 mask -= QRect(width() - 40, height() - 1, 1, 1);
00694 mask -= QRect(0, height() - 4, width() - 40, 4);
00695 } else {
00696 mask -= QRect(0, height() - 1, 1, 1);
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
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))
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
00890
00891
00892
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
00901
00902
00903
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
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
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
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
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
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
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
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
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
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)
01066 cap = "XXXXX";
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
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
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
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
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 }
01381
01382 #include "b2client.moc"
01383
01384
01385