Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <campbell@blender.org>2022-11-01 02:41:06 +0300
committerCampbell Barton <campbell@blender.org>2022-11-01 03:32:17 +0300
commit409070e0d480df99948e36bf2e48f123d9285aa0 (patch)
tree77ca85f08c03ea4d16490568742bc090318d86ed
parentc3e4fa74044a5a2a38ec28cf66be45c98f982501 (diff)
GHOST/Wayland: support for multiple seats (one active seat at a time)
This isn't full multi-seat support, instead set the active seat using pointer/tablet & keyboard enter handlers. This means that seats beside the first aren't prevented from having their events handled.
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.cpp146
-rw-r--r--intern/ghost/intern/GHOST_SystemWayland.h3
2 files changed, 109 insertions, 40 deletions
diff --git a/intern/ghost/intern/GHOST_SystemWayland.cpp b/intern/ghost/intern/GHOST_SystemWayland.cpp
index f3dc1609e69..f713ddced27 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.cpp
+++ b/intern/ghost/intern/GHOST_SystemWayland.cpp
@@ -776,6 +776,18 @@ struct GWL_Display {
struct wl_shm *wl_shm = nullptr;
std::vector<GWL_Output *> outputs;
std::vector<GWL_Seat *> seats;
+ /**
+ * Support a single active seat at once, this isn't an exact or correct mapping from WAYLAND.
+ * Only allow input from different seats, not full concurrent multi-seat support.
+ *
+ * The main purpose of having an active seat is an alternative from always using the first
+ * seat which prevents events from any other seat.
+ *
+ * NOTE(@campbellbarton): This could be extended and developed further extended to support
+ * an active seat per window (for e.g.), basic support is sufficient for now as currently isn't
+ * a widely used feature.
+ */
+ int seats_active_index = 0;
/* Managers. */
struct wl_data_device_manager *wl_data_device_manager = nullptr;
@@ -830,6 +842,37 @@ static void gwl_display_destroy(GWL_Display *display)
delete display;
}
+static int gwl_display_seat_index(GWL_Display *display, const GWL_Seat *seat)
+{
+ std::vector<GWL_Seat *>::iterator iter = std::find(
+ display->seats.begin(), display->seats.end(), seat);
+ const int index = (iter != display->seats.cend()) ? std::distance(display->seats.begin(), iter) :
+ -1;
+ GHOST_ASSERT(index != -1, "invalid internal state");
+ return index;
+}
+
+static GWL_Seat *gwl_display_seat_active_get(const GWL_Display *display)
+{
+ if (UNLIKELY(display->seats.empty())) {
+ return nullptr;
+ }
+ return display->seats[display->seats_active_index];
+}
+
+static bool gwl_display_seat_active_set(GWL_Display *display, const GWL_Seat *seat)
+{
+ if (UNLIKELY(display->seats.empty())) {
+ return false;
+ }
+ const int index = gwl_display_seat_index(display, seat);
+ if (index == display->seats_active_index) {
+ return false;
+ }
+ display->seats_active_index = index;
+ return true;
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -1925,6 +1968,9 @@ static void data_device_handle_enter(void *data,
}
seat->wl_surface_focus_dnd = wl_surface;
+
+ seat->system->seat_active_set(seat);
+
dnd_events(seat, GHOST_kEventDraggingEntered);
}
@@ -2256,6 +2302,8 @@ static void pointer_handle_enter(void *data,
seat->pointer.wl_surface = wl_surface;
+ seat->system->seat_active_set(seat);
+
win->setCursorShape(win->getCursorShape());
const wl_fixed_t scale = win->scale();
@@ -2900,6 +2948,8 @@ static void tablet_tool_handle_proximity_in(void *data,
seat->data_source_serial = serial;
+ seat->system->seat_active_set(seat);
+
/* Update #GHOST_TabletData. */
GHOST_TabletData &td = tablet_tool->data;
/* Reset, to avoid using stale tilt/pressure. */
@@ -3286,6 +3336,8 @@ static void keyboard_handle_enter(void *data,
seat->keyboard.serial = serial;
seat->keyboard.wl_surface = wl_surface;
+ seat->system->seat_active_set(seat);
+
/* If there are any keys held when activating the window,
* modifiers will be compared against the seat state,
* only enabling modifiers that were previously disabled. */
@@ -4472,6 +4524,9 @@ static void gwl_registry_wl_seat_remove(GWL_Display *display, void *user_data, c
GHOST_ASSERT(index != -1, "invalid internal state");
if (!on_exit) {
+ if (display->seats_active_index >= index) {
+ display->seats_active_index -= 1;
+ }
display->seats.erase(display->seats.begin() + index);
}
delete seat;
@@ -4980,12 +5035,11 @@ bool GHOST_SystemWayland::setConsoleWindowState(GHOST_TConsoleWindowState /*acti
GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) const
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- GWL_Seat *seat = display_->seats[0];
-
const xkb_mod_mask_t state = xkb_state_serialize_mods(seat->xkb_state, XKB_STATE_MODS_DEPRESSED);
bool show_warning = true;
@@ -5042,10 +5096,10 @@ GHOST_TSuccess GHOST_SystemWayland::getModifierKeys(GHOST_ModifierKeys &keys) co
GHOST_TSuccess GHOST_SystemWayland::getButtons(GHOST_Buttons &buttons) const
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- GWL_Seat *seat = display_->seats[0];
GWL_SeatStatePointer *seat_state_pointer = gwl_seat_state_pointer_active(seat);
if (!seat_state_pointer) {
return GHOST_kFailure;
@@ -5073,7 +5127,10 @@ static const char *system_clipboard_text_mime_type(
static char *system_clipboard_get_primary_selection(GWL_Display *display)
{
- GWL_Seat *seat = display->seats[0];
+ GWL_Seat *seat = gwl_display_seat_active_get(display);
+ if (UNLIKELY(!seat)) {
+ return nullptr;
+ }
GWL_PrimarySelection *primary = &seat->primary_selection;
std::mutex &mutex = primary->data_offer_mutex;
@@ -5120,7 +5177,10 @@ static char *system_clipboard_get_primary_selection(GWL_Display *display)
static char *system_clipboard_get(GWL_Display *display)
{
- GWL_Seat *seat = display->seats[0];
+ GWL_Seat *seat = gwl_display_seat_active_get(display);
+ if (UNLIKELY(!seat)) {
+ return nullptr;
+ }
std::mutex &mutex = seat->data_offer_copy_paste_mutex;
mutex.lock();
@@ -5166,10 +5226,6 @@ static char *system_clipboard_get(GWL_Display *display)
char *GHOST_SystemWayland::getClipboard(bool selection) const
{
- if (UNLIKELY(display_->seats.empty())) {
- return nullptr;
- }
-
char *data = nullptr;
if (selection) {
data = system_clipboard_get_primary_selection(display_);
@@ -5185,7 +5241,10 @@ static void system_clipboard_put_primary_selection(GWL_Display *display, const c
if (!display->wp_primary_selection_device_manager) {
return;
}
- GWL_Seat *seat = display->seats[0];
+ GWL_Seat *seat = gwl_display_seat_active_get(display);
+ if (UNLIKELY(!seat)) {
+ return;
+ }
GWL_PrimarySelection *primary = &seat->primary_selection;
std::lock_guard lock{primary->data_source_mutex};
@@ -5219,8 +5278,10 @@ static void system_clipboard_put(GWL_Display *display, const char *buffer)
if (!display->wl_data_device_manager) {
return;
}
- GWL_Seat *seat = display->seats[0];
-
+ GWL_Seat *seat = gwl_display_seat_active_get(display);
+ if (UNLIKELY(!seat)) {
+ return;
+ }
std::lock_guard lock{seat->data_source_mutex};
GWL_DataSource *data_source = seat->data_source;
@@ -5245,10 +5306,6 @@ static void system_clipboard_put(GWL_Display *display, const char *buffer)
void GHOST_SystemWayland::putClipboard(const char *buffer, bool selection) const
{
- if (UNLIKELY(display_->seats.empty())) {
- return;
- }
-
if (selection) {
system_clipboard_put_primary_selection(display_, buffer);
}
@@ -5301,10 +5358,10 @@ GHOST_TSuccess GHOST_SystemWayland::getCursorPositionClientRelative(const GHOST_
int32_t &x,
int32_t &y) const
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- GWL_Seat *seat = display_->seats[0];
GWL_SeatStatePointer *seat_state_pointer = gwl_seat_state_pointer_active(seat);
if (!seat_state_pointer || !seat_state_pointer->wl_surface) {
return GHOST_kFailure;
@@ -5317,20 +5374,20 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorPositionClientRelative(GHOST_IWindo
const int32_t x,
const int32_t y)
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- GWL_Seat *seat = display_->seats[0];
GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(window);
return setCursorPositionClientRelative_impl(seat, win, x, y);
}
GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(int32_t &x, int32_t &y) const
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- GWL_Seat *seat = display_->seats[0];
GWL_SeatStatePointer *seat_state_pointer = gwl_seat_state_pointer_active(seat);
if (!seat_state_pointer) {
return GHOST_kFailure;
@@ -5345,10 +5402,10 @@ GHOST_TSuccess GHOST_SystemWayland::getCursorPosition(int32_t &x, int32_t &y) co
GHOST_TSuccess GHOST_SystemWayland::setCursorPosition(const int32_t x, const int32_t y)
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- GWL_Seat *seat = display_->seats[0];
/* Intentionally different from `getCursorPosition` which supports both tablet & pointer.
* In the case of setting the cursor location, tablets don't support this. */
@@ -5699,7 +5756,8 @@ static bool cursor_is_software(const GHOST_TGrabCursorMode mode, const bool use_
GHOST_TSuccess GHOST_SystemWayland::setCursorShape(const GHOST_TStandardCursor shape)
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
auto cursor_find = ghost_wl_cursors.find(shape);
@@ -5707,7 +5765,6 @@ GHOST_TSuccess GHOST_SystemWayland::setCursorShape(const GHOST_TStandardCursor s
ghost_wl_cursors.at(GHOST_kStandardCursorDefault) :
(*cursor_find).second;
- GWL_Seat *seat = display_->seats[0];
GWL_Cursor *cursor = &seat->cursor;
if (!cursor->wl_theme) {
@@ -5760,12 +5817,12 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
const int hotY,
const bool /*canInvertColor*/)
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- GWL_Cursor *cursor = &display_->seats[0]->cursor;
-
+ GWL_Cursor *cursor = &seat->cursor;
if (cursor->custom_data) {
munmap(cursor->custom_data, cursor->custom_data_size);
cursor->custom_data = nullptr;
@@ -5823,14 +5880,19 @@ GHOST_TSuccess GHOST_SystemWayland::setCustomCursorShape(uint8_t *bitmap,
cursor->wl_image.hotspot_x = uint32_t(hotX);
cursor->wl_image.hotspot_y = uint32_t(hotY);
- cursor_buffer_set(display_->seats[0], buffer);
+ cursor_buffer_set(seat, buffer);
return GHOST_kSuccess;
}
GHOST_TSuccess GHOST_SystemWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitmap)
{
- GWL_Cursor *cursor = &display_->seats[0]->cursor;
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
+ return GHOST_kFailure;
+ }
+
+ GWL_Cursor *cursor = &seat->cursor;
if (cursor->custom_data == nullptr) {
return GHOST_kFailure;
}
@@ -5851,11 +5913,11 @@ GHOST_TSuccess GHOST_SystemWayland::getCursorBitmap(GHOST_CursorBitmapRef *bitma
GHOST_TSuccess GHOST_SystemWayland::setCursorVisibility(const bool visible)
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
- GWL_Seat *seat = display_->seats[0];
cursor_visible_set(seat, visible, seat->cursor.is_hardware, CURSOR_VISIBLE_ALWAYS_SET);
return GHOST_kSuccess;
}
@@ -5875,12 +5937,12 @@ bool GHOST_SystemWayland::supportsWindowPosition()
bool GHOST_SystemWayland::getCursorGrabUseSoftwareDisplay(const GHOST_TGrabCursorMode mode)
{
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return false;
}
#ifdef USE_GNOME_CONFINE_HACK
- GWL_Seat *seat = display_->seats[0];
const bool use_software_confine = seat->use_pointer_software_confine;
#else
const bool use_software_confine = false;
@@ -6068,6 +6130,11 @@ GHOST_WindowWayland *ghost_wl_surface_user_data(struct wl_surface *wl_surface)
* Functionality only used for the WAYLAND implementation.
* \{ */
+void GHOST_SystemWayland::seat_active_set(const struct GWL_Seat *seat)
+{
+ gwl_display_seat_active_set(display_, seat);
+}
+
void GHOST_SystemWayland::window_surface_unref(const wl_surface *wl_surface)
{
#define SURFACE_CLEAR_PTR(surface_test) \
@@ -6099,7 +6166,8 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
return GHOST_kFailure;
}
- if (UNLIKELY(display_->seats.empty())) {
+ GWL_Seat *seat = gwl_display_seat_active_get(display_);
+ if (UNLIKELY(!seat)) {
return GHOST_kFailure;
}
/* No change, success. */
@@ -6107,8 +6175,6 @@ bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mod
return GHOST_kSuccess;
}
- GWL_Seat *seat = display_->seats[0];
-
#ifdef USE_GNOME_CONFINE_HACK
const bool was_software_confine = seat->use_pointer_software_confine;
const bool use_software_confine = setCursorGrab_use_software_confine(mode, wl_surface);
diff --git a/intern/ghost/intern/GHOST_SystemWayland.h b/intern/ghost/intern/GHOST_SystemWayland.h
index db4fef23538..a8e8d8ddc45 100644
--- a/intern/ghost/intern/GHOST_SystemWayland.h
+++ b/intern/ghost/intern/GHOST_SystemWayland.h
@@ -178,6 +178,9 @@ class GHOST_SystemWayland : public GHOST_System {
/* WAYLAND utility functions. */
+ /** Set this seat to be active. */
+ void seat_active_set(const struct GWL_Seat *seat);
+
/** Clear all references to this surface to prevent accessing NULL pointers. */
void window_surface_unref(const wl_surface *wl_surface);