1 /*
2 * Copyright © 2009 Dennis Kasprzyk <onestone@compiz-fusion.org>
3 * Copyright © 2006 Novell, Inc.
4 * Copyright © 2006 Volker Krause <vkrause@kde.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 *
21 * Author: David Reveman <davidr@novell.com>
22 */
23
24 #include "window.h"
25 #include "decorator.h"
26 #include "options.h"
27 #include "utils.h"
28
29 #include <X11/Xlib.h>
30 #include <X11/extensions/shape.h>
31 #include <X11/extensions/Xcomposite.h>
32 #include <X11/Xregion.h>
33
34 #include <fixx11h.h>
35
36 #include <KDE/KGlobal>
37 #include <KDE/KGlobalSettings>
38 #include <KDE/KIconLoader>
39 #include <kdecoration.h>
40 #include <kwindowsystem.h>
41 #include <KDE/KLocale>
42 #include <KDE/KStandardDirs>
43 #include <KDE/KAction>
44 #include <KDE/KActionCollection>
45 #include <KDE/KIcon>
46
47 #include <QApplication>
48 #include <QEvent>
49 #include <QWidget>
50 #include <QString>
51 #include <QTimer>
52 #include <QMenu>
53 #include <QX11Info>
54 #include <QObjectList>
55 #include <QVector>
56 #include <QProcess>
57 #include <QStyle>
58 #include <QPainter>
59
60 #include "paintredirector.h"
61
Window(WId parentId,WId clientId,WId frame,Type type,int x,int y,int w,int h)62 KWD::Window::Window (WId parentId,
63 WId clientId,
64 WId frame,
65 Type type,
66 int x,
67 int y,
68 int w,
69 int h) :
70 mType (type),
71 mParentId (parentId),
72 mFrame (0),
73 mClientId (clientId),
74 mSelectedId (0),
75 mDecor (0),
76 mPixmap (0),
77 mUpdateProperty (false),
78 mShapeSet (false),
79 mPopup (0),
80 mAdvancedMenu (0),
81 mOpacityMenu (0),
82 mDesktopMenu (0),
83 mProcessKiller (this),
84 mKeys (this),
85 mResizeOpAction (0),
86 mMoveOpAction (0),
87 mMaximizeOpAction (0),
88 mShadeOpAction (0),
89 mKeepAboveOpAction (0),
90 mKeepBelowOpAction (0),
91 mFullScreenOpAction (0),
92 mMinimizeOpAction (0),
93 mCloseOpAction (0),
94 mDesktopOpAction (0),
95 mPaintRedirector (0)
96 {
97 memset (&mBorder, 0, sizeof (mBorder));
98
99 if (mType == Normal)
100 {
101 KWindowInfo wInfo = KWindowSystem::windowInfo (mClientId, NET::WMState |
102 NET::WMVisibleName, 0);
103
104 mState = wInfo.state ();
105
106 if (mType == Normal)
107 {
108 mName = wInfo.visibleName ();
109
110 mIcon = KWindowSystem::icon (mClientId, 32, 32, true,
111 KWindowSystem::NETWM |
112 KWindowSystem::WMHints );
113
114 mMiniIcon = KWindowSystem::icon (mClientId, 16, 16, true,
115 KWindowSystem::NETWM |
116 KWindowSystem::WMHints );
117
118 if (mIcon.isNull ())
119 {
120 mIcon = KWindowSystem::icon (mClientId, 32, 32, true,
121 KWindowSystem::ClassHint |
122 KWindowSystem::XApp );
123 mMiniIcon = KWindowSystem::icon (mClientId, 16, 16, true,
124 KWindowSystem::ClassHint |
125 KWindowSystem::XApp );
126 }
127
128 mOpacity = readPropertyShort (mClientId, Atoms::netWmWindowOpacity,
129 0xffff);
130 }
131 else
132 {
133 mIcon = QPixmap ();
134 mMiniIcon = QPixmap ();
135 mName = QString ("");
136 }
137
138 updateFrame (frame);
139
140 mGeometry = QRect (x, y, w, h);
141
142 getWindowProtocols ();
143 }
144 else
145 {
146 mIcon = QPixmap ();
147 mMiniIcon = QPixmap ();
148 mName = QString ("");
149 mGeometry = QRect (50, 50, 30, 1);
150 }
151
152 createDecoration ();
153
154 mActiveChild = NULL;
155 }
156
~Window(void)157 KWD::Window::~Window (void)
158 {
159 if (mPixmap)
160 XFreePixmap (QX11Info::display(), mPixmap);
161
162 if (mDecor)
163 delete mDecor;
164
165 if (mPopup)
166 delete mPopup;
167
168 if (mPaintRedirector)
169 delete mPaintRedirector;
170
171 if (mProcessKiller.state () == QProcess::Running)
172 {
173 mProcessKiller.terminate ();
174 mProcessKiller.waitForFinished (10000);
175 if (mProcessKiller.state () == QProcess::Running)
176 {
177 mProcessKiller.kill ();
178 mProcessKiller.waitForFinished (5000);
179 }
180 }
181 }
182
183 bool
isActive(void) const184 KWD::Window::isActive (void) const
185 {
186 if (mType == DefaultActive)
187 return true;
188
189 return Decorator::activeId () == mClientId;
190 }
191
192 bool
isCloseable(void) const193 KWD::Window::isCloseable (void) const
194 {
195 KWindowInfo wInfo;
196
197 if (mType != Normal)
198 return false;
199
200 wInfo = KWindowSystem::windowInfo (mClientId, NET::WMPid,
201 NET::WM2AllowedActions);
202 return wInfo.actionSupported (NET::ActionClose);
203 }
204
205 bool
isMaximizable(void) const206 KWD::Window::isMaximizable (void) const
207 {
208 KWindowInfo wInfo;
209
210 if (mType != Normal)
211 return false;
212
213 wInfo = KWindowSystem::windowInfo (mClientId, NET::WMPid,
214 NET::WM2AllowedActions);
215 return wInfo.actionSupported (NET::ActionMax);
216 }
217
218 KDecoration::MaximizeMode
maximizeMode(void) const219 KWD::Window::maximizeMode (void) const
220 {
221 MaximizeMode mode = MaximizeRestore;
222
223 if (mType != Normal)
224 return mode;
225
226 mode =
227 ((mState & NET::MaxVert) ? MaximizeVertical : MaximizeRestore) |
228 ((mState & NET::MaxHoriz) ? MaximizeHorizontal : MaximizeRestore);
229
230 return mode;
231 }
232
233 bool
isMinimizable(void) const234 KWD::Window::isMinimizable (void) const
235 {
236 KWindowInfo wInfo;
237
238 if (mType != Normal)
239 return false;
240
241 wInfo = KWindowSystem::windowInfo (mClientId, NET::WMPid,
242 NET::WM2AllowedActions);
243 return wInfo.actionSupported (NET::ActionMinimize);
244 }
245
246 bool
providesContextHelp(void) const247 KWD::Window::providesContextHelp (void) const
248 {
249 if (mType != Normal)
250 return false;
251
252 return mSupportContextHelp;
253 }
254
255 int
desktop(void) const256 KWD::Window::desktop (void) const
257 {
258 KWindowInfo wInfo = KWindowSystem::windowInfo (mClientId,
259 NET::WMDesktop, 0);
260
261 return wInfo.desktop ();
262 }
263
264 bool
isModal(void) const265 KWD::Window::isModal (void) const
266 {
267 return mState & NET::Modal;
268 }
269
270 bool
isShadeable(void) const271 KWD::Window::isShadeable (void) const
272 {
273 KWindowInfo wInfo = KWindowSystem::windowInfo (mClientId, NET::WMPid,
274 NET::WM2AllowedActions);
275
276 return wInfo.actionSupported (NET::ActionShade);
277 }
278
279 bool
isShade(void) const280 KWD::Window::isShade (void) const
281 {
282 if (mType != Normal)
283 return false;
284
285 return (mState & NET::Shaded);
286 }
287
288 bool
isSetShade(void) const289 KWD::Window::isSetShade (void) const
290 {
291 return isShade ();
292 }
293
294 bool
keepAbove(void) const295 KWD::Window::keepAbove (void) const
296 {
297 if (mType != Normal)
298 return false;
299
300 return (mState & NET::KeepAbove);
301 }
302
303 bool
keepBelow(void) const304 KWD::Window::keepBelow (void) const
305 {
306 if (mType != Normal)
307 return false;
308
309 return (mState & NET::KeepBelow);
310 }
311
312 bool
isMovable(void) const313 KWD::Window::isMovable (void) const
314 {
315 KWindowInfo wInfo = KWindowSystem::windowInfo (mClientId, NET::WMPid,
316 NET::WM2AllowedActions);
317
318 return wInfo.actionSupported (NET::ActionMove);
319 }
320
321 NET::WindowType
windowType(unsigned long mask) const322 KWD::Window::windowType (unsigned long mask) const
323 {
324 KWindowInfo wInfo = KWindowSystem::windowInfo (mClientId,
325 NET::WMWindowType, 0);
326
327 return wInfo.windowType (mask);
328 }
329
330 bool
isResizable(void) const331 KWD::Window::isResizable (void) const
332 {
333 KWindowInfo wInfo = KWindowSystem::windowInfo (mClientId, NET::WMPid,
334 NET::WM2AllowedActions);
335
336 return wInfo.actionSupported (NET::ActionResize);
337 }
338
339 QIcon
icon(void) const340 KWD::Window::icon (void) const
341 {
342 QIcon icon (mIcon);
343 icon.addPixmap (mMiniIcon);
344 return icon;
345 }
346
347 QString
caption(void) const348 KWD::Window::caption (void) const
349 {
350 return mName;
351 }
352
353 /* TODO: We should use libtaskmanager, which is part of kdebase to create
354 the window menu instead but the headers for that library are currently
355 not installed. If kdebase could install those headers, we wouldn't have
356 to have our own window menu implementaion here. */
357 void
showWindowMenu(const QPoint & pos)358 KWD::Window::showWindowMenu (const QPoint &pos)
359 {
360 if (!mPopup)
361 {
362 QAction *action;
363 const int levels[] = { 100, 90, 75, 50, 25, 10 };
364
365 mPopup = new QMenu ();
366 mPopup->setFont (KGlobalSettings::menuFont ());
367
368 connect (mPopup, SIGNAL (aboutToShow ()),
369 SLOT (handlePopupAboutToShow ()));
370 connect (mPopup, SIGNAL (triggered (QAction*)),
371 SLOT (handlePopupActivated (QAction*)));
372
373 mAdvancedMenu = new QMenu (mPopup);
374 mAdvancedMenu->setFont (KGlobalSettings::menuFont ());
375
376 mKeepAboveOpAction = mAdvancedMenu->addAction (i18n ("Keep &Above Others"));
377 mKeepAboveOpAction->setIcon (KIcon ("go-up"));
378 KAction *kaction = qobject_cast<KAction*>
379 (mKeys.action ("Window Above Other Windows"));
380 if (kaction != 0)
381 mKeepAboveOpAction->setShortcut (kaction->globalShortcut ().primary ());
382 mKeepAboveOpAction->setCheckable (true);
383 mKeepAboveOpAction->setData (KDecorationDefines::KeepAboveOp);
384
385 mKeepBelowOpAction = mAdvancedMenu->addAction (i18n ("Keep &Below Others"));
386 mKeepBelowOpAction->setIcon (KIcon ("go-down"));
387 kaction = qobject_cast<KAction*>
388 (mKeys.action ("Window Below Other Windows"));
389 if (kaction != 0)
390 mKeepBelowOpAction->setShortcut (kaction->globalShortcut ().primary ());
391 mKeepBelowOpAction->setCheckable (true);
392 mKeepBelowOpAction->setData (KDecorationDefines::KeepBelowOp);
393
394 mFullScreenOpAction = mAdvancedMenu->addAction (i18n ("&Fullscreen"));
395 mFullScreenOpAction->setIcon (KIcon ("view-fullscreen"));
396 kaction = qobject_cast<KAction*> (mKeys.action ("Window Fullscreen"));
397 if (kaction != 0)
398 mFullScreenOpAction->setShortcut (kaction->globalShortcut ().primary ());
399 mFullScreenOpAction->setCheckable (true);
400 mFullScreenOpAction->setData (KDecorationDefines::FullScreenOp);
401
402 action = mPopup->addMenu (mAdvancedMenu);
403 action->setText (i18n ("Ad&vanced"));
404
405 mOpacityMenu = new QMenu (mPopup);
406 mOpacityMenu->setFont (KGlobalSettings::menuFont ());
407
408 connect (mOpacityMenu, SIGNAL (triggered (QAction*)),
409 SLOT (handleOpacityPopupActivated (QAction*)));
410
411
412 for( unsigned int i = 0; i < sizeof (levels) / sizeof (levels[0]); ++i)
413 {
414 action = mOpacityMenu->addAction
415 (QString::number (levels[i]) + "%");
416 action->setCheckable (true);
417 action->setData (levels[i]);
418 }
419 action = mPopup->addMenu (mOpacityMenu);
420 action->setText (i18n ("&Opacity"));
421
422
423 mDesktopMenu = new QMenu (mPopup);
424 mDesktopMenu->setFont (KGlobalSettings::menuFont ());
425
426 connect (mDesktopMenu, SIGNAL (triggered (QAction*)),
427 SLOT (handleDesktopPopupActivated (QAction*)));
428
429 mDesktopOpAction = mPopup->addMenu (mDesktopMenu);
430 mDesktopOpAction->setText (i18n ("To &Desktop"));
431
432 mMoveOpAction = mPopup->addAction (i18n ("&Move"));
433 mMoveOpAction->setIcon (KIcon ("move"));
434 kaction = qobject_cast<KAction*> (mKeys.action ("Window Move"));
435 if (kaction != 0)
436 mMoveOpAction->setShortcut (kaction->globalShortcut ().primary ());
437 mMoveOpAction->setData (KDecorationDefines::MoveOp);
438
439 mResizeOpAction = mPopup->addAction (i18n ("Re&size"));
440 kaction = qobject_cast<KAction*> (mKeys.action("Window Resize"));
441 if (kaction != 0)
442 mResizeOpAction->setShortcut (kaction->globalShortcut ().primary ());
443 mResizeOpAction->setData (KDecorationDefines::ResizeOp);
444
445 mMinimizeOpAction = mPopup->addAction (i18n ("Mi&nimize"));
446 kaction = qobject_cast<KAction*> (mKeys.action ("Window Minimize"));
447 if (kaction != 0)
448 mMinimizeOpAction->setShortcut (kaction->globalShortcut ().primary ());
449 mMinimizeOpAction->setData (KDecorationDefines::MinimizeOp);
450
451 mMaximizeOpAction = mPopup->addAction (i18n ("Ma&ximize"));
452 kaction = qobject_cast<KAction*> (mKeys.action ("Window Maximize"));
453 if (kaction != 0)
454 mMaximizeOpAction->setShortcut (kaction->globalShortcut ().primary ());
455 mMaximizeOpAction->setCheckable (true);
456 mMaximizeOpAction->setData (KDecorationDefines::MaximizeOp);
457
458 mShadeOpAction = mPopup->addAction (i18n ("Sh&ade"));
459 kaction = qobject_cast<KAction*> (mKeys.action ("Window Shade"));
460 if (kaction != 0)
461 mShadeOpAction->setShortcut (kaction->globalShortcut ().primary ());
462 mShadeOpAction->setCheckable (true);
463 mShadeOpAction->setData (KDecorationDefines::ShadeOp);
464
465 mPopup->addSeparator ();
466
467 mCloseOpAction = mPopup->addAction (i18n("&Close"));
468 mCloseOpAction->setIcon (KIcon ("window-close" ));
469 kaction = qobject_cast<KAction*> (mKeys.action("Window Close"));
470 if (kaction != 0)
471 mCloseOpAction->setShortcut (kaction->globalShortcut ().primary ());
472 mCloseOpAction->setData (KDecorationDefines::CloseOp);
473 }
474
475 QPoint pnt = mDecor->widget ()->mapFromGlobal (pos);
476
477 pnt += QPoint (mGeometry.x () - mBorder.left - mPadding.left,
478 mGeometry.y () - mBorder.top - mPadding.top);
479
480 mPopup->exec (pnt);
481 }
482
483 void
showWindowMenu(const QRect & pos)484 KWD::Window::showWindowMenu (const QRect &pos)
485 {
486 showWindowMenu (pos.bottomLeft ());
487 }
488
489 KWD::Options::MouseCommand
buttonToCommand(Qt::MouseButtons button)490 KWD::Window::buttonToCommand (Qt::MouseButtons button)
491 {
492 Options::MouseCommand com = Options::MouseNothing;
493 bool active = isActive ();
494
495 if (!mSupportTakeFocus)
496 active = true;
497
498 switch (button) {
499 case Qt::LeftButton:
500 com = active ? Decorator::options ()->commandActiveTitlebar1 () :
501 Decorator::options()->commandInactiveTitlebar1 ();
502 break;
503 case Qt::MidButton:
504 com = active ? Decorator::options ()->commandActiveTitlebar2 () :
505 Decorator::options()->commandInactiveTitlebar2 ();
506 break;
507 case Qt::RightButton:
508 com = active ? Decorator::options ()->commandActiveTitlebar3 () :
509 Decorator::options()->commandInactiveTitlebar3 ();
510 default:
511 break;
512 }
513
514 return com;
515 }
516
517 void
processMousePressEvent(QMouseEvent * qme)518 KWD::Window::processMousePressEvent (QMouseEvent *qme)
519 {
520 Options::MouseCommand com = buttonToCommand (qme->button ());
521
522 if (qme->button () == Qt::LeftButton)
523 {
524 // actions where it's not possible to get the matching release event
525 if (com != Options::MouseOperationsMenu &&
526 com != Options::MouseMinimize)
527 {
528 moveWindow (qme);
529 return;
530 }
531 }
532
533 performMouseCommand (com, qme);
534 }
535
536 void
performWindowOperation(WindowOperation wo)537 KWD::Window::performWindowOperation (WindowOperation wo)
538 {
539 switch (wo) {
540 case KDecoration::MaximizeOp:
541 maximize (maximizeMode () == KDecoration::MaximizeFull ?
542 KDecoration::MaximizeRestore : KDecoration::MaximizeFull);
543 break;
544 case KDecoration::HMaximizeOp:
545 maximize (maximizeMode () ^ KDecoration::MaximizeHorizontal);
546 break;
547 case KDecoration::VMaximizeOp:
548 maximize (maximizeMode () ^ KDecoration::MaximizeVertical);
549 break;
550 case KDecoration::MinimizeOp:
551 minimize ();
552 break;
553 case KDecoration::ShadeOp:
554 setShade (!isShade ());
555 break;
556 case KDecoration::CloseOp:
557 closeWindow ();
558 break;
559 case KDecoration::KeepAboveOp:
560 setKeepAbove (!keepAbove ());
561 break;
562 case KDecoration::KeepBelowOp:
563 setKeepBelow (!keepBelow ());
564 break;
565 case KDecoration::FullScreenOp:
566 if (mState & NET::FullScreen)
567 KWindowSystem::clearState (mClientId, NET::FullScreen);
568 else
569 KWindowSystem::setState (mClientId, NET::FullScreen);
570 break;
571 case KDecoration::MoveOp:
572 Decorator::rootInfo ()->moveResizeRequest (mClientId,
573 mGeometry.x () +
574 mGeometry.width () / 2,
575 mGeometry.y () +
576 mGeometry.height () / 2,
577 NET::KeyboardMove);
578 break;
579 case KDecoration::ResizeOp:
580 Decorator::rootInfo ()->moveResizeRequest (mClientId,
581 mGeometry.x () +
582 mGeometry.width () / 2,
583 mGeometry.y () +
584 mGeometry.height () / 2,
585 NET::KeyboardSize);
586 default:
587 break;
588 }
589 }
590
591 bool
isPreview(void) const592 KWD::Window::isPreview (void) const
593 {
594 return false;
595 }
596
597 QRect
geometry(void) const598 KWD::Window::geometry (void) const
599 {
600 QRect rect = mGeometry;
601
602 return QRect (rect.x () - ROOT_OFF_X,
603 rect.y () - ROOT_OFF_Y,
604 rect.width (),
605 rect.height ());
606 }
607
608 QRect
iconGeometry(void) const609 KWD::Window::iconGeometry (void) const
610 {
611 return QRect ();
612 }
613
614 QRect
clientGeometry(void)615 KWD::Window::clientGeometry (void)
616 {
617 return mGeometry;
618
619 QRect frame = geometry ();
620
621 return QRect (frame.x () + mBorder.left,
622 frame.y () + mBorder.top,
623 frame.width () - mBorder.left - mBorder.right,
624 frame.height () - mBorder.top - mBorder.bottom);
625 }
626
627 QRegion
unobscuredRegion(const QRegion & r) const628 KWD::Window::unobscuredRegion (const QRegion & r) const
629 {
630 return r;
631 }
632
633 WId
windowId(void) const634 KWD::Window::windowId (void) const
635 {
636 return mClientId;
637 }
638
639 void
closeWindow(void)640 KWD::Window::closeWindow (void)
641 {
642 Decorator::rootInfo ()->closeWindowRequest (mClientId);
643 }
644
645 void
maximize(MaximizeMode mode)646 KWD::Window::maximize (MaximizeMode mode)
647 {
648 KWindowSystem::setState (mClientId,
649 ((mode & MaximizeVertical) ? NET::MaxVert : 0) |
650 ((mode & MaximizeHorizontal) ? NET::MaxHoriz : 0));
651 KWindowSystem::clearState (mClientId,
652 ((mode & MaximizeVertical) ? 0 : NET::MaxVert) |
653 ((mode & MaximizeHorizontal) ? 0 : NET::MaxHoriz));
654 }
655
656 void
minimize(void)657 KWD::Window::minimize (void)
658 {
659 KWindowSystem::minimizeWindow (mClientId, false);
660 }
661
662 void
showContextHelp(void)663 KWD::Window::showContextHelp (void)
664 {
665 if (mSupportContextHelp)
666 KWD::Decorator::sendClientMessage (mClientId, mClientId,
667 Atoms::wmProtocols,
668 Atoms::netWmContextHelp);
669 }
670
671 void
titlebarDblClickOperation(void)672 KWD::Window::titlebarDblClickOperation (void)
673 {
674 WindowOperation op;
675
676 op = KWD::Decorator::options ()->operationTitlebarDblClick ();
677 performWindowOperation (op);
678 }
679
680 void
setDesktop(int desktop)681 KWD::Window::setDesktop (int desktop)
682 {
683 KWindowSystem::setOnDesktop (mClientId, desktop);
684 }
685
686 void
setKeepBelow(bool set)687 KWD::Window::setKeepBelow (bool set)
688 {
689 if (set)
690 {
691 KWindowSystem::clearState (mClientId, NET::KeepAbove);
692 KWindowSystem::setState (mClientId, NET::KeepBelow);
693 }
694 else
695 {
696 KWindowSystem::clearState (mClientId, NET::KeepBelow);
697 }
698 }
699
700 void
setKeepAbove(bool set)701 KWD::Window::setKeepAbove (bool set)
702 {
703 if (set)
704 {
705 KWindowSystem::clearState (mClientId, NET::KeepBelow);
706 KWindowSystem::setState (mClientId, NET::KeepAbove);
707 }
708 else
709 {
710 KWindowSystem::clearState (mClientId, NET::KeepAbove);
711 }
712 }
713
714 void
setShade(bool set)715 KWD::Window::setShade (bool set)
716 {
717 if (set)
718 KWindowSystem::setState (mClientId, NET::Shaded);
719 else
720 KWindowSystem::clearState (mClientId, NET::Shaded);
721
722 mDecor->shadeChange ();
723 }
724
725 void
titlebarMouseWheelOperation(int delta)726 KWD::Window::titlebarMouseWheelOperation (int delta)
727 {
728 Options::MouseCommand com;
729
730 com = Decorator::options()->operationTitlebarMouseWheel (delta);
731 performMouseCommand (com, 0);
732 }
733
734 int
currentDesktop(void) const735 KWD::Window::currentDesktop (void) const
736 {
737 return KWindowSystem::currentDesktop ();
738 }
739
740 QWidget *
initialParentWidget(void) const741 KWD::Window::initialParentWidget (void) const
742 {
743 return 0;
744 }
745
746 Qt::WFlags
initialWFlags(void) const747 KWD::Window::initialWFlags (void) const
748 {
749 return 0;
750 }
751
752 void
grabXServer(bool)753 KWD::Window::grabXServer (bool)
754 {
755 }
756
757 bool
compositingActive(void) const758 KWD::Window::compositingActive (void) const
759 {
760 return true;
761 }
762
763 #if KDE_IS_VERSION(4,3,90)
764
765 QRect
transparentRect() const766 KWD::Window::transparentRect () const
767 {
768 return QRect ();
769 }
770
771 bool
isClientGroupActive()772 KWD::Window::isClientGroupActive ()
773 {
774 return false;
775 }
776
777 QList<ClientGroupItem>
clientGroupItems() const778 KWD::Window::clientGroupItems () const
779 {
780 QList<ClientGroupItem> items;
781
782 QIcon icon (mIcon);
783 icon.addPixmap (mMiniIcon);
784
785 items.append (ClientGroupItem (mName, icon));
786
787 return items;
788 }
789
790 long
itemId(int index)791 KWD::Window::itemId (int index)
792 {
793 return (long) mClientId;
794 }
795
796 int
visibleClientGroupItem()797 KWD::Window::visibleClientGroupItem ()
798 {
799 return 0;
800 }
801
802 void
setVisibleClientGroupItem(int index)803 KWD::Window::setVisibleClientGroupItem (int index)
804 {
805 }
806
807 void
moveItemInClientGroup(int index,int before)808 KWD::Window::moveItemInClientGroup (int index, int before)
809 {
810 }
811
812 void
moveItemToClientGroup(long itemId,int before)813 KWD::Window::moveItemToClientGroup (long itemId, int before)
814 {
815 }
816
817 void
removeFromClientGroup(int index,const QRect & newGeom)818 KWD::Window::removeFromClientGroup (int index, const QRect& newGeom)
819 {
820 }
821
822 void
closeClientGroupItem(int index)823 KWD::Window::closeClientGroupItem (int index)
824 {
825 closeWindow ();
826 }
827
828 void
closeAllInClientGroup()829 KWD::Window::closeAllInClientGroup ()
830 {
831 closeWindow ();
832 }
833
834 void
displayClientMenu(int index,const QPoint & pos)835 KWD::Window::displayClientMenu (int index, const QPoint& pos)
836 {
837 showWindowMenu (pos);
838 }
839
840 KDecorationDefines::WindowOperation
buttonToWindowOperation(Qt::MouseButtons button)841 KWD::Window::buttonToWindowOperation(Qt::MouseButtons button)
842 {
843 Options::MouseCommand com = buttonToCommand (button);
844
845 if (com == Options::MouseOperationsMenu)
846 return KDecorationDefines::OperationsOp;
847
848 return KDecorationDefines::NoOp;
849 }
850
851 #endif
852
853 void
createDecoration(void)854 KWD::Window::createDecoration (void)
855 {
856 KDecoration *decor;
857
858 if (mDecor)
859 return;
860
861 decor = Decorator::pluginManager ()->createDecoration (this);
862 decor->init ();
863
864 mDecor = decor;
865
866 mDecor->widget ()->installEventFilter (this);
867
868 mPaintRedirector = new KWin::PaintRedirector (mDecor->widget ());
869 connect (mPaintRedirector, SIGNAL (paintPending()),
870 this, SLOT (decorRepaintPending ()));
871
872 mPadding.top = mPadding.bottom = mPadding.left = mPadding.right = 0;
873
874 if (KDecorationUnstable *deco2 = dynamic_cast<KDecorationUnstable*>(decor))
875 deco2->padding (mPadding.left, mPadding.right, mPadding.top, mPadding.bottom);
876
877 XReparentWindow (QX11Info::display(), mDecor->widget ()->winId (), mParentId, 0, 0);
878
879 //decor->widget()->move(-mPadding.left, -mPadding.top);
880
881 if (mType == Normal && mFrame)
882 {
883 KWD::trapXError ();
884 XSelectInput (QX11Info::display(), mFrame,
885 StructureNotifyMask | PropertyChangeMask |
886 ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
887 EnterWindowMask | LeaveWindowMask);
888 if (KWD::popXError ())
889 return;
890 }
891
892 resizeDecoration (true);
893 }
894
895 void
setMask(const QRegion & region,int)896 KWD::Window::setMask (const QRegion ®ion, int)
897 {
898 if (region.isEmpty ())
899 {
900 mShapeSet = false;
901 return;
902 }
903
904 if (mShapeSet && region == mShape)
905 return;
906
907 mShape = region;
908 mShapeSet = true;
909
910 if (mFrame)
911 {
912 QRegion r = region.translated (-mPadding.left, -mPadding.top);
913
914 r -= QRegion (mBorder.left, mBorder.top,
915 mGeometry.width (), mGeometry.height ());
916
917 KWD::trapXError ();
918 XShapeCombineRegion (QX11Info::display(),
919 mFrame,
920 ShapeInput,
921 0,
922 0,
923 r.handle (),
924 ShapeSet);
925 KWD::popXError ();
926 }
927 }
928
929 void
resizeDecoration(bool force)930 KWD::Window::resizeDecoration (bool force)
931 {
932 int w, h;
933
934 mDecor->borders (mBorder.left, mBorder.right, mBorder.top, mBorder.bottom);
935
936 mExtents.left = mBorder.left + mPadding.left;
937 mExtents.right = mBorder.right + mPadding.right;
938 mExtents.top = mBorder.top + mPadding.top;
939 mExtents.bottom = mBorder.bottom + mPadding.bottom;
940
941 if (mType != Normal)
942 {
943 mGeometry = QRect (50, 50, 100, 100);
944 }
945
946 w = mGeometry.width () + mExtents.left + mExtents.right;
947 h = mGeometry.height () + mExtents.top + mExtents.bottom;
948
949 if (!force)
950 {
951 if (w == decorWidget ()->width () && h == decorWidget ()->height ())
952 return;
953 }
954
955 /* reset shape */
956 mShapeSet = false;
957
958 if (mPixmap)
959 {
960 XFreePixmap (QX11Info::display(), mPixmap);
961 mPixmap = None;
962 }
963
964 mDecor->resize (QSize (w, h));
965 mDecor->widget ()->show ();
966 mDecor->widget ()->update ();
967
968 mPixmap = XCreatePixmap (QX11Info::display(),
969 QX11Info::appRootWindow (),
970 qMax (w, mGeometry.height ()),
971 mExtents.top + mExtents.bottom +
972 mExtents.left + mExtents.right, 32);
973
974 mPixmapQt = QPixmap::fromX11Pixmap (mPixmap, QPixmap::ExplicitlyShared);
975
976 mPixmapQt.fill (Qt::transparent);
977
978 mUpdateProperty = true;
979 }
980
981 void
updateBlurProperty(int topOffset,int bottomOffset,int leftOffset,int rightOffset)982 KWD::Window::updateBlurProperty (int topOffset,
983 int bottomOffset,
984 int leftOffset,
985 int rightOffset)
986 {
987 Atom atom = Atoms::compizWindowBlurDecor;
988 QRegion topQRegion, bottomQRegion, leftQRegion, rightQRegion;
989 Region topRegion = NULL;
990 Region bottomRegion = NULL;
991 Region leftRegion = NULL;
992 Region rightRegion = NULL;
993 int size = 0;
994 int w, h;
995
996 w = mGeometry.width () + mBorder.left + mBorder.right;
997 h = mGeometry.height () + mBorder.top + mBorder.bottom;
998
999 if (blurType != BLUR_TYPE_NONE)
1000 {
1001 QRegion r, shape = QRegion (0, 0, w, h);
1002
1003 if (mShapeSet)
1004 shape = mShape.translated (-mPadding.left, -mPadding.top);
1005
1006 r = QRegion (0, 0, w, mBorder.top);
1007 topQRegion = r.intersect (shape);
1008 if (!topQRegion.isEmpty ())
1009 {
1010 topQRegion.translate (-mBorder.left,
1011 -mBorder.top);
1012 topRegion = topQRegion.handle ();
1013 }
1014
1015 if (blurType == BLUR_TYPE_ALL)
1016 {
1017 r = QRegion (0, h - mBorder.bottom,
1018 w, mBorder.bottom);
1019 bottomQRegion = r.intersect (shape);
1020 if (!bottomQRegion.isEmpty ())
1021 {
1022 bottomQRegion.translate (-mBorder.left,
1023 -(h - mBorder.bottom));
1024 bottomRegion = bottomQRegion.handle ();
1025 }
1026
1027 r = QRegion (0, mBorder.top,
1028 mBorder.left, mGeometry.height ());
1029 leftQRegion = r.intersect (shape);
1030 if (!leftQRegion.isEmpty ())
1031 {
1032 leftQRegion.translate (-mBorder.left,
1033 -mBorder.top);
1034 leftRegion = leftQRegion.handle ();
1035 }
1036
1037 r = QRegion (w - mBorder.right, mBorder.top,
1038 mBorder.right, mGeometry.height ());
1039 rightQRegion = r.intersect (shape);
1040 if (!rightQRegion.isEmpty ())
1041 {
1042 rightQRegion.translate (-(w - mBorder.right),
1043 -mBorder.top);
1044 rightRegion = rightQRegion.handle ();
1045 }
1046 }
1047 }
1048
1049 if (topRegion)
1050 size += topRegion->numRects;
1051 if (bottomRegion)
1052 size += bottomRegion->numRects;
1053 if (leftRegion)
1054 size += leftRegion->numRects;
1055 if (rightRegion)
1056 size += rightRegion->numRects;
1057
1058 if (size)
1059 {
1060 long data[size * 6 + 2];
1061
1062 decor_region_to_blur_property (data, 4, 0,
1063 mGeometry.width (),
1064 mGeometry.height (),
1065 topRegion, topOffset,
1066 bottomRegion, bottomOffset,
1067 leftRegion, leftOffset,
1068 rightRegion, rightOffset);
1069
1070 KWD::trapXError ();
1071 XChangeProperty (QX11Info::display(), mClientId, atom,
1072 XA_INTEGER,
1073 32, PropModeReplace, (unsigned char *) data,
1074 2 + size * 6);
1075 KWD::popXError ();
1076 }
1077 else
1078 {
1079 KWD::trapXError ();
1080 XDeleteProperty (QX11Info::display(), mClientId, atom);
1081 KWD::popXError ();
1082 }
1083 }
1084
1085 void
updateProperty(void)1086 KWD::Window::updateProperty (void)
1087 {
1088 Atom atom = Atoms::netWindowDecor;
1089 decor_extents_t maxExtents;
1090 long data[256];
1091 decor_quad_t quads[N_QUADS_MAX];
1092 int nQuad = 0;
1093 int left, right, top, bottom, width, height;
1094 unsigned int saveState;
1095
1096 if (mType == Default)
1097 atom = Atoms::netWindowDecorNormal;
1098 else if (mType == DefaultActive)
1099 atom = Atoms::netWindowDecorActive;
1100
1101 saveState = mState;
1102 mState = NET::MaxVert | NET::MaxHoriz;
1103 mDecor->borders (maxExtents.left, maxExtents.right,
1104 maxExtents.top, maxExtents.bottom);
1105 mState = saveState;
1106 mDecor->borders (mBorder.left, mBorder.right, mBorder.top, mBorder.bottom);
1107
1108 left = mExtents.left;
1109 right = mExtents.right;
1110 top = mExtents.top;
1111 bottom = mExtents.bottom;
1112 width = mGeometry.width ();
1113 height = mGeometry.height ();
1114
1115 if (mType == Normal)
1116 {
1117 decor_quad_t *q = quads;
1118 int n = 0;
1119
1120 int topXOffset = width;
1121 QWidget *widget = mDecor->widget ();
1122 int x;
1123
1124 if (widget)
1125 {
1126 const QList<QObject*> children = widget->children ();
1127
1128 foreach (QObject *obj, children)
1129 {
1130 QWidget *child;
1131
1132 if (!obj->isWidgetType ())
1133 continue;
1134
1135 child = static_cast <QWidget *> (obj);
1136
1137 x = child->x () - mExtents.left - 2;
1138 if (x > width / 2 && x < topXOffset)
1139 topXOffset = x;
1140 }
1141 }
1142
1143 // top quads
1144 n = decor_set_horz_quad_line (q, left, topXOffset, right,
1145 width - topXOffset - 1, -top, 0, GRAVITY_NORTH,
1146 left + right + width, -(width - topXOffset - 1),
1147 GRAVITY_EAST, 0, 0);
1148
1149 q += n; nQuad += n;
1150
1151 // bottom quads
1152 n = decor_set_horz_quad_line (q, left, width / 2, right, (width / 2) - 1, 0,
1153 bottom, GRAVITY_SOUTH, left + right + width,
1154 -((width / 2) - 1), GRAVITY_EAST, 0, top);
1155
1156 q += n; nQuad += n;
1157
1158 // left quads
1159 n = decor_set_vert_quad_row (q, 0, height / 2, 0, (height / 2) - 1, -left, 0,
1160 GRAVITY_WEST, height, -((height / 2) - 1),
1161 GRAVITY_SOUTH, 0, top + bottom, 1);
1162
1163 q += n; nQuad += n;
1164
1165 // right quads
1166 n = decor_set_vert_quad_row (q, 0, height / 2, 0, (height / 2) - 1, 0, right,
1167 GRAVITY_EAST, height, -((height / 2) - 1),
1168 GRAVITY_SOUTH, 0, top + bottom + left, 1);
1169
1170 q += n; nQuad += n;
1171
1172 updateBlurProperty (topXOffset, width / 2, height / 2, height / 2);
1173 }
1174 else
1175 {
1176 decor_quad_t *q = quads;
1177 int n = 0;
1178
1179 // top
1180 n = decor_set_horz_quad_line (q, left, 0, right, 0, -top, 0,
1181 GRAVITY_NORTH, left + right + width,
1182 width / 2, 0, 0, 0);
1183
1184 q += n; nQuad += n;
1185
1186 // bottom
1187 n = decor_set_horz_quad_line (q, left, 0, right, 0, 0, bottom,
1188 GRAVITY_SOUTH, left + right + width,
1189 width / 2, 0, 0, top);
1190
1191 q += n; nQuad += n;
1192
1193 // left
1194 n = decor_set_vert_quad_row (q, 0, 0, 0, 0, -left, 0, GRAVITY_WEST,
1195 height, height / 2, 0, 0, top + bottom, 1);
1196
1197 q += n; nQuad += n;
1198
1199 // right
1200 n = decor_set_vert_quad_row (q, 0, 0, 0, 0, 0, right, GRAVITY_EAST,
1201 height, height / 2, 0, 0, top + bottom + left, 1);
1202
1203 q += n; nQuad += n;
1204 }
1205
1206 decor_quads_to_property (data, mPixmap,
1207 &mBorder, &maxExtents,
1208 1, 0,
1209 quads, nQuad);
1210
1211 KWD::trapXError ();
1212 XChangeProperty (QX11Info::display(), mClientId, atom,
1213 XA_INTEGER,
1214 32, PropModeReplace, (unsigned char *) data,
1215 BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
1216 KWD::popXError ();
1217
1218 mUpdateProperty = false;
1219 }
1220
1221 void
handleActiveChange(void)1222 KWD::Window::handleActiveChange (void)
1223 {
1224 mDecor->activeChange ();
1225 resizeDecoration ();
1226 }
1227
1228 void
updateFrame(WId frame)1229 KWD::Window::updateFrame (WId frame)
1230 {
1231 mFrame = frame;
1232
1233 KWD::trapXError ();
1234 XSelectInput (QX11Info::display(), mFrame,
1235 StructureNotifyMask | PropertyChangeMask |
1236 ButtonPressMask | ButtonReleaseMask | PointerMotionMask |
1237 EnterWindowMask | LeaveWindowMask);
1238 KWD::popXError ();
1239 }
1240
1241 void
updateSelected(WId selectedId)1242 KWD::Window::updateSelected (WId selectedId)
1243 {
1244 mSelectedId = selectedId;
1245
1246 updateName ();
1247 }
1248
1249 void
updateWindowGeometry(void)1250 KWD::Window::updateWindowGeometry (void)
1251 {
1252 KWD::trapXError ();
1253 KWindowInfo wInfo = KWindowSystem::windowInfo (mClientId, NET::WMGeometry);
1254 KWD::popXError ();
1255
1256 if (!wInfo.valid ())
1257 return;
1258
1259 QRect geometry = wInfo.geometry ();
1260 int w, h;
1261
1262 w = mGeometry.width () + mBorder.left + mBorder.right;
1263 h = mGeometry.height () + mBorder.top + mBorder.bottom;
1264
1265 if (mGeometry.width () != geometry.width () ||
1266 mGeometry.height () != geometry.height ())
1267 {
1268 mGeometry = geometry;
1269 resizeDecoration ();
1270 }
1271 else if (mGeometry.x () != geometry.x () ||
1272 mGeometry.y () != geometry.y ())
1273 {
1274 mGeometry = geometry;
1275 }
1276 }
1277
1278 void
reloadDecoration(void)1279 KWD::Window::reloadDecoration (void)
1280 {
1281 delete mDecor;
1282 mDecor = 0;
1283
1284 delete mPaintRedirector;
1285 mPaintRedirector = 0;
1286
1287 mShapeSet = false;
1288
1289 createDecoration ();
1290 }
1291
1292 Cursor
positionToCursor(QPoint pos)1293 KWD::Window::positionToCursor (QPoint pos)
1294 {
1295 switch (mDecor->mousePosition (pos + QPoint (mPadding.left, mPadding.top))) {
1296 case PositionCenter:
1297 return cursors[1][1].cursor;
1298 case PositionLeft:
1299 return cursors[1][0].cursor;
1300 case PositionRight:
1301 return cursors[1][2].cursor;
1302 case PositionTop:
1303 return cursors[0][1].cursor;
1304 case PositionBottom:
1305 return cursors[2][1].cursor;
1306 case PositionTopLeft:
1307 return cursors[0][0].cursor;
1308 case PositionTopRight:
1309 return cursors[0][2].cursor;
1310 case PositionBottomLeft:
1311 return cursors[2][0].cursor;
1312 case PositionBottomRight:
1313 return cursors[2][2].cursor;
1314 default:
1315 break;
1316 }
1317
1318 return cursors[1][1].cursor;
1319 }
1320
1321 void
updateCursor(QPoint pos)1322 KWD::Window::updateCursor (QPoint pos)
1323 {
1324 KWD::trapXError ();
1325 XDefineCursor (QX11Info::display(), mFrame, positionToCursor (pos));
1326 KWD::popXError ();
1327 }
1328
1329 void
getWindowProtocols(void)1330 KWD::Window::getWindowProtocols (void)
1331 {
1332 Atom *p;
1333 int n;
1334 int status;
1335
1336 mSupportTakeFocus = false;
1337 mSupportContextHelp = false;
1338
1339 KWD::trapXError ();
1340 status = XGetWMProtocols (QX11Info::display(), mClientId, &p, &n);
1341 if (KWD::popXError ())
1342 return;
1343
1344 if (status)
1345 {
1346 int i;
1347
1348 for (i = 0; i < n; i++)
1349 {
1350 if (p[i] == Atoms::wmTakeFocus)
1351 mSupportTakeFocus = true;
1352 else if (p[i] == Atoms::netWmContextHelp)
1353 mSupportContextHelp = true;
1354 }
1355
1356 if (n > 0)
1357 XFree (p);
1358 }
1359 }
1360
1361 void
handlePopupActivated(QAction * action)1362 KWD::Window::handlePopupActivated (QAction * action)
1363 {
1364 WindowOperation op = static_cast <WindowOperation> (action->data().toInt());
1365
1366 performWindowOperation (op);
1367 }
1368
1369 void
handleOpacityPopupActivated(QAction * action)1370 KWD::Window::handleOpacityPopupActivated (QAction *action)
1371 {
1372 int op = action->data().toInt();
1373
1374 op = op * 0xffff / 100;
1375
1376 if (op != mOpacity)
1377 Decorator::sendClientMessage (QX11Info::appRootWindow(), mClientId,
1378 Atoms::netWmWindowOpacity,
1379 (op << 16) | op);
1380 }
1381
1382
1383 void
handleDesktopPopupActivated(QAction * action)1384 KWD::Window::handleDesktopPopupActivated (QAction *action)
1385 {
1386
1387 if (action->data().toInt())
1388 setDesktop (action->data().toInt());
1389 else
1390 KWindowSystem::setOnAllDesktops (mClientId, true);
1391 }
1392
1393 void
handlePopupAboutToShow(void)1394 KWD::Window::handlePopupAboutToShow (void)
1395 {
1396 int numberOfDesktops;
1397
1398 numberOfDesktops = KWindowSystem::numberOfDesktops ();
1399 if (numberOfDesktops > 1)
1400 {
1401 NETRootInfo *rootInfo = Decorator::rootInfo ();
1402 QString name;
1403 int i;
1404 int winDesktop = desktop ();
1405 QAction *action;
1406 const int BASE = 10;
1407
1408 mDesktopMenu->clear ();
1409
1410 action = mDesktopMenu->addAction (i18n ("&All Desktops"));
1411 action->setData (0);
1412 action->setCheckable (true);
1413
1414
1415 action->setChecked (winDesktop == NET::OnAllDesktops);
1416 mDesktopMenu->addSeparator ();
1417
1418 for (i = 1; i <= numberOfDesktops; i++)
1419 {
1420 QString basic_name ("%1 %2");
1421 if (i < BASE)
1422 basic_name.prepend ('&');
1423
1424 basic_name = basic_name.arg (i).arg (
1425 QString (rootInfo->desktopName (i)).replace
1426 ('&', "&&"));
1427
1428 action = mDesktopMenu->addAction (basic_name);
1429 action->setData (i);
1430 action->setCheckable (true);
1431 action->setChecked (winDesktop == i);
1432 }
1433
1434 mDesktopOpAction->setVisible (true);
1435 }
1436 else
1437 {
1438 mDesktopOpAction->setVisible (false);
1439 }
1440
1441 mResizeOpAction->setEnabled (isResizable ());
1442 mMoveOpAction->setEnabled (isMovable ());
1443
1444 mMaximizeOpAction->setEnabled (isMaximizable ());
1445 mMaximizeOpAction->setChecked (maximizeMode () == MaximizeFull);
1446
1447 mShadeOpAction->setChecked (isShade ());
1448 mShadeOpAction->setEnabled (isShadeable ());
1449
1450 mKeepAboveOpAction->setChecked (keepAbove ());
1451 mKeepBelowOpAction->setChecked (keepBelow ());
1452 mFullScreenOpAction->setChecked (mState & NET::FullScreen);
1453
1454 mMinimizeOpAction->setEnabled (isMinimizable ());
1455 mCloseOpAction->setEnabled (isCloseable ());
1456
1457 foreach (QAction* action, mOpacityMenu->actions ())
1458 {
1459 if(action->data ().toInt () ==
1460 qRound ((float)mOpacity * 100.0 / 0xffff))
1461 action->setChecked( true );
1462 else
1463 action->setChecked( false );
1464 }
1465
1466 }
1467
1468 void
updateState(void)1469 KWD::Window::updateState (void)
1470 {
1471 KWindowInfo wInfo = KWindowSystem::windowInfo (mClientId, NET::WMState, 0);
1472
1473 unsigned long newState = wInfo.state ();
1474 unsigned long stateChange = mState ^ newState;
1475
1476 mState = newState;
1477
1478 if (stateChange & NET::Max)
1479 {
1480 mDecor->maximizeChange ();
1481 resizeDecoration (false);
1482 }
1483
1484 if (stateChange & NET::KeepAbove && !(mState & NET::KeepAbove))
1485 mDecor->emitKeepAboveChanged (mState & NET::KeepAbove);
1486 if (stateChange & NET::KeepBelow && !(mState & NET::KeepBelow))
1487 mDecor->emitKeepBelowChanged (mState & NET::KeepBelow);
1488 if (stateChange & NET::KeepAbove && mState & NET::KeepAbove)
1489 mDecor->emitKeepAboveChanged (mState & NET::KeepAbove);
1490 if (stateChange & NET::KeepBelow && mState & NET::KeepBelow)
1491 mDecor->emitKeepBelowChanged (mState & NET::KeepBelow);
1492 if (stateChange & NET::Shaded)
1493 mDecor->shadeChange ();
1494 if (stateChange & NET::Sticky)
1495 mDecor->desktopChange ();
1496 }
1497
1498 void
updateName(void)1499 KWD::Window::updateName (void)
1500 {
1501 KWindowInfo wInfo;
1502
1503 wInfo = KWindowSystem::windowInfo (mClientId, NET::WMVisibleName, 0);
1504
1505 mName = wInfo.visibleName ();
1506
1507 mDecor->captionChange ();
1508 }
1509
1510 void
updateIcons(void)1511 KWD::Window::updateIcons (void)
1512 {
1513 mIcon = KWindowSystem::icon (mClientId, 32, 32, true,
1514 KWindowSystem::NETWM |
1515 KWindowSystem::WMHints);
1516
1517 mMiniIcon = KWindowSystem::icon (mClientId, 16, 16, true,
1518 KWindowSystem::NETWM |
1519 KWindowSystem::WMHints);
1520
1521 if (mIcon.isNull ())
1522 {
1523 mIcon = KWindowSystem::icon (mClientId, 32, 32, true,
1524 KWindowSystem::ClassHint |
1525 KWindowSystem::XApp );
1526 mMiniIcon = KWindowSystem::icon (mClientId, 16, 16, true,
1527 KWindowSystem::ClassHint |
1528 KWindowSystem::XApp );
1529 }
1530
1531 mDecor->iconChange ();
1532 }
1533
1534 NET::Direction
positionToDirection(int pos)1535 KWD::Window::positionToDirection (int pos)
1536 {
1537 switch (pos) {
1538 case PositionLeft:
1539 return NET::Left;
1540 case PositionRight:
1541 return NET::Right;
1542 case PositionTop:
1543 return NET::Top;
1544 case PositionBottom:
1545 return NET::Bottom;
1546 case PositionTopLeft:
1547 return NET::TopLeft;
1548 case PositionTopRight:
1549 return NET::TopRight;
1550 case PositionBottomLeft:
1551 return NET::BottomLeft;
1552 case PositionBottomRight:
1553 return NET::BottomRight;
1554 default:
1555 break;
1556 }
1557
1558 return NET::Move;
1559 }
1560
1561 void
moveWindow(QMouseEvent * qme)1562 KWD::Window::moveWindow (QMouseEvent *qme)
1563 {
1564 NET::Direction direction;
1565
1566 direction = positionToDirection (mDecor->mousePosition (qme->pos ()));
1567
1568 QPoint p (mGeometry.x () - mExtents.left, mGeometry.y () - mExtents.top);
1569 p += qme->pos ();
1570
1571 XUngrabPointer (QX11Info::display(), CurrentTime);
1572 XUngrabKeyboard (QX11Info::display(), CurrentTime);
1573
1574 Decorator::rootInfo ()->restackRequest (mClientId, NET::FromApplication,
1575 None, Above,
1576 QX11Info::appTime());
1577
1578 Decorator::rootInfo ()->moveResizeRequest (mClientId,
1579 p.x (),
1580 p.y (),
1581 direction);
1582 mFakeRelease = true;
1583
1584 }
1585
1586 #define OPACITY_STEP (0xffff / 10)
1587
1588 void
performMouseCommand(Options::MouseCommand command,QMouseEvent * qme)1589 KWD::Window::performMouseCommand (Options::MouseCommand command,
1590 QMouseEvent *qme)
1591 {
1592 switch (command) {
1593 case Options::MouseRaise:
1594 KWindowSystem::raiseWindow (mClientId);
1595 break;
1596 case Options::MouseLower:
1597 KWindowSystem::lowerWindow (mClientId);
1598 break;
1599 case Options::MouseShade :
1600 setShade (!isShade ());
1601 break;
1602 case Options::MouseSetShade:
1603 setShade (true);
1604 break;
1605 case Options::MouseUnsetShade:
1606 setShade (false);
1607 break;
1608 case Options::MouseOperationsMenu:
1609 showWindowMenu (mDecor->widget ()->mapToGlobal (qme->pos ()));
1610 break;
1611 case Options::MouseMaximize:
1612 maximize (KDecoration::MaximizeFull);
1613 break;
1614 case Options::MouseRestore:
1615 maximize (KDecoration::MaximizeRestore);
1616 break;
1617 case Options::MouseMinimize:
1618 minimize ();
1619 break;
1620 case Options::MouseAbove:
1621 if (keepBelow ())
1622 setKeepBelow (false);
1623 else
1624 setKeepAbove (true);
1625 break;
1626 case Options::MouseBelow:
1627 if (keepAbove ())
1628 setKeepAbove (false);
1629 else
1630 setKeepBelow (true);
1631 break;
1632 case Options::MousePreviousDesktop:
1633 break;
1634 case Options::MouseNextDesktop:
1635 break;
1636 case Options::MouseOpacityMore:
1637 {
1638 int opacity = mOpacity;
1639
1640 if (opacity < 0xffff)
1641 {
1642 opacity += OPACITY_STEP;
1643 if (opacity > 0xffff)
1644 opacity = 0xffff;
1645
1646 Decorator::sendClientMessage (QX11Info::appRootWindow(),
1647 mClientId,
1648 Atoms::netWmWindowOpacity,
1649 (opacity << 16) | opacity);
1650 }
1651 } break;
1652 case Options::MouseOpacityLess:
1653 {
1654 int opacity = mOpacity;
1655
1656 if (opacity > OPACITY_STEP)
1657 {
1658 opacity -= OPACITY_STEP;
1659 if (opacity < OPACITY_STEP)
1660 opacity = OPACITY_STEP;
1661
1662 Decorator::sendClientMessage (QX11Info::appRootWindow(),
1663 mClientId,
1664 Atoms::netWmWindowOpacity,
1665 (opacity << 16) | opacity);
1666 }
1667 } break;
1668 case Options::MouseActivateRaiseAndMove:
1669 case Options::MouseActivateRaiseAndUnrestrictedMove:
1670 case Options::MouseMove:
1671 case Options::MouseUnrestrictedMove:
1672 case Options::MouseResize:
1673 case Options::MouseUnrestrictedResize:
1674 if (qme)
1675 moveWindow (qme);
1676 case Options::MouseNothing:
1677 default:
1678 break;
1679 }
1680 }
1681
1682 void
showKillProcessDialog(Time timestamp)1683 KWD::Window::showKillProcessDialog (Time timestamp)
1684 {
1685 KWindowInfo kWinInfo =
1686 KWindowSystem::windowInfo (mClientId, 0, NET::WM2WindowClass |
1687 NET::WM2ClientMachine);
1688 NETWinInfo wInfo = NETWinInfo (QX11Info::display(), mClientId,
1689 QX11Info::appRootWindow(), NET::WMPid);
1690 QByteArray clientMachine, resourceClass;
1691 pid_t pid;
1692 char buf[257];
1693
1694 if (mProcessKiller.state () == QProcess::Running)
1695 return;
1696
1697 clientMachine = kWinInfo.clientMachine ();
1698 resourceClass = kWinInfo.windowClassClass ();
1699 pid = wInfo.pid ();
1700
1701 if (gethostname (buf, sizeof (buf) - 1) == 0)
1702 {
1703 if (strcmp (buf, clientMachine) == 0)
1704 clientMachine = "localhost";
1705 }
1706
1707 mProcessKiller.start (KStandardDirs::findExe ("kwin_killer_helper"),
1708 QStringList () << "--pid" << QByteArray ().setNum (pid) <<
1709 "--hostname" << clientMachine <<
1710 "--windowname" << mName.toUtf8 () <<
1711 "--applicationname" << resourceClass <<
1712 "--wid" << QByteArray ().setNum ((unsigned int) mClientId) <<
1713 "--timestamp" << QByteArray ().setNum ((unsigned int) timestamp),
1714 QIODevice::NotOpen);
1715 }
1716
1717 void
hideKillProcessDialog(void)1718 KWD::Window::hideKillProcessDialog (void)
1719 {
1720 if (mProcessKiller.state () == QProcess::Running)
1721 {
1722 mProcessKiller.terminate ();
1723 }
1724 }
1725
1726 void
decorRepaintPending()1727 KWD::Window::decorRepaintPending ()
1728 {
1729 if (!mPaintRedirector || !mPixmap)
1730 return;
1731
1732 QRegion reg = mPaintRedirector->pendingRegion();
1733 if (reg.isEmpty())
1734 return;
1735
1736 QRect bBox = reg.boundingRect();
1737
1738 if (mShapeSet)
1739 reg &= mShape;
1740
1741 int l = mExtents.left;
1742 int r = mExtents.right;
1743 int t = mExtents.top;
1744 int b = mExtents.bottom;
1745 int w = mGeometry.width ();
1746 int h = mGeometry.height ();
1747
1748 QRect top = QRect (0, 0, w + l + r, t);
1749 QRect bottom = QRect (0, t + h, w + l + r, b);
1750 QRect left = QRect (0, t, l, h);
1751 QRect right = QRect (l + w, t, r, h);
1752
1753 QRegion rtop = reg & top;
1754 QRegion rbottom = reg & bottom;
1755 QRegion rleft = reg & left;
1756 QRegion rright = reg & right;
1757
1758 QPixmap p = mPaintRedirector->performPendingPaint();
1759
1760 QPainter pt (&mPixmapQt);
1761 pt.setCompositionMode( QPainter::CompositionMode_Source );
1762
1763 QRect bb, pb;
1764
1765 // Top
1766 if (!rtop.isEmpty ())
1767 {
1768 bb = rtop.boundingRect();
1769 pb = bb;
1770 pb.moveTo (bb.topLeft () - bBox.topLeft ());
1771 pt.resetTransform ();
1772 pt.setClipRegion( reg );
1773 pt.drawPixmap( bb.topLeft(), p, pb );
1774 }
1775
1776 // Bottom
1777 if (!rbottom.isEmpty ())
1778 {
1779 bb = rbottom.boundingRect();
1780 pb = bb;
1781 pb.moveTo (bb.topLeft () - bBox.topLeft ());
1782 pt.resetTransform ();
1783 pt.translate(0, -h);
1784 pt.setClipRegion( reg );
1785 pt.drawPixmap( bb.topLeft(), p, pb );
1786 }
1787
1788 // Left
1789 if (!rleft.isEmpty ())
1790 {
1791 bb = rleft.boundingRect();
1792 pb = bb;
1793 pb.moveTo (bb.topLeft () - bBox.topLeft ());
1794 pt.resetTransform ();
1795 pt.translate(0, t + b);
1796 pt.rotate (90);
1797 pt.scale (1.0, -1.0);
1798 pt.translate(0, -t);
1799 pt.setClipRegion( reg );
1800 pt.drawPixmap( bb.topLeft(), p, pb );
1801 }
1802
1803 // Right
1804 if (!rright.isEmpty ())
1805 {
1806 bb = rright.boundingRect();
1807 pb = bb;
1808 pb.moveTo (bb.topLeft () - bBox.topLeft ());
1809 pt.resetTransform ();
1810 pt.translate(0, t + b + l);
1811 pt.rotate (90);
1812 pt.scale (1.0, -1.0);
1813 pt.translate(- (l + w), -t);
1814 pt.setClipRegion( reg );
1815 pt.drawPixmap( bb.topLeft(), p, pb );
1816 }
1817
1818
1819
1820 if (mUpdateProperty)
1821 updateProperty ();
1822 }
1823
1824 QWidget *
decorWidget(void) const1825 KWD::Window::decorWidget (void) const
1826 {
1827 if (!mDecor)
1828 return 0;
1829 return mDecor->widget ();
1830 }
1831
1832 QWidget *
childAt(int x,int y) const1833 KWD::Window::childAt (int x, int y) const
1834 {
1835 if (!mDecor)
1836 return 0;
1837
1838 QWidget *child = mDecor->widget ()->childAt (x + mPadding.left, y + mPadding.top);
1839 return (child)? child : decorWidget ();
1840 }
1841
1842 QPoint
mapToChildAt(QPoint p) const1843 KWD::Window::mapToChildAt (QPoint p) const
1844 {
1845 if (!mDecor)
1846 return p;
1847 if (childAt (p.x (), p.y ()) == decorWidget ())
1848 return p + QPoint (mPadding.left, mPadding.right);
1849 return childAt (p.x (), p.y ())->mapFrom (decorWidget (), p + QPoint (mPadding.left, mPadding.right));
1850 }
1851
1852 bool
eventFilter(QObject * o,QEvent * e)1853 KWD::Window::eventFilter (QObject* o, QEvent* e)
1854 {
1855 if (mDecor == NULL || o != mDecor->widget ())
1856 return false;
1857 if (e->type() == QEvent::Resize)
1858 {
1859 QResizeEvent* ev = static_cast<QResizeEvent*> (e);
1860 // Filter out resize events that inform about size different than frame size.
1861 // This will ensure that mDecor->width() etc. and mDecor->widget()->width() will be in sync.
1862 // These events only seem to be delayed events from initial resizing before show() was called
1863 // on the decoration widget.
1864 if (ev->size () != (mGeometry.size () + QSize (mExtents.left + mExtents.right,
1865 mExtents.top + mExtents.bottom)))
1866 {
1867 int w = mGeometry.width () + mExtents.left + mExtents.right;
1868 int h = mGeometry.height () + mExtents.top + mExtents.bottom;
1869
1870 mDecor->resize (QSize (w, h));
1871 return true;
1872 }
1873 // HACK: Avoid decoration redraw delays. On resize Qt sets WA_WStateConfigPending
1874 // which delays all painting until a matching ConfigureNotify event comes.
1875 // But this process itself is the window manager, so it's not needed
1876 // to wait for that event, the geometry is known.
1877 // Note that if Qt in the future changes how this flag is handled and what it
1878 // triggers then this may potentionally break things. See mainly QETWidget::translateConfigEvent().
1879 mDecor->widget()->setAttribute( Qt::WA_WState_ConfigPending, false );
1880 mDecor->widget()->update();
1881 return false;
1882 }
1883 return false;
1884 }
1885