| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/exo/wayland/zwp_pointer_constraints.h" |
| |
| #include <pointer-constraints-unstable-v1-server-protocol.h> |
| #include <wayland-server-core.h> |
| #include <wayland-server-protocol-core.h> |
| |
| #include <cstdarg> |
| #include <memory> |
| |
| #include "components/exo/pointer.h" |
| #include "components/exo/pointer_constraint_delegate.h" |
| #include "components/exo/wayland/server_util.h" |
| #include "third_party/skia/include/core/SkRegion.h" |
| |
| namespace exo { |
| namespace wayland { |
| |
| namespace { |
| |
| // Implements a PointerConstraintDelegate in terms of the zwp_locked_pointer |
| // Wayland protocol. |
| // |
| // Lifetime note: The underlying Wayland protocol gives control over this |
| // object's lifetime to the client. However, it's possible that its |
| // dependencies could be destroyed prior to the client destroying it. |
| // At this point we consider the object "defunct" and its |surface_| member |
| // to be potentially dangling. |pointer_| is correctly nulled when appropriate. |
| class WaylandPointerConstraintDelegate : public PointerConstraintDelegate { |
| public: |
| WaylandPointerConstraintDelegate(wl_resource* constraint_resource, |
| Surface* surface, |
| Pointer* pointer, |
| SkRegion* region, |
| uint32_t lifetime) |
| : constraint_resource_(constraint_resource), |
| pointer_(pointer), |
| surface_(surface), |
| is_persistent_(lifetime == |
| ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT) { |
| pointer->ConstrainPointer(this); |
| } |
| |
| ~WaylandPointerConstraintDelegate() override { |
| if (pointer_) { |
| pointer_->OnPointerConstraintDelegateDestroying(this); |
| pointer_ = nullptr; |
| } |
| } |
| |
| // PointerConstraintDelegate:: |
| void OnConstraintActivated() override { SendLocked(); } |
| void OnAlreadyConstrained() override { |
| wl_resource_post_error( |
| constraint_resource_, |
| ZWP_POINTER_CONSTRAINTS_V1_ERROR_ALREADY_CONSTRAINED, |
| "A pointer constraint was already requested for this wl_pointer " |
| "on this wl_surface."); |
| } |
| void OnConstraintBroken() override { SendUnlocked(); } |
| bool IsPersistent() override { return is_persistent_; } |
| Surface* GetConstrainedSurface() override { return surface_; } |
| void OnDefunct() override { pointer_ = nullptr; } |
| |
| private: |
| // Inform the client of the state of the lock. |
| void SendLocked() { |
| VLOG(1) << "send_locked(" << constraint_resource_ << ")"; |
| zwp_locked_pointer_v1_send_locked(constraint_resource_); |
| } |
| |
| void SendUnlocked() { |
| VLOG(1) << "send_unlocked(" << constraint_resource_ << ")"; |
| zwp_locked_pointer_v1_send_unlocked(constraint_resource_); |
| } |
| |
| wl_resource* const constraint_resource_; |
| Pointer* pointer_; |
| Surface* const surface_; |
| bool is_persistent_; |
| }; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // zwp_locked_pointer |
| |
| void locked_pointer_destroy(wl_client* client, wl_resource* resource) { |
| VLOG(1) << "locked_pointer_destroy(" << client << ", " << resource << ")"; |
| wl_resource_destroy(resource); |
| } |
| |
| void locked_pointer_set_cursor_position_hint(wl_client* client, |
| wl_resource* resource, |
| wl_fixed_t surface_x, |
| wl_fixed_t surface_y) { |
| // Not supported. |
| } |
| |
| void locked_pointer_set_region(wl_client* client, |
| wl_resource* resource, |
| wl_resource* region_resource) { |
| // Not supported. |
| } |
| |
| const struct zwp_locked_pointer_v1_interface locked_pointer_implementation = { |
| locked_pointer_destroy, locked_pointer_set_cursor_position_hint, |
| locked_pointer_set_region}; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // zwp_confined_pointer |
| |
| void confined_pointer_destroy(wl_client* client, wl_resource* resource) { |
| wl_resource_destroy(resource); |
| } |
| |
| void confined_pointer_set_region(wl_client* client, |
| wl_resource* resource, |
| wl_resource* region_resource) { |
| // Not supported. |
| } |
| |
| const struct zwp_confined_pointer_v1_interface confined_pointer_implementation = |
| { |
| confined_pointer_destroy, |
| confined_pointer_set_region, |
| }; |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| // zwp_pointer_constraints |
| |
| void pointer_constraints_destroy(wl_client* client, wl_resource* resource) { |
| VLOG(1) << "pointer_constraints_destroy(" << client << ", " << resource |
| << ")"; |
| wl_resource_destroy(resource); |
| } |
| |
| void pointer_constraints_lock_pointer(wl_client* client, |
| wl_resource* resource, |
| uint32_t id, |
| wl_resource* surface_resource, |
| wl_resource* pointer_resource, |
| wl_resource* region_resource, |
| uint32_t lifetime) { |
| Surface* surface = GetUserDataAs<Surface>(surface_resource); |
| Pointer* pointer = GetUserDataAs<Pointer>(pointer_resource); |
| SkRegion* region = |
| region_resource ? GetUserDataAs<SkRegion>(region_resource) : nullptr; |
| |
| VLOG(1) << "lock_pointer(" << client << ", " << resource << "; Surface " |
| << surface << " @ window '" |
| << (surface && surface->window() ? surface->window()->GetTitle() |
| : base::EmptyString16()) |
| << "', " |
| << "Pointer " << pointer << ")"; |
| |
| wl_resource* locked_pointer_resource = |
| wl_resource_create(client, &zwp_locked_pointer_v1_interface, 1, id); |
| SetImplementation( |
| locked_pointer_resource, &locked_pointer_implementation, |
| std::make_unique<WaylandPointerConstraintDelegate>( |
| locked_pointer_resource, surface, pointer, region, lifetime)); |
| } |
| |
| void pointer_constraints_confine_pointer(wl_client* client, |
| wl_resource* resource, |
| uint32_t id, |
| wl_resource* surface_resource, |
| wl_resource* pointer_resource, |
| wl_resource* region_resource, |
| uint32_t lifetime) { |
| // Confined pointer is not currently supported. |
| wl_resource* confined_pointer_resource = |
| wl_resource_create(client, &zwp_confined_pointer_v1_interface, 1, id); |
| SetImplementation<int>(confined_pointer_resource, |
| &confined_pointer_implementation, nullptr); |
| } |
| |
| const struct zwp_pointer_constraints_v1_interface |
| pointer_constraints_implementation = {pointer_constraints_destroy, |
| pointer_constraints_lock_pointer, |
| pointer_constraints_confine_pointer}; |
| |
| } // namespace |
| |
| void bind_pointer_constraints(wl_client* client, |
| void* data, |
| uint32_t version, |
| uint32_t id) { |
| wl_resource* resource = wl_resource_create( |
| client, &zwp_pointer_constraints_v1_interface, version, id); |
| wl_resource_set_implementation(resource, &pointer_constraints_implementation, |
| data, nullptr); |
| } |
| |
| } // namespace wayland |
| } // namespace exo |