diff options
Diffstat (limited to 'platform/linuxbsd/wayland/wayland_thread.cpp')
-rw-r--r-- | platform/linuxbsd/wayland/wayland_thread.cpp | 177 |
1 files changed, 86 insertions, 91 deletions
diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp index dea8bae438..e066e78e5b 100644 --- a/platform/linuxbsd/wayland/wayland_thread.cpp +++ b/platform/linuxbsd/wayland/wayland_thread.cpp @@ -169,12 +169,13 @@ Vector<uint8_t> WaylandThread::_wp_primary_selection_offer_read(struct wl_displa int fds[2]; if (pipe(fds) == 0) { - // This function expects to return a string, so we can only ask for a MIME of - // "text/plain" zwp_primary_selection_offer_v1_receive(p_offer, p_mime, fds[1]); - // Wait for the compositor to know about the pipe. - wl_display_roundtrip(p_display); + // NOTE: It's important to just flush and not roundtrip here as we would risk + // running some cleanup event, like for example `wl_data_device::leave`. We're + // going to wait for the message anyways as the read will probably block if + // the compositor doesn't read from the other end of the pipe. + wl_display_flush(p_display); // Close the write end of the pipe, which we don't need and would otherwise // just stall our next `read`s. @@ -264,8 +265,6 @@ bool WaylandThread::_load_cursor_theme(int p_cursor_size) { if (wl_cursor_theme) { wl_cursor_theme_destroy(wl_cursor_theme); wl_cursor_theme = nullptr; - - current_wl_cursor = nullptr; } if (cursor_theme_name.is_empty()) { @@ -356,7 +355,12 @@ void WaylandThread::_update_scale(int p_scale) { int cursor_size = unscaled_cursor_size * p_scale; if (_load_cursor_theme(cursor_size)) { - cursor_set_shape(last_cursor_shape); + for (struct wl_seat *wl_seat : registry.wl_seats) { + SeatState *ss = wl_seat_get_seat_state(wl_seat); + ERR_FAIL_NULL(ss); + + seat_state_update_cursor(ss); + } } } @@ -1263,23 +1267,25 @@ void WaylandThread::_wl_seat_on_capabilities(void *data, struct wl_seat *wl_seat // Pointer handling. if (capabilities & WL_SEAT_CAPABILITY_POINTER) { - ss->cursor_surface = wl_compositor_create_surface(ss->registry->wl_compositor); - wl_surface_commit(ss->cursor_surface); + if (!ss->wl_pointer) { + ss->cursor_surface = wl_compositor_create_surface(ss->registry->wl_compositor); + wl_surface_commit(ss->cursor_surface); - ss->wl_pointer = wl_seat_get_pointer(wl_seat); - wl_pointer_add_listener(ss->wl_pointer, &wl_pointer_listener, ss); + ss->wl_pointer = wl_seat_get_pointer(wl_seat); + wl_pointer_add_listener(ss->wl_pointer, &wl_pointer_listener, ss); - if (ss->registry->wp_relative_pointer_manager) { - ss->wp_relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(ss->registry->wp_relative_pointer_manager, ss->wl_pointer); - zwp_relative_pointer_v1_add_listener(ss->wp_relative_pointer, &wp_relative_pointer_listener, ss); - } + if (ss->registry->wp_relative_pointer_manager) { + ss->wp_relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(ss->registry->wp_relative_pointer_manager, ss->wl_pointer); + zwp_relative_pointer_v1_add_listener(ss->wp_relative_pointer, &wp_relative_pointer_listener, ss); + } - if (ss->registry->wp_pointer_gestures) { - ss->wp_pointer_gesture_pinch = zwp_pointer_gestures_v1_get_pinch_gesture(ss->registry->wp_pointer_gestures, ss->wl_pointer); - zwp_pointer_gesture_pinch_v1_add_listener(ss->wp_pointer_gesture_pinch, &wp_pointer_gesture_pinch_listener, ss); - } + if (ss->registry->wp_pointer_gestures) { + ss->wp_pointer_gesture_pinch = zwp_pointer_gestures_v1_get_pinch_gesture(ss->registry->wp_pointer_gestures, ss->wl_pointer); + zwp_pointer_gesture_pinch_v1_add_listener(ss->wp_pointer_gesture_pinch, &wp_pointer_gesture_pinch_listener, ss); + } - // TODO: Constrain new pointers if the global mouse mode is constrained. + // TODO: Constrain new pointers if the global mouse mode is constrained. + } } else { if (ss->cursor_frame_callback) { // Just in case. I got bitten by weird race-like conditions already. @@ -1317,11 +1323,13 @@ void WaylandThread::_wl_seat_on_capabilities(void *data, struct wl_seat *wl_seat // Keyboard handling. if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { - ss->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - ERR_FAIL_NULL(ss->xkb_context); + if (!ss->wl_keyboard) { + ss->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + ERR_FAIL_NULL(ss->xkb_context); - ss->wl_keyboard = wl_seat_get_keyboard(wl_seat); - wl_keyboard_add_listener(ss->wl_keyboard, &wl_keyboard_listener, ss); + ss->wl_keyboard = wl_seat_get_keyboard(wl_seat); + wl_keyboard_add_listener(ss->wl_keyboard, &wl_keyboard_listener, ss); + } } else { if (ss->xkb_context) { xkb_context_unref(ss->xkb_context); @@ -1390,6 +1398,8 @@ void WaylandThread::_wl_pointer_on_leave(void *data, struct wl_pointer *wl_point ss->pointed_surface = nullptr; + ss->pointer_data_buffer.pressed_button_mask.clear(); + Ref<WindowEventMessage> msg; msg.instantiate(); msg->event = DisplayServer::WINDOW_EVENT_MOUSE_EXIT; @@ -1412,10 +1422,10 @@ void WaylandThread::_wl_pointer_on_motion(void *data, struct wl_pointer *wl_poin PointerData &pd = ss->pointer_data_buffer; // TODO: Scale only when sending the Wayland message. - pd.position.x = wl_fixed_to_int(surface_x); - pd.position.y = wl_fixed_to_int(surface_y); + pd.position.x = wl_fixed_to_double(surface_x); + pd.position.y = wl_fixed_to_double(surface_y); - pd.position = scale_vector2i(pd.position, window_state_get_scale_factor(ws)); + pd.position *= window_state_get_scale_factor(ws); pd.motion_time = time; } @@ -1528,7 +1538,7 @@ void WaylandThread::_wl_pointer_on_frame(void *data, struct wl_pointer *wl_point mm->set_position(pd.position); mm->set_global_position(pd.position); - Vector2i pos_delta = pd.position - old_pd.position; + Vector2 pos_delta = pd.position - old_pd.position; if (old_pd.relative_motion_time != pd.relative_motion_time) { uint32_t time_delta = pd.relative_motion_time - old_pd.relative_motion_time; @@ -1645,7 +1655,7 @@ void WaylandThread::_wl_pointer_on_frame(void *data, struct wl_pointer *wl_point // We have to set the last position pressed here as we can't take for // granted what the individual events might have seen due to them not having - // a garaunteed order. + // a guaranteed order. if (mb->is_pressed()) { pd.last_pressed_position = pd.position; } @@ -2384,9 +2394,9 @@ void WaylandThread::_wp_tablet_tool_on_motion(void *data, struct zwp_tablet_tool double scale_factor = window_state_get_scale_factor(ws); - td.position.x = wl_fixed_to_int(x); - td.position.y = wl_fixed_to_int(y); - td.position = scale_vector2i(td.position, scale_factor); + td.position.x = wl_fixed_to_double(x); + td.position.y = wl_fixed_to_double(y); + td.position *= scale_factor; td.motion_time = OS::get_singleton()->get_ticks_msec(); } @@ -2516,7 +2526,7 @@ void WaylandThread::_wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_ mm->set_relative(td.position - old_td.position); mm->set_relative_screen_position(mm->get_relative()); - Vector2i pos_delta = td.position - old_td.position; + Vector2 pos_delta = td.position - old_td.position; uint32_t time_delta = td.motion_time - old_td.motion_time; mm->set_velocity((Vector2)pos_delta / time_delta); @@ -3067,19 +3077,25 @@ void WaylandThread::seat_state_confine_pointer(SeatState *p_ss) { void WaylandThread::seat_state_update_cursor(SeatState *p_ss) { ERR_FAIL_NULL(p_ss); + + WaylandThread *thread = p_ss->wayland_thread; ERR_FAIL_NULL(p_ss->wayland_thread); - if (p_ss->wl_pointer && p_ss->cursor_surface) { - // NOTE: Those values are valid by default and will hide the cursor when - // unchanged, which happens when both the current custom cursor and the - // current wl_cursor are `nullptr`. - struct wl_buffer *cursor_buffer = nullptr; - uint32_t hotspot_x = 0; - uint32_t hotspot_y = 0; - int scale = 1; + if (!p_ss->wl_pointer || !p_ss->cursor_surface) { + return; + } + + // NOTE: Those values are valid by default and will hide the cursor when + // unchanged. + struct wl_buffer *cursor_buffer = nullptr; + uint32_t hotspot_x = 0; + uint32_t hotspot_y = 0; + int scale = 1; + + if (thread->cursor_visible) { + DisplayServer::CursorShape shape = thread->cursor_shape; - CustomCursor *custom_cursor = p_ss->wayland_thread->current_custom_cursor; - struct wl_cursor *wl_cursor = p_ss->wayland_thread->current_wl_cursor; + struct CustomCursor *custom_cursor = thread->custom_cursors.getptr(shape); if (custom_cursor) { cursor_buffer = custom_cursor->wl_buffer; @@ -3089,7 +3105,13 @@ void WaylandThread::seat_state_update_cursor(SeatState *p_ss) { // We can't really reasonably scale custom cursors, so we'll let the // compositor do it for us (badly). scale = 1; - } else if (wl_cursor) { + } else { + struct wl_cursor *wl_cursor = thread->wl_cursors[shape]; + + if (!wl_cursor) { + return; + } + int frame_idx = 0; if (wl_cursor->image_count > 1) { @@ -3105,24 +3127,24 @@ void WaylandThread::seat_state_update_cursor(SeatState *p_ss) { struct wl_cursor_image *wl_cursor_image = wl_cursor->images[frame_idx]; - scale = p_ss->wayland_thread->cursor_scale; + scale = thread->cursor_scale; cursor_buffer = wl_cursor_image_get_buffer(wl_cursor_image); // As the surface's buffer is scaled (thus the surface is smaller) and the // hotspot must be expressed in surface-local coordinates, we need to scale - // them down accordingly. + // it down accordingly. hotspot_x = wl_cursor_image->hotspot_x / scale; hotspot_y = wl_cursor_image->hotspot_y / scale; } + } - wl_pointer_set_cursor(p_ss->wl_pointer, p_ss->pointer_enter_serial, p_ss->cursor_surface, hotspot_x, hotspot_y); - wl_surface_set_buffer_scale(p_ss->cursor_surface, scale); - wl_surface_attach(p_ss->cursor_surface, cursor_buffer, 0, 0); - wl_surface_damage_buffer(p_ss->cursor_surface, 0, 0, INT_MAX, INT_MAX); + wl_pointer_set_cursor(p_ss->wl_pointer, p_ss->pointer_enter_serial, p_ss->cursor_surface, hotspot_x, hotspot_y); + wl_surface_set_buffer_scale(p_ss->cursor_surface, scale); + wl_surface_attach(p_ss->cursor_surface, cursor_buffer, 0, 0); + wl_surface_damage_buffer(p_ss->cursor_surface, 0, 0, INT_MAX, INT_MAX); - wl_surface_commit(p_ss->cursor_surface); - } + wl_surface_commit(p_ss->cursor_surface); } void WaylandThread::seat_state_echo_keys(SeatState *p_ss) { @@ -3763,25 +3785,8 @@ Error WaylandThread::init() { return OK; } -void WaylandThread::cursor_hide() { - current_wl_cursor = nullptr; - current_custom_cursor = nullptr; - - SeatState *ss = wl_seat_get_seat_state(wl_seat_current); - ERR_FAIL_NULL(ss); - seat_state_update_cursor(ss); -} - -void WaylandThread::cursor_set_shape(DisplayServer::CursorShape p_cursor_shape) { - if (!wl_cursors[p_cursor_shape]) { - return; - } - - // The point of this method is make the current cursor a "plain" shape and, as - // the custom cursor overrides what gets set, we have to clear it too. - current_custom_cursor = nullptr; - - current_wl_cursor = wl_cursors[p_cursor_shape]; +void WaylandThread::cursor_set_visible(bool p_visible) { + cursor_visible = p_visible; for (struct wl_seat *wl_seat : registry.wl_seats) { SeatState *ss = wl_seat_get_seat_state(wl_seat); @@ -3789,14 +3794,10 @@ void WaylandThread::cursor_set_shape(DisplayServer::CursorShape p_cursor_shape) seat_state_update_cursor(ss); } - - last_cursor_shape = p_cursor_shape; } -void WaylandThread::cursor_set_custom_shape(DisplayServer::CursorShape p_cursor_shape) { - ERR_FAIL_COND(!custom_cursors.has(p_cursor_shape)); - - current_custom_cursor = &custom_cursors[p_cursor_shape]; +void WaylandThread::cursor_set_shape(DisplayServer::CursorShape p_cursor_shape) { + cursor_shape = p_cursor_shape; for (struct wl_seat *wl_seat : registry.wl_seats) { SeatState *ss = wl_seat_get_seat_state(wl_seat); @@ -3804,8 +3805,6 @@ void WaylandThread::cursor_set_custom_shape(DisplayServer::CursorShape p_cursor_ seat_state_update_cursor(ss); } - - last_cursor_shape = p_cursor_shape; } void WaylandThread::cursor_shape_set_custom_image(DisplayServer::CursorShape p_cursor_shape, Ref<Image> p_image, const Point2i &p_hotspot) { @@ -3825,23 +3824,21 @@ void WaylandThread::cursor_shape_set_custom_image(DisplayServer::CursorShape p_c CustomCursor &cursor = custom_cursors[p_cursor_shape]; cursor.hotspot = p_hotspot; + if (cursor.wl_buffer) { + // Clean up the old Wayland buffer. + wl_buffer_destroy(cursor.wl_buffer); + } + if (cursor.buffer_data) { // Clean up the old buffer data. munmap(cursor.buffer_data, cursor.buffer_data_size); } - // NOTE: From `wl_keyboard`s of version 7 or later, the spec requires the mmap - // operation to be done with MAP_PRIVATE, as "MAP_SHARED may fail". We'll do it - // regardless of global version. - cursor.buffer_data = (uint32_t *)mmap(nullptr, data_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - - if (cursor.wl_buffer) { - // Clean up the old Wayland buffer. - wl_buffer_destroy(cursor.wl_buffer); - } + cursor.buffer_data = (uint32_t *)mmap(nullptr, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + cursor.buffer_data_size = data_size; // Create the Wayland buffer. - struct wl_shm_pool *wl_shm_pool = wl_shm_create_pool(registry.wl_shm, fd, image_size.height * data_size); + struct wl_shm_pool *wl_shm_pool = wl_shm_create_pool(registry.wl_shm, fd, data_size); // TODO: Make sure that WL_SHM_FORMAT_ARGB8888 format is supported. It // technically isn't garaunteed to be supported, but I think that'd be a // pretty unlikely thing to stumble upon. @@ -3869,8 +3866,6 @@ void WaylandThread::cursor_shape_clear_custom_image(DisplayServer::CursorShape p CustomCursor cursor = custom_cursors[p_cursor_shape]; custom_cursors.erase(p_cursor_shape); - current_custom_cursor = nullptr; - if (cursor.wl_buffer) { wl_buffer_destroy(cursor.wl_buffer); } |