1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
|
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/ozone/platform/wayland/host/wayland_cursor_shape.h"
#include <cursor-shape-v1-client-protocol.h>
#include <optional>
#include "base/check.h"
#include "ui/base/cursor/mojom/cursor_type.mojom-shared.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
#include "ui/ozone/platform/wayland/host/wayland_seat.h"
namespace ui {
namespace {
constexpr uint32_t kMinVersion = 1;
}
using mojom::CursorType;
// static
constexpr char WaylandCursorShape::kInterfaceName[];
// static
void WaylandCursorShape::Instantiate(WaylandConnection* connection,
wl_registry* registry,
uint32_t name,
const std::string& interface,
uint32_t version) {
CHECK_EQ(interface, kInterfaceName) << "Expected \"" << kInterfaceName
<< "\" but got \"" << interface << "\"";
if (connection->cursor_shape_ ||
!wl::CanBind(interface, version, kMinVersion, kMinVersion)) {
return;
}
auto cursor_shape_manager =
wl::Bind<wp_cursor_shape_manager_v1>(registry, name, kMinVersion);
if (!cursor_shape_manager) {
LOG(ERROR) << "Failed to bind wp_cursor_shape_manager_v1";
return;
}
connection->cursor_shape_ = std::make_unique<WaylandCursorShape>(
cursor_shape_manager.release(), connection);
}
WaylandCursorShape::WaylandCursorShape(wp_cursor_shape_manager_v1* cursor_shape,
WaylandConnection* connection)
: wp_cursor_shape_manager_v1_(cursor_shape), connection_(connection) {
// |wp_cursor_shape_manager_v1_| and |connection_| may be null in tests.
}
WaylandCursorShape::~WaylandCursorShape() = default;
wp_cursor_shape_device_v1* WaylandCursorShape::GetShapeDevice() {
DCHECK(connection_->seat()->pointer());
if (!wp_cursor_shape_device_v1_.get()) {
wl_pointer* pointer = connection_->seat()->pointer()->wl_object();
wp_cursor_shape_device_v1_.reset(wp_cursor_shape_manager_v1_get_pointer(
wp_cursor_shape_manager_v1_.get(), pointer));
}
DCHECK(wp_cursor_shape_device_v1_);
return wp_cursor_shape_device_v1_.get();
}
// static
std::optional<uint32_t> WaylandCursorShape::ShapeFromType(CursorType type) {
switch (type) {
case CursorType::kNull:
// kNull is an alias for kPointer. Fall through.
case CursorType::kPointer:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
case CursorType::kCross:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR;
case CursorType::kHand:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_POINTER;
case CursorType::kIBeam:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT;
case CursorType::kWait:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_WAIT;
case CursorType::kHelp:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_HELP;
case CursorType::kEastResize:
case CursorType::kEastPanning:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_E_RESIZE;
case CursorType::kNorthResize:
case CursorType::kNorthPanning:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_N_RESIZE;
case CursorType::kNorthEastResize:
case CursorType::kNorthEastPanning:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NE_RESIZE;
case CursorType::kNorthWestResize:
case CursorType::kNorthWestPanning:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NW_RESIZE;
case CursorType::kSouthResize:
case CursorType::kSouthPanning:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_S_RESIZE;
case CursorType::kSouthEastResize:
case CursorType::kSouthEastPanning:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SE_RESIZE;
case CursorType::kSouthWestResize:
case CursorType::kSouthWestPanning:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SW_RESIZE;
case CursorType::kWestResize:
case CursorType::kWestPanning:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_W_RESIZE;
case CursorType::kNorthSouthResize:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE;
case CursorType::kEastWestResize:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE;
case CursorType::kNorthEastSouthWestResize:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE;
case CursorType::kNorthWestSouthEastResize:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE;
case CursorType::kColumnResize:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_COL_RESIZE;
case CursorType::kRowResize:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ROW_RESIZE;
case CursorType::kMove:
// Returning `MOVE` is the correct thing here, but Blink does not make a
// distinction between move and all-scroll. Other platforms use a cursor
// more consistent with all-scroll, so use that.
case CursorType::kMiddlePanning:
case CursorType::kMiddlePanningVertical:
case CursorType::kMiddlePanningHorizontal:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALL_SCROLL;
case CursorType::kVerticalText:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_VERTICAL_TEXT;
case CursorType::kCell:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CELL;
case CursorType::kContextMenu:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CONTEXT_MENU;
case CursorType::kAlias:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ALIAS;
case CursorType::kProgress:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_PROGRESS;
case CursorType::kNoDrop:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NO_DROP;
case CursorType::kCopy:
case CursorType::kDndCopy:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_COPY;
case CursorType::kNone:
// To be cleared through wl_pointer.set_cursor.
return std::nullopt;
case CursorType::kNotAllowed:
case CursorType::kNorthSouthNoResize:
case CursorType::kEastWestNoResize:
case CursorType::kNorthEastSouthWestNoResize:
case CursorType::kNorthWestSouthEastNoResize:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NOT_ALLOWED;
case CursorType::kZoomIn:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_IN;
case CursorType::kZoomOut:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_ZOOM_OUT;
case CursorType::kGrab:
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRAB;
case CursorType::kGrabbing:
case CursorType::kDndNone:
case CursorType::kDndMove:
case CursorType::kDndLink:
// For drag-and-drop, the compositor knows the drag type and can use it to
// additionally decorate the cursor.
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRABBING;
case CursorType::kCustom:
// "Custom" means a bitmap cursor, which cannot use the shape API.
return std::nullopt;
}
}
void WaylandCursorShape::SetCursorShape(uint32_t shape) {
DCHECK(connection_->seat());
// Nothing to do if there is no pointer (mouse) connected.
if (!connection_->seat()->pointer()) {
return;
}
auto pointer_enter_serial =
connection_->serial_tracker().GetSerial(wl::SerialType::kMouseEnter);
if (!pointer_enter_serial) {
VLOG(1) << "Failed to set cursor shape: no mouse enter serial found.";
return;
}
wp_cursor_shape_device_v1_set_shape(GetShapeDevice(),
pointer_enter_serial->value, shape);
}
} // namespace ui
|