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 | |
14 | struct wl_display; |
15 | |
16 | namespace 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 | **/ |
41 | namespace 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 | **/ |
106 | class KWAYLANDCLIENT_EXPORT ConnectionThread : public QObject |
107 | { |
108 | Q_OBJECT |
109 | public: |
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 | |
193 | public 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 | |
210 | Q_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 | |
241 | protected: |
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 | |
248 | private Q_SLOTS: |
249 | /** |
250 | * @internal |
251 | **/ |
252 | void doInitConnection(); |
253 | |
254 | private: |
255 | class Private; |
256 | QScopedPointer<Private> d; |
257 | }; |
258 | } |
259 | } |
260 | |
261 | #endif |
262 | |