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
|
// Copyright 2022 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_seat.h"
#include "base/logging.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/ozone/platform/wayland/host/wayland_connection.h"
#include "ui/ozone/platform/wayland/host/wayland_event_source.h"
#include "ui/ozone/platform/wayland/host/wayland_keyboard.h"
#include "ui/ozone/platform/wayland/host/wayland_pointer.h"
#include "ui/ozone/platform/wayland/host/wayland_touch.h"
namespace ui {
namespace {
constexpr uint32_t kMinVersion = 1;
constexpr uint32_t kMaxVersion = 8;
} // namespace
// static
void WaylandSeat::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->seat_ ||
!wl::CanBind(interface, version, kMinVersion, kMaxVersion)) {
return;
}
auto seat = wl::Bind<wl_seat>(registry, name, std::min(version, kMaxVersion));
if (!seat) {
LOG(ERROR) << "Failed to bind to wl_seat global";
return;
}
connection->seat_ = std::make_unique<WaylandSeat>(seat.release(), connection);
// The seat is one of objects needed for data exchange. Notify the connection
// so it might set up the rest if all other parts are in place.
connection->CreateDataObjectsIfReady();
}
WaylandSeat::WaylandSeat(wl_seat* seat, WaylandConnection* connection)
: obj_(seat), connection_(connection) {
DCHECK(connection_);
DCHECK(obj_);
static constexpr wl_seat_listener kSeatListener = {
.capabilities = &OnCapabilities,
.name = &OnName,
};
wl_seat_add_listener(wl_object(), &kSeatListener, this);
}
WaylandSeat::~WaylandSeat() = default;
bool WaylandSeat::RefreshKeyboard() {
// Make sure to destroy the old WaylandKeyboard (if it exists) before creating
// the new one.
keyboard_.reset();
wl_keyboard* keyboard = wl_seat_get_keyboard(wl_object());
if (!keyboard)
return false;
auto* layout_engine = KeyboardLayoutEngineManager::GetKeyboardLayoutEngine();
keyboard_ = std::make_unique<WaylandKeyboard>(
keyboard, connection_->keyboard_extension_v1_.get(), connection_,
layout_engine, connection_->event_source());
return true;
}
// static
void WaylandSeat::OnCapabilities(void* data,
wl_seat* seat,
uint32_t capabilities) {
auto* self = static_cast<WaylandSeat*>(data);
self->HandleCapabilities(data, seat, capabilities);
}
// static
void WaylandSeat::OnName(void* data, wl_seat* seat, const char* name) {
NOTIMPLEMENTED_LOG_ONCE();
}
void WaylandSeat::HandleCapabilities(void* data,
wl_seat* seat,
uint32_t capabilities) {
DCHECK(connection_->event_source());
bool prev_keyboard_available = !!keyboard_;
if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {
if (!RefreshKeyboard()) {
LOG(ERROR) << "Failed to get wl_keyboard from seat";
}
} else {
keyboard_.reset();
}
if (capabilities & WL_SEAT_CAPABILITY_POINTER) {
if (wl_pointer* pointer = wl_seat_get_pointer(seat)) {
pointer_ = std::make_unique<WaylandPointer>(pointer, connection_,
connection_->event_source());
} else {
LOG(ERROR) << "Failed to get wl_pointer from seat";
}
} else {
pointer_.reset();
}
if (capabilities & WL_SEAT_CAPABILITY_TOUCH) {
if (wl_touch* touch = wl_seat_get_touch(seat)) {
touch_ = std::make_unique<WaylandTouch>(touch, connection_,
connection_->event_source());
} else {
LOG(ERROR) << "Failed to get wl_touch from seat";
}
} else {
touch_.reset();
}
connection_->UpdateInputDevices();
connection_->UpdateCursor();
connection_->Flush();
bool keyboard_available = !!keyboard_;
if (keyboard_available != prev_keyboard_available) {
// Keyboard focus can be used to determine window active state depending on
// keyboard availability.
connection_->window_manager()->UpdateActivationState();
}
}
} // namespace ui
|