1 | // Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com> |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "qwaylandclient.h" |
5 | #include <QtCore/private/qobject_p.h> |
6 | |
7 | #include <QtWaylandCompositor/QWaylandCompositor> |
8 | #include <QtWaylandCompositor/private/qwaylandcompositor_p.h> |
9 | |
10 | |
11 | #include <wayland-server-core.h> |
12 | #include <wayland-util.h> |
13 | |
14 | QT_BEGIN_NAMESPACE |
15 | |
16 | class QWaylandClientPrivate : public QObjectPrivate |
17 | { |
18 | public: |
19 | QWaylandClientPrivate(QWaylandCompositor *compositor, wl_client *_client) |
20 | : compositor(compositor) |
21 | , client(_client) |
22 | { |
23 | // Save client credentials |
24 | wl_client_get_credentials(client, pid: &pid, uid: &uid, gid: &gid); |
25 | } |
26 | |
27 | ~QWaylandClientPrivate() override |
28 | { |
29 | } |
30 | |
31 | static void client_destroy_callback(wl_listener *listener, void *data) |
32 | { |
33 | Q_UNUSED(data); |
34 | |
35 | QWaylandClient *client = reinterpret_cast<Listener *>(listener)->parent; |
36 | Q_ASSERT(client != nullptr); |
37 | delete client; |
38 | } |
39 | |
40 | QWaylandCompositor *compositor = nullptr; |
41 | wl_client *client = nullptr; |
42 | |
43 | uid_t uid; |
44 | gid_t gid; |
45 | pid_t pid; |
46 | |
47 | struct Listener { |
48 | wl_listener listener; |
49 | QWaylandClient *parent = nullptr; |
50 | }; |
51 | Listener listener; |
52 | |
53 | QWaylandClient::TextInputProtocols mTextInputProtocols = QWaylandClient::NoProtocol; |
54 | }; |
55 | |
56 | /*! |
57 | * \qmltype WaylandClient |
58 | * \instantiates QWaylandClient |
59 | * \inqmlmodule QtWayland.Compositor |
60 | * \since 5.8 |
61 | * \brief Represents a client connecting to the WaylandCompositor. |
62 | * |
63 | * This type represents a client connecting to the compositor using the Wayland protocol. |
64 | * It corresponds to the Wayland interface wl_client. |
65 | */ |
66 | |
67 | /*! |
68 | * \class QWaylandClient |
69 | * \inmodule QtWaylandCompositor |
70 | * \since 5.8 |
71 | * \brief The QWaylandClient class represents a client connecting to the QWaylandCompositor. |
72 | * |
73 | * This class corresponds to a client connecting to the compositor using the Wayland protocol. |
74 | * It corresponds to the Wayland interface wl_client. |
75 | */ |
76 | |
77 | /*! |
78 | * Constructs a QWaylandClient for the \a compositor and the Wayland \a client. |
79 | */ |
80 | QWaylandClient::QWaylandClient(QWaylandCompositor *compositor, wl_client *client) |
81 | : QObject(*new QWaylandClientPrivate(compositor, client)) |
82 | { |
83 | Q_D(QWaylandClient); |
84 | |
85 | // Destroy wrapper when the client goes away |
86 | d->listener.parent = this; |
87 | d->listener.listener.notify = QWaylandClientPrivate::client_destroy_callback; |
88 | wl_client_add_destroy_listener(client, listener: &d->listener.listener); |
89 | |
90 | QWaylandCompositorPrivate::get(compositor)->addClient(client: this); |
91 | } |
92 | |
93 | /*! |
94 | * Destroys the QWaylandClient. |
95 | */ |
96 | QWaylandClient::~QWaylandClient() |
97 | { |
98 | Q_D(QWaylandClient); |
99 | |
100 | // Remove listener from signal |
101 | wl_list_remove(elm: &d->listener.listener.link); |
102 | |
103 | QWaylandCompositorPrivate::get(compositor: d->compositor)->removeClient(client: this); |
104 | } |
105 | |
106 | /*! |
107 | * Returns the QWaylandClient corresponding to the Wayland client \a wlClient and \a compositor. |
108 | * If a QWaylandClient has not already been created for a client, it is |
109 | * created and returned. |
110 | */ |
111 | QWaylandClient *QWaylandClient::fromWlClient(QWaylandCompositor *compositor, wl_client *wlClient) |
112 | { |
113 | if (!wlClient) |
114 | return nullptr; |
115 | |
116 | QWaylandClient *client = nullptr; |
117 | |
118 | wl_listener *l = wl_client_get_destroy_listener(client: wlClient, |
119 | notify: QWaylandClientPrivate::client_destroy_callback); |
120 | if (l) |
121 | client = reinterpret_cast<QWaylandClientPrivate::Listener *>( |
122 | wl_container_of(l, (QWaylandClientPrivate::Listener *)nullptr, listener))->parent; |
123 | |
124 | if (!client) { |
125 | // The original idea was to create QWaylandClient instances when |
126 | // a client bound wl_compositor, but it's legal for a client to |
127 | // bind several times resulting in multiple QWaylandClient |
128 | // instances for the same wl_client therefore we create it from |
129 | // here on demand |
130 | client = new QWaylandClient(compositor, wlClient); |
131 | } |
132 | |
133 | return client; |
134 | } |
135 | |
136 | /*! |
137 | * \qmlproperty WaylandCompositor QtWayland.Compositor::WaylandClient::compositor |
138 | * |
139 | * This property holds the compositor of this WaylandClient. |
140 | */ |
141 | |
142 | /*! |
143 | * \property QWaylandClient::compositor |
144 | * |
145 | * This property holds the compositor of this QWaylandClient. |
146 | */ |
147 | QWaylandCompositor *QWaylandClient::compositor() const |
148 | { |
149 | Q_D(const QWaylandClient); |
150 | |
151 | return d->compositor; |
152 | } |
153 | |
154 | /*! |
155 | * Returns the Wayland client of this QWaylandClient. |
156 | */ |
157 | wl_client *QWaylandClient::client() const |
158 | { |
159 | Q_D(const QWaylandClient); |
160 | |
161 | return d->client; |
162 | } |
163 | |
164 | /*! |
165 | * \qmlproperty int QtWayland.Compositor::WaylandClient::userId |
166 | * |
167 | * This property holds the user id of this WaylandClient. |
168 | */ |
169 | |
170 | /*! |
171 | * \property QWaylandClient::userId |
172 | * \readonly |
173 | * |
174 | * This property holds the user id of this QWaylandClient. |
175 | */ |
176 | qint64 QWaylandClient::userId() const |
177 | { |
178 | Q_D(const QWaylandClient); |
179 | |
180 | return d->uid; |
181 | } |
182 | |
183 | /*! |
184 | * \qmlproperty int QtWayland.Compositor::WaylandClient::groupId |
185 | * \readonly |
186 | * |
187 | * This property holds the group id of this WaylandClient. |
188 | */ |
189 | |
190 | /*! |
191 | * \property QWaylandClient::groupId |
192 | * |
193 | * This property holds the group id of this QWaylandClient. |
194 | */ |
195 | qint64 QWaylandClient::groupId() const |
196 | { |
197 | Q_D(const QWaylandClient); |
198 | |
199 | return d->gid; |
200 | } |
201 | |
202 | /*! |
203 | * \qmlproperty int QtWayland.Compositor::WaylandClient::processId |
204 | * \readonly |
205 | * |
206 | * This property holds the process id of this WaylandClient. |
207 | */ |
208 | |
209 | /*! |
210 | * \property QWaylandClient::processId |
211 | * |
212 | * This property holds the process id of this QWaylandClient. |
213 | */ |
214 | qint64 QWaylandClient::processId() const |
215 | { |
216 | Q_D(const QWaylandClient); |
217 | |
218 | return d->pid; |
219 | } |
220 | |
221 | /*! |
222 | * \qmlmethod void QtWayland.Compositor::WaylandClient::kill(signal) |
223 | * |
224 | * Kills the client with the specified \a signal. |
225 | */ |
226 | |
227 | /*! |
228 | * Kills the client with the specified \a signal. |
229 | */ |
230 | void QWaylandClient::kill(int signal) |
231 | { |
232 | Q_D(QWaylandClient); |
233 | |
234 | ::kill(pid: d->pid, sig: signal); |
235 | } |
236 | |
237 | /*! |
238 | * \qmlmethod void QtWayland.Compositor::WaylandClient::close() |
239 | * |
240 | * Closes the client |
241 | */ |
242 | |
243 | /*! |
244 | * Closes the client. |
245 | */ |
246 | void QWaylandClient::close() |
247 | { |
248 | Q_D(QWaylandClient); |
249 | d->compositor->destroyClient(client: this); |
250 | } |
251 | |
252 | QWaylandClient::TextInputProtocols QWaylandClient::textInputProtocols() const |
253 | { |
254 | Q_D(const QWaylandClient); |
255 | return d->mTextInputProtocols; |
256 | } |
257 | |
258 | void QWaylandClient::setTextInputProtocols(TextInputProtocols p) |
259 | { |
260 | Q_D(QWaylandClient); |
261 | if (d->mTextInputProtocols != p) |
262 | d->mTextInputProtocols = p; |
263 | } |
264 | |
265 | QT_END_NAMESPACE |
266 | |
267 | #include "moc_qwaylandclient.cpp" |
268 | |
269 | |