KWin
Loading...
Searching...
No Matches
waylandwindow.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2015 Martin Flöser <mgraesslin@kde.org>
3 SPDX-FileCopyrightText: 2018 David Edmundson <davidedmundson@kde.org>
4 SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
5
6 SPDX-License-Identifier: GPL-2.0-or-later
7*/
8
9#include "waylandwindow.h"
10#include "scene/windowitem.h"
12#include "wayland/display.h"
13#include "wayland/surface.h"
14#include "wayland_server.h"
15#include "workspace.h"
16
17#include <QFileInfo>
18
19#include <csignal>
20
21#include <sys/types.h>
22#include <unistd.h>
23
24namespace KWin
25{
26
32Q_DECLARE_FLAGS(WaylandGeometryTypes, WaylandGeometryType)
33
35 : m_isScreenLocker(surface->client() == waylandServer()->screenLockerClientConnection())
36{
37 setSurface(surface);
38
39 connect(surface, &SurfaceInterface::shadowChanged,
44 this, &WaylandWindow::updateIcon);
46
47 updateResourceName();
48 updateIcon();
49}
50
51std::unique_ptr<WindowItem> WaylandWindow::createItem(Scene *scene)
52{
53 return std::make_unique<WindowItemWayland>(this, scene);
54}
55
57{
58 return m_captionNormal;
59}
60
62{
63 return m_captionSuffix;
64}
65
66pid_t WaylandWindow::pid() const
67{
68 return surface() ? surface()->client()->processId() : -1;
69}
70
72{
73 return true;
74}
75
77{
78 return m_isScreenLocker;
79}
80
82{
83 return true;
84}
85
87{
88 return nullptr;
89}
90
91QRectF WaylandWindow::resizeWithChecks(const QRectF &geometry, const QSizeF &size)
92{
93 const QRectF area = workspace()->clientArea(WorkArea, this, geometry.center());
94
95 qreal width = size.width();
96 qreal height = size.height();
97
98 // don't allow growing larger than workarea
99 if (width > area.width()) {
100 width = area.width();
101 }
102 if (height > area.height()) {
103 height = area.height();
104 }
105 return QRectF(geometry.topLeft(), QSizeF(width, height));
106}
107
109{
110 if (!surface()) {
111 return;
112 }
113 auto c = surface()->client();
114 if (c->processId() == getpid() || c->processId() == 0) {
115 c->destroy();
116 return;
117 }
118 ::kill(c->processId(), SIGTERM);
119 // give it time to terminate and only if terminate fails, try destroy Wayland connection
120 QTimer::singleShot(5000, c, &ClientConnection::destroy);
121}
122
124{
125 return QString();
126}
127
128bool WaylandWindow::belongsToSameApplication(const Window *other, SameApplicationChecks checks) const
129{
130 if (checks.testFlag(SameApplicationCheck::AllowCrossProcesses)) {
131 if (other->desktopFileName() == desktopFileName()) {
132 return true;
133 }
134 }
135 if (auto s = other->surface()) {
136 return s->client() == surface()->client();
137 }
138 return false;
139}
140
142{
143 const auto clients = waylandServer()->windows();
144
145 return std::any_of(clients.constBegin(), clients.constEnd(),
146 [this](const Window *client) {
147 if (belongsToSameApplication(client, SameApplicationChecks())) {
148 return client->isDesktop();
149 }
150 return false;
151 });
152}
153
154void WaylandWindow::updateClientOutputs()
155{
156 if (isDeleted()) {
157 return;
158 }
159 surface()->setOutputs(waylandServer()->display()->outputsIntersecting(frameGeometry().toAlignedRect()),
160 waylandServer()->display()->largestIntersectingOutput(frameGeometry().toAlignedRect()));
161 if (output()) {
162 surface()->setPreferredBufferScale(output()->scale());
163 surface()->setPreferredBufferTransform(output()->transform());
164 surface()->setPreferredColorDescription(output()->colorDescription());
165 }
166}
167
168void WaylandWindow::updateIcon()
169{
170 const QString waylandIconName = QStringLiteral("wayland");
171 const QString dfIconName = iconFromDesktopFile();
172 const QString iconName = dfIconName.isEmpty() ? waylandIconName : dfIconName;
173 if (iconName == icon().name()) {
174 return;
175 }
176 setIcon(QIcon::fromTheme(iconName));
177}
178
179void WaylandWindow::updateResourceName()
180{
181 const QFileInfo fileInfo(surface()->client()->executablePath());
182 if (fileInfo.exists()) {
183 const QByteArray executableFileName = fileInfo.fileName().toUtf8();
184 setResourceClass(executableFileName, executableFileName);
185 }
186}
187
188void WaylandWindow::updateCaption()
189{
190 const QString suffix = shortcutCaptionSuffix();
191 if (m_captionSuffix != suffix) {
192 m_captionSuffix = suffix;
193 Q_EMIT captionChanged();
194 }
195}
196
197void WaylandWindow::setCaption(const QString &caption)
198{
199 const QString simplified = caption.simplified();
200 if (m_captionNormal != simplified) {
201 m_captionNormal = simplified;
202 Q_EMIT captionNormalChanged();
203 Q_EMIT captionChanged();
204 }
205}
206
207void WaylandWindow::doSetActive()
208{
209 if (isActive()) { // TODO: Xwayland clients must be unfocused somewhere else.
212 }
213}
214
215void WaylandWindow::cleanGrouping()
216{
217 // We want to break parent-child relationships, but preserve stacking
218 // order constraints at the same time for window closing animations.
219
220 if (transientFor()) {
221 transientFor()->removeTransientFromList(this);
222 setTransientFor(nullptr);
223 }
224
225 const auto children = transients();
226 for (Window *transient : children) {
227 removeTransientFromList(transient);
228 transient->setTransientFor(nullptr);
229 }
230}
231
232QRectF WaylandWindow::frameRectToBufferRect(const QRectF &rect) const
233{
234 return QRectF(rect.topLeft(), surface()->size());
235}
236
237void WaylandWindow::updateGeometry(const QRectF &rect)
238{
239 const QRectF oldClientGeometry = m_clientGeometry;
240 const QRectF oldFrameGeometry = m_frameGeometry;
241 const QRectF oldBufferGeometry = m_bufferGeometry;
242 const Output *oldOutput = m_output;
243
244 m_clientGeometry = frameRectToClientRect(rect);
245 m_frameGeometry = rect;
246 m_bufferGeometry = frameRectToBufferRect(rect);
247
248 WaylandGeometryTypes changedGeometries;
249
250 if (m_clientGeometry != oldClientGeometry) {
251 changedGeometries |= WaylandGeometryClient;
252 }
253 if (m_frameGeometry != oldFrameGeometry) {
254 changedGeometries |= WaylandGeometryFrame;
255 }
256 if (m_bufferGeometry != oldBufferGeometry) {
257 changedGeometries |= WaylandGeometryBuffer;
258 }
259
260 if (!changedGeometries) {
261 return;
262 }
263
264 m_output = workspace()->outputAt(rect.center());
265 updateWindowRules(Rules::Position | Rules::Size);
266
267 if (changedGeometries & WaylandGeometryBuffer) {
268 Q_EMIT bufferGeometryChanged(oldBufferGeometry);
269 }
270 if (changedGeometries & WaylandGeometryClient) {
271 Q_EMIT clientGeometryChanged(oldClientGeometry);
272 }
273 if (changedGeometries & WaylandGeometryFrame) {
274 Q_EMIT frameGeometryChanged(oldFrameGeometry);
275 }
276 if (oldOutput != m_output) {
277 Q_EMIT outputChanged();
278 }
279}
280
281void WaylandWindow::markAsMapped()
282{
283 if (Q_UNLIKELY(!ready_for_painting)) {
284 setupCompositing();
285 setReadyForPainting();
286 }
287}
288
289} // namespace KWin
290
291#include "moc_waylandwindow.cpp"
Resource representing a wl_surface.
Definition surface.h:80
ClientConnection * client() const
Definition surface.cpp:444
QList< Window * > windows() const
QString captionSuffix() const override
bool isLocalhost() const override
bool belongsToSameApplication(const Window *other, SameApplicationChecks checks) const override
bool isClient() const override
QString windowRole() const override
QString captionNormal() const override
void killWindow() override
std::unique_ptr< WindowItem > createItem(Scene *scene) override
pid_t pid() const override
bool belongsToDesktop() const override
QRectF resizeWithChecks(const QRectF &geometry, const QSizeF &size) override
bool isLockScreen() const override
Window * findModal(bool allow_itself=false) override
qreal width
Definition window.h:99
QSizeF size
Definition window.h:84
SurfaceInterface * surface() const
Definition window.cpp:342
QString desktopFileName
Definition window.h:501
void desktopFileNameChanged()
qreal height
Definition window.h:104
void frameGeometryChanged(const QRectF &oldGeometry)
void updateShadow()
Definition window.cpp:264
QPointer< Decoration::DecoratedClientImpl > client
Definition window.h:1821
QRectF clientArea(clientAreaOption, const Output *output, const VirtualDesktop *desktop) const
Output * outputAt(const QPointF &pos) const
void outputsChanged()
WaylandGeometryType
@ WaylandGeometryFrame
@ WaylandGeometryBuffer
@ WaylandGeometryClient
@ WorkArea
Definition globals.h:55
WaylandServer * waylandServer()
Workspace * workspace()
Definition workspace.h:830