KWin
Loading...
Searching...
No Matches
layershellv1integration.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
8#include "core/output.h"
10#include "wayland/display.h"
12#include "wayland/output.h"
13#include "wayland_server.h"
14#include "workspace.h"
15
16#include <QTimer>
17
18namespace KWin
19{
20
21static const Qt::Edges AnchorHorizontal = Qt::LeftEdge | Qt::RightEdge;
22static const Qt::Edges AnchorVertical = Qt::TopEdge | Qt::BottomEdge;
23
26{
27 LayerShellV1Interface *shell = new LayerShellV1Interface(waylandServer()->display(), this);
30
31 m_rearrangeTimer = new QTimer(this);
32 m_rearrangeTimer->setSingleShot(true);
33 connect(m_rearrangeTimer, &QTimer::timeout, this, &LayerShellV1Integration::rearrange);
34}
35
37{
38 Output *output = shellSurface->output() ? shellSurface->output()->handle() : workspace()->activeOutput();
39 if (!output) {
40 qCWarning(KWIN_CORE) << "Could not find any suitable output for a layer surface";
41 shellSurface->sendClosed();
42 return;
43 }
44
45 Q_EMIT windowCreated(new LayerShellV1Window(shellSurface, output, this));
46}
47
49{
50 destroyWindow(shellSurface);
51 createWindow(shellSurface);
52}
53
55{
56 const QList<Window *> windows = waylandServer()->windows();
57 for (Window *window : windows) {
58 LayerShellV1Window *layerShellWindow = qobject_cast<LayerShellV1Window *>(window);
59 if (layerShellWindow && layerShellWindow->shellSurface() == shellSurface) {
60 layerShellWindow->destroyWindow();
61 break;
62 }
63 }
64}
65
66static void adjustWorkArea(const LayerSurfaceV1Interface *shellSurface, QRect *workArea)
67{
68 switch (shellSurface->exclusiveEdge()) {
69 case Qt::LeftEdge:
70 workArea->adjust(shellSurface->leftMargin() + shellSurface->exclusiveZone(), 0, 0, 0);
71 break;
72 case Qt::RightEdge:
73 workArea->adjust(0, 0, -shellSurface->rightMargin() - shellSurface->exclusiveZone(), 0);
74 break;
75 case Qt::TopEdge:
76 workArea->adjust(0, shellSurface->topMargin() + shellSurface->exclusiveZone(), 0, 0);
77 break;
78 case Qt::BottomEdge:
79 workArea->adjust(0, 0, 0, -shellSurface->bottomMargin() - shellSurface->exclusiveZone());
80 break;
81 }
82}
83
84static void rearrangeLayer(const QList<LayerShellV1Window *> &windows, QRect *workArea,
85 LayerSurfaceV1Interface::Layer layer, bool exclusive)
86{
87 for (LayerShellV1Window *window : windows) {
88 LayerSurfaceV1Interface *shellSurface = window->shellSurface();
89
90 if (shellSurface->layer() != layer) {
91 continue;
92 }
93 if (exclusive != (shellSurface->exclusiveZone() > 0)) {
94 continue;
95 }
96
97 QRect bounds;
98 if (shellSurface->exclusiveZone() == -1) {
99 bounds = window->desiredOutput()->geometry();
100 } else {
101 bounds = *workArea;
102 }
103
104 QRect geometry(QPoint(0, 0), shellSurface->desiredSize());
105
106 if ((shellSurface->anchor() & AnchorHorizontal) && geometry.width() == 0) {
107 geometry.setLeft(bounds.left());
108 geometry.setWidth(bounds.width());
109 } else if (shellSurface->anchor() & Qt::LeftEdge) {
110 geometry.moveLeft(bounds.left());
111 } else if (shellSurface->anchor() & Qt::RightEdge) {
112 geometry.moveRight(bounds.right());
113 } else {
114 geometry.moveLeft(bounds.left() + (bounds.width() - geometry.width()) / 2);
115 }
116
117 if ((shellSurface->anchor() & AnchorVertical) && geometry.height() == 0) {
118 geometry.setTop(bounds.top());
119 geometry.setHeight(bounds.height());
120 } else if (shellSurface->anchor() & Qt::TopEdge) {
121 geometry.moveTop(bounds.top());
122 } else if (shellSurface->anchor() & Qt::BottomEdge) {
123 geometry.moveBottom(bounds.bottom());
124 } else {
125 geometry.moveTop(bounds.top() + (bounds.height() - geometry.height()) / 2);
126 }
127
128 if ((shellSurface->anchor() & AnchorHorizontal) == AnchorHorizontal) {
129 geometry.adjust(shellSurface->leftMargin(), 0, -shellSurface->rightMargin(), 0);
130 } else if (shellSurface->anchor() & Qt::LeftEdge) {
131 geometry.translate(shellSurface->leftMargin(), 0);
132 } else if (shellSurface->anchor() & Qt::RightEdge) {
133 geometry.translate(-shellSurface->rightMargin(), 0);
134 }
135
136 if ((shellSurface->anchor() & AnchorVertical) == AnchorVertical) {
137 geometry.adjust(0, shellSurface->topMargin(), 0, -shellSurface->bottomMargin());
138 } else if (shellSurface->anchor() & Qt::TopEdge) {
139 geometry.translate(0, shellSurface->topMargin());
140 } else if (shellSurface->anchor() & Qt::BottomEdge) {
141 geometry.translate(0, -shellSurface->bottomMargin());
142 }
143
144 // Move the window's bottom if its virtual keyboard is overlapping it
145 if (shellSurface->exclusiveZone() >= 0 && !window->virtualKeyboardGeometry().isEmpty() && geometry.bottom() > window->virtualKeyboardGeometry().top()) {
146 geometry.setBottom(window->virtualKeyboardGeometry().top());
147 }
148
149 window->updateLayer();
150
151 if (geometry.isValid()) {
152 window->moveResize(geometry);
153 } else {
154 qCWarning(KWIN_CORE) << "Closing a layer shell window due to invalid geometry";
155 window->closeWindow();
156 continue;
157 }
158
159 if (exclusive && shellSurface->exclusiveZone() > 0) {
160 adjustWorkArea(shellSurface, workArea);
161 }
162 }
163}
164
165static QList<LayerShellV1Window *> windowsForOutput(Output *output)
166{
167 QList<LayerShellV1Window *> result;
168 const QList<Window *> windows = waylandServer()->windows();
169 for (Window *window : windows) {
170 LayerShellV1Window *layerShellWindow = qobject_cast<LayerShellV1Window *>(window);
171 if (!layerShellWindow || layerShellWindow->desiredOutput() != output) {
172 continue;
173 }
174 if (layerShellWindow->shellSurface()->isCommitted()) {
175 result.append(layerShellWindow);
176 }
177 }
178 return result;
179}
180
181static void rearrangeOutput(Output *output)
182{
183 const QList<LayerShellV1Window *> windows = windowsForOutput(output);
184 if (!windows.isEmpty()) {
185 QRect workArea = output->geometry();
186
187 rearrangeLayer(windows, &workArea, LayerSurfaceV1Interface::OverlayLayer, true);
188 rearrangeLayer(windows, &workArea, LayerSurfaceV1Interface::TopLayer, true);
189 rearrangeLayer(windows, &workArea, LayerSurfaceV1Interface::BottomLayer, true);
190 rearrangeLayer(windows, &workArea, LayerSurfaceV1Interface::BackgroundLayer, true);
191
192 rearrangeLayer(windows, &workArea, LayerSurfaceV1Interface::OverlayLayer, false);
193 rearrangeLayer(windows, &workArea, LayerSurfaceV1Interface::TopLayer, false);
194 rearrangeLayer(windows, &workArea, LayerSurfaceV1Interface::BottomLayer, false);
195 rearrangeLayer(windows, &workArea, LayerSurfaceV1Interface::BackgroundLayer, false);
196 }
197}
198
200{
201 m_rearrangeTimer->stop();
202
203 const QList<Output *> outputs = workspace()->outputs();
204 for (Output *output : outputs) {
205 rearrangeOutput(output);
206 }
207
208 if (workspace()) {
210 }
211}
212
214{
215 m_rearrangeTimer->start();
216}
217
218} // namespace KWin
219
220#include "moc_layershellv1integration.cpp"
void destroyWindow(LayerSurfaceV1Interface *shellSurface)
void createWindow(LayerSurfaceV1Interface *shellSurface)
LayerShellV1Integration(QObject *parent=nullptr)
void recreateWindow(LayerSurfaceV1Interface *shellSurface)
void surfaceCreated(LayerSurfaceV1Interface *surface)
LayerSurfaceV1Interface * shellSurface() const
OutputInterface * output() const
Output * handle() const
Definition output.cpp:263
QList< Window * > windows() const
void windowCreated(Window *window)
void updateClientArea()
Output * activeOutput() const
QList< Output * > outputs() const
Definition workspace.h:762
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830