diff options
| -rw-r--r-- | examples/compositor/main.c | 84 | ||||
| -rw-r--r-- | examples/rotation.c | 2 | ||||
| -rw-r--r-- | examples/shared.c | 8 | ||||
| -rw-r--r-- | examples/shared.h | 4 | ||||
| -rw-r--r-- | include/wlr/types/wlr_seat.h | 62 | ||||
| -rw-r--r-- | types/meson.build | 1 | ||||
| -rw-r--r-- | types/wlr_seat.c | 213 | 
7 files changed, 365 insertions, 9 deletions
| diff --git a/examples/compositor/main.c b/examples/compositor/main.c index 8a9de2f9..1fe81046 100644 --- a/examples/compositor/main.c +++ b/examples/compositor/main.c @@ -4,6 +4,8 @@  #include <stdlib.h>  #include <time.h>  #include <inttypes.h> +#include <unistd.h> +#include <sys/mman.h>  #include <wayland-server.h>  #include <wlr/backend.h>  #include <wlr/backend/session.h> @@ -14,16 +16,26 @@  #include <wlr/types/wlr_surface.h>  #include <wlr/types/wlr_wl_shell.h>  #include <wlr/types/wlr_xdg_shell_v6.h> +#include <wlr/types/wlr_seat.h>  #include <xkbcommon/xkbcommon.h>  #include <wlr/util/log.h>  #include "shared.h"  #include "compositor.h" +// TODO: move to common header? +int os_create_anonymous_file(off_t size); +  struct sample_state {  	struct wlr_renderer *renderer;  	struct wl_compositor_state compositor;  	struct wlr_wl_shell *wl_shell; +	struct wlr_seat *wl_seat;  	struct wlr_xdg_shell_v6 *xdg_shell; +	struct wl_resource *focus; +	struct wl_listener keyboard_bound; +	int keymap_fd; +	size_t keymap_size; +	uint32_t serial;  };  /* @@ -33,7 +45,7 @@ static inline int64_t timespec_to_msec(const struct timespec *a) {  	return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000;  } -void output_frame_handle_surface(struct sample_state *sample, +static void output_frame_handle_surface(struct sample_state *sample,  		struct wlr_output *wlr_output, struct timespec *ts,  		struct wl_resource *_res) {  	struct wlr_surface *surface = wl_resource_get_user_data(_res); @@ -53,7 +65,7 @@ void output_frame_handle_surface(struct sample_state *sample,  		}  	}  } -void handle_output_frame(struct output_state *output, struct timespec *ts) { +static void handle_output_frame(struct output_state *output, struct timespec *ts) {  	struct compositor_state *state = output->compositor;  	struct sample_state *sample = state->data;  	struct wlr_output *wlr_output = output->output; @@ -74,11 +86,58 @@ void handle_output_frame(struct output_state *output, struct timespec *ts) {  	wlr_output_swap_buffers(wlr_output);  } +static void handle_keyboard_key(struct keyboard_state *keyboard, uint32_t keycode, +	 	xkb_keysym_t sym, enum wlr_key_state key_state) { +	struct compositor_state *state = keyboard->compositor; +	struct sample_state *sample = state->data; + +	struct wl_resource *res = NULL; +	struct wlr_seat_handle *seat_handle = NULL; +	wl_list_for_each(res, &sample->compositor.surfaces, link) { +		break; +	} + +	if (res) { +		seat_handle = wlr_seat_handle_for_client(sample->wl_seat, +			wl_resource_get_client(res)); +	} + +	if (res != sample->focus && seat_handle && seat_handle->keyboard) { +		struct wl_array keys; +		wl_array_init(&keys); +		wl_keyboard_send_enter(seat_handle->keyboard, ++sample->serial, res, &keys); +		sample->focus = res; +	} + +	if (seat_handle && seat_handle->keyboard) { +		uint32_t depressed = xkb_state_serialize_mods(keyboard->xkb_state, +			XKB_STATE_MODS_DEPRESSED); +		uint32_t latched = xkb_state_serialize_mods(keyboard->xkb_state, +			XKB_STATE_MODS_LATCHED); +		uint32_t locked = xkb_state_serialize_mods(keyboard->xkb_state, +			XKB_STATE_MODS_LOCKED); +		uint32_t group = xkb_state_serialize_layout(keyboard->xkb_state, +			XKB_STATE_LAYOUT_EFFECTIVE); +		wl_keyboard_send_modifiers(seat_handle->keyboard, ++sample->serial, depressed, +			latched, locked, group); +		wl_keyboard_send_key(seat_handle->keyboard, ++sample->serial, 0, keycode, key_state); +	} +} + +static void handle_keyboard_bound(struct wl_listener *listener, void *data) { +	struct wlr_seat_handle *handle = data; +	struct sample_state *state = wl_container_of(listener, state, keyboard_bound); + +	wl_keyboard_send_keymap(handle->keyboard, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, +		state->keymap_fd, state->keymap_size); +} +  int main() {  	struct sample_state state = { 0 };  	struct compositor_state compositor = { 0,  		.data = &state,  		.output_frame_cb = handle_output_frame, +		.keyboard_key_cb = handle_keyboard_key  	};  	compositor_init(&compositor); @@ -92,8 +151,29 @@ int main() {  	state.wl_shell = wlr_wl_shell_create(compositor.display);  	state.xdg_shell = wlr_xdg_shell_v6_create(compositor.display); +	state.wl_seat = wlr_seat_create(compositor.display, "seat0"); +	state.keyboard_bound.notify = handle_keyboard_bound; +	wl_signal_add(&state.wl_seat->events.keyboard_bound, &state.keyboard_bound); +	wlr_seat_set_capabilities(state.wl_seat, WL_SEAT_CAPABILITY_KEYBOARD +		| WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_TOUCH); + +	struct keyboard_state *kbstate; +	wl_list_for_each(kbstate, &compositor.keyboards, link) { +		char *keymap = xkb_keymap_get_as_string(kbstate->keymap, +			XKB_KEYMAP_FORMAT_TEXT_V1); +		state.keymap_size = strlen(keymap); +		state.keymap_fd = os_create_anonymous_file(state.keymap_size); +		void *ptr = mmap(NULL, state.keymap_size, +				     PROT_READ | PROT_WRITE, +				     MAP_SHARED, state.keymap_fd, 0); +		strcpy(ptr, keymap); +		free(keymap); +		break; +	} +  	compositor_run(&compositor);  	wlr_wl_shell_destroy(state.wl_shell);  	wlr_xdg_shell_v6_destroy(state.xdg_shell); +	close(state.keymap_fd);  } diff --git a/examples/rotation.c b/examples/rotation.c index fc12558f..7024b249 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -104,7 +104,7 @@ static void update_velocities(struct compositor_state *state,  }  static void handle_keyboard_key(struct keyboard_state *kbstate, -		xkb_keysym_t sym, enum wlr_key_state key_state) { +		uint32_t keycode, xkb_keysym_t sym, enum wlr_key_state key_state) {  	// NOTE: It may be better to simply refer to our key state during each frame  	// and make this change in pixels/sec^2  	// Also, key repeat diff --git a/examples/shared.c b/examples/shared.c index b2818578..58aef21a 100644 --- a/examples/shared.c +++ b/examples/shared.c @@ -32,6 +32,9 @@ static void keyboard_key_notify(struct wl_listener *listener, void *data) {  	enum wlr_key_state key_state = event->state;  	const xkb_keysym_t *syms;  	int nsyms = xkb_state_key_get_syms(kbstate->xkb_state, keycode, &syms); +	xkb_state_update_key(kbstate->xkb_state, keycode, +		event->state == WLR_KEY_PRESSED ?  XKB_KEY_DOWN : XKB_KEY_UP); +	keyboard_led_update(kbstate);  	for (int i = 0; i < nsyms; ++i) {  		xkb_keysym_t sym = syms[i];  		char name[64]; @@ -41,7 +44,7 @@ static void keyboard_key_notify(struct wl_listener *listener, void *data) {  					key_state == WLR_KEY_PRESSED ? "pressed" : "released");  		}  		if (kbstate->compositor->keyboard_key_cb) { -			kbstate->compositor->keyboard_key_cb(kbstate, sym, key_state); +			kbstate->compositor->keyboard_key_cb(kbstate, event->keycode, sym, key_state);  		}  		if (sym == XKB_KEY_Escape) {  			wl_display_terminate(kbstate->compositor->display); @@ -57,9 +60,6 @@ static void keyboard_key_notify(struct wl_listener *listener, void *data) {  			}  		}  	} -	xkb_state_update_key(kbstate->xkb_state, keycode, -		event->state == WLR_KEY_PRESSED ?  XKB_KEY_DOWN : XKB_KEY_UP); -	keyboard_led_update(kbstate);  }  static void keyboard_add(struct wlr_input_device *device, struct compositor_state *state) { diff --git a/examples/shared.h b/examples/shared.h index 2379eef9..9ffd506a 100644 --- a/examples/shared.h +++ b/examples/shared.h @@ -79,8 +79,8 @@ struct compositor_state {  	void (*output_frame_cb)(struct output_state *s, struct timespec *ts);  	void (*output_remove_cb)(struct output_state *s);  	void (*keyboard_remove_cb)(struct keyboard_state *s); -	void (*keyboard_key_cb)(struct keyboard_state *s, xkb_keysym_t sym, -			enum wlr_key_state key_state); +	void (*keyboard_key_cb)(struct keyboard_state *s, uint32_t keycode, +			xkb_keysym_t sym, enum wlr_key_state key_state);  	void (*pointer_motion_cb)(struct pointer_state *s,  			double d_x, double d_y);  	void (*pointer_motion_absolute_cb)(struct pointer_state *s, diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h new file mode 100644 index 00000000..99c09258 --- /dev/null +++ b/include/wlr/types/wlr_seat.h @@ -0,0 +1,62 @@ +#ifndef _WLR_TYPES_SEAT_H +#define _WLR_TYPES_SEAT_H +#include <wayland-server.h> + +/** + * Contains state for a single client's bound wl_seat resource and can be used + * to issue input events to that client. The lifetime of these objects is + * managed by wlr_seat; some may be NULL. + */ +struct wlr_seat_handle { +	struct wl_resource *wl_resource; +	struct wlr_seat *wlr_seat; + +	struct wl_resource *pointer; +	struct wl_resource *keyboard; +	struct wl_resource *touch; + +	struct wl_list link; +}; + +struct wlr_seat { +	struct wl_global *wl_global; +	struct wl_list handles; +	char *name; +	uint32_t capabilities; + +	struct { +		struct wl_signal client_bound; +		struct wl_signal client_unbound; +		struct wl_signal keyboard_bound; +	} events; + +	void *data; +}; + + +/** + * Allocates a new wlr_seat and adds a wl_seat global to the display. + */ +struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name); +/** + * Destroys a wlr_seat and removes its wl_seat global. + */ +void wlr_seat_destroy(struct wlr_seat *wlr_seat); +/** + * Gets a wlr_seat_handle for the specified client, or returns NULL if no + * handle is bound for that client. + */ +struct wlr_seat_handle *wlr_seat_handle_for_client(struct wlr_seat *wlr_seat, +		struct wl_client *client); +/** + * Updates the capabilities available on this seat. + * Will automatically send them to all clients. + */ +void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat, uint32_t capabilities); +/** + * Updates the name of this seat. + * Will automatically send it to all clients. + */ +void wlr_seat_set_name(struct wlr_seat *wlr_seat, const char *name); + +#endif diff --git a/types/meson.build b/types/meson.build index 943c83c3..61dd913c 100644 --- a/types/meson.build +++ b/types/meson.build @@ -4,6 +4,7 @@ lib_wlr_types = static_library('wlr_types', files(      'wlr_output.c',      'wlr_pointer.c',      'wlr_region.c', +    'wlr_seat.c',      'wlr_surface.c',      'wlr_tablet_pad.c',      'wlr_tablet_tool.c', diff --git a/types/wlr_seat.c b/types/wlr_seat.c new file mode 100644 index 00000000..05da9a43 --- /dev/null +++ b/types/wlr_seat.c @@ -0,0 +1,213 @@ +#define _POSIX_C_SOURCE 200809L +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <wayland-server.h> +#include <wlr/types/wlr_seat.h> +#include <wlr/util/log.h> + +static void resource_destroy(struct wl_client *client, +		struct wl_resource *resource) { +	wl_resource_destroy(resource); +} + +static void wl_pointer_set_cursor(struct wl_client *client, +	   struct wl_resource *resource, +	   uint32_t serial, +	   struct wl_resource *surface, +	   int32_t hotspot_x, +	   int32_t hotspot_y) { +	wlr_log(L_DEBUG, "TODO: wl_pointer_set_cursor"); +} + +static const struct wl_pointer_interface wl_pointer_impl = { +	.set_cursor = wl_pointer_set_cursor, +	.release = resource_destroy +}; + +static void wl_pointer_destroy(struct wl_resource *resource) { +	struct wlr_seat_handle *handle = wl_resource_get_user_data(resource); +	if (handle->pointer) { +		handle->pointer = NULL; +	} +} + +static void wl_seat_get_pointer(struct wl_client *client, +		struct wl_resource *_handle, uint32_t id) { +	struct wlr_seat_handle *handle = wl_resource_get_user_data(_handle); +	if (!(handle->wlr_seat->capabilities & WL_SEAT_CAPABILITY_POINTER)) { +		return; +	} +	if (handle->pointer) { +		// TODO: this is probably a protocol violation but it simplifies our +		// code and it'd be stupid for clients to create several pointers for +		// the same seat +		wl_resource_destroy(handle->pointer); +	} +	handle->pointer = wl_resource_create(client, &wl_pointer_interface, +		wl_resource_get_version(_handle), id); +	wl_resource_set_implementation(handle->pointer, &wl_pointer_impl, +		handle, &wl_pointer_destroy); +} + +static const struct wl_keyboard_interface wl_keyboard_impl = { +	.release = resource_destroy +}; + +static void wl_keyboard_destroy(struct wl_resource *resource) { +	struct wlr_seat_handle *handle = wl_resource_get_user_data(resource); +	if (handle->keyboard) { +		handle->keyboard = NULL; +	} +} + +static void wl_seat_get_keyboard(struct wl_client *client, +		struct wl_resource *_handle, uint32_t id) { +	struct wlr_seat_handle *handle = wl_resource_get_user_data(_handle); +	if (!(handle->wlr_seat->capabilities & WL_SEAT_CAPABILITY_KEYBOARD)) { +		return; +	} +	if (handle->keyboard) { +		// TODO: this is probably a protocol violation but it simplifies our +		// code and it'd be stupid for clients to create several pointers for +		// the same seat +		wl_resource_destroy(handle->keyboard); +	} +	handle->keyboard = wl_resource_create(client, &wl_keyboard_interface, +		wl_resource_get_version(_handle), id); +	wl_resource_set_implementation(handle->keyboard, &wl_keyboard_impl, +		handle, &wl_keyboard_destroy); +	wl_signal_emit(&handle->wlr_seat->events.keyboard_bound, handle); +} + +static const struct wl_touch_interface wl_touch_impl = { +	.release = resource_destroy +}; + +static void wl_touch_destroy(struct wl_resource *resource) { +	struct wlr_seat_handle *handle = wl_resource_get_user_data(resource); +	if (handle->touch) { +		handle->touch = NULL; +	} +} + +static void wl_seat_get_touch(struct wl_client *client, +		struct wl_resource *_handle, uint32_t id) { +	struct wlr_seat_handle *handle = wl_resource_get_user_data(_handle); +	if (!(handle->wlr_seat->capabilities & WL_SEAT_CAPABILITY_TOUCH)) { +		return; +	} +	if (handle->touch) { +		// TODO: this is probably a protocol violation but it simplifies our +		// code and it'd be stupid for clients to create several pointers for +		// the same seat +		wl_resource_destroy(handle->touch); +	} +	handle->touch = wl_resource_create(client, &wl_touch_interface, +		wl_resource_get_version(_handle), id); +	wl_resource_set_implementation(handle->touch, &wl_touch_impl, +		handle, &wl_touch_destroy); +} + +static void wl_seat_destroy(struct wl_resource *resource) { +	struct wlr_seat_handle *handle = wl_resource_get_user_data(resource); +	if (handle->pointer) { +		wl_resource_destroy(handle->pointer); +	} +	if (handle->keyboard) { +		wl_resource_destroy(handle->keyboard); +	} +	if (handle->touch) { +		wl_resource_destroy(handle->touch); +	} +	wl_signal_emit(&handle->wlr_seat->events.client_unbound, handle); +	wl_list_remove(&handle->link); +	free(handle); +} + +struct wl_seat_interface wl_seat_impl = { +	.get_pointer = wl_seat_get_pointer, +	.get_keyboard = wl_seat_get_keyboard, +	.get_touch = wl_seat_get_touch, +	.release = resource_destroy +}; + +static void wl_seat_bind(struct wl_client *wl_client, void *_wlr_seat, +		uint32_t version, uint32_t id) { +	struct wlr_seat *wlr_seat = _wlr_seat; +	assert(wl_client && wlr_seat); +	if (version > 6) { +		wlr_log(L_ERROR, "Client requested unsupported wl_seat version, disconnecting"); +		wl_client_destroy(wl_client); +		return; +	} +	struct wlr_seat_handle *handle = calloc(1, sizeof(struct wlr_seat_handle)); +	handle->wl_resource = wl_resource_create( +			wl_client, &wl_seat_interface, version, id); +	handle->wlr_seat = wlr_seat; +	wl_resource_set_implementation(handle->wl_resource, &wl_seat_impl, +		handle, wl_seat_destroy); +	wl_list_insert(&wlr_seat->handles, &handle->link); +	wl_seat_send_capabilities(handle->wl_resource, wlr_seat->capabilities); +	wl_signal_emit(&wlr_seat->events.client_bound, handle); +} + +struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { +	struct wlr_seat *wlr_seat = calloc(1, sizeof(struct wlr_seat)); +	if (!wlr_seat) { +		return NULL; +	} +	struct wl_global *wl_global = wl_global_create(display, +		&wl_seat_interface, 6, wlr_seat, wl_seat_bind); +	if (!wl_global) { +		free(wlr_seat); +		return NULL; +	} +	wlr_seat->wl_global = wl_global; +	wlr_seat->name = strdup(name); +	wl_list_init(&wlr_seat->handles); +	wl_signal_init(&wlr_seat->events.client_bound); +	wl_signal_init(&wlr_seat->events.client_unbound); +	wl_signal_init(&wlr_seat->events.keyboard_bound); +	return wlr_seat; +} + +void wlr_seat_destroy(struct wlr_seat *wlr_seat) { +	if (!wlr_seat) { +		return; +	} + +	wl_global_destroy(wlr_seat->wl_global); +	free(wlr_seat->name); +	free(wlr_seat); +} + +struct wlr_seat_handle *wlr_seat_handle_for_client(struct wlr_seat *wlr_seat, +		struct wl_client *client) { +	assert(wlr_seat); +	struct wlr_seat_handle *handle; +	wl_list_for_each(handle, &wlr_seat->handles, link) { +		if (wl_resource_get_client(handle->wl_resource) == client) { +			return handle; +		} +	} +	return NULL; +} + +void wlr_seat_set_capabilities(struct wlr_seat *wlr_seat, +		uint32_t capabilities) { +	wlr_seat->capabilities = capabilities; +	struct wlr_seat_handle *handle; +	wl_list_for_each(handle, &wlr_seat->handles, link) { +		wl_seat_send_capabilities(handle->wl_resource, capabilities); +	} +} + +void wlr_seat_set_name(struct wlr_seat *wlr_seat, const char *name) { +	free(wlr_seat->name); +	wlr_seat->name = strdup(name); +	struct wlr_seat_handle *handle; +	wl_list_for_each(handle, &wlr_seat->handles, link) { +		wl_seat_send_name(handle->wl_resource, name); +	} +} | 
