Skip to content

Commit

Permalink
Multiple seats (#417)
Browse files Browse the repository at this point in the history
Added the ability to have multiple seats, this allows f.e. weston screenshare and a local touch input to work at the same time.

Signed-off-by: Ómar Högni Guðmarsson <ohg@skaginn3x.com>
  • Loading branch information
Ómar Högni Guðmarsson authored May 23, 2024
1 parent 9743862 commit 434d509
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 77 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ Yunhao Tian (t123yh@outlook.com)
Luke Howard <lukeh@padl.com>
Stanislav Shmarov <github@snarpix.com>
Sebastian Urban <surban@surban.net>
Ómar Högni Guðmarsson <ohg@skaginn3x.com>
Original file line number Diff line number Diff line change
Expand Up @@ -289,29 +289,32 @@ const wl_seat_listener ELinuxWindowWayland::kWlSeatListener = {
ELINUX_LOG(TRACE) << "wl_seat_listener.capabilities";

auto self = reinterpret_cast<ELinuxWindowWayland*>(data);
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !self->wl_pointer_) {
self->wl_pointer_ = wl_seat_get_pointer(seat);
wl_pointer_add_listener(self->wl_pointer_, &kWlPointerListener, self);
} else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && self->wl_pointer_) {
wl_pointer_destroy(self->wl_pointer_);
self->wl_pointer_ = nullptr;
auto [iter_inputs, _] =
self->seat_inputs_map_.emplace(seat, seat_inputs());
auto& inputs = iter_inputs->second;

if ((caps & WL_SEAT_CAPABILITY_POINTER) && !inputs.pointer) {
inputs.pointer = wl_seat_get_pointer(seat);
wl_pointer_add_listener(inputs.pointer, &kWlPointerListener, self);
} else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && inputs.pointer) {
wl_pointer_destroy(inputs.pointer);
inputs.pointer = nullptr;
}

if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !self->wl_touch_) {
self->wl_touch_ = wl_seat_get_touch(seat);
wl_touch_add_listener(self->wl_touch_, &kWlTouchListener, self);
} else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && self->wl_touch_) {
wl_touch_destroy(self->wl_touch_);
self->wl_touch_ = nullptr;
if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !inputs.touch) {
inputs.touch = wl_seat_get_touch(seat);
wl_touch_add_listener(inputs.touch, &kWlTouchListener, self);
} else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && inputs.touch) {
wl_touch_destroy(inputs.touch);
inputs.touch = nullptr;
}

if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !self->wl_keyboard_) {
self->wl_keyboard_ = wl_seat_get_keyboard(seat);
wl_keyboard_add_listener(self->wl_keyboard_, &kWlKeyboardListener,
self);
} else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && self->wl_keyboard_) {
wl_keyboard_destroy(self->wl_keyboard_);
self->wl_keyboard_ = nullptr;
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !inputs.keyboard) {
inputs.keyboard = wl_seat_get_keyboard(seat);
wl_keyboard_add_listener(inputs.keyboard, &kWlKeyboardListener, self);
} else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && inputs.keyboard) {
wl_keyboard_destroy(inputs.keyboard);
inputs.keyboard = nullptr;
}
},
.name = [](void* data, struct wl_seat* wl_seat, const char* name) -> void {
Expand All @@ -333,7 +336,7 @@ const wl_pointer_listener ELinuxWindowWayland::kWlPointerListener = {
self->serial_ = serial;

if (self->view_properties_.use_mouse_cursor) {
self->cursor_info_.pointer = self->wl_pointer_;
self->cursor_info_.pointer = wl_pointer;
self->cursor_info_.serial = serial;
}

Expand Down Expand Up @@ -399,7 +402,14 @@ const wl_pointer_listener ELinuxWindowWayland::kWlPointerListener = {
self->window_decorations_->IsMatched(
self->wl_current_surface_,
WindowDecoration::DecorationType::TITLE_BAR)) {
xdg_toplevel_move(self->xdg_toplevel_, self->wl_seat_, serial);
for (auto& [seat, inputs] : self->seat_inputs_map_) {
if (inputs.pointer == pointer) {
xdg_toplevel_move(self->xdg_toplevel_, seat, serial);
return;
}
}
ELINUX_LOG(TRACE)
<< "Failed to find the pointer for moving the window";
return;
}

Expand Down Expand Up @@ -1043,11 +1053,8 @@ ELinuxWindowWayland::ELinuxWindowWayland(
wl_compositor_(nullptr),
wl_subcompositor_(nullptr),
wl_current_surface_(nullptr),
wl_seat_(nullptr),
wl_pointer_(nullptr),
wl_touch_(nullptr),
wl_keyboard_(nullptr),
wl_shm_(nullptr),
seat_inputs_map_(),
wl_data_device_manager_(nullptr),
wl_data_device_(nullptr),
wl_data_offer_(nullptr),
Expand Down Expand Up @@ -1087,34 +1094,37 @@ ELinuxWindowWayland::ELinuxWindowWayland(
wl_registry_add_listener(wl_registry_, &kWlRegistryListener, this);
wl_display_roundtrip(wl_display_);

if (wl_data_device_manager_ && wl_seat_) {
wl_data_device_ = wl_data_device_manager_get_data_device(
wl_data_device_manager_, wl_seat_);
wl_data_device_add_listener(wl_data_device_, &kWlDataDeviceListener, this);
}
for (auto& [seat, _] : seat_inputs_map_) {
if (wl_data_device_manager_ && seat) {
wl_data_device_ =
wl_data_device_manager_get_data_device(wl_data_device_manager_, seat);
wl_data_device_add_listener(wl_data_device_, &kWlDataDeviceListener,
this);
}

// Setup text-input protocol for onscreen keyboard inputs.
{
if (zwp_text_input_manager_v3_ && wl_seat_) {
zwp_text_input_v3_ = zwp_text_input_manager_v3_get_text_input(
zwp_text_input_manager_v3_, wl_seat_);
if (!zwp_text_input_v3_) {
ELINUX_LOG(ERROR) << "Failed to create the text input manager v3.";
return;
}
zwp_text_input_v3_add_listener(zwp_text_input_v3_,
&kZwpTextInputV3Listener, this);
} else if (zwp_text_input_manager_v1_) {
zwp_text_input_v1_ = zwp_text_input_manager_v1_create_text_input(
zwp_text_input_manager_v1_);
if (!zwp_text_input_v1_) {
ELINUX_LOG(ERROR) << "Failed to create text input manager v1.";
return;
// Setup text-input protocol for onscreen keyboard inputs.
{
if (zwp_text_input_manager_v3_ && seat) {
zwp_text_input_v3_ = zwp_text_input_manager_v3_get_text_input(
zwp_text_input_manager_v3_, seat);
if (!zwp_text_input_v3_) {
ELINUX_LOG(ERROR) << "Failed to create the text input manager v3.";
return;
}
zwp_text_input_v3_add_listener(zwp_text_input_v3_,
&kZwpTextInputV3Listener, this);
} else if (zwp_text_input_manager_v1_) {
zwp_text_input_v1_ = zwp_text_input_manager_v1_create_text_input(
zwp_text_input_manager_v1_);
if (!zwp_text_input_v1_) {
ELINUX_LOG(ERROR) << "Failed to create text input manager v1.";
return;
}
zwp_text_input_v1_add_listener(zwp_text_input_v1_,
&kZwpTextInputV1Listener, this);
} else {
// do nothing.
}
zwp_text_input_v1_add_listener(zwp_text_input_v1_,
&kZwpTextInputV1Listener, this);
} else {
// do nothing.
}
}

Expand Down Expand Up @@ -1190,26 +1200,29 @@ ELinuxWindowWayland::~ELinuxWindowWayland() {
wl_data_device_manager_ = nullptr;
}

if (wl_pointer_) {
wl_pointer_destroy(wl_pointer_);
wl_pointer_ = nullptr;
}
for (auto& [seat, inputs] : seat_inputs_map_) {
if (inputs.pointer) {
wl_pointer_destroy(inputs.pointer);
inputs.pointer = nullptr;
}

if (wl_touch_) {
wl_touch_destroy(wl_touch_);
wl_touch_ = nullptr;
}
if (inputs.touch) {
wl_touch_destroy(inputs.touch);
inputs.touch = nullptr;
}

if (wl_keyboard_) {
wl_keyboard_destroy(wl_keyboard_);
wl_keyboard_ = nullptr;
}
if (inputs.keyboard) {
wl_keyboard_destroy(inputs.keyboard);
inputs.keyboard = nullptr;
}

if (wl_seat_) {
wl_seat_destroy(wl_seat_);
wl_seat_ = nullptr;
if (seat) {
wl_seat_destroy(seat);
}
}

seat_inputs_map_.clear();

if (wl_output_) {
wl_output_destroy(wl_output_);
wl_output_ = nullptr;
Expand Down Expand Up @@ -1486,7 +1499,7 @@ void ELinuxWindowWayland::DestroyRenderSurface() {

void ELinuxWindowWayland::UpdateVirtualKeyboardStatus(const bool show) {
// Not supported virtual keyboard.
if (!(zwp_text_input_v1_ || zwp_text_input_v3_) || !wl_seat_) {
if (!(zwp_text_input_v1_ || zwp_text_input_v3_) || seat_inputs_map_.empty()) {
return;
}

Expand All @@ -1500,7 +1513,14 @@ void ELinuxWindowWayland::UpdateVirtualKeyboardStatus(const bool show) {

void ELinuxWindowWayland::UpdateFlutterCursor(const std::string& cursor_name) {
if (view_properties_.use_mouse_cursor) {
if (!wl_pointer_) {
wl_pointer* pointer = nullptr;
for (auto& [_, inputs] : seat_inputs_map_) {
if (inputs.pointer != nullptr) {
pointer = inputs.pointer;
break;
}
}
if (!pointer) {
return;
}
if (cursor_name.compare(cursor_info_.cursor_name) == 0) {
Expand Down Expand Up @@ -1619,9 +1639,12 @@ void ELinuxWindowWayland::WlRegistryHandler(wl_registry* wl_registry,

if (!strcmp(interface, wl_seat_interface.name)) {
constexpr uint32_t kMaxVersion = 4;
wl_seat_ = static_cast<decltype(wl_seat_)>(wl_registry_bind(
wl_registry, name, &wl_seat_interface, std::min(kMaxVersion, version)));
wl_seat_add_listener(wl_seat_, &kWlSeatListener, this);
auto [inserted, _] =
seat_inputs_map_.emplace(static_cast<wl_seat*>(wl_registry_bind(
wl_registry, name, &wl_seat_interface,
std::min(kMaxVersion, version))),
seat_inputs());
wl_seat_add_listener(inserted->first, &kWlSeatListener, this);
return;
}

Expand Down Expand Up @@ -1826,7 +1849,8 @@ void ELinuxWindowWayland::ShowVirtualKeyboard() {
} else {
if (native_window_) {
zwp_text_input_v1_show_input_panel(zwp_text_input_v1_);
zwp_text_input_v1_activate(zwp_text_input_v1_, wl_seat_,
zwp_text_input_v1_activate(zwp_text_input_v1_,
seat_inputs_map_.begin()->first,
native_window_->Surface());
}
}
Expand All @@ -1837,7 +1861,8 @@ void ELinuxWindowWayland::DismissVirtualKeybaord() {
zwp_text_input_v3_disable(zwp_text_input_v3_);
zwp_text_input_v3_commit(zwp_text_input_v3_);
} else {
zwp_text_input_v1_deactivate(zwp_text_input_v1_, wl_seat_);
zwp_text_input_v1_deactivate(zwp_text_input_v1_,
seat_inputs_map_.begin()->first);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ namespace {
constexpr char kXcursorSizeEnvironmentKey[] = "XCURSOR_SIZE";
} // namespace

// Track input devices for each seat
struct seat_inputs {
wl_pointer* pointer = nullptr;
wl_touch* touch = nullptr;
wl_keyboard* keyboard = nullptr;
};

class ELinuxWindowWayland : public ELinuxWindow, public WindowBindingHandler {
public:
ELinuxWindowWayland(FlutterDesktopViewProperties view_properties);
Expand Down Expand Up @@ -161,12 +168,9 @@ class ELinuxWindowWayland : public ELinuxWindow, public WindowBindingHandler {
wl_display* wl_display_;
wl_registry* wl_registry_;
wl_compositor* wl_compositor_;
wl_seat* wl_seat_;
wl_output* wl_output_;
wl_shm* wl_shm_;
wl_pointer* wl_pointer_;
wl_touch* wl_touch_;
wl_keyboard* wl_keyboard_;
std::unordered_map<wl_seat*, seat_inputs> seat_inputs_map_;
wl_surface* wl_cursor_surface_;
xdg_wm_base* xdg_wm_base_;
xdg_surface* xdg_surface_;
Expand Down

0 comments on commit 434d509

Please sign in to comment.