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