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 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 { // the list must be sorted
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 ); // FRAME
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     // Empty.
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     // Get the bevel from the client handler
00797     if ( button == MenuButton || button == OnAllDesktopsButton || button == HelpButton )
00798         pix = clientHandler->roundButton();
00799     else
00800         pix = clientHandler->squareButton();
00801 
00802     // Draw the button background
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         // Pressed
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         // Mouse over
00813         p->drawPixmap( QPoint(), *pix, QStyle::visualRect( QRect(size, 0, size, size), pix->rect() ) );
00814     else
00815         // Normal
00816         p->drawPixmap( QPoint(), *pix, QStyle::visualRect( QRect(0, 0, size, size), pix->rect() ) );
00817 
00818 
00819     // Draw the button deco on the bevel
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             // The '?' won't be flipped around in the ctor, so we need to
00832             //  shift it to the right to compensate for the button shadow
00833             //  being on the left side of the button in RTL mode.
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 ); // ### hardcoded color
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     // Minimize flicker
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 );     // Titlebar
00919     mainLayout->addLayout( windowLayout, 1 ); // Left border + window + right border
00920     mainLayout->addSpacing( grabBarHeight );  // Bottom grab bar
00921 
00922     titleLayout->setSpacing( buttonSpacing );
00923 
00924     titleLayout->addSpacing( buttonMargin );      // Left button margin
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 );  // Right button margin
00936 
00937     windowLayout->addSpacing( leftBorderWidth );                // Left border
00938         if( isPreview())
00939         windowLayout->addWidget( new QLabel( i18n( "<center><b>Keramik</b></center>" ), widget()));
00940         else
00941             windowLayout->addItem( new QSpacerItem( 0, 0 )); //no widget in the middle
00942     windowLayout->addSpacing( rightBorderWidth );                // Right border
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         // We're switching from small caption bubbles to large
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             // Compensate for the titlebar size change
00968 
00969             // TODO This is wrong, this may break size increments (see bug #53784).
00970             // FRAME
00971             widget()->setGeometry( widget()->x(), widget()->y() - 3, width(), height() + 3 );
00972         }
00973     }
00974     else if ( !clientHandler->largeCaptionBubbles() && largeTitlebar )
00975     {
00976         // We're switching from large caption bubbles to small
00977         topSpacer->changeSize( 10, 1, QSizePolicy::Expanding, QSizePolicy::Minimum );
00978         largeTitlebar = largeCaption = false;
00979 
00980         widget()->layout()->activate();
00981 
00982         // Compensate for the titlebar size change
00983         // FRAME
00984         widget()->setGeometry( widget()->x(), widget()->y() + 3, width(), height() - 3 );
00985     }
00986 
00987     calculateCaptionRect();
00988 
00989     captionBufferDirty = maskDirty = true;
00990 
00991     // Only repaint the window if it's visible
00992     // (i.e. not minimized and on the current desktop)
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             // Menu button
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             // OnAllDesktops button
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             // Help button
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             // Minimize button
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             // Maximize button
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             // Close button
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             // Above button
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             // Below button
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             // Shade button
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             // Additional spacing
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     // To maximize performance this code uses precalculated bounding rects
01108     // to set the window mask. This saves us from having to allocate a 1bpp
01109     // pixmap, paint the mask on it and then have the X server iterate
01110     // over the pixels to compute the bounding rects from it.
01111 
01112     QRegion r;
01113     register int w, y = 0;
01114     int nrects;
01115 
01116     if ( QApplication::reverseLayout() ) {
01117 
01118         // If the caption bubble is visible and extends above the titlebar
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             // Do we have a large titlebar with a retracted caption bubble?
01129             // (i.e. the style is set to use large caption bubbles, we're
01130             //       not maximized and not active)
01131             if ( largeTitlebar )
01132                 y = 3;
01133         }
01134 
01135         w = width(); // FRAME
01136 
01137         // The rounded titlebar corners
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         // If the caption bubble is visible and extends above the titlebar
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             // Do we have a large titlebar with a retracted caption bubble?
01159             // (i.e. the style is set to use large caption bubbles, we're
01160             //       not maximized and not active)
01161             if ( largeTitlebar )
01162                 y = 3;
01163         }
01164 
01165         w = width(); // FRAME
01166 
01167         // The rounded titlebar corners
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     // The part of the window below the titlebar
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     // Draw the caption bubble
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 )); // FRAME
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     //p.setPen( Qt::red ); // debug
01242     //p.drawRect( tr );    // debug
01243 
01244     // Application icon
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         //p.drawRect( r ); // debug
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     // Draw the titlebar text
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; // icon width + space
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         // Force updateCaptionBuffer() to recreate the cached icons
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     // Note: It's assumed that the same font will always be used for both active
01345     //       and inactive windows, since the fonts kcm hasn't supported setting
01346     //       different fonts for different window states for some time.
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             // We've been maximized - shrink the titlebar by 3 pixels
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             // We've been restored - enlarge the titlebar by 3 pixels
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 )) // 'this' was destroyed
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     // Titlebar
01494     // -----------------------------------------------------------------------
01495     if ( updateRect.y() < titleBarHeight )
01496     {
01497         int titleBarBaseHeight = titleBarHeight - titleBaseY;
01498 
01499         if ( captionBufferDirty )
01500             updateCaptionBuffer();
01501 
01502         // Top left corner
01503         if ( updateRect.x() < 15 )
01504             p.drawPixmap( 0, titleBaseY,
01505                     *clientHandler->tile( TitleLeft, active ) );
01506 
01507         // Space between the top left corner and the caption bubble
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         // Caption bubble
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         // Space between the caption bubble and the top right corner
01526         if ( updateRect.right() > captionRect.right() && updateRect.x() < width() - 15 ) { // FRAME
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         // Top right corner
01535         if ( updateRect.right() >= width() - 15 )
01536             p.drawPixmap( width() - 15, titleBaseY,
01537                     *clientHandler->tile( TitleRight, active ) );
01538     }
01539 
01540     // Borders
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         // Left border
01549         if ( updateRect.x() < leftBorderWidth )
01550             p.drawTiledPixmap( 0, top, leftBorderWidth, bottom - top + 1,
01551                     *clientHandler->tile( BorderLeft, active ) );
01552 
01553         // Right border
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     // Bottom grab bar
01560     // -----------------------------------------------------------------------
01561     if ( updateRect.bottom() >= height() - grabBarHeight ) {
01562         // Bottom left corner
01563         if ( updateRect.x() < 9 )
01564             p.drawPixmap( 0, height() - grabBarHeight,
01565                     *clientHandler->tile( GrabBarLeft, active ) );
01566 
01567         // Space between the left corner and the right corner
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         // Bottom right corner
01577         if ( updateRect.right() > width() - 9 )
01578             p.drawPixmap( width() - 9, height() - grabBarHeight,
01579                     *clientHandler->tile( GrabBarRight, active ) );
01580     }
01581 
01582     // Extra drawline for the 1 pixel empty space QLayout leaves when a window is shaded.
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 // FRAME    Client::resizeEvent( e );
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             // Titlebar needs no paint event
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     // Test if the mouse is over the titlebar area
01646     if ( p.y() < titleBaseY + 11 ) {
01647         // Test for the top left corner
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         // Test for the top right corner
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         // Test for the top border
01664         if ( p.y() <= 3 || (p.y() <= titleBaseY+3 &&
01665                     (p.x() < captionRect.left() || p.x() > captionRect.right()) ) )
01666             return PositionTop;
01667 
01668         // The cursor must be over the center of the titlebar.
01669         return PositionCenter;
01670     }
01671 
01672     // Test the sides
01673     else if ( p.y() < bottomBorder ) {
01674         // Test for the left side
01675         if ( p.x() < leftBorder ) {
01676             if ( p.y() < height() - bottomCornerSize )
01677                 return PositionLeft;
01678             else
01679                 return PositionBottomLeft;
01680         }
01681 
01682         // Test for the right side
01683         else if ( p.x() > rightBorder ) {
01684             if ( p.y() < height() - bottomCornerSize )
01685                 return PositionRight;
01686             else
01687                 return PositionBottomRight;
01688         }
01689 
01690         // The cursor must be over the center of the window
01691         return PositionCenter;
01692     }
01693 
01694     // Test the grab bar / bottom border
01695     else {
01696         // Test for the bottom left corner
01697         if ( p.x() < bottomCornerSize )
01698             return PositionBottomLeft;
01699 
01700         // Test for the bottom right corner
01701         else if ( p.x() > width() - bottomCornerSize - 1 )
01702             return PositionBottomRight;
01703 
01704         // The cursor must be over the bottom border
01705         return PositionBottom;
01706     }
01707 
01708     // We should never get here
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 } // namespace Keramik
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 // vim: set noet ts=4 sw=4:
KDE Logo
This file is part of the documentation for kwin Library Version 3.3.90.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Apr 5 03:59:39 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003