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 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.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Aug 13 21:47:05 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003