Fix some error
[kdeartwork.git] / kwin-styles / icewm / icewm.cpp
blobe36c96511bf39776563e3eba2f1b5a1a2f4620d7
1 /*
2 $Id$
4 Gallium-IceWM themeable KWin client
6 Copyright 2001
7 Karol Szwed <gallium@kde.org>
8 http://gallium.n3.net/
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public
12 License as published by the Free Software Foundation; either
13 version 2 of the License, or (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; see the file COPYING. If not, write to
22 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 Boston, MA 02110-1301, USA.
25 -----------------------------------------------------------------------------
26 This client loads most icewm 1.0.X pixmap themes, without taking into account
27 specific font settings for clients, or coloured mouse cursors. Titlebar
28 fonts can be changed via the kde control center. Bi-colour mouse cursors
29 may be added in future if requested by users, as well as theme font support.
30 Any styles using inbuilt icewm titlebar drawing without using pixmaps (e.g.
31 Warp4, win95 etc.) are not fully supported, and may cause drawing errors,
32 as these themes use in-built icewm drawing mechanisms.
34 When a pixmap theme is not present (or a corrupt one is present) then very
35 plain title decorations are painted instead, so that users don't see
36 non-painted window areas where possible ;)
38 At a later date, frame shaping may be added if really requested, and an
39 update to support the latest icewm 1.1.X theme format may be made.
43 #include <kconfig.h>
44 #include <kstandarddirs.h>
45 #include <kglobal.h>
46 #include <klocale.h>
47 #include <kdrawutil.h>
48 #include <qapplication.h>
49 #include <qlabel.h>
50 #include <qdrawutil.h>
51 #include <qdatetime.h>
52 #include <qbitmap.h>
53 #include <qcursor.h>
54 #include <qstring.h>
55 #include <qtooltip.h>
56 #include <qregexp.h>
57 //Added by qt3to4:
58 #include <QPixmap>
59 #include <QPaintEvent>
60 #include <QGridLayout>
61 #include <QEvent>
62 #include <QBoxLayout>
63 #include <QShowEvent>
64 #include <QResizeEvent>
65 #include <QMouseEvent>
66 #include "icewm.h"
68 namespace IceWM {
70 ////////////////////////////////////////////////////////////////////////////////////////////
71 // Here's the global pixmap stuff - as memory efficient as it can be :)
72 ////////////////////////////////////////////////////////////////////////////////////////////
74 // IceWM frame pixmaps
75 QPixmap* frameTL[] = {NULL, NULL};
76 QPixmap* frameT [] = {NULL, NULL};
77 QPixmap* frameTR[] = {NULL, NULL};
78 QPixmap* frameL [] = {NULL, NULL};
79 QPixmap* frameR [] = {NULL, NULL};
80 QPixmap* frameBL[] = {NULL, NULL};
81 QPixmap* frameB [] = {NULL, NULL};
82 QPixmap* frameBR[] = {NULL, NULL};
84 // Button pixmaps
85 QPixmap* closePix[] = {NULL, NULL};
86 QPixmap* depthPix[] = {NULL, NULL};
87 QPixmap* maximizePix[] = {NULL, NULL};
88 QPixmap* minimizePix[] = {NULL, NULL};
89 QPixmap* restorePix[] = {NULL, NULL};
90 QPixmap* hidePix[] = {NULL, NULL};
91 QPixmap* rollupPix[] = {NULL, NULL};
92 QPixmap* rolldownPix[] = {NULL, NULL};
93 QPixmap* menuButtonPix[] = {NULL, NULL};
95 // Titlebar pixmaps
96 QPixmap* titleJ[] = {NULL, NULL};
97 QPixmap* titleL[] = {NULL, NULL};
98 QPixmap* titleS[] = {NULL, NULL};
99 QPixmap* titleP[] = {NULL, NULL};
100 QPixmap* titleT[] = {NULL, NULL};
101 QPixmap* titleM[] = {NULL, NULL};
102 QPixmap* titleB[] = {NULL, NULL};
103 QPixmap* titleR[] = {NULL, NULL};
104 QPixmap* titleQ[] = {NULL, NULL};
106 ThemeHandler* clientHandler;
108 QString* titleButtonsLeft;
109 QString* titleButtonsRight;
111 QColor* colorActiveBorder;
112 QColor* colorInActiveBorder;
113 QColor* colorActiveButton;
114 QColor* colorInActiveButton;
115 QColor* colorActiveTitleBarText;
116 QColor* colorInActiveTitleBarText;
117 QColor* colorActiveTitleBar;
118 QColor* colorInActiveTitleBar;
119 QColor* colorActiveTitleTextShadow;
120 QColor* colorInActiveTitleTextShadow;
122 int cornerSizeX;
123 int cornerSizeY;
124 int titleBarHeight;
125 int borderSizeX;
126 int borderSizeY;
128 bool validframe = false;
129 bool useActiveShadow = false;
130 bool useInActiveShadow = false;
132 // KControl Settings - Read from kwinicewmrc config file or icewm theme
133 bool themeTitleTextColors = true; // Allow theme to set colors.
134 // kcontrol will have no effect
136 bool titleBarOnTop = true; // Titlebars can be below windows too :)
137 bool showMenuButtonIcon = false; // Draw a mini icon over the menu pixmap.
138 bool customButtonPositions = false; // Let the theme dictate the btn pos.
139 bool titleBarCentered = true;
141 enum styles {OTHER, WARP3, WARP4, MOTIF, WIN95, NICE} themeLook;
143 ////////////////////////////////////////////////////////////////////////////////////////////
144 // General utility functions
145 ////////////////////////////////////////////////////////////////////////////////////////////
147 // Returns true if both active and inactive pixmaps are valid, and not null
148 bool validPixmaps( QPixmap* p[] )
150 return ( p[Active] && ( !p[Active]->isNull() ) &&
151 p[InActive] && ( !p[InActive]->isNull() ) );
155 ////////////////////////////////////////////////////////////////////////////////////////////
156 // ThemeHandler class
158 // This class allows us to free dynamic memory upon being reset, or unloaded
159 // from kwin, so we don't leak big images everywhere, and handles the theme
160 // initialisation / destruction in general.
161 ////////////////////////////////////////////////////////////////////////////////////////////
163 ThemeHandler::ThemeHandler()
165 initialized = false;
167 // Prevent having globals objects (use pointers to objects)
168 titleButtonsLeft = new QString();
169 titleButtonsRight = new QString();
171 colorActiveBorder = new QColor();
172 colorInActiveBorder = new QColor();
173 colorActiveButton = new QColor();
174 colorInActiveButton = new QColor();
175 colorActiveTitleBarText = new QColor();
176 colorInActiveTitleBarText = new QColor();
177 colorActiveTitleBar = new QColor();
178 colorInActiveTitleBar = new QColor();
179 colorActiveTitleTextShadow = new QColor();
180 colorInActiveTitleTextShadow = new QColor();
182 // Initialize
183 readConfig();
184 initTheme();
185 validframe = isFrameValid();
186 initialized = true;
190 ThemeHandler::~ThemeHandler()
192 if (initialized)
193 freePixmaps();
195 delete colorInActiveTitleTextShadow;
196 delete colorActiveTitleTextShadow;
197 delete colorInActiveBorder;
198 delete colorActiveTitleBarText;
199 delete colorInActiveTitleBarText;
200 delete colorActiveTitleBar;
201 delete colorInActiveTitleBar;
202 delete colorActiveBorder;
203 delete colorActiveButton;
204 delete colorInActiveButton;
206 delete titleButtonsRight;
207 delete titleButtonsLeft;
211 KDecoration* ThemeHandler::createDecoration( KDecorationBridge* bridge )
213 return new IceWMClient( bridge, this );
217 // Converts KDE style button strings to icewm style button strings
218 void ThemeHandler::convertButtons( QString& s )
220 s.replace( QRegExp("_"), ""); // Spacer (ignored)
221 s.replace( QRegExp("H"), ""); // Help (ignored)
222 s.replace( QRegExp("M"), "s"); // Sysmenu
223 s.replace( QRegExp("S"), "d"); // Sticky/OnAllDesktops
224 s.replace( QRegExp("I"), "i"); // Minimize
225 s.replace( QRegExp("A"), "m"); // Maximize
226 s.replace( QRegExp("X"), "x"); // Close
230 // Reverses all characters in a QString
231 QString ThemeHandler::reverseString( QString s )
233 if (s.length() <= 1)
234 return s;
236 QString tmpStr;
237 for(int i = s.length()-1; i >= 0; i--)
239 tmpStr += s[(unsigned int)i];
242 return tmpStr;
246 // This function reads the kwinicewmrc config file
247 void ThemeHandler::readConfig()
249 KConfig conf("kwinicewmrc");
250 conf.setGroup("General");
251 themeName = conf.readEntry("CurrentTheme");
252 themeTitleTextColors = conf.readBoolEntry("ThemeTitleTextColors", true);
253 showMenuButtonIcon = conf.readBoolEntry("ShowMenuButtonIcon", false);
254 titleBarOnTop = conf.readBoolEntry("TitleBarOnTop", true);
256 customButtonPositions = KDecoration::options()->customButtonPositions();
257 if (customButtonPositions)
259 *titleButtonsLeft = KDecoration::options()->titleButtonsLeft();
260 *titleButtonsRight = KDecoration::options()->titleButtonsRight();
262 // Convert KDE to icewm style buttons
263 convertButtons( *titleButtonsLeft );
264 convertButtons( *titleButtonsRight );
267 // Provide a default theme alias
268 if (themeName == "default")
269 themeName = "";
273 // This creates the dynamic pixmaps upon loading the style
274 // into the pixmap buffers above, and configures the dimensioning stuff.
275 void ThemeHandler::initTheme()
277 // Add a slash if required
278 if ( !themeName.isEmpty() )
279 themeName += "/";
281 // We use kconfig to read icewm config files...
282 // this is easy since icewm uses key=value pairs!
283 KConfig config( locate("data", QString("kwin/icewm-themes/") +
284 themeName + QString("default.theme")) );
286 // Load specifics, or use IceWM defaults instead.
287 borderSizeX = config.readNumEntry("BorderSizeX", 6);
288 borderSizeY = config.readNumEntry("BorderSizeY", 6);
289 cornerSizeX = config.readNumEntry("CornerSizeX", 24);
290 cornerSizeY = config.readNumEntry("CornerSizeY", 24);
291 titleBarCentered = (bool) config.readNumEntry("TitleBarCentered", 0);
293 // Check if readConfig() hasn't overridden this value...
294 if (!showMenuButtonIcon)
295 showMenuButtonIcon = (bool) config.readNumEntry("ShowMenuButtonIcon", 0);
296 titleBarHeight = config.readNumEntry("TitleBarHeight", 20);
298 if (!customButtonPositions)
300 // Read in the button configuration, stripping any quotes
301 // Ignore on all desktops 'd' on the left buttons
302 // (some themes look bad with it on by default)
303 *titleButtonsLeft = config.readEntry("TitleButtonsLeft", "s");
304 *titleButtonsLeft = titleButtonsLeft->replace( QRegExp(QString("\"")), "");
305 *titleButtonsRight = config.readEntry("TitleButtonsRight", "xmir");
306 *titleButtonsRight = titleButtonsRight->replace( QRegExp(QString("\"")), "");
308 // I have no idea why the right side buttons in icewm are reversed
309 *titleButtonsRight = reverseString( *titleButtonsRight );
312 // Read the default border and text colours from the config file
313 // And use IceWM defaults if not found
314 QString s;
316 s = config.readEntry("Look", "other");
317 if (s=="motif") themeLook = MOTIF;
318 else if (s=="warp3") themeLook = WARP3;
319 else if (s=="warp4") themeLook = WARP4;
320 else if (s=="win95") themeLook = WIN95;
321 else if (s=="nice") themeLook = NICE;
322 else themeLook = OTHER;
324 s = config.readEntry("ColorActiveBorder", "#C0C0C0");
325 *colorActiveBorder = decodeColor( s );
326 s = config.readEntry("ColorNormalBorder", "#C0C0C0");
327 *colorInActiveBorder = decodeColor( s );
328 s = config.readEntry("ColorActiveButton", "#C0C0C0");
329 *colorActiveButton = decodeColor( s );
330 s = config.readEntry("ColorNormalButton", "#C0C0C0");
331 *colorInActiveButton = decodeColor( s );
333 // Use these as a last resort
334 s = config.readEntry("ColorActiveTitleBar", "#0000A0");
335 *colorActiveTitleBar = decodeColor( s );
336 s = config.readEntry("ColorNormalTitleBar", "#808080");
337 *colorInActiveTitleBar = decodeColor( s );
339 // Read titlebar text colours
340 s = config.readEntry("ColorActiveTitleBarText", "#FFFFFF");
341 *colorActiveTitleBarText = decodeColor( s );
342 s = config.readEntry("ColorNormalTitleBarText", "#000000");
343 *colorInActiveTitleBarText = decodeColor( s );
345 // Use title text shadows only with theme title text colors
346 if ( themeTitleTextColors )
348 s = config.readEntry("ColorActiveTitleBarShadow");
349 if (!s.isEmpty())
351 *colorActiveTitleTextShadow = decodeColor( s );
352 useActiveShadow = true;
353 } else
354 useActiveShadow = false;
356 s = config.readEntry("ColorNormalTitleBarShadow");
357 if (!s.isEmpty())
359 *colorInActiveTitleTextShadow = decodeColor( s );
360 useInActiveShadow = true;
361 } else
362 useInActiveShadow = false;
363 } else
365 useActiveShadow = false;
366 useInActiveShadow = false;
369 // Stretch pixmaps for speed, where required
370 setPixmap( titleJ, "title", "J.xpm" );
371 setPixmap( titleL, "title", "L.xpm" );
372 setPixmap( titleS, "title", "S.xpm", true );
374 setPixmap( titleP, "title", "P.xpm" );
375 setPixmap( titleT, "title", "T.xpm", true );
376 setPixmap( titleM, "title", "M.xpm" );
377 setPixmap( titleB, "title", "B.xpm", true );
378 setPixmap( titleR, "title", "R.xpm" );
379 setPixmap( titleQ, "title", "Q.xpm" );
381 setPixmapButton( closePix, "close", ".xpm" );
382 setPixmapButton( depthPix, "depth", ".xpm" );
383 setPixmapButton( maximizePix, "maximize", ".xpm" );
384 setPixmapButton( minimizePix, "minimize", ".xpm" );
385 setPixmapButton( restorePix, "restore", ".xpm" );
386 setPixmapButton( hidePix, "hide", ".xpm" );
387 setPixmapButton( rollupPix, "rollup", ".xpm" );
388 setPixmapButton( rolldownPix, "rolldown", ".xpm" );
389 setPixmapButton( menuButtonPix,"menuButton",".xpm" );
391 // Top
392 setPixmap( frameTL, "frame", "TL.xpm" );
393 setPixmap( frameT, "frame", "T.xpm", true );
394 setPixmap( frameTR, "frame", "TR.xpm" );
396 // Sides
397 setPixmap( frameL, "frame", "L.xpm", true, Vertical );
398 setPixmap( frameR, "frame", "R.xpm", true, Vertical );
400 // Bottom
401 setPixmap( frameBL, "frame", "BL.xpm" );
402 setPixmap( frameB, "frame", "B.xpm", true );
403 setPixmap( frameBR, "frame", "BR.xpm" );
405 // Make sure border sizes are at least reasonable...
406 if (borderSizeX < 0)
407 borderSizeX = 0;
408 if (borderSizeY < 0)
409 borderSizeY = 0;
410 // ...and titleBarHeight as well
411 if (titleBarHeight < 0)
412 titleBarHeight = 0;
414 // This is a work-around for some themes
415 if (!titleT[Active])
416 titleT[Active] = duplicateValidPixmap( Active );
418 if (!titleB[Active])
419 titleB[Active] = duplicateValidPixmap( Active );
422 if (titleL[Active] && !titleL[InActive])
423 titleL[InActive] = duplicateValidPixmap( InActive, titleL[Active]->width() );
425 if (titleS[Active] && !titleS[InActive])
426 titleS[InActive] = duplicateValidPixmap( InActive, titleS[Active]->width() );
428 if (titleP[Active] && !titleP[InActive])
429 titleP[InActive] = duplicateValidPixmap( InActive, titleP[Active]->width() );
431 if (titleT[Active] && !titleT[InActive])
432 titleT[InActive] = duplicateValidPixmap( InActive, titleT[Active]->width() );
434 if (titleM[Active] && !titleM[InActive])
435 titleM[InActive] = duplicateValidPixmap( InActive, titleM[Active]->width() );
437 if (titleB[Active] && !titleB[InActive])
438 titleB[InActive] = duplicateValidPixmap( InActive, titleB[Active]->width() );
440 if (titleR[Active] && !titleR[InActive])
441 titleR[InActive] = duplicateValidPixmap( InActive, titleR[Active]->width() );
445 QPixmap* ThemeHandler::duplicateValidPixmap( bool act, int size )
447 QPixmap* p1 = NULL;
448 // Use the stretch or title pixmaps instead
449 if ( titleS[act] )
450 p1 = new QPixmap( *titleS[act] );
451 else if ( titleB[act] )
452 p1 = new QPixmap( *titleB[act] );
453 else if ( titleT[act] )
454 p1 = new QPixmap( *titleT[act] );
456 // Stretch if required
457 if ( (size != -1) && p1 && (!p1->isNull()) )
458 p1 = stretchPixmap( p1, true, size );
460 return p1;
464 // Frees all memory used by pixmaps.
465 void ThemeHandler::freePixmaps()
467 freePixmapGroup( frameTL );
468 freePixmapGroup( frameT );
469 freePixmapGroup( frameTR );
470 freePixmapGroup( frameL );
471 freePixmapGroup( frameR );
472 freePixmapGroup( frameBL );
473 freePixmapGroup( frameB );
474 freePixmapGroup( frameBR );
476 freePixmapGroup( closePix );
477 freePixmapGroup( depthPix );
478 freePixmapGroup( maximizePix );
479 freePixmapGroup( minimizePix );
480 freePixmapGroup( restorePix );
481 freePixmapGroup( hidePix );
482 freePixmapGroup( rollupPix );
483 freePixmapGroup( rolldownPix );
484 freePixmapGroup( menuButtonPix );
486 freePixmapGroup( titleJ );
487 freePixmapGroup( titleL );
488 freePixmapGroup( titleS );
489 freePixmapGroup( titleP );
490 freePixmapGroup( titleT );
491 freePixmapGroup( titleM );
492 freePixmapGroup( titleB );
493 freePixmapGroup( titleR );
494 freePixmapGroup( titleQ );
498 // Frees a dynamic pixmap group from the heap.
499 void ThemeHandler::freePixmapGroup( QPixmap* p[] )
501 if (p)
503 if (p[Active]) delete p[Active];
504 if (p[InActive]) delete p[InActive];
505 p[Active] = NULL;
506 p[InActive] = NULL;
507 } else
508 qWarning("kwin-icewm: freePixmapGroup - invalid QPixmap** 'p'\n");
512 // Converts icewm colors #C0C0C0 or rgb:C0/C0/C0 to QColors
513 QColor ThemeHandler::decodeColor( QString& s )
515 // Make rgb:C0/C0/C0, or #C0/C0/C0 -> C0C0C0
516 s.replace( QRegExp("r"), "");
517 s.replace( QRegExp("g"), "");
518 s.replace( QRegExp("b"), "");
519 s.replace( QRegExp("#"), "");
520 s.replace( QRegExp("/"), "");
521 s.replace( QRegExp(":"), "");
522 s.replace( QRegExp("\\"), "");
523 s.replace( QRegExp("\""), "");
525 // Wierd error - return grey
526 if (s.length() != 6)
527 return QColor( 0xC0, 0xC0, 0xC0 );
529 // Qt makes this conversion very easy
530 return QColor( QString("#") + s );
534 // Stretches tiny pixmaps vertically or horizontally, taking into account
535 // repetition in patterns, so as not to make them mismatched
536 QPixmap* ThemeHandler::stretchPixmap( QPixmap* src, bool stretchHoriz, int stretchSize )
538 if (!src) return NULL;
539 if (src->isNull()) return NULL;
541 int s_inc, size;
543 // If its the right size already, just return
544 if (stretchSize == -1)
546 if (stretchHoriz)
547 s_inc = src->width();
548 else
549 s_inc = src->height();
551 size = s_inc;
552 if (size >= 100)
553 return src;
555 // Stretch an appropriate amount - taking care of pattern repetition
556 while( size < 100 )
557 size += s_inc;
558 } else
559 size = stretchSize;
561 QPixmap* p = new QPixmap();
562 if ( stretchHoriz )
563 p->resize( size, src->height() );
564 else
565 p->resize( src->width(), size );
567 QPainter pnt( p );
568 if ( stretchHoriz )
569 pnt.drawTiledPixmap( 0, 0, size, src->height(), *src);
570 else
571 pnt.drawTiledPixmap( 0, 0, src->width(), size, *src);
572 pnt.end();
574 delete src;
575 return p;
578 static void draw3DRect(QPainter &pnt, QColor &col, int x, int y, int w, int h, bool up) {
579 QColor light = col.light(135);
580 QColor dark = col.dark(140);
581 pnt.setPen(up ? light : dark);
582 pnt.drawLine(x, y, x+w, y);
583 pnt.drawLine(x, y, x, y+h);
584 pnt.setPen(up ? dark : light);
585 pnt.drawLine(x, y+h, x+w, y+h);
586 pnt.drawLine(x+w, y, x+w, y+h);
587 pnt.setPen(col);
588 pnt.drawPoint(x+w, y);
589 pnt.drawPoint(x, y+h);
592 void ThemeHandler::setPixmapButton( QPixmap* p[], QString s1, QString s2)
594 if ( p[Active] )
595 qWarning("kwin-icewm: setPixmap - should be null (1)\n");
596 if ( p[InActive] )
597 qWarning("kwin-icewm: setPixmap - should be null (2)\n");
599 QString str = locate("appdata", QString("icewm-themes/")
600 + themeName + s1 + "A" + s2);
601 if (str.isEmpty())
602 str = locate("appdata", QString("icewm-themes/")
603 + themeName + s1 + s2);
605 QPixmap *qp = new QPixmap(str);
606 QColor cActive = themeLook == WIN95 ? *colorActiveTitleBar : *colorActiveButton;
607 QColor cInActive = themeLook == WIN95 ? *colorInActiveTitleBar : *colorInActiveButton;
609 if (!qp->isNull() && themeLook > 0) {
610 int w = qp->width();
611 if (themeLook > 0 && titleBarHeight > w) w = titleBarHeight;
612 p[Active] = new QPixmap(w, 2*titleBarHeight );
613 p[Active] -> fill(cActive);
615 QPainter pnt( p[Active] );
617 int offX = (w - qp->width())/2;
618 int offY = (titleBarHeight - qp->height())/2;
619 if (offY < 0) offY = 0;
621 if (themeLook == WIN95) {
622 draw3DRect(pnt, *colorActiveButton, offX-1, offY-1,
623 qp->width()+1, qp->height()+1, true);
624 draw3DRect(pnt, *colorActiveButton, offX-1, offY-1 + titleBarHeight,
625 qp->width()+1, qp->height()+1, false);
626 } else if (themeLook != WARP4) {
627 draw3DRect(pnt, *colorActiveButton, 0, 0,
628 w-1, titleBarHeight-1, true);
629 draw3DRect(pnt, *colorActiveButton, 0, titleBarHeight,
630 w-1, 2*titleBarHeight-1, false);
633 pnt.drawPixmap(offX, offY, *qp);
634 if (qp->height() <= titleBarHeight) {
635 pnt.drawPixmap(offX, titleBarHeight+offY, *qp);
637 pnt.end();
638 delete qp;
639 } else {
640 p[Active] = qp;
643 str = locate("appdata", QString("icewm-themes/")
644 + themeName + s1 + "I" + s2);
645 if (str.isEmpty())
646 str = locate("appdata", QString("icewm-themes/")
647 + themeName + s1 + s2);
649 qp = new QPixmap(str);
650 if (!qp->isNull() && themeLook > 0) {
651 int w = qp->width();
652 if (titleBarHeight > w) w = titleBarHeight;
653 p[InActive] = new QPixmap(w, 2*titleBarHeight );
654 p[InActive] -> fill(cInActive);
656 QPainter pnt( p[InActive] );
658 int offX = (w - qp->width())/2;
659 int offY = (titleBarHeight - qp->height())/2;
660 if (offY < 0) offY = 0;
662 if (themeLook == WIN95) {
663 draw3DRect(pnt, *colorInActiveButton, offX-1, offY-1,
664 qp->width()+1, qp->height()+1, true);
665 draw3DRect(pnt, *colorInActiveButton, offX-1, offY-1 + titleBarHeight,
666 qp->width()+1, qp->height()+1, false);
667 } else if (themeLook != WARP4) {
668 draw3DRect(pnt, *colorInActiveButton, 0, 0,
669 w-1, titleBarHeight-1, true);
670 draw3DRect(pnt, *colorActiveButton, 0, titleBarHeight,
671 w-1, 2*titleBarHeight-1, false);
673 pnt.drawPixmap(offX, offY, *qp);
674 if (qp->height() <= titleBarHeight) {
675 pnt.drawPixmap(offX, titleBarHeight+offY, *qp);
677 pnt.end();
678 delete qp;
679 } else {
680 p[InActive] = qp;
687 // Loads the specified Active/InActive files into the specific pixmaps, and
688 // can perform horizontal / vertical stretching if required for speed.
689 // Tries to implement some icewm specific pixmap handling for some dodgy themes
690 void ThemeHandler::setPixmap( QPixmap* p[], QString s1, QString s2,
691 bool stretch, bool stretchHoriz )
693 if ( p[Active] )
694 qWarning("kwin-icewm: setPixmap - should be null (1)\n");
695 if ( p[InActive] )
696 qWarning("kwin-icewm: setPixmap - should be null (2)\n");
698 p[Active] = new QPixmap( locate("data", QString("kwin/icewm-themes/")
699 + themeName + s1 + "A" + s2) );
700 p[InActive] = new QPixmap( locate("data", QString("kwin/icewm-themes/")
701 + themeName + s1 + "I" + s2) );
703 // Stretch the pixmap if requested.
704 if ( stretch )
706 if (p[Active])
707 p[Active] = stretchPixmap( p[Active], stretchHoriz );
708 if (p[InActive])
709 p[InActive] = stretchPixmap( p[InActive], stretchHoriz );
712 if ( p[Active] && p[InActive] )
714 // Make sure active and inactive pixmaps are the same width for proper painting
715 if (p[Active]->width() > p[InActive]->width())
716 p[InActive] = stretchPixmap( p[InActive], true, p[Active]->width() );
722 // returns true if there were enough pixmaps loaded to
723 // draw the pixmap frame properly.
724 bool ThemeHandler::isFrameValid()
726 return
727 ( validPixmaps( frameTL ) &&
728 validPixmaps( frameT ) &&
729 validPixmaps( frameTR ) &&
730 validPixmaps( frameL ) &&
731 validPixmaps( frameR ) &&
732 validPixmaps( frameBL ) &&
733 validPixmaps( frameB ) &&
734 validPixmaps( frameBR ) );
738 // Resets the theme, and re-clients all kwin's wrapped windows.
739 bool ThemeHandler::reset( unsigned long)
741 initialized = false;
742 freePixmaps();
743 readConfig();
744 initTheme();
745 validframe = isFrameValid();
746 initialized = true;
748 // recreate all clients
749 return true;
752 bool ThemeHandler::supports( Ability ability )
754 switch( ability )
756 case AbilityAnnounceButtons:
757 case AbilityButtonMenu:
758 case AbilityButtonOnAllDesktops:
759 case AbilityButtonMinimize:
760 case AbilityButtonMaximize:
761 case AbilityButtonClose:
762 return true;
763 default:
764 return false;
769 ////////////////////////////////////////////////////////////////////////////////////////////
770 // IceWM button class
771 ////////////////////////////////////////////////////////////////////////////////////////////
773 IceWMButton::IceWMButton(IceWMClient *parent, const char *name, QPixmap* (*p)[2],
774 bool isToggle, const QString& tip, const int realizeBtns )
775 : Q3Button(parent->widget(), name)
777 m_realizeButtons = realizeBtns;
778 setTipText(tip);
779 setCursor(ArrowCursor);
780 // Eliminate any possible background flicker
781 setBackgroundMode( QWidget::NoBackground );
782 client = parent;
783 usePixmap( p );
784 setFixedSize( sizeHint() );
785 setToggleButton( isToggle );
789 void IceWMButton::setTipText(const QString &tip) {
790 if(KDecoration::options()->showTooltips()) {
791 QToolTip::remove(this );
792 this->setToolTip( tip );
797 QSize IceWMButton::sizeHint() const
799 // Check for invalid data
800 if ( validPixmaps( (QPixmap**) (*pix) ) ) // Cast to avoid dumb warning
802 QPixmap* p = (*pix)[ client->isActive() ? Active : InActive ];
803 return( QSize(p->width(), titleBarHeight) );
804 } else
805 return( QSize(0, 0) );
809 void IceWMButton::usePixmap( QPixmap* (*p)[2] )
811 if (validPixmaps( *p )) {
812 pix = p;
813 setFixedSize( (*pix)[Active]->width(), titleBarHeight );
814 repaint( false );
815 } else
816 pix = NULL;
820 void IceWMButton::drawButton(QPainter *pnt)
822 if ( pix && validPixmaps(*pix) )
824 QPixmap* p = (*pix)[ client->isActive() ? Active : InActive ];
826 if( p && (!p->isNull()) )
828 int width = p->width();
830 // Only draw the lower pixmap 1/2 for down, and upper 1/2 for up state
831 if( isDown() || isOn() )
832 pnt->drawPixmap(0, 0, *p, 0, titleBarHeight, width, titleBarHeight);
833 else
834 pnt->drawPixmap(0, 0, *p, 0, 0, width, titleBarHeight);
836 } else
837 qWarning("kwin-icewm: Can't paint a null pixmap button");
841 void IceWMButton::turnOn( bool isOn )
843 if ( isToggleButton() )
844 setOn( isOn );
848 void IceWMButton::mousePressEvent( QMouseEvent* e )
850 last_button = e->button();
851 QMouseEvent me ( e->type(), e->pos(), e->globalPos(),
852 (e->button()&m_realizeButtons)?Qt::LeftButton:Qt::NoButton, e->state() );
853 Q3Button::mousePressEvent( &me );
857 void IceWMButton::mouseReleaseEvent( QMouseEvent* e )
859 last_button = e->button();
860 QMouseEvent me ( e->type(), e->pos(), e->globalPos(),
861 (e->button()&m_realizeButtons)?Qt::LeftButton:Qt::NoButton, e->state() );
862 Q3Button::mouseReleaseEvent( &me );
867 ////////////////////////////////////////////////////////////////////////////////////////////
868 // IceWMClient class
869 ////////////////////////////////////////////////////////////////////////////////////////////
871 IceWMClient::IceWMClient( KDecorationBridge* bridge, KDecorationFactory* factory )
872 : KDecoration (bridge, factory),
873 m_closing(false)
878 IceWMClient::~IceWMClient()
880 // Free the menu pixmaps if previously allocated
881 if ( menuButtonWithIconPix[Active] )
882 delete menuButtonWithIconPix[Active];
883 if ( menuButtonWithIconPix[InActive] )
884 delete menuButtonWithIconPix[InActive];
888 void IceWMClient::init()
890 createMainWidget( WNoAutoErase | WStaticContents );
891 widget()->installEventFilter( this );
893 // Set button pointers to null so we can track things
894 for(int i= IceWMClient::BtnSysMenu; i < IceWMClient::BtnCount; i++)
895 button[i] = NULL;
897 // Make sure we can track the menu pixmaps too.
898 menuButtonWithIconPix[Active] = NULL;
899 menuButtonWithIconPix[InActive] = NULL;
901 // No flicker thanks
902 widget()->setBackgroundMode( NoBackground );
904 // Pack the windowWrapper() window within a grid layout
905 grid = new QGridLayout(widget(), 0, 0, 0);
906 grid->setResizeMode(QLayout::FreeResize);
907 grid->addRowSpacing(0, borderSizeY); // Top grab bar
909 // Do something IceWM can't do :)
910 if (titleBarOnTop) {
911 if( isPreview())
912 grid->addWidget( new QLabel( i18n( "<center><b>IceWM preview</b></center>" ), widget() ), 2, 1);
913 else
914 grid->addItem( new QSpacerItem( 0, 0 ), 2, 1);
915 // no shade flicker
916 grid->addItem( new QSpacerItem( 0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding ) );
918 else {
919 // no shade flicker
920 grid->addItem( new QSpacerItem( 0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding ) );
921 if( isPreview())
922 grid->addWidget( new QLabel( i18n( "<center><b>IceWM preview</b></center>" ), widget() ), 1, 1);
923 else
924 grid->addItem( new QSpacerItem( 0, 0 ), 1, 1);
927 grid->setRowStretch(1, 10);
928 grid->setRowStretch(2, 10);
929 grid->setColStretch(1, 10);
930 grid->addRowSpacing(3, borderSizeY);
931 grid->addColSpacing(0, borderSizeX);
932 grid->addColSpacing(2, borderSizeX);
934 // Pack the titlebar with spacers and buttons
935 hb = new QBoxLayout(0, QBoxLayout::LeftToRight, 0, 0, 0);
936 hb->setResizeMode( QLayout::FreeResize );
938 titleSpacerJ = addPixmapSpacer( titleJ );
940 addClientButtons( *titleButtonsLeft );
941 titleSpacerL = addPixmapSpacer( titleL );
943 // Centre titlebar if required.
944 QSizePolicy::SizeType spTitleBar;
945 spTitleBar = titleBarCentered ? QSizePolicy::Expanding : QSizePolicy::Maximum;
946 titleSpacerS = addPixmapSpacer( titleS, spTitleBar, 1 );
947 titleSpacerP = addPixmapSpacer( titleP );
949 titlebar = new QSpacerItem( titleTextWidth(caption()), titleBarHeight,
950 QSizePolicy::Preferred, QSizePolicy::Fixed );
951 hb->addItem(titlebar);
953 titleSpacerM = addPixmapSpacer( titleM );
954 titleSpacerB = addPixmapSpacer( titleB, QSizePolicy::Expanding, 1 );
955 titleSpacerR = addPixmapSpacer( titleR );
957 addClientButtons( *titleButtonsRight );
959 titleSpacerQ = addPixmapSpacer( titleQ );
961 if (titleBarOnTop)
962 grid->addLayout ( hb, 1, 1 );
963 else
964 grid->addLayout ( hb, 2, 1 );
968 // Adds the buttons to the hbox layout as per the buttons specified
969 // in the button string 's'
970 void IceWMClient::addClientButtons( const QString& s )
972 if (!s.isEmpty())
973 for(unsigned int i = 0; i < s.length(); i++)
975 switch ( s[i].latin1() )
977 case 's':
978 // Create the menu icons, and render with the current mini-icon
979 // if explicitly requested by the theme.
980 if ( (validPixmaps(menuButtonPix) || showMenuButtonIcon) && !button[BtnSysMenu])
982 if (showMenuButtonIcon) {
983 renderMenuIcons();
984 button[BtnSysMenu] = new IceWMButton(this, "menu",
985 &menuButtonWithIconPix, false, i18n("Menu"), LeftButton|RightButton);
987 else
988 button[BtnSysMenu] = new IceWMButton(this, "menu",
989 &menuButtonPix, false, i18n("Menu"));
991 connect( button[BtnSysMenu], SIGNAL(pressed()),
992 this, SLOT(menuButtonPressed()));
993 connect( button[BtnSysMenu], SIGNAL(released()),
994 this, SLOT(menuButtonReleased()));
995 hb->addWidget( button[BtnSysMenu] );
997 break;
999 case 'x':
1000 if ( validPixmaps(closePix) && !button[BtnClose] && isCloseable())
1002 button[BtnClose] = new IceWMButton(this, "close",
1003 &closePix, false, i18n("Close"));
1004 hb->addWidget( button[BtnClose] );
1005 connect( button[BtnClose], SIGNAL(clicked()),
1006 this, SLOT(closeWindow()));
1008 break;
1010 case 'm':
1011 if ( validPixmaps(maximizePix) && !button[BtnMaximize] && isMaximizable() )
1013 button[BtnMaximize] = new IceWMButton(this, "maximize",
1014 &maximizePix, false, i18n("Maximize"), LeftButton|MidButton|RightButton);
1015 hb->addWidget( button[BtnMaximize] );
1016 connect( button[BtnMaximize], SIGNAL(clicked()),
1017 this, SLOT(slotMaximize()));
1019 break;
1021 case 'i':
1022 if ( validPixmaps(minimizePix) && !button[BtnMinimize] &&
1023 isMinimizable() )
1025 button[BtnMinimize] = new IceWMButton(this, "minimize",
1026 &minimizePix, false, i18n("Minimize"));
1027 hb->addWidget( button[BtnMinimize] );
1028 connect( button[BtnMinimize], SIGNAL(clicked()),
1029 this, SLOT(minimize()));
1031 break;
1033 /* Not yet implemented - how's hide useful anyway?
1034 case 'h':
1035 if ( button[BtnHide] && !button[BtnHide] )
1036 hb->addWidget( button[BtnHide] );
1037 break; */
1039 case 'r':
1040 // NOTE: kwin doesn't have toggleShade() in clients.h !
1041 if ( validPixmaps(rollupPix) && !button[BtnRollup] )
1043 button[BtnRollup] = new IceWMButton(this, "shade",
1044 isSetShade() ? &rolldownPix : &rollupPix,
1045 false, i18n("Rollup"));
1046 hb->addWidget( button[BtnRollup] );
1047 connect( button[BtnRollup], SIGNAL(clicked()),
1048 this, SLOT(toggleShade()));
1050 break;
1052 case 'd':
1053 // Make depth == on all desktops
1054 if ( validPixmaps(depthPix) && !button[BtnDepth] )
1056 button[BtnDepth] = new IceWMButton(this, "on_all_desktops",
1057 &depthPix, true, isOnAllDesktops()?i18n("Not on all desktops"):i18n("On all desktops"));
1058 button[BtnDepth]->turnOn( isOnAllDesktops() );
1059 hb->addWidget( button[BtnDepth] );
1060 connect( button[BtnDepth], SIGNAL(clicked()),
1061 this, SLOT(toggleOnAllDesktops()));
1063 break;
1069 // Adds a pixmap to the titlebar layout via the use of a nice QSpacerItem
1070 QSpacerItem* IceWMClient::addPixmapSpacer( QPixmap* p[], QSizePolicy::SizeType s, int hsize )
1072 QSpacerItem* sp;
1074 // Add a null spacer for zero image
1075 if ( p && p[Active] )
1077 int w = (hsize == -1) ? p[Active]->width(): hsize;
1078 sp = new QSpacerItem( w, titleBarHeight, s, QSizePolicy::Fixed );
1080 else
1081 sp = new QSpacerItem(0, 0, QSizePolicy::Maximum, QSizePolicy::Fixed );
1083 hb->addItem( sp );
1084 return sp;
1088 void IceWMClient::renderMenuIcons()
1090 QPixmap miniIcon( icon().pixmap( QIcon::Small, QIcon::Normal) );
1092 if (!miniIcon.isNull())
1093 for(int i = 0; i < 2; i++) {
1094 if ( menuButtonWithIconPix[i] )
1095 delete menuButtonWithIconPix[i];
1097 // Try to be more friendly to dodgy themes - icewm assumes a square menu button
1098 // but some pixmap themes don't provide a square menu button.
1099 int w = titleBarHeight;
1100 if (validPixmaps(menuButtonPix) && menuButtonPix[i]->width() > w)
1101 w = menuButtonPix[i]->width();
1102 menuButtonWithIconPix[i] = new QPixmap(w, 2*titleBarHeight );
1103 if (themeLook != WIN95)
1104 menuButtonWithIconPix[i] -> fill((i==0) ? *colorInActiveButton : *colorActiveButton);
1105 else
1106 menuButtonWithIconPix[i] -> fill((i==0) ? *colorInActiveTitleBar : *colorActiveTitleBar);
1107 QPainter pnt( menuButtonWithIconPix[i] );
1109 if (themeLook > 0 && themeLook != WIN95 && themeLook != WARP4) {
1110 draw3DRect(pnt, *colorActiveButton, 0, 0,
1111 w-1, titleBarHeight-1, true);
1112 draw3DRect(pnt, *colorActiveButton, 0, titleBarHeight,
1113 w-1, 2*titleBarHeight-1, false);
1115 if (validPixmaps(menuButtonPix)) {
1116 pnt.drawPixmap(0, 0, *menuButtonPix[i]);
1118 int offset = (titleBarHeight - miniIcon.width())/2;
1119 if (offset<0) offset = 0;
1120 // Paint the mini icon over the menu pixmap in the centre
1121 pnt.drawPixmap( offset, offset, miniIcon );
1122 pnt.drawPixmap( offset, titleBarHeight+offset, miniIcon );
1123 pnt.end();
1129 void IceWMClient::slotMaximize()
1131 maximize(button[BtnMaximize]->last_button);
1134 void IceWMClient::toggleShade()
1136 setShade(!isSetShade());
1139 int IceWMClient::titleTextWidth( const QString& s )
1141 // Obtains the actual width of the text, using the titlebar font
1142 QSize size;
1143 QFontMetrics fm( options()->font(true) );
1144 size = fm.size( 0, s );
1145 return size.width();
1149 void IceWMClient::borders(int& left, int& right, int& top, int& bottom) const
1151 left = borderSizeX;
1152 right = borderSizeX;
1153 if( titleBarOnTop ) {
1154 top = titleBarHeight + borderSizeY;
1155 bottom = borderSizeY;
1156 } else {
1157 top = borderSizeY;
1158 bottom = titleBarHeight + borderSizeY;
1163 void IceWMClient::resize( const QSize& s )
1165 widget()->resize( s );
1169 QSize IceWMClient::minimumSize() const
1171 return widget()->minimumSize();
1175 // Repaint nicely upon resize to minimise flicker.
1176 void IceWMClient::resizeEvent( QResizeEvent* e )
1178 calcHiddenButtons();
1180 if (widget()->isVisibleToTLW())
1182 widget()->update(widget()->rect());
1183 int dx = 0;
1184 int dy = 0;
1186 if ( e->oldSize().width() != widget()->width() )
1187 dx = 32 + QABS( e->oldSize().width() - width() );
1189 if ( e->oldSize().height() != height() )
1190 dy = 8 + QABS( e->oldSize().height() - height() );
1192 if ( dy )
1193 widget()->update( 0, height() - dy + 1, width(), dy );
1195 if ( dx )
1197 widget()->update( width() - dx + 1, 0, dx, height() );
1198 widget()->update( QRect( QPoint(4,4), titlebar->geometry().bottomLeft() - QPoint(1,0) ) );
1199 widget()->update( QRect( titlebar->geometry().topRight(), QPoint( width() - 4, titlebar->geometry().bottom() ) ) );
1200 widget()->repaint(titlebar->geometry(), false);
1206 // IceWM Paint magic goes here.
1207 void IceWMClient::paintEvent( QPaintEvent* )
1209 QColor colorTitleShadow;
1210 QColor colorTitle;
1211 QColor c1;
1212 int rx, rw;
1214 QPainter p( widget() );
1215 int act = isActive() ? Active: InActive;
1217 // Determine titlebar shadow colors
1218 bool useShadow = isActive() ? useActiveShadow : useInActiveShadow;
1219 if ( useShadow )
1220 colorTitleShadow = isActive() ? *colorActiveTitleTextShadow : *colorInActiveTitleTextShadow;
1222 if ( themeTitleTextColors )
1223 colorTitle = isActive()? *colorActiveTitleBarText : *colorInActiveTitleBarText;
1224 else
1225 colorTitle = options()->color(ColorFont, isActive());
1227 // Obtain widget bounds.
1228 QRect r;
1229 r = widget()->rect();
1230 int fillWidth = r.width() - 2*borderSizeX;
1231 int y = r.y();
1232 int x = r.x();
1233 int w = r.width();
1234 int h = r.height();
1236 // Do we have pixmaps for the frame?
1237 if (validframe)
1239 // Top corner
1240 p.drawPixmap(0, 0, *frameTL[ act ], 0, 0, cornerSizeX, borderSizeY);
1241 p.drawPixmap(0, 0, *frameTL[ act ], 0, 0, borderSizeX, cornerSizeY);
1243 // Top right corner
1244 p.drawPixmap(w-cornerSizeX, 0, *frameTR[ act ],
1245 frameTR[act]->width()-cornerSizeX, 0, cornerSizeX, borderSizeY);
1246 p.drawPixmap(w-borderSizeX, 0, *frameTR[ act ],
1247 frameTR[act]->width()-borderSizeX, 0, borderSizeX, cornerSizeY);
1249 // Top bar
1250 p.drawTiledPixmap( cornerSizeX, 0, w-(2*cornerSizeX), borderSizeY, *frameT[ act ] );
1252 // Left bar
1253 p.drawTiledPixmap( 0, cornerSizeY, borderSizeX, h-(2*cornerSizeY), *frameL[ act ] );
1255 // Right bar
1256 p.drawTiledPixmap( w-borderSizeX, cornerSizeY, borderSizeX, h-(2*cornerSizeY),
1257 *frameR[ act ],frameR[act]->width()-borderSizeX );
1259 // Bottom left corner
1260 p.drawPixmap(0, h-borderSizeY, *frameBL[ act ],
1261 0, frameBL[act]->height()-borderSizeY, cornerSizeX, borderSizeY);
1262 p.drawPixmap(0, h-cornerSizeY, *frameBL[ act ],
1263 0, frameBL[act]->height()-cornerSizeY, borderSizeX, cornerSizeY);
1265 // Bottom right corner
1266 p.drawPixmap(w-cornerSizeX, h-borderSizeY, *frameBR[ act ],
1267 frameBR[act]->width()-cornerSizeX, frameBR[act]->height()-borderSizeY,
1268 cornerSizeX, borderSizeY);
1270 p.drawPixmap(w-borderSizeX, h-cornerSizeY, *frameBR[ act ],
1271 frameBR[act]->width()-borderSizeX, frameBR[act]->height()-cornerSizeY,
1272 borderSizeX, cornerSizeY);
1274 // Bottom bar
1275 p.drawTiledPixmap(cornerSizeX, h-borderSizeY, w-(2*cornerSizeX), borderSizeY,
1276 *frameB[ act ], 0, frameB[ act ]->height()-borderSizeY );
1278 // Ensure uncovered areas during shading are painted with something
1279 p.setPen( *colorInActiveBorder );
1280 if (titleBarOnTop)
1281 p.drawLine( x+borderSizeX, y+h-borderSizeY-1,
1282 x+w-borderSizeX-1, y+h-borderSizeY-1);
1283 else
1284 p.drawLine( x+borderSizeX, y+borderSizeY,
1285 x+w-borderSizeX-1, y+borderSizeY);
1287 } else
1289 // Draw a stock IceWM frame instead of a pixmap frame
1290 c1 = isActive() ? *colorActiveBorder : *colorInActiveBorder;
1292 if (themeLook == WARP3 || themeLook == MOTIF) {
1293 draw3DRect(p, c1, x, y, w-1, h-1, true);
1294 p.setPen(c1);
1295 p.drawRect(x+1, y+1, w-2, h-2);
1296 } else {
1297 p.setPen( c1.light(135) );
1298 p.drawLine(0, 0, w-2, 0);
1299 p.drawLine(0, 0, 0, h-2);
1301 p.setPen(c1);
1302 p.drawLine(1, 1, w-3, 1);
1303 p.drawLine(1, 1, 1, h-3);
1305 p.setPen( c1.dark(140) );
1306 p.drawLine(1, h-2, w-2, h-2);
1307 p.drawLine(w-2, 1, w-2, h-2);
1309 p.setPen( Qt::black );
1310 p.drawLine(w-1, 0, w-1, h-1);
1311 p.drawLine(0, h-1, w-1, h-1);
1315 // Fill frame border if required
1316 if (borderSizeX > 2)
1318 // Fill Vertical sizes
1319 p.fillRect( x+2, y+2, borderSizeX-2, h-4, c1);
1320 p.fillRect( w-borderSizeX, y+2, borderSizeX-2, h-4, c1);
1323 if (borderSizeY > 2)
1325 // Fill horizontal frame parts
1326 p.fillRect( x+borderSizeX, y+2, fillWidth, borderSizeY-2, c1);
1327 p.fillRect( x+borderSizeX, h-borderSizeY, fillWidth, borderSizeY-2, c1);
1330 if (themeLook == WARP3 || themeLook == MOTIF) {
1331 draw3DRect(p, c1, x+borderSizeX-1, y+borderSizeY-1,
1332 w+1-2*borderSizeX, h+1-2*borderSizeY, false);
1334 if (themeLook == MOTIF && !isShade()) {
1335 int xext = titleBarHeight + borderSizeX - 1;
1336 int yext = titleBarHeight + borderSizeY - 1;
1338 int xext2 = w-xext-2;
1339 int yext2 = h-yext-2;
1341 int bX = w - borderSizeX-1;
1342 int bY = h - borderSizeY-1;
1344 p.setPen( c1.dark(140) );
1345 p.drawLine(xext, 0, xext, borderSizeY);
1346 p.drawLine(xext2, 0, xext2, borderSizeY);
1347 p.drawLine(xext, bY, xext, h-1);
1348 p.drawLine(xext2, bY, xext2, h-1);
1350 p.drawLine(0, yext, borderSizeX, yext);
1351 p.drawLine(0, yext2, borderSizeX, yext2);
1352 p.drawLine(bX, yext, w-1, yext);
1353 p.drawLine(bX, yext2, w-1, yext2);
1355 p.setPen( c1.light(135) );
1357 ++xext; ++yext; ++xext2; ++yext2;
1359 p.drawLine(xext, 0, xext, borderSizeY);
1360 p.drawLine(xext2, 0, xext2, borderSizeY);
1361 p.drawLine(xext, bY, xext, h-1);
1362 p.drawLine(xext2, bY, xext2, h-1);
1364 p.drawLine(0, yext, borderSizeX, yext);
1365 p.drawLine(0, yext2, borderSizeX, yext2);
1366 p.drawLine(bX, yext, w-1, yext);
1367 p.drawLine(bX, yext2, w-1, yext2);
1372 // Ensure uncovered areas during shading are painted with something
1373 p.setPen( *colorInActiveBorder );
1374 if (titleBarOnTop)
1375 p.drawLine( x+borderSizeX, y+h-borderSizeY-1,
1376 x+w-borderSizeX-1, y+h-borderSizeY-1);
1377 else
1378 p.drawLine( x+borderSizeX, y+borderSizeY,
1379 x+w-borderSizeX-1, y+borderSizeY);
1382 // Draw the title elements, if we need to draw a titlebar.
1383 if (titleBarHeight > 0)
1385 QPixmap* titleBuffer = new QPixmap( width()-(2*borderSizeX), titleBarHeight );
1386 QPainter p2( titleBuffer, this );
1387 titleBuffer->fill( act ? *colorActiveTitleBar : *colorInActiveTitleBar );
1389 r = titleSpacerJ->geometry();
1390 if (!r.isEmpty() && titleJ[ act ])
1391 p2.drawPixmap( r.x()-borderSizeX, 0, *titleJ[ act ]);
1393 r = titleSpacerL->geometry();
1394 if (!r.isEmpty() && titleL[ act ])
1395 p2.drawPixmap( r.x()-borderSizeX, 0, *titleL[ act ]);
1397 r = titleSpacerS->geometry();
1398 if (!r.isEmpty() && titleS[ act ])
1399 p2.drawTiledPixmap( r.x()-borderSizeX, 0, r.width(), titleBarHeight, *titleS[ act ]);
1401 r = titleSpacerP->geometry();
1402 if (!r.isEmpty() && titleP[ act ])
1403 p2.drawPixmap( r.x()-borderSizeX, 0, *titleP[ act ]);
1405 r = titlebar->geometry();
1406 if (!r.isEmpty() && titleT[ act ] )
1407 p2.drawTiledPixmap( r.x()-borderSizeX, 0, r.width(), titleBarHeight, *titleT[ act ]);
1409 r = titleSpacerM->geometry();
1410 if (!r.isEmpty() && titleM[ act ])
1411 p2.drawPixmap( r.x()-borderSizeX, 0, *titleM[ act ], 0, 0, r.width(), r.height());
1413 r = titleSpacerB->geometry();
1414 if (!r.isEmpty() && titleB[ act ])
1415 p2.drawTiledPixmap( r.x()-borderSizeX, 0, r.width(), titleBarHeight, *titleB[ act ]);
1417 r = titleSpacerR->geometry();
1418 if (!r.isEmpty() && titleR[ act ])
1419 p2.drawPixmap( r.x()-borderSizeX, 0, *titleR[ act ], 0, 0, r.width(), r.height());
1421 r = titleSpacerQ->geometry();
1422 if (!r.isEmpty() && titleQ[ act ])
1423 p2.drawPixmap( r.x()-borderSizeX, 0, *titleQ[ act ], 0, 0, r.width(), r.height());
1425 p2.setFont( options()->font(true) );
1427 // Pre-compute as much as possible
1428 r = titlebar->geometry();
1429 rx = r.x() - borderSizeX;
1430 rw = width()-(2*borderSizeX)-r.x();
1432 // Paint a title text shadow if requested
1433 if ( useShadow )
1435 p2.setPen( colorTitleShadow );
1436 p2.drawText(rx+1, 1, rw, titleBarHeight, AlignLeft|AlignVCenter, caption());
1439 // Draw the title text
1440 p2.setPen( colorTitle );
1441 p2.drawText(rx, 0, rw, titleBarHeight, AlignLeft|AlignVCenter, caption());
1442 p2.end();
1444 bitBlt( widget(), borderSizeX, hb->geometry().y(), titleBuffer );
1446 delete titleBuffer;
1451 void IceWMClient::showEvent(QShowEvent *ev)
1453 calcHiddenButtons();
1455 titlebar->changeSize( titleTextWidth(caption()), titleBarHeight,
1456 QSizePolicy::Preferred, QSizePolicy::Fixed );
1457 grid->activate();
1458 widget()->show();
1459 IceWMClient::showEvent(ev);
1463 void IceWMClient::mouseDoubleClickEvent( QMouseEvent * e )
1465 if( e->button() != LeftButton )
1466 return;
1468 QRect r;
1469 if (titleBarOnTop)
1470 r.setRect( borderSizeX, borderSizeY, width()-(2*borderSizeX), titleBarHeight);
1471 else
1472 r.setRect( borderSizeX, height()-borderSizeY-titleBarHeight,
1473 width()-(2*borderSizeX), titleBarHeight);
1475 if (r.contains( e->pos() ) )
1476 titlebarDblClickOperation();
1481 // Called via Client class when the miniIcon() changes
1482 void IceWMClient::iconChange()
1484 if (validPixmaps(menuButtonPix) && showMenuButtonIcon)
1486 if (button[BtnSysMenu])
1488 renderMenuIcons();
1489 button[BtnSysMenu]->usePixmap( &menuButtonWithIconPix );
1490 if (button[BtnSysMenu]->isVisible())
1491 button[BtnSysMenu]->repaint(false);
1497 void IceWMClient::desktopChange()
1499 if (button[BtnDepth])
1501 button[BtnDepth]->turnOn( isOnAllDesktops() );
1502 button[BtnDepth]->repaint(false);
1503 button[BtnDepth]->setTipText(isOnAllDesktops() ? i18n("Not on all desktops") : i18n("On all desktops"));
1508 // Please don't modify the following unless you want layout problems
1509 void IceWMClient::captionChange()
1511 QRect r( 0, borderSizeY, geometry().width(), titleBarHeight);
1513 titlebar->changeSize( titleTextWidth( caption() ), titleBarHeight,
1514 QSizePolicy::Preferred, QSizePolicy::Fixed );
1515 titlebar->invalidate();
1516 grid->activate();
1517 widget()->repaint( r, false );
1521 void IceWMClient::maximizeChange()
1523 // Change the button pixmap to restore if required
1524 if (button[BtnMaximize] && validPixmaps(restorePix))
1526 button[BtnMaximize]->usePixmap( (maximizeMode()==MaximizeFull) ? &restorePix : &maximizePix );
1527 button[BtnMaximize]->setTipText( (maximizeMode()==MaximizeFull) ? i18n("Restore") : i18n("Maximize"));
1532 void IceWMClient::shadeChange()
1534 // Change the button pixmap to rolldown if required
1535 if (button[BtnRollup] && validPixmaps(rolldownPix))
1537 button[BtnRollup]->usePixmap( isSetShade() ? &rolldownPix : &rollupPix );
1538 button[BtnRollup]->setTipText( isSetShade() ? i18n("Rolldown") : i18n("Rollup"));
1544 void IceWMClient::activeChange()
1546 widget()->repaint(false);
1548 // Reset the button pixmaps.
1549 for(int i= IceWMClient::BtnSysMenu; i < IceWMClient::BtnCount; i++)
1550 if(button[i])
1551 button[i]->repaint( false );
1555 // This does the showing / hiding button magic
1556 // for variable positioned buttons.
1557 void IceWMClient::calcHiddenButtons()
1559 const int minwidth = 220; // Minimum width where all buttons are shown
1560 const int btn_width = 20; // Average width
1562 // Show/Hide buttons in this order - OnAllDesktops, Maximize, Menu, Rollup, Minimize, Close.
1563 IceWMButton* btnArray[] = { button[BtnDepth], button[BtnMaximize], button[BtnSysMenu],
1564 button[BtnRollup], button[BtnMinimize], button[BtnClose] };
1566 int current_width = width();
1567 int count = 0;
1568 int i;
1570 // Find out how many buttons we have to hide.
1571 while (current_width < minwidth)
1573 current_width += btn_width;
1574 count++;
1577 // Bound the number of buttons to hide
1578 if (count > 6) count = 6;
1580 // Hide the required buttons...
1581 for(i = 0; i < count; i++)
1583 if (btnArray[i] && btnArray[i]->isVisible() )
1584 btnArray[i]->hide();
1587 // Show the rest of the buttons...
1588 for(i = count; i < 6; i++)
1590 if (btnArray[i] && (!btnArray[i]->isVisible()) )
1591 btnArray[i]->show();
1596 // Mouse position code modified from that in workspace.cpp
1597 IceWMClient::Position IceWMClient::mousePosition( const QPoint& p ) const
1599 int rangeX = cornerSizeX;
1600 int rangeY = cornerSizeY;
1601 int borderX = borderSizeX;
1602 int borderY = borderSizeY;
1604 Position m = PositionCenter;
1606 if ((p.x() > borderX && p.x() < width() - borderX) &&
1607 ( p.y() > borderY && p.y() < height() - borderY))
1608 return PositionCenter;
1610 if ( p.y() <= rangeY && p.x() <= rangeX)
1611 m = PositionTopLeft;
1612 else if ( p.y() >= height()-rangeY && p.x() >= width()-rangeX)
1613 m = PositionBottomRight;
1614 else if ( p.y() >= height()-rangeX && p.x() <= rangeX)
1615 m = PositionBottomLeft;
1616 else if ( p.y() <= rangeY && p.x() >= width()-rangeX)
1617 m = PositionTopRight;
1618 else if ( p.y() <= borderY )
1619 m = PositionTop;
1620 else if ( p.y() >= height()-borderY )
1621 m = PositionBottom;
1622 else if ( p.x() <= borderX )
1623 m = PositionLeft;
1624 else if ( p.x() >= width()-borderX )
1625 m = PositionRight;
1626 else
1627 m = PositionCenter;
1628 return m;
1632 void IceWMClient::menuButtonPressed()
1634 static QTime t;
1635 static IceWMClient* lastClient = NULL;
1636 bool dbl = ( lastClient == this && t.elapsed() <= QApplication::doubleClickInterval());
1637 lastClient = this;
1638 t.start();
1640 if (dbl)
1642 m_closing = true;
1643 return;
1646 QPoint menuPoint ( button[BtnSysMenu]->rect().bottomLeft() );
1648 // Move to right if menu on rhs, otherwise on left
1649 // and make this depend on windowWrapper(), not button.
1651 KDecorationFactory* f = factory();
1652 showWindowMenu( button[BtnSysMenu]->mapToGlobal(menuPoint) );
1653 if( !f->exists( this )) // 'this' was deleted
1654 return;
1655 button[BtnSysMenu]->setDown(false);
1658 void IceWMClient::menuButtonReleased()
1660 if (m_closing)
1661 closeWindow();
1664 bool IceWMClient::eventFilter( QObject* o, QEvent* e )
1666 if( o != widget())
1667 return false;
1668 switch( e->type())
1670 case QEvent::Resize:
1671 resizeEvent(static_cast< QResizeEvent* >( e ) );
1672 return true;
1673 case QEvent::Paint:
1674 paintEvent(static_cast< QPaintEvent* >( e ) );
1675 return true;
1676 case QEvent::MouseButtonDblClick:
1677 mouseDoubleClickEvent(static_cast< QMouseEvent* >( e ) );
1678 return true;
1679 case QEvent::MouseButtonPress:
1680 processMousePressEvent(static_cast< QMouseEvent* >( e ) );
1681 return true;
1682 default:
1683 break;
1685 return false;
1690 extern "C"
1692 KDE_EXPORT KDecorationFactory *create_factory()
1694 IceWM::clientHandler = new IceWM::ThemeHandler;
1695 return IceWM::clientHandler;
1700 #include "icewm.moc"
1702 // vim: ts=4