3 * Keramik KWin client (version 0.8)
5 * Copyright (C) 2002 Fredrik H�lund <fredrik@kde.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the license, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
25 #include <kconfiggroup.h>
27 #include <kiconeffect.h>
36 #include <QApplication>
40 #include "keramik.moc"
42 // -------------------------------------------------------------------------------------------
44 static void flip( QPixmap
*&pix
)
46 QPixmap
*tmp
= new QPixmap( pix
->transformed( QMatrix(-1,0,0,1,pix
->width(),0) ) );
51 static void flip( QBitmap
*&pix
)
53 QBitmap
*tmp
= new QBitmap( pix
->transformed( QMatrix(-1,0,0,1,pix
->width(),0) ) );
61 const int buttonMargin
= 9; // Margin between the window edge and the buttons
62 const int buttonSpacing
= 4; // Spacing between the titlebar buttons
63 const int iconSpacing
= 5; // Spacing between the icon and the text label
65 // Titlebar button bitmaps
66 const unsigned char menu_bits
[] = {
67 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
68 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0xf0, 0x07, 0x00,
69 0xe0, 0x03, 0x00, 0xc0, 0x01, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
70 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73 const unsigned char on_all_desktops_bits
[] = {
74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75 0x80, 0x01, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00, 0xf0, 0x0f, 0x00,
76 0xf0, 0x0f, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80 const unsigned char not_on_all_desktops_bits
[] = {
81 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00,
83 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87 const unsigned char help_bits
[] = {
88 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
89 0xf0, 0x07, 0x00, 0x30, 0x06, 0x00, 0x00, 0x07, 0x00, 0x80, 0x03, 0x00,
90 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x80, 0x01, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94 const unsigned char minimize_bits
[] = {
95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
98 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101 const unsigned char maximize_bits
[] = {
102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103 0x80, 0x01, 0x00, 0xc0, 0x03, 0x00, 0xe0, 0x07, 0x00, 0xf0, 0x0f, 0x00,
104 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108 const unsigned char restore_bits
[] = {
109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00,
111 0xf0, 0x0f, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00, 0x80, 0x01, 0x00,
112 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
115 const unsigned char close_bits
[] = {
116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
117 0x30, 0x0c, 0x00, 0x70, 0x0e, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00,
118 0xc0, 0x03, 0x00, 0xe0, 0x07, 0x00, 0x70, 0x0e, 0x00, 0x30, 0x0c, 0x00,
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122 const unsigned char above_on_bits
[] = {
123 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
124 0x80, 0x01, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00, 0x80, 0x01, 0x00,
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129 const unsigned char above_off_bits
[] = {
130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xc0, 0x03, 0x00,
131 0xe0, 0x07, 0x00, 0x80, 0x01, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
136 const unsigned char below_on_bits
[] = {
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0xc0, 0x03, 0x00,
139 0xe0, 0x07, 0x00, 0x80, 0x01, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143 const unsigned char below_off_bits
[] = {
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
146 0x80, 0x01, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x03, 0x00, 0x80, 0x01, 0x00,
147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150 const unsigned char shade_on_bits
[] = {
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
152 0x10, 0x08, 0x00, 0x10, 0x08, 0x00, 0x10, 0x08, 0x00, 0x10, 0x08, 0x00,
153 0x10, 0x08, 0x00, 0x10, 0x08, 0x00, 0x10, 0x08, 0x00, 0xf0, 0x0f, 0x00,
154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157 const unsigned char shade_off_bits
[] = {
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0xf0, 0x0f, 0x00,
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164 KeramikHandler
*clientHandler
= NULL
;
165 bool keramik_initialized
= false;
169 // -------------------------------------------------------------------------------------------
173 KeramikHandler::KeramikHandler()
175 for ( int i
= 0; i
< NumTiles
; i
++ ) {
176 activeTiles
[i
] = NULL
;
177 inactiveTiles
[i
] = NULL
;
180 settings_cache
= NULL
;
182 // Create the button deco bitmaps
183 buttonDecos
[ Menu
] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), menu_bits
) );
184 buttonDecos
[ OnAllDesktops
] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), on_all_desktops_bits
) );
185 buttonDecos
[ NotOnAllDesktops
] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), not_on_all_desktops_bits
) );
186 buttonDecos
[ Help
] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), help_bits
) );
187 buttonDecos
[ Minimize
] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), minimize_bits
) );
188 buttonDecos
[ Maximize
] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), maximize_bits
) );
189 buttonDecos
[ Restore
] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), restore_bits
) );
190 buttonDecos
[ Close
] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), close_bits
) );
191 buttonDecos
[ AboveOn
] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), above_on_bits
) );
192 buttonDecos
[ AboveOff
] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), above_off_bits
) );
193 buttonDecos
[ BelowOn
] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), below_on_bits
) );
194 buttonDecos
[ BelowOff
] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), below_off_bits
) );
195 buttonDecos
[ ShadeOn
] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), shade_on_bits
) );
196 buttonDecos
[ ShadeOff
] = new QBitmap( QBitmap::fromData( QSize( 17, 17 ), shade_off_bits
) );
198 // Selfmask the bitmaps
199 for ( int i
= 0; i
< NumButtonDecos
; i
++ )
200 buttonDecos
[i
]->setMask( *buttonDecos
[i
] );
202 // Flip the bitmaps horizontally in right-to-left mode
203 if ( QApplication::isRightToLeft() ) {
204 for ( int i
= 0; i
< Help
; ++i
)
205 ::flip( buttonDecos
[i
] );
207 for ( int i
= Help
+ 1; i
< NumButtonDecos
; ++i
)
208 ::flip( buttonDecos
[i
] );
214 keramik_initialized
= true;
218 KeramikHandler::~KeramikHandler()
220 keramik_initialized
= false;
223 for ( int i
= 0; i
< NumButtonDecos
; i
++ )
224 delete buttonDecos
[i
];
226 delete settings_cache
;
228 clientHandler
= NULL
;
232 void KeramikHandler::createPixmaps()
236 switch(options()->preferredBorderSize(this)) {
241 case BorderVeryLarge
:
253 case BorderOversized
:
263 int fontHeight
= QFontMetrics(options()->font(true)).height();
264 if (fontHeight
> heightOffset
+ 20)
265 heightOffset
= fontHeight
- 20;
267 QString size
= (heightOffset
< 8) ? "" : (heightOffset
< 20) ? "-large" : "-huge";
269 QColor titleColor
, captionColor
, buttonColor
;
270 QImage
*titleCenter
= NULL
, *captionLeft
= NULL
,
271 *captionRight
= NULL
, *captionCenter
= NULL
;
275 // -------------------------------------------------------------------------
276 captionColor
= KDecoration::options()->color( ColorTitleBar
, true );
277 titleColor
= KDecoration::options()->color( ColorTitleBlend
, true );
279 // Load the titlebar corners.
280 activeTiles
[ TitleLeft
] = loadPixmap( "titlebar-left", titleColor
);
281 activeTiles
[ TitleRight
] = loadPixmap( "titlebar-right", titleColor
);
283 // Load the titlebar center tile image (this will be used as
284 // the background for the caption bubble tiles).
285 titleCenter
= loadImage( "titlebar-center", titleColor
);
287 // Load the small version of the caption bubble corner & center images.
288 captionLeft
= loadImage( "caption-small-left", captionColor
);
289 captionRight
= loadImage( "caption-small-right", captionColor
);
290 captionCenter
= loadImage( "caption-small-center", captionColor
);
292 // Create the caption bubble tiles (by blending the images onto the titlebar)
293 activeTiles
[ CaptionSmallLeft
] = composite( captionLeft
, titleCenter
);
294 activeTiles
[ CaptionSmallRight
] = composite( captionRight
, titleCenter
);
295 activeTiles
[ CaptionSmallCenter
] = composite( captionCenter
, titleCenter
);
299 delete captionCenter
;
301 // Now do the same with the large version
302 captionLeft
= loadImage( "caption-large-left", captionColor
);
303 captionRight
= loadImage( "caption-large-right", captionColor
);
304 captionCenter
= loadImage( "caption-large-center", captionColor
);
306 activeTiles
[ CaptionLargeLeft
] = composite( captionLeft
, titleCenter
);
307 activeTiles
[ CaptionLargeRight
] = composite( captionRight
, titleCenter
);
308 activeTiles
[ CaptionLargeCenter
] = composite( captionCenter
, titleCenter
);
312 delete captionCenter
;
314 // Create the titlebar center tile
315 activeTiles
[ TitleCenter
] = new QPixmap( QPixmap::fromImage( *titleCenter
) );
319 // Load the left & right border pixmaps
320 activeTiles
[ BorderLeft
] = loadPixmap( "border-left", titleColor
);
321 activeTiles
[ BorderRight
] = loadPixmap( "border-right", titleColor
);
323 // Load the bottom grabbar pixmaps
324 if ( largeGrabBars
) {
325 activeTiles
[ GrabBarLeft
] = loadPixmap( "grabbar-left", titleColor
);
326 activeTiles
[ GrabBarRight
] = loadPixmap( "grabbar-right", titleColor
);
327 activeTiles
[ GrabBarCenter
] = loadPixmap( "grabbar-center", titleColor
);
329 activeTiles
[ GrabBarLeft
] = loadPixmap( "bottom-left", titleColor
);
330 activeTiles
[ GrabBarRight
] = loadPixmap( "bottom-right", titleColor
);
331 activeTiles
[ GrabBarCenter
] = loadPixmap( "bottom-center", titleColor
);
335 // -------------------------------------------------------------------------
336 captionColor
= KDecoration::options()->color( ColorTitleBar
, false );
337 titleColor
= KDecoration::options()->color( ColorTitleBlend
, false );
339 inactiveTiles
[ TitleLeft
] = loadPixmap( "titlebar-left", titleColor
);
340 inactiveTiles
[ TitleRight
] = loadPixmap( "titlebar-right", titleColor
);
342 titleCenter
= loadImage( "titlebar-center", titleColor
);
344 captionLeft
= loadImage( "caption-small-left", captionColor
);
345 captionRight
= loadImage( "caption-small-right", captionColor
);
346 captionCenter
= loadImage( "caption-small-center", captionColor
);
348 inactiveTiles
[ CaptionSmallLeft
] = composite( captionLeft
, titleCenter
);
349 inactiveTiles
[ CaptionSmallRight
] = composite( captionRight
, titleCenter
);
350 inactiveTiles
[ CaptionSmallCenter
] = composite( captionCenter
, titleCenter
);
354 delete captionCenter
;
356 inactiveTiles
[ TitleCenter
] = new QPixmap( QPixmap::fromImage( *titleCenter
) );
360 inactiveTiles
[ BorderLeft
] = loadPixmap( "border-left", titleColor
);
361 inactiveTiles
[ BorderRight
] = loadPixmap( "border-right", titleColor
);
363 if ( largeGrabBars
) {
364 inactiveTiles
[ GrabBarLeft
] = loadPixmap( "grabbar-left", titleColor
);
365 inactiveTiles
[ GrabBarRight
] = loadPixmap( "grabbar-right", titleColor
);
366 inactiveTiles
[ GrabBarCenter
] = loadPixmap( "grabbar-center", titleColor
);
368 inactiveTiles
[ GrabBarLeft
] = loadPixmap( "bottom-left", titleColor
);
369 inactiveTiles
[ GrabBarRight
] = loadPixmap( "bottom-right", titleColor
);
370 inactiveTiles
[ GrabBarCenter
] = loadPixmap( "bottom-center", titleColor
);
374 // -------------------------------------------------------------------------
375 buttonColor
= QColor(); //KDecoration::options()->color( ButtonBg, true );
377 titleButtonRound
= loadPixmap( "titlebutton-round"+size
, buttonColor
);
378 titleButtonSquare
= loadPixmap( "titlebutton-square"+size
, buttonColor
);
381 // Prepare the tiles for use
382 // -------------------------------------------------------------------------
383 if ( QApplication::isRightToLeft() ) {
386 flip( activeTiles
[CaptionSmallLeft
], activeTiles
[CaptionSmallRight
] );
387 flip( inactiveTiles
[CaptionSmallLeft
], inactiveTiles
[CaptionSmallRight
] );
389 flip( activeTiles
[CaptionLargeLeft
], activeTiles
[CaptionLargeRight
] );
391 flip( activeTiles
[TitleLeft
], activeTiles
[TitleRight
] );
392 flip( inactiveTiles
[TitleLeft
], inactiveTiles
[TitleRight
] );
394 flip( activeTiles
[BorderLeft
], activeTiles
[BorderRight
] );
395 flip( inactiveTiles
[BorderLeft
], inactiveTiles
[BorderRight
] );
397 flip( activeTiles
[GrabBarLeft
], activeTiles
[GrabBarRight
] );
398 flip( inactiveTiles
[GrabBarLeft
], inactiveTiles
[GrabBarRight
] );
400 ::flip( titleButtonRound
);
401 ::flip( titleButtonSquare
);
404 // Pretile the center & border tiles for optimal performance
405 pretile( activeTiles
[ CaptionSmallCenter
], 64, Qt::Horizontal
);
406 pretile( activeTiles
[ CaptionLargeCenter
], 64, Qt::Horizontal
);
407 pretile( activeTiles
[ TitleCenter
], 64, Qt::Horizontal
);
408 pretile( activeTiles
[ GrabBarCenter
], 128, Qt::Horizontal
);
409 pretile( activeTiles
[ BorderLeft
], 128, Qt::Vertical
);
410 pretile( activeTiles
[ BorderRight
], 128, Qt::Vertical
);
412 pretile( inactiveTiles
[ CaptionSmallCenter
], 64, Qt::Horizontal
);
413 pretile( inactiveTiles
[ TitleCenter
], 64, Qt::Horizontal
);
414 pretile( inactiveTiles
[ GrabBarCenter
], 128, Qt::Horizontal
);
415 pretile( inactiveTiles
[ BorderLeft
], 128, Qt::Vertical
);
416 pretile( inactiveTiles
[ BorderRight
], 128, Qt::Vertical
);
418 if (heightOffset
> 0) {
419 addHeight (heightOffset
, activeTiles
[TitleLeft
]);
420 addHeight (heightOffset
, activeTiles
[TitleCenter
]);
421 addHeight (heightOffset
, activeTiles
[TitleRight
]);
422 addHeight (heightOffset
, activeTiles
[CaptionSmallLeft
]);
423 addHeight (heightOffset
, activeTiles
[CaptionSmallCenter
]);
424 addHeight (heightOffset
, activeTiles
[CaptionSmallRight
]);
425 addHeight (heightOffset
, activeTiles
[CaptionLargeLeft
]);
426 addHeight (heightOffset
, activeTiles
[CaptionLargeCenter
]);
427 addHeight (heightOffset
, activeTiles
[CaptionLargeRight
]);
429 addHeight (heightOffset
, inactiveTiles
[TitleLeft
]);
430 addHeight (heightOffset
, inactiveTiles
[TitleCenter
]);
431 addHeight (heightOffset
, inactiveTiles
[TitleRight
]);
432 addHeight (heightOffset
, inactiveTiles
[CaptionSmallLeft
]);
433 addHeight (heightOffset
, inactiveTiles
[CaptionSmallCenter
]);
434 addHeight (heightOffset
, inactiveTiles
[CaptionSmallRight
]);
437 if (widthOffset
> 0) {
438 addWidth (widthOffset
, activeTiles
[BorderLeft
], true, activeTiles
[GrabBarCenter
]);
439 addWidth (widthOffset
, activeTiles
[BorderRight
], false, activeTiles
[GrabBarCenter
]);
440 addWidth (widthOffset
, inactiveTiles
[BorderLeft
], true, inactiveTiles
[GrabBarCenter
]);
441 addWidth (widthOffset
, inactiveTiles
[BorderRight
], false, inactiveTiles
[GrabBarCenter
]);
444 widthOffset
= widthOffset
*3/2;
446 addHeight (widthOffset
, activeTiles
[GrabBarLeft
]);
447 addHeight (widthOffset
, activeTiles
[GrabBarCenter
]);
448 addHeight (widthOffset
, activeTiles
[GrabBarRight
]);
449 addHeight (widthOffset
, inactiveTiles
[GrabBarLeft
]);
450 addHeight (widthOffset
, inactiveTiles
[GrabBarCenter
]);
451 addHeight (widthOffset
, inactiveTiles
[GrabBarRight
]);
457 void KeramikHandler::destroyPixmaps()
459 for ( int i
= 0; i
< NumTiles
; i
++ ) {
460 delete activeTiles
[i
];
461 delete inactiveTiles
[i
];
462 activeTiles
[i
] = NULL
;
463 inactiveTiles
[i
] = NULL
;
466 delete titleButtonRound
;
467 delete titleButtonSquare
;
471 void KeramikHandler::addWidth (int width
, QPixmap
*&pix
, bool left
, QPixmap
*bottomPix
) {
472 int w
= pix
->width()+width
;
473 int h
= pix
->height();
475 QPixmap
*tmp
= new QPixmap (w
, h
);
480 for (int i
= 0; i
< h
; i
++)
481 p
.drawPixmap (0, i
, *bottomPix
, i
%2, 0, w
,1);
484 p
.drawPixmap(0, 0, *pix
);
486 p
.drawPixmap(width
, 0, *pix
);
495 void KeramikHandler::addHeight (int height
, QPixmap
*&pix
) {
496 int w
= pix
->width();
497 int h
= pix
->height()+height
;
499 QPixmap
*tmp
= new QPixmap (w
, h
);
502 if (pix
->height() > 10) {
503 p
.drawPixmap(0, 0, *pix
, 0, 0, w
, 11);
504 for (int i
= 0; i
< height
; i
+=2)
505 p
.drawPixmap(0, 11+i
, *pix
, 0, 11, w
, 2);
506 p
.drawPixmap(0, 11+height
, *pix
, 0, 11, w
, -1);
510 int factor
= pix
->height()-3;
511 for (int i
= 0; i
< lines
; i
++)
512 p
.drawPixmap(0, i
, *pix
, 0, i
*factor
/lines
, w
, 1);
513 p
.drawPixmap(0, lines
, *pix
, 0, factor
, w
, 3);
522 void KeramikHandler::flip( QPixmap
*&pix1
, QPixmap
*&pix2
)
524 // Flip the pixmaps horizontally
525 QPixmap
*tmp
= new QPixmap( pix1
->transformed( QMatrix(-1,0,0,1,pix1
->width(),0) ) );
528 pix1
= new QPixmap( pix2
->transformed( QMatrix(-1,0,0,1,pix2
->width(),0) ) );
535 void KeramikHandler::pretile( QPixmap
*&pix
, int size
, Qt::Orientation dir
)
540 if ( dir
== Qt::Horizontal
)
541 newpix
= new QPixmap( size
, pix
->height() );
543 newpix
= new QPixmap( pix
->width(), size
);
546 p
.drawTiledPixmap( newpix
->rect(), *pix
) ;
554 void KeramikHandler::readConfig()
556 KConfig
*c
= new KConfig( "kwinkeramikrc" );
557 KConfigGroup
cg(c
, "General");
558 showIcons
= cg
.readEntry( "ShowAppIcons", true);
559 shadowedText
= cg
.readEntry( "UseShadowedText", true);
560 smallCaptionBubbles
= cg
.readEntry( "SmallCaptionBubbles", false);
561 largeGrabBars
= cg
.readEntry( "LargeGrabBars", true);
563 if ( ! settings_cache
) {
564 settings_cache
= new SettingsCache
;
565 settings_cache
->largeGrabBars
= largeGrabBars
;
566 settings_cache
->smallCaptionBubbles
= smallCaptionBubbles
;
573 QPixmap
*KeramikHandler::composite( QImage
*over
, QImage
*under
)
575 QImage
dest( over
->width(), over
->height(), QImage::Format_ARGB32_Premultiplied
);
578 p
.setCompositionMode( QPainter::CompositionMode_Source
);
579 p
.fillRect( dest
.rect(), Qt::transparent
);
580 p
.drawImage( 0, dest
.height() - under
->height(), *under
);
581 p
.setCompositionMode( QPainter::CompositionMode_SourceOver
);
582 p
.drawImage( 0, 0, *over
);
585 // Create the final pixmap and return it
586 return new QPixmap( QPixmap::fromImage( dest
) );
590 QImage
*KeramikHandler::loadImage( const QString
&name
, const QColor
&col
)
592 if ( col
.isValid() ) {
593 QImage
*img
= new QImage( ":/pics/" + name
+ ".png" );
594 KIconEffect::colorize( *img
, col
, 1.0 );
597 return new QImage( ":/pics/" + name
+ ".png" );
601 QPixmap
*KeramikHandler::loadPixmap( const QString
&name
, const QColor
&col
)
603 QImage
*img
= loadImage( name
, col
);
604 QPixmap
*pix
= new QPixmap( QPixmap::fromImage( *img
) );
611 bool KeramikHandler::reset( unsigned long changed
)
613 keramik_initialized
= false;
615 bool needHardReset
= false;
616 bool pixmapsInvalid
= false;
618 // Re-read the config file
621 if ( changed
& SettingBorder
)
623 pixmapsInvalid
= true;
624 needHardReset
= true;
626 if ( changed
& SettingFont
)
628 pixmapsInvalid
= true;
629 needHardReset
= true;
631 // Check if the color scheme has changed
632 if ( changed
& SettingColors
)
634 pixmapsInvalid
= true;
636 // Check if button positions have changed
638 if ( changed
& SettingButtons
) {
639 needHardReset
= true;
642 // Check if tooltips options have changed
643 if ( changed
& SettingTooltips
) {
644 needHardReset
= true;
647 if ( (settings_cache
->largeGrabBars
!= largeGrabBars
) ) {
648 pixmapsInvalid
= true;
649 needHardReset
= true;
652 if ( (settings_cache
->smallCaptionBubbles
!= smallCaptionBubbles
) ) {
653 needHardReset
= true;
656 // Update our config cache
657 settings_cache
->largeGrabBars
= largeGrabBars
;
658 settings_cache
->smallCaptionBubbles
= smallCaptionBubbles
;
660 // Do we need to recreate the pixmaps?
661 if ( pixmapsInvalid
) {
666 keramik_initialized
= true;
668 // Do we need to "hit the wooden hammer" ?
669 if ( !needHardReset
)
670 resetDecorations( changed
);
671 return needHardReset
;
675 bool KeramikHandler::supports( Ability ability
) const
680 case AbilityAnnounceButtons
:
681 case AbilityAnnounceColors
:
683 case AbilityButtonMenu
:
684 case AbilityButtonOnAllDesktops
:
685 case AbilityButtonSpacer
:
686 case AbilityButtonHelp
:
687 case AbilityButtonMinimize
:
688 case AbilityButtonMaximize
:
689 case AbilityButtonClose
:
690 case AbilityButtonAboveOthers
:
691 case AbilityButtonBelowOthers
:
692 case AbilityButtonShade
:
694 case AbilityColorTitleBack
:
695 case AbilityColorTitleBlend
:
696 case AbilityColorTitleFore
:
704 const QPixmap
*KeramikHandler::tile( TilePixmap tilePix
, bool active
) const
706 return ( active
? activeTiles
[ tilePix
] : inactiveTiles
[ tilePix
] );
709 KDecoration
* KeramikHandler::createDecoration( KDecorationBridge
* bridge
)
711 return new KeramikClient( bridge
, this );
714 QList
< KeramikHandler::BorderSize
> KeramikHandler::borderSizes() const
715 { // the list must be sorted
716 return QList
< BorderSize
>() << BorderNormal
<< BorderLarge
<<
717 BorderVeryLarge
<< BorderHuge
<< BorderVeryHuge
<< BorderOversized
;
721 // -------------------------------------------------------------------------------------------
725 KeramikButton::KeramikButton( KeramikClient
* c
, Button btn
, const QString
&tip
, const int realizeBtns
)
726 : QAbstractButton( c
->widget() ),
727 client( c
), button( btn
), hover( false ), lastbutton( Qt::NoButton
)
729 realizeButtons
= realizeBtns
;
731 this->setToolTip( tip
); // FRAME
732 setAttribute( Qt::WA_NoSystemBackground
);
733 setCursor( Qt::ArrowCursor
);
734 int size
= clientHandler
->roundButton()->height();
735 setFixedSize( size
, size
);
737 setCheckable( (button
== OnAllDesktopsButton
) );
741 KeramikButton::~KeramikButton()
747 void KeramikButton::enterEvent( QEvent
*e
)
749 QAbstractButton::enterEvent( e
);
756 void KeramikButton::leaveEvent( QEvent
*e
)
758 QAbstractButton::leaveEvent( e
);
765 void KeramikButton::mousePressEvent( QMouseEvent
*e
)
767 lastbutton
= e
->button();
768 QMouseEvent
me( e
->type(), e
->pos(), e
->globalPos(),
769 (e
->button()&realizeButtons
)?Qt::LeftButton
: Qt::NoButton
,
770 (e
->button()&realizeButtons
)?Qt::LeftButton
: Qt::NoButton
,
772 QAbstractButton::mousePressEvent( &me
);
776 void KeramikButton::mouseReleaseEvent( QMouseEvent
*e
)
778 lastbutton
= e
->button();
779 QMouseEvent
me( e
->type(), e
->pos(), e
->globalPos(),
780 (e
->button()&realizeButtons
)?Qt::LeftButton
: Qt::NoButton
,
781 (e
->button()&realizeButtons
)?Qt::LeftButton
: Qt::NoButton
,
783 QAbstractButton::mouseReleaseEvent( &me
);
787 void KeramikButton::paintEvent( QPaintEvent
* )
791 int size
= clientHandler
->roundButton()->height();
795 // Get the bevel from the client handler
796 if ( button
== MenuButton
|| button
== OnAllDesktopsButton
|| button
== HelpButton
)
797 pix
= clientHandler
->roundButton();
799 pix
= clientHandler
->squareButton();
801 // Draw the button background
802 const QPixmap
*background
= clientHandler
->tile( TitleCenter
, client
->isActive() );
803 p
.drawPixmap( 0, 0, *background
,
804 0, (background
->height()-size
+1)/2, size
, size
);
808 p
.drawPixmap( QPoint(), *pix
, QStyle::visualRect( QApplication::layoutDirection(), pix
->rect(), QRect(2*size
, 0, size
, size
) ) );
809 p
.translate( QApplication::isRightToLeft() ? -1 : 1, 1 );
812 p
.drawPixmap( QPoint(), *pix
, QStyle::visualRect( QApplication::layoutDirection(), pix
->rect(), QRect(size
, 0, size
, size
) ) );
815 p
.drawPixmap( QPoint(), *pix
, QStyle::visualRect( QApplication::layoutDirection(), pix
->rect(), QRect(0, 0, size
, size
) ) );
818 // Draw the button deco on the bevel
821 deco
= clientHandler
->buttonDeco( Menu
);
824 case OnAllDesktopsButton
:
825 deco
= clientHandler
->buttonDeco( client
->isOnAllDesktops() ? NotOnAllDesktops
: OnAllDesktops
);
829 deco
= clientHandler
->buttonDeco( Help
);
830 // The '?' won't be flipped around in the ctor, so we need to
831 // shift it to the right to compensate for the button shadow
832 // being on the left side of the button in RTL mode.
833 if ( QApplication::isRightToLeft() )
838 deco
= clientHandler
->buttonDeco( Minimize
);
842 deco
= clientHandler
->buttonDeco( client
->maximizeMode() == KeramikClient::MaximizeFull
? Restore
: Maximize
);
846 deco
= clientHandler
->buttonDeco( Close
);
850 deco
= clientHandler
->buttonDeco( client
->keepAbove() ? AboveOn
: AboveOff
);
854 deco
= clientHandler
->buttonDeco( client
->keepBelow() ? BelowOn
: BelowOff
);
858 deco
= clientHandler
->buttonDeco( client
->isSetShade() ? ShadeOn
: ShadeOff
);
865 p
.setPen( Qt::black
); // ### hardcoded color
867 p
.drawPixmap( (size
-17)/2, (size
-17)/2, *deco
);
872 // ------------------------------------------------------------------------------------------
876 KeramikClient::KeramikClient( KDecorationBridge
* bridge
, KDecorationFactory
* factory
)
877 : KDecoration( bridge
, factory
),
878 activeIcon( NULL
), inactiveIcon( NULL
), captionBufferDirty( true ), maskDirty( true )
882 void KeramikClient::init()
884 connect( this, SIGNAL( keepAboveChanged( bool )), SLOT( keepAboveChange( bool )));
885 connect( this, SIGNAL( keepBelowChanged( bool )), SLOT( keepBelowChange( bool )));
888 widget()->setAttribute( Qt::WA_StaticContents
);
889 widget()->installEventFilter( this );
892 widget()->setAttribute( Qt::WA_NoSystemBackground
);
894 for ( int i
=0; i
< NumButtons
; i
++ )
900 void KeramikClient::createLayout()
903 QVBoxLayout
*mainLayout
= new QVBoxLayout( widget() );
904 QBoxLayout
*titleLayout
= new QBoxLayout( QBoxLayout::LeftToRight
);
905 QHBoxLayout
*windowLayout
= new QHBoxLayout();
907 mainLayout
->setMargin( 0 );
908 mainLayout
->setSpacing( 0 );
910 titleLayout
->setMargin( 0 );
911 titleLayout
->setSpacing( 0 );
913 windowLayout
->setMargin( 0 );
914 windowLayout
->setSpacing( 0 );
916 largeTitlebar
= ( !maximizedVertical() && clientHandler
->largeCaptionBubbles() );
917 largeCaption
= ( isActive() && largeTitlebar
);
919 int grabBarHeight
= clientHandler
->grabBarHeight();
920 int topSpacing
= ( largeTitlebar
? 4 : 1 );
921 int leftBorderWidth
= clientHandler
->tile( BorderLeft
, true )->width();
922 int rightBorderWidth
= clientHandler
->tile( BorderRight
, true )->width();
923 topSpacer
= new QSpacerItem( 10, topSpacing
,
924 QSizePolicy::Expanding
, QSizePolicy::Minimum
);
926 mainLayout
->addItem( topSpacer
);
928 mainLayout
->addLayout( titleLayout
); // Titlebar
929 mainLayout
->addLayout( windowLayout
, 1 ); // Left border + window + right border
930 mainLayout
->addSpacing( grabBarHeight
); // Bottom grab bar
932 titleLayout
->setSpacing( buttonSpacing
);
934 titleLayout
->addSpacing( buttonMargin
); // Left button margin
935 addButtons( titleLayout
, options()->customButtonPositions() ?
936 options()->titleButtonsLeft() : KDecorationOptions::defaultTitleButtonsLeft() );
938 titlebar
= new QSpacerItem( 10, clientHandler
->titleBarHeight(largeTitlebar
)
939 - topSpacing
, QSizePolicy::Expanding
, QSizePolicy::Minimum
);
940 titleLayout
->addItem( titlebar
);
942 titleLayout
->addSpacing( buttonSpacing
);
943 addButtons( titleLayout
, options()->customButtonPositions() ?
944 options()->titleButtonsRight() : KDecorationOptions::defaultTitleButtonsRight() );
945 titleLayout
->addSpacing( buttonMargin
- 1 ); // Right button margin
947 windowLayout
->addSpacing( leftBorderWidth
); // Left border
950 QWidget
*previewWidget
= new QLabel( i18n( "<center><b>Keramik preview</b></center>" ), widget() );
951 previewWidget
->setAutoFillBackground( true );
952 windowLayout
->addWidget( previewWidget
);
955 windowLayout
->addItem( new QSpacerItem( 0, 0 )); //no widget in the middle
956 windowLayout
->addSpacing( rightBorderWidth
); // Right border
960 KeramikClient::~KeramikClient()
965 activeIcon
= inactiveIcon
= NULL
;
969 void KeramikClient::reset( unsigned long )
971 if ( clientHandler
->largeCaptionBubbles() && !largeTitlebar
)
973 // We're switching from small caption bubbles to large
974 if ( !maximizedVertical() ) {
975 topSpacer
->changeSize( 10, 4, QSizePolicy::Expanding
, QSizePolicy::Minimum
);
976 largeTitlebar
= true;
977 largeCaption
= isActive();
979 widget()->layout()->activate();
981 // Compensate for the titlebar size change
983 // TODO This is wrong, this may break size increments (see bug #53784).
985 widget()->setGeometry( widget()->x(), widget()->y() - 3, width(), height() + 3 );
988 else if ( !clientHandler
->largeCaptionBubbles() && largeTitlebar
)
990 // We're switching from large caption bubbles to small
991 topSpacer
->changeSize( 10, 1, QSizePolicy::Expanding
, QSizePolicy::Minimum
);
992 largeTitlebar
= largeCaption
= false;
994 widget()->layout()->activate();
996 // Compensate for the titlebar size change
998 widget()->setGeometry( widget()->x(), widget()->y() + 3, width(), height() - 3 );
1001 calculateCaptionRect();
1003 captionBufferDirty
= maskDirty
= true;
1005 // Only repaint the window if it's visible
1006 // (i.e. not minimized and on the current desktop)
1007 if ( widget()->isVisible() ) {
1008 widget()->repaint();
1010 for ( int i
= 0; i
< NumButtons
; i
++ )
1011 if ( button
[i
] ) button
[i
]->repaint();
1016 void KeramikClient::addButtons( QBoxLayout
*layout
, const QString
&s
)
1018 for ( int i
=0; i
< s
.length(); i
++ )
1020 switch ( s
[i
].toLatin1() )
1024 if ( !button
[MenuButton
] ) {
1025 button
[MenuButton
] = new KeramikButton( this, MenuButton
, i18n("Menu"), Qt::LeftButton
|Qt::RightButton
);
1026 connect( button
[MenuButton
], SIGNAL( pressed() ), SLOT( menuButtonPressed() ) );
1027 layout
->addWidget( button
[MenuButton
] );
1031 // OnAllDesktops button
1033 if ( !button
[OnAllDesktopsButton
] ) {
1034 button
[OnAllDesktopsButton
] = new KeramikButton( this,
1035 OnAllDesktopsButton
, isOnAllDesktops()?i18n("Not on all desktops"):i18n("On all desktops") );
1036 if(isOnAllDesktops())
1037 button
[OnAllDesktopsButton
]->toggle();
1038 connect( button
[OnAllDesktopsButton
], SIGNAL( clicked() ), SLOT( toggleOnAllDesktops() ) );
1039 layout
->addWidget( button
[OnAllDesktopsButton
] );
1045 if ( !button
[HelpButton
] && providesContextHelp() ) {
1046 button
[HelpButton
] = new KeramikButton( this, HelpButton
, i18n("Help") );
1047 connect( button
[HelpButton
], SIGNAL( clicked() ), SLOT( showContextHelp() ) );
1048 layout
->addWidget( button
[HelpButton
] );
1054 if ( !button
[MinButton
] && isMinimizable() ) {
1055 button
[MinButton
] = new KeramikButton( this, MinButton
, i18n("Minimize") );
1056 connect( button
[MinButton
], SIGNAL( clicked() ), SLOT( minimize() ) );
1057 layout
->addWidget( button
[MinButton
] );
1063 if ( !button
[MaxButton
] && isMaximizable() ) {
1064 button
[MaxButton
] = new KeramikButton( this, MaxButton
, i18n("Maximize"), Qt::LeftButton
|Qt::MidButton
|Qt::RightButton
);
1065 connect( button
[MaxButton
], SIGNAL( clicked() ), SLOT( slotMaximize() ) );
1066 layout
->addWidget( button
[MaxButton
] );
1072 if ( !button
[CloseButton
] && isCloseable() ) {
1073 button
[CloseButton
] = new KeramikButton( this, CloseButton
, i18n("Close") );
1074 connect( button
[CloseButton
], SIGNAL( clicked() ), SLOT( closeWindow() ) );
1075 layout
->addWidget( button
[CloseButton
] );
1081 if ( !button
[AboveButton
]) {
1082 button
[AboveButton
] = new KeramikButton( this, AboveButton
, i18n("Keep Above Others") );
1083 connect( button
[AboveButton
], SIGNAL( clicked() ), SLOT( slotAbove() ) );
1084 layout
->addWidget( button
[AboveButton
] );
1090 if ( !button
[BelowButton
]) {
1091 button
[BelowButton
] = new KeramikButton( this, BelowButton
, i18n("Keep Below Others") );
1092 connect( button
[BelowButton
], SIGNAL( clicked() ), SLOT( slotBelow() ) );
1093 layout
->addWidget( button
[BelowButton
] );
1099 if ( !button
[ShadeButton
] && isShadeable() ) {
1100 button
[ShadeButton
] = new KeramikButton( this, ShadeButton
,
1101 isSetShade() ? i18n("Unshade") : i18n( "Shade" ));
1102 connect( button
[ShadeButton
], SIGNAL( clicked() ), SLOT( slotShade() ) );
1103 layout
->addWidget( button
[ShadeButton
] );
1107 // Additional spacing
1109 layout
->addSpacing( buttonSpacing
);
1116 void KeramikClient::updateMask()
1118 if ( !keramik_initialized
)
1121 // To maximize performance this code uses precalculated bounding rects
1122 // to set the window mask. This saves us from having to allocate a 1bpp
1123 // pixmap, paint the mask on it and then have the X server iterate
1124 // over the pixels to compute the bounding rects from it.
1127 register int w
, y
= 0;
1130 if ( QApplication::isRightToLeft() ) {
1132 // If the caption bubble is visible and extends above the titlebar
1133 if ( largeCaption
&& captionRect
.width() >= 25 ) {
1134 register int x
= captionRect
.left();
1135 w
= captionRect
.width();
1136 r
+= QRegion( x
+ 11, y
++, w
- 19, 1 );
1137 r
+= QRegion( x
+ 9, y
++, w
- 15, 1 );
1138 r
+= QRegion( x
+ 7, y
++, w
- 12, 1 );
1142 // Do we have a large titlebar with a retracted caption bubble?
1143 // (i.e. the style is set to use large caption bubbles, we're
1144 // not maximized and not active)
1145 if ( largeTitlebar
)
1149 w
= width(); // FRAME
1151 // The rounded titlebar corners
1152 r
+= QRegion( 9, y
++, w
- 17, 1 );
1153 r
+= QRegion( 7, y
++, w
- 13, 1 );
1154 r
+= QRegion( 5, y
++, w
- 9, 1 );
1155 r
+= QRegion( 4, y
++, w
- 7, 1 );
1156 r
+= QRegion( 3, y
++, w
- 5, 1 );
1157 r
+= QRegion( 2, y
++, w
- 4, 1 );
1158 r
+= QRegion( 1, y
++, w
- 2, 2 );
1161 // If the caption bubble is visible and extends above the titlebar
1162 if ( largeCaption
&& captionRect
.width() >= 25 ) {
1164 register int x
= captionRect
.left();
1165 w
= captionRect
.width();
1166 r
+= QRegion( x
+ 8, y
++, w
- 19, 1 );
1167 r
+= QRegion( x
+ 6, y
++, w
- 15, 1 );
1168 r
+= QRegion( x
+ 5, y
++, w
- 12, 1 );
1172 // Do we have a large titlebar with a retracted caption bubble?
1173 // (i.e. the style is set to use large caption bubbles, we're
1174 // not maximized and not active)
1175 if ( largeTitlebar
)
1179 w
= width(); // FRAME
1181 // The rounded titlebar corners
1182 r
+= QRegion( 8, y
++, w
- 17, 1 );
1183 r
+= QRegion( 6, y
++, w
- 13, 1 );
1184 r
+= QRegion( 4, y
++, w
- 9, 1 );
1185 r
+= QRegion( 3, y
++, w
- 7, 1 );
1186 r
+= QRegion( 2, y
++, w
- 5, 1 );
1187 r
+= QRegion( 2, y
++, w
- 4, 1 );
1188 r
+= QRegion( 1, y
++, w
- 2, 2 );
1193 // The part of the window below the titlebar
1194 r
+= QRegion( 0, y
, w
, height() - y
);
1196 setMask( r
, YXBanded
);
1202 void KeramikClient::updateCaptionBuffer()
1204 if ( !keramik_initialized
)
1207 bool active
= isActive();
1208 QPixmap
*icon
= NULL
;
1210 if ( captionBuffer
.size() != captionRect
.size() )
1211 captionBuffer
= QPixmap( captionRect
.size() );
1213 if ( captionBuffer
.isNull() )
1216 QPainter
p( &captionBuffer
);
1218 // Draw the caption bubble
1219 if ( active
&& largeCaption
) {
1220 p
.drawPixmap( 0, 0, *clientHandler
->tile( CaptionLargeLeft
, true ) );
1221 p
.drawTiledPixmap( 15, 0, captionRect
.width() - 30, captionRect
.height(),
1222 *clientHandler
->tile( CaptionLargeCenter
, true ) );
1223 p
.drawPixmap( captionRect
.width() - 15, 0, *clientHandler
->tile( CaptionLargeRight
, true ) );
1225 p
.drawPixmap( 0, 0, *clientHandler
->tile( CaptionSmallLeft
, active
) );
1226 p
.drawTiledPixmap( 15, 0, captionRect
.width() - 30, captionRect
.height(),
1227 *clientHandler
->tile( CaptionSmallCenter
, active
) );
1228 p
.drawPixmap( captionRect
.width() - 15, 0, *clientHandler
->tile( CaptionSmallRight
, active
) );
1231 if ( clientHandler
->showAppIcons() )
1233 QStyle
*style
= QApplication::style();
1236 activeIcon
= new QPixmap( this->icon().pixmap( style
->pixelMetric( QStyle::PM_SmallIconSize
), QIcon::Normal
)); // FRAME
1239 if ( ! inactiveIcon
) {
1240 QImage img
= this->icon().pixmap( style
->pixelMetric( QStyle::PM_SmallIconSize
), QIcon::Normal
).toImage();
1241 KIconEffect::semiTransparent( img
);
1242 inactiveIcon
= new QPixmap( QPixmap::fromImage( img
) );
1244 icon
= inactiveIcon
;
1248 p
.setFont( options()->font( active
) );
1249 int tw
= p
.fontMetrics().width( caption() ) +
1250 ( clientHandler
->showAppIcons() ? 16 + iconSpacing
: 0 );
1252 int xpos
= qMax( (captionRect
.width() - tw
) / 3, 8 );
1253 QRect tr
= QStyle::visualRect( QApplication::layoutDirection(), captionBuffer
.rect(),
1254 QRect(xpos
, 1, captionRect
.width() - xpos
- 10, captionRect
.height() - 4) );
1256 //p.setPen( Qt::red ); // debug
1257 //p.drawRect( tr ); // debug
1260 if ( clientHandler
->showAppIcons() )
1262 QRect iconRect
= QStyle::visualRect( QApplication::layoutDirection(), tr
,
1263 QRect(tr
.x(), 1 + (captionRect
.height() - 4 - 16) / 2, 16, 16) );
1264 QRect
r( icon
->rect() );
1265 r
.moveCenter( iconRect
.center() );
1267 if ( tr
.width() > 16 ) {
1268 p
.drawPixmap( r
, *icon
);
1270 QRect
sr( 0, 0, icon
->width(), icon
->height() );
1272 if ( QApplication::isRightToLeft() )
1273 sr
.adjust( icon
->width() - tr
.width(), 0, 0, 0 );
1275 sr
.adjust( 0, 0, -( icon
->width() - tr
.width() ), 0 );
1277 p
.drawPixmap( r
.x() + sr
.x(), r
.y() + sr
.y(), *icon
,
1278 sr
.x(), sr
.y(), sr
.width(), sr
.height() );
1281 //p.drawRect( r ); // debug
1283 if ( QApplication::isRightToLeft() )
1284 tr
.adjust( 0, 0, -(16 + iconSpacing
), 0 );
1286 tr
.adjust( (16 + iconSpacing
), 0, 0, 0 );
1289 // Draw the titlebar text
1290 int flags
= Qt::AlignVCenter
| Qt::TextSingleLine
;
1291 flags
|= ( QApplication::isRightToLeft() ? Qt::AlignRight
: Qt::AlignLeft
);
1293 if ( clientHandler
->useShadowedText() )
1295 p
.translate( QApplication::isRightToLeft() ? -1 : 1, 1 );
1296 //p.setPen( options()->color(ColorTitleBar, active).dark() );
1297 if (qGray(options()->color(ColorFont
, active
).rgb()) < 100)
1298 p
.setPen( QColor(200,200,200) );
1300 p
.setPen( Qt::black
);
1301 p
.drawText( tr
, flags
, caption() );
1302 p
.translate( QApplication::isRightToLeft() ? 1 : -1, -1 );
1305 p
.setPen( options()->color( ColorFont
, active
) );
1306 p
.drawText( tr
, flags
, caption() );
1308 captionBufferDirty
= false;
1312 void KeramikClient::calculateCaptionRect()
1314 QFontMetrics
fm( options()->font(isActive()) );
1315 int cw
= fm
.width( caption() ) + 95;
1316 int titleBaseY
= ( largeTitlebar
? 3 : 0 );
1318 if ( clientHandler
->showAppIcons() )
1319 cw
+= 16 + 4; // icon width + space
1321 cw
= qMin( cw
, titlebar
->geometry().width() );
1322 captionRect
= QStyle::visualRect( QApplication::layoutDirection(), titlebar
->geometry(),
1323 QRect(titlebar
->geometry().x(), (largeCaption
? 0 : titleBaseY
),
1324 cw
, clientHandler
->titleBarHeight(largeCaption
) ) );
1328 void KeramikClient::captionChange()
1330 QRect
r( captionRect
);
1331 calculateCaptionRect();
1333 if ( r
.size() != captionRect
.size() )
1336 captionBufferDirty
= true;
1338 widget()->repaint( r
| captionRect
);
1342 void KeramikClient::iconChange()
1344 if ( clientHandler
->showAppIcons() ) {
1346 // Force updateCaptionBuffer() to recreate the cached icons
1349 delete inactiveIcon
;
1351 activeIcon
= inactiveIcon
= NULL
;
1353 captionBufferDirty
= true;
1354 widget()->repaint( captionRect
);
1359 void KeramikClient::activeChange()
1361 bool active
= isActive();
1362 // Note: It's assumed that the same font will always be used for both active
1363 // and inactive windows, since the fonts kcm hasn't supported setting
1364 // different fonts for different window states for some time.
1365 if ( largeTitlebar
) {
1366 largeCaption
= ( active
&& !maximizedVertical() );
1367 calculateCaptionRect();
1371 captionBufferDirty
= true;
1373 widget()->repaint();
1375 for ( int i
=0; i
< NumButtons
; i
++ )
1376 if ( button
[i
] ) button
[i
]->repaint();
1380 void KeramikClient::maximizeChange()
1382 if ( clientHandler
->largeCaptionBubbles() )
1384 if ( maximizeMode() & MaximizeVertical
) {
1385 // We've been maximized - shrink the titlebar by 3 pixels
1386 topSpacer
->changeSize( 10, 1, QSizePolicy::Expanding
, QSizePolicy::Minimum
);
1387 largeCaption
= largeTitlebar
= false;
1389 calculateCaptionRect();
1390 captionBufferDirty
= maskDirty
= true;
1392 widget()->layout()->activate();
1393 widget()->repaint();
1394 } else if (( maximizeMode() & MaximizeVertical
) == 0 && !largeTitlebar
) {
1395 // We've been restored - enlarge the titlebar by 3 pixels
1396 topSpacer
->changeSize( 10, 4, QSizePolicy::Expanding
, QSizePolicy::Minimum
);
1397 largeCaption
= largeTitlebar
= true;
1399 calculateCaptionRect();
1400 captionBufferDirty
= maskDirty
= true;
1402 widget()->layout()->activate();
1403 widget()->repaint();
1407 if ( button
[ MaxButton
] ) {
1408 button
[ MaxButton
]->setToolTip( maximizeMode() == MaximizeFull
? i18n("Restore") : i18n("Maximize") );
1409 button
[ MaxButton
]->repaint();
1414 void KeramikClient::desktopChange()
1416 if ( button
[ OnAllDesktopsButton
] )
1418 button
[ OnAllDesktopsButton
]->repaint();
1419 button
[ OnAllDesktopsButton
]->setToolTip( isOnAllDesktops() ? i18n("Not on all desktops") : i18n("On all desktops") );
1424 void KeramikClient::shadeChange()
1426 if ( button
[ ShadeButton
] )
1428 button
[ ShadeButton
]->repaint();
1429 button
[ ShadeButton
]->setToolTip( isSetShade() ? i18n("Unshade") : i18n("Shade") );
1434 void KeramikClient::keepAboveChange( bool )
1436 if ( button
[ AboveButton
] )
1437 button
[ AboveButton
]->repaint();
1441 void KeramikClient::keepBelowChange( bool )
1443 if ( button
[ BelowButton
] )
1444 button
[ BelowButton
]->repaint();
1448 void KeramikClient::menuButtonPressed()
1450 QPoint
menuTop ( button
[MenuButton
]->rect().topLeft() );
1451 QPoint
menuBottom ( button
[MenuButton
]->rect().bottomRight() );
1452 menuTop
+= QPoint(-6, -3);
1453 menuBottom
+= QPoint(6, 3);
1454 KDecorationFactory
* f
= factory();
1455 showWindowMenu( QRect( button
[MenuButton
]->mapToGlobal( menuTop
),
1456 button
[MenuButton
]->mapToGlobal( menuBottom
)) );
1457 if( !f
->exists( this )) // 'this' was destroyed
1459 button
[MenuButton
]->setDown(false);
1463 void KeramikClient::slotMaximize()
1465 maximize( button
[ MaxButton
]->lastButton() );
1469 void KeramikClient::slotAbove()
1471 setKeepAbove( !keepAbove());
1472 button
[ AboveButton
]->repaint();
1476 void KeramikClient::slotBelow()
1478 setKeepBelow( !keepBelow());
1479 button
[ BelowButton
]->repaint();
1483 void KeramikClient::slotShade()
1485 setShade( !isSetShade());
1486 button
[ ShadeButton
]->repaint();
1490 void KeramikClient::paintEvent( QPaintEvent
*e
)
1492 if ( !keramik_initialized
)
1495 QPainter
p( widget());
1496 QRect
updateRect( e
->rect() );
1497 bool active
= isActive();
1499 int titleBaseY
= ( largeTitlebar
? 3 : 0 );
1500 int titleBarHeight
= clientHandler
->titleBarHeight( largeTitlebar
);
1501 int grabBarHeight
= clientHandler
->grabBarHeight();
1502 int leftBorderWidth
= clientHandler
->tile( BorderLeft
, active
)->width();
1503 int rightBorderWidth
= clientHandler
->tile( BorderRight
, active
)->width();
1509 // -----------------------------------------------------------------------
1510 if ( updateRect
.y() < titleBarHeight
)
1512 int titleBarBaseHeight
= titleBarHeight
- titleBaseY
;
1514 if ( captionBufferDirty
)
1515 updateCaptionBuffer();
1518 if ( updateRect
.x() < 15 )
1519 p
.drawPixmap( 0, titleBaseY
,
1520 *clientHandler
->tile( TitleLeft
, active
) );
1522 // Space between the top left corner and the caption bubble
1523 if ( updateRect
.x() < captionRect
.left() && updateRect
.right() >= 15 ) {
1524 int x1
= qMax( 15, updateRect
.x() );
1525 int x2
= qMin( captionRect
.left(), updateRect
.right() );
1527 p
.drawTiledPixmap( x1
, titleBaseY
, x2
- x1
+ 1, titleBarBaseHeight
,
1528 *clientHandler
->tile( TitleCenter
, active
) );
1532 if ( updateRect
.x() <= captionRect
.right() && updateRect
.right() > 15 ) {
1533 if ( captionRect
.width() >= 25 )
1534 p
.drawPixmap( captionRect
.left(), active
? 0 : titleBaseY
, captionBuffer
);
1536 p
.drawTiledPixmap( captionRect
.x(), titleBaseY
, captionRect
.width(),
1537 titleBarBaseHeight
, *clientHandler
->tile( TitleCenter
, active
) );
1540 // Space between the caption bubble and the top right corner
1541 if ( updateRect
.right() > captionRect
.right() && updateRect
.x() < width() - 15 ) { // FRAME
1542 int x1
= qMax( captionRect
.right() + 1, updateRect
.x() );
1543 int x2
= qMin( width() - 15, updateRect
.right() );
1545 p
.drawTiledPixmap( x1
, titleBaseY
, x2
- x1
+ 1, titleBarBaseHeight
,
1546 *clientHandler
->tile( TitleCenter
, active
) );
1550 if ( updateRect
.right() >= width() - 15 )
1551 p
.drawPixmap( width() - 15, titleBaseY
,
1552 *clientHandler
->tile( TitleRight
, active
) );
1556 // -----------------------------------------------------------------------
1557 if ( updateRect
.bottom() >= titleBarHeight
&&
1558 updateRect
.top() < height() - grabBarHeight
)
1560 int top
= qMax( titleBarHeight
, updateRect
.top() );
1561 int bottom
= qMin( updateRect
.bottom(), height() - grabBarHeight
);
1564 if ( updateRect
.x() < leftBorderWidth
)
1565 p
.drawTiledPixmap( 0, top
, leftBorderWidth
, bottom
- top
+ 1,
1566 *clientHandler
->tile( BorderLeft
, active
) );
1569 if ( e
->rect().right() > width() - rightBorderWidth
- 1 )
1570 p
.drawTiledPixmap( width() - rightBorderWidth
, top
, rightBorderWidth
,
1571 bottom
- top
+ 1, *clientHandler
->tile( BorderRight
, active
) );
1575 // -----------------------------------------------------------------------
1576 if ( updateRect
.bottom() >= height() - grabBarHeight
) {
1577 // Bottom left corner
1578 if ( updateRect
.x() < 9 )
1579 p
.drawPixmap( 0, height() - grabBarHeight
,
1580 *clientHandler
->tile( GrabBarLeft
, active
) );
1582 // Space between the left corner and the right corner
1583 if ( updateRect
.x() < width() - 9 ) {
1584 int x1
= qMax( 9, updateRect
.x() );
1585 int x2
= qMin( width() - 9, updateRect
.right() );
1587 p
.drawTiledPixmap( x1
, height() - grabBarHeight
, x2
- x1
+ 1,
1588 grabBarHeight
, *clientHandler
->tile( GrabBarCenter
, active
) );
1591 // Bottom right corner
1592 if ( updateRect
.right() > width() - 9 )
1593 p
.drawPixmap( width() - 9, height() - grabBarHeight
,
1594 *clientHandler
->tile( GrabBarRight
, active
) );
1597 // Extra drawline for the 1 pixel empty space QLayout leaves when a window is shaded.
1598 p
.setPen( options()->color( ColorTitleBlend
, active
) );
1599 p
.drawLine( leftBorderWidth
, height() - grabBarHeight
- 1,
1600 width() - rightBorderWidth
- 1, height() - grabBarHeight
- 1 );
1604 void KeramikClient::resizeEvent( QResizeEvent
*e
)
1606 // FRAME Client::resizeEvent( e );
1608 QRect
r( captionRect
);
1609 calculateCaptionRect();
1611 if ( r
.size() != captionRect
.size() )
1612 captionBufferDirty
= true;
1616 if ( widget()->isVisible() )
1618 widget()->update( widget()->rect() );
1622 if ( e
->oldSize().width() != width() )
1623 dx
= 32 + qAbs( e
->oldSize().width() - width() );
1625 if ( e
->oldSize().height() != height() )
1626 dy
= 8 + qAbs( e
->oldSize().height() - height() );
1629 widget()->update( 0, height() - dy
+ 1, width(), dy
);
1633 widget()->update( width() - dx
+ 1, 0, dx
, height() );
1634 widget()->update( QRect( QPoint(4,4), titlebar
->geometry().bottomLeft() - QPoint(1,0) ) );
1635 widget()->update( QRect( titlebar
->geometry().topRight(), QPoint( width() - 4,
1636 titlebar
->geometry().bottom() ) ) );
1637 // Titlebar needs no paint event
1638 QApplication::postEvent( this, new QPaintEvent( titlebar
->geometry() ) );
1644 void KeramikClient::mouseDoubleClickEvent( QMouseEvent
*e
)
1646 if ( e
->button() == Qt::LeftButton
1647 && QRect( 0, 0, width(), clientHandler
->titleBarHeight( largeTitlebar
) ).contains( e
->pos() ) )
1648 titlebarDblClickOperation();
1652 KeramikClient::Position
KeramikClient::mousePosition( const QPoint
&p
) const
1654 int titleBaseY
= (largeTitlebar
? 3 : 0);
1656 int leftBorder
= clientHandler
->tile( BorderLeft
, true )->width();
1657 int rightBorder
= width() - clientHandler
->tile( BorderRight
, true )->width() - 1;
1658 int bottomBorder
= height() - clientHandler
->grabBarHeight() - 1;
1659 int bottomCornerSize
= 3*clientHandler
->tile( BorderRight
, true )->width()/2 + 24;
1661 // Test if the mouse is over the titlebar area
1662 if ( p
.y() < titleBaseY
+ 11 ) {
1663 // Test for the top left corner
1664 if ( p
.x() < leftBorder
+ 11 ) {
1665 if ( (p
.y() < titleBaseY
+ 3 && p
.x() < leftBorder
+ 11) ||
1666 (p
.y() < titleBaseY
+ 6 && p
.x() < leftBorder
+ 6) ||
1667 (p
.y() < titleBaseY
+ 11 && p
.x() < leftBorder
+ 3) )
1668 return PositionTopLeft
;
1671 // Test for the top right corner
1672 if ( p
.x() > rightBorder
- 11 ) {
1673 if ( (p
.y() < titleBaseY
+ 3 && p
.x() > rightBorder
- 11) ||
1674 (p
.y() < titleBaseY
+ 6 && p
.x() > rightBorder
- 6) ||
1675 (p
.y() < titleBaseY
+ 11 && p
.x() > rightBorder
- 3) )
1676 return PositionTopRight
;
1679 // Test for the top border
1680 if ( p
.y() <= 3 || (p
.y() <= titleBaseY
+3 &&
1681 (p
.x() < captionRect
.left() || p
.x() > captionRect
.right()) ) )
1684 // The cursor must be over the center of the titlebar.
1685 return PositionCenter
;
1689 else if ( p
.y() < bottomBorder
) {
1690 // Test for the left side
1691 if ( p
.x() < leftBorder
) {
1692 if ( p
.y() < height() - bottomCornerSize
)
1693 return PositionLeft
;
1695 return PositionBottomLeft
;
1698 // Test for the right side
1699 else if ( p
.x() > rightBorder
) {
1700 if ( p
.y() < height() - bottomCornerSize
)
1701 return PositionRight
;
1703 return PositionBottomRight
;
1706 // The cursor must be over the center of the window
1707 return PositionCenter
;
1710 // Test the grab bar / bottom border
1712 // Test for the bottom left corner
1713 if ( p
.x() < bottomCornerSize
)
1714 return PositionBottomLeft
;
1716 // Test for the bottom right corner
1717 else if ( p
.x() > width() - bottomCornerSize
- 1 )
1718 return PositionBottomRight
;
1720 // The cursor must be over the bottom border
1721 return PositionBottom
;
1724 // We should never get here
1725 return PositionCenter
;
1729 void KeramikClient::resize( const QSize
& s
)
1731 widget()->resize( s
);
1735 void KeramikClient::borders( int& left
, int& right
, int& top
, int& bottom
) const
1737 int titleBarHeight
= clientHandler
->titleBarHeight( clientHandler
->largeCaptionBubbles() );
1738 int grabBarHeight
= clientHandler
->grabBarHeight();
1739 int leftBorderWidth
= clientHandler
->tile( BorderLeft
, isActive() )->width();
1740 int rightBorderWidth
= clientHandler
->tile( BorderRight
, isActive() )->width();
1742 left
= leftBorderWidth
;
1743 right
= rightBorderWidth
;
1744 top
= titleBarHeight
;
1745 bottom
= grabBarHeight
;
1747 if ( ( maximizeMode() & MaximizeHorizontal
) && !options()->moveResizeMaximizedWindows())
1749 if( maximizeMode() & MaximizeVertical
)
1751 top
= clientHandler
->titleBarHeight( false );
1752 if( !options()->moveResizeMaximizedWindows())
1758 QSize
KeramikClient::minimumSize() const
1760 return widget()->minimumSize();
1764 bool KeramikClient::eventFilter( QObject
* o
, QEvent
* e
)
1766 if ( o
!= widget() )
1769 switch ( e
->type() )
1771 case QEvent::Resize
:
1772 resizeEvent( static_cast< QResizeEvent
* >( e
) );
1776 paintEvent( static_cast< QPaintEvent
* >( e
) );
1779 case QEvent::MouseButtonDblClick
:
1780 mouseDoubleClickEvent( static_cast< QMouseEvent
* >( e
) );
1783 case QEvent::MouseButtonPress
:
1784 processMousePressEvent( static_cast< QMouseEvent
* >( e
) );
1792 } // namespace Keramik
1796 // -------------------------------------------------------------------------------------------
1802 KDE_EXPORT KDecorationFactory
*create_factory()
1804 Keramik::clientHandler
= new Keramik::KeramikHandler();
1805 return Keramik::clientHandler
;
1811 // vim: set noet ts=4 sw=4: