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 return QSize(64, 48);
00743 }
00744
00745 void B2Client::resize(const QSize& s)
00746 {
00747 widget()->resize(s);
00748 }
00749
00750 void B2Client::borders(int &left, int &right, int &top, int &bottom) const
00751 {
00752 left = right = thickness;
00753 top = buttonSize + 4;
00754 bottom = thickness + (isResizable() ? 4 : 0);
00755 }
00756
00757 void B2Client::menuButtonPressed()
00758 {
00759 QPoint menupoint = button[BtnMenu]->mapToGlobal(
00760 button[BtnMenu]->rect().bottomLeft());
00761 KDecorationFactory* f = factory();
00762 showWindowMenu(menupoint);
00763 if( !f->exists( this ))
00764 return;
00765 button[BtnMenu]->setDown(false);
00766 }
00767
00768 #if 0
00769 void B2Client::slotReset()
00770 {
00771 redraw_pixmaps();
00772 QColor c = options()->colorGroup(KDecoration::ColorTitleBar, isActive()).
00773 color(QColorGroup::Button);
00774
00775 for (int i = 0; i < BtnCount; i++)
00776 if (button[i]) {
00777 button[i]->setBg(c);
00778 button[i]->repaint(false);
00779 }
00780
00781 widget()->repaint();
00782 titlebar->recalcBuffer();
00783 titlebar->repaint(false);
00784 }
00785 #endif
00786
00787 void B2Client::unobscureTitlebar()
00788 {
00789
00790
00791
00792
00793 if (in_unobs) {
00794 return;
00795 }
00796 in_unobs = 1;
00797 QRegion reg(QRect(0,0,width(), buttonSize + 4));
00798 reg = unobscuredRegion( reg );
00799 if (!reg.isEmpty()) {
00800
00801
00802
00803
00804 titleMoveAbs(reg.boundingRect().x());
00805 }
00806 in_unobs = 0;
00807 }
00808
00809 static void redraw_pixmaps()
00810 {
00811 QColorGroup aGrp = options()->colorGroup(KDecoration::ColorButtonBg, true);
00812 QColorGroup iGrp = options()->colorGroup(KDecoration::ColorButtonBg, false);
00813
00814
00815 drawB2Rect(PIXMAP_A(P_CLOSE), aGrp.button(), false);
00816 drawB2Rect(PIXMAP_AD(P_CLOSE), aGrp.button(), true);
00817
00818 drawB2Rect(PIXMAP_I(P_CLOSE), iGrp.button(), false);
00819 drawB2Rect(PIXMAP_ID(P_CLOSE), iGrp.button(), true);
00820
00821
00822 int i;
00823 for (i = 0; i < 4; i++) {
00824 *pixmap[P_MAX*4 + i] = *pixmap[P_CLOSE*4 + i];
00825 pixmap[P_MAX*4 + i]->detach();
00826 }
00827
00828
00829 KPixmap smallBox;
00830 smallBox.resize(10, 10);
00831 KPixmap largeBox;
00832 largeBox.resize(12, 12);
00833
00834 for (i = 0; i < 4; i++) {
00835 bool is_act = (i < 2);
00836 bool is_down = ((i & 1) == 1);
00837 KPixmap *pix = pixmap[P_NORMALIZE*4 + i];
00838 drawB2Rect(&smallBox, is_act ? aGrp.button() : iGrp.button(), is_down);
00839 drawB2Rect(&largeBox, is_act ? aGrp.button() : iGrp.button(), is_down);
00840 pix->fill(options()->color(KDecoration::ColorTitleBar, is_act));
00841 bitBlt(pix, pix->width() - 12, pix->width() - 12, &largeBox,
00842 0, 0, 12, 12, Qt::CopyROP, true);
00843 bitBlt(pix, 0, 0, &smallBox, 0, 0, 10, 10, Qt::CopyROP, true);
00844
00845 bitBlt(pixmap[P_ICONIFY * 4 + i], 0, 0,
00846 &smallBox, 0, 0, 10, 10, Qt::CopyROP, true);
00847 }
00848
00849 QPainter p;
00850
00851 int pix = P_CLOSE;
00852 const unsigned char *light = close_white_bits;
00853 const unsigned char *dark = close_dgray_bits;
00854 int off = (pixmap[pix * 4]->width() - 16) / 2;
00855 for (i = 0; i < 4; i++) {
00856 p.begin(pixmap[pix * 4 + i]);
00857 kColorBitmaps(&p, (i < 2) ? aGrp : iGrp, off, off, 16, 16, true,
00858 light, NULL, NULL, dark, NULL, NULL);
00859 p.end();
00860 }
00861
00862 for (int j = 0; j < 2; j++) {
00863 switch (j) {
00864 case 1:
00865 pix = P_MENU; light = menu_white_bits; dark = menu_dgray_bits;
00866 break;
00867 default:
00868 pix = P_HELP; light = help_light_bits; dark = help_dark_bits;
00869 break;
00870 }
00871 for (i = 0; i < 4; i++) {
00872 p.begin(pixmap[pix * 4 + i]);
00873 kColorBitmaps(&p, (i < 2) ? aGrp : iGrp, 0, 0, 16, 16, true,
00874 light, NULL, NULL, dark, NULL, NULL);
00875 p.end();
00876 }
00877 }
00878
00879
00880 for (i = 0; i < 4; i++) {
00881 const unsigned char *white = (i&1) ? pindown_white_bits : pinup_white_bits;
00882 const unsigned char *gray = (i&1) ? pindown_gray_bits : pinup_gray_bits;
00883 const unsigned char *dgray = (i&1) ? pindown_dgray_bits : pinup_dgray_bits;
00884 p.begin(pixmap[P_PINUP*4 + i]);
00885 kColorBitmaps(&p, (i<2)?aGrp:iGrp, 0, 0, 16, 16, true, white,
00886 gray, NULL, dgray, NULL, NULL);
00887 p.end();
00888 }
00889
00890
00891 if (QPixmap::defaultDepth() > 8) {
00892 QColor titleColor[4] = {
00893 options()->color(KDecoration::ColorTitleBar, true),
00894 options()->color(KDecoration::ColorFrame, true),
00895
00896 options()->color(KDecoration::ColorTitleBlend, false),
00897 options()->color(KDecoration::ColorTitleBar, false)
00898 };
00899
00900 if (colored_frame) {
00901 titleColor[0] = options()->color(KDecoration::ColorTitleBlend, true);
00902 titleColor[1] = options()->color(KDecoration::ColorTitleBar, true);
00903 }
00904
00905 for (i = 0; i < 2; i++) {
00906 if (titleColor[2 * i] != titleColor[2 * i + 1]) {
00907 if (!titleGradient[i]) {
00908 titleGradient[i] = new KPixmap;
00909 }
00910 titleGradient[i]->resize(64, buttonSize + 3);
00911 KPixmapEffect::gradient(*titleGradient[i],
00912 titleColor[2 * i], titleColor[2 * i + 1],
00913 KPixmapEffect::VerticalGradient);
00914 } else {
00915 delete titleGradient[i];
00916 titleGradient[i] = 0;
00917 }
00918 }
00919 }
00920 }
00921
00922 void B2Client::positionButtons()
00923 {
00924 QFontMetrics fm(options()->font(isActive()));
00925 QString cap = caption();
00926 if (cap.length() < 5)
00927 cap = "XXXXX";
00928 int textLen = fm.width( cap );
00929
00930 QRect t = titlebar->captionSpacer->geometry();
00931 int titleWidth = titlebar->width() - t.width() + textLen+2;
00932 if (titleWidth > width()) titleWidth=width();
00933
00934 titlebar->resize(titleWidth, buttonSize + 4);
00935 titlebar->move(bar_x_ofs, 0);
00936 }
00937
00938
00939
00940 static QRect *visible_bound;
00941 static QPointArray bound_shape;
00942
00943 bool B2Client::drawbound(const QRect& geom, bool clear)
00944 {
00945 if (clear) {
00946 if (!visible_bound) return true;
00947 }
00948
00949 if (!visible_bound) {
00950 visible_bound = new QRect(geom);
00951 QRect t = titlebar->geometry();
00952 int frameTop = geom.top() + t.bottom();
00953 int barLeft = geom.left() + bar_x_ofs;
00954 int barRight = barLeft + t.width() - 1;
00955 if (barRight > geom.right()) barRight = geom.right();
00956
00957 bound_shape.putPoints(0, 8,
00958 geom.left(), frameTop,
00959 barLeft, frameTop,
00960 barLeft, geom.top(),
00961 barRight, geom.top(),
00962 barRight, frameTop,
00963 geom.right(), frameTop,
00964 geom.right(), geom.bottom(),
00965 geom.left(), geom.bottom());
00966 } else {
00967 *visible_bound = geom;
00968 }
00969 QPainter p(workspaceWidget());
00970 p.setPen(QPen(Qt::white, 5));
00971 p.setRasterOp(Qt::XorROP);
00972 p.drawPolygon(bound_shape);
00973
00974 if (clear) {
00975 delete visible_bound;
00976 visible_bound = 0;
00977 }
00978 return true;
00979 }
00980
00981 bool B2Client::eventFilter(QObject *o, QEvent *e)
00982 {
00983 if (o != widget())
00984 return false;
00985 switch (e->type()) {
00986 case QEvent::Resize:
00987 resizeEvent(static_cast< QResizeEvent* >(e));
00988 return true;
00989 case QEvent::Paint:
00990 paintEvent(static_cast< QPaintEvent* >(e));
00991 return true;
00992 case QEvent::MouseButtonDblClick:
00993 titlebar->mouseDoubleClickEvent(static_cast< QMouseEvent* >(e));
00994 return true;
00995 case QEvent::MouseButtonPress:
00996 processMousePressEvent(static_cast< QMouseEvent* >(e));
00997 return true;
00998 case QEvent::Show:
00999 showEvent(static_cast< QShowEvent* >(e));
01000 return true;
01001 default:
01002 break;
01003 }
01004 return false;
01005 }
01006
01007
01008
01009 B2Button::B2Button(B2Client *_client, QWidget *parent, const QString& tip, const int realizeBtns)
01010 : QButton(parent, 0)
01011 {
01012 setBackgroundMode(NoBackground);
01013 realizeButtons = realizeBtns;
01014 client = _client;
01015 useMiniIcon = false;
01016 setFixedSize(buttonSize, buttonSize);
01017 QToolTip::add(this, tip);
01018 }
01019
01020
01021 QSize B2Button::sizeHint() const
01022 {
01023 return QSize(buttonSize, buttonSize);
01024 }
01025
01026 QSizePolicy B2Button::sizePolicy() const
01027 {
01028 return(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
01029 }
01030
01031 void B2Button::drawButton(QPainter *p)
01032 {
01033 KPixmap* gradient = titleGradient[client->isActive() ? 0 : 1];
01034 if (gradient) {
01035 p->drawTiledPixmap(0, 0, buttonSize, buttonSize, *gradient, 0, 2);
01036 } else {
01037 p->fillRect(rect(), bg);
01038 }
01039 if (useMiniIcon) {
01040 QPixmap miniIcon = client->icon().pixmap(QIconSet::Small,
01041 client->isActive() ? QIconSet::Normal : QIconSet::Disabled);
01042 p->drawPixmap((width()-miniIcon.width())/2,
01043 (height()-miniIcon.height())/2, miniIcon);
01044 }
01045 else{
01046 if(client->isActive()){
01047 if (isDown())
01048 p->drawPixmap((width()-pDown->width())/2,
01049 (height()-pDown->height())/2, *pDown);
01050 else
01051 p->drawPixmap((width()-pNorm->width())/2,
01052 (height()-pNorm->height())/2, *pNorm);
01053 }
01054 else{
01055 if (isDown())
01056 p->drawPixmap((width()-pDown->width())/2,
01057 (height()-pDown->height())/2, *iDown);
01058 else
01059 p->drawPixmap((width()-pNorm->width())/2,
01060 (height()-pNorm->height())/2, *iNorm);
01061 }
01062 }
01063 }
01064
01065 void B2Button::setPixmaps(KPixmap *pix, KPixmap *pixDown, KPixmap *iPix,
01066 KPixmap *iPixDown)
01067 {
01068 pNorm = pix;
01069 pDown = pixDown;
01070 iNorm = iPix;
01071 iDown = iPixDown;
01072 repaint(false);
01073 }
01074
01075 void B2Button::setPixmaps(int button_id)
01076 {
01077 button_id *= 4;
01078 setPixmaps(B2::pixmap[button_id], B2::pixmap[button_id+1],
01079 B2::pixmap[button_id+2], B2::pixmap[button_id+3]);
01080 }
01081
01082 void B2Button::mousePressEvent( QMouseEvent* e )
01083 {
01084 last_button = e->button();
01085 QMouseEvent me(e->type(), e->pos(), e->globalPos(),
01086 (e->button()&realizeButtons)?LeftButton:NoButton, e->state());
01087 QButton::mousePressEvent(&me);
01088 }
01089
01090 void B2Button::mouseReleaseEvent( QMouseEvent* e )
01091 {
01092 last_button = e->button();
01093 QMouseEvent me(e->type(), e->pos(), e->globalPos(),
01094 (e->button()&realizeButtons)?LeftButton:NoButton, e->state());
01095 QButton::mouseReleaseEvent(&me);
01096 }
01097
01098
01099
01100 B2Titlebar::B2Titlebar(B2Client *parent)
01101 : QWidget(parent->widget(), 0, WStyle_Customize | WRepaintNoErase),
01102 client(parent),
01103 set_x11mask(false), isfullyobscured(false), shift_move(false)
01104 {
01105 setBackgroundMode(NoBackground);
01106 captionSpacer = new QSpacerItem(10, buttonSize + 4,
01107 QSizePolicy::Expanding, QSizePolicy::Fixed);
01108 }
01109
01110 bool B2Titlebar::x11Event(XEvent *e)
01111 {
01112 if (!set_x11mask) {
01113 set_x11mask = true;
01114 XSelectInput(qt_xdisplay(), winId(),
01115 KeyPressMask | KeyReleaseMask |
01116 ButtonPressMask | ButtonReleaseMask |
01117 KeymapStateMask |
01118 ButtonMotionMask |
01119 EnterWindowMask | LeaveWindowMask |
01120 FocusChangeMask |
01121 ExposureMask |
01122 PropertyChangeMask |
01123 StructureNotifyMask | SubstructureRedirectMask |
01124 VisibilityChangeMask);
01125 }
01126 switch ( e->type ) {
01127 case VisibilityNotify:
01128 isfullyobscured = false;
01129 if (e->xvisibility.state == VisibilityFullyObscured) {
01130 isfullyobscured = true;
01131 client->unobscureTitlebar();
01132 }
01133 break;
01134 default:
01135 break;
01136 }
01137 return QWidget::x11Event(e);
01138 }
01139
01140 void B2Titlebar::drawTitlebar(QPainter &p, bool state)
01141 {
01142 KPixmap* gradient = titleGradient[state ? 0 : 1];
01143
01144 QRect t = rect();
01145
01146 p.setPen(Qt::black);
01147 p.drawLine(0, 0, 0, t.bottom());
01148 p.drawLine(0, 0, t.right(), 0);
01149 p.drawLine(t.right(), 0, t.right(), t.bottom());
01150
01151
01152 const QColorGroup cg =
01153 options()->colorGroup(KDecoration::ColorTitleBar, state);
01154 QBrush brush(cg.background());
01155 if (gradient) brush.setPixmap(*gradient);
01156 qDrawShadeRect(&p, 1, 1, t.right() - 1, t.height() - 1,
01157 cg, false, 1, 0, &brush);
01158
01159
01160 p.setPen(options()->color(KDecoration::ColorFont, state));
01161 p.setFont(options()->font(state));
01162 t = captionSpacer->geometry();
01163 p.drawText(t, AlignLeft | AlignVCenter, client->caption());
01164 }
01165
01166 void B2Titlebar::recalcBuffer()
01167 {
01168 QFontMetrics fm(options()->font(true));
01169 titleBuffer.resize(width(), height());
01170
01171 QPainter p(&titleBuffer);
01172 drawTitlebar(p, true);
01173 oldTitle = caption();
01174 }
01175
01176 void B2Titlebar::resizeEvent(QResizeEvent *)
01177 {
01178 recalcBuffer();
01179 repaint(false);
01180 }
01181
01182
01183 void B2Titlebar::paintEvent(QPaintEvent *)
01184 {
01185 if(client->isActive())
01186 bitBlt(this, 0, 0, &titleBuffer, 0, 0, titleBuffer.width(),
01187 titleBuffer.height(), Qt::CopyROP, true);
01188 else {
01189 QPainter p(this);
01190 drawTitlebar(p, false);
01191 }
01192 }
01193
01194 void B2Titlebar::mouseDoubleClickEvent(QMouseEvent *e)
01195 {
01196 if (e->y() < height()) {
01197 client->titlebarDblClickOperation();
01198 }
01199 }
01200
01201 void B2Titlebar::mousePressEvent( QMouseEvent * e )
01202 {
01203 shift_move = e->state() & ShiftButton;
01204 if (shift_move) {
01205 moveOffset = e->globalPos();
01206 } else {
01207 e->ignore();
01208 }
01209 }
01210
01211 void B2Titlebar::mouseReleaseEvent( QMouseEvent * e )
01212 {
01213 if (shift_move) shift_move = false;
01214 else e->ignore();
01215 }
01216
01217 void B2Titlebar::mouseMoveEvent( QMouseEvent * e )
01218 {
01219 if (shift_move) {
01220 int oldx = mapFromGlobal(moveOffset).x();
01221 int xdiff = e->globalPos().x() - moveOffset.x();
01222 moveOffset = e->globalPos();
01223 if (oldx >= 0 && oldx <= rect().right()) {
01224 client->titleMoveRel(xdiff);
01225 }
01226 } else {
01227 e->ignore();
01228 }
01229 }
01230
01231 }
01232
01233 #include "b2client.moc"
01234
01235
01236