4 Gallium-IceWM themeable KWin client
7 Karol Szwed <gallium@kde.org>
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.
44 #include <kstandarddirs.h>
47 #include <kdrawutil.h>
48 #include <qapplication.h>
50 #include <qdrawutil.h>
51 #include <qdatetime.h>
59 #include <QPaintEvent>
60 #include <QGridLayout>
64 #include <QResizeEvent>
65 #include <QMouseEvent>
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
};
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
};
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
;
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()
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();
185 validframe
= isFrameValid();
190 ThemeHandler::~ThemeHandler()
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
)
237 for(int i
= s
.length()-1; i
>= 0; i
--)
239 tmpStr
+= s
[(unsigned int)i
];
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
.readEntry("ThemeTitleTextColors", true);
253 showMenuButtonIcon
= conf
.readEntry("ShowMenuButtonIcon", false);
254 titleBarOnTop
= conf
.readEntry("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")
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() )
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
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");
351 *colorActiveTitleTextShadow
= decodeColor( s
);
352 useActiveShadow
= true;
354 useActiveShadow
= false;
356 s
= config
.readEntry("ColorNormalTitleBarShadow");
359 *colorInActiveTitleTextShadow
= decodeColor( s
);
360 useInActiveShadow
= true;
362 useInActiveShadow
= false;
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" );
392 setPixmap( frameTL
, "frame", "TL.xpm" );
393 setPixmap( frameT
, "frame", "T.xpm", true );
394 setPixmap( frameTR
, "frame", "TR.xpm" );
397 setPixmap( frameL
, "frame", "L.xpm", true, Vertical
);
398 setPixmap( frameR
, "frame", "R.xpm", true, Vertical
);
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...
410 // ...and titleBarHeight as well
411 if (titleBarHeight
< 0)
414 // This is a work-around for some themes
416 titleT
[Active
] = duplicateValidPixmap( 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
)
448 // Use the stretch or title pixmaps instead
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
);
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
[] )
503 if (p
[Active
]) delete p
[Active
];
504 if (p
[InActive
]) delete p
[InActive
];
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
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
;
543 // If its the right size already, just return
544 if (stretchSize
== -1)
547 s_inc
= src
->width();
549 s_inc
= src
->height();
555 // Stretch an appropriate amount - taking care of pattern repetition
561 QPixmap
* p
= new QPixmap();
563 p
->resize( size
, src
->height() );
565 p
->resize( src
->width(), size
);
569 pnt
.drawTiledPixmap( 0, 0, size
, src
->height(), *src
);
571 pnt
.drawTiledPixmap( 0, 0, src
->width(), size
, *src
);
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
);
588 pnt
.drawPoint(x
+w
, y
);
589 pnt
.drawPoint(x
, y
+h
);
592 void ThemeHandler::setPixmapButton( QPixmap
* p
[], QString s1
, QString s2
)
595 qWarning("kwin-icewm: setPixmap - should be null (1)\n");
597 qWarning("kwin-icewm: setPixmap - should be null (2)\n");
599 QString str
= locate("appdata", QString("icewm-themes/")
600 + themeName
+ s1
+ "A" + s2
);
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) {
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
);
643 str
= locate("appdata", QString("icewm-themes/")
644 + themeName
+ s1
+ "I" + s2
);
646 str
= locate("appdata", QString("icewm-themes/")
647 + themeName
+ s1
+ s2
);
649 qp
= new QPixmap(str
);
650 if (!qp
->isNull() && themeLook
> 0) {
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
);
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
)
694 qWarning("kwin-icewm: setPixmap - should be null (1)\n");
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.
707 p
[Active
] = stretchPixmap( p
[Active
], stretchHoriz
);
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()
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)
745 validframe
= isFrameValid();
748 // recreate all clients
752 bool ThemeHandler::supports( Ability ability
)
756 case AbilityAnnounceButtons
:
757 case AbilityButtonMenu
:
758 case AbilityButtonOnAllDesktops
:
759 case AbilityButtonMinimize
:
760 case AbilityButtonMaximize
:
761 case AbilityButtonClose
:
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
;
779 setCursor(ArrowCursor
);
780 // Eliminate any possible background flicker
781 setBackgroundMode( QWidget::NoBackground
);
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
) );
805 return( QSize(0, 0) );
809 void IceWMButton::usePixmap( QPixmap
* (*p
)[2] )
811 if (validPixmaps( *p
)) {
813 setFixedSize( (*pix
)[Active
]->width(), titleBarHeight
);
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
);
834 pnt
->drawPixmap(0, 0, *p
, 0, 0, width
, titleBarHeight
);
837 qWarning("kwin-icewm: Can't paint a null pixmap button");
841 void IceWMButton::turnOn( bool isOn
)
843 if ( isToggleButton() )
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 ////////////////////////////////////////////////////////////////////////////////////////////
869 ////////////////////////////////////////////////////////////////////////////////////////////
871 IceWMClient::IceWMClient( KDecorationBridge
* bridge
, KDecorationFactory
* factory
)
872 : KDecoration (bridge
, factory
),
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
++)
897 // Make sure we can track the menu pixmaps too.
898 menuButtonWithIconPix
[Active
] = NULL
;
899 menuButtonWithIconPix
[InActive
] = NULL
;
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 :)
912 grid
->addWidget( new QLabel( i18n( "<center><b>IceWM preview</b></center>" ), widget() ), 2, 1);
914 grid
->addItem( new QSpacerItem( 0, 0 ), 2, 1);
916 grid
->addItem( new QSpacerItem( 0, 0, QSizePolicy::Fixed
, QSizePolicy::Expanding
) );
920 grid
->addItem( new QSpacerItem( 0, 0, QSizePolicy::Fixed
, QSizePolicy::Expanding
) );
922 grid
->addWidget( new QLabel( i18n( "<center><b>IceWM preview</b></center>" ), widget() ), 1, 1);
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
);
962 grid
->addLayout ( hb
, 1, 1 );
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
)
973 for(unsigned int i
= 0; i
< s
.length(); i
++)
975 switch ( s
[i
].latin1() )
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
) {
984 button
[BtnSysMenu
] = new IceWMButton(this, "menu",
985 &menuButtonWithIconPix
, false, i18n("Menu"), Qt::LeftButton
|Qt::RightButton
);
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
] );
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()));
1011 if ( validPixmaps(maximizePix
) && !button
[BtnMaximize
] && isMaximizable() )
1013 button
[BtnMaximize
] = new IceWMButton(this, "maximize",
1014 &maximizePix
, false, i18n("Maximize"), Qt::LeftButton
|Qt::MidButton
|Qt::RightButton
);
1015 hb
->addWidget( button
[BtnMaximize
] );
1016 connect( button
[BtnMaximize
], SIGNAL(clicked()),
1017 this, SLOT(slotMaximize()));
1022 if ( validPixmaps(minimizePix
) && !button
[BtnMinimize
] &&
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()));
1033 /* Not yet implemented - how's hide useful anyway?
1035 if ( button[BtnHide] && !button[BtnHide] )
1036 hb->addWidget( button[BtnHide] );
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()));
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()));
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
)
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
);
1081 sp
= new QSpacerItem(0, 0, QSizePolicy::Maximum
, QSizePolicy::Fixed
);
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
);
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
);
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
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
1152 right
= borderSizeX
;
1153 if( titleBarOnTop
) {
1154 top
= titleBarHeight
+ borderSizeY
;
1155 bottom
= 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());
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() );
1193 widget()->update( 0, height() - dy
+ 1, width(), dy
);
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
;
1214 QPainter
p( widget() );
1215 int act
= isActive() ? Active
: InActive
;
1217 // Determine titlebar shadow colors
1218 bool useShadow
= isActive() ? useActiveShadow
: useInActiveShadow
;
1220 colorTitleShadow
= isActive() ? *colorActiveTitleTextShadow
: *colorInActiveTitleTextShadow
;
1222 if ( themeTitleTextColors
)
1223 colorTitle
= isActive()? *colorActiveTitleBarText
: *colorInActiveTitleBarText
;
1225 colorTitle
= options()->color(ColorFont
, isActive());
1227 // Obtain widget bounds.
1229 r
= widget()->rect();
1230 int fillWidth
= r
.width() - 2*borderSizeX
;
1236 // Do we have pixmaps for the frame?
1240 p
.drawPixmap(0, 0, *frameTL
[ act
], 0, 0, cornerSizeX
, borderSizeY
);
1241 p
.drawPixmap(0, 0, *frameTL
[ act
], 0, 0, borderSizeX
, cornerSizeY
);
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
);
1250 p
.drawTiledPixmap( cornerSizeX
, 0, w
-(2*cornerSizeX
), borderSizeY
, *frameT
[ act
] );
1253 p
.drawTiledPixmap( 0, cornerSizeY
, borderSizeX
, h
-(2*cornerSizeY
), *frameL
[ act
] );
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
);
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
);
1281 p
.drawLine( x
+borderSizeX
, y
+h
-borderSizeY
-1,
1282 x
+w
-borderSizeX
-1, y
+h
-borderSizeY
-1);
1284 p
.drawLine( x
+borderSizeX
, y
+borderSizeY
,
1285 x
+w
-borderSizeX
-1, y
+borderSizeY
);
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);
1295 p
.drawRect(x
+1, y
+1, w
-2, h
-2);
1297 p
.setPen( c1
.light(135) );
1298 p
.drawLine(0, 0, w
-2, 0);
1299 p
.drawLine(0, 0, 0, h
-2);
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
);
1375 p
.drawLine( x
+borderSizeX
, y
+h
-borderSizeY
-1,
1376 x
+w
-borderSizeX
-1, y
+h
-borderSizeY
-1);
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
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());
1444 bitBlt( widget(), borderSizeX
, hb
->geometry().y(), titleBuffer
);
1451 void IceWMClient::showEvent(QShowEvent
*ev
)
1453 calcHiddenButtons();
1455 titlebar
->changeSize( titleTextWidth(caption()), titleBarHeight
,
1456 QSizePolicy::Preferred
, QSizePolicy::Fixed
);
1459 IceWMClient::showEvent(ev
);
1463 void IceWMClient::mouseDoubleClickEvent( QMouseEvent
* e
)
1465 if( e
->button() != Qt::LeftButton
)
1470 r
.setRect( borderSizeX
, borderSizeY
, width()-(2*borderSizeX
), titleBarHeight
);
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
])
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();
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
++)
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();
1570 // Find out how many buttons we have to hide.
1571 while (current_width
< minwidth
)
1573 current_width
+= btn_width
;
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
)
1620 else if ( p
.y() >= height()-borderY
)
1622 else if ( p
.x() <= borderX
)
1624 else if ( p
.x() >= width()-borderX
)
1632 void IceWMClient::menuButtonPressed()
1635 static IceWMClient
* lastClient
= NULL
;
1636 bool dbl
= ( lastClient
== this && t
.elapsed() <= QApplication::doubleClickInterval());
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
1655 button
[BtnSysMenu
]->setDown(false);
1658 void IceWMClient::menuButtonReleased()
1664 bool IceWMClient::eventFilter( QObject
* o
, QEvent
* e
)
1670 case QEvent::Resize
:
1671 resizeEvent(static_cast< QResizeEvent
* >( e
) );
1674 paintEvent(static_cast< QPaintEvent
* >( e
) );
1676 case QEvent::MouseButtonDblClick
:
1677 mouseDoubleClickEvent(static_cast< QMouseEvent
* >( e
) );
1679 case QEvent::MouseButtonPress
:
1680 processMousePressEvent(static_cast< QMouseEvent
* >( e
) );
1692 KDE_EXPORT KDecorationFactory
*create_factory()
1694 IceWM::clientHandler
= new IceWM::ThemeHandler
;
1695 return IceWM::clientHandler
;
1700 #include "icewm.moc"