00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <kconfig.h>
00025 #include <klocale.h>
00026 #include <kiconeffect.h>
00027
00028 #include <qpainter.h>
00029 #include <qlayout.h>
00030 #include <qbitmap.h>
00031 #include <qstyle.h>
00032 #include <qtooltip.h>
00033 #include <qwidget.h>
00034 #include <qlabel.h>
00035
00036 #include <X11/Xlib.h>
00037
00038 #include "keramik.h"
00039 #include "keramik.moc"
00040
00041
00042
00043
00044
00045
00046
00047 namespace Keramik
00048 {
00049
00050 const int buttonMargin = 9;
00051 const int buttonSpacing = 4;
00052 const int iconSpacing = 5;
00053
00054
00055 const char default_left[] = "M";
00056 const char default_right[] = "HIAX";
00057
00058
00059 const unsigned char menu_bits[] = {
00060 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00061 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0xf0, 0x07, 0x00,
00062 0xe0, 0x03, 0x00, 0xc0, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
00063 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00064 0x00, 0x00, 0x00};
00065
00066 const unsigned char on_all_desktops_bits[] = {
00067 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00068 0x80, 0x01, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00, 0xf0, 0x0f, 0x00,
00069 0xf0, 0x0f, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00,
00070 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00071 0x00, 0x00, 0x00};
00072
00073 const unsigned char not_on_all_desktops_bits[] = {
00074 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00075 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00,
00076 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00077 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00078 0x00, 0x00, 0x00};
00079
00080 const unsigned char help_bits[] = {
00081 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
00082 0xf0, 0x07, 0x00, 0x30, 0x06, 0x00, 0x00, 0x07, 0x00, 0x80, 0x03, 0x00,
00083 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00,
00084 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00085 0x00, 0x00, 0x00};
00086
00087 const unsigned char minimize_bits[] = {
00088 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00089 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00090 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
00091 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00092 0x00, 0x00, 0x00};
00093
00094 const unsigned char maximize_bits[] = {
00095 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00096 0x80, 0x01, 0x00, 0xc0, 0x03, 0x00, 0xe0, 0x07, 0x00, 0xf0, 0x0f, 0x00,
00097 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
00098 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00099 0x00, 0x00, 0x00};
00100
00101 const unsigned char restore_bits[] = {
00102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00103 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00,
00104 0xf0, 0x0f, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00, 0x80, 0x01, 0x00,
00105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00106 0x00, 0x00, 0x00};
00107
00108 const unsigned char close_bits[] = {
00109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00110 0x30, 0x0c, 0x00, 0x70, 0x0e, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00,
00111 0xc0, 0x03, 0x00, 0xe0, 0x07, 0x00, 0x70, 0x0e, 0x00, 0x30, 0x0c, 0x00,
00112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00113 0x00, 0x00, 0x00};
00114
00115
00116 KeramikHandler *clientHandler = NULL;
00117 bool keramik_initialized = false;
00118
00119
00120
00121
00122
00123
00124
00125 KeramikHandler::KeramikHandler()
00126 {
00127 for ( int i = 0; i < NumTiles; i++ ) {
00128 activeTiles[i] = NULL;
00129 inactiveTiles[i] = NULL;
00130 }
00131
00132 settings_cache = NULL;
00133
00134 imageDb = KeramikImageDb::instance();
00135
00136
00137 buttonDecos[ Menu ] = new QBitmap( 17, 17, menu_bits, true );
00138 buttonDecos[ OnAllDesktops ] = new QBitmap( 17, 17, on_all_desktops_bits, true );
00139 buttonDecos[ NotOnAllDesktops ] = new QBitmap( 17, 17, not_on_all_desktops_bits, true );
00140 buttonDecos[ Help ] = new QBitmap( 17, 17, help_bits, true );
00141 buttonDecos[ Minimize ] = new QBitmap( 17, 17, minimize_bits, true );
00142 buttonDecos[ Maximize ] = new QBitmap( 17, 17, maximize_bits, true );
00143 buttonDecos[ Restore ] = new QBitmap( 17, 17, restore_bits, true );
00144 buttonDecos[ Close ] = new QBitmap( 17, 17, close_bits, true );
00145
00146
00147 for ( int i = 0; i < NumButtonDecos; i++ )
00148 buttonDecos[i]->setMask( *buttonDecos[i] );
00149
00150
00151 if ( QApplication::reverseLayout() ) {
00152 for ( int i = 0; i < Help; i++ )
00153 flip( reinterpret_cast<QPixmap**>(buttonDecos)[i] );
00154
00155 for ( int i = Help + 1; i < NumButtonDecos; i++ )
00156 flip( reinterpret_cast<QPixmap**>(buttonDecos)[i] );
00157 }
00158
00159 readConfig();
00160 createPixmaps();
00161
00162 keramik_initialized = true;
00163 }
00164
00165
00166 KeramikHandler::~KeramikHandler()
00167 {
00168 keramik_initialized = false;
00169 destroyPixmaps();
00170
00171 for ( int i = 0; i < NumButtonDecos; i++ )
00172 delete buttonDecos[i];
00173
00174 delete settings_cache;
00175
00176 KeramikImageDb::release();
00177 imageDb = NULL;
00178 clientHandler = NULL;
00179 }
00180
00181
00182 void KeramikHandler::createPixmaps()
00183 {
00184 int heightOffset;
00185 int widthOffset;
00186 switch(options()->preferredBorderSize(this)) {
00187 case BorderLarge:
00188 widthOffset = 4;
00189 heightOffset = 0;
00190 break;
00191 case BorderVeryLarge:
00192 widthOffset = 8;
00193 heightOffset = 0;
00194 break;
00195 case BorderHuge:
00196 widthOffset = 14;
00197 heightOffset = 0;
00198 break;
00199 case BorderVeryHuge:
00200 widthOffset = 23;
00201 heightOffset = 10;
00202 break;
00203 case BorderOversized:
00204 widthOffset = 36;
00205 heightOffset = 25;
00206 break;
00207 case BorderTiny:
00208 case BorderNormal:
00209 default:
00210 widthOffset = 0;
00211 heightOffset = 0;
00212 }
00213 int fontHeight = QFontMetrics(options()->font(true)).height();
00214 if (fontHeight > heightOffset + 20)
00215 heightOffset = fontHeight - 20;
00216
00217 QString size = (heightOffset < 8) ? "" : (heightOffset < 20) ? "-large" : "-huge";
00218
00219 QColor titleColor, captionColor, buttonColor;
00220 QImage *titleCenter = NULL, *captionLeft = NULL,
00221 *captionRight = NULL, *captionCenter = NULL;
00222
00223
00224
00225
00226 captionColor = KDecoration::options()->color( ColorTitleBar, true );
00227 titleColor = KDecoration::options()->color( ColorTitleBlend, true );
00228
00229
00230 activeTiles[ TitleLeft ] = loadPixmap( "titlebar-left", titleColor );
00231 activeTiles[ TitleRight ] = loadPixmap( "titlebar-right", titleColor );
00232
00233
00234
00235 titleCenter = loadImage( "titlebar-center", titleColor );
00236
00237
00238 captionLeft = loadImage( "caption-small-left", captionColor );
00239 captionRight = loadImage( "caption-small-right", captionColor );
00240 captionCenter = loadImage( "caption-small-center", captionColor );
00241
00242
00243 activeTiles[ CaptionSmallLeft ] = composite( captionLeft, titleCenter );
00244 activeTiles[ CaptionSmallRight ] = composite( captionRight, titleCenter );
00245 activeTiles[ CaptionSmallCenter ] = composite( captionCenter, titleCenter );
00246
00247 delete captionLeft;
00248 delete captionRight;
00249 delete captionCenter;
00250
00251
00252 captionLeft = loadImage( "caption-large-left", captionColor );
00253 captionRight = loadImage( "caption-large-right", captionColor );
00254 captionCenter = loadImage( "caption-large-center", captionColor );
00255
00256 activeTiles[ CaptionLargeLeft ] = composite( captionLeft, titleCenter );
00257 activeTiles[ CaptionLargeRight ] = composite( captionRight, titleCenter );
00258 activeTiles[ CaptionLargeCenter ] = composite( captionCenter, titleCenter );
00259
00260 delete captionLeft;
00261 delete captionRight;
00262 delete captionCenter;
00263
00264
00265 activeTiles[ TitleCenter ] = new QPixmap( *titleCenter );
00266
00267 delete titleCenter;
00268
00269
00270 activeTiles[ BorderLeft ] = loadPixmap( "border-left", titleColor );
00271 activeTiles[ BorderRight ] = loadPixmap( "border-right", titleColor );
00272
00273
00274 if ( largeGrabBars ) {
00275 activeTiles[ GrabBarLeft ] = loadPixmap( "grabbar-left", titleColor );
00276 activeTiles[ GrabBarRight ] = loadPixmap( "grabbar-right", titleColor );
00277 activeTiles[ GrabBarCenter ] = loadPixmap( "grabbar-center", titleColor );
00278 } else {
00279 activeTiles[ GrabBarLeft ] = loadPixmap( "bottom-left", titleColor );
00280 activeTiles[ GrabBarRight ] = loadPixmap( "bottom-right", titleColor );
00281 activeTiles[ GrabBarCenter ] = loadPixmap( "bottom-center", titleColor );
00282 }
00283
00284
00285
00286 captionColor = KDecoration::options()->color( ColorTitleBar, false );
00287 titleColor = KDecoration::options()->color( ColorTitleBlend, false );
00288
00289 inactiveTiles[ TitleLeft ] = loadPixmap( "titlebar-left", titleColor );
00290 inactiveTiles[ TitleRight ] = loadPixmap( "titlebar-right", titleColor );
00291
00292 titleCenter = loadImage( "titlebar-center", titleColor );
00293
00294 captionLeft = loadImage( "caption-small-left", captionColor );
00295 captionRight = loadImage( "caption-small-right", captionColor );
00296 captionCenter = loadImage( "caption-small-center", captionColor );
00297
00298 inactiveTiles[ CaptionSmallLeft ] = composite( captionLeft, titleCenter );
00299 inactiveTiles[ CaptionSmallRight ] = composite( captionRight, titleCenter );
00300 inactiveTiles[ CaptionSmallCenter ] = composite( captionCenter, titleCenter );
00301
00302 delete captionLeft;
00303 delete captionRight;
00304 delete captionCenter;
00305
00306 inactiveTiles[ TitleCenter ] = new QPixmap( *titleCenter );
00307
00308 delete titleCenter;
00309
00310 inactiveTiles[ BorderLeft ] = loadPixmap( "border-left", titleColor );
00311 inactiveTiles[ BorderRight ] = loadPixmap( "border-right", titleColor );
00312
00313 if ( largeGrabBars ) {
00314 inactiveTiles[ GrabBarLeft ] = loadPixmap( "grabbar-left", titleColor );
00315 inactiveTiles[ GrabBarRight ] = loadPixmap( "grabbar-right", titleColor );
00316 inactiveTiles[ GrabBarCenter ] = loadPixmap( "grabbar-center", titleColor );
00317 } else {
00318 inactiveTiles[ GrabBarLeft ] = loadPixmap( "bottom-left", titleColor );
00319 inactiveTiles[ GrabBarRight ] = loadPixmap( "bottom-right", titleColor );
00320 inactiveTiles[ GrabBarCenter ] = loadPixmap( "bottom-center", titleColor );
00321 }
00322
00323
00324
00325 buttonColor = QColor();
00326
00327 titleButtonRound = loadPixmap( "titlebutton-round"+size, buttonColor );
00328 titleButtonSquare = loadPixmap( "titlebutton-square"+size, buttonColor );
00329
00330
00331
00332
00333 if ( QApplication::reverseLayout() ) {
00334
00335
00336 flip( activeTiles[CaptionSmallLeft], activeTiles[CaptionSmallRight] );
00337 flip( inactiveTiles[CaptionSmallLeft], inactiveTiles[CaptionSmallRight] );
00338
00339 flip( activeTiles[CaptionLargeLeft], activeTiles[CaptionLargeRight] );
00340
00341 flip( activeTiles[TitleLeft], activeTiles[TitleRight] );
00342 flip( inactiveTiles[TitleLeft], inactiveTiles[TitleRight] );
00343
00344 flip( activeTiles[BorderLeft], activeTiles[BorderRight] );
00345 flip( inactiveTiles[BorderLeft], inactiveTiles[BorderRight] );
00346
00347 flip( activeTiles[GrabBarLeft], activeTiles[GrabBarRight] );
00348 flip( inactiveTiles[GrabBarLeft], inactiveTiles[GrabBarRight] );
00349
00350 flip( titleButtonRound );
00351 flip( titleButtonSquare );
00352 }
00353
00354
00355 pretile( activeTiles[ CaptionSmallCenter ], 64, Qt::Horizontal );
00356 pretile( activeTiles[ CaptionLargeCenter ], 64, Qt::Horizontal );
00357 pretile( activeTiles[ TitleCenter ], 64, Qt::Horizontal );
00358 pretile( activeTiles[ GrabBarCenter ], 128, Qt::Horizontal );
00359 pretile( activeTiles[ BorderLeft ], 128, Qt::Vertical );
00360 pretile( activeTiles[ BorderRight ], 128, Qt::Vertical );
00361
00362 pretile( inactiveTiles[ CaptionSmallCenter ], 64, Qt::Horizontal );
00363 pretile( inactiveTiles[ TitleCenter ], 64, Qt::Horizontal );
00364 pretile( inactiveTiles[ GrabBarCenter ], 128, Qt::Horizontal );
00365 pretile( inactiveTiles[ BorderLeft ], 128, Qt::Vertical );
00366 pretile( inactiveTiles[ BorderRight ], 128, Qt::Vertical );
00367
00368 if (heightOffset > 0) {
00369 addHeight (heightOffset, activeTiles[TitleLeft]);
00370 addHeight (heightOffset, activeTiles[TitleCenter]);
00371 addHeight (heightOffset, activeTiles[TitleRight]);
00372 addHeight (heightOffset, activeTiles[CaptionSmallLeft]);
00373 addHeight (heightOffset, activeTiles[CaptionSmallCenter]);
00374 addHeight (heightOffset, activeTiles[CaptionSmallRight]);
00375 addHeight (heightOffset, activeTiles[CaptionLargeLeft]);
00376 addHeight (heightOffset, activeTiles[CaptionLargeCenter]);
00377 addHeight (heightOffset, activeTiles[CaptionLargeRight]);
00378
00379 addHeight (heightOffset, inactiveTiles[TitleLeft]);
00380 addHeight (heightOffset, inactiveTiles[TitleCenter]);
00381 addHeight (heightOffset, inactiveTiles[TitleRight]);
00382 addHeight (heightOffset, inactiveTiles[CaptionSmallLeft]);
00383 addHeight (heightOffset, inactiveTiles[CaptionSmallCenter]);
00384 addHeight (heightOffset, inactiveTiles[CaptionSmallRight]);
00385 }
00386
00387 if (widthOffset > 0) {
00388 addWidth (widthOffset, activeTiles[BorderLeft], true, activeTiles[GrabBarCenter]);
00389 addWidth (widthOffset, activeTiles[BorderRight], false, activeTiles[GrabBarCenter]);
00390 addWidth (widthOffset, inactiveTiles[BorderLeft], true, inactiveTiles[GrabBarCenter]);
00391 addWidth (widthOffset, inactiveTiles[BorderRight], false, inactiveTiles[GrabBarCenter]);
00392
00393 if (largeGrabBars)
00394 widthOffset = widthOffset*3/2;
00395
00396 addHeight (widthOffset, activeTiles[GrabBarLeft]);
00397 addHeight (widthOffset, activeTiles[GrabBarCenter]);
00398 addHeight (widthOffset, activeTiles[GrabBarRight]);
00399 addHeight (widthOffset, inactiveTiles[GrabBarLeft]);
00400 addHeight (widthOffset, inactiveTiles[GrabBarCenter]);
00401 addHeight (widthOffset, inactiveTiles[GrabBarRight]);
00402 }
00403 }
00404
00405
00406
00407 void KeramikHandler::destroyPixmaps()
00408 {
00409 for ( int i = 0; i < NumTiles; i++ ) {
00410 delete activeTiles[i];
00411 delete inactiveTiles[i];
00412 activeTiles[i] = NULL;
00413 inactiveTiles[i] = NULL;
00414 }
00415
00416 delete titleButtonRound;
00417 delete titleButtonSquare;
00418 }
00419
00420
00421 void KeramikHandler::addWidth (int width, QPixmap *&pix, bool left, QPixmap *bottomPix) {
00422 int w = pix->width()+width;
00423 int h = pix->height();
00424
00425 QPixmap *tmp = new QPixmap (w, h);
00426 tmp->fill ();
00427 QPainter p;
00428 p.begin (tmp);
00429
00430 for (int i = 0; i < h; i++)
00431 p.drawPixmap (0, i, *bottomPix, i%2, 0, w,1);
00432
00433 if (left)
00434 p.drawPixmap(0, 0, *pix);
00435 else
00436 p.drawPixmap(width, 0, *pix);
00437
00438 p.end();
00439
00440 delete pix;
00441 pix = tmp;
00442 }
00443
00444
00445 void KeramikHandler::addHeight (int height, QPixmap *&pix) {
00446 int w = pix->width();
00447 int h = pix->height()+height;
00448
00449 QPixmap *tmp = new QPixmap (w, h);
00450 QPainter p;
00451 p.begin (tmp);
00452 if (pix->height() > 10) {
00453 p.drawPixmap(0, 0, *pix, 0, 0, w, 11);
00454 for (int i = 0; i < height; i+=2)
00455 p.drawPixmap(0, 11+i, *pix, 0, 11, w, 2);
00456 p.drawPixmap(0, 11+height, *pix, 0, 11, w, -1);
00457 }
00458 else {
00459 int lines = h-3;
00460 int factor = pix->height()-3;
00461 for (int i = 0; i < lines; i++)
00462 p.drawPixmap(0, i, *pix, 0, i*factor/lines, w, 1);
00463 p.drawPixmap(0, lines, *pix, 0, factor, w, 3);
00464 }
00465 p.end();
00466
00467 delete pix;
00468 pix = tmp;
00469 }
00470
00471
00472 void KeramikHandler::flip( QPixmap *&pix1, QPixmap *&pix2 )
00473 {
00474
00475 QPixmap *tmp = new QPixmap( pix1->xForm( QWMatrix(-1,0,0,1,pix1->width(),0) ) );
00476
00477 delete pix1;
00478 pix1 = new QPixmap( pix2->xForm( QWMatrix(-1,0,0,1,pix2->width(),0) ) );
00479
00480 delete pix2;
00481 pix2 = tmp;
00482 }
00483
00484
00485 void KeramikHandler::flip( QPixmap *&pix )
00486 {
00487
00488 QPixmap *tmp = new QPixmap( pix->xForm( QWMatrix(-1,0,0,1,pix->width(),0) ) );
00489 delete pix;
00490 pix = tmp;
00491 }
00492
00493
00494 void KeramikHandler::pretile( QPixmap *&pix, int size, Qt::Orientation dir )
00495 {
00496 QPixmap *newpix;
00497 QPainter p;
00498
00499 if ( dir == Qt::Horizontal )
00500 newpix = new QPixmap( size, pix->height() );
00501 else
00502 newpix = new QPixmap( pix->width(), size );
00503
00504 p.begin( newpix );
00505 p.drawTiledPixmap( newpix->rect(), *pix ) ;
00506 p.end();
00507
00508 delete pix;
00509 pix = newpix;
00510 }
00511
00512
00513 void KeramikHandler::readConfig()
00514 {
00515 KConfig *c = new KConfig( "kwinkeramikrc" );
00516
00517 c->setGroup( "General" );
00518 showIcons = c->readBoolEntry( "ShowAppIcons", true );
00519 shadowedText = c->readBoolEntry( "UseShadowedText", true );
00520 smallCaptionBubbles = c->readBoolEntry( "SmallCaptionBubbles", false );
00521 largeGrabBars = c->readBoolEntry( "LargeGrabBars", true );
00522
00523 if ( ! settings_cache ) {
00524 settings_cache = new SettingsCache;
00525 settings_cache->largeGrabBars = largeGrabBars;
00526 settings_cache->smallCaptionBubbles = smallCaptionBubbles;
00527 }
00528
00529 delete c;
00530 }
00531
00532
00533 QPixmap *KeramikHandler::composite( QImage *over, QImage *under )
00534 {
00535 QImage dest( over->width(), over->height(), 32 );
00536 int width = over->width(), height = over->height();
00537
00538
00539 Q_UINT32 *data = reinterpret_cast<Q_UINT32*>( dest.bits() );
00540 for (int i = 0; i < width * height; i++)
00541 *(data++) = 0;
00542
00543
00544 for (int y1 = height - under->height(), y2 = 0; y1 < height; y1++, y2++ )
00545 {
00546 register Q_UINT32 *dst = reinterpret_cast<Q_UINT32*>( dest.scanLine(y1) );
00547 register Q_UINT32 *src = reinterpret_cast<Q_UINT32*>( under->scanLine(y2) );
00548
00549 for ( int x = 0; x < width; x++ )
00550 *(dst++) = *(src++);
00551 }
00552
00553
00554 register Q_UINT32 *dst = reinterpret_cast<Q_UINT32*>( dest.bits() );
00555 register Q_UINT32 *src = reinterpret_cast<Q_UINT32*>( over->bits() );
00556 for ( int i = 0; i < width * height; i++ )
00557 {
00558 int r1 = qRed( *dst ), g1 = qGreen( *dst ), b1 = qBlue( *dst );
00559 int r2 = qRed( *src ), g2 = qGreen( *src ), b2 = qBlue( *src );
00560 int a = qAlpha( *src );
00561
00562 if ( a == 0xff )
00563 *dst = *src;
00564
00565 else if ( a != 0x00 )
00566 *dst = qRgba( Q_UINT8( r1 + (((r2 - r1) * a) >> 8) ),
00567 Q_UINT8( g1 + (((g2 - g1) * a) >> 8) ),
00568 Q_UINT8( b1 + (((b2 - b1) * a) >> 8) ),
00569 0xff );
00570
00571 else if ( qAlpha(*dst) == 0x00 )
00572 *dst = 0;
00573
00574 src++; dst++;
00575 }
00576
00577
00578 return new QPixmap( dest );
00579 }
00580
00581
00582 QImage *KeramikHandler::loadImage( const QString &name, const QColor &col )
00583 {
00584 if ( col.isValid() ) {
00585 QImage *img = new QImage( imageDb->image(name)->copy() );
00586 KIconEffect::colorize( *img, col, 1.0 );
00587 return img;
00588 } else
00589 return new QImage( imageDb->image(name)->copy() );
00590 }
00591
00592
00593 QPixmap *KeramikHandler::loadPixmap( const QString &name, const QColor &col )
00594 {
00595 QImage *img = loadImage( name, col );
00596 QPixmap *pix = new QPixmap( *img );
00597 delete img;
00598
00599 return pix;
00600 }
00601
00602
00603 bool KeramikHandler::reset( unsigned long changed )
00604 {
00605 keramik_initialized = false;
00606
00607 bool needHardReset = false;
00608 bool pixmapsInvalid = false;
00609
00610
00611 readConfig();
00612
00613 if ( changed & SettingBorder )
00614 {
00615 pixmapsInvalid = true;
00616 needHardReset = true;
00617 }
00618 if ( changed & SettingFont )
00619 {
00620 pixmapsInvalid = true;
00621 needHardReset = true;
00622 }
00623
00624 if ( changed & SettingColors )
00625 {
00626 pixmapsInvalid = true;
00627 }
00628
00629
00630 if ( changed & SettingButtons ) {
00631 needHardReset = true;
00632 }
00633
00634
00635 if ( changed & SettingTooltips ) {
00636 needHardReset = true;
00637 }
00638
00639 if ( (settings_cache->largeGrabBars != largeGrabBars) ) {
00640 pixmapsInvalid = true;
00641 needHardReset = true;
00642 }
00643
00644 if ( (settings_cache->smallCaptionBubbles != smallCaptionBubbles) ) {
00645 needHardReset = true;
00646 }
00647
00648
00649 settings_cache->largeGrabBars = largeGrabBars;
00650 settings_cache->smallCaptionBubbles = smallCaptionBubbles;
00651
00652
00653 if ( pixmapsInvalid ) {
00654 destroyPixmaps();
00655 createPixmaps();
00656 }
00657
00658 keramik_initialized = true;
00659
00660
00661 if ( !needHardReset )
00662 resetDecorations( changed );
00663 return needHardReset;
00664 }
00665
00666
00667 const QPixmap *KeramikHandler::tile( TilePixmap tilePix, bool active ) const
00668 {
00669 return ( active ? activeTiles[ tilePix ] : inactiveTiles[ tilePix ] );
00670 }
00671
00672 KDecoration* KeramikHandler::createDecoration( KDecorationBridge* bridge )
00673 {
00674 return new KeramikClient( bridge, this );
00675 }
00676
00677 QValueList< KeramikHandler::BorderSize > KeramikHandler::borderSizes() const
00678 {
00679 return QValueList< BorderSize >() << BorderNormal << BorderLarge <<
00680 BorderVeryLarge << BorderHuge << BorderVeryHuge << BorderOversized;
00681 }
00682
00683
00684
00685
00686
00687
00688 KeramikButton::KeramikButton( KeramikClient* c, const char *name, Button btn, const QString &tip, const int realizeBtns )
00689 : QButton( c->widget(), name ),
00690 client( c ), button( btn ), hover( false ), lastbutton( 0 )
00691 {
00692 realizeButtons = realizeBtns;
00693
00694 QToolTip::add( this, tip );
00695 setBackgroundMode( NoBackground );
00696 setCursor( arrowCursor );
00697 int size = clientHandler->roundButton()->height();
00698 setFixedSize( size, size );
00699
00700 setToggleButton( (button == OnAllDesktopsButton) );
00701 }
00702
00703
00704 KeramikButton::~KeramikButton()
00705 {
00706
00707 }
00708
00709
00710 void KeramikButton::enterEvent( QEvent *e )
00711 {
00712 QButton::enterEvent( e );
00713
00714 hover = true;
00715 repaint( false );
00716 }
00717
00718
00719 void KeramikButton::leaveEvent( QEvent *e )
00720 {
00721 QButton::leaveEvent( e );
00722
00723 hover = false;
00724 repaint( false );
00725 }
00726
00727
00728 void KeramikButton::mousePressEvent( QMouseEvent *e )
00729 {
00730 lastbutton = e->button();
00731 QMouseEvent me( e->type(), e->pos(), e->globalPos(), (e->button()&realizeButtons)?LeftButton:NoButton, e->state() );
00732 QButton::mousePressEvent( &me );
00733 }
00734
00735
00736 void KeramikButton::mouseReleaseEvent( QMouseEvent *e )
00737 {
00738 lastbutton = e->button();
00739 QMouseEvent me( e->type(), e->pos(), e->globalPos(), (e->button()&realizeButtons)?LeftButton:NoButton, e->state() );
00740 QButton::mouseReleaseEvent( &me );
00741 }
00742
00743
00744 void KeramikButton::drawButton( QPainter *p )
00745 {
00746 const QPixmap *pix;
00747 const QBitmap *deco;
00748 int size = clientHandler->roundButton()->height();
00749
00750
00751 if ( button == MenuButton || button == OnAllDesktopsButton || button == HelpButton )
00752 pix = clientHandler->roundButton();
00753 else
00754 pix = clientHandler->squareButton();
00755
00756
00757 const QPixmap *background = clientHandler->tile( TitleCenter, client->isActive() );
00758 p->drawPixmap( 0, 0, *background,
00759 0, (background->height()-size+1)/2, size, size );
00760
00761 if ( isDown() ) {
00762
00763 p->drawPixmap( QPoint(), *pix, QStyle::visualRect( QRect(2*size, 0, size, size), pix->rect() ) );
00764 p->translate( QApplication::reverseLayout() ? -1 : 1, 1 );
00765 } else if ( hover )
00766
00767 p->drawPixmap( QPoint(), *pix, QStyle::visualRect( QRect(size, 0, size, size), pix->rect() ) );
00768 else
00769
00770 p->drawPixmap( QPoint(), *pix, QStyle::visualRect( QRect(0, 0, size, size), pix->rect() ) );
00771
00772
00773
00774 switch ( button ) {
00775 case MenuButton:
00776 deco = clientHandler->buttonDeco( Menu );
00777 break;
00778
00779 case OnAllDesktopsButton:
00780 deco = clientHandler->buttonDeco( isOn() ? NotOnAllDesktops : OnAllDesktops );
00781 break;
00782
00783 case HelpButton:
00784 deco = clientHandler->buttonDeco( Help );
00785
00786
00787
00788 if ( QApplication::reverseLayout() )
00789 p->translate( 2, 0 );
00790 break;
00791
00792 case MinButton:
00793 deco = clientHandler->buttonDeco( Minimize );
00794 break;
00795
00796 case MaxButton:
00797 deco = clientHandler->buttonDeco( client->maximizeMode() == KeramikClient::MaximizeFull ? Restore : Maximize );
00798 break;
00799
00800 case CloseButton:
00801 deco = clientHandler->buttonDeco( Close );
00802 break;
00803
00804 default:
00805 deco = NULL;
00806 }
00807
00808 p->setPen( Qt::black );
00809 p->drawPixmap( (size-17)/2, (size-17)/2, *deco );
00810 }
00811
00812
00813
00814
00815
00816
00817
00818 KeramikClient::KeramikClient( KDecorationBridge* bridge, KDecorationFactory* factory )
00819 : KDecoration( bridge, factory ),
00820 activeIcon( NULL ), inactiveIcon( NULL ), captionBufferDirty( true ), maskDirty( true )
00821 {
00822 }
00823
00824 void KeramikClient::init()
00825 {
00826 createMainWidget( WStaticContents | WResizeNoErase | WRepaintNoErase );
00827 widget()->installEventFilter( this );
00828
00829
00830 widget()->setBackgroundMode( NoBackground );
00831
00832 for ( int i=0; i < NumButtons; i++ )
00833 button[i] = NULL;
00834
00835 createLayout();
00836 }
00837
00838 void KeramikClient::createLayout()
00839 {
00840
00841 QVBoxLayout *mainLayout = new QVBoxLayout( widget() );
00842 QBoxLayout *titleLayout = new QBoxLayout( 0, QBoxLayout::LeftToRight, 0, 0, 0 );
00843 QHBoxLayout *windowLayout = new QHBoxLayout();
00844
00845 largeTitlebar = ( !maximizedVertical() && clientHandler->largeCaptionBubbles() );
00846 largeCaption = ( isActive() && largeTitlebar );
00847
00848 int grabBarHeight = clientHandler->grabBarHeight();
00849 int topSpacing = ( largeTitlebar ? 4 : 1 );
00850 int leftBorderWidth = clientHandler->tile( BorderLeft, true )->width();
00851 int rightBorderWidth = clientHandler->tile( BorderRight, true )->width();
00852 topSpacer = new QSpacerItem( 10, topSpacing,
00853 QSizePolicy::Expanding, QSizePolicy::Minimum );
00854
00855 mainLayout->addItem( topSpacer );
00856
00857 mainLayout->addLayout( titleLayout );
00858 mainLayout->addLayout( windowLayout, 1 );
00859 mainLayout->addSpacing( grabBarHeight );
00860
00861 titleLayout->setSpacing( buttonSpacing );
00862
00863 titleLayout->addSpacing( buttonMargin );
00864 addButtons( titleLayout, options()->customButtonPositions() ?
00865 options()->titleButtonsLeft() : QString(default_left) );
00866
00867 titlebar = new QSpacerItem( 10, clientHandler->titleBarHeight(largeTitlebar)
00868 - topSpacing, QSizePolicy::Expanding, QSizePolicy::Minimum );
00869 titleLayout->addItem( titlebar );
00870
00871 titleLayout->addSpacing( buttonSpacing );
00872 addButtons( titleLayout, options()->customButtonPositions() ?
00873 options()->titleButtonsRight() : QString(default_right) );
00874 titleLayout->addSpacing( buttonMargin - 1 );
00875
00876 windowLayout->addSpacing( leftBorderWidth );
00877 if( isPreview())
00878 windowLayout->addWidget( new QLabel( i18n( "<center><b>Keramik</b></center>" ), widget()));
00879 else
00880 windowLayout->addItem( new QSpacerItem( 0, 0 ));
00881 windowLayout->addSpacing( rightBorderWidth );
00882 }
00883
00884
00885 KeramikClient::~KeramikClient()
00886 {
00887 delete activeIcon;
00888 delete inactiveIcon;
00889
00890 activeIcon = inactiveIcon = NULL;
00891 }
00892
00893
00894 void KeramikClient::reset( unsigned long )
00895 {
00896 if ( clientHandler->largeCaptionBubbles() && !largeTitlebar )
00897 {
00898
00899 if ( !maximizedVertical() ) {
00900 topSpacer->changeSize( 10, 4, QSizePolicy::Expanding, QSizePolicy::Minimum );
00901 largeTitlebar = true;
00902 largeCaption = isActive();
00903
00904 widget()->layout()->activate();
00905
00906
00907
00908
00909
00910 widget()->setGeometry( widget()->x(), widget()->y() - 3, width(), height() + 3 );
00911 }
00912 }
00913 else if ( !clientHandler->largeCaptionBubbles() && largeTitlebar )
00914 {
00915
00916 topSpacer->changeSize( 10, 1, QSizePolicy::Expanding, QSizePolicy::Minimum );
00917 largeTitlebar = largeCaption = false;
00918
00919 widget()->layout()->activate();
00920
00921
00922
00923 widget()->setGeometry( widget()->x(), widget()->y() + 3, width(), height() - 3 );
00924 }
00925
00926 calculateCaptionRect();
00927
00928 captionBufferDirty = maskDirty = true;
00929
00930
00931
00932 if ( widget()->isVisible() ) {
00933 widget()->repaint( false );
00934
00935 for ( int i = 0; i < NumButtons; i++ )
00936 if ( button[i] ) button[i]->repaint( false );
00937 }
00938 }
00939
00940
00941 void KeramikClient::addButtons( QBoxLayout *layout, const QString &s )
00942 {
00943 for ( uint i=0; i < s.length(); i++ )
00944 {
00945 switch ( s[i].latin1() )
00946 {
00947
00948 case 'M' :
00949 if ( !button[MenuButton] ) {
00950 button[MenuButton] = new KeramikButton( this, "menu", MenuButton, i18n("Menu"), LeftButton|RightButton );
00951 connect( button[MenuButton], SIGNAL( pressed() ), SLOT( menuButtonPressed() ) );
00952 layout->addWidget( button[MenuButton] );
00953 }
00954 break;
00955
00956
00957 case 'S' :
00958 if ( !button[OnAllDesktopsButton] ) {
00959 button[OnAllDesktopsButton] = new KeramikButton( this, "on_all_desktops",
00960 OnAllDesktopsButton, isOnAllDesktops()?i18n("Not On All Desktops"):i18n("On All Desktops") );
00961 if(isOnAllDesktops())
00962 button[OnAllDesktopsButton]->toggle();
00963 connect( button[OnAllDesktopsButton], SIGNAL( clicked() ), SLOT( toggleOnAllDesktops() ) );
00964 layout->addWidget( button[OnAllDesktopsButton] );
00965 }
00966 break;
00967
00968
00969 case 'H' :
00970 if ( !button[HelpButton] && providesContextHelp() ) {
00971 button[HelpButton] = new KeramikButton( this, "help", HelpButton, i18n("Help") );
00972 connect( button[HelpButton], SIGNAL( clicked() ), SLOT( showContextHelp() ) );
00973 layout->addWidget( button[HelpButton] );
00974 }
00975 break;
00976
00977
00978 case 'I' :
00979 if ( !button[MinButton] && isMinimizable() ) {
00980 button[MinButton] = new KeramikButton( this, "minimize", MinButton, i18n("Minimize") );
00981 connect( button[MinButton], SIGNAL( clicked() ), SLOT( minimize() ) );
00982 layout->addWidget( button[MinButton] );
00983 }
00984 break;
00985
00986
00987 case 'A' :
00988 if ( !button[MaxButton] && isMaximizable() ) {
00989 button[MaxButton] = new KeramikButton( this, "maximize", MaxButton, i18n("Maximize"), LeftButton|MidButton|RightButton );
00990 connect( button[MaxButton], SIGNAL( clicked() ), SLOT( slotMaximize() ) );
00991 layout->addWidget( button[MaxButton] );
00992 }
00993 break;
00994
00995
00996 case 'X' :
00997 if ( !button[CloseButton] && isCloseable() ) {
00998 button[CloseButton] = new KeramikButton( this, "close", CloseButton, i18n("Close") );
00999 connect( button[CloseButton], SIGNAL( clicked() ), SLOT( closeWindow() ) );
01000 layout->addWidget( button[CloseButton] );
01001 }
01002 break;
01003
01004
01005 case '_' :
01006 layout->addSpacing( buttonSpacing );
01007 break;
01008 }
01009 }
01010 }
01011
01012
01013 void KeramikClient::updateMask()
01014 {
01015 if ( !keramik_initialized )
01016 return;
01017
01018
01019
01020
01021
01022
01023 QRegion r;
01024 register int w, y = 0;
01025 int nrects;
01026
01027 if ( QApplication::reverseLayout() ) {
01028
01029
01030 if ( largeCaption && captionRect.width() >= 25 ) {
01031 register int x = captionRect.left();
01032 w = captionRect.width();
01033 r += QRegion( x + 11, y++, w - 19, 1 );
01034 r += QRegion( x + 9, y++, w - 15, 1 );
01035 r += QRegion( x + 7, y++, w - 12, 1 );
01036 } else {
01037 nrects = 8;
01038
01039
01040
01041
01042 if ( largeTitlebar )
01043 y = 3;
01044 }
01045
01046 w = width();
01047
01048
01049 r += QRegion( 9, y++, w - 17, 1 );
01050 r += QRegion( 7, y++, w - 13, 1 );
01051 r += QRegion( 5, y++, w - 9, 1 );
01052 r += QRegion( 4, y++, w - 7, 1 );
01053 r += QRegion( 3, y++, w - 5, 1 );
01054 r += QRegion( 2, y++, w - 4, 1 );
01055 r += QRegion( 1, y++, w - 2, 2 );
01056 } else {
01057
01058
01059 if ( largeCaption && captionRect.width() >= 25 ) {
01060 nrects = 11;
01061 register int x = captionRect.left();
01062 w = captionRect.width();
01063 r += QRegion( x + 8, y++, w - 19, 1 );
01064 r += QRegion( x + 6, y++, w - 15, 1 );
01065 r += QRegion( x + 5, y++, w - 12, 1 );
01066 } else {
01067 nrects = 8;
01068
01069
01070
01071
01072 if ( largeTitlebar )
01073 y = 3;
01074 }
01075
01076 w = width();
01077
01078
01079 r += QRegion( 8, y++, w - 17, 1 );
01080 r += QRegion( 6, y++, w - 13, 1 );
01081 r += QRegion( 4, y++, w - 9, 1 );
01082 r += QRegion( 3, y++, w - 7, 1 );
01083 r += QRegion( 2, y++, w - 5, 1 );
01084 r += QRegion( 2, y++, w - 4, 1 );
01085 r += QRegion( 1, y++, w - 2, 2 );
01086 }
01087
01088 y++;
01089
01090
01091 r += QRegion( 0, y, w, height() - y );
01092
01093 setMask( r, YXBanded );
01094
01095 maskDirty = false;
01096 }
01097
01098
01099 void KeramikClient::updateCaptionBuffer()
01100 {
01101 if ( !keramik_initialized )
01102 return;
01103
01104 bool active = isActive();
01105 QPixmap *icon = NULL;
01106
01107 if ( captionBuffer.size() != captionRect.size() )
01108 captionBuffer.resize( captionRect.size() );
01109
01110 if ( captionBuffer.isNull() )
01111 return;
01112
01113 QPainter p( &captionBuffer );
01114
01115
01116 if ( active && largeCaption ) {
01117 p.drawPixmap( 0, 0, *clientHandler->tile( CaptionLargeLeft, true ) );
01118 p.drawTiledPixmap( 15, 0, captionRect.width() - 30, captionRect.height(),
01119 *clientHandler->tile( CaptionLargeCenter, true ) );
01120 p.drawPixmap( captionRect.width() - 15, 0, *clientHandler->tile( CaptionLargeRight, true ) );
01121 } else {
01122 p.drawPixmap( 0, 0, *clientHandler->tile( CaptionSmallLeft, active ) );
01123 p.drawTiledPixmap( 15, 0, captionRect.width() - 30, captionRect.height(),
01124 *clientHandler->tile( CaptionSmallCenter, active ) );
01125 p.drawPixmap( captionRect.width() - 15, 0, *clientHandler->tile( CaptionSmallRight, active ) );
01126 }
01127
01128 if ( clientHandler->showAppIcons() )
01129 {
01130 if ( active ) {
01131 if ( ! activeIcon )
01132 activeIcon = new QPixmap( this->icon().pixmap( QIconSet::Small, QIconSet::Normal ));
01133 icon = activeIcon;
01134 } else {
01135 if ( ! inactiveIcon ) {
01136 QImage img = this->icon().pixmap( QIconSet::Small, QIconSet::Normal ).convertToImage();
01137 KIconEffect::semiTransparent( img );
01138 inactiveIcon = new QPixmap( img );
01139 }
01140 icon = inactiveIcon;
01141 }
01142 }
01143
01144 p.setFont( options()->font( active ) );
01145 int tw = p.fontMetrics().width( caption() ) +
01146 ( clientHandler->showAppIcons() ? 16 + iconSpacing : 0 );
01147
01148 int xpos = QMAX( (captionRect.width() - tw) / 3, 8 );
01149 QRect tr = QStyle::visualRect( QRect(xpos, 1, captionRect.width() - xpos - 10,
01150 captionRect.height() - 4), captionBuffer.rect() );
01151
01152
01153
01154
01155
01156 if ( clientHandler->showAppIcons() )
01157 {
01158 QRect iconRect = QStyle::visualRect( QRect(tr.x(),
01159 1 + (captionRect.height() - 4 - 16) / 2, 16, 16), tr );
01160 QRect r( icon->rect() );
01161 r.moveCenter( iconRect.center() );
01162
01163 if ( tr.width() > 16 ) {
01164 p.drawPixmap( r, *icon );
01165 } else {
01166 QRect sr( 0, 0, icon->width(), icon->height() );
01167
01168 if ( QApplication::reverseLayout() )
01169 sr.addCoords( icon->width() - tr.width(), 0, 0, 0 );
01170 else
01171 sr.addCoords( 0, 0, -( icon->width() - tr.width() ), 0 );
01172
01173 p.drawPixmap( r.x() + sr.x(), r.y() + sr.y(), *icon,
01174 sr.x(), sr.y(), sr.width(), sr.height() );
01175 }
01176
01177
01178
01179 if ( QApplication::reverseLayout() )
01180 tr.addCoords( 0, 0, -(16 + iconSpacing), 0 );
01181 else
01182 tr.addCoords( (16 + iconSpacing), 0, 0, 0 );
01183 }
01184
01185
01186 int flags = AlignVCenter | SingleLine;
01187 flags |= ( QApplication::reverseLayout() ? AlignRight : AlignLeft );
01188
01189 if ( clientHandler->useShadowedText() )
01190 {
01191 p.translate( QApplication::reverseLayout() ? -1 : 1, 1 );
01192 p.setPen( options()->color(ColorTitleBar, active).dark() );
01193 p.setPen( black );
01194 p.drawText( tr, flags, caption() );
01195 p.translate( QApplication::reverseLayout() ? 1 : -1, -1 );
01196 }
01197
01198 p.setPen( options()->color( ColorFont, active ) );
01199 p.drawText( tr, flags, caption() );
01200
01201 captionBufferDirty = false;
01202 }
01203
01204
01205 void KeramikClient::calculateCaptionRect()
01206 {
01207 QFontMetrics fm( options()->font(isActive()) );
01208 int cw = fm.width( caption() ) + 95;
01209 int titleBaseY = ( largeTitlebar ? 3 : 0 );
01210
01211 if ( clientHandler->showAppIcons() )
01212 cw += 16 + 4;
01213
01214 cw = QMIN( cw, titlebar->geometry().width() );
01215 captionRect = QStyle::visualRect( QRect(titlebar->geometry().x(), (largeCaption ? 0 : titleBaseY),
01216 cw, clientHandler->titleBarHeight(largeCaption) ),
01217 titlebar->geometry() );
01218 }
01219
01220
01221 void KeramikClient::captionChange()
01222 {
01223 QRect r( captionRect );
01224 calculateCaptionRect();
01225
01226 if ( r.size() != captionRect.size() )
01227 maskDirty = true;
01228
01229 captionBufferDirty = true;
01230
01231 widget()->repaint( r | captionRect, false );
01232 }
01233
01234
01235 void KeramikClient::iconChange()
01236 {
01237 if ( clientHandler->showAppIcons() ) {
01238
01239
01240 if ( activeIcon )
01241 delete activeIcon;
01242
01243 if ( inactiveIcon )
01244 delete inactiveIcon;
01245
01246 activeIcon = inactiveIcon = NULL;
01247
01248 captionBufferDirty = true;
01249 widget()->repaint( captionRect, false );
01250 }
01251 }
01252
01253
01254 void KeramikClient::activeChange()
01255 {
01256 bool active = isActive();
01257
01258
01259
01260 if ( largeTitlebar ) {
01261 largeCaption = ( active && !maximizedVertical() );
01262 calculateCaptionRect();
01263 maskDirty = true;
01264 }
01265
01266 captionBufferDirty = true;
01267
01268 widget()->repaint( false );
01269
01270 for ( int i=0; i < NumButtons; i++ )
01271 if ( button[i] ) button[i]->repaint( false );
01272 }
01273
01274
01275 void KeramikClient::maximizeChange()
01276 {
01277 if ( clientHandler->largeCaptionBubbles() )
01278 {
01279 if ( maximizeMode() & MaximizeVertical ) {
01280
01281 topSpacer->changeSize( 10, 1, QSizePolicy::Expanding, QSizePolicy::Minimum );
01282 largeCaption = largeTitlebar = false;
01283
01284 calculateCaptionRect();
01285 captionBufferDirty = maskDirty = true;
01286
01287 widget()->layout()->activate();
01288 widget()->repaint( false );
01289 } else if (( maximizeMode() & MaximizeVertical ) == 0 && !largeTitlebar ) {
01290
01291 topSpacer->changeSize( 10, 4, QSizePolicy::Expanding, QSizePolicy::Minimum );
01292 largeCaption = largeTitlebar = true;
01293
01294 calculateCaptionRect();
01295 captionBufferDirty = maskDirty = true;
01296
01297 widget()->layout()->activate();
01298 widget()->repaint( false );
01299 }
01300 }
01301
01302 if ( button[ MaxButton ] ) {
01303 QToolTip::remove( button[ MaxButton ] );
01304 QToolTip::add( button[ MaxButton ], maximizeMode() == MaximizeFull ? i18n("Restore") : i18n("Maximize") );
01305 button[ MaxButton ]->repaint();
01306 }
01307 }
01308
01309
01310 void KeramikClient::desktopChange()
01311 {
01312 if ( button[ OnAllDesktopsButton ] )
01313 {
01314 QToolTip::remove( button[ OnAllDesktopsButton ] );
01315 QToolTip::add( button[ OnAllDesktopsButton ], isOnAllDesktops() ? i18n("Not On All Desktops") : i18n("On All Desktops") );
01316 }
01317 }
01318
01319
01320 void KeramikClient::menuButtonPressed()
01321 {
01322 QPoint menuPoint ( button[MenuButton]->rect().bottomLeft().x() - 6,
01323 button[MenuButton]->rect().bottomLeft().y() + 3 );
01324 KDecorationFactory* f = factory();
01325 showWindowMenu( button[MenuButton]->mapToGlobal( menuPoint ));
01326 if( !f->exists( this ))
01327 return;
01328 button[MenuButton]->setDown(false);
01329 }
01330
01331
01332 void KeramikClient::slotMaximize()
01333 {
01334 switch ( button[ MaxButton ]->lastButton() )
01335 {
01336 case MidButton:
01337 maximize( maximizeMode() ^ MaximizeVertical );
01338 break;
01339
01340 case RightButton:
01341 maximize( maximizeMode() ^ MaximizeHorizontal );
01342 break;
01343
01344 case LeftButton:
01345 maximize( maximizeMode() == MaximizeFull ? MaximizeRestore : MaximizeFull );
01346 break;
01347 }
01348 }
01349
01350
01351 void KeramikClient::paintEvent( QPaintEvent *e )
01352 {
01353 if ( !keramik_initialized )
01354 return;
01355
01356 QPainter p( widget());
01357 QRect updateRect( e->rect() );
01358 bool active = isActive();
01359
01360 int titleBaseY = ( largeTitlebar ? 3 : 0 );
01361 int titleBarHeight = clientHandler->titleBarHeight( largeTitlebar );
01362 int grabBarHeight = clientHandler->grabBarHeight();
01363 int leftBorderWidth = clientHandler->tile( BorderLeft, active )->width();
01364 int rightBorderWidth = clientHandler->tile( BorderRight, active )->width();
01365
01366 if ( maskDirty )
01367 updateMask();
01368
01369
01370
01371 if ( updateRect.y() < titleBarHeight )
01372 {
01373 int titleBarBaseHeight = titleBarHeight - titleBaseY;
01374
01375 if ( captionBufferDirty )
01376 updateCaptionBuffer();
01377
01378
01379 if ( updateRect.x() < 15 )
01380 p.drawPixmap( 0, titleBaseY,
01381 *clientHandler->tile( TitleLeft, active ) );
01382
01383
01384 if ( updateRect.x() < captionRect.left() && updateRect.right() >= 15 ) {
01385 int x1 = QMAX( 15, updateRect.x() );
01386 int x2 = QMIN( captionRect.left(), updateRect.right() );
01387
01388 p.drawTiledPixmap( x1, titleBaseY, x2 - x1 + 1, titleBarBaseHeight,
01389 *clientHandler->tile( TitleCenter, active ) );
01390 }
01391
01392
01393 if ( updateRect.x() <= captionRect.right() && updateRect.right() > 15 ) {
01394 if ( captionRect.width() >= 25 )
01395 p.drawPixmap( captionRect.left(), active ? 0 : titleBaseY, captionBuffer );
01396 else
01397 p.drawTiledPixmap( captionRect.x(), titleBaseY, captionRect.width(),
01398 titleBarBaseHeight, *clientHandler->tile( TitleCenter, active ) );
01399 }
01400
01401
01402 if ( updateRect.right() > captionRect.right() && updateRect.x() < width() - 15 ) {
01403 int x1 = QMAX( captionRect.right() + 1, updateRect.x() );
01404 int x2 = QMIN( width() - 15, updateRect.right() );
01405
01406 p.drawTiledPixmap( x1, titleBaseY, x2 - x1 + 1, titleBarBaseHeight,
01407 *clientHandler->tile( TitleCenter, active ) );
01408 }
01409
01410
01411 if ( updateRect.right() >= width() - 15 )
01412 p.drawPixmap( width() - 15, titleBaseY,
01413 *clientHandler->tile( TitleRight, active ) );
01414 }
01415
01416
01417
01418 if ( updateRect.bottom() >= titleBarHeight &&
01419 updateRect.top() < height() - grabBarHeight )
01420 {
01421 int top = QMAX( titleBarHeight, updateRect.top() );
01422 int bottom = QMIN( updateRect.bottom(), height() - grabBarHeight );
01423
01424
01425 if ( updateRect.x() < leftBorderWidth )
01426 p.drawTiledPixmap( 0, top, leftBorderWidth, bottom - top + 1,
01427 *clientHandler->tile( BorderLeft, active ) );
01428
01429
01430 if ( e->rect().right() > width() - rightBorderWidth - 1 )
01431 p.drawTiledPixmap( width() - rightBorderWidth, top, rightBorderWidth,
01432 bottom - top + 1, *clientHandler->tile( BorderRight, active ) );
01433 }
01434
01435
01436
01437 if ( updateRect.bottom() >= height() - grabBarHeight ) {
01438
01439 if ( updateRect.x() < 9 )
01440 p.drawPixmap( 0, height() - grabBarHeight,
01441 *clientHandler->tile( GrabBarLeft, active ) );
01442
01443
01444 if ( updateRect.x() < width() - 9 ) {
01445 int x1 = QMAX( 9, updateRect.x() );
01446 int x2 = QMIN( width() - 9, updateRect.right() );
01447
01448 p.drawTiledPixmap( x1, height() - grabBarHeight, x2 - x1 + 1,
01449 grabBarHeight, *clientHandler->tile( GrabBarCenter, active ) );
01450 }
01451
01452
01453 if ( updateRect.right() > width() - 9 )
01454 p.drawPixmap( width() - 9, height() - grabBarHeight,
01455 *clientHandler->tile( GrabBarRight, active ) );
01456 }
01457
01458
01459 p.setPen( options()->color( ColorTitleBlend, active ) );
01460 p.drawLine( leftBorderWidth, height() - grabBarHeight - 1,
01461 width() - rightBorderWidth - 1, height() - grabBarHeight - 1 );
01462 }
01463
01464
01465 void KeramikClient::resizeEvent( QResizeEvent *e )
01466 {
01467
01468
01469 QRect r( captionRect );
01470 calculateCaptionRect();
01471
01472 if ( r.size() != captionRect.size() )
01473 captionBufferDirty = true;
01474
01475 maskDirty = true;
01476
01477 if ( widget()->isVisible() )
01478 {
01479 widget()->update( widget()->rect() );
01480 int dx = 0;
01481 int dy = 0;
01482
01483 if ( e->oldSize().width() != width() )
01484 dx = 32 + QABS( e->oldSize().width() - width() );
01485
01486 if ( e->oldSize().height() != height() )
01487 dy = 8 + QABS( e->oldSize().height() - height() );
01488
01489 if ( dy )
01490 widget()->update( 0, height() - dy + 1, width(), dy );
01491
01492 if ( dx )
01493 {
01494 widget()->update( width() - dx + 1, 0, dx, height() );
01495 widget()->update( QRect( QPoint(4,4), titlebar->geometry().bottomLeft() - QPoint(1,0) ) );
01496 widget()->update( QRect( titlebar->geometry().topRight(), QPoint( width() - 4,
01497 titlebar->geometry().bottom() ) ) );
01498
01499 QApplication::postEvent( this, new QPaintEvent( titlebar->geometry(), FALSE ) );
01500 }
01501 }
01502 }
01503
01504
01505 void KeramikClient::mouseDoubleClickEvent( QMouseEvent *e )
01506 {
01507 if ( QRect( 0, 0, width(), clientHandler->titleBarHeight( largeTitlebar ) ).contains( e->pos() ) )
01508 titlebarDblClickOperation();
01509 }
01510
01511
01512 KeramikClient::Position KeramikClient::mousePosition( const QPoint &p ) const
01513 {
01514 int titleBaseY = (largeTitlebar ? 3 : 0);
01515
01516 int leftBorder = clientHandler->tile( BorderLeft, true )->width();
01517 int rightBorder = width() - clientHandler->tile( BorderRight, true )->width() - 1;
01518 int bottomBorder = height() - clientHandler->grabBarHeight() - 1;
01519 int bottomCornerSize = 3*clientHandler->tile( BorderRight, true )->width()/2 + 24;
01520
01521
01522 if ( p.y() < titleBaseY + 11 ) {
01523
01524 if ( p.x() < leftBorder + 11 ) {
01525 if ( (p.y() < titleBaseY + 3 && p.x() < leftBorder + 11) ||
01526 (p.y() < titleBaseY + 6 && p.x() < leftBorder + 6) ||
01527 (p.y() < titleBaseY + 11 && p.x() < leftBorder + 3) )
01528 return PositionTopLeft;
01529 }
01530
01531
01532 if ( p.x() > rightBorder - 11 ) {
01533 if ( (p.y() < titleBaseY + 3 && p.x() > rightBorder - 11) ||
01534 (p.y() < titleBaseY + 6 && p.x() > rightBorder - 6) ||
01535 (p.y() < titleBaseY + 11 && p.x() > rightBorder - 3) )
01536 return PositionTopRight;
01537 }
01538
01539
01540 if ( p.y() <= 3 || (p.y() <= titleBaseY+3 &&
01541 (p.x() < captionRect.left() || p.x() > captionRect.right()) ) )
01542 return PositionTop;
01543
01544
01545 return PositionCenter;
01546 }
01547
01548
01549 else if ( p.y() < bottomBorder ) {
01550
01551 if ( p.x() < leftBorder ) {
01552 if ( p.y() < height() - bottomCornerSize )
01553 return PositionLeft;
01554 else
01555 return PositionBottomLeft;
01556 }
01557
01558
01559 else if ( p.x() > rightBorder ) {
01560 if ( p.y() < height() - bottomCornerSize )
01561 return PositionRight;
01562 else
01563 return PositionBottomRight;
01564 }
01565
01566
01567 return PositionCenter;
01568 }
01569
01570
01571 else {
01572
01573 if ( p.x() < bottomCornerSize )
01574 return PositionBottomLeft;
01575
01576
01577 else if ( p.x() > width() - bottomCornerSize - 1 )
01578 return PositionBottomRight;
01579
01580
01581 return PositionBottom;
01582 }
01583
01584
01585 return PositionCenter;
01586 }
01587
01588
01589 void KeramikClient::resize( const QSize& s )
01590 {
01591 widget()->resize( s );
01592 }
01593
01594
01595 void KeramikClient::borders( int& left, int& right, int& top, int& bottom ) const
01596 {
01597 int titleBarHeight = clientHandler->titleBarHeight( clientHandler->largeCaptionBubbles() );
01598 int grabBarHeight = clientHandler->grabBarHeight();
01599 int leftBorderWidth = clientHandler->tile( BorderLeft, isActive() )->width();
01600 int rightBorderWidth = clientHandler->tile( BorderRight, isActive() )->width();
01601
01602 left = leftBorderWidth;
01603 right = rightBorderWidth;
01604 top = titleBarHeight;
01605 bottom = grabBarHeight;
01606
01607 if ( ( maximizeMode() & MaximizeHorizontal ) && !options()->moveResizeMaximizedWindows())
01608 left = right = 0;
01609 if( maximizeMode() & MaximizeVertical)
01610 {
01611 top = clientHandler->titleBarHeight( false );
01612 if( !options()->moveResizeMaximizedWindows())
01613 bottom = 0;
01614 }
01615 }
01616
01617
01618 QSize KeramikClient::minimumSize() const
01619 {
01620 return widget()->minimumSize();
01621 }
01622
01623
01624 bool KeramikClient::eventFilter( QObject* o, QEvent* e )
01625 {
01626 if ( o != widget() )
01627 return false;
01628
01629 switch ( e->type() )
01630 {
01631 case QEvent::Resize:
01632 resizeEvent( static_cast< QResizeEvent* >( e ) );
01633 return true;
01634
01635 case QEvent::Paint:
01636 paintEvent( static_cast< QPaintEvent* >( e ) );
01637 return true;
01638
01639 case QEvent::MouseButtonDblClick:
01640 mouseDoubleClickEvent( static_cast< QMouseEvent* >( e ) );
01641 return true;
01642
01643 case QEvent::MouseButtonPress:
01644 processMousePressEvent( static_cast< QMouseEvent* >( e ) );
01645 return true;
01646
01647 default:
01648 return false;
01649 }
01650 }
01651
01652 }
01653
01654
01655
01656
01657
01658
01659
01660 extern "C"
01661 {
01662 KDecorationFactory *create_factory()
01663 {
01664 Keramik::clientHandler = new Keramik::KeramikHandler();
01665 return Keramik::clientHandler;
01666 }
01667 }
01668
01669
01670
01671