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 const QPixmap *KeramikHandler::tile( TilePixmap tilePix, bool active ) const
00714 {
00715 return ( active ? activeTiles[ tilePix ] : inactiveTiles[ tilePix ] );
00716 }
00717
00718 KDecoration* KeramikHandler::createDecoration( KDecorationBridge* bridge )
00719 {
00720 return new KeramikClient( bridge, this );
00721 }
00722
00723 QValueList< KeramikHandler::BorderSize > KeramikHandler::borderSizes() const
00724 {
00725 return QValueList< BorderSize >() << BorderNormal << BorderLarge <<
00726 BorderVeryLarge << BorderHuge << BorderVeryHuge << BorderOversized;
00727 }
00728
00729
00730
00731
00732
00733
00734 KeramikButton::KeramikButton( KeramikClient* c, const char *name, Button btn, const QString &tip, const int realizeBtns )
00735 : QButton( c->widget(), name ),
00736 client( c ), button( btn ), hover( false ), lastbutton( NoButton )
00737 {
00738 realizeButtons = realizeBtns;
00739
00740 QToolTip::add( this, tip );
00741 setBackgroundMode( NoBackground );
00742 setCursor( arrowCursor );
00743 int size = clientHandler->roundButton()->height();
00744 setFixedSize( size, size );
00745
00746 setToggleButton( (button == OnAllDesktopsButton) );
00747 }
00748
00749
00750 KeramikButton::~KeramikButton()
00751 {
00752
00753 }
00754
00755
00756 void KeramikButton::enterEvent( QEvent *e )
00757 {
00758 QButton::enterEvent( e );
00759
00760 hover = true;
00761 repaint( false );
00762 }
00763
00764
00765 void KeramikButton::leaveEvent( QEvent *e )
00766 {
00767 QButton::leaveEvent( e );
00768
00769 hover = false;
00770 repaint( false );
00771 }
00772
00773
00774 void KeramikButton::mousePressEvent( QMouseEvent *e )
00775 {
00776 lastbutton = e->button();
00777 QMouseEvent me( e->type(), e->pos(), e->globalPos(), (e->button()&realizeButtons)?LeftButton:NoButton, e->state() );
00778 QButton::mousePressEvent( &me );
00779 }
00780
00781
00782 void KeramikButton::mouseReleaseEvent( QMouseEvent *e )
00783 {
00784 lastbutton = e->button();
00785 QMouseEvent me( e->type(), e->pos(), e->globalPos(), (e->button()&realizeButtons)?LeftButton:NoButton, e->state() );
00786 QButton::mouseReleaseEvent( &me );
00787 }
00788
00789
00790 void KeramikButton::drawButton( QPainter *p )
00791 {
00792 const QPixmap *pix;
00793 const QBitmap *deco;
00794 int size = clientHandler->roundButton()->height();
00795
00796
00797 if ( button == MenuButton || button == OnAllDesktopsButton || button == HelpButton )
00798 pix = clientHandler->roundButton();
00799 else
00800 pix = clientHandler->squareButton();
00801
00802
00803 const QPixmap *background = clientHandler->tile( TitleCenter, client->isActive() );
00804 p->drawPixmap( 0, 0, *background,
00805 0, (background->height()-size+1)/2, size, size );
00806
00807 if ( isDown() ) {
00808
00809 p->drawPixmap( QPoint(), *pix, QStyle::visualRect( QRect(2*size, 0, size, size), pix->rect() ) );
00810 p->translate( QApplication::reverseLayout() ? -1 : 1, 1 );
00811 } else if ( hover )
00812
00813 p->drawPixmap( QPoint(), *pix, QStyle::visualRect( QRect(size, 0, size, size), pix->rect() ) );
00814 else
00815
00816 p->drawPixmap( QPoint(), *pix, QStyle::visualRect( QRect(0, 0, size, size), pix->rect() ) );
00817
00818
00819
00820 switch ( button ) {
00821 case MenuButton:
00822 deco = clientHandler->buttonDeco( Menu );
00823 break;
00824
00825 case OnAllDesktopsButton:
00826 deco = clientHandler->buttonDeco( client->isOnAllDesktops() ? NotOnAllDesktops : OnAllDesktops );
00827 break;
00828
00829 case HelpButton:
00830 deco = clientHandler->buttonDeco( Help );
00831
00832
00833
00834 if ( QApplication::reverseLayout() )
00835 p->translate( 2, 0 );
00836 break;
00837
00838 case MinButton:
00839 deco = clientHandler->buttonDeco( Minimize );
00840 break;
00841
00842 case MaxButton:
00843 deco = clientHandler->buttonDeco( client->maximizeMode() == KeramikClient::MaximizeFull ? Restore : Maximize );
00844 break;
00845
00846 case CloseButton:
00847 deco = clientHandler->buttonDeco( Close );
00848 break;
00849
00850 case AboveButton:
00851 deco = clientHandler->buttonDeco( client->keepAbove() ? AboveOn : AboveOff );
00852 break;
00853
00854 case BelowButton:
00855 deco = clientHandler->buttonDeco( client->keepBelow() ? BelowOn : BelowOff );
00856 break;
00857
00858 case ShadeButton:
00859 deco = clientHandler->buttonDeco( client->isSetShade() ? ShadeOn : ShadeOff );
00860 break;
00861
00862 default:
00863 deco = NULL;
00864 }
00865
00866 p->setPen( Qt::black );
00867 p->drawPixmap( (size-17)/2, (size-17)/2, *deco );
00868 }
00869
00870
00871
00872
00873
00874
00875
00876 KeramikClient::KeramikClient( KDecorationBridge* bridge, KDecorationFactory* factory )
00877 : KDecoration( bridge, factory ),
00878 activeIcon( NULL ), inactiveIcon( NULL ), captionBufferDirty( true ), maskDirty( true )
00879 {
00880 }
00881
00882 void KeramikClient::init()
00883 {
00884 connect( this, SIGNAL( keepAboveChanged( bool )), SLOT( keepAboveChange( bool )));
00885 connect( this, SIGNAL( keepBelowChanged( bool )), SLOT( keepBelowChange( bool )));
00886
00887 createMainWidget( WStaticContents | WResizeNoErase | WRepaintNoErase );
00888 widget()->installEventFilter( this );
00889
00890
00891 widget()->setBackgroundMode( NoBackground );
00892
00893 for ( int i=0; i < NumButtons; i++ )
00894 button[i] = NULL;
00895
00896 createLayout();
00897 }
00898
00899 void KeramikClient::createLayout()
00900 {
00901
00902 QVBoxLayout *mainLayout = new QVBoxLayout( widget() );
00903 QBoxLayout *titleLayout = new QBoxLayout( 0, QBoxLayout::LeftToRight, 0, 0, 0 );
00904 QHBoxLayout *windowLayout = new QHBoxLayout();
00905
00906 largeTitlebar = ( !maximizedVertical() && clientHandler->largeCaptionBubbles() );
00907 largeCaption = ( isActive() && largeTitlebar );
00908
00909 int grabBarHeight = clientHandler->grabBarHeight();
00910 int topSpacing = ( largeTitlebar ? 4 : 1 );
00911 int leftBorderWidth = clientHandler->tile( BorderLeft, true )->width();
00912 int rightBorderWidth = clientHandler->tile( BorderRight, true )->width();
00913 topSpacer = new QSpacerItem( 10, topSpacing,
00914 QSizePolicy::Expanding, QSizePolicy::Minimum );
00915
00916 mainLayout->addItem( topSpacer );
00917
00918 mainLayout->addLayout( titleLayout );
00919 mainLayout->addLayout( windowLayout, 1 );
00920 mainLayout->addSpacing( grabBarHeight );
00921
00922 titleLayout->setSpacing( buttonSpacing );
00923
00924 titleLayout->addSpacing( buttonMargin );
00925 addButtons( titleLayout, options()->customButtonPositions() ?
00926 options()->titleButtonsLeft() : QString(default_left) );
00927
00928 titlebar = new QSpacerItem( 10, clientHandler->titleBarHeight(largeTitlebar)
00929 - topSpacing, QSizePolicy::Expanding, QSizePolicy::Minimum );
00930 titleLayout->addItem( titlebar );
00931
00932 titleLayout->addSpacing( buttonSpacing );
00933 addButtons( titleLayout, options()->customButtonPositions() ?
00934 options()->titleButtonsRight() : QString(default_right) );
00935 titleLayout->addSpacing( buttonMargin - 1 );
00936
00937 windowLayout->addSpacing( leftBorderWidth );
00938 if( isPreview())
00939 windowLayout->addWidget( new QLabel( i18n( "<center><b>Keramik</b></center>" ), widget()));
00940 else
00941 windowLayout->addItem( new QSpacerItem( 0, 0 ));
00942 windowLayout->addSpacing( rightBorderWidth );
00943 }
00944
00945
00946 KeramikClient::~KeramikClient()
00947 {
00948 delete activeIcon;
00949 delete inactiveIcon;
00950
00951 activeIcon = inactiveIcon = NULL;
00952 }
00953
00954
00955 void KeramikClient::reset( unsigned long )
00956 {
00957 if ( clientHandler->largeCaptionBubbles() && !largeTitlebar )
00958 {
00959
00960 if ( !maximizedVertical() ) {
00961 topSpacer->changeSize( 10, 4, QSizePolicy::Expanding, QSizePolicy::Minimum );
00962 largeTitlebar = true;
00963 largeCaption = isActive();
00964
00965 widget()->layout()->activate();
00966
00967
00968
00969
00970
00971 widget()->setGeometry( widget()->x(), widget()->y() - 3, width(), height() + 3 );
00972 }
00973 }
00974 else if ( !clientHandler->largeCaptionBubbles() && largeTitlebar )
00975 {
00976
00977 topSpacer->changeSize( 10, 1, QSizePolicy::Expanding, QSizePolicy::Minimum );
00978 largeTitlebar = largeCaption = false;
00979
00980 widget()->layout()->activate();
00981
00982
00983
00984 widget()->setGeometry( widget()->x(), widget()->y() + 3, width(), height() - 3 );
00985 }
00986
00987 calculateCaptionRect();
00988
00989 captionBufferDirty = maskDirty = true;
00990
00991
00992
00993 if ( widget()->isVisible() ) {
00994 widget()->repaint( false );
00995
00996 for ( int i = 0; i < NumButtons; i++ )
00997 if ( button[i] ) button[i]->repaint( false );
00998 }
00999 }
01000
01001
01002 void KeramikClient::addButtons( QBoxLayout *layout, const QString &s )
01003 {
01004 for ( uint i=0; i < s.length(); i++ )
01005 {
01006 switch ( s[i].latin1() )
01007 {
01008
01009 case 'M' :
01010 if ( !button[MenuButton] ) {
01011 button[MenuButton] = new KeramikButton( this, "menu", MenuButton, i18n("Menu"), LeftButton|RightButton );
01012 connect( button[MenuButton], SIGNAL( pressed() ), SLOT( menuButtonPressed() ) );
01013 layout->addWidget( button[MenuButton] );
01014 }
01015 break;
01016
01017
01018 case 'S' :
01019 if ( !button[OnAllDesktopsButton] ) {
01020 button[OnAllDesktopsButton] = new KeramikButton( this, "on_all_desktops",
01021 OnAllDesktopsButton, isOnAllDesktops()?i18n("Not on all desktops"):i18n("On all desktops") );
01022 if(isOnAllDesktops())
01023 button[OnAllDesktopsButton]->toggle();
01024 connect( button[OnAllDesktopsButton], SIGNAL( clicked() ), SLOT( toggleOnAllDesktops() ) );
01025 layout->addWidget( button[OnAllDesktopsButton] );
01026 }
01027 break;
01028
01029
01030 case 'H' :
01031 if ( !button[HelpButton] && providesContextHelp() ) {
01032 button[HelpButton] = new KeramikButton( this, "help", HelpButton, i18n("Help") );
01033 connect( button[HelpButton], SIGNAL( clicked() ), SLOT( showContextHelp() ) );
01034 layout->addWidget( button[HelpButton] );
01035 }
01036 break;
01037
01038
01039 case 'I' :
01040 if ( !button[MinButton] && isMinimizable() ) {
01041 button[MinButton] = new KeramikButton( this, "minimize", MinButton, i18n("Minimize") );
01042 connect( button[MinButton], SIGNAL( clicked() ), SLOT( minimize() ) );
01043 layout->addWidget( button[MinButton] );
01044 }
01045 break;
01046
01047
01048 case 'A' :
01049 if ( !button[MaxButton] && isMaximizable() ) {
01050 button[MaxButton] = new KeramikButton( this, "maximize", MaxButton, i18n("Maximize"), LeftButton|MidButton|RightButton );
01051 connect( button[MaxButton], SIGNAL( clicked() ), SLOT( slotMaximize() ) );
01052 layout->addWidget( button[MaxButton] );
01053 }
01054 break;
01055
01056
01057 case 'X' :
01058 if ( !button[CloseButton] && isCloseable() ) {
01059 button[CloseButton] = new KeramikButton( this, "close", CloseButton, i18n("Close") );
01060 connect( button[CloseButton], SIGNAL( clicked() ), SLOT( closeWindow() ) );
01061 layout->addWidget( button[CloseButton] );
01062 }
01063 break;
01064
01065
01066 case 'F' :
01067 if ( !button[AboveButton]) {
01068 button[AboveButton] = new KeramikButton( this, "above", AboveButton, i18n("Keep Above Others") );
01069 connect( button[AboveButton], SIGNAL( clicked() ), SLOT( slotAbove() ) );
01070 layout->addWidget( button[AboveButton] );
01071 }
01072 break;
01073
01074
01075 case 'B' :
01076 if ( !button[BelowButton]) {
01077 button[BelowButton] = new KeramikButton( this, "below", BelowButton, i18n("Keep Below Others") );
01078 connect( button[BelowButton], SIGNAL( clicked() ), SLOT( slotBelow() ) );
01079 layout->addWidget( button[BelowButton] );
01080 }
01081 break;
01082
01083
01084 case 'L' :
01085 if ( !button[ShadeButton] && isShadeable() ) {
01086 button[ShadeButton] = new KeramikButton( this, "shade", ShadeButton,
01087 isSetShade() ? i18n("Unshade") : i18n( "Shade" ));
01088 connect( button[ShadeButton], SIGNAL( clicked() ), SLOT( slotShade() ) );
01089 layout->addWidget( button[ShadeButton] );
01090 }
01091 break;
01092
01093
01094 case '_' :
01095 layout->addSpacing( buttonSpacing );
01096 break;
01097 }
01098 }
01099 }
01100
01101
01102 void KeramikClient::updateMask()
01103 {
01104 if ( !keramik_initialized )
01105 return;
01106
01107
01108
01109
01110
01111
01112 QRegion r;
01113 register int w, y = 0;
01114 int nrects;
01115
01116 if ( QApplication::reverseLayout() ) {
01117
01118
01119 if ( largeCaption && captionRect.width() >= 25 ) {
01120 register int x = captionRect.left();
01121 w = captionRect.width();
01122 r += QRegion( x + 11, y++, w - 19, 1 );
01123 r += QRegion( x + 9, y++, w - 15, 1 );
01124 r += QRegion( x + 7, y++, w - 12, 1 );
01125 } else {
01126 nrects = 8;
01127
01128
01129
01130
01131 if ( largeTitlebar )
01132 y = 3;
01133 }
01134
01135 w = width();
01136
01137
01138 r += QRegion( 9, y++, w - 17, 1 );
01139 r += QRegion( 7, y++, w - 13, 1 );
01140 r += QRegion( 5, y++, w - 9, 1 );
01141 r += QRegion( 4, y++, w - 7, 1 );
01142 r += QRegion( 3, y++, w - 5, 1 );
01143 r += QRegion( 2, y++, w - 4, 1 );
01144 r += QRegion( 1, y++, w - 2, 2 );
01145 } else {
01146
01147
01148 if ( largeCaption && captionRect.width() >= 25 ) {
01149 nrects = 11;
01150 register int x = captionRect.left();
01151 w = captionRect.width();
01152 r += QRegion( x + 8, y++, w - 19, 1 );
01153 r += QRegion( x + 6, y++, w - 15, 1 );
01154 r += QRegion( x + 5, y++, w - 12, 1 );
01155 } else {
01156 nrects = 8;
01157
01158
01159
01160
01161 if ( largeTitlebar )
01162 y = 3;
01163 }
01164
01165 w = width();
01166
01167
01168 r += QRegion( 8, y++, w - 17, 1 );
01169 r += QRegion( 6, y++, w - 13, 1 );
01170 r += QRegion( 4, y++, w - 9, 1 );
01171 r += QRegion( 3, y++, w - 7, 1 );
01172 r += QRegion( 2, y++, w - 5, 1 );
01173 r += QRegion( 2, y++, w - 4, 1 );
01174 r += QRegion( 1, y++, w - 2, 2 );
01175 }
01176
01177 y++;
01178
01179
01180 r += QRegion( 0, y, w, height() - y );
01181
01182 setMask( r, YXBanded );
01183
01184 maskDirty = false;
01185 }
01186
01187
01188 void KeramikClient::updateCaptionBuffer()
01189 {
01190 if ( !keramik_initialized )
01191 return;
01192
01193 bool active = isActive();
01194 QPixmap *icon = NULL;
01195
01196 if ( captionBuffer.size() != captionRect.size() )
01197 captionBuffer.resize( captionRect.size() );
01198
01199 if ( captionBuffer.isNull() )
01200 return;
01201
01202 QPainter p( &captionBuffer );
01203
01204
01205 if ( active && largeCaption ) {
01206 p.drawPixmap( 0, 0, *clientHandler->tile( CaptionLargeLeft, true ) );
01207 p.drawTiledPixmap( 15, 0, captionRect.width() - 30, captionRect.height(),
01208 *clientHandler->tile( CaptionLargeCenter, true ) );
01209 p.drawPixmap( captionRect.width() - 15, 0, *clientHandler->tile( CaptionLargeRight, true ) );
01210 } else {
01211 p.drawPixmap( 0, 0, *clientHandler->tile( CaptionSmallLeft, active ) );
01212 p.drawTiledPixmap( 15, 0, captionRect.width() - 30, captionRect.height(),
01213 *clientHandler->tile( CaptionSmallCenter, active ) );
01214 p.drawPixmap( captionRect.width() - 15, 0, *clientHandler->tile( CaptionSmallRight, active ) );
01215 }
01216
01217 if ( clientHandler->showAppIcons() )
01218 {
01219 if ( active ) {
01220 if ( ! activeIcon )
01221 activeIcon = new QPixmap( this->icon().pixmap( QIconSet::Small, QIconSet::Normal ));
01222 icon = activeIcon;
01223 } else {
01224 if ( ! inactiveIcon ) {
01225 QImage img = this->icon().pixmap( QIconSet::Small, QIconSet::Normal ).convertToImage();
01226 KIconEffect::semiTransparent( img );
01227 inactiveIcon = new QPixmap( img );
01228 }
01229 icon = inactiveIcon;
01230 }
01231 }
01232
01233 p.setFont( options()->font( active ) );
01234 int tw = p.fontMetrics().width( caption() ) +
01235 ( clientHandler->showAppIcons() ? 16 + iconSpacing : 0 );
01236
01237 int xpos = QMAX( (captionRect.width() - tw) / 3, 8 );
01238 QRect tr = QStyle::visualRect( QRect(xpos, 1, captionRect.width() - xpos - 10,
01239 captionRect.height() - 4), captionBuffer.rect() );
01240
01241
01242
01243
01244
01245 if ( clientHandler->showAppIcons() )
01246 {
01247 QRect iconRect = QStyle::visualRect( QRect(tr.x(),
01248 1 + (captionRect.height() - 4 - 16) / 2, 16, 16), tr );
01249 QRect r( icon->rect() );
01250 r.moveCenter( iconRect.center() );
01251
01252 if ( tr.width() > 16 ) {
01253 p.drawPixmap( r, *icon );
01254 } else {
01255 QRect sr( 0, 0, icon->width(), icon->height() );
01256
01257 if ( QApplication::reverseLayout() )
01258 sr.addCoords( icon->width() - tr.width(), 0, 0, 0 );
01259 else
01260 sr.addCoords( 0, 0, -( icon->width() - tr.width() ), 0 );
01261
01262 p.drawPixmap( r.x() + sr.x(), r.y() + sr.y(), *icon,
01263 sr.x(), sr.y(), sr.width(), sr.height() );
01264 }
01265
01266
01267
01268 if ( QApplication::reverseLayout() )
01269 tr.addCoords( 0, 0, -(16 + iconSpacing), 0 );
01270 else
01271 tr.addCoords( (16 + iconSpacing), 0, 0, 0 );
01272 }
01273
01274
01275 int flags = AlignVCenter | SingleLine;
01276 flags |= ( QApplication::reverseLayout() ? AlignRight : AlignLeft );
01277
01278 if ( clientHandler->useShadowedText() )
01279 {
01280 p.translate( QApplication::reverseLayout() ? -1 : 1, 1 );
01281 p.setPen( options()->color(ColorTitleBar, active).dark() );
01282 p.setPen( black );
01283 p.drawText( tr, flags, caption() );
01284 p.translate( QApplication::reverseLayout() ? 1 : -1, -1 );
01285 }
01286
01287 p.setPen( options()->color( ColorFont, active ) );
01288 p.drawText( tr, flags, caption() );
01289
01290 captionBufferDirty = false;
01291 }
01292
01293
01294 void KeramikClient::calculateCaptionRect()
01295 {
01296 QFontMetrics fm( options()->font(isActive()) );
01297 int cw = fm.width( caption() ) + 95;
01298 int titleBaseY = ( largeTitlebar ? 3 : 0 );
01299
01300 if ( clientHandler->showAppIcons() )
01301 cw += 16 + 4;
01302
01303 cw = QMIN( cw, titlebar->geometry().width() );
01304 captionRect = QStyle::visualRect( QRect(titlebar->geometry().x(), (largeCaption ? 0 : titleBaseY),
01305 cw, clientHandler->titleBarHeight(largeCaption) ),
01306 titlebar->geometry() );
01307 }
01308
01309
01310 void KeramikClient::captionChange()
01311 {
01312 QRect r( captionRect );
01313 calculateCaptionRect();
01314
01315 if ( r.size() != captionRect.size() )
01316 maskDirty = true;
01317
01318 captionBufferDirty = true;
01319
01320 widget()->repaint( r | captionRect, false );
01321 }
01322
01323
01324 void KeramikClient::iconChange()
01325 {
01326 if ( clientHandler->showAppIcons() ) {
01327
01328
01329 delete activeIcon;
01330
01331 delete inactiveIcon;
01332
01333 activeIcon = inactiveIcon = NULL;
01334
01335 captionBufferDirty = true;
01336 widget()->repaint( captionRect, false );
01337 }
01338 }
01339
01340
01341 void KeramikClient::activeChange()
01342 {
01343 bool active = isActive();
01344
01345
01346
01347 if ( largeTitlebar ) {
01348 largeCaption = ( active && !maximizedVertical() );
01349 calculateCaptionRect();
01350 maskDirty = true;
01351 }
01352
01353 captionBufferDirty = true;
01354
01355 widget()->repaint( false );
01356
01357 for ( int i=0; i < NumButtons; i++ )
01358 if ( button[i] ) button[i]->repaint( false );
01359 }
01360
01361
01362 void KeramikClient::maximizeChange()
01363 {
01364 if ( clientHandler->largeCaptionBubbles() )
01365 {
01366 if ( maximizeMode() & MaximizeVertical ) {
01367
01368 topSpacer->changeSize( 10, 1, QSizePolicy::Expanding, QSizePolicy::Minimum );
01369 largeCaption = largeTitlebar = false;
01370
01371 calculateCaptionRect();
01372 captionBufferDirty = maskDirty = true;
01373
01374 widget()->layout()->activate();
01375 widget()->repaint( false );
01376 } else if (( maximizeMode() & MaximizeVertical ) == 0 && !largeTitlebar ) {
01377
01378 topSpacer->changeSize( 10, 4, QSizePolicy::Expanding, QSizePolicy::Minimum );
01379 largeCaption = largeTitlebar = true;
01380
01381 calculateCaptionRect();
01382 captionBufferDirty = maskDirty = true;
01383
01384 widget()->layout()->activate();
01385 widget()->repaint( false );
01386 }
01387 }
01388
01389 if ( button[ MaxButton ] ) {
01390 QToolTip::remove( button[ MaxButton ] );
01391 QToolTip::add( button[ MaxButton ], maximizeMode() == MaximizeFull ? i18n("Restore") : i18n("Maximize") );
01392 button[ MaxButton ]->repaint();
01393 }
01394 }
01395
01396
01397 void KeramikClient::desktopChange()
01398 {
01399 if ( button[ OnAllDesktopsButton ] )
01400 {
01401 button[ OnAllDesktopsButton ]->repaint( true );
01402 QToolTip::remove( button[ OnAllDesktopsButton ] );
01403 QToolTip::add( button[ OnAllDesktopsButton ], isOnAllDesktops() ? i18n("Not on all desktops") : i18n("On all desktops") );
01404 }
01405 }
01406
01407
01408 void KeramikClient::shadeChange()
01409 {
01410 if ( button[ ShadeButton ] )
01411 {
01412 button[ ShadeButton ]->repaint( true );
01413 QToolTip::remove( button[ ShadeButton ] );
01414 QToolTip::add( button[ ShadeButton ], isSetShade() ? i18n("Unshade") : i18n("Shade") );
01415 }
01416 }
01417
01418
01419 void KeramikClient::keepAboveChange( bool )
01420 {
01421 if ( button[ AboveButton ] )
01422 button[ AboveButton ]->repaint( true );
01423 }
01424
01425
01426 void KeramikClient::keepBelowChange( bool )
01427 {
01428 if ( button[ BelowButton ] )
01429 button[ BelowButton ]->repaint( true );
01430 }
01431
01432
01433 void KeramikClient::menuButtonPressed()
01434 {
01435 QPoint menuTop ( button[MenuButton]->rect().topLeft() );
01436 QPoint menuBottom ( button[MenuButton]->rect().bottomRight() );
01437 menuTop += QPoint(-6, -3);
01438 menuBottom += QPoint(6, 3);
01439 KDecorationFactory* f = factory();
01440 showWindowMenu( QRect( button[MenuButton]->mapToGlobal( menuTop ),
01441 button[MenuButton]->mapToGlobal( menuBottom )) );
01442 if( !f->exists( this ))
01443 return;
01444 button[MenuButton]->setDown(false);
01445 }
01446
01447
01448 void KeramikClient::slotMaximize()
01449 {
01450 maximize( button[ MaxButton ]->lastButton() );
01451 }
01452
01453
01454 void KeramikClient::slotAbove()
01455 {
01456 setKeepAbove( !keepAbove());
01457 button[ AboveButton ]->repaint( true );
01458 }
01459
01460
01461 void KeramikClient::slotBelow()
01462 {
01463 setKeepBelow( !keepBelow());
01464 button[ BelowButton ]->repaint( true );
01465 }
01466
01467
01468 void KeramikClient::slotShade()
01469 {
01470 setShade( !isSetShade());
01471 button[ ShadeButton ]->repaint( true );
01472 }
01473
01474
01475 void KeramikClient::paintEvent( QPaintEvent *e )
01476 {
01477 if ( !keramik_initialized )
01478 return;
01479
01480 QPainter p( widget());
01481 QRect updateRect( e->rect() );
01482 bool active = isActive();
01483
01484 int titleBaseY = ( largeTitlebar ? 3 : 0 );
01485 int titleBarHeight = clientHandler->titleBarHeight( largeTitlebar );
01486 int grabBarHeight = clientHandler->grabBarHeight();
01487 int leftBorderWidth = clientHandler->tile( BorderLeft, active )->width();
01488 int rightBorderWidth = clientHandler->tile( BorderRight, active )->width();
01489
01490 if ( maskDirty )
01491 updateMask();
01492
01493
01494
01495 if ( updateRect.y() < titleBarHeight )
01496 {
01497 int titleBarBaseHeight = titleBarHeight - titleBaseY;
01498
01499 if ( captionBufferDirty )
01500 updateCaptionBuffer();
01501
01502
01503 if ( updateRect.x() < 15 )
01504 p.drawPixmap( 0, titleBaseY,
01505 *clientHandler->tile( TitleLeft, active ) );
01506
01507
01508 if ( updateRect.x() < captionRect.left() && updateRect.right() >= 15 ) {
01509 int x1 = QMAX( 15, updateRect.x() );
01510 int x2 = QMIN( captionRect.left(), updateRect.right() );
01511
01512 p.drawTiledPixmap( x1, titleBaseY, x2 - x1 + 1, titleBarBaseHeight,
01513 *clientHandler->tile( TitleCenter, active ) );
01514 }
01515
01516
01517 if ( updateRect.x() <= captionRect.right() && updateRect.right() > 15 ) {
01518 if ( captionRect.width() >= 25 )
01519 p.drawPixmap( captionRect.left(), active ? 0 : titleBaseY, captionBuffer );
01520 else
01521 p.drawTiledPixmap( captionRect.x(), titleBaseY, captionRect.width(),
01522 titleBarBaseHeight, *clientHandler->tile( TitleCenter, active ) );
01523 }
01524
01525
01526 if ( updateRect.right() > captionRect.right() && updateRect.x() < width() - 15 ) {
01527 int x1 = QMAX( captionRect.right() + 1, updateRect.x() );
01528 int x2 = QMIN( width() - 15, updateRect.right() );
01529
01530 p.drawTiledPixmap( x1, titleBaseY, x2 - x1 + 1, titleBarBaseHeight,
01531 *clientHandler->tile( TitleCenter, active ) );
01532 }
01533
01534
01535 if ( updateRect.right() >= width() - 15 )
01536 p.drawPixmap( width() - 15, titleBaseY,
01537 *clientHandler->tile( TitleRight, active ) );
01538 }
01539
01540
01541
01542 if ( updateRect.bottom() >= titleBarHeight &&
01543 updateRect.top() < height() - grabBarHeight )
01544 {
01545 int top = QMAX( titleBarHeight, updateRect.top() );
01546 int bottom = QMIN( updateRect.bottom(), height() - grabBarHeight );
01547
01548
01549 if ( updateRect.x() < leftBorderWidth )
01550 p.drawTiledPixmap( 0, top, leftBorderWidth, bottom - top + 1,
01551 *clientHandler->tile( BorderLeft, active ) );
01552
01553
01554 if ( e->rect().right() > width() - rightBorderWidth - 1 )
01555 p.drawTiledPixmap( width() - rightBorderWidth, top, rightBorderWidth,
01556 bottom - top + 1, *clientHandler->tile( BorderRight, active ) );
01557 }
01558
01559
01560
01561 if ( updateRect.bottom() >= height() - grabBarHeight ) {
01562
01563 if ( updateRect.x() < 9 )
01564 p.drawPixmap( 0, height() - grabBarHeight,
01565 *clientHandler->tile( GrabBarLeft, active ) );
01566
01567
01568 if ( updateRect.x() < width() - 9 ) {
01569 int x1 = QMAX( 9, updateRect.x() );
01570 int x2 = QMIN( width() - 9, updateRect.right() );
01571
01572 p.drawTiledPixmap( x1, height() - grabBarHeight, x2 - x1 + 1,
01573 grabBarHeight, *clientHandler->tile( GrabBarCenter, active ) );
01574 }
01575
01576
01577 if ( updateRect.right() > width() - 9 )
01578 p.drawPixmap( width() - 9, height() - grabBarHeight,
01579 *clientHandler->tile( GrabBarRight, active ) );
01580 }
01581
01582
01583 p.setPen( options()->color( ColorTitleBlend, active ) );
01584 p.drawLine( leftBorderWidth, height() - grabBarHeight - 1,
01585 width() - rightBorderWidth - 1, height() - grabBarHeight - 1 );
01586 }
01587
01588
01589 void KeramikClient::resizeEvent( QResizeEvent *e )
01590 {
01591
01592
01593 QRect r( captionRect );
01594 calculateCaptionRect();
01595
01596 if ( r.size() != captionRect.size() )
01597 captionBufferDirty = true;
01598
01599 maskDirty = true;
01600
01601 if ( widget()->isVisible() )
01602 {
01603 widget()->update( widget()->rect() );
01604 int dx = 0;
01605 int dy = 0;
01606
01607 if ( e->oldSize().width() != width() )
01608 dx = 32 + QABS( e->oldSize().width() - width() );
01609
01610 if ( e->oldSize().height() != height() )
01611 dy = 8 + QABS( e->oldSize().height() - height() );
01612
01613 if ( dy )
01614 widget()->update( 0, height() - dy + 1, width(), dy );
01615
01616 if ( dx )
01617 {
01618 widget()->update( width() - dx + 1, 0, dx, height() );
01619 widget()->update( QRect( QPoint(4,4), titlebar->geometry().bottomLeft() - QPoint(1,0) ) );
01620 widget()->update( QRect( titlebar->geometry().topRight(), QPoint( width() - 4,
01621 titlebar->geometry().bottom() ) ) );
01622
01623 QApplication::postEvent( this, new QPaintEvent( titlebar->geometry(), FALSE ) );
01624 }
01625 }
01626 }
01627
01628
01629 void KeramikClient::mouseDoubleClickEvent( QMouseEvent *e )
01630 {
01631 if ( QRect( 0, 0, width(), clientHandler->titleBarHeight( largeTitlebar ) ).contains( e->pos() ) )
01632 titlebarDblClickOperation();
01633 }
01634
01635
01636 KeramikClient::Position KeramikClient::mousePosition( const QPoint &p ) const
01637 {
01638 int titleBaseY = (largeTitlebar ? 3 : 0);
01639
01640 int leftBorder = clientHandler->tile( BorderLeft, true )->width();
01641 int rightBorder = width() - clientHandler->tile( BorderRight, true )->width() - 1;
01642 int bottomBorder = height() - clientHandler->grabBarHeight() - 1;
01643 int bottomCornerSize = 3*clientHandler->tile( BorderRight, true )->width()/2 + 24;
01644
01645
01646 if ( p.y() < titleBaseY + 11 ) {
01647
01648 if ( p.x() < leftBorder + 11 ) {
01649 if ( (p.y() < titleBaseY + 3 && p.x() < leftBorder + 11) ||
01650 (p.y() < titleBaseY + 6 && p.x() < leftBorder + 6) ||
01651 (p.y() < titleBaseY + 11 && p.x() < leftBorder + 3) )
01652 return PositionTopLeft;
01653 }
01654
01655
01656 if ( p.x() > rightBorder - 11 ) {
01657 if ( (p.y() < titleBaseY + 3 && p.x() > rightBorder - 11) ||
01658 (p.y() < titleBaseY + 6 && p.x() > rightBorder - 6) ||
01659 (p.y() < titleBaseY + 11 && p.x() > rightBorder - 3) )
01660 return PositionTopRight;
01661 }
01662
01663
01664 if ( p.y() <= 3 || (p.y() <= titleBaseY+3 &&
01665 (p.x() < captionRect.left() || p.x() > captionRect.right()) ) )
01666 return PositionTop;
01667
01668
01669 return PositionCenter;
01670 }
01671
01672
01673 else if ( p.y() < bottomBorder ) {
01674
01675 if ( p.x() < leftBorder ) {
01676 if ( p.y() < height() - bottomCornerSize )
01677 return PositionLeft;
01678 else
01679 return PositionBottomLeft;
01680 }
01681
01682
01683 else if ( p.x() > rightBorder ) {
01684 if ( p.y() < height() - bottomCornerSize )
01685 return PositionRight;
01686 else
01687 return PositionBottomRight;
01688 }
01689
01690
01691 return PositionCenter;
01692 }
01693
01694
01695 else {
01696
01697 if ( p.x() < bottomCornerSize )
01698 return PositionBottomLeft;
01699
01700
01701 else if ( p.x() > width() - bottomCornerSize - 1 )
01702 return PositionBottomRight;
01703
01704
01705 return PositionBottom;
01706 }
01707
01708
01709 return PositionCenter;
01710 }
01711
01712
01713 void KeramikClient::resize( const QSize& s )
01714 {
01715 widget()->resize( s );
01716 }
01717
01718
01719 void KeramikClient::borders( int& left, int& right, int& top, int& bottom ) const
01720 {
01721 int titleBarHeight = clientHandler->titleBarHeight( clientHandler->largeCaptionBubbles() );
01722 int grabBarHeight = clientHandler->grabBarHeight();
01723 int leftBorderWidth = clientHandler->tile( BorderLeft, isActive() )->width();
01724 int rightBorderWidth = clientHandler->tile( BorderRight, isActive() )->width();
01725
01726 left = leftBorderWidth;
01727 right = rightBorderWidth;
01728 top = titleBarHeight;
01729 bottom = grabBarHeight;
01730
01731 if ( ( maximizeMode() & MaximizeHorizontal ) && !options()->moveResizeMaximizedWindows())
01732 left = right = 0;
01733 if( maximizeMode() & MaximizeVertical)
01734 {
01735 top = clientHandler->titleBarHeight( false );
01736 if( !options()->moveResizeMaximizedWindows())
01737 bottom = 0;
01738 }
01739 }
01740
01741
01742 QSize KeramikClient::minimumSize() const
01743 {
01744 return widget()->minimumSize();
01745 }
01746
01747
01748 bool KeramikClient::eventFilter( QObject* o, QEvent* e )
01749 {
01750 if ( o != widget() )
01751 return false;
01752
01753 switch ( e->type() )
01754 {
01755 case QEvent::Resize:
01756 resizeEvent( static_cast< QResizeEvent* >( e ) );
01757 return true;
01758
01759 case QEvent::Paint:
01760 paintEvent( static_cast< QPaintEvent* >( e ) );
01761 return true;
01762
01763 case QEvent::MouseButtonDblClick:
01764 mouseDoubleClickEvent( static_cast< QMouseEvent* >( e ) );
01765 return true;
01766
01767 case QEvent::MouseButtonPress:
01768 processMousePressEvent( static_cast< QMouseEvent* >( e ) );
01769 return true;
01770
01771 default:
01772 return false;
01773 }
01774 }
01775
01776 }
01777
01778
01779
01780
01781
01782
01783
01784 extern "C"
01785 {
01786 KDE_EXPORT KDecorationFactory *create_factory()
01787 {
01788 Keramik::clientHandler = new Keramik::KeramikHandler();
01789 return Keramik::clientHandler;
01790 }
01791 }
01792
01793
01794
01795