Renamed devices.
[kdeartwork.git] / kwin-styles / kstep / nextclient.cpp
blob00e8d86e831574da2f2ce8bb5cd42e5dc2a174de
1 /********************************************************************
2 This program is free software; you can redistribute it and/or modify
3 it under the terms of the GNU General Public License as published by
4 the Free Software Foundation; either version 2 of the License, or
5 (at your option) any later version.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License
13 along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *********************************************************************/
16 #include "nextclient.h"
18 #include <QStyle>
19 #include <QPainter>
20 #include <QBoxLayout>
21 #include <QHBoxLayout>
22 #include <QVBoxLayout>
23 #include <QEvent>
24 #include <QPaintEvent>
25 #include <QShowEvent>
26 #include <QResizeEvent>
27 #include <QMouseEvent>
29 #include <kdebug.h>
30 #include <klocale.h>
32 namespace KStep {
34 static const unsigned char close_bits[] = {
35 0x03, 0x03, 0x87, 0x03, 0xce, 0x01, 0xfc, 0x00, 0x78, 0x00, 0x78, 0x00,
36 0xfc, 0x00, 0xce, 0x01, 0x87, 0x03, 0x03, 0x03};
38 static const unsigned char iconify_bits[] = {
39 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0x03, 0x03, 0x03, 0x03,
40 0x03, 0x03, 0x03, 0x03, 0xff, 0x03, 0xff, 0x03};
42 static const unsigned char question_bits[] = {
43 0x00, 0x00, 0x78, 0x00, 0xcc, 0x00, 0xc0, 0x00, 0x60, 0x00, 0x30, 0x00,
44 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00};
46 static const unsigned char sticky_bits[] = {
47 0x00, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0xfe, 0x01, 0xfe, 0x01,
48 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00};
50 static const unsigned char unsticky_bits[] = {
51 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0xfe, 0x01,
52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
54 static const unsigned char maximize_bits[] = {
55 0x30, 0x00, 0x78, 0x00, 0xfc, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x01,
56 0x02, 0x01, 0x84, 0x00, 0x48, 0x00, 0x30, 0x00 };
58 static const unsigned char shade_bits[] = {
59 0xff,0x03,
60 0xff,0x03,
61 0x03,0x03,
62 0xff,0x03,
63 0xff,0x03,
64 0x00,0x00,
65 0x00,0x00,
66 0x00,0x00,
67 0x00,0x00,
68 0x00,0x00
71 static const unsigned char unshade_bits[] = {
72 0xff,0x03,
73 0xff,0x03,
74 0x03,0x03,
75 0x03,0x03,
76 0x03,0x03,
77 0x03,0x03,
78 0x03,0x03,
79 0x03,0x03,
80 0xff,0x03,
81 0xff,0x03
84 static const unsigned char keep_above_bits[] = {
85 0x30,0x00,
86 0x78,0x00,
87 0xfc,0x00,
88 0x00,0x00,
89 0xff,0x03,
90 0xff,0x03,
91 0x00,0x00,
92 0x00,0x00,
93 0x00,0x00,
94 0x00,0x00
97 static const unsigned char from_above_bits[] = {
98 0xff,0x03,
99 0xff,0x03,
100 0x00,0x00,
101 0xfc,0x00,
102 0x78,0x00,
103 0x30,0x00,
104 0x00,0x00,
105 0x00,0x00,
106 0x00,0x00,
107 0x00,0x00
110 static const unsigned char keep_below_bits[] = {
111 0x00,0x00,
112 0x00,0x00,
113 0x00,0x00,
114 0x00,0x00,
115 0xff,0x03,
116 0xff,0x03,
117 0x00,0x00,
118 0xfc,0x00,
119 0x78,0x00,
120 0x30,0x00
123 static const unsigned char from_below_bits[] = {
124 0x00,0x00,
125 0x00,0x00,
126 0x00,0x00,
127 0x00,0x00,
128 0x30,0x00,
129 0x78,0x00,
130 0xfc,0x00,
131 0x00,0x00,
132 0xff,0x03,
133 0xff,0x03
136 static const unsigned char resize_bits[] = {
137 0xff, 0x03,
138 0xff, 0x03,
139 0x33, 0x03,
140 0x33, 0x03,
141 0xf3, 0x03,
142 0xf3, 0x03,
143 0x03, 0x03,
144 0x03, 0x03,
145 0xff, 0x03,
146 0xff, 0x03
150 // If the maximize graphic above (which I did quickly in about a
151 // minute, just so I could have something) doesn't please, maybe one
152 // of the following would be better. IMO it doesn't matter, as long
153 // as it's not offensive---people will get used to whatever you use.
154 // True NeXT fans won't turn on the maximize button anyway.
156 // static const unsigned char maximize_bits[] = {
157 // 0xcf, 0x03, 0x87, 0x03, 0xcf, 0x03, 0xfd, 0x02, 0x48, 0x00, 0x48, 0x00,
158 // 0xfd, 0x02, 0xcf, 0x03, 0x87, 0x03, 0xcf, 0x03 };
160 // static const unsigned char maximize_bits[] = {
161 // 0xcf, 0x03, 0x87, 0x03, 0x87, 0x03, 0x79, 0x02, 0x48, 0x00, 0x48, 0x00,
162 // 0x79, 0x02, 0x87, 0x03, 0x87, 0x03, 0xcf, 0x03 };
164 // static const unsigned char maximize_bits[] = {
165 // 0x87, 0x03, 0x03, 0x03, 0xfd, 0x02, 0x84, 0x00, 0x84, 0x00, 0x84, 0x00,
166 // 0x84, 0x00, 0xfd, 0x02, 0x03, 0x03, 0x87, 0x03 };
168 // static const unsigned char maximize_bits[] = {
169 // 0x30, 0x00, 0x78, 0x00, 0xcc, 0x00, 0x86, 0x01, 0x33, 0x03, 0x79, 0x02,
170 // 0xcd, 0x02, 0x87, 0x03, 0x03, 0x03, 0x01, 0x02 };
172 // static const unsigned char maximize_bits[] = {
173 // 0x30, 0x00, 0x78, 0x00, 0x78, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfe, 0x01,
174 // 0xfe, 0x01, 0xff, 0x03, 0xff, 0x03, 0xff, 0x03 };
177 static QPixmap *aTitlePix;
178 static QPixmap *iTitlePix;
179 static QPixmap *aFramePix;
180 static QPixmap *iFramePix;
181 static QPixmap *aHandlePix;
182 static QPixmap *iHandlePix;
183 static QPixmap *aBtn;
184 static QPixmap *aBtnDown;
185 static QPixmap *iBtn;
186 static QPixmap *iBtnDown;
187 static QColor *btnForeground;
188 static bool pixmaps_created = false;
190 static int titleHeight = 16;
192 // Precomputed border sizes for accessibility
193 // The sizes are applied for tiny -> normal -> large -> very large -> huge -> very huge -> oversized
194 static const int borderSizes[] = { 4, 6, 9, 14, 21, 32, 48 };
196 static int handleSize = 6; // the resize handle size in pixels
198 static inline const KDecorationOptions* options()
200 return KDecoration::options();
203 static void verticalGradient(QPixmap *pix, QColor first, QColor second)
205 QLinearGradient gradient(0, 0, 0, pix->height());
206 gradient.setColorAt(0.0, first);
207 gradient.setColorAt(1.0, second);
208 QBrush brush(gradient);
209 QPainter p;
210 p.begin(pix);
211 p.fillRect(pix->rect(), brush);
212 p.end();
215 static void diagonalGradient(QPixmap *pix, QColor first, QColor second)
217 QLinearGradient gradient(0, 0, pix->width(), pix->height());
218 gradient.setColorAt(0.0, first);
219 gradient.setColorAt(1.0, second);
220 QBrush brush(gradient);
221 QPainter p;
222 p.begin(pix);
223 p.fillRect(pix->rect(), brush);
224 p.end();
227 static void create_pixmaps(NextClientFactory *f)
229 if(pixmaps_created)
230 return;
231 pixmaps_created = true;
233 // find preferred border size
234 int i = options()->preferredBorderSize(f);
235 if (i >= 0 && i <= 6) handleSize = borderSizes[i];
237 titleHeight = QFontMetrics(options()->font(true)).height() + 4;
238 if (titleHeight < handleSize) titleHeight = handleSize;
239 titleHeight &= ~1; // Make title height even
240 if (titleHeight < 16) titleHeight = 16;
242 const int gradientHeight = titleHeight - 2;
243 aTitlePix = new QPixmap(32, gradientHeight);
245 verticalGradient(aTitlePix,
246 options()->color(KDecoration::ColorTitleBar, true),
247 options()->color(KDecoration::ColorTitleBlend, true));
248 iTitlePix = new QPixmap(32, titleHeight - 2);
250 verticalGradient(iTitlePix,
251 options()->color(KDecoration::ColorTitleBar, false),
252 options()->color(KDecoration::ColorTitleBlend, false));
253 // Bottom frame gradient
254 aFramePix = new QPixmap(32, handleSize);
255 verticalGradient(aFramePix,
256 options()->color(KDecoration::ColorFrame, true).light(150),
257 options()->color(KDecoration::ColorFrame, true).dark(120));
258 iFramePix = new QPixmap(32, handleSize);
259 verticalGradient(iFramePix,
260 options()->color(KDecoration::ColorFrame, false).light(150),
261 options()->color(KDecoration::ColorFrame, false).dark(120));
262 // Handle gradient
263 aHandlePix = new QPixmap(32, handleSize);
264 verticalGradient(aHandlePix,
265 options()->color(KDecoration::ColorHandle, true).light(150),
266 options()->color(KDecoration::ColorHandle, true).dark(120));
267 iHandlePix = new QPixmap(32, handleSize);
268 verticalGradient(iHandlePix,
269 options()->color(KDecoration::ColorHandle, true).light(150),
270 options()->color(KDecoration::ColorHandle, true).dark(120));
272 int btnWidth = titleHeight;
273 iBtn = new QPixmap(btnWidth, btnWidth);
274 iBtnDown = new QPixmap(btnWidth, btnWidth);
275 aBtn = new QPixmap(btnWidth, btnWidth);
276 aBtnDown = new QPixmap(btnWidth, btnWidth);
277 int internalHeight = btnWidth - 6;
278 QPixmap internal(internalHeight, internalHeight);
279 QRect dest(internal.rect());
280 dest.moveTo(3, 3);
282 QPainter p;
284 // inactive buttons
285 QColor c(options()->color(KDecoration::ColorButtonBg, false));
286 diagonalGradient(iBtn, c.light(120), c.dark(120));
287 diagonalGradient(&internal, c.dark(120), c.light(120));
288 p.begin(iBtn);
289 p.drawPixmap(dest, internal, internal.rect());
290 p.end();
291 //bitBlt(iBtn, 3, 3, &internal, 0, 0, internalHeight, internalHeight, Qt::CopyROP, true);
294 diagonalGradient(iBtnDown, c.dark(120), c.light(120));
295 diagonalGradient(&internal, c.light(120), c.dark(120));
296 //bitBlt(iBtnDown, 3, 3, &internal, 0, 0, internalHeight, internalHeight, Qt::CopyROP, true);
297 p.begin(iBtnDown);
298 dest.moveTo(3, 3);
299 p.drawPixmap(dest, internal, internal.rect());
300 p.end();
302 // active buttons
303 c = options()->color(KDecoration::ColorButtonBg, true);
304 diagonalGradient(aBtn, c.light(120), c.dark(120));
305 diagonalGradient(&internal, c.dark(120), c.light(120));
306 //bitBlt(aBtn, 3, 3, &internal, 0, 0, internalHeight, internalHeight, Qt::CopyROP, true);
307 p.begin(aBtn);
308 p.drawPixmap(dest, internal, internal.rect());
309 p.end();
311 diagonalGradient(aBtnDown, c.dark(120), c.light(120));
312 diagonalGradient(&internal, c.light(120), c.dark(120));
313 //bitBlt(aBtnDown, 3, 3, &internal, 0, 0, internalHeight, internalHeight, Qt::CopyROP, true);
314 p.begin(aBtnDown);
315 p.drawPixmap(dest, internal, internal.rect());
316 p.end();
318 p.begin(aBtn);
319 p.setPen(Qt::black);
320 p.drawRect(0, 0, btnWidth, btnWidth);
321 p.end();
322 p.begin(iBtn);
323 p.setPen(Qt::black);
324 p.drawRect(0, 0, btnWidth, btnWidth);
325 p.end();
326 p.begin(aBtnDown);
327 p.setPen(Qt::black);
328 p.drawRect(0, 0, btnWidth, btnWidth);
329 p.end();
330 p.begin(iBtnDown);
331 p.setPen(Qt::black);
332 p.drawRect(0, 0, btnWidth, btnWidth);
333 p.end();
335 if(qGray(options()->color(KDecoration::ColorButtonBg, true).rgb()) > 128)
336 btnForeground = new QColor(Qt::black);
337 else
338 btnForeground = new QColor(Qt::white);
341 static void delete_pixmaps()
343 delete aTitlePix;
344 delete iTitlePix;
345 delete aFramePix;
346 delete iFramePix;
347 delete aHandlePix;
348 delete iHandlePix;
349 delete aBtn;
350 delete iBtn;
351 delete aBtnDown;
352 delete iBtnDown;
353 delete btnForeground;
355 pixmaps_created = false;
358 // =====================================
360 NextButton::NextButton(NextClient *parent,
361 const unsigned char *bitmap, int bw, int bh,
362 const QString& tip, const int realizeBtns)
363 : QAbstractButton(parent->widget()),
364 client(parent), last_button(Qt::NoButton)
366 realizeButtons = realizeBtns;
368 setAttribute(Qt::WA_NoSystemBackground);
369 resize(titleHeight, titleHeight);
370 setFixedSize(titleHeight, titleHeight);
372 if(bitmap)
373 setBitmap(bitmap, bw, bh);
375 this->setToolTip( tip);
378 void NextButton::reset()
380 repaint();
383 void NextButton::setBitmap(const unsigned char *bitmap, int w, int h)
385 QSize s(w, h);
386 deco = QBitmap::fromData(s, bitmap, QImage::Format_MonoLSB);
387 deco.setMask(deco);
388 repaint();
391 void NextButton::paintEvent(QPaintEvent *)
393 QPainter p(this);
394 if (client->isActive())
395 p.drawPixmap(0, 0, isDown() ? *aBtnDown : *aBtn);
396 else
397 p.drawPixmap(0, 0, isDown() ? *iBtnDown : *iBtn);
399 // If we have a decoration, draw it; otherwise, we have the menu
400 // button (remember, we set the bitmap to NULL).
401 int offset;
402 if (!deco.isNull()) {
403 offset = (titleHeight - 10) / 2 + (isDown() ? 1 : 0);
404 p.setPen(*btnForeground);
405 p.drawPixmap(offset, offset, deco);
406 } else {
407 offset = (titleHeight - 16) / 2;
408 QPixmap btnpix = client->icon().pixmap(
409 style()->pixelMetric(QStyle::PM_SmallIconSize),
410 client->isActive() ? QIcon::Normal : QIcon::Disabled);
411 p.drawPixmap(offset, offset, btnpix);
415 void NextButton::mousePressEvent( QMouseEvent* e )
417 last_button = e->button();
418 QMouseEvent me(e->type(), e->pos(), e->globalPos(),
419 (e->button() & realizeButtons) ? Qt::LeftButton : Qt::NoButton,
420 (e->button() & realizeButtons) ? Qt::LeftButton : Qt::NoButton,
421 e->modifiers());
422 QAbstractButton::mousePressEvent(&me);
425 void NextButton::mouseReleaseEvent( QMouseEvent* e )
427 last_button = e->button();
428 QMouseEvent me(e->type(), e->pos(), e->globalPos(),
429 (e->button() & realizeButtons) ? Qt::LeftButton : Qt::NoButton,
430 (e->button() & realizeButtons) ? Qt::LeftButton : Qt::NoButton,
431 e->modifiers());
432 QAbstractButton::mouseReleaseEvent(&me);
435 // =====================================
437 NextClient::NextClient(KDecorationBridge *b, KDecorationFactory *f)
438 : KDecoration(b, f)
442 void NextClient::init()
444 createMainWidget();
445 widget()->setAttribute(Qt::WA_NoSystemBackground);
446 widget()->installEventFilter(this);
448 //widget()->setBackgroundMode( NoBackground );
450 QVBoxLayout *mainLayout = new QVBoxLayout(widget());
451 QBoxLayout *titleLayout = new QBoxLayout(QBoxLayout::LeftToRight);
452 QHBoxLayout *windowLayout = new QHBoxLayout();
453 mainLayout->setMargin(0);
454 titleLayout->setMargin(0);
455 titleLayout->setSpacing(0);
456 mainLayout->addLayout(titleLayout);
457 mainLayout->addLayout(windowLayout, 1);
458 mainLayout->addSpacing(mustDrawHandle() ? handleSize : 1);
460 windowLayout->addSpacing(1);
461 if (isPreview())
462 windowLayout->addWidget(new QLabel(i18n(
463 "<center><b>KStep preview</b></center>"), widget()));
464 else
465 windowLayout->addItem(new QSpacerItem( 0, 0 ));
467 windowLayout->addSpacing(1);
469 initializeButtonsAndTitlebar(titleLayout);
473 Preconditions:
474 + button is an array of length MAX_NUM_BUTTONS
476 Postconditions:
477 + Title bar and buttons have been initialized and laid out
478 + for all i in 0..(MAX_NUM_BUTTONS-1), button[i] points to
479 either (1) a valid NextButton instance, if the corresponding
480 button is selected in the current button scheme, or (2) null
481 otherwise.
483 void NextClient::initializeButtonsAndTitlebar(QBoxLayout* titleLayout)
485 // Null the buttons to begin with (they are not guaranteed to be null).
486 for (int i=0; i<MAX_NUM_BUTTONS; i++) {
487 button[i] = NULL;
490 // The default button positions for other styles do not match the
491 // behavior of older versions of KStep, so we have to set these
492 // manually when customButtonPositions isn't enabled.
493 QString left, right;
494 if (options()->customButtonPositions()) {
495 left = options()->titleButtonsLeft();
496 right = options()->titleButtonsRight();
497 } else {
498 left = QString("I");
499 right = QString("SX");
502 // Do actual creation and addition to titleLayout
503 addButtons(titleLayout, left);
505 titlebar = new QSpacerItem(10, titleHeight, QSizePolicy::Expanding,
506 QSizePolicy::Minimum );
507 titleLayout->addItem(titlebar);
508 addButtons(titleLayout, right);
510 // Finally, activate all live buttons
511 for (int i = 0; i < MAX_NUM_BUTTONS; i++) {
512 if (button[i]) {
513 button[i]->setMouseTracking( TRUE );
518 /** Adds the buttons for one side of the title bar, based on the spec
519 * string; see the KWin::KDecoration class, methods
520 * titleButtonsLeft and titleBUttonsRight. */
521 void NextClient::addButtons(QBoxLayout* titleLayout, const QString& spec)
523 for (int i = 0; i < spec.length(); i++) {
524 switch (spec[i].toLatin1()) {
525 case 'A':
526 if (isMaximizable()) {
527 button[MAXIMIZE_IDX] =
528 new NextButton(this, maximize_bits, 10, 10,
529 i18n("Maximize"), Qt::LeftButton|Qt::MidButton|Qt::RightButton);
530 titleLayout->addWidget( button[MAXIMIZE_IDX] );
531 connect( button[MAXIMIZE_IDX], SIGNAL(clicked()),
532 this, SLOT(maximizeButtonClicked()) );
534 break;
536 case 'H':
537 if (providesContextHelp()) {
538 button[HELP_IDX] = new NextButton(this, question_bits, 10, 10, i18n("Help"));
539 titleLayout->addWidget( button[HELP_IDX] );
540 connect( button[HELP_IDX], SIGNAL(clicked()),
541 this, SLOT(showContextHelp()) );
543 break;
545 case 'I':
546 if (isMinimizable()) {
547 button[ICONIFY_IDX] =
548 new NextButton(this, iconify_bits, 10, 10,
549 i18n("Minimize"));
550 titleLayout->addWidget( button[ICONIFY_IDX] );
551 connect( button[ICONIFY_IDX], SIGNAL(clicked()),
552 this, SLOT(minimize()) );
554 break;
556 case 'M':
557 button[MENU_IDX] =
558 new NextButton(this, NULL, 10, 10, i18n("Menu"), Qt::LeftButton|Qt::RightButton);
559 titleLayout->addWidget( button[MENU_IDX] );
560 // NOTE DIFFERENCE: capture pressed(), not clicked()
561 connect( button[MENU_IDX], SIGNAL(pressed()),
562 this, SLOT(menuButtonPressed()) );
563 break;
565 case 'L':
566 button[SHADE_IDX] =
567 new NextButton(this, NULL, 0, 0, i18n("Shade"));
568 titleLayout->addWidget( button[SHADE_IDX] );
569 connect( button[SHADE_IDX], SIGNAL(clicked()),
570 this, SLOT(shadeClicked()) );
571 // NOTE DIFFERENCE: set the pixmap separately (2 states)
572 shadeChange();
573 break;
575 case 'S':
576 button[STICKY_IDX] =
577 new NextButton(this, NULL, 0, 0, i18n("On all desktops"));
578 titleLayout->addWidget( button[STICKY_IDX] );
579 connect( button[STICKY_IDX], SIGNAL(clicked()),
580 this, SLOT(toggleOnAllDesktops()) );
581 // NOTE DIFFERENCE: set the pixmap separately (2 states)
582 desktopChange();
583 break;
585 case 'F':
586 button[ABOVE_IDX] = new NextButton(this, NULL, 0, 0, "");
587 titleLayout->addWidget( button[ABOVE_IDX] );
588 connect( button[ABOVE_IDX], SIGNAL(clicked()),
589 this, SLOT(aboveClicked()) );
590 connect(this, SIGNAL(keepAboveChanged(bool)),
591 SLOT(keepAboveChange(bool)));
592 keepAboveChange(keepAbove());
593 break;
595 case 'B':
596 button[BELOW_IDX] = new NextButton(this, NULL, 0, 0, "");
597 titleLayout->addWidget( button[BELOW_IDX] );
598 connect( button[BELOW_IDX], SIGNAL(clicked()),
599 this, SLOT(belowClicked()) );
600 connect(this, SIGNAL(keepBelowChanged(bool)),
601 SLOT(keepBelowChange(bool)));
602 keepBelowChange(keepBelow());
603 break;
605 case 'X':
606 if (isCloseable()) {
607 button[CLOSE_IDX] =
608 new NextButton(this, close_bits, 10, 10,
609 i18n("Close"));
610 titleLayout->addWidget(button[CLOSE_IDX]);
611 connect(button[CLOSE_IDX], SIGNAL(clicked()),
612 this, SLOT(closeWindow()));
614 break;
616 case 'R':
617 if (mustDrawHandle()) {
618 button[RESIZE_IDX] =
619 new NextButton(this, resize_bits, 10, 10,
620 i18n("Resize"));
621 titleLayout->addWidget(button[RESIZE_IDX]);
622 // NOTE DIFFERENCE: capture pressed(), not clicked()
623 connect(button[RESIZE_IDX], SIGNAL(pressed()),
624 this, SLOT(resizePressed()));
626 break;
627 case '_':
628 // TODO: Add spacer handling
629 break;
631 default:
632 kDebug() << " Can't happen: unknown button code "
633 << QString(spec[i]);
634 break;
639 bool NextClient::mustDrawHandle() const
641 bool drawSmallBorders = !options()->moveResizeMaximizedWindows();
642 if (drawSmallBorders && (maximizeMode() & MaximizeVertical)) {
643 return false;
644 } else {
645 return isResizable();
649 void NextClient::iconChange()
651 if (button[MENU_IDX] && button[MENU_IDX]->isVisible())
652 button[MENU_IDX]->repaint();
655 void NextClient::menuButtonPressed()
657 // Probably don't need this null check, but we might as well.
658 if (button[MENU_IDX]) {
659 QRect menuRect = button[MENU_IDX]->rect();
660 QPoint menuTop = button[MENU_IDX]->mapToGlobal(menuRect.topLeft());
661 QPoint menuBottom = button[MENU_IDX]->mapToGlobal(menuRect.bottomRight());
662 menuTop += QPoint(1, 1);
663 menuBottom += QPoint(1, 1);
664 KDecorationFactory* f = factory();
665 showWindowMenu(QRect(menuTop, menuBottom));
666 if( !f->exists( this )) // 'this' was deleted
667 return;
668 button[MENU_IDX]->setDown(false);
672 // Copied, with minor edits, from KDEDefaultClient::slotMaximize()
673 void NextClient::maximizeButtonClicked()
675 if (button[MAXIMIZE_IDX]) {
676 maximize(button[MAXIMIZE_IDX]->lastButton());
680 void NextClient::shadeClicked()
682 setShade(!isSetShade());
685 void NextClient::aboveClicked()
687 setKeepAbove(!keepAbove());
690 void NextClient::belowClicked()
692 setKeepBelow(!keepBelow());
693 keepAboveChange(keepAbove());
694 keepBelowChange(keepBelow());
697 void NextClient::resizePressed()
699 performWindowOperation(ResizeOp);
702 void NextClient::resizeEvent(QResizeEvent *)
704 if (widget()->isVisible()) {
705 // TODO ? update border area only?
706 widget()->update();
707 #if 0
708 widget()->update(titlebar->geometry());
709 QPainter p(widget());
710 QRect t = titlebar->geometry();
711 t.setTop( 0 );
712 QRegion r = widget()->rect();
713 r = r.subtract( t );
714 p.setClipRegion( r );
715 p.eraseRect(widget()->rect());
716 #endif
720 void NextClient::captionChange()
722 widget()->repaint(titlebar->geometry());
726 void NextClient::paintEvent( QPaintEvent* )
728 QPainter p(widget());
730 // Draw black frame
731 QRect fr = widget()->rect();
732 p.setPen(Qt::black);
733 p.drawRect(fr);
735 // Draw title bar
736 QRect t = titlebar->geometry();
737 t.setTop(1);
738 p.drawTiledPixmap(t.x()+1, t.y()+1, t.width()-2, t.height()-2,
739 isActive() ? *aTitlePix : *iTitlePix);
740 qDrawShadePanel(&p, t.x(), t.y(), t.width(), t.height()-1,
741 options()->palette(KDecoration::ColorTitleBar, isActive()));
742 p.drawLine(t.x(), t.bottom(), t.right(), t.bottom());
744 #if 0
745 // Why setting up a clipping region if it is not used? (setClipping(false))
746 QRegion r = fr;
747 r = r.subtract( t );
748 p.setClipRegion( r );
749 p.setClipping(false);
750 #endif
752 t.setTop( 1 );
753 t.setHeight(t.height()-2);
754 t.setLeft( t.left() + 4 );
755 t.setRight( t.right() - 2 );
757 p.setPen(options()->color(KDecoration::ColorFont, isActive()));
758 p.setFont(options()->font(isActive()));
759 p.drawText( t, Qt::AlignCenter | Qt::AlignVCenter, caption() );
761 // Draw resize handle
762 if (mustDrawHandle()) {
763 int corner = 16 + 3*handleSize/2;
764 qDrawShadePanel(&p,
765 fr.x() + 1, fr.bottom() - handleSize, corner-1, handleSize,
766 options()->palette(KDecoration::ColorHandle, isActive()),
767 false);
768 p.drawTiledPixmap(fr.x() + 2, fr.bottom() - handleSize + 1,
769 corner - 3, handleSize - 2, isActive() ? *aHandlePix : *iHandlePix);
771 qDrawShadePanel(&p,
772 fr.x() + corner, fr.bottom() - handleSize,
773 fr.width() - 2*corner, handleSize,
774 options()->palette(KDecoration::ColorFrame, isActive()),
775 false);
776 p.drawTiledPixmap(fr.x() + corner + 1, fr.bottom() - handleSize + 1,
777 fr.width() - 2*corner - 2, handleSize - 2,
778 isActive() ? *aFramePix : *iFramePix);
780 qDrawShadePanel(&p,
781 fr.right() - corner + 1, fr.bottom() - handleSize, corner - 1, handleSize,
782 options()->palette(KDecoration::ColorHandle, isActive()),
783 false);
784 p.drawTiledPixmap(fr.right() - corner + 2, fr.bottom() - handleSize + 1,
785 corner - 3, handleSize - 2, isActive() ? *aHandlePix : *iHandlePix);
789 void NextClient::mouseDoubleClickEvent( QMouseEvent * e )
791 if (e->button() == Qt::LeftButton && titlebar->geometry().contains( e->pos() ) )
792 titlebarDblClickOperation();
795 void NextClient::showEvent(QShowEvent *)
797 widget()->repaint();
800 void NextClient::desktopChange()
802 bool on = isOnAllDesktops();
803 if (NextButton * b = button[STICKY_IDX]) {
804 b->setBitmap( on ? unsticky_bits : sticky_bits, 10, 10);
805 //QToolTip::remove(b);
806 b->setToolTip( on ? i18n("Not on all desktops") : i18n("On all desktops"));
810 void NextClient::maximizeChange()
812 if (button[MAXIMIZE_IDX]) {
813 bool m = maximizeMode() == MaximizeFull;
814 //button[MAXIMIZE_IDX]->setBitmap(m ? minmax_bits : maximize_bits);
815 //QToolTip::remove(button[MAXIMIZE_IDX]);
816 button[MAXIMIZE_IDX]->setToolTip(
817 m ? i18n("Restore") : i18n("Maximize"));
819 //spacer->changeSize(10, mustDrawHandle() ? handleSize : 1,
820 // QSizePolicy::Expanding, QSizePolicy::Minimum);
821 //mainLayout->activate();
824 void NextClient::activeChange()
826 widget()->repaint();
827 slotReset();
830 void NextClient::slotReset()
832 for (int i=0; i<MAX_NUM_BUTTONS; i++) {
833 if (button[i]) {
834 button[i]->reset();
839 KDecoration::Position
840 NextClient::mousePosition( const QPoint& p ) const
842 Position m = PositionCenter;
844 if (p.y() < (height() - handleSize))
845 m = KDecoration::mousePosition(p);
847 else {
848 int corner = 16 + 3*handleSize/2;
849 if (p.x() >= (width() - corner))
850 m = PositionBottomRight;
851 else if (p.x() <= corner)
852 m = PositionBottomLeft;
853 else
854 m = PositionBottom;
857 return m;
860 void NextClient::borders(int &left, int &right, int &top, int &bottom) const
862 left = right = 1;
863 top = titleHeight; // FRAME is this ok?
864 bottom = mustDrawHandle() ? handleSize : 1;
867 void NextClient::shadeChange()
869 if (NextButton *b = button[SHADE_IDX]) {
870 b->setBitmap(isSetShade() ? unshade_bits : shade_bits, 10, 10);
871 //QToolTip::remove(b);
872 b->setToolTip( isSetShade() ? i18n("Unshade") : i18n("Shade"));
876 void NextClient::keepAboveChange(bool above)
878 if (NextButton *b = button[ABOVE_IDX]) {
879 b->setBitmap(above ? from_above_bits : keep_above_bits, 10, 10);
880 //QToolTip::remove(b);
881 b->setToolTip( above ?
882 i18n("Do not keep above others") : i18n("Keep above others"));
883 b->repaint();
887 void NextClient::keepBelowChange(bool below)
889 if (NextButton *b = button[BELOW_IDX]) {
890 b->setBitmap(below ? from_below_bits : keep_below_bits, 10, 10);
891 //QToolTip::remove(b);
892 b->setToolTip( below ?
893 i18n("Do not keep below others") : i18n("Keep below others"));
894 b->repaint();
898 QSize NextClient::minimumSize() const
900 return QSize(titleHeight * 6 + 2, titleHeight + handleSize + 2);
903 void NextClient::resize(const QSize& s)
905 widget()->resize(s);
908 void NextClient::reset(unsigned long)
910 for (int i = 0; i < MAX_NUM_BUTTONS; ++i) {
911 if (button[i])
912 button[i]->reset();
914 widget()->repaint();
917 bool NextClient::eventFilter(QObject *o, QEvent *e)
919 if (o != widget())
920 return false;
921 switch (e->type()) {
922 case QEvent::Resize:
923 resizeEvent(static_cast< QResizeEvent* >( e ));
924 return true;
925 case QEvent::Paint:
926 paintEvent(static_cast< QPaintEvent* >( e ));
927 return true;
928 case QEvent::MouseButtonDblClick:
929 mouseDoubleClickEvent(static_cast< QMouseEvent* >( e ));
930 return true;
931 case QEvent::MouseButtonPress:
932 processMousePressEvent(static_cast< QMouseEvent* >( e ));
933 return true;
934 case QEvent::Show:
935 showEvent(static_cast< QShowEvent* >( e ));
936 return true;
937 default:
938 break;
940 return false;
943 bool NextClient::drawbound(const QRect& geom, bool /* clear */)
945 // Let kwin draw the bounds, for now.
946 return false;
947 #if 0
948 QPainter p(workspaceWidget());
949 p.setPen(QPen(Qt::white, 3));
950 p.setCompositionMode(QPainter::CompositionMode_Xor);
951 p.drawRect(geom);
952 int leftMargin = geom.left() + 2;
953 p.fillRect(leftMargin, geom.top() + titleHeight - 1,
954 geom.width() - 4, 3, Qt::white);
955 if (mustDrawHandle()) {
956 p.fillRect(leftMargin, geom.bottom() - handleSize - 1,
957 geom.width() - 4, 3, Qt::white);
959 return true;
960 #endif
963 // =====================================
965 NextClientFactory::NextClientFactory()
967 create_pixmaps(this);
970 NextClientFactory::~NextClientFactory()
972 delete_pixmaps();
975 KDecoration *NextClientFactory::createDecoration(KDecorationBridge *b)
977 return new NextClient(b, this);
980 bool NextClientFactory::reset(unsigned long /*changed*/)
982 // TODO Do not recreate decorations if it is not needed. Look at
983 // ModernSystem for how to do that
984 delete_pixmaps();
985 create_pixmaps(this);
986 // For now just return true.
987 return true;
990 bool NextClientFactory::supports( Ability ability ) const
992 switch( ability )
994 case AbilityAnnounceButtons:
995 case AbilityButtonMenu:
996 case AbilityButtonOnAllDesktops:
997 case AbilityButtonHelp:
998 case AbilityButtonMinimize:
999 case AbilityButtonMaximize:
1000 case AbilityButtonClose:
1001 case AbilityButtonAboveOthers:
1002 case AbilityButtonBelowOthers:
1003 case AbilityButtonShade:
1004 case AbilityButtonResize:
1005 return true;
1006 default:
1007 return false;
1011 QList< NextClientFactory::BorderSize >
1012 NextClientFactory::borderSizes() const
1014 // the list must be sorted
1015 return QList< BorderSize >() << BorderTiny << BorderNormal <<
1016 BorderLarge << BorderVeryLarge << BorderHuge <<
1017 BorderVeryHuge << BorderOversized;
1020 } // KStep namespace
1022 extern "C" KDE_EXPORT KDecorationFactory* create_factory()
1024 return new KStep::NextClientFactory();
1027 #include "nextclient.moc"
1029 // vim: sw=4