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
14QT_BEGIN_NAMESPACE
15
16class QWaylandClientPrivate : public QObjectPrivate
17{
18public:
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 */
80QWaylandClient::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 */
96QWaylandClient::~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 */
111QWaylandClient *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 */
147QWaylandCompositor *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 */
157wl_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 */
176qint64 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 */
195qint64 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 */
214qint64 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 */
230void 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 */
246void QWaylandClient::close()
247{
248 Q_D(QWaylandClient);
249 d->compositor->destroyClient(client: this);
250}
251
252QWaylandClient::TextInputProtocols QWaylandClient::textInputProtocols() const
253{
254 Q_D(const QWaylandClient);
255 return d->mTextInputProtocols;
256}
257
258void QWaylandClient::setTextInputProtocols(TextInputProtocols p)
259{
260 Q_D(QWaylandClient);
261 if (d->mTextInputProtocols != p)
262 d->mTextInputProtocols = p;
263}
264
265QT_END_NAMESPACE
266
267#include "moc_qwaylandclient.cpp"
268
269

source code of qtwayland/src/compositor/compositor_api/qwaylandclient.cpp