File: waylandwindow.cpp

package info (click to toggle)
kwin 4%3A6.5.4-5
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 53,420 kB
  • sloc: cpp: 240,899; javascript: 2,225; xml: 2,096; ansic: 775; sh: 37; python: 15; makefile: 8
file content (274 lines) | stat: -rw-r--r-- 7,302 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/*
    SPDX-FileCopyrightText: 2015 Martin Flöser <mgraesslin@kde.org>
    SPDX-FileCopyrightText: 2018 David Edmundson <davidedmundson@kde.org>
    SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>

    SPDX-License-Identifier: GPL-2.0-or-later
*/

#include "waylandwindow.h"
#include "core/pixelgrid.h"
#include "scene/windowitem.h"
#include "wayland/clientconnection.h"
#include "wayland/display.h"
#include "wayland/surface.h"
#include "wayland_server.h"
#include "workspace.h"

#include <QFileInfo>

#include <csignal>

#include <sys/types.h>
#include <unistd.h>

namespace KWin
{

enum WaylandGeometryType {
    WaylandGeometryClient = 0x1,
    WaylandGeometryFrame = 0x2,
    WaylandGeometryBuffer = 0x4,
};
Q_DECLARE_FLAGS(WaylandGeometryTypes, WaylandGeometryType)

WaylandWindow::WaylandWindow(SurfaceInterface *surface)
    : m_isScreenLocker(surface->client() == waylandServer()->screenLockerClientConnection())
{
    setSurface(surface);

    connect(surface, &SurfaceInterface::shadowChanged,
            this, &WaylandWindow::updateShadow);
    connect(this, &WaylandWindow::frameGeometryChanged,
            this, &WaylandWindow::updateClientOutputs);
    connect(workspace(), &Workspace::outputsChanged, this, &WaylandWindow::updateClientOutputs);

    updateResourceName();
    updateShadow();
}

std::unique_ptr<WindowItem> WaylandWindow::createItem(Item *parentItem)
{
    return std::make_unique<WindowItemWayland>(this, parentItem);
}

QString WaylandWindow::captionNormal() const
{
    return m_captionNormal;
}

QString WaylandWindow::captionSuffix() const
{
    return m_captionSuffix;
}

pid_t WaylandWindow::pid() const
{
    return surface() ? surface()->client()->processId() : -1;
}

bool WaylandWindow::isClient() const
{
    return true;
}

bool WaylandWindow::isLockScreen() const
{
    return m_isScreenLocker;
}

bool WaylandWindow::isLocalhost() const
{
    return true;
}

QRectF WaylandWindow::resizeWithChecks(const QRectF &geometry, const QSizeF &size) const
{
    const QRectF area = workspace()->clientArea(WorkArea, this, geometry.center());

    qreal width = size.width();
    qreal height = size.height();

    // don't allow growing larger than workarea
    if (width > area.width()) {
        width = area.width();
    }
    if (height > area.height()) {
        height = area.height();
    }
    return QRectF(geometry.topLeft(), QSizeF(width, height));
}

void WaylandWindow::killWindow()
{
    if (!surface()) {
        return;
    }
    auto c = surface()->client();
    if (c->processId() == getpid() || c->processId() == 0) {
        c->destroy();
        return;
    }
    ::kill(c->processId(), SIGTERM);
    // give it time to terminate and only if terminate fails, try destroy Wayland connection
    QTimer::singleShot(5000, c, &ClientConnection::destroy);
}

QString WaylandWindow::windowRole() const
{
    return QString();
}

bool WaylandWindow::belongsToSameApplication(const Window *other, SameApplicationChecks checks) const
{
    if (checks.testFlag(SameApplicationCheck::AllowCrossProcesses)) {
        if (other->desktopFileName() == desktopFileName()) {
            return true;
        }
    }
    if (auto s = other->surface()) {
        return s->client() == surface()->client();
    }
    return false;
}

bool WaylandWindow::belongsToDesktop() const
{
    const auto clients = waylandServer()->windows();

    return std::any_of(clients.constBegin(), clients.constEnd(),
                       [this](const Window *client) {
                           if (belongsToSameApplication(client, SameApplicationChecks())) {
                               return client->isDesktop();
                           }
                           return false;
                       });
}

void WaylandWindow::updateClientOutputs()
{
    if (isDeleted()) {
        return;
    }
    const auto rect = frameGeometry().toAlignedRect();
    if (rect.isEmpty()) {
        return;
    }

    surface()->setOutputs(waylandServer()->display()->outputsIntersecting(rect),
                          waylandServer()->display()->largestIntersectingOutput(rect));
}

void WaylandWindow::updateResourceName()
{
    const QFileInfo fileInfo(surface()->client()->executablePath());
    if (fileInfo.exists()) {
        const QByteArray executableFileName = fileInfo.fileName().toUtf8();
        setResourceClass(executableFileName, executableFileName);
    }
}

void WaylandWindow::updateCaption()
{
    const QString suffix = shortcutCaptionSuffix();
    if (m_captionSuffix != suffix) {
        m_captionSuffix = suffix;
        Q_EMIT captionChanged();
    }
}

void WaylandWindow::setCaption(const QString &caption)
{
    const QString simplified = caption.simplified();
    if (m_captionNormal != simplified) {
        m_captionNormal = simplified;
        Q_EMIT captionNormalChanged();
        Q_EMIT captionChanged();
    }
}

void WaylandWindow::doSetActive()
{
    if (isActive()) { // TODO: Xwayland clients must be unfocused somewhere else.
        StackingUpdatesBlocker blocker(workspace());
        workspace()->focusToNull();
    }
}

void WaylandWindow::cleanGrouping()
{
    // We want to break parent-child relationships, but preserve stacking
    // order constraints at the same time for window closing animations.

    if (transientFor()) {
        transientFor()->removeTransientFromList(this);
        setTransientFor(nullptr);
    }

    const auto children = transients();
    for (Window *transient : children) {
        removeTransientFromList(transient);
        transient->setTransientFor(nullptr);
    }
}

QRectF WaylandWindow::frameRectToBufferRect(const QRectF &rect) const
{
    return QRectF(rect.topLeft(), snapToPixels(surface()->size(), targetScale()));
}

void WaylandWindow::updateGeometry(const QRectF &rect)
{
    const QRectF oldClientGeometry = m_clientGeometry;
    const QRectF oldFrameGeometry = m_frameGeometry;
    const QRectF oldBufferGeometry = m_bufferGeometry;
    const Output *oldOutput = m_output;

    m_clientGeometry = frameRectToClientRect(rect);
    m_frameGeometry = rect;
    m_bufferGeometry = frameRectToBufferRect(rect);

    WaylandGeometryTypes changedGeometries;

    if (m_clientGeometry != oldClientGeometry) {
        changedGeometries |= WaylandGeometryClient;
    }
    if (m_frameGeometry != oldFrameGeometry) {
        changedGeometries |= WaylandGeometryFrame;
    }
    if (m_bufferGeometry != oldBufferGeometry) {
        changedGeometries |= WaylandGeometryBuffer;
    }

    if (!changedGeometries) {
        return;
    }

    m_output = workspace()->outputAt(rect.center());
    updateWindowRules(Rules::Position | Rules::Size);

    if (changedGeometries & WaylandGeometryBuffer) {
        Q_EMIT bufferGeometryChanged(oldBufferGeometry);
    }
    if (changedGeometries & WaylandGeometryClient) {
        Q_EMIT clientGeometryChanged(oldClientGeometry);
    }
    if (changedGeometries & WaylandGeometryFrame) {
        Q_EMIT frameGeometryChanged(oldFrameGeometry);
    }
    if (oldOutput != m_output) {
        Q_EMIT outputChanged();
    }
}

void WaylandWindow::markAsMapped()
{
    if (Q_UNLIKELY(!ready_for_painting)) {
        setupCompositing();
        setReadyForPainting();
    }
}

} // namespace KWin

#include "moc_waylandwindow.cpp"