1/*
2 SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5*/
6#ifndef WAYLAND_CONNECTION_THREAD_H
7#define WAYLAND_CONNECTION_THREAD_H
8
9#include <QList>
10#include <QObject>
11
12#include "KWayland/Client/kwaylandclient_export.h"
13
14struct wl_display;
15
16namespace KWayland
17{
18/**
19 * @short KWayland Client.
20 *
21 * This namespace groups all classes related to the Client module.
22 *
23 * The main entry point into the KWayland::Client API is the ConnectionThread class.
24 * It allows to create a Wayland client connection either in a native way or wrap a
25 * connection created by the QtWayland QPA plugin.
26 *
27 * KWayland::Client provides one the one hand a low-level API to interact with the
28 * Wayland API, on the other hand an easy to use convenience API. Each class directly
29 * relates to a low-level Wayland type and allows direct casting into the type.
30 *
31 * On the convenience side KWayland::Client allows easy creation of objects, signals
32 * emitted for Wayland events and easy conversion from Qt to Wayland types.
33 *
34 * Once one has a ConnectionThread created, it's possible to setup a Registry to
35 * get a listing of all registered globals. For each global the Registry provides a convenience
36 * method to create the resource.
37 *
38 * @see ConnectionThread
39 * @see Registry
40 **/
41namespace Client
42{
43/**
44 * @short Creates and manages the connection to a Wayland server.
45 *
46 * The purpose of this class is to create the connection to a Wayland server
47 * and to manage it. As the name suggests it's intended to move instances of
48 * this class into a dedicated thread. This also means that this class doesn't
49 * inherit QThread. In order to use it in a threaded way one needs to create a
50 * QThread and move the object there:
51 *
52 * @code
53 * ConnectionThread *connection = new ConnectionThread;
54 * QThread *thread = new QThread;
55 * connection->moveToThread(thread);
56 * thread->start();
57 * @endcode
58 *
59 * To finalize the initialization of the connection one needs to call @link ::initConnection @endlink.
60 * This starts an asynchronous connection initialization. In case the initialization
61 * succeeds the signal @link ::connected @endlink will be emitted, otherwise @link ::failed @endlink will
62 * be emitted:
63 *
64 * @code
65 * connect(connection, &ConnectionThread::connected, [connection] {
66 * qDebug() << "Successfully connected to Wayland server at socket:" << connection->socketName();
67 * });
68 * connect(connection, &ConnectionThread::failed, [connection] {
69 * qDebug() << "Failed to connect to Wayland server at socket:" << connection->socketName();
70 * });
71 * connection->initConnection();
72 * @endcode
73 *
74 * This class is also responsible for dispatching events. Whenever new data is available on
75 * the Wayland socket, it will be dispatched and the signal @link ::eventsRead @endlink is emitted.
76 * This allows further event queues in other threads to also dispatch their events.
77 *
78 * Furthermore this class flushes the Wayland connection whenever the QAbstractEventDispatcher
79 * is about to block.
80 *
81 * To disconnect the connection to the Wayland server one should delete the instance of this
82 * class and quit the dedicated thread:
83 *
84 * @code
85 * connection->deleteLater();
86 * thread->quit();
87 * thread->wait();
88 * @endcode
89 *
90 * In addition the ConnectionThread provides integration with QtWayland QPA plugin. For that
91 * it provides a static factory method:
92 *
93 * @code
94 * auto connection = ConnectionThread::fromApplication();
95 * @endcode
96 *
97 * The semantics of the ConnectionThread are slightly changed if it's integrated with QtWayland.
98 * The ConnectionThread does not hold the connection, does not emit connected or released signals
99 * (one can safely assume that the connection is valid when integrating with the Qt application),
100 * does not dispatch events. Given that the use case of the ConnectionThread is rather limited to
101 * a convenient API around wl_display to allow easily setup an own Registry in a QtWayland powered
102 * application. Also moving the ConnectionThread to a different thread is not necessarily recommended
103 * in that case as QtWayland holds it's connection in an own thread anyway.
104 *
105 **/
106class KWAYLANDCLIENT_EXPORT ConnectionThread : public QObject
107{
108 Q_OBJECT
109public:
110 explicit ConnectionThread(QObject *parent = nullptr);
111 ~ConnectionThread() override;
112
113 /**
114 * Creates a ConnectionThread for the used QGuiApplication.
115 * This is an integration feature for QtWayland. On non-wayland platforms this method returns
116 * @c nullptr.
117 *
118 * The returned ConnectionThread will be fully setup, which means it manages a wl_display.
119 * There is no need to initConnection and the connected or failed signals won't be emitted.
120 * When the created ConnectionThread gets destroyed the managed wl_display won't be disconnected
121 * as that's managed by Qt.
122 *
123 * The returned ConnectionThread is not able to detect (protocol) error. The signal
124 * {@link errorOccurred} won't be emitted, {@link hasError} will return @c false, even if the
125 * actual connection held by QtWayland is on error. The behavior of QtWayland is to exit the
126 * application on error.
127 *
128 * @since 5.4
129 **/
130 static ConnectionThread *fromApplication(QObject *parent = nullptr);
131
132 /**
133 * The display this ConnectionThread is connected to.
134 * As long as there is no connection this method returns @c null.
135 * @see initConnection
136 **/
137 wl_display *display();
138 /**
139 * @returns the name of the socket it connects to.
140 **/
141 QString socketName() const;
142 /**
143 * Sets the @p socketName to connect to.
144 * Only applies if called before calling initConnection.
145 * The default socket name is derived from environment variable WAYLAND_DISPLAY
146 * and if not set is hard coded to "wayland-0".
147 *
148 * The socket name will be ignored if a file descriptor has been set through @link setSocketFd @endlink.
149 *
150 * @see setSocketFd
151 **/
152 void setSocketName(const QString &socketName);
153 /**
154 * Sets the socket @p fd to connect to.
155 * Only applies if called before calling initConnection.
156 * If this method is invoked, the connection will be created on the file descriptor
157 * and not on the socket name passed through @link setSocketName @endlink or through the
158 * default environment variable WAYLAND_DISPLAY.
159 * @see setSocketName
160 **/
161 void setSocketFd(int fd);
162
163 /**
164 * Trigger a blocking roundtrip to the Wayland server. Ensures that all events are processed
165 * before returning to the event loop.
166 *
167 * @since 5.4
168 **/
169 void roundtrip();
170
171 /**
172 * @returns whether the Wayland connection experienced an error
173 * @see errorCode
174 * @see errorOccurred
175 * @since 5.23
176 **/
177 bool hasError() const;
178
179 /**
180 * @returns the error code of the last occurred error or @c 0 if the connection doesn't have an error
181 * @see hasError
182 * @see errorOccurred
183 * @since 5.23
184 **/
185 int errorCode() const;
186
187 /**
188 * @returns all connections created in this application
189 * @since 5.37
190 **/
191 static QList<ConnectionThread *> connections();
192
193public Q_SLOTS:
194 /**
195 * Initializes the connection in an asynchronous way.
196 * In case the connection gets established the signal @link ::connected @endlink will be
197 * emitted, on failure the signal @link ::failed @endlink will be emitted.
198 *
199 * @see connected
200 * @see failed
201 **/
202 void initConnection();
203
204 /**
205 * Explicitly flush the Wayland display.
206 * @since 5.3
207 **/
208 void flush();
209
210Q_SIGNALS:
211 /**
212 * Emitted once a connection to a Wayland server is established.
213 * Normally emitted after invoking initConnection(), but might also be
214 * emitted after re-connecting to another server.
215 **/
216 void connected();
217 /**
218 * Emitted if connecting to a Wayland server failed.
219 **/
220 void failed();
221 /**
222 * Emitted whenever new events are ready to be read.
223 **/
224 void eventsRead();
225 /**
226 * Emitted if the Wayland server connection dies.
227 * If the socket reappears, it is tried to reconnect.
228 **/
229 void connectionDied();
230 /**
231 * The Wayland connection experienced a fatal error.
232 * The ConnectionThread is no longer valid, no requests may be sent.
233 * This has the same effects as {@link connectionDied}.
234 *
235 * @see hasError
236 * @see errorCode
237 * @since 5.23
238 **/
239 void errorOccurred();
240
241protected:
242 /*
243 * Creates a connection thread from an existing wl_display object
244 * @see ConnectionThread::fromApplication
245 */
246 explicit ConnectionThread(wl_display *display, QObject *parent);
247
248private Q_SLOTS:
249 /**
250 * @internal
251 **/
252 void doInitConnection();
253
254private:
255 class Private;
256 QScopedPointer<Private> d;
257};
258}
259}
260
261#endif
262

source code of kwayland/src/client/connection_thread.h