KWin
Loading...
Searching...
No Matches
tile.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: 2022 Marco Martin <mart@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9
10#include "tile.h"
11#include "core/output.h"
12#include "tilemanager.h"
13#include "virtualdesktops.h"
14#include "window.h"
15#include "workspace.h"
16
17#include <cmath>
18
19namespace KWin
20{
21
22QSizeF Tile::s_minimumSize = QSizeF(0.15, 0.15);
23
24Tile::Tile(TileManager *tiling, Tile *parent)
25 : QObject(parent)
26 , m_parentTile(parent)
27 , m_tiling(tiling)
28{
29 if (m_parentTile) {
30 m_padding = m_parentTile->padding();
31 }
33}
34
36{
37 for (auto *t : std::as_const(m_children)) {
38 // Prevents access upon child tiles destruction
39 t->m_parentTile = nullptr;
40 }
41 if (m_parentTile) {
42 m_parentTile->removeChild(this);
43 }
44 for (auto *w : std::as_const(m_windows)) {
45 Tile *tile = m_tiling->bestTileForPosition(w->moveResizeGeometry().center());
46 w->setTile(tile);
47 }
48}
49
51{
52 if (!m_parentTile) {
53 return false;
54 }
55
56 switch (gravity) {
57 case Gravity::Left:
58 return m_relativeGeometry.left() > 0.0;
59 case Gravity::Top:
60 return m_relativeGeometry.top() > 0.0;
61 case Gravity::Right:
62 return m_relativeGeometry.right() < 1.0;
63 case Gravity::Bottom:
64 return m_relativeGeometry.bottom() < 1.0;
66 return m_relativeGeometry.top() > 0.0 && m_relativeGeometry.left() > 0.0;
68 return m_relativeGeometry.top() > 0.0 && m_relativeGeometry.right() < 1.0;
70 return m_relativeGeometry.bottom() < 1.0 && m_relativeGeometry.left() > 0.0;
72 return m_relativeGeometry.bottom() < 1.0 && m_relativeGeometry.right() < 1.0;
73 case Gravity::None:
74 default:
75 return false;
76 }
77}
78
79void Tile::setGeometryFromWindow(const QRectF &geom)
80{
81 setGeometryFromAbsolute(geom + QMarginsF(m_padding, m_padding, m_padding, m_padding));
82}
83
84void Tile::setGeometryFromAbsolute(const QRectF &geom)
85{
86 const QRectF outGeom = m_tiling->output()->geometryF();
87 const QRectF relGeom((geom.x() - outGeom.x()) / outGeom.width(),
88 (geom.y() - outGeom.y()) / outGeom.height(),
89 geom.width() / outGeom.width(),
90 geom.height() / outGeom.height());
91
92 setRelativeGeometry(relGeom);
93}
94
95void Tile::setRelativeGeometry(const QRectF &geom)
96{
97 QRectF constrainedGeom = geom;
98 constrainedGeom.setWidth(std::max(constrainedGeom.width(), s_minimumSize.width()));
99 constrainedGeom.setHeight(std::max(constrainedGeom.height(), s_minimumSize.height()));
100
101 if (m_relativeGeometry == constrainedGeom) {
102 return;
103 }
104
105 m_relativeGeometry = constrainedGeom;
106
109 Q_EMIT windowGeometryChanged();
110
111 for (auto *w : std::as_const(m_windows)) {
112 w->moveResize(windowGeometry());
113 }
114}
115
117{
118 return m_relativeGeometry;
119}
120
122{
123 const QRectF geom = m_tiling->output()->geometryF();
124 return QRectF(std::round(geom.x() + m_relativeGeometry.x() * geom.width()),
125 std::round(geom.y() + m_relativeGeometry.y() * geom.height()),
126 std::round(m_relativeGeometry.width() * geom.width()),
127 std::round(m_relativeGeometry.height() * geom.height()));
128}
129
131{
132 const QRectF geom = m_tiling->output()->geometryF();
133 return QRectF(std::round(m_relativeGeometry.x() * geom.width()),
134 std::round(m_relativeGeometry.y() * geom.height()),
135 std::round(m_relativeGeometry.width() * geom.width()),
136 std::round(m_relativeGeometry.height() * geom.height()));
137}
138
140{
141 // Apply half padding between tiles and full against the screen edges
142 QMarginsF effectiveMargins;
143 effectiveMargins.setLeft(m_relativeGeometry.left() > 0.0 ? m_padding / 2.0 : m_padding);
144 effectiveMargins.setTop(m_relativeGeometry.top() > 0.0 ? m_padding / 2.0 : m_padding);
145 effectiveMargins.setRight(m_relativeGeometry.right() < 1.0 ? m_padding / 2.0 : m_padding);
146 effectiveMargins.setBottom(m_relativeGeometry.bottom() < 1.0 ? m_padding / 2.0 : m_padding);
147
148 const auto geom = absoluteGeometry();
149 return geom.intersected(workspace()->clientArea(MaximizeArea, m_tiling->output(), VirtualDesktopManager::self()->currentDesktop())) - effectiveMargins;
150}
151
153{
154 const auto geom = absoluteGeometry();
155 return geom.intersected(workspace()->clientArea(MaximizeArea, m_tiling->output(), VirtualDesktopManager::self()->currentDesktop()));
156}
157
158bool Tile::isLayout() const
159{
160 // Items with a single child are not allowed, unless the root which is *always* layout
161 return m_children.count() > 0 || !m_parentTile;
162}
163
165{
166 // The root tile can *never* be removed
167 return m_parentTile;
168}
169
170qreal Tile::padding() const
171{
172 // Assume padding is all the same
173 return m_padding;
174}
175
176void Tile::setPadding(qreal padding)
177{
178 if (m_padding == padding) {
179 return;
180 }
181
182 m_padding = padding;
183
184 for (auto *t : std::as_const(m_children)) {
185 t->setPadding(padding);
186 }
187 for (auto *w : std::as_const(m_windows)) {
188 w->moveResize(windowGeometry());
189 }
190
191 Q_EMIT paddingChanged(padding);
192 Q_EMIT windowGeometryChanged();
193}
194
195QuickTileMode Tile::quickTileMode() const
196{
197 return m_quickTileMode;
198}
199
200void Tile::setQuickTileMode(QuickTileMode mode)
201{
202 m_quickTileMode = mode;
203}
204
205void Tile::resizeFromGravity(Gravity gravity, int x_root, int y_root)
206{
207 if (!m_parentTile) {
208 return;
209 }
210
211 const QRectF outGeom = m_tiling->output()->geometryF();
212 const QPointF relativePos = QPointF((x_root - outGeom.x()) / outGeom.width(), (y_root - outGeom.y()) / outGeom.height());
213 QRectF newGeom = m_relativeGeometry;
214
215 switch (gravity) {
216 case Gravity::TopLeft:
217 newGeom.setTopLeft(relativePos - QPointF(m_padding / outGeom.width(), m_padding / outGeom.height()));
218 break;
220 newGeom.setBottomRight(relativePos + QPointF(m_padding / outGeom.width(), m_padding / outGeom.height()));
221 break;
223 newGeom.setBottomLeft(relativePos + QPointF(-m_padding / outGeom.width(), m_padding / outGeom.height()));
224 break;
226 newGeom.setTopRight(relativePos + QPointF(m_padding / outGeom.width(), -m_padding / outGeom.height()));
227 break;
228 case Gravity::Top:
229 newGeom.setTop(relativePos.y() - m_padding / outGeom.height());
230 break;
231 case Gravity::Bottom:
232 newGeom.setBottom(relativePos.y() + m_padding / outGeom.height());
233 break;
234 case Gravity::Left:
235 newGeom.setLeft(relativePos.x() - m_padding / outGeom.width());
236 break;
237 case Gravity::Right:
238 newGeom.setRight(relativePos.x() + m_padding / outGeom.width());
239 break;
240 case Gravity::None:
241 Q_UNREACHABLE();
242 break;
243 }
244
245 setRelativeGeometry(newGeom);
246}
247
248void Tile::resizeByPixels(qreal delta, Qt::Edge edge)
249{
250 if (!m_parentTile) {
251 return;
252 }
253
254 const auto outGeom = m_tiling->output()->geometryF();
255 auto newGeom = m_relativeGeometry;
256
257 switch (edge) {
258 case Qt::LeftEdge: {
259 qreal relativeDelta = delta / outGeom.width();
260 newGeom.setLeft(newGeom.left() + relativeDelta);
261 break;
262 }
263 case Qt::TopEdge: {
264 qreal relativeDelta = delta / outGeom.height();
265 newGeom.setTop(newGeom.top() + relativeDelta);
266 break;
267 }
268 case Qt::RightEdge: {
269 qreal relativeDelta = delta / outGeom.width();
270 newGeom.setRight(newGeom.right() + relativeDelta);
271 break;
272 }
273 case Qt::BottomEdge: {
274 qreal relativeDelta = delta / outGeom.height();
275 newGeom.setBottom(newGeom.bottom() + relativeDelta);
276 break;
277 }
278 }
279 setRelativeGeometry(newGeom);
280}
281
283{
284 if (!m_windows.contains(window)) {
285 window->moveResize(windowGeometry());
286 m_windows.append(window);
287 window->setTile(this);
288 Q_EMIT windowAdded(window);
289 Q_EMIT windowsChanged();
290 }
291}
292
294{
295 // We already ensure there is a single copy of window in m_windows
296 if (m_windows.removeOne(window)) {
297 window->setTile(nullptr);
298 Q_EMIT windowRemoved(window);
299 Q_EMIT windowsChanged();
300 }
301}
302
303QList<KWin::Window *> Tile::windows() const
304{
305 return m_windows;
306}
307
308void Tile::insertChild(int position, Tile *item)
309{
310 Q_ASSERT(position >= 0);
311 const bool wasEmpty = m_children.isEmpty();
312 item->setParent(this);
313
314 m_children.insert(std::clamp<qsizetype>(position, 0, m_children.length()), item);
315
316 if (wasEmpty) {
317 Q_EMIT isLayoutChanged(true);
318 for (auto *w : std::as_const(m_windows)) {
319 Tile *tile = m_tiling->bestTileForPosition(w->moveResizeGeometry().center());
320 w->setTile(tile);
321 }
322 }
323
324 Q_EMIT childTilesChanged();
325}
326
328{
329 removeChild(tile);
330 delete tile;
331}
332
334{
335 const bool wasEmpty = m_children.isEmpty();
336 const int idx = m_children.indexOf(child);
337 m_children.removeAll(child);
338 if (m_children.isEmpty() && !wasEmpty) {
339 Q_EMIT isLayoutChanged(false);
340 }
341 if (idx > -1) {
342 for (int i = idx; i < m_children.count(); ++i) {
343 Q_EMIT m_children[i]->rowChanged(i);
344 }
345 }
346 Q_EMIT childTilesChanged();
347}
348
349QList<Tile *> Tile::childTiles() const
350{
351 return m_children;
352}
353
355{
356 if (row < 0 || row >= m_children.size()) {
357 return nullptr;
358 }
359 return m_children.value(row);
360}
361
363{
364 return m_children.count();
365}
366
367QList<Tile *> Tile::descendants() const
368{
369 QList<Tile *> tiles;
370 for (auto *t : std::as_const(m_children)) {
371 tiles << t << t->descendants();
372 }
373 return tiles;
374}
375
377{
378 return m_parentTile;
379}
380
381void Tile::visitDescendants(std::function<void(const Tile *child)> callback) const
382{
383 callback(this);
384 for (const Tile *child : m_children) {
385 child->visitDescendants(callback);
386 }
387}
388
390{
391 return m_tiling;
392}
393
394int Tile::row() const
395{
396 if (m_parentTile) {
397 return m_parentTile->m_children.indexOf(this);
398 }
399
400 return -1;
401}
402
404{
405 const int r = row();
406 if (!m_parentTile || row() >= m_parentTile->childCount() - 1) {
407 return nullptr;
408 } else {
409 return m_parentTile->childTiles()[r + 1];
410 }
411}
412
414{
415 const int r = row();
416 if (r <= 0 || !m_parentTile) {
417 return nullptr;
418 } else {
419 return m_parentTile->childTiles().at(r - 1);
420 }
421}
422
423} // namespace KWin
424
425#include "moc_tile.cpp"
QRectF geometryF() const
Definition output.cpp:465
void resizeFromGravity(Gravity gravity, int x_root, int y_root)
Definition tile.cpp:205
QRectF absoluteGeometry
Definition tile.h:29
int row() const
Definition tile.cpp:394
Q_INVOKABLE void resizeByPixels(qreal delta, Qt::Edge edge)
Definition tile.cpp:248
void isLayoutChanged(bool isLayout)
void removeWindow(Window *window)
Definition tile.cpp:293
void paddingChanged(qreal padding)
QRectF absoluteGeometryInScreen
Definition tile.h:30
void setQuickTileMode(QuickTileMode mode)
Definition tile.cpp:200
QList< KWin::Tile * > tiles
Definition tile.h:34
void visitDescendants(std::function< void(const Tile *child)> callback) const
Definition tile.cpp:381
Tile * nextSibling() const
Definition tile.cpp:403
void relativeGeometryChanged()
bool canBeRemoved
Definition tile.h:37
QRectF maximizedWindowGeometry() const
Definition tile.cpp:152
TileManager * manager() const
Definition tile.cpp:389
void windowRemoved(Window *window)
void absoluteGeometryChanged()
Tile * childTile(int row)
Definition tile.cpp:354
void childTilesChanged()
bool isLayout
Definition tile.h:36
void addWindow(Window *window)
Definition tile.cpp:282
QList< KWin::Window * > windows
Definition tile.h:35
void setGeometryFromAbsolute(const QRectF &geom)
Definition tile.cpp:84
virtual bool supportsResizeGravity(Gravity gravity)
Definition tile.cpp:50
QuickTileMode quickTileMode() const
Definition tile.cpp:195
Tile * parentTile() const
Definition tile.cpp:376
int childCount() const
Definition tile.cpp:362
void destroyChild(Tile *tile)
Definition tile.cpp:327
void setGeometryFromWindow(const QRectF &geom)
Definition tile.cpp:79
Tile(TileManager *tiling, Tile *parentItem=nullptr)
Definition tile.cpp:24
Tile * previousSibling() const
Definition tile.cpp:413
qreal padding
Definition tile.h:31
virtual void setRelativeGeometry(const QRectF &geom)
Definition tile.cpp:95
QList< Tile * > descendants() const
Definition tile.cpp:367
QList< Tile * > childTiles() const
Definition tile.cpp:349
void windowAdded(Window *window)
QRectF windowGeometry() const
Definition tile.cpp:139
void windowsChanged()
void windowGeometryChanged()
QRectF relativeGeometry
Definition tile.h:28
void setPadding(qreal padding)
Definition tile.cpp:176
void insertChild(int position, Tile *item)
Definition tile.cpp:308
void removeChild(Tile *child)
Definition tile.cpp:333
Output * output() const
KWin::Tile * bestTileForPosition(const QPointF &pos)
void moveResize(const QRectF &rect)
Definition window.cpp:3323
void setTile(Tile *tile)
Definition window.cpp:3547
static Workspace * self()
Definition workspace.h:91
void configChanged()
Gravity
Definition globals.h:150
@ MaximizeArea
Definition globals.h:51
Workspace * workspace()
Definition workspace.h:830