1 /*
2     SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
3     SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
4 
5     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6 */
7 
8 #include "pointerconstraints_v1_interface.h"
9 #include "display.h"
10 #include "pointer_interface.h"
11 #include "pointerconstraints_v1_interface_p.h"
12 #include "region_interface_p.h"
13 #include "surface_interface_p.h"
14 
15 namespace KWaylandServer
16 {
17 static const int s_version = 1;
18 
PointerConstraintsV1InterfacePrivate(Display * display)19 PointerConstraintsV1InterfacePrivate::PointerConstraintsV1InterfacePrivate(Display *display)
20     : QtWaylandServer::zwp_pointer_constraints_v1(*display, s_version)
21 {
22 }
23 
regionFromResource(::wl_resource * resource)24 static QRegion regionFromResource(::wl_resource *resource)
25 {
26     const RegionInterface *region = RegionInterface::get(resource);
27     return region ? region->region() : QRegion();
28 }
29 
zwp_pointer_constraints_v1_lock_pointer(Resource * resource,uint32_t id,::wl_resource * surface_resource,::wl_resource * pointer_resource,::wl_resource * region_resource,uint32_t lifetime)30 void PointerConstraintsV1InterfacePrivate::zwp_pointer_constraints_v1_lock_pointer(Resource *resource,
31                                                                                    uint32_t id,
32                                                                                    ::wl_resource *surface_resource,
33                                                                                    ::wl_resource *pointer_resource,
34                                                                                    ::wl_resource *region_resource,
35                                                                                    uint32_t lifetime)
36 {
37     PointerInterface *pointer = PointerInterface::get(pointer_resource);
38     if (!pointer) {
39         wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid pointer");
40         return;
41     }
42 
43     SurfaceInterface *surface = SurfaceInterface::get(surface_resource);
44     if (!surface) {
45         wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid surface");
46         return;
47     }
48 
49     if (surface->lockedPointer() || surface->confinedPointer()) {
50         wl_resource_post_error(resource->handle, error_already_constrained, "the surface is already constrained");
51         return;
52     }
53 
54     if (lifetime != lifetime_oneshot && lifetime != lifetime_persistent) {
55         wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "unknown lifetime %d", lifetime);
56         return;
57     }
58 
59     wl_resource *lockedPointerResource = wl_resource_create(resource->client(), &zwp_locked_pointer_v1_interface, resource->version(), id);
60     if (!lockedPointerResource) {
61         wl_resource_post_no_memory(resource->handle);
62         return;
63     }
64 
65     auto lockedPointer = new LockedPointerV1Interface(LockedPointerV1Interface::LifeTime(lifetime), regionFromResource(region_resource), lockedPointerResource);
66 
67     SurfaceInterfacePrivate::get(surface)->installPointerConstraint(lockedPointer);
68 }
69 
zwp_pointer_constraints_v1_confine_pointer(Resource * resource,uint32_t id,::wl_resource * surface_resource,::wl_resource * pointer_resource,::wl_resource * region_resource,uint32_t lifetime)70 void PointerConstraintsV1InterfacePrivate::zwp_pointer_constraints_v1_confine_pointer(Resource *resource,
71                                                                                       uint32_t id,
72                                                                                       ::wl_resource *surface_resource,
73                                                                                       ::wl_resource *pointer_resource,
74                                                                                       ::wl_resource *region_resource,
75                                                                                       uint32_t lifetime)
76 {
77     PointerInterface *pointer = PointerInterface::get(pointer_resource);
78     if (!pointer) {
79         wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid pointer");
80         return;
81     }
82 
83     SurfaceInterface *surface = SurfaceInterface::get(surface_resource);
84     if (!surface) {
85         wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid surface");
86         return;
87     }
88 
89     if (lifetime != lifetime_oneshot && lifetime != lifetime_persistent) {
90         wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "unknown lifetime %d", lifetime);
91         return;
92     }
93 
94     if (surface->lockedPointer() || surface->confinedPointer()) {
95         wl_resource_post_error(resource->handle, error_already_constrained, "the surface is already constrained");
96         return;
97     }
98 
99     wl_resource *confinedPointerResource = wl_resource_create(resource->client(), &zwp_confined_pointer_v1_interface, resource->version(), id);
100     if (!confinedPointerResource) {
101         wl_resource_post_no_memory(resource->handle);
102         return;
103     }
104 
105     auto confinedPointer =
106         new ConfinedPointerV1Interface(ConfinedPointerV1Interface::LifeTime(lifetime), regionFromResource(region_resource), confinedPointerResource);
107 
108     SurfaceInterfacePrivate::get(surface)->installPointerConstraint(confinedPointer);
109 }
110 
zwp_pointer_constraints_v1_destroy(Resource * resource)111 void PointerConstraintsV1InterfacePrivate::zwp_pointer_constraints_v1_destroy(Resource *resource)
112 {
113     wl_resource_destroy(resource->handle);
114 }
115 
PointerConstraintsV1Interface(Display * display,QObject * parent)116 PointerConstraintsV1Interface::PointerConstraintsV1Interface(Display *display, QObject *parent)
117     : QObject(parent)
118     , d(new PointerConstraintsV1InterfacePrivate(display))
119 {
120 }
121 
~PointerConstraintsV1Interface()122 PointerConstraintsV1Interface::~PointerConstraintsV1Interface()
123 {
124 }
125 
get(LockedPointerV1Interface * q)126 LockedPointerV1InterfacePrivate *LockedPointerV1InterfacePrivate::get(LockedPointerV1Interface *q)
127 {
128     return q->d.data();
129 }
130 
LockedPointerV1InterfacePrivate(LockedPointerV1Interface * q,LockedPointerV1Interface::LifeTime lifeTime,const QRegion & region,::wl_resource * resource)131 LockedPointerV1InterfacePrivate::LockedPointerV1InterfacePrivate(LockedPointerV1Interface *q,
132                                                                  LockedPointerV1Interface::LifeTime lifeTime,
133                                                                  const QRegion &region,
134                                                                  ::wl_resource *resource)
135     : QtWaylandServer::zwp_locked_pointer_v1(resource)
136     , q(q)
137     , lifeTime(lifeTime)
138     , region(region)
139 {
140 }
141 
commit()142 void LockedPointerV1InterfacePrivate::commit()
143 {
144     if (hasPendingRegion) {
145         region = pendingRegion;
146         hasPendingRegion = false;
147         Q_EMIT q->regionChanged();
148     }
149     if (hasPendingHint) {
150         hint = pendingHint;
151         hasPendingHint = false;
152         Q_EMIT q->cursorPositionHintChanged();
153     }
154 }
155 
zwp_locked_pointer_v1_destroy_resource(Resource * resource)156 void LockedPointerV1InterfacePrivate::zwp_locked_pointer_v1_destroy_resource(Resource *resource)
157 {
158     Q_UNUSED(resource)
159     Q_EMIT q->aboutToBeDestroyed();
160     delete q;
161 }
162 
zwp_locked_pointer_v1_destroy(Resource * resource)163 void LockedPointerV1InterfacePrivate::zwp_locked_pointer_v1_destroy(Resource *resource)
164 {
165     wl_resource_destroy(resource->handle);
166 }
167 
zwp_locked_pointer_v1_set_cursor_position_hint(Resource * resource,wl_fixed_t surface_x,wl_fixed_t surface_y)168 void LockedPointerV1InterfacePrivate::zwp_locked_pointer_v1_set_cursor_position_hint(Resource *resource, wl_fixed_t surface_x, wl_fixed_t surface_y)
169 {
170     Q_UNUSED(resource)
171     pendingHint = QPointF(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y));
172     hasPendingHint = true;
173 }
174 
zwp_locked_pointer_v1_set_region(Resource * resource,::wl_resource * region_resource)175 void LockedPointerV1InterfacePrivate::zwp_locked_pointer_v1_set_region(Resource *resource, ::wl_resource *region_resource)
176 {
177     Q_UNUSED(resource)
178     pendingRegion = regionFromResource(region_resource);
179     hasPendingRegion = true;
180 }
181 
LockedPointerV1Interface(LifeTime lifeTime,const QRegion & region,::wl_resource * resource)182 LockedPointerV1Interface::LockedPointerV1Interface(LifeTime lifeTime, const QRegion &region, ::wl_resource *resource)
183     : d(new LockedPointerV1InterfacePrivate(this, lifeTime, region, resource))
184 {
185 }
186 
~LockedPointerV1Interface()187 LockedPointerV1Interface::~LockedPointerV1Interface()
188 {
189 }
190 
lifeTime() const191 LockedPointerV1Interface::LifeTime LockedPointerV1Interface::lifeTime() const
192 {
193     return d->lifeTime;
194 }
195 
region() const196 QRegion LockedPointerV1Interface::region() const
197 {
198     return d->region;
199 }
200 
cursorPositionHint() const201 QPointF LockedPointerV1Interface::cursorPositionHint() const
202 {
203     return d->hint;
204 }
205 
isLocked() const206 bool LockedPointerV1Interface::isLocked() const
207 {
208     return d->isLocked;
209 }
210 
setLocked(bool locked)211 void LockedPointerV1Interface::setLocked(bool locked)
212 {
213     if (d->isLocked == locked) {
214         return;
215     }
216     if (!locked) {
217         d->hint = QPointF(-1, -1);
218     }
219     d->isLocked = locked;
220     if (d->isLocked) {
221         d->send_locked();
222     } else {
223         d->send_unlocked();
224     }
225     Q_EMIT lockedChanged();
226 }
227 
get(ConfinedPointerV1Interface * q)228 ConfinedPointerV1InterfacePrivate *ConfinedPointerV1InterfacePrivate::get(ConfinedPointerV1Interface *q)
229 {
230     return q->d.data();
231 }
232 
ConfinedPointerV1InterfacePrivate(ConfinedPointerV1Interface * q,ConfinedPointerV1Interface::LifeTime lifeTime,const QRegion & region,::wl_resource * resource)233 ConfinedPointerV1InterfacePrivate::ConfinedPointerV1InterfacePrivate(ConfinedPointerV1Interface *q,
234                                                                      ConfinedPointerV1Interface::LifeTime lifeTime,
235                                                                      const QRegion &region,
236                                                                      ::wl_resource *resource)
237     : QtWaylandServer::zwp_confined_pointer_v1(resource)
238     , q(q)
239     , lifeTime(lifeTime)
240     , region(region)
241 {
242 }
243 
commit()244 void ConfinedPointerV1InterfacePrivate::commit()
245 {
246     if (hasPendingRegion) {
247         region = pendingRegion;
248         hasPendingRegion = false;
249         Q_EMIT q->regionChanged();
250     }
251 }
252 
zwp_confined_pointer_v1_destroy_resource(Resource * resource)253 void ConfinedPointerV1InterfacePrivate::zwp_confined_pointer_v1_destroy_resource(Resource *resource)
254 {
255     Q_UNUSED(resource)
256     delete q;
257 }
258 
zwp_confined_pointer_v1_destroy(Resource * resource)259 void ConfinedPointerV1InterfacePrivate::zwp_confined_pointer_v1_destroy(Resource *resource)
260 {
261     wl_resource_destroy(resource->handle);
262 }
263 
zwp_confined_pointer_v1_set_region(Resource * resource,::wl_resource * region_resource)264 void ConfinedPointerV1InterfacePrivate::zwp_confined_pointer_v1_set_region(Resource *resource, ::wl_resource *region_resource)
265 {
266     Q_UNUSED(resource)
267     pendingRegion = regionFromResource(region_resource);
268     hasPendingRegion = true;
269 }
270 
ConfinedPointerV1Interface(LifeTime lifeTime,const QRegion & region,::wl_resource * resource)271 ConfinedPointerV1Interface::ConfinedPointerV1Interface(LifeTime lifeTime, const QRegion &region, ::wl_resource *resource)
272     : d(new ConfinedPointerV1InterfacePrivate(this, lifeTime, region, resource))
273 {
274 }
275 
~ConfinedPointerV1Interface()276 ConfinedPointerV1Interface::~ConfinedPointerV1Interface()
277 {
278 }
279 
lifeTime() const280 ConfinedPointerV1Interface::LifeTime ConfinedPointerV1Interface::lifeTime() const
281 {
282     return d->lifeTime;
283 }
284 
region() const285 QRegion ConfinedPointerV1Interface::region() const
286 {
287     return d->region;
288 }
289 
isConfined() const290 bool ConfinedPointerV1Interface::isConfined() const
291 {
292     return d->isConfined;
293 }
294 
setConfined(bool confined)295 void ConfinedPointerV1Interface::setConfined(bool confined)
296 {
297     if (d->isConfined == confined) {
298         return;
299     }
300     d->isConfined = confined;
301     if (d->isConfined) {
302         d->send_confined();
303     } else {
304         d->send_unconfined();
305     }
306     Q_EMIT confinedChanged();
307 }
308 
309 } // namespace KWaylandServer
310