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