KWin
Loading...
Searching...
No Matches
slideback.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2009 Michael Zanetti <michael_zanetti@gmx.net>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9
10#include "slideback.h"
12
13namespace KWin
14{
15
31
33{
34 if (effects->activeFullScreenEffect() || m_tabboxActive) {
35 oldStackingOrder = effects->stackingOrder();
36 usableOldStackingOrder = usableWindows(oldStackingOrder);
37 return;
38 }
39
40 QList<EffectWindow *> newStackingOrder = effects->stackingOrder(),
41 usableNewStackingOrder = usableWindows(newStackingOrder);
42 if (usableNewStackingOrder == usableOldStackingOrder || usableNewStackingOrder.isEmpty()) {
43 oldStackingOrder = newStackingOrder;
44 usableOldStackingOrder = usableNewStackingOrder;
45 return;
46 }
47
48 m_upmostWindow = usableNewStackingOrder.last();
49
50 if (m_upmostWindow == m_justMapped) { // a window was added, got on top, stacking changed. Nothing impressive
51 m_justMapped = nullptr;
52 } else if (!usableOldStackingOrder.isEmpty() && m_upmostWindow != usableOldStackingOrder.last()) {
53 windowRaised(m_upmostWindow);
54 }
55
56 oldStackingOrder = newStackingOrder;
57 usableOldStackingOrder = usableNewStackingOrder;
58}
59
60void SlideBackEffect::windowRaised(EffectWindow *w)
61{
62 // Determine all windows on top of the activated one
63 bool currentFound = false;
64 for (EffectWindow *tmp : std::as_const(oldStackingOrder)) {
65 if (!currentFound) {
66 if (tmp == w) {
67 currentFound = true;
68 }
69 } else {
70 if (isWindowUsable(tmp) && tmp->isOnCurrentDesktop() && w->isOnCurrentDesktop()) {
71 // Do we have to move it?
72 if (intersects(w, tmp->frameGeometry().toRect())) {
73 QRect slideRect;
74 slideRect = getSlideDestination(getModalGroupGeometry(w), tmp->frameGeometry().toRect());
75 effects->setElevatedWindow(tmp, true);
76 elevatedList.append(tmp);
77 motionManager.manage(tmp);
78 motionManager.moveWindow(tmp, slideRect);
79 destinationList.insert(tmp, slideRect);
80 coveringWindows.append(tmp);
81 } else {
82 // Does it intersect with a moved (elevated) window and do we have to elevate it too?
83 for (EffectWindow *elevatedWindow : std::as_const(elevatedList)) {
84 if (tmp->frameGeometry().intersects(elevatedWindow->frameGeometry())) {
85 effects->setElevatedWindow(tmp, true);
86 elevatedList.append(tmp);
87 break;
88 }
89 }
90 }
91 }
92 if (tmp->isDock() || tmp->keepAbove()) {
93 effects->setElevatedWindow(tmp, true);
94 elevatedList.append(tmp);
95 }
96 }
97 }
98 // If a window is minimized it could happen that the panels stay elevated without any windows sliding.
99 // clear all elevation settings
100 if (!motionManager.managingWindows()) {
101 for (EffectWindow *tmp : std::as_const(elevatedList)) {
102 effects->setElevatedWindow(tmp, false);
103 }
104 }
105}
106
107QRect SlideBackEffect::getSlideDestination(const QRect &windowUnderGeometry, const QRect &windowOverGeometry)
108{
109 // Determine the shortest way:
110 int leftSlide = windowUnderGeometry.left() - windowOverGeometry.right() - 20;
111 int rightSlide = windowUnderGeometry.right() - windowOverGeometry.left() + 20;
112 int upSlide = windowUnderGeometry.top() - windowOverGeometry.bottom() - 20;
113 int downSlide = windowUnderGeometry.bottom() - windowOverGeometry.top() + 20;
114
115 int horizSlide = leftSlide;
116 if (std::abs(horizSlide) > std::abs(rightSlide)) {
117 horizSlide = rightSlide;
118 }
119 int vertSlide = upSlide;
120 if (std::abs(vertSlide) > std::abs(downSlide)) {
121 vertSlide = downSlide;
122 }
123
124 QRect slideRect = windowOverGeometry;
125 if (std::abs(horizSlide) < std::abs(vertSlide)) {
126 slideRect.moveLeft(slideRect.x() + horizSlide);
127 } else {
128 slideRect.moveTop(slideRect.y() + vertSlide);
129 }
130 return slideRect;
131}
132
133void SlideBackEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime)
134{
135 int time = 0;
136 if (m_lastPresentTime.count()) {
137 time = (presentTime - m_lastPresentTime).count();
138 }
139 m_lastPresentTime = presentTime;
140
141 if (motionManager.managingWindows()) {
142 motionManager.calculate(time);
144 }
145
146 const QList<EffectWindow *> windows = effects->stackingOrder();
147 for (auto *w : windows) {
148 w->setData(WindowForceBlurRole, QVariant(true));
149 }
150
151 effects->prePaintScreen(data, presentTime);
152}
153
155{
156 if (motionManager.areWindowsMoving()) {
158 }
159
160 for (auto &w : effects->stackingOrder()) {
161 w->setData(WindowForceBlurRole, QVariant());
162 }
163
165}
166
167void SlideBackEffect::prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime)
168{
169 if (motionManager.isManaging(w)) {
170 data.setTransformed();
171 }
172
173 effects->prePaintWindow(w, data, presentTime);
174}
175
176void SlideBackEffect::paintWindow(const RenderTarget &renderTarget, const RenderViewport &viewport, EffectWindow *w, int mask, QRegion region, WindowPaintData &data)
177{
178 if (motionManager.isManaging(w)) {
179 motionManager.apply(w, data);
180 }
181 for (const QRegion &r : std::as_const(clippedRegions)) {
182 region = region.intersected(r);
183 }
184 effects->paintWindow(renderTarget, viewport, w, mask, region, data);
185 clippedRegions.clear();
186}
187
189{
190 if (motionManager.isManaging(w)) {
191 if (destinationList.contains(w)) {
192 if (!motionManager.isWindowMoving(w)) { // has window reched its destination?
193 // If we are still intersecting with the upmostWindow it is moving. slide to somewhere else
194 // restore the stacking order of all windows not intersecting any more except panels
195 if (coveringWindows.contains(w)) {
196 QList<EffectWindow *> tmpList;
197 for (EffectWindow *tmp : std::as_const(elevatedList)) {
198 QRect elevatedGeometry = tmp->frameGeometry().toRect();
199 if (motionManager.isManaging(tmp)) {
200 elevatedGeometry = motionManager.transformedGeometry(tmp).toAlignedRect();
201 }
202 if (m_upmostWindow && !tmp->isDock() && !tmp->keepAbove() && m_upmostWindow->frameGeometry().intersects(elevatedGeometry)) {
203 QRect newDestination;
204 newDestination = getSlideDestination(getModalGroupGeometry(m_upmostWindow), elevatedGeometry);
205 if (!motionManager.isManaging(tmp)) {
206 motionManager.manage(tmp);
207 }
208 motionManager.moveWindow(tmp, newDestination);
209 destinationList[tmp] = newDestination;
210 } else {
211 if (!tmp->isDock()) {
212 bool keepElevated = false;
213 for (EffectWindow *elevatedWindow : std::as_const(tmpList)) {
214 if (tmp->frameGeometry().intersects(elevatedWindow->frameGeometry())) {
215 keepElevated = true;
216 }
217 }
218 if (!keepElevated) {
219 effects->setElevatedWindow(tmp, false);
220 elevatedList.removeAll(tmp);
221 }
222 }
223 }
224 tmpList.append(tmp);
225 }
226 } else {
227 // Move the window back where it belongs
228 motionManager.moveWindow(w, w->frameGeometry().toRect());
229 destinationList.remove(w);
230 }
231 }
232 } else {
233 // is window back at its original position?
234 if (!motionManager.isWindowMoving(w)) {
235 motionManager.unmanage(w);
237 }
238 }
239 if (coveringWindows.contains(w)) {
240 // It could happen that there is no aciveWindow() here if the user clicks the close-button on an inactive window.
241 // Just skip... the window will be removed in windowDeleted() later
242 if (m_upmostWindow && !intersects(m_upmostWindow, motionManager.transformedGeometry(w).toAlignedRect())) {
243 coveringWindows.removeAll(w);
244 if (coveringWindows.isEmpty()) {
245 // Restore correct stacking order
246 for (EffectWindow *tmp : std::as_const(elevatedList)) {
247 effects->setElevatedWindow(tmp, false);
248 }
249 elevatedList.clear();
250 }
251 }
252 }
253 }
254 if (!isActive()) {
255 m_lastPresentTime = std::chrono::milliseconds::zero();
256 }
258}
259
261{
262 if (w == m_upmostWindow) {
263 m_upmostWindow = nullptr;
264 }
265 if (w == m_justMapped) {
266 m_justMapped = nullptr;
267 }
268 usableOldStackingOrder.removeAll(w);
269 oldStackingOrder.removeAll(w);
270 coveringWindows.removeAll(w);
271 elevatedList.removeAll(w);
272 if (motionManager.isManaging(w)) {
273 motionManager.unmanage(w);
274 }
275}
276
278{
279 m_justMapped = w;
280
281 connect(w, &EffectWindow::minimizedChanged, this, [this, w]() {
282 if (!w->isMinimized()) {
283 slotWindowUnminimized(w);
284 }
285 });
286}
287
289{
290 // SlideBack should not be triggered on an unminimized window. For this we need to store the last unminimized window.
291 m_justMapped = w;
292 // the stackingOrderChanged() signal came before the window turned an effect window
293 // usually this is no problem as the change shall not be caught anyway, but
294 // the window may have changed its stack position, bug #353745
296}
297
299{
300 ++m_tabboxActive;
301}
302
304{
305 m_tabboxActive = std::max(m_tabboxActive - 1, 0);
306}
307
308bool SlideBackEffect::isWindowUsable(EffectWindow *w)
309{
310 return w && (w->isNormalWindow() || w->isDialog()) && !w->keepAbove() && !w->isDeleted() && !w->isMinimized();
311}
312
313bool SlideBackEffect::intersects(EffectWindow *windowUnder, const QRect &windowOverGeometry)
314{
315 QRect windowUnderGeometry = getModalGroupGeometry(windowUnder);
316 return windowUnderGeometry.intersects(windowOverGeometry);
317}
318
319QList<EffectWindow *> SlideBackEffect::usableWindows(const QList<EffectWindow *> &allWindows)
320{
321 QList<EffectWindow *> retList;
322 auto isWindowVisible = [](const EffectWindow *window) {
323 return window && effects->virtualScreenGeometry().intersects(window->frameGeometry().toAlignedRect());
324 };
325 for (EffectWindow *tmp : std::as_const(allWindows)) {
326 if (isWindowUsable(tmp) && isWindowVisible(tmp)) {
327 retList.append(tmp);
328 }
329 }
330 return retList;
331}
332
333QRect SlideBackEffect::getModalGroupGeometry(EffectWindow *w)
334{
335 QRect modalGroupGeometry = w->frameGeometry().toRect();
336 if (w->isModal()) {
337 const auto mainWindows = w->mainWindows();
338 for (EffectWindow *modalWindow : mainWindows) {
339 modalGroupGeometry = modalGroupGeometry.united(getModalGroupGeometry(modalWindow));
340 }
341 }
342 return modalGroupGeometry;
343}
344
346{
347 return motionManager.managingWindows();
348}
349
350} // Namespace
351
352#include "moc_slideback.cpp"
Representation of a window used by/for Effect classes.
bool isMinimized() const
void minimizedChanged(KWin::EffectWindow *w)
bool isNormalWindow() const
bool isOnCurrentDesktop() const
bool isDock() const
Q_SCRIPTABLE void setData(int role, const QVariant &data)
bool isDialog() const
QRectF frameGeometry() const
bool isDeleted() const
void windowDeleted(KWin::EffectWindow *w)
QList< EffectWindow * > stackingOrder
Q_SCRIPTABLE void setElevatedWindow(KWin::EffectWindow *w, bool set)
void paintWindow(const RenderTarget &renderTarget, const RenderViewport &viewport, EffectWindow *w, int mask, const QRegion &region, WindowPaintData &data)
void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime)
void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime)
void windowAdded(KWin::EffectWindow *w)
Q_SCRIPTABLE void addRepaintFull()
Effect * activeFullScreenEffect() const
void postPaintWindow(EffectWindow *w)
void tabBoxAdded(int mode)
void postPaintScreen() override
void prePaintWindow(EffectWindow *w, WindowPrePaintData &data, std::chrono::milliseconds presentTime) override
bool isActive() const override
void postPaintWindow(EffectWindow *w) override
void slotStackingOrderChanged()
Definition slideback.cpp:32
void slotWindowUnminimized(KWin::EffectWindow *w)
void slotWindowAdded(KWin::EffectWindow *w)
void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override
void paintWindow(const RenderTarget &renderTarget, const RenderViewport &viewport, EffectWindow *w, int mask, QRegion region, WindowPaintData &data) override
void slotWindowDeleted(KWin::EffectWindow *w)
void unmanage(EffectWindow *w)
bool isWindowMoving(EffectWindow *w) const
void manage(EffectWindow *w)
void apply(EffectWindow *w, WindowPaintData &data)
void moveWindow(EffectWindow *w, QPoint target, double scale=1.0, double yScale=0.0)
QRectF transformedGeometry(EffectWindow *w) const
bool isManaging(EffectWindow *w) const
@ PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS
Definition effect.h:567
@ WindowForceBlurRole
For fullscreen effects to enforce blurring of windows,.
EffectsHandler * effects