kwin Library API Documentation

keramik.cpp

00001 /*
00002  *
00003  * Keramik KWin client (version 0.8)
00004  *
00005  * Copyright (C) 2002 Fredrik H�lund <fredrik@kde.org>
00006  *
00007  * This program is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the license, or
00010  * (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; see the file COPYING.  If not, write to
00019  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020  * Boston, MA 02111-1307, USA.
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;  // Margin between the window edge and the buttons
00050     const int buttonSpacing    =  4;  // Spacing between the titlebar buttons
00051     const int iconSpacing      =  5;  // Spacing between the icon and the text label
00052 
00053     // Default button layout
00054     const char default_left[]  = "M";
00055     const char default_right[] = "HIAX";
00056 
00057     // Titlebar button bitmaps
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     // Create the button deco bitmaps
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     // Selfmask the bitmaps
00193     for ( int i = 0; i < NumButtonDecos; i++ )
00194         buttonDecos[i]->setMask( *buttonDecos[i] );
00195 
00196     // Flip the bitmaps horizontally in right-to-left mode
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     // Active tiles
00271     // -------------------------------------------------------------------------
00272     captionColor = KDecoration::options()->color( ColorTitleBar,   true );
00273     titleColor   = KDecoration::options()->color( ColorTitleBlend, true );
00274 
00275     // Load the titlebar corners.
00276     activeTiles[ TitleLeft ]  = loadPixmap( "titlebar-left",  titleColor );
00277     activeTiles[ TitleRight ] = loadPixmap( "titlebar-right", titleColor );
00278 
00279     // Load the titlebar center tile image (this will be used as
00280     //     the background for the caption bubble tiles).
00281     titleCenter = loadImage( "titlebar-center", titleColor );
00282 
00283     // Load the small version of the caption bubble corner & center images.
00284     captionLeft   = loadImage( "caption-small-left",   captionColor );
00285     captionRight  = loadImage( "caption-small-right",  captionColor );
00286     captionCenter = loadImage( "caption-small-center", captionColor );
00287 
00288     // Create the caption bubble tiles (by blending the images onto the titlebar)
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     // Now do the same with the large version
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     // Create the titlebar center tile
00311     activeTiles[ TitleCenter ] = new QPixmap( *titleCenter );
00312 
00313     delete titleCenter;
00314 
00315     // Load the left & right border pixmaps
00316     activeTiles[ BorderLeft ]  = loadPixmap( "border-left",  titleColor );
00317     activeTiles[ BorderRight ] = loadPixmap( "border-right", titleColor );
00318 
00319     // Load the bottom grabbar pixmaps
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     // Inactive tiles
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     // Buttons
00370     // -------------------------------------------------------------------------
00371     buttonColor  = QColor(); //KDecoration::options()->color( ButtonBg, true );
00372 
00373     titleButtonRound  = loadPixmap( "titlebutton-round"+size,  buttonColor );
00374     titleButtonSquare = loadPixmap( "titlebutton-square"+size, buttonColor );
00375 
00376 
00377     // Prepare the tiles for use
00378     // -------------------------------------------------------------------------
00379     if ( QApplication::reverseLayout() ) {
00380 
00381         // Fix lighting
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     // Pretile the center & border tiles for optimal performance
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     // Flip the pixmaps horizontally
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     // Flip the pixmap horizontally
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     // Clear the destination image
00585     Q_UINT32 *data = reinterpret_cast<Q_UINT32*>( dest.bits() );
00586     for (int i = 0; i < width * height; i++)
00587         *(data++) = 0;
00588 
00589     // Copy the under image (bottom aligned) to the destination image
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     // Blend the over image onto the destination
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     // Create the final pixmap and return it
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     // Re-read the config file
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     // Check if the color scheme has changed
00670     if ( changed & SettingColors )
00671     {
00672         pixmapsInvalid = true;
00673     }
00674     // Check if button positions have changed
00675 
00676     if ( changed & SettingButtons ) {
00677         needHardReset = true;
00678     }
00679 
00680     // Check if tooltips options have changed
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     // Update our config cache
00695     settings_cache->largeGrabBars       = largeGrabBars;
00696     settings_cache->smallCaptionBubbles = smallCaptionBubbles;
00697 
00698     // Do we need to recreate the pixmaps?
00699     if ( pixmapsInvalid ) {
00700         destroyPixmaps();
00701         createPixmaps();
00702     }
00703 
00704     keramik_initialized = true;
00705 
00706     // Do we need to "hit the wooden hammer" ?
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 { // the list must be sorted
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 ); // FRAME
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     // Empty.
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     // Get the bevel from the client handler
00819     if ( button == MenuButton || button == OnAllDesktopsButton || button == HelpButton )
00820         pix = clientHandler->roundButton();
00821     else
00822         pix = clientHandler->squareButton();
00823 
00824     // Draw the button background
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         // Pressed
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         // Mouse over
00835         p->drawPixmap( QPoint(), *pix, QStyle::visualRect( QRect(size, 0, size, size), pix->rect() ) );
00836     else
00837         // Normal
00838         p->drawPixmap( QPoint(), *pix, QStyle::visualRect( QRect(0, 0, size, size), pix->rect() ) );
00839 
00840 
00841     // Draw the button deco on the bevel
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             // The '?' won't be flipped around in the ctor, so we need to
00854             //  shift it to the right to compensate for the button shadow
00855             //  being on the left side of the button in RTL mode.
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 ); // ### hardcoded color
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     // Minimize flicker
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 );     // Titlebar
00941     mainLayout->addLayout( windowLayout, 1 ); // Left border + window + right border
00942     mainLayout->addSpacing( grabBarHeight );  // Bottom grab bar
00943 
00944     titleLayout->setSpacing( buttonSpacing );
00945 
00946     titleLayout->addSpacing( buttonMargin );      // Left button margin
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 );  // Right button margin
00958 
00959     windowLayout->addSpacing( leftBorderWidth );                // Left border
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 )); //no widget in the middle
00964     windowLayout->addSpacing( rightBorderWidth );                // Right border
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         // We're switching from small caption bubbles to large
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             // Compensate for the titlebar size change
00990 
00991             // TODO This is wrong, this may break size increments (see bug #53784).
00992             // FRAME
00993             widget()->setGeometry( widget()->x(), widget()->y() - 3, width(), height() + 3 );
00994         }
00995     }
00996     else if ( !clientHandler->largeCaptionBubbles() && largeTitlebar )
00997     {
00998         // We're switching from large caption bubbles to small
00999         topSpacer->changeSize( 10, 1, QSizePolicy::Expanding, QSizePolicy::Minimum );
01000         largeTitlebar = largeCaption = false;
01001 
01002         widget()->layout()->activate();
01003 
01004         // Compensate for the titlebar size change
01005         // FRAME
01006         widget()->setGeometry( widget()->x(), widget()->y() + 3, width(), height() - 3 );
01007     }
01008 
01009     calculateCaptionRect();
01010 
01011     captionBufferDirty = maskDirty = true;
01012 
01013     // Only repaint the window if it's visible
01014     // (i.e. not minimized and on the current desktop)
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             // Menu button
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             // OnAllDesktops button
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             // Help button
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             // Minimize button
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             // Maximize button
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             // Close button
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             // Above button
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             // Below button
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             // Shade button
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             // Additional spacing
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     // To maximize performance this code uses precalculated bounding rects
01130     // to set the window mask. This saves us from having to allocate a 1bpp
01131     // pixmap, paint the mask on it and then have the X server iterate
01132     // over the pixels to compute the bounding rects from it.
01133 
01134     QRegion r;
01135     register int w, y = 0;
01136     int nrects;
01137 
01138     if ( QApplication::reverseLayout() ) {
01139 
01140         // If the caption bubble is visible and extends above the titlebar
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             // Do we have a large titlebar with a retracted caption bubble?
01151             // (i.e. the style is set to use large caption bubbles, we're
01152             //       not maximized and not active)
01153             if ( largeTitlebar )
01154                 y = 3;
01155         }
01156 
01157         w = width(); // FRAME
01158 
01159         // The rounded titlebar corners
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         // If the caption bubble is visible and extends above the titlebar
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             // Do we have a large titlebar with a retracted caption bubble?
01181             // (i.e. the style is set to use large caption bubbles, we're
01182             //       not maximized and not active)
01183             if ( largeTitlebar )
01184                 y = 3;
01185         }
01186 
01187         w = width(); // FRAME
01188 
01189         // The rounded titlebar corners
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     // The part of the window below the titlebar
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     // Draw the caption bubble
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 )); // FRAME
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     //p.setPen( Qt::red ); // debug
01264     //p.drawRect( tr );    // debug
01265 
01266     // Application icon
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         //p.drawRect( r ); // debug
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     // Draw the titlebar text
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         //p.setPen( options()->color(ColorTitleBar, active).dark() );
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; // icon width + space
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         // Force updateCaptionBuffer() to recreate the cached icons
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     // Note: It's assumed that the same font will always be used for both active
01370     //       and inactive windows, since the fonts kcm hasn't supported setting
01371     //       different fonts for different window states for some time.
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             // We've been maximized - shrink the titlebar by 3 pixels
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             // We've been restored - enlarge the titlebar by 3 pixels
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 )) // 'this' was destroyed
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     // Titlebar
01519     // -----------------------------------------------------------------------
01520     if ( updateRect.y() < titleBarHeight )
01521     {
01522         int titleBarBaseHeight = titleBarHeight - titleBaseY;
01523 
01524         if ( captionBufferDirty )
01525             updateCaptionBuffer();
01526 
01527         // Top left corner
01528         if ( updateRect.x() < 15 )
01529             p.drawPixmap( 0, titleBaseY,
01530                     *clientHandler->tile( TitleLeft, active ) );
01531 
01532         // Space between the top left corner and the caption bubble
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         // Caption bubble
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         // Space between the caption bubble and the top right corner
01551         if ( updateRect.right() > captionRect.right() && updateRect.x() < width() - 15 ) { // FRAME
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         // Top right corner
01560         if ( updateRect.right() >= width() - 15 )
01561             p.drawPixmap( width() - 15, titleBaseY,
01562                     *clientHandler->tile( TitleRight, active ) );
01563     }
01564 
01565     // Borders
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         // Left border
01574         if ( updateRect.x() < leftBorderWidth )
01575             p.drawTiledPixmap( 0, top, leftBorderWidth, bottom - top + 1,
01576                     *clientHandler->tile( BorderLeft, active ) );
01577 
01578         // Right border
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     // Bottom grab bar
01585     // -----------------------------------------------------------------------
01586     if ( updateRect.bottom() >= height() - grabBarHeight ) {
01587         // Bottom left corner
01588         if ( updateRect.x() < 9 )
01589             p.drawPixmap( 0, height() - grabBarHeight,
01590                     *clientHandler->tile( GrabBarLeft, active ) );
01591 
01592         // Space between the left corner and the right corner
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         // Bottom right corner
01602         if ( updateRect.right() > width() - 9 )
01603             p.drawPixmap( width() - 9, height() - grabBarHeight,
01604                     *clientHandler->tile( GrabBarRight, active ) );
01605     }
01606 
01607     // Extra drawline for the 1 pixel empty space QLayout leaves when a window is shaded.
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 // FRAME    Client::resizeEvent( e );
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             // Titlebar needs no paint event
01648             QApplication::postEvent( this, new QPaintEvent( titlebar->geometry(), FALSE ) );
01649         }
01650     }
01651 }
01652 
01653 
01654 void KeramikClient::mouseDoubleClickEvent( QMouseEvent *e )
01655 {
01656     if ( e->button() == LeftButton
01657             && QRect( 0, 0, width(), clientHandler->titleBarHeight( largeTitlebar ) ).contains( e->pos() ) )
01658         titlebarDblClickOperation();
01659 }
01660 
01661 
01662 KeramikClient::Position KeramikClient::mousePosition( const QPoint &p ) const
01663 {
01664     int titleBaseY = (largeTitlebar ? 3 : 0);
01665 
01666     int leftBorder   = clientHandler->tile( BorderLeft, true )->width();
01667     int rightBorder  = width() - clientHandler->tile( BorderRight, true )->width() - 1;
01668     int bottomBorder = height() - clientHandler->grabBarHeight() - 1;
01669     int bottomCornerSize = 3*clientHandler->tile( BorderRight, true )->width()/2 + 24;
01670 
01671     // Test if the mouse is over the titlebar area
01672     if ( p.y() < titleBaseY + 11 ) {
01673         // Test for the top left corner
01674         if ( p.x() < leftBorder + 11 ) {
01675             if ( (p.y() < titleBaseY + 3 && p.x() < leftBorder + 11) ||
01676                     (p.y() < titleBaseY + 6 && p.x() < leftBorder + 6) ||
01677                     (p.y() < titleBaseY + 11 && p.x() < leftBorder + 3) )
01678                 return PositionTopLeft;
01679         }
01680 
01681         // Test for the top right corner
01682         if ( p.x() > rightBorder - 11 ) {
01683             if ( (p.y() < titleBaseY + 3 && p.x() > rightBorder - 11) ||
01684                     (p.y() < titleBaseY + 6 && p.x() > rightBorder - 6) ||
01685                     (p.y() < titleBaseY + 11 && p.x() > rightBorder - 3) )
01686                 return PositionTopRight;
01687         }
01688 
01689         // Test for the top border
01690         if ( p.y() <= 3 || (p.y() <= titleBaseY+3 &&
01691                     (p.x() < captionRect.left() || p.x() > captionRect.right()) ) )
01692             return PositionTop;
01693 
01694         // The cursor must be over the center of the titlebar.
01695         return PositionCenter;
01696     }
01697 
01698     // Test the sides
01699     else if ( p.y() < bottomBorder ) {
01700         // Test for the left side
01701         if ( p.x() < leftBorder ) {
01702             if ( p.y() < height() - bottomCornerSize )
01703                 return PositionLeft;
01704             else
01705                 return PositionBottomLeft;
01706         }
01707 
01708         // Test for the right side
01709         else if ( p.x() > rightBorder ) {
01710             if ( p.y() < height() - bottomCornerSize )
01711                 return PositionRight;
01712             else
01713                 return PositionBottomRight;
01714         }
01715 
01716         // The cursor must be over the center of the window
01717         return PositionCenter;
01718     }
01719 
01720     // Test the grab bar / bottom border
01721     else {
01722         // Test for the bottom left corner
01723         if ( p.x() < bottomCornerSize )
01724             return PositionBottomLeft;
01725 
01726         // Test for the bottom right corner
01727         else if ( p.x() > width() - bottomCornerSize - 1 )
01728             return PositionBottomRight;
01729 
01730         // The cursor must be over the bottom border
01731         return PositionBottom;
01732     }
01733 
01734     // We should never get here
01735     return PositionCenter;
01736 }
01737 
01738 
01739 void KeramikClient::resize( const QSize& s )
01740 {
01741     widget()->resize( s );
01742 }
01743 
01744 
01745 void KeramikClient::borders( int& left, int& right, int& top, int& bottom ) const
01746 {
01747     int titleBarHeight     = clientHandler->titleBarHeight( clientHandler->largeCaptionBubbles() );
01748     int grabBarHeight      = clientHandler->grabBarHeight();
01749     int leftBorderWidth    = clientHandler->tile( BorderLeft, isActive() )->width();
01750     int rightBorderWidth   = clientHandler->tile( BorderRight, isActive() )->width();
01751 
01752     left   = leftBorderWidth;
01753     right  = rightBorderWidth;
01754     top    = titleBarHeight;
01755     bottom = grabBarHeight;
01756 
01757     if ( ( maximizeMode() & MaximizeHorizontal ) && !options()->moveResizeMaximizedWindows())
01758         left = right = 0;
01759     if( maximizeMode() & MaximizeVertical)
01760     {
01761         top = clientHandler->titleBarHeight( false );
01762         if( !options()->moveResizeMaximizedWindows())
01763             bottom = 0;
01764     }
01765 }
01766 
01767 
01768 QSize KeramikClient::minimumSize() const
01769 {
01770     return widget()->minimumSize();
01771 }
01772 
01773 
01774 bool KeramikClient::eventFilter( QObject* o, QEvent* e )
01775 {
01776     if ( o != widget() )
01777         return false;
01778 
01779     switch ( e->type() )
01780     {
01781         case QEvent::Resize:
01782             resizeEvent( static_cast< QResizeEvent* >( e ) );
01783             return true;
01784 
01785         case QEvent::Paint:
01786             paintEvent( static_cast< QPaintEvent* >( e ) );
01787             return true;
01788 
01789         case QEvent::MouseButtonDblClick:
01790             mouseDoubleClickEvent( static_cast< QMouseEvent* >( e ) );
01791             return true;
01792 
01793         case QEvent::MouseButtonPress:
01794             processMousePressEvent( static_cast< QMouseEvent* >( e ) );
01795             return true;
01796 
01797         default:
01798                 return false;
01799     }
01800 }
01801 
01802 } // namespace Keramik
01803 
01804 
01805 
01806 // -------------------------------------------------------------------------------------------
01807 
01808 
01809 
01810 extern "C"
01811 {
01812     KDE_EXPORT KDecorationFactory *create_factory()
01813     {
01814         Keramik::clientHandler = new Keramik::KeramikHandler();
01815                 return Keramik::clientHandler;
01816     }
01817 }
01818 
01819 
01820 
01821 // vim: set noet ts=4 sw=4:
KDE Logo
This file is part of the documentation for kwin Library Version 3.4.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Nov 4 00:48:55 2005 by doxygen 1.4.4 written by Dimitri van Heesch, © 1997-2003