File indexing completed on 2024-11-10 04:57:30

0001 /*
0002     SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
0003     SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0006 */
0007 
0008 #include "pointerconstraints_v1.h"
0009 #include "display.h"
0010 #include "pointer.h"
0011 #include "pointerconstraints_v1_p.h"
0012 #include "region_p.h"
0013 #include "surface_p.h"
0014 
0015 namespace KWin
0016 {
0017 static const int s_version = 1;
0018 
0019 static QRegion mapScaleOverride(const QRegion &region, qreal scaleOverride)
0020 {
0021     QRegion out;
0022     for (const QRect &rect : region) {
0023         out += QRect(rect.topLeft() / scaleOverride, rect.size() / scaleOverride);
0024     }
0025     return out;
0026 }
0027 
0028 PointerConstraintsV1InterfacePrivate::PointerConstraintsV1InterfacePrivate(Display *display)
0029     : QtWaylandServer::zwp_pointer_constraints_v1(*display, s_version)
0030 {
0031 }
0032 
0033 static QRegion regionFromResource(::wl_resource *resource)
0034 {
0035     const RegionInterface *region = RegionInterface::get(resource);
0036     return region ? region->region() : QRegion();
0037 }
0038 
0039 void PointerConstraintsV1InterfacePrivate::zwp_pointer_constraints_v1_lock_pointer(Resource *resource,
0040                                                                                    uint32_t id,
0041                                                                                    ::wl_resource *surface_resource,
0042                                                                                    ::wl_resource *pointer_resource,
0043                                                                                    ::wl_resource *region_resource,
0044                                                                                    uint32_t lifetime)
0045 {
0046     PointerInterface *pointer = PointerInterface::get(pointer_resource);
0047     if (!pointer) {
0048         wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid pointer");
0049         return;
0050     }
0051 
0052     SurfaceInterface *surface = SurfaceInterface::get(surface_resource);
0053     if (!surface) {
0054         wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid surface");
0055         return;
0056     }
0057 
0058     if (surface->lockedPointer() || surface->confinedPointer()) {
0059         wl_resource_post_error(resource->handle, error_already_constrained, "the surface is already constrained");
0060         return;
0061     }
0062 
0063     if (lifetime != lifetime_oneshot && lifetime != lifetime_persistent) {
0064         wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "unknown lifetime %d", lifetime);
0065         return;
0066     }
0067 
0068     wl_resource *lockedPointerResource = wl_resource_create(resource->client(), &zwp_locked_pointer_v1_interface, resource->version(), id);
0069     if (!lockedPointerResource) {
0070         wl_resource_post_no_memory(resource->handle);
0071         return;
0072     }
0073 
0074     new LockedPointerV1Interface(surface, LockedPointerV1Interface::LifeTime(lifetime), regionFromResource(region_resource), lockedPointerResource);
0075 }
0076 
0077 void PointerConstraintsV1InterfacePrivate::zwp_pointer_constraints_v1_confine_pointer(Resource *resource,
0078                                                                                       uint32_t id,
0079                                                                                       ::wl_resource *surface_resource,
0080                                                                                       ::wl_resource *pointer_resource,
0081                                                                                       ::wl_resource *region_resource,
0082                                                                                       uint32_t lifetime)
0083 {
0084     PointerInterface *pointer = PointerInterface::get(pointer_resource);
0085     if (!pointer) {
0086         wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid pointer");
0087         return;
0088     }
0089 
0090     SurfaceInterface *surface = SurfaceInterface::get(surface_resource);
0091     if (!surface) {
0092         wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid surface");
0093         return;
0094     }
0095 
0096     if (lifetime != lifetime_oneshot && lifetime != lifetime_persistent) {
0097         wl_resource_post_error(resource->handle, WL_DISPLAY_ERROR_INVALID_OBJECT, "unknown lifetime %d", lifetime);
0098         return;
0099     }
0100 
0101     if (surface->lockedPointer() || surface->confinedPointer()) {
0102         wl_resource_post_error(resource->handle, error_already_constrained, "the surface is already constrained");
0103         return;
0104     }
0105 
0106     wl_resource *confinedPointerResource = wl_resource_create(resource->client(), &zwp_confined_pointer_v1_interface, resource->version(), id);
0107     if (!confinedPointerResource) {
0108         wl_resource_post_no_memory(resource->handle);
0109         return;
0110     }
0111 
0112     new ConfinedPointerV1Interface(surface, ConfinedPointerV1Interface::LifeTime(lifetime), regionFromResource(region_resource), confinedPointerResource);
0113 }
0114 
0115 void PointerConstraintsV1InterfacePrivate::zwp_pointer_constraints_v1_destroy(Resource *resource)
0116 {
0117     wl_resource_destroy(resource->handle);
0118 }
0119 
0120 PointerConstraintsV1Interface::PointerConstraintsV1Interface(Display *display, QObject *parent)
0121     : QObject(parent)
0122     , d(new PointerConstraintsV1InterfacePrivate(display))
0123 {
0124 }
0125 
0126 PointerConstraintsV1Interface::~PointerConstraintsV1Interface()
0127 {
0128 }
0129 
0130 LockedPointerV1InterfacePrivate *LockedPointerV1InterfacePrivate::get(LockedPointerV1Interface *q)
0131 {
0132     return q->d.get();
0133 }
0134 
0135 LockedPointerV1InterfacePrivate::LockedPointerV1InterfacePrivate(LockedPointerV1Interface *q,
0136                                                                  SurfaceInterface *surface,
0137                                                                  LockedPointerV1Interface::LifeTime lifeTime,
0138                                                                  const QRegion &region,
0139                                                                  ::wl_resource *resource)
0140     : QtWaylandServer::zwp_locked_pointer_v1(resource)
0141     , SurfaceExtension(surface)
0142     , q(q)
0143     , surface(surface)
0144     , lifeTime(lifeTime)
0145 {
0146     pending.region = region;
0147 
0148     apply(&pending);
0149 
0150     pending = LockedPointerV1Commit{};
0151 }
0152 
0153 void LockedPointerV1InterfacePrivate::apply(LockedPointerV1Commit *commit)
0154 {
0155     const QRegion oldRegion = effectiveRegion;
0156     const QPointF oldHint = hint;
0157 
0158     if (commit->region.has_value()) {
0159         region = mapScaleOverride(commit->region.value(), surface->scaleOverride());
0160     }
0161     if (commit->hint.has_value()) {
0162         hint = commit->hint.value() / surface->scaleOverride();
0163     }
0164 
0165     effectiveRegion = surface->input();
0166     if (!region.isEmpty()) {
0167         effectiveRegion &= region;
0168     }
0169 
0170     if (oldRegion != effectiveRegion) {
0171         Q_EMIT q->regionChanged();
0172     }
0173     if (oldHint != hint) {
0174         Q_EMIT q->cursorPositionHintChanged();
0175     }
0176 }
0177 
0178 void LockedPointerV1InterfacePrivate::zwp_locked_pointer_v1_destroy_resource(Resource *resource)
0179 {
0180     Q_EMIT q->aboutToBeDestroyed();
0181     delete q;
0182 }
0183 
0184 void LockedPointerV1InterfacePrivate::zwp_locked_pointer_v1_destroy(Resource *resource)
0185 {
0186     wl_resource_destroy(resource->handle);
0187 }
0188 
0189 void LockedPointerV1InterfacePrivate::zwp_locked_pointer_v1_set_cursor_position_hint(Resource *resource, wl_fixed_t surface_x, wl_fixed_t surface_y)
0190 {
0191     pending.hint = QPointF(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y));
0192 }
0193 
0194 void LockedPointerV1InterfacePrivate::zwp_locked_pointer_v1_set_region(Resource *resource, ::wl_resource *region_resource)
0195 {
0196     pending.region = regionFromResource(region_resource);
0197 }
0198 
0199 LockedPointerV1Interface::LockedPointerV1Interface(SurfaceInterface *surface,
0200                                                    LifeTime lifeTime,
0201                                                    const QRegion &region,
0202                                                    ::wl_resource *resource)
0203     : d(new LockedPointerV1InterfacePrivate(this, surface, lifeTime, region, resource))
0204 {
0205     SurfaceInterfacePrivate::get(surface)->installPointerConstraint(this);
0206 }
0207 
0208 LockedPointerV1Interface::~LockedPointerV1Interface()
0209 {
0210 }
0211 
0212 LockedPointerV1Interface::LifeTime LockedPointerV1Interface::lifeTime() const
0213 {
0214     return d->lifeTime;
0215 }
0216 
0217 QRegion LockedPointerV1Interface::region() const
0218 {
0219     return d->effectiveRegion;
0220 }
0221 
0222 QPointF LockedPointerV1Interface::cursorPositionHint() const
0223 {
0224     return d->hint;
0225 }
0226 
0227 bool LockedPointerV1Interface::isLocked() const
0228 {
0229     return d->isLocked;
0230 }
0231 
0232 void LockedPointerV1Interface::setLocked(bool locked)
0233 {
0234     if (d->isLocked == locked) {
0235         return;
0236     }
0237     if (!locked) {
0238         d->hint = QPointF(-1, -1);
0239     }
0240     d->isLocked = locked;
0241     if (d->isLocked) {
0242         d->send_locked();
0243     } else {
0244         d->send_unlocked();
0245     }
0246     Q_EMIT lockedChanged();
0247 }
0248 
0249 ConfinedPointerV1InterfacePrivate *ConfinedPointerV1InterfacePrivate::get(ConfinedPointerV1Interface *q)
0250 {
0251     return q->d.get();
0252 }
0253 
0254 ConfinedPointerV1InterfacePrivate::ConfinedPointerV1InterfacePrivate(ConfinedPointerV1Interface *q,
0255                                                                      SurfaceInterface *surface,
0256                                                                      ConfinedPointerV1Interface::LifeTime lifeTime,
0257                                                                      const QRegion &region,
0258                                                                      ::wl_resource *resource)
0259     : QtWaylandServer::zwp_confined_pointer_v1(resource)
0260     , SurfaceExtension(surface)
0261     , q(q)
0262     , surface(surface)
0263     , lifeTime(lifeTime)
0264 {
0265     pending.region = region;
0266 
0267     apply(&pending);
0268 
0269     pending = ConfinedPointerV1Commit{};
0270 }
0271 
0272 void ConfinedPointerV1InterfacePrivate::apply(ConfinedPointerV1Commit *commit)
0273 {
0274     const QRegion oldRegion = effectiveRegion;
0275 
0276     if (commit->region.has_value()) {
0277         region = mapScaleOverride(commit->region.value(), surface->scaleOverride());
0278     }
0279 
0280     effectiveRegion = surface->input();
0281     if (!region.isEmpty()) {
0282         effectiveRegion &= region;
0283     }
0284 
0285     if (oldRegion != effectiveRegion) {
0286         Q_EMIT q->regionChanged();
0287     }
0288 }
0289 
0290 void ConfinedPointerV1InterfacePrivate::zwp_confined_pointer_v1_destroy_resource(Resource *resource)
0291 {
0292     delete q;
0293 }
0294 
0295 void ConfinedPointerV1InterfacePrivate::zwp_confined_pointer_v1_destroy(Resource *resource)
0296 {
0297     wl_resource_destroy(resource->handle);
0298 }
0299 
0300 void ConfinedPointerV1InterfacePrivate::zwp_confined_pointer_v1_set_region(Resource *resource, ::wl_resource *region_resource)
0301 {
0302     pending.region = regionFromResource(region_resource);
0303 }
0304 
0305 ConfinedPointerV1Interface::ConfinedPointerV1Interface(SurfaceInterface *surface,
0306                                                        LifeTime lifeTime,
0307                                                        const QRegion &region,
0308                                                        ::wl_resource *resource)
0309     : d(new ConfinedPointerV1InterfacePrivate(this, surface, lifeTime, region, resource))
0310 {
0311     SurfaceInterfacePrivate::get(surface)->installPointerConstraint(this);
0312 }
0313 
0314 ConfinedPointerV1Interface::~ConfinedPointerV1Interface()
0315 {
0316 }
0317 
0318 ConfinedPointerV1Interface::LifeTime ConfinedPointerV1Interface::lifeTime() const
0319 {
0320     return d->lifeTime;
0321 }
0322 
0323 QRegion ConfinedPointerV1Interface::region() const
0324 {
0325     return d->effectiveRegion;
0326 }
0327 
0328 bool ConfinedPointerV1Interface::isConfined() const
0329 {
0330     return d->isConfined;
0331 }
0332 
0333 void ConfinedPointerV1Interface::setConfined(bool confined)
0334 {
0335     if (d->isConfined == confined) {
0336         return;
0337     }
0338     d->isConfined = confined;
0339     if (d->isConfined) {
0340         d->send_confined();
0341     } else {
0342         d->send_unconfined();
0343     }
0344     Q_EMIT confinedChanged();
0345 }
0346 
0347 } // namespace KWin
0348 
0349 #include "moc_pointerconstraints_v1.cpp"