KWin
Loading...
Searching...
No Matches
snaphelper.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 Lucas Murray <lmurray@undefinedfire.com>
6 SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
7
8 SPDX-License-Identifier: GPL-2.0-or-later
9*/
10
11#include "snaphelper.h"
12
13#include "core/rendertarget.h"
14#include "core/renderviewport.h"
16#include "opengl/glutils.h"
17
18#include <QPainter>
19
20namespace KWin
21{
22
23static const int s_lineWidth = 4;
24static const QColor s_lineColor = QColor(128, 128, 128, 128);
25
26static QRegion computeDirtyRegion(const QRectF &windowRect)
27{
28 const QMargins outlineMargins(
29 s_lineWidth / 2,
30 s_lineWidth / 2,
31 s_lineWidth / 2,
32 s_lineWidth / 2);
33
34 QRegion dirtyRegion;
35
36 const QList<Output *> screens = effects->screens();
37 for (Output *screen : screens) {
38 const QRectF screenRect = effects->clientArea(ScreenArea, screen, effects->currentDesktop());
39
40 QRectF screenWindowRect = windowRect;
41 screenWindowRect.moveCenter(screenRect.center());
42
43 QRectF verticalBarRect(0, 0, s_lineWidth, screenRect.height());
44 verticalBarRect.moveCenter(screenRect.center());
45 verticalBarRect.adjust(-1, -1, 1, 1);
46 dirtyRegion += verticalBarRect.toAlignedRect();
47
48 QRectF horizontalBarRect(0, 0, screenRect.width(), s_lineWidth);
49 horizontalBarRect.moveCenter(screenRect.center());
50 horizontalBarRect.adjust(-1, -1, 1, 1);
51 dirtyRegion += horizontalBarRect.toAlignedRect();
52
53 const QRectF outlineOuterRect = screenWindowRect
54 .marginsAdded(outlineMargins)
55 .adjusted(-1, -1, 1, 1);
56 const QRectF outlineInnerRect = screenWindowRect
57 .marginsRemoved(outlineMargins)
58 .adjusted(1, 1, -1, -1);
59 dirtyRegion += QRegion(outlineOuterRect.toRect()) - QRegion(outlineInnerRect.toRect());
60 }
61
62 return dirtyRegion;
63}
64
66{
68
69 connect(effects, &EffectsHandler::windowAdded, this, &SnapHelperEffect::slotWindowAdded);
70 connect(effects, &EffectsHandler::windowClosed, this, &SnapHelperEffect::slotWindowClosed);
71
72 const auto windows = effects->stackingOrder();
73 for (EffectWindow *window : windows) {
74 slotWindowAdded(window);
75 }
76}
77
81
82void SnapHelperEffect::reconfigure(ReconfigureFlags flags)
83{
84 m_animation.timeLine.setDuration(
85 std::chrono::milliseconds(static_cast<int>(animationTime(250))));
86}
87
88void SnapHelperEffect::prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime)
89{
90 if (m_animation.active) {
91 m_animation.timeLine.advance(presentTime);
92 }
93
94 effects->prePaintScreen(data, presentTime);
95}
96
97void SnapHelperEffect::paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion &region, Output *screen)
98{
99 effects->paintScreen(renderTarget, viewport, mask, region, screen);
100
101 const qreal opacityFactor = m_animation.active
102 ? m_animation.timeLine.value()
103 : 1.0;
104 const QList<Output *> screens = effects->screens();
105
106 const auto scale = viewport.scale();
107
108 // Display the guide
111 vbo->reset();
114 binder.shader()->setColorspaceUniformsFromSRGB(renderTarget.colorDescription());
115 glEnable(GL_BLEND);
116 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
117
118 QColor color = s_lineColor;
119 color.setAlphaF(color.alphaF() * opacityFactor);
121
122 glLineWidth(s_lineWidth);
123 QList<QVector2D> verts;
124 verts.reserve(screens.count() * 24);
125 for (Output *screen : screens) {
126 const QRectF rect = effects->clientArea(ScreenArea, screen, effects->currentDesktop());
127 const int midX = rect.x() + rect.width() / 2;
128 const int midY = rect.y() + rect.height() / 2;
129 const int halfWidth = m_geometry.width() / 2;
130 const int halfHeight = m_geometry.height() / 2;
131
132 // Center vertical line.
133 verts.push_back(QVector2D((rect.x() + rect.width() / 2) * scale, rect.y() * scale));
134 verts.push_back(QVector2D((rect.x() + rect.width() / 2) * scale, (rect.y() + rect.height()) * scale));
135
136 // Center horizontal line.
137 verts.push_back(QVector2D(rect.x() * scale, (rect.y() + rect.height() / 2) * scale));
138 verts.push_back(QVector2D((rect.x() + rect.width()) * scale, (rect.y() + rect.height() / 2) * scale));
139
140 // Top edge of the window outline.
141 verts.push_back(QVector2D((midX - halfWidth - s_lineWidth / 2) * scale, (midY - halfHeight) * scale));
142 verts.push_back(QVector2D((midX + halfWidth + s_lineWidth / 2) * scale, (midY - halfHeight) * scale));
143
144 // Right edge of the window outline.
145 verts.push_back(QVector2D((midX + halfWidth) * scale, (midY - halfHeight + s_lineWidth / 2) * scale));
146 verts.push_back(QVector2D((midX + halfWidth) * scale, (midY + halfHeight - s_lineWidth / 2) * scale));
147
148 // Bottom edge of the window outline.
149 verts.push_back(QVector2D((midX + halfWidth + s_lineWidth / 2) * scale, (midY + halfHeight) * scale));
150 verts.push_back(QVector2D((midX - halfWidth - s_lineWidth / 2) * scale, (midY + halfHeight) * scale));
151
152 // Left edge of the window outline.
153 verts.push_back(QVector2D((midX - halfWidth) * scale, (midY + halfHeight - s_lineWidth / 2) * scale));
154 verts.push_back(QVector2D((midX - halfWidth) * scale, (midY - halfHeight + s_lineWidth / 2) * scale));
155 }
156 vbo->setVertices(verts);
157 vbo->render(GL_LINES);
158
159 glDisable(GL_BLEND);
160 glLineWidth(1.0);
162 QPainter *painter = effects->scenePainter();
163 painter->save();
164 QColor color = s_lineColor;
165 color.setAlphaF(color.alphaF() * opacityFactor);
166 QPen pen(color);
167 pen.setWidth(s_lineWidth);
168 painter->setPen(pen);
169 painter->setBrush(Qt::NoBrush);
170
171 for (Output *screen : screens) {
172 const QRectF rect = effects->clientArea(ScreenArea, screen, effects->currentDesktop());
173 // Center lines.
174 painter->drawLine(rect.center().x(), rect.y(), rect.center().x(), rect.y() + rect.height());
175 painter->drawLine(rect.x(), rect.center().y(), rect.x() + rect.width(), rect.center().y());
176
177 // Window outline.
178 QRectF outlineRect(0, 0, m_geometry.width(), m_geometry.height());
179 outlineRect.moveCenter(rect.center());
180 painter->drawRect(outlineRect);
181 }
182 painter->restore();
183 }
184}
185
187{
188 if (m_animation.active) {
189 effects->addRepaint(computeDirtyRegion(m_geometry));
190 }
191
192 if (m_animation.timeLine.done()) {
193 m_animation.active = false;
194 }
195
197}
198
199void SnapHelperEffect::slotWindowAdded(EffectWindow *w)
200{
201 connect(w, &EffectWindow::windowStartUserMovedResized, this, &SnapHelperEffect::slotWindowStartUserMovedResized);
202 connect(w, &EffectWindow::windowFinishUserMovedResized, this, &SnapHelperEffect::slotWindowFinishUserMovedResized);
203 connect(w, &EffectWindow::windowFrameGeometryChanged, this, &SnapHelperEffect::slotWindowFrameGeometryChanged);
204}
205
206void SnapHelperEffect::slotWindowClosed(EffectWindow *w)
207{
208 if (w != m_window) {
209 return;
210 }
211
212 m_window = nullptr;
213
214 m_animation.active = true;
215 m_animation.timeLine.setDirection(TimeLine::Backward);
216
217 if (m_animation.timeLine.done()) {
218 m_animation.timeLine.reset();
219 }
220
221 effects->addRepaint(computeDirtyRegion(m_geometry));
222}
223
224void SnapHelperEffect::slotWindowStartUserMovedResized(EffectWindow *w)
225{
226 if (!w->isMovable()) {
227 return;
228 }
229
230 m_window = w;
231 m_geometry = w->frameGeometry();
232
233 m_animation.active = true;
234 m_animation.timeLine.setDirection(TimeLine::Forward);
235
236 if (m_animation.timeLine.done()) {
237 m_animation.timeLine.reset();
238 }
239
240 effects->addRepaint(computeDirtyRegion(m_geometry));
241}
242
243void SnapHelperEffect::slotWindowFinishUserMovedResized(EffectWindow *w)
244{
245 if (w != m_window) {
246 return;
247 }
248
249 m_window = nullptr;
250 m_geometry = w->frameGeometry();
251
252 m_animation.active = true;
253 m_animation.timeLine.setDirection(TimeLine::Backward);
254
255 if (m_animation.timeLine.done()) {
256 m_animation.timeLine.reset();
257 }
258
259 effects->addRepaint(computeDirtyRegion(m_geometry));
260}
261
262void SnapHelperEffect::slotWindowFrameGeometryChanged(EffectWindow *w, const QRectF &old)
263{
264 if (w != m_window) {
265 return;
266 }
267
268 m_geometry = w->frameGeometry();
269
270 effects->addRepaint(computeDirtyRegion(old));
271}
272
274{
275 return m_window != nullptr || m_animation.active;
276}
277
278} // namespace KWin
279
280#include "moc_snaphelper.cpp"
Representation of a window used by/for Effect classes.
void windowStartUserMovedResized(KWin::EffectWindow *w)
void windowFrameGeometryChanged(KWin::EffectWindow *window, const QRectF &oldGeometry)
void windowFinishUserMovedResized(KWin::EffectWindow *w)
void windowClosed(KWin::EffectWindow *w)
void paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion &region, Output *screen)
QList< EffectWindow * > stackingOrder
Q_SCRIPTABLE void addRepaint(const QRectF &r)
CompositingType compositingType
KWin::VirtualDesktop * currentDesktop
void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime)
QList< Output * > screens() const
bool isOpenGLCompositing() const
Whether the Compositor is OpenGL based (either GL 1 or 2).
QRectF clientArea(clientAreaOption, const Output *screen, const VirtualDesktop *desktop) const
void windowAdded(KWin::EffectWindow *w)
QPainter * scenePainter()
Provides access to the QPainter which is rendering to the back buffer.
bool setColorspaceUniformsFromSRGB(const ColorDescription &dst)
Definition glshader.cpp:457
bool setUniform(const char *name, float value)
Definition glshader.cpp:301
Vertex Buffer Object.
static GLVertexBuffer * streamingBuffer()
void render(GLenum primitiveMode)
void setVertices(const T &range)
const ColorDescription & colorDescription() const
QMatrix4x4 projectionMatrix() const
void prePaintScreen(ScreenPrePaintData &data, std::chrono::milliseconds presentTime) override
void reconfigure(ReconfigureFlags flags) override
bool isActive() const override
void postPaintScreen() override
~SnapHelperEffect() override
void paintScreen(const RenderTarget &renderTarget, const RenderViewport &viewport, int mask, const QRegion &region, Output *screen) override
qreal value() const
Definition timeline.cpp:46
void advance(std::chrono::milliseconds timestamp)
Definition timeline.cpp:53
void setDuration(std::chrono::milliseconds duration)
Definition timeline.cpp:103
void setDirection(Direction direction)
Definition timeline.cpp:122
static double animationTime(const KConfigGroup &cfg, const QString &key, int defaultTime)
Definition effect.cpp:483
@ ReconfigureAll
Definition effect.h:601
@ ScreenArea
Definition globals.h:57
@ QPainterCompositing
Definition globals.h:39
EffectsHandler * effects