Repository: godotengine/godot
File: platform/linuxbsd/wayland/wayland_thread.cpp (C++)

Code before:
		xkb_keycode_t xkb_keycode = KeyMappingXKB::get_xkb_keycode(p_key);
		return KeyMappingXKB::get_keycode(xkb_state_key_get_one_sym(ss->xkb_state, xkb_keycode));
	}

	return Key::NONE;
}

void WaylandThread::keyboard_echo_keys() {
	SeatState *ss = wl_seat_get_seat_state(wl_seat_current);

	if (ss) {
		seat_state_echo_keys(ss);
	}
}

void WaylandThread::selection_set_text(const String &p_text) {
	SeatState *ss = wl_seat_get_seat_state(wl_seat_current);

	if (registry.wl_data_device_manager == nullptr) {
		DEBUG_LOG_WAYLAND_THREAD("Couldn't set selection, wl_data_device_manager global not available.");
		return;
	}

	if (ss == nullptr) {
		DEBUG_LOG_WAYLAND_THREAD("Couldn't set selection, current seat not set.");
		return;
	}

	if (ss->wl_data_device == nullptr) {
		DEBUG_LOG_WAYLAND_THREAD("Couldn't set selection, seat doesn't have wl_data_device.");
		return;
	}

	ss->selection_data = p_text.to_utf8_buffer();

	if (ss->wl_data_source_selection == nullptr) {
		ss->wl_data_source_selection = wl_data_device_manager_create_data_source(registry.wl_data_device_manager);
		wl_data_source_add_listener(ss->wl_data_source_selection, &wl_data_source_listener, ss);
		wl_data_source_offer(ss->wl_data_source_selection, "text/plain;charset=utf-8");
		wl_data_source_offer(ss->wl_data_source_selection, "text/plain");

		// TODO: Implement a good way of getting the latest serial from the user.
		wl_data_device_set_selection(ss->wl_data_device, ss->wl_data_source_selection, MAX(ss->pointer_data.button_serial, ss->last_key_pressed_serial));
	}

	// Wait for the message to get to the server before continuing, otherwise the
	// clipboard update might come with a delay.
	wl_display_roundtrip(wl_display);
}

bool WaylandThread::selection_has_mime(const String &p_mime) const {

Review comment (suggestion):
random note: I think that the reason that this does not work is the fact that we do not wait for a frame/commit before setting the old constraint, as [the hint is double-buffered](https://wayland.app/protocols/pointer-constraints-unstable-v1#zwp_locked_pointer_v1:request:set_cursor_position_hint):

> The cursor position hint is double-buffered state, see wl_surface.commit.

We "could" do a roundtrip/commit there but committing in the middle of the frame is a bad, bad idea: #93684 (IIRC main thread commits are safe but the less the better)

IIRC this works on sway, which I think has a way more liberal interpretation, that's why I never noticed it.

To be clear, this is absolutely not something you should look in in this PR, it's for reference.

I really appreciate your PR, as there are lots of tiny rough edges here and there that I should look into (including good documentation about the backend) but my limited time is completely absorbed by the embedder PR, thank you.

Code after:
		return;
	}

	// NOTE: It looks like it's not really recommended to convert from
	// "godot-space" to "wayland-space" and in general I received mixed feelings
	// discussing about this. I'm not really sure about the maths behind this but,
	// oh well, we're setting a cursor hint. ¯\_(ツ)_/¯
	// See: https://oftc.irclog.whitequark.org/wayland/2023-08-23#1692756914-1692816818
	int hint_x = Math::round(p_hint.x / window_state_get_scale_factor(ws));
	int hint_y = Math::round(p_hint.y / window_state_get_scale_factor(ws));

	if (ss) {
		seat_state_set_hint(ss, hint_x, hint_y);
	}
}

void WaylandThread::pointer_warp(const Point2i &p_to) {
	// NOTE: This is for compositors that don't support the pointer-warp protocol.
	// It's hacked together and not guaranteed to work.
	if (registry.wp_pointer_warp == nullptr) {
		PointerConstraint old_constraint = pointer_get_constraint();

		pointer_set_constraint(PointerConstraint::LOCKED);
		pointer_set_hint(p_to);

		pointer_set_constraint(old_constraint);

		return;
	}

	SeatState *ss = wl_seat_get_seat_state(wl_seat_current);
	if (!ss) {
		return;
	}

	WindowState *ws = window_get_state(ss->pointer_data.pointed_id);
	if (!ws) {
		return;
	}

	// NOTE: It looks like it's not really recommended to convert from
	// "godot-space" to "wayland-space" and in general I received mixed feelings
	// discussing about this. I'm not really sure about the maths behind this but,
	// oh well. ¯\_(ツ)_/¯
	// See: https://oftc.irclog.whitequark.org/wayland/2023-08-23#1692756914-1692816818
	int wl_pos_x = Math::round(p_to.x / window_state_get_scale_factor(ws));
	int wl_pos_y = Math::round(p_to.y / window_state_get_scale_factor(ws));

	if (ss) {
		seat_state_warp_pointer(ss, wl_pos_x, wl_pos_y);
	}