KWaylandServer

display.cpp
1 /*
2  SPDX-FileCopyrightText: 2014 Martin Gräßlin <[email protected]>
3  SPDX-FileCopyrightText: 2018 David Edmundson <[email protected]>
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 "clientbufferintegration.h"
9 #include "display_p.h"
10 #include "drmclientbuffer.h"
11 #include "logging.h"
12 #include "output_interface.h"
13 #include "shmclientbuffer.h"
14 
15 #include <QAbstractEventDispatcher>
16 #include <QCoreApplication>
17 #include <QDebug>
18 #include <QRect>
19 
20 namespace KWaylandServer
21 {
22 DisplayPrivate *DisplayPrivate::get(Display *display)
23 {
24  return display->d.data();
25 }
26 
27 DisplayPrivate::DisplayPrivate(Display *q)
28  : q(q)
29 {
30 }
31 
32 void DisplayPrivate::registerSocketName(const QString &socketName)
33 {
34  socketNames.append(socketName);
35  Q_EMIT q->socketNamesChanged();
36 }
37 
38 Display::Display(QObject *parent)
39  : QObject(parent)
40  , d(new DisplayPrivate(this))
41 {
42  d->display = wl_display_create();
43  d->loop = wl_display_get_event_loop(d->display);
44 }
45 
46 Display::~Display()
47 {
48  wl_display_destroy_clients(d->display);
49  wl_display_destroy(d->display);
50 }
51 
52 bool Display::addSocketFileDescriptor(int fileDescriptor, const QString &name)
53 {
54  if (wl_display_add_socket_fd(d->display, fileDescriptor)) {
55  qCWarning(KWAYLAND_SERVER, "Failed to add %d fd to display", fileDescriptor);
56  return false;
57  }
58  if (!name.isEmpty()) {
59  d->registerSocketName(name);
60  }
61  return true;
62 }
63 
65 {
66  if (name.isEmpty()) {
67  const char *socket = wl_display_add_socket_auto(d->display);
68  if (!socket) {
69  qCWarning(KWAYLAND_SERVER, "Failed to find a free display socket");
70  return false;
71  }
72  d->registerSocketName(QString::fromUtf8(socket));
73  } else {
74  if (wl_display_add_socket(d->display, qPrintable(name))) {
75  qCWarning(KWAYLAND_SERVER, "Failed to add %s socket to display", qPrintable(name));
76  return false;
77  }
78  d->registerSocketName(name);
79  }
80  return true;
81 }
82 
84 {
85  return d->socketNames;
86 }
87 
89 {
90  if (d->running) {
91  return true;
92  }
93 
94  const int fileDescriptor = wl_event_loop_get_fd(d->loop);
95  if (fileDescriptor == -1) {
96  qCWarning(KWAYLAND_SERVER) << "Did not get the file descriptor for the event loop";
97  return false;
98  }
99 
100  d->socketNotifier = new QSocketNotifier(fileDescriptor, QSocketNotifier::Read, this);
101  connect(d->socketNotifier, &QSocketNotifier::activated, this, &Display::dispatchEvents);
102 
104  connect(dispatcher, &QAbstractEventDispatcher::aboutToBlock, this, &Display::flush);
105 
106  d->running = true;
107  Q_EMIT runningChanged(true);
108 
109  return true;
110 }
111 
112 void Display::dispatchEvents()
113 {
114  if (wl_event_loop_dispatch(d->loop, 0) != 0) {
115  qCWarning(KWAYLAND_SERVER) << "Error on dispatching Wayland event loop";
116  }
117 }
118 
119 void Display::flush()
120 {
121  wl_display_flush_clients(d->display);
122 }
123 
124 void Display::createShm()
125 {
126  Q_ASSERT(d->display);
127  new ShmClientBufferIntegration(this);
128 }
129 
130 quint32 Display::nextSerial()
131 {
132  return wl_display_next_serial(d->display);
133 }
134 
135 quint32 Display::serial()
136 {
137  return wl_display_get_serial(d->display);
138 }
139 
140 bool Display::isRunning() const
141 {
142  return d->running;
143 }
144 
145 Display::operator wl_display *()
146 {
147  return d->display;
148 }
149 
150 Display::operator wl_display *() const
151 {
152  return d->display;
153 }
154 
155 QList<OutputInterface *> Display::outputs() const
156 {
157  return d->outputs;
158 }
159 
160 QList< OutputDeviceV2Interface* > Display::outputDevices() const
161 {
162  return d->outputdevicesV2;
163 }
164 
165 QVector<OutputInterface *> Display::outputsIntersecting(const QRect &rect) const
166 {
168  for (auto *output : qAsConst(d->outputs)) {
169  const QRect outputGeometry(output->globalPosition(), output->pixelSize() / output->scale());
170  if (rect.intersects(outputGeometry)) {
171  outputs << output;
172  }
173  }
174  return outputs;
175 }
176 
178 {
179  return d->seats;
180 }
181 
183 {
184  Q_ASSERT(client);
185  auto it = std::find_if(d->clients.constBegin(), d->clients.constEnd(), [client](ClientConnection *c) {
186  return c->client() == client;
187  });
188  if (it != d->clients.constEnd()) {
189  return *it;
190  }
191  // no ConnectionData yet, create it
192  auto c = new ClientConnection(client, this);
193  d->clients << c;
195  const int index = d->clients.indexOf(c);
196  Q_ASSERT(index != -1);
197  d->clients.remove(index);
198  Q_ASSERT(d->clients.indexOf(c) == -1);
199  Q_EMIT clientDisconnected(c);
200  });
201  Q_EMIT clientConnected(c);
202  return c;
203 }
204 
205 QVector<ClientConnection *> Display::connections() const
206 {
207  return d->clients;
208 }
209 
211 {
212  Q_ASSERT(fd != -1);
213  Q_ASSERT(d->display);
214  wl_client *c = wl_client_create(d->display, fd);
215  if (!c) {
216  return nullptr;
217  }
218  return getConnection(c);
219 }
220 
221 void Display::setEglDisplay(void *display)
222 {
223  if (d->eglDisplay != EGL_NO_DISPLAY) {
224  qCWarning(KWAYLAND_SERVER) << "EGLDisplay cannot be changed";
225  return;
226  }
227  d->eglDisplay = (EGLDisplay)display;
228  new DrmClientBufferIntegration(this);
229 }
230 
231 void *Display::eglDisplay() const
232 {
233  return d->eglDisplay;
234 }
235 
236 struct ClientBufferDestroyListener : wl_listener {
237  ClientBufferDestroyListener(Display *display, ClientBuffer *buffer);
238  ~ClientBufferDestroyListener();
239 
240  Display *display;
241 };
242 
243 void bufferDestroyCallback(wl_listener *listener, void *data)
244 {
245  ClientBufferDestroyListener *destroyListener = static_cast<ClientBufferDestroyListener *>(listener);
246  DisplayPrivate *displayPrivate = DisplayPrivate::get(destroyListener->display);
247 
248  ClientBuffer *buffer = displayPrivate->q->clientBufferForResource(static_cast<wl_resource *>(data));
249  displayPrivate->unregisterClientBuffer(buffer);
250 
251  buffer->markAsDestroyed();
252 }
253 
254 ClientBufferDestroyListener::ClientBufferDestroyListener(Display *display, ClientBuffer *buffer)
255  : display(display)
256 {
257  notify = bufferDestroyCallback;
258 
259  link.prev = nullptr;
260  link.next = nullptr;
261 
262  wl_resource_add_destroy_listener(buffer->resource(), this);
263 }
264 
265 ClientBufferDestroyListener::~ClientBufferDestroyListener()
266 {
267  wl_list_remove(&link);
268 }
269 
270 ClientBuffer *Display::clientBufferForResource(wl_resource *resource) const
271 {
272  ClientBuffer *buffer = d->resourceToBuffer.value(resource);
273  if (buffer) {
274  return buffer;
275  }
276 
277  for (ClientBufferIntegration *integration : qAsConst(d->bufferIntegrations)) {
278  ClientBuffer *buffer = integration->createBuffer(resource);
279  if (buffer) {
280  d->registerClientBuffer(buffer);
281  return buffer;
282  }
283  }
284  return nullptr;
285 }
286 
287 void DisplayPrivate::registerClientBuffer(ClientBuffer *buffer)
288 {
289  resourceToBuffer.insert(buffer->resource(), buffer);
290  bufferToListener.insert(buffer, new ClientBufferDestroyListener(q, buffer));
291 }
292 
293 void DisplayPrivate::unregisterClientBuffer(ClientBuffer *buffer)
294 {
295  Q_ASSERT_X(buffer->resource(), "unregisterClientBuffer", "buffer must have valid resource");
296  resourceToBuffer.remove(buffer->resource());
297  delete bufferToListener.take(buffer);
298 }
299 
300 }
void activated(QSocketDescriptor socket, QSocketNotifier::Type type)
void * eglDisplay() const
Definition: display.cpp:231
QVector< SeatInterface * > seats() const
Definition: display.cpp:177
Class holding the Wayland server display loop.
Definition: display.h:47
void setEglDisplay(void *display)
Set the EGL display for this Wayland display.
Definition: display.cpp:221
bool intersects(const QRect &rectangle) const const
bool addSocketName(const QString &name=QString())
Adds a UNIX socket with the specified name to the Wayland display.
Definition: display.cpp:64
ClientConnection * createClient(int fd)
Create a client for the given file descriptor.
Definition: display.cpp:210
The ShmClientBufferIntegration class provides support for wl_shm_buffer buffers.
QString fromUtf8(const char *str, int size)
bool isEmpty() const const
QStringList socketNames() const
Returns the list of socket names that the display listens for client connections. ...
Definition: display.cpp:83
void disconnected(KWaylandServer::ClientConnection *)
Signal emitted when the ClientConnection got disconnected from the server.
ClientConnection * getConnection(wl_client *client)
Gets the ClientConnection for the given client.
Definition: display.cpp:182
Convenient Class which represents a wl_client.
The DrmClientBufferIntegration class provides support for wl_drm client buffers.
ClientBuffer * clientBufferForResource(wl_resource *resource) const
Returns the client buffer with the specified resource.
Definition: display.cpp:270
QAbstractEventDispatcher * eventDispatcher()
bool start()
Start accepting client connections.
Definition: display.cpp:88
The ClientBuffer class represents a client buffer.
Definition: clientbuffer.h:29
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
Q_EMITQ_EMIT
bool addSocketFileDescriptor(int fileDescriptor, const QString &socketName=QString())
Adds a socket with the given fileDescriptor to the Wayland display.
Definition: display.cpp:52
wl_resource * resource() const
Returns the wl_resource for this ClientBuffer.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 16 2021 23:10:14 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.