KWin
Loading...
Searching...
No Matches
display.cpp
Go to the documentation of this file.
1/*
2 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
3 SPDX-FileCopyrightText: 2018 David Edmundson <davidedmundson@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6*/
7#include "display.h"
8#include "clientconnection.h"
9#include "display_p.h"
11#include "output.h"
12#include "shmclientbuffer_p.h"
13#include "utils/common.h"
14
15#include <poll.h>
16#include <string.h>
17#include <sys/socket.h>
18
19#include <QAbstractEventDispatcher>
20#include <QCoreApplication>
21#include <QDebug>
22#include <QRect>
23
24namespace KWin
25{
27{
28 return display->d.get();
29}
30
35
36void DisplayPrivate::registerSocketName(const QString &socketName)
37{
38 socketNames.append(socketName);
39 Q_EMIT q->socketNamesChanged();
40}
41
42Display::Display(QObject *parent)
43 : QObject(parent)
44 , d(new DisplayPrivate(this))
45{
46 d->display = wl_display_create();
47 d->loop = wl_display_get_event_loop(d->display);
48}
49
50Display::~Display()
51{
52 wl_display_destroy_clients(d->display);
53 wl_display_destroy(d->display);
54}
55
56bool Display::addSocketFileDescriptor(int fileDescriptor, const QString &name)
57{
58 if (wl_display_add_socket_fd(d->display, fileDescriptor)) {
59 qCWarning(KWIN_CORE, "Failed to add %d fd to display", fileDescriptor);
60 return false;
61 }
62 if (!name.isEmpty()) {
63 d->registerSocketName(name);
64 }
65 return true;
66}
67
68bool Display::addSocketName(const QString &name)
69{
70 if (name.isEmpty()) {
71 const char *socket = wl_display_add_socket_auto(d->display);
72 if (!socket) {
73 qCWarning(KWIN_CORE, "Failed to find a free display socket");
74 return false;
75 }
76 d->registerSocketName(QString::fromUtf8(socket));
77 } else {
78 if (wl_display_add_socket(d->display, qPrintable(name))) {
79 qCWarning(KWIN_CORE, "Failed to add %s socket to display", qPrintable(name));
80 return false;
81 }
82 d->registerSocketName(name);
83 }
84 return true;
85}
86
87QStringList Display::socketNames() const
88{
89 return d->socketNames;
90}
91
92bool Display::start()
93{
94 if (d->running) {
95 return true;
96 }
97
98 const int fileDescriptor = wl_event_loop_get_fd(d->loop);
99 if (fileDescriptor == -1) {
100 qCWarning(KWIN_CORE) << "Did not get the file descriptor for the event loop";
101 return false;
102 }
103
104 d->socketNotifier = new QSocketNotifier(fileDescriptor, QSocketNotifier::Read, this);
105 connect(d->socketNotifier, &QSocketNotifier::activated, this, &Display::dispatchEvents);
106
107 QAbstractEventDispatcher *dispatcher = QCoreApplication::eventDispatcher();
108 connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, this, &Display::flush);
109
110 d->running = true;
111 Q_EMIT runningChanged(true);
112
113 return true;
114}
115
116void Display::dispatchEvents()
117{
118 if (wl_event_loop_dispatch(d->loop, 0) != 0) {
119 qCWarning(KWIN_CORE) << "Error on dispatching Wayland event loop";
120 }
121}
122
123void Display::flush()
124{
125 wl_display_flush_clients(d->display);
126}
127
128void Display::createShm()
129{
130 Q_ASSERT(d->display);
132}
133
134quint32 Display::nextSerial()
135{
136 return wl_display_next_serial(d->display);
137}
138
139quint32 Display::serial()
140{
141 return wl_display_get_serial(d->display);
142}
143
144bool Display::isRunning() const
145{
146 return d->running;
147}
148
149Display::operator wl_display *()
150{
151 return d->display;
152}
153
154Display::operator wl_display *() const
155{
156 return d->display;
157}
158
159QList<OutputInterface *> Display::outputs() const
160{
161 return d->outputs;
162}
163
164QList<OutputDeviceV2Interface *> Display::outputDevices() const
165{
166 return d->outputdevicesV2;
167}
168
169QList<OutputInterface *> Display::outputsIntersecting(const QRect &rect) const
170{
171 QList<OutputInterface *> outputs;
172 for (auto *output : std::as_const(d->outputs)) {
173 if (output->handle()->geometry().intersects(rect)) {
174 outputs << output;
175 }
176 }
177 return outputs;
178}
179
180OutputInterface *Display::largestIntersectingOutput(const QRect &rect) const
181{
182 OutputInterface *returnOutput = nullptr;
183 uint64_t biggestArea = 0;
184 for (auto *output : std::as_const(d->outputs)) {
185 const QRect intersect = output->handle()->geometry().intersected(rect);
186 const uint64_t area = intersect.width() * intersect.height();
187 if (area > biggestArea) {
188 biggestArea = area;
189 returnOutput = output;
190 }
191 }
192 return returnOutput;
193}
194
195QList<SeatInterface *> Display::seats() const
196{
197 return d->seats;
198}
199
200ClientConnection *Display::getConnection(wl_client *client)
201{
202 Q_ASSERT(client);
203 auto it = std::find_if(d->clients.constBegin(), d->clients.constEnd(), [client](ClientConnection *c) {
204 return c->client() == client;
205 });
206 if (it != d->clients.constEnd()) {
207 return *it;
208 }
209 // no ConnectionData yet, create it
210 auto c = new ClientConnection(client, this);
211 d->clients << c;
212 connect(c, &ClientConnection::disconnected, this, [this](ClientConnection *c) {
213 const int index = d->clients.indexOf(c);
214 Q_ASSERT(index != -1);
215 d->clients.remove(index);
216 Q_ASSERT(d->clients.indexOf(c) == -1);
217 Q_EMIT clientDisconnected(c);
218 });
219 Q_EMIT clientConnected(c);
220 return c;
221}
222
223QList<ClientConnection *> Display::connections() const
224{
225 return d->clients;
226}
227
228ClientConnection *Display::createClient(int fd)
229{
230 Q_ASSERT(fd != -1);
231 Q_ASSERT(d->display);
232 wl_client *c = wl_client_create(d->display, fd);
233 if (!c) {
234 return nullptr;
235 }
236 return getConnection(c);
237}
238
239GraphicsBuffer *Display::bufferForResource(wl_resource *resource)
240{
241 if (auto buffer = LinuxDmaBufV1ClientBuffer::get(resource)) {
242 return buffer;
243 } else if (auto buffer = ShmClientBuffer::get(resource)) {
244 return buffer;
245 } else {
246 return nullptr;
247 }
248}
249
250SecurityContext::SecurityContext(Display *display, FileDescriptor &&listenFd, FileDescriptor &&closeFd, const QString &appId)
251 : QObject(display)
252 , m_display(display)
253 , m_listenFd(std::move(listenFd))
254 , m_closeFd(std::move(closeFd))
255 , m_appId(appId)
256{
257 qCDebug(KWIN_CORE) << "Adding listen fd for" << appId;
258
259 auto closeSocketWatcher = new QSocketNotifier(m_closeFd.get(), QSocketNotifier::Read, this);
260 connect(closeSocketWatcher, &QSocketNotifier::activated, this, &SecurityContext::onCloseFdActivated);
261
262 if (m_closeFd.isClosed()) {
263 deleteLater();
264 return;
265 }
266
267 auto listenFdListener = new QSocketNotifier(m_listenFd.get(), QSocketNotifier::Read, this);
268 connect(listenFdListener, &QSocketNotifier::activated, this, &SecurityContext::onListenFdActivated);
269}
270
272{
273 qCDebug(KWIN_CORE) << "Removing listen fd for " << m_appId;
274}
275
276void SecurityContext::onListenFdActivated(QSocketDescriptor socketDescriptor)
277{
278 int clientFd = accept4(socketDescriptor, nullptr, nullptr, SOCK_CLOEXEC);
279 if (clientFd < 0) {
280 qCWarning(KWIN_CORE) << "Failed to accept client from security listen FD";
281 return;
282 }
283 auto client = m_display->createClient(clientFd);
284 client->setSecurityContextAppId(m_appId);
285}
286
287void SecurityContext::onCloseFdActivated()
288{
289 if (m_closeFd.isClosed()) {
290 deleteLater();
291 }
292}
293
294} // namespace KWin
295
296#include "moc_display.cpp"
Convenient Class which represents a wl_client.
void setSecurityContextAppId(const QString &appId)
void disconnected(KWin::ClientConnection *)
Class holding the Wayland server display loop.
Definition display.h:34
void clientConnected(KWin::ClientConnection *)
ClientConnection * createClient(int fd)
Definition display.cpp:228
void clientDisconnected(KWin::ClientConnection *)
QList< OutputInterface * > outputs() const
Definition display.cpp:159
ClientConnection * getConnection(wl_client *client)
Definition display.cpp:200
void runningChanged(bool)
void socketNamesChanged()
QStringList socketNames
Definition display_p.h:44
static DisplayPrivate * get(Display *display)
Definition display.cpp:26
DisplayPrivate(Display *q)
Definition display.cpp:31
void registerSocketName(const QString &socketName)
Definition display.cpp:36
wl_display * display
Definition display_p.h:37
QRect geometry
Definition output.h:134
Output * handle() const
Definition output.cpp:263
~SecurityContext() override
Definition display.cpp:271
SecurityContext(Display *display, FileDescriptor &&listenFd, FileDescriptor &&closeFd, const QString &appId)
Definition display.cpp:250
static LinuxDmaBufV1ClientBuffer * get(wl_resource *resource)
static ShmClientBuffer * get(wl_resource *resource)