| 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 | |