File: wayland_cursor_shape.cc

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (195 lines) | stat: -rw-r--r-- 7,484 bytes parent folder | download | duplicates (6)
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