00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <kconfig.h>
00017 #include <kdrawutil.h>
00018 #include <kglobal.h>
00019 #include <klocale.h>
00020 #include <kpixmapeffect.h>
00021 #include <qbitmap.h>
00022 #include <qcursor.h>
00023 #include <qdrawutil.h>
00024 #include <qimage.h>
00025 #include <qlabel.h>
00026 #include <qlayout.h>
00027 #include <qtooltip.h>
00028 #include <qapplication.h>
00029
00030 #include "quartz.h"
00031
00032
00033 namespace Quartz {
00034
00035 static const unsigned char iconify_bits[] = {
00036 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00,
00037 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
00038
00039 static const unsigned char close_bits[] = {
00040 0x00, 0x00, 0x86, 0x01, 0xcc, 0x00, 0x78, 0x00, 0x30, 0x00, 0x78, 0x00,
00041 0xcc, 0x00, 0x86, 0x01, 0x00, 0x00, 0x00, 0x00};
00042
00043 static const unsigned char maximize_bits[] = {
00044 0xff, 0x01, 0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
00045 0x01, 0x01, 0x01, 0x01, 0xff, 0x01, 0x00, 0x00};
00046
00047 static const unsigned char minmax_bits[] = {
00048 0xfc, 0x00, 0xfc, 0x00, 0x84, 0x00, 0xbf, 0x00, 0xbf, 0x00, 0xe1, 0x00,
00049 0x21, 0x00, 0x21, 0x00, 0x3f, 0x00, 0x00, 0x00};
00050
00051 static const unsigned char question_bits[] = {
00052 0x00, 0x00, 0x3c, 0x00, 0x66, 0x00, 0x60, 0x00, 0x30, 0x00, 0x18, 0x00,
00053 0x00, 0x00, 0x18, 0x00, 0x18, 0x00, 0x00, 0x00};
00054
00055 static const unsigned char pindown_white_bits[] = {
00056 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x80, 0x1f, 0xa0, 0x03,
00057 0xb0, 0x01, 0x30, 0x01, 0xf0, 0x00, 0x70, 0x00, 0x20, 0x00, 0x00, 0x00,
00058 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00059
00060 static const unsigned char pindown_gray_bits[] = {
00061 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
00062 0x00, 0x0e, 0x00, 0x06, 0x00, 0x00, 0x80, 0x07, 0xc0, 0x03, 0xe0, 0x01,
00063 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00064
00065 static const unsigned char pindown_dgray_bits[] = {
00066 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xc0, 0x10, 0x70, 0x20, 0x50, 0x20,
00067 0x48, 0x30, 0xc8, 0x38, 0x08, 0x1f, 0x08, 0x18, 0x10, 0x1c, 0x10, 0x0e,
00068 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00069
00070 static const unsigned char pinup_white_bits[] = {
00071 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x11,
00072 0x3f, 0x15, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00073 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00074
00075 static const unsigned char pinup_gray_bits[] = {
00076 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00077 0x80, 0x0a, 0xbf, 0x0a, 0x80, 0x15, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
00078 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00079
00080 static const unsigned char pinup_dgray_bits[] = {
00081 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x20, 0x40, 0x31, 0x40, 0x2e,
00082 0x40, 0x20, 0x40, 0x20, 0x7f, 0x2a, 0x40, 0x3f, 0xc0, 0x31, 0xc0, 0x20,
00083 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00084
00085 static const unsigned char above_on_bits[] = {
00086 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0x30, 0x00, 0xfc, 0x00, 0x78, 0x00,
00087 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00088
00089 static const unsigned char above_off_bits[] = {
00090 0x30, 0x00, 0x78, 0x00, 0xfc, 0x00, 0x30, 0x00, 0xfe, 0x01, 0xfe, 0x01,
00091 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00092
00093 static const unsigned char below_on_bits[] = {
00094 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x78, 0x00, 0xfc, 0x00,
00095 0x30, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0x00, 0x00};
00096
00097 static const unsigned char below_off_bits[] = {
00098 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01,
00099 0x30, 0x00, 0xfc, 0x00, 0x78, 0x00, 0x30, 0x00};
00100
00101 static const unsigned char shade_on_bits[] = {
00102 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0x02, 0x01, 0x02, 0x01,
00103 0x02, 0x01, 0x02, 0x01, 0xfe, 0x01, 0x00, 0x00};
00104
00105 static const unsigned char shade_off_bits[] = {
00106 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00,
00107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
00108
00109
00111
00112
00113 bool onAllDesktopsButtonOnLeft = true;
00114 bool coloredFrame = true;
00115 bool extraSlim = false;
00116
00117 KPixmap* titleBlocks = NULL;
00118 KPixmap* ititleBlocks = NULL;
00119 KPixmap* pinDownPix = NULL;
00120 KPixmap* pinUpPix = NULL;
00121 KPixmap* ipinDownPix = NULL;
00122 KPixmap* ipinUpPix = NULL;
00123 static int normalTitleHeight;
00124 static int toolTitleHeight;
00125 static int borderWidth;
00126
00127 bool quartz_initialized = false;
00128 QuartzHandler* clientHandler;
00129
00131
00132
00133 QuartzHandler::QuartzHandler()
00134 {
00135 quartz_initialized = false;
00136 readConfig();
00137 createPixmaps();
00138 quartz_initialized = true;
00139 }
00140
00141
00142 QuartzHandler::~QuartzHandler()
00143 {
00144 quartz_initialized = false;
00145 freePixmaps();
00146 }
00147
00148
00149 KDecoration* QuartzHandler::createDecoration( KDecorationBridge* bridge )
00150 {
00151 return new QuartzClient( bridge, this );
00152 }
00153
00154
00155 bool QuartzHandler::reset(unsigned long changed)
00156 {
00157 quartz_initialized = false;
00158 freePixmaps();
00159 readConfig();
00160 createPixmaps();
00161 quartz_initialized = true;
00162
00163
00164 bool needHardReset = true;
00165 if (changed & SettingColors)
00166 {
00167 needHardReset = false;
00168 }
00169
00170 if (needHardReset) {
00171 return true;
00172 } else {
00173 resetDecorations(changed);
00174 return false;
00175 }
00176 return true;
00177 }
00178
00179
00180 bool QuartzHandler::supports( Ability ability )
00181 {
00182 switch( ability )
00183 {
00184 case AbilityAnnounceButtons:
00185 case AbilityButtonMenu:
00186 case AbilityButtonOnAllDesktops:
00187 case AbilityButtonHelp:
00188 case AbilityButtonMinimize:
00189 case AbilityButtonMaximize:
00190 case AbilityButtonClose:
00191 case AbilityButtonAboveOthers:
00192 case AbilityButtonBelowOthers:
00193 case AbilityButtonShade:
00194 return true;
00195 default:
00196 return false;
00197 };
00198 }
00199
00200
00201 void QuartzHandler::readConfig()
00202 {
00203 KConfig conf("kwinquartzrc");
00204 conf.setGroup("General");
00205 coloredFrame = conf.readBoolEntry( "UseTitleBarBorderColors", true );
00206 extraSlim = conf.readBoolEntry( "UseQuartzExtraSlim", false );
00207
00208
00209 onAllDesktopsButtonOnLeft = KDecoration::options()->titleButtonsLeft().contains( 'S' );
00210 if ( QApplication::reverseLayout() )
00211 onAllDesktopsButtonOnLeft = !onAllDesktopsButtonOnLeft;
00212 switch(options()->preferredBorderSize(this)) {
00213 case BorderLarge:
00214 borderWidth = 8;
00215 break;
00216 case BorderVeryLarge:
00217 borderWidth = 12;
00218 break;
00219 case BorderHuge:
00220 borderWidth = 18;
00221 break;
00222 case BorderVeryHuge:
00223 borderWidth = 27;
00224 break;
00225 case BorderOversized:
00226 borderWidth = 40;
00227 break;
00228 case BorderTiny:
00229 case BorderNormal:
00230 default:
00231 borderWidth = extraSlim?2:4;
00232 }
00233
00234 normalTitleHeight = QFontMetrics(options()->font(true)).height();
00235 int nTH_limit=extraSlim?14:18;
00236 normalTitleHeight = QFontMetrics(options()->font(true)).height()-(extraSlim?1:0);
00237 if (normalTitleHeight < nTH_limit) normalTitleHeight = nTH_limit;
00238 if (normalTitleHeight < borderWidth) normalTitleHeight = borderWidth;
00239
00240 toolTitleHeight = QFontMetrics(options()->font(true, true)).height();
00241 if (toolTitleHeight < 12) toolTitleHeight = 12;
00242 if (toolTitleHeight < borderWidth) toolTitleHeight = borderWidth;
00243 }
00244
00245
00246
00247
00248 void QuartzHandler::drawBlocks( KPixmap *pi, KPixmap &p, const QColor &c1, const QColor &c2 )
00249 {
00250 QPainter px;
00251
00252 px.begin( pi );
00253
00254
00255 KPixmapEffect::gradient(p, c1, c2, KPixmapEffect::HorizontalGradient);
00256
00257 int factor = (pi->height()-2)/4;
00258 int square = factor - (factor+2)/4;
00259
00260 int x = pi->width() - 5*factor - square;
00261 int y = (pi->height() - 4*factor)/2;
00262
00263 px.fillRect( x, y, square, square, c1.light(120) );
00264 px.fillRect( x, y+factor, square, square, c1 );
00265 px.fillRect( x, y+2*factor, square, square, c1.light(110) );
00266 px.fillRect( x, y+3*factor, square, square, c1 );
00267
00268 px.fillRect( x+factor, y, square, square, c1.light(110) );
00269 px.fillRect( x+factor, y+factor, square, square, c2.light(110) );
00270 px.fillRect( x+factor, y+2*factor, square, square, c1.light(120) );
00271 px.fillRect( x+factor, y+3*factor, square, square, c2.light(130) );
00272
00273 px.fillRect( x+2*factor, y+factor, square, square, c1.light(110) );
00274 px.fillRect( x+2*factor, y+2*factor, square, square, c2.light(120) );
00275 px.fillRect( x+2*factor, y+3*factor, square, square, c2.light(150) );
00276
00277 px.fillRect( x+3*factor, y, square, square, c1.dark(110) );
00278 px.fillRect( x+3*factor, y+2*factor, square, square, c2.light(120) );
00279 px.fillRect( x+3*factor, y+3*factor, square, square, c1.dark(120) );
00280
00281 px.fillRect( x+4*factor, y+factor, square, square, c1.light(110) );
00282 px.fillRect( x+4*factor, y+3*factor, square, square, c1.dark(110) );
00283
00284 px.fillRect( x+5*factor, y+2*factor, square, square, c2.light(120));
00285 px.fillRect( x+5*factor, y+3*factor, square, square, c2.light(110) );
00286 }
00287
00288
00289
00290 void QuartzHandler::createPixmaps()
00291 {
00292
00293 QColorGroup g2 = options()->colorGroup(ColorTitleBlend, true);
00294 QColor c2 = g2.background();
00295 g2 = options()->colorGroup(ColorTitleBar, true );
00296 QColor c = g2.background().light(130);
00297
00298 titleBlocks = new KPixmap();
00299 titleBlocks->resize( normalTitleHeight*25/18, normalTitleHeight );
00300 drawBlocks( titleBlocks, *titleBlocks, c, c2 );
00301
00302 g2 = options()->colorGroup(ColorTitleBlend, false);
00303 c2 = g2.background();
00304 g2 = options()->colorGroup(ColorTitleBar, false );
00305 c = g2.background().light(130);
00306
00307 ititleBlocks = new KPixmap();
00308 ititleBlocks->resize( normalTitleHeight*25/18, normalTitleHeight );
00309 drawBlocks( ititleBlocks, *ititleBlocks, c, c2 );
00310
00311
00312 QColorGroup g;
00313 QPainter p;
00314
00315 g = options()->colorGroup( onAllDesktopsButtonOnLeft ? ColorTitleBar : ColorTitleBlend, true );
00316 c = onAllDesktopsButtonOnLeft ? g.background().light(130) : g.background();
00317 g2 = options()->colorGroup( ColorButtonBg, true );
00318
00319 pinUpPix = new KPixmap();
00320 pinUpPix->resize(16, 16);
00321 p.begin( pinUpPix );
00322 p.fillRect( 0, 0, 16, 16, c);
00323 kColorBitmaps( &p, g2, 0, 1, 16, 16, true, pinup_white_bits,
00324 pinup_gray_bits, NULL, NULL, pinup_dgray_bits, NULL );
00325 p.end();
00326
00327 pinDownPix = new KPixmap();
00328 pinDownPix->resize(16, 16);
00329 p.begin( pinDownPix );
00330 p.fillRect( 0, 0, 16, 16, c);
00331 kColorBitmaps( &p, g2, 0, 1, 16, 16, true, pindown_white_bits,
00332 pindown_gray_bits, NULL, NULL, pindown_dgray_bits, NULL );
00333 p.end();
00334
00335
00336
00337 g = options()->colorGroup( onAllDesktopsButtonOnLeft ? ColorTitleBar : ColorTitleBlend, false );
00338 c = onAllDesktopsButtonOnLeft ? g.background().light(130) : g.background();
00339 g2 = options()->colorGroup( ColorButtonBg, false );
00340
00341 ipinUpPix = new KPixmap();
00342 ipinUpPix->resize(16, 16);
00343 p.begin( ipinUpPix );
00344 p.fillRect( 0, 0, 16, 16, c);
00345 kColorBitmaps( &p, g2, 0, 1, 16, 16, true, pinup_white_bits,
00346 pinup_gray_bits, NULL, NULL, pinup_dgray_bits, NULL );
00347 p.end();
00348
00349 ipinDownPix = new KPixmap();
00350 ipinDownPix->resize(16, 16);
00351 p.begin( ipinDownPix );
00352 p.fillRect( 0, 0, 16, 16, c);
00353 kColorBitmaps( &p, g2, 0, 1, 16, 16, true, pindown_white_bits,
00354 pindown_gray_bits, NULL, NULL, pindown_dgray_bits, NULL );
00355 p.end();
00356 }
00357
00358
00359 void QuartzHandler::freePixmaps()
00360 {
00361 delete titleBlocks;
00362 delete ititleBlocks;
00363
00364
00365 delete pinUpPix;
00366 delete ipinUpPix;
00367 delete pinDownPix;
00368 delete ipinDownPix;
00369 }
00370
00371
00372 QValueList< QuartzHandler::BorderSize > QuartzHandler::borderSizes() const
00373 {
00374 return QValueList< BorderSize >() << BorderNormal << BorderLarge <<
00375 BorderVeryLarge << BorderHuge << BorderVeryHuge << BorderOversized;
00376 }
00377
00378
00379 QuartzButton::QuartzButton(QuartzClient *parent, const char *name, bool largeButton,
00380 bool isLeftButton, bool isOnAllDesktopsButton, const unsigned char *bitmap,
00381 const QString& tip, const int realizeBtns)
00382 : QButton(parent->widget(), name),
00383 last_button(NoButton)
00384 {
00385 setTipText(tip);
00386 setCursor(ArrowCursor);
00387
00388
00389 setBackgroundMode( QWidget::NoBackground );
00390 setToggleButton( isOnAllDesktopsButton );
00391
00392 realizeButtons = realizeBtns;
00393
00394 deco = NULL;
00395 large = largeButton;
00396 if ( QApplication::reverseLayout() )
00397 isLeft = !isLeftButton;
00398 else
00399 isLeft = isLeftButton;
00400 isOnAllDesktops = isOnAllDesktopsButton;
00401 client = parent;
00402
00403 if ( large )
00404 setFixedSize(normalTitleHeight-2, normalTitleHeight-2);
00405 else
00406 setFixedSize(toolTitleHeight-2, toolTitleHeight-2);
00407
00408 if(bitmap)
00409 setBitmap(bitmap);
00410 }
00411
00412
00413 QuartzButton::~QuartzButton()
00414 {
00415 delete deco;
00416 }
00417
00418
00419 QSize QuartzButton::sizeHint() const
00420 {
00421 if ( large )
00422 return( QSize(normalTitleHeight-2, normalTitleHeight-2) );
00423 else
00424 return( QSize(toolTitleHeight-2, toolTitleHeight-2) );
00425 }
00426
00427
00428 void QuartzButton::setBitmap(const unsigned char *bitmap)
00429 {
00430 delete deco;
00431
00432 deco = new QBitmap(10, 10, bitmap, true);
00433 deco->setMask( *deco );
00434 repaint( false );
00435 }
00436
00437
00438 void QuartzButton::setTipText(const QString &tip) {
00439 if(KDecoration::options()->showTooltips()) {
00440 QToolTip::remove(this );
00441 QToolTip::add(this, tip );
00442 }
00443 }
00444
00445
00446 void QuartzButton::drawButton(QPainter *p)
00447 {
00448
00449 if (!quartz_initialized)
00450 return;
00451
00452 QColor c;
00453
00454 if (isLeft)
00455 c = KDecoration::options()->color(KDecoration::ColorTitleBar, client->isActive()).light(130);
00456 else
00457 c = KDecoration::options()->color(KDecoration::ColorTitleBlend, client->isActive());
00458
00459
00460 p->fillRect(0, 0, width(), height(), c );
00461
00462
00463
00464 if( deco )
00465 {
00466 int xOff = (width()-10)/2;
00467 int yOff = (height()-10)/2;
00468 p->setPen( Qt::black );
00469 p->drawPixmap(isDown() ? xOff+2: xOff+1, isDown() ? yOff+2 : yOff+1, *deco);
00470 p->setPen( KDecoration::options()->color(KDecoration::ColorButtonBg, client->isActive()).light(150) );
00471 p->drawPixmap(isDown() ? xOff+1: xOff, isDown() ? yOff+1 : yOff, *deco);
00472 } else
00473 {
00474 QPixmap btnpix;
00475 int Offset = 0;
00476
00477 if (isOnAllDesktops)
00478 {
00479 if (isDown())
00480 Offset = 1;
00481
00482
00483 if (client->isActive())
00484 btnpix = isOn() ? *pinDownPix : *pinUpPix;
00485 else
00486 btnpix = isOn() ? *ipinDownPix : *ipinUpPix;
00487
00488 } else
00489 btnpix = client->icon().pixmap( QIconSet::Small, QIconSet::Normal);
00490
00491
00492 if ( height() < 16)
00493 {
00494 QPixmap tmpPix;
00495
00496
00497 tmpPix.convertFromImage( btnpix.convertToImage().smoothScale(height(), height()));
00498 p->drawPixmap( 0, 0, tmpPix );
00499 } else {
00500 Offset += (height() - 16)/2;
00501 p->drawPixmap( Offset, Offset, btnpix );
00502 }
00503 }
00504 }
00505
00506
00507
00508 void QuartzButton::turnOn( bool isOn )
00509 {
00510 if ( isToggleButton() )
00511 setOn( isOn );
00512 }
00513
00514
00515 void QuartzButton::mousePressEvent( QMouseEvent* e )
00516 {
00517 last_button = e->button();
00518 QMouseEvent me( e->type(), e->pos(), e->globalPos(),
00519 (e->button()&realizeButtons)?LeftButton:NoButton, e->state() );
00520 QButton::mousePressEvent( &me );
00521 }
00522
00523
00524 void QuartzButton::mouseReleaseEvent( QMouseEvent* e )
00525 {
00526 last_button = e->button();
00527 QMouseEvent me( e->type(), e->pos(), e->globalPos(),
00528 (e->button()&realizeButtons)?LeftButton:NoButton, e->state() );
00529 QButton::mouseReleaseEvent( &me );
00530 }
00531
00532
00534
00535 QuartzClient::QuartzClient(KDecorationBridge* bridge, KDecorationFactory* factory)
00536 : KDecoration (bridge, factory)
00537 {
00538 }
00539
00540
00541 void QuartzClient::init()
00542 {
00543 connect( this, SIGNAL( keepAboveChanged( bool )), SLOT( keepAboveChange( bool )));
00544 connect( this, SIGNAL( keepBelowChanged( bool )), SLOT( keepBelowChange( bool )));
00545
00546 createMainWidget(WNoAutoErase | WStaticContents);
00547
00548 widget()->installEventFilter( this );
00549
00550
00551 widget()->setBackgroundMode( QWidget::NoBackground );
00552
00553
00554 for(int i=0; i < QuartzClient::BtnCount; i++)
00555 button[i] = NULL;
00556
00557
00558 if ( isTool() ) {
00559 titleHeight = toolTitleHeight;
00560 largeButtons = false;
00561 }
00562 else {
00563 titleHeight = normalTitleHeight;
00564 largeButtons = true;
00565 }
00566
00567 borderSize = borderWidth;
00568
00569
00570 QGridLayout* g = new QGridLayout(widget(), 0, 0, 0);
00571 g->setResizeMode(QLayout::FreeResize);
00572 g->addRowSpacing(0, borderSize-1);
00573 if( isPreview())
00574 g->addWidget(new QLabel( i18n( "<center><b>Quartz preview</b></center>" ), widget()), 3, 1);
00575 else
00576 g->addItem(new QSpacerItem( 0, 0 ), 3, 1);
00577
00578
00579 g->addItem( new QSpacerItem( 0, 0, QSizePolicy::Fixed,
00580 QSizePolicy::Expanding ) );
00581 g->setRowStretch(3, 10);
00582 g->addRowSpacing(2, 1);
00583 g->addRowSpacing(4, borderSize);
00584 g->addColSpacing(0, borderSize);
00585 g->addColSpacing(2, borderSize);
00586
00587
00588 hb = new QBoxLayout(0, QBoxLayout::LeftToRight, 0, 0, 0);
00589 hb->setResizeMode( QLayout::FreeResize );
00590 g->addLayout ( hb, 1, 1 );
00591
00592 addClientButtons( options()->titleButtonsLeft() );
00593
00594 titlebar = new QSpacerItem( 10, titleHeight, QSizePolicy::Expanding, QSizePolicy::Minimum );
00595 hb->addItem(titlebar);
00596 hb->addSpacing(2);
00597
00598 addClientButtons( options()->titleButtonsRight(), false );
00599
00600 hb->addSpacing(2);
00601 }
00602
00603 void QuartzClient::reset( unsigned long changed )
00604 {
00605 if (changed & SettingColors || changed & SettingFont)
00606 {
00607
00608 widget()->repaint(false);
00609 }
00610 }
00611
00612 const int SUPPORTED_WINDOW_TYPES_MASK = NET::NormalMask | NET::DesktopMask | NET::DockMask
00613 | NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask | NET::TopMenuMask
00614 | NET::UtilityMask | NET::SplashMask;
00615
00616 bool QuartzClient::isTool()
00617 {
00618 NET::WindowType type = windowType( SUPPORTED_WINDOW_TYPES_MASK );
00619 return ((type==NET::Toolbar)||(type==NET::Utility)||(type==NET::Menu));
00620 }
00621
00622
00623 void QuartzClient::addClientButtons( const QString& s, bool isLeft )
00624 {
00625 if (s.length() > 0)
00626 for(unsigned int i = 0; i < s.length(); i++)
00627 {
00628 switch( s[i].latin1() )
00629 {
00630
00631 case 'M':
00632 if (!button[BtnMenu])
00633 {
00634 button[BtnMenu] = new QuartzButton(this, "menu",
00635 largeButtons, isLeft, false, NULL, i18n("Menu"), LeftButton|RightButton);
00636 connect( button[BtnMenu], SIGNAL(pressed()),
00637 this, SLOT(menuButtonPressed()) );
00638 hb->addWidget( button[BtnMenu] );
00639 }
00640 break;
00641
00642
00643 case 'S':
00644 if (!button[BtnOnAllDesktops])
00645 {
00646 button[BtnOnAllDesktops] = new QuartzButton(this, "on_all_desktops",
00647 largeButtons, isLeft, true, NULL, isOnAllDesktops()?i18n("Not on all desktops"):i18n("On all desktops"));
00648 button[BtnOnAllDesktops]->turnOn( isOnAllDesktops() );
00649 connect( button[BtnOnAllDesktops], SIGNAL(clicked()),
00650 this, SLOT(toggleOnAllDesktops()) );
00651 hb->addSpacing(1);
00652 hb->addWidget( button[BtnOnAllDesktops] );
00653 hb->addSpacing(1);
00654 }
00655 break;
00656
00657
00658 case 'H':
00659 if( providesContextHelp() && (!button[BtnHelp]) )
00660 {
00661 button[BtnHelp] = new QuartzButton(this, "help",
00662 largeButtons, isLeft, true, question_bits, i18n("Help"));
00663 connect( button[BtnHelp], SIGNAL( clicked() ),
00664 this, SLOT(showContextHelp()));
00665 hb->addWidget( button[BtnHelp] );
00666 }
00667 break;
00668
00669
00670 case 'I':
00671 if ( (!button[BtnIconify]) && isMinimizable())
00672 {
00673 button[BtnIconify] = new QuartzButton(this, "iconify",
00674 largeButtons, isLeft, true, iconify_bits, i18n("Minimize"));
00675 connect( button[BtnIconify], SIGNAL( clicked()),
00676 this, SLOT(minimize()) );
00677 hb->addWidget( button[BtnIconify] );
00678 }
00679 break;
00680
00681
00682 case 'A':
00683 if ( (!button[BtnMax]) && isMaximizable())
00684 {
00685 button[BtnMax] = new QuartzButton(this, "maximize",
00686 largeButtons, isLeft, true, maximize_bits, i18n("Maximize"), LeftButton|MidButton|RightButton);
00687 connect( button[BtnMax], SIGNAL( clicked()),
00688 this, SLOT(slotMaximize()) );
00689 hb->addWidget( button[BtnMax] );
00690 }
00691 break;
00692
00693
00694 case 'X':
00695 if (!button[BtnClose] && isCloseable())
00696 {
00697 button[BtnClose] = new QuartzButton(this, "close",
00698 largeButtons, isLeft, true, close_bits, i18n("Close"));
00699 connect( button[BtnClose], SIGNAL( clicked()),
00700 this, SLOT(closeWindow()) );
00701 hb->addWidget( button[BtnClose] );
00702 }
00703 break;
00704
00705
00706 case 'F':
00707 if ( (!button[BtnAbove]))
00708 {
00709 button[BtnAbove] = new QuartzButton(this, "above",
00710 largeButtons, isLeft, true,
00711 keepAbove() ? above_on_bits : above_off_bits,
00712 i18n("Keep Above Others"));
00713 connect( button[BtnAbove], SIGNAL( clicked()),
00714 this, SLOT(slotAbove()) );
00715 hb->addWidget( button[BtnAbove] );
00716 }
00717 break;
00718
00719
00720 case 'B':
00721 if ( (!button[BtnBelow]))
00722 {
00723 button[BtnBelow] = new QuartzButton(this, "below",
00724 largeButtons, isLeft, true,
00725 keepBelow() ? below_on_bits : below_off_bits,
00726 i18n("Keep Below Others"));
00727 connect( button[BtnBelow], SIGNAL( clicked()),
00728 this, SLOT(slotBelow()) );
00729 hb->addWidget( button[BtnBelow] );
00730 }
00731 break;
00732
00733
00734 case 'L':
00735 if ( (!button[BtnShade]) && isShadeable())
00736 {
00737 button[BtnShade] = new QuartzButton(this, "shade",
00738 largeButtons, isLeft, true,
00739 isSetShade() ? shade_on_bits : shade_off_bits,
00740 isSetShade() ? i18n( "Unshade" ) : i18n("Shade"));
00741 connect( button[BtnShade], SIGNAL( clicked()),
00742 this, SLOT(slotShade()) );
00743 hb->addWidget( button[BtnShade] );
00744 }
00745 break;
00746 }
00747 }
00748 }
00749
00750
00751 void QuartzClient::iconChange()
00752 {
00753 if (button[BtnMenu] && button[BtnMenu]->isVisible())
00754 button[BtnMenu]->repaint(false);
00755 }
00756
00757
00758 void QuartzClient::desktopChange()
00759 {
00760 if (button[BtnOnAllDesktops])
00761 {
00762 button[BtnOnAllDesktops]->turnOn(isOnAllDesktops());
00763 button[BtnOnAllDesktops]->repaint(false);
00764 button[BtnOnAllDesktops]->setTipText(isOnAllDesktops() ? i18n("Not on all desktops") : i18n("On all desktops"));
00765 }
00766 }
00767
00768
00769 void QuartzClient::keepAboveChange( bool above )
00770 {
00771 if (button[BtnAbove]) {
00772 button[BtnAbove]->setBitmap( above ? above_on_bits : above_off_bits );
00773 button[BtnAbove]->repaint(false);
00774 }
00775 }
00776
00777
00778 void QuartzClient::keepBelowChange( bool below )
00779 {
00780 if (button[BtnBelow]) {
00781 button[BtnBelow]->setBitmap( below ? below_on_bits : below_off_bits );
00782 button[BtnBelow]->repaint(false);
00783 }
00784 }
00785
00786 void QuartzClient::shadeChange()
00787 {
00788 if (button[BtnShade]) {
00789 bool on = isSetShade();
00790 button[BtnShade]->turnOn(on);
00791 button[BtnShade]->setBitmap(on ? shade_on_bits : shade_off_bits );
00792 button[BtnShade]->repaint(false);
00793 QToolTip::remove( button[BtnShade] );
00794 QToolTip::add( button[BtnShade], on ? i18n("Unshade") : i18n("Shade"));
00795 }
00796 }
00797
00798
00799 void QuartzClient::slotMaximize()
00800 {
00801 if (button[BtnMax])
00802 {
00803 maximize(button[BtnMax]->last_button);
00804 }
00805 }
00806
00807
00808 void QuartzClient::slotAbove()
00809 {
00810 setKeepAbove( !keepAbove());
00811 button[BtnAbove]->turnOn(keepAbove());
00812 button[BtnAbove]->repaint(true);
00813 }
00814
00815
00816 void QuartzClient::slotBelow()
00817 {
00818 setKeepBelow( !keepBelow());
00819 button[BtnBelow]->turnOn(keepBelow());
00820 button[BtnBelow]->repaint(true);
00821 }
00822
00823
00824 void QuartzClient::slotShade()
00825 {
00826 setShade( !isSetShade());
00827 }
00828
00829
00830 void QuartzClient::resizeEvent( QResizeEvent* e)
00831 {
00832 calcHiddenButtons();
00833
00834 if (widget()->isVisibleToTLW())
00835 {
00836 widget()->update(widget()->rect());
00837 int dx = 0;
00838 int dy = 0;
00839
00840 if ( e->oldSize().width() != width() )
00841 dx = 32 + QABS( e->oldSize().width() - width() );
00842
00843 if ( e->oldSize().height() != height() )
00844 dy = 8 + QABS( e->oldSize().height() - height() );
00845
00846 if ( dy )
00847 widget()->update( 0, height() - dy + 1, width(), dy );
00848
00849 if ( dx )
00850 {
00851 widget()->update( width() - dx + 1, 0, dx, height() );
00852 widget()->update( QRect( QPoint(4,4), titlebar->geometry().bottomLeft() - QPoint(1,0) ) );
00853 widget()->update( QRect( titlebar->geometry().topRight(), QPoint( width() - 4, titlebar->geometry().bottom() ) ) );
00854
00855 widget()->repaint(titlebar->geometry(), false);
00856 }
00857 }
00858 }
00859
00860
00861 void QuartzClient::captionChange()
00862 {
00863 widget()->repaint( titlebar->geometry(), false );
00864 }
00865
00866
00867
00868 void QuartzClient::paintEvent( QPaintEvent* )
00869 {
00870
00871 if (!quartz_initialized)
00872 return;
00873
00874 const bool maxFull = (maximizeMode()==MaximizeFull) && !options()->moveResizeMaximizedWindows();
00875
00876 QColorGroup g;
00877 QPainter p(widget());
00878
00879
00880 QRect r(widget()->rect());
00881 int x = r.x();
00882 int y = r.y();
00883 int x2 = r.width() - 1;
00884 int y2 = r.height() - 1;
00885 int w = r.width();
00886 int h = r.height();
00887
00888
00889
00890 if( coloredFrame )
00891 g = options()->colorGroup(ColorTitleBar, isActive());
00892 else
00893 g = options()->colorGroup(ColorFrame, isActive());
00894
00895
00896 p.setPen( g.light().light(120) );
00897 p.drawLine( x, y, x2-1, y );
00898 p.drawLine( x, y+1, x, y2-1 );
00899 p.setPen( g.dark().light(120) );
00900 p.drawLine( x2, y, x2, y2 );
00901 p.drawLine( x, y2, x2, y2 );
00902
00903
00904 QColor frameColor;
00905 if ( coloredFrame)
00906 frameColor = g.background().light(130);
00907 else
00908 frameColor = g.background();
00909 if (borderSize > 2) {
00910 p.fillRect(x+1, y+1, w-2, borderSize-2, frameColor);
00911 if (!maxFull) {
00912 p.fillRect(x+1, y+h-(borderSize-1), w-2, borderSize-2, frameColor);
00913 p.fillRect(x+1, y+borderSize-1, borderSize-1, h-2*(borderSize-1), frameColor);
00914 p.fillRect(x+w-(borderSize), y+borderSize-1, borderSize-1, h-2*(borderSize-1), frameColor);
00915 }
00916 }
00917
00918
00919 p.setPen( g.background() );
00920 if (maxFull) {
00921 p.drawLine(x+1, y+titleHeight+(borderSize-1), w-2, y+titleHeight+(borderSize-1));
00922 } else {
00923 p.drawRect( x+(borderSize-1), y+titleHeight+(borderSize-1), w-2*(borderSize-1), h-titleHeight-2*(borderSize-1) );
00924 }
00925
00926
00927 p.drawLine( x+borderSize, y2-borderSize, x2-borderSize, y2-borderSize);
00928
00929
00930 p.setPen( g.light().light(160) );
00931 p.drawPoint( x, y );
00932 p.setPen( g.light().light(140) );
00933 p.drawPoint( x+1, y );
00934 p.drawPoint( x, y+1 );
00935
00936
00937
00938 r = titlebar->geometry();
00939
00940
00941 QColor c1 = options()->color(ColorTitleBar, isActive() ).light(130);
00942 QColor c2 = options()->color(ColorTitleBlend, isActive() );
00943
00944
00945 KPixmap* titleBuffer = new KPixmap;
00946 titleBuffer->resize( maxFull?w-2:(w-2*(borderSize-1)), titleHeight );
00947
00948 QPainter p2( titleBuffer, this );
00949
00950
00951 int rightoffset = r.x()+r.width()-titleBlocks->width()-borderSize;
00952
00953 p2.fillRect( 0, 0, w, r.height(), c1 );
00954 p2.fillRect( rightoffset, 0, maxFull?w-rightoffset:w-rightoffset-2*(borderSize-1), r.height(), c2 );
00955
00956
00957 if ( isActive() )
00958 p2.drawPixmap( rightoffset, 0, *titleBlocks );
00959 else
00960 p2.drawPixmap( rightoffset, 0, *ititleBlocks );
00961
00962
00963
00964 QFont fnt;
00965 if ( largeButtons ) {
00966 fnt = options()->font(true, false);
00967 } else {
00968 fnt = options()->font(true, true);
00969 fnt.setWeight( QFont::Normal );
00970 }
00971 p2.setFont( fnt );
00972
00973 p2.setPen( options()->color(ColorFont, isActive() ));
00974 p2.drawText(r.x()+4-borderSize, 0, r.width()-3, r.height(),
00975 AlignLeft | AlignVCenter, caption() );
00976 p2.end();
00977
00978 p.drawPixmap( maxFull?1:borderSize-1, borderSize-1, *titleBuffer );
00979
00980 delete titleBuffer;
00981 }
00982
00983
00984 void QuartzClient::showEvent(QShowEvent *)
00985 {
00986 calcHiddenButtons();
00987 widget()->show();
00988 }
00989
00990
00991 void QuartzClient::mouseDoubleClickEvent( QMouseEvent * e )
00992 {
00993 if (titlebar->geometry().contains( e->pos() ) )
00994 titlebarDblClickOperation();
00995 }
00996
00997
00998 void QuartzClient::maximizeChange()
00999 {
01000 if (button[BtnMax]) {
01001 button[BtnMax]->setBitmap((maximizeMode()==MaximizeFull) ? minmax_bits : maximize_bits);
01002 button[BtnMax]->setTipText((maximizeMode()==MaximizeFull) ? i18n("Restore") : i18n("Maximize"));
01003 }
01004 }
01005
01006
01007 void QuartzClient::activeChange()
01008 {
01009 for(int i=QuartzClient::BtnHelp; i < QuartzClient::BtnCount; i++)
01010 if(button[i])
01011 button[i]->repaint(false);
01012
01013 widget()->repaint(false);
01014 }
01015
01016
01017 QuartzClient::Position QuartzClient::mousePosition(const QPoint &point) const
01018 {
01019 const int corner = 3*borderSize/2 + 18;
01020 Position pos = PositionCenter;
01021
01022 QRect r(widget()->rect());
01023
01024 if(point.y() < (borderSize-1)) {
01025 if(point.x() < corner) return PositionTopLeft;
01026 else if(point.x() > (r.right()-corner)) return PositionTopRight;
01027 else return PositionTop;
01028 } else if(point.y() > (r.bottom()-borderSize)) {
01029 if(point.x() < corner) return PositionBottomLeft;
01030 else if(point.x() > (r.right()-corner)) return PositionBottomRight;
01031 else return PositionBottom;
01032 } else if(point.x() < borderSize) {
01033 if(point.y() < corner) return PositionTopLeft;
01034 else if(point.y() > (r.bottom()-corner)) return PositionBottomLeft;
01035 else return PositionLeft;
01036 } else if(point.x() > (r.right()-borderSize)) {
01037 if(point.y() < corner) return PositionTopRight;
01038 else if(point.y() > (r.bottom()-corner)) return PositionBottomRight;
01039 else return PositionRight;
01040 }
01041
01042 return pos;
01043 }
01044
01045
01046 void QuartzClient::borders(int& left, int& right, int& top, int& bottom) const
01047 {
01048 left = borderSize;
01049 right = borderSize;
01050 top = 1 + titleHeight + (borderSize-1);
01051 bottom = borderSize;
01052
01053 if ((maximizeMode()==MaximizeFull) && !options()->moveResizeMaximizedWindows()) {
01054 left = right = bottom = 0;
01055 top = 1 + titleHeight + (borderSize-1);
01056 }
01057 }
01058
01059
01060 void QuartzClient::resize( const QSize& s )
01061 {
01062 widget()->resize( s );
01063 }
01064
01065
01066 QSize QuartzClient::minimumSize() const
01067 {
01068 return widget()->minimumSize();
01069 }
01070
01071
01072
01073 void QuartzClient::calcHiddenButtons()
01074 {
01075
01076
01077 QuartzButton* btnArray[] = { button[BtnShade], button[BtnBelow], button[BtnAbove],
01078 button[BtnOnAllDesktops], button[BtnHelp], button[BtnMax],
01079 button[BtnMenu], button[BtnIconify], button[BtnClose] };
01080 const int buttons_cnt = sizeof( btnArray ) / sizeof( btnArray[ 0 ] );
01081
01082 int minwidth = largeButtons ? 180 : 140;
01083 int btn_width = largeButtons ? 16 : 10;
01084 int current_width = width();
01085 int count = 0;
01086 int i;
01087
01088
01089 while (current_width < minwidth)
01090 {
01091 current_width += btn_width;
01092 count++;
01093 }
01094
01095
01096 if (count > buttons_cnt) count = buttons_cnt;
01097
01098
01099 for(i = 0; i < count; i++)
01100 {
01101 if (btnArray[i] && btnArray[i]->isVisible() )
01102 btnArray[i]->hide();
01103 }
01104
01105
01106 for(i = count; i < buttons_cnt; i++)
01107 {
01108 if (btnArray[i] && (!btnArray[i]->isVisible()) )
01109 btnArray[i]->show();
01110 }
01111 }
01112
01113
01114
01115 void QuartzClient::menuButtonPressed()
01116 {
01117 QRect menuRect = button[BtnMenu]->rect();
01118 QPoint menuTop ( menuRect.topLeft() );
01119 QPoint menuBottom ( menuRect.bottomRight() );
01120 menuTop += QPoint(-1, 2);
01121 menuBottom += QPoint(1, 2);
01122 menuTop = button[BtnMenu]->mapToGlobal( menuTop );
01123 menuBottom = button[BtnMenu]->mapToGlobal( menuBottom );
01124 KDecorationFactory* f = factory();
01125 showWindowMenu(QRect(menuTop, menuBottom));
01126 if( !f->exists( this ))
01127 return;
01128 button[BtnMenu]->setDown(false);
01129 }
01130
01131 bool QuartzClient::eventFilter( QObject* o, QEvent* e )
01132 {
01133 if( o != widget())
01134 return false;
01135 switch( e->type())
01136 {
01137 case QEvent::Resize:
01138 resizeEvent(static_cast< QResizeEvent* >( e ) );
01139 return true;
01140 case QEvent::Paint:
01141 paintEvent(static_cast< QPaintEvent* >( e ) );
01142 return true;
01143 case QEvent::MouseButtonDblClick:
01144 mouseDoubleClickEvent(static_cast< QMouseEvent* >( e ) );
01145 return true;
01146 case QEvent::MouseButtonPress:
01147 processMousePressEvent(static_cast< QMouseEvent* >( e ) );
01148 return true;
01149 default:
01150 break;
01151 }
01152 return false;
01153 }
01154
01155 }
01156
01157
01159 extern "C"
01160 {
01161 KDE_EXPORT KDecorationFactory *create_factory()
01162 {
01163 Quartz::clientHandler = new Quartz::QuartzHandler();
01164 return Quartz::clientHandler;
01165 }
01166 }
01167
01168
01169
01170 #include "quartz.moc"
01171