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