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 &region, 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