commit
						fa4a04da22
					
				|  | @ -0,0 +1,19 @@ | |||
| # - Find XKBCommon | ||||
| # Once done, this will define | ||||
| # | ||||
| #   XKBCOMMON_FOUND - System has XKBCommon | ||||
| #   XKBCOMMON_INCLUDE_DIRS - The XKBCommon include directories | ||||
| #   XKBCOMMON_LIBRARIES - The libraries needed to use XKBCommon | ||||
| #   XKBCOMMON_DEFINITIONS - Compiler switches required for using XKBCommon | ||||
| 
 | ||||
| find_package(PkgConfig) | ||||
| pkg_check_modules(PC_XKBCOMMON QUIET xkbcommon) | ||||
| find_path(XKBCOMMON_INCLUDE_DIRS NAMES xkbcommon/xkbcommon.h HINTS ${PC_XKBCOMMON_INCLUDE_DIRS}) | ||||
| find_library(XKBCOMMON_LIBRARIES NAMES xkbcommon HINTS ${PC_XKBCOMMON_LIBRARY_DIRS}) | ||||
| 
 | ||||
| set(XKBCOMMON_DEFINITIONS ${PC_XKBCOMMON_CFLAGS_OTHER}) | ||||
| 
 | ||||
| include(FindPackageHandleStandardArgs) | ||||
| find_package_handle_standard_args(XKBCOMMON DEFAULT_MSG XKBCOMMON_LIBRARIES XKBCOMMON_INCLUDE_DIRS) | ||||
| mark_as_advanced(XKBCOMMON_LIBRARIES XKBCOMMON_INCLUDE_DIRS) | ||||
| 
 | ||||
|  | @ -2,9 +2,6 @@ cmake_minimum_required(VERSION 3.1.0) | |||
| 
 | ||||
| project(wlroots C) | ||||
| 
 | ||||
| if (CMAKE_BUILD_TYPE EQUAL "Debug") | ||||
|     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") | ||||
| endif() | ||||
| set(CMAKE_C_STANDARD 99) | ||||
| set(CMAKE_C_EXTENSIONS OFF) | ||||
| set(CMAKE_POSITION_INDEPENDENT_CODE ON) | ||||
|  | @ -51,6 +48,7 @@ find_package(GLESv2 REQUIRED) | |||
| find_package(DRM REQUIRED) | ||||
| find_package(GBM REQUIRED) | ||||
| find_package(LibInput REQUIRED) | ||||
| find_package(XKBCommon REQUIRED) | ||||
| find_package(Udev REQUIRED) | ||||
| find_package(Systemd) | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ include_directories( | |||
| 	${PROTOCOLS_INCLUDE_DIRS} | ||||
| 	${WAYLAND_INCLUDE_DIR} | ||||
| 	${DRM_INCLUDE_DIRS} | ||||
|     ${LIBINPUT_INCLUDE_DIRS} | ||||
| ) | ||||
| 
 | ||||
| add_library(wlr-backend | ||||
|  | @ -9,11 +10,22 @@ add_library(wlr-backend | |||
|     #wayland/registry.c | ||||
|     #wayland/wl_seat.c | ||||
|     #wayland/wl_output.c | ||||
| 
 | ||||
|     drm/backend.c | ||||
|     drm/drm.c | ||||
|     udev.c | ||||
| 
 | ||||
|     libinput/backend.c | ||||
|     libinput/events.c | ||||
|     libinput/keyboard.c | ||||
|     libinput/pointer.c | ||||
|     libinput/touch.c | ||||
|     libinput/tablet_tool.c | ||||
|     libinput/tablet_pad.c | ||||
| 
 | ||||
|     multi/backend.c | ||||
|     backend.c | ||||
|     egl.c | ||||
|     udev.c | ||||
| ) | ||||
| 
 | ||||
| target_link_libraries(wlr-backend | ||||
|  | @ -26,5 +38,6 @@ target_link_libraries(wlr-backend | |||
|     ${EGL_LIBRARIES} | ||||
|     ${SYSTEMD_LIBRARIES} | ||||
|     ${UDEV_LIBRARIES} | ||||
|     ${LIBINPUT_LIBRARIES} | ||||
|     ${GBM_LIBRARIES} | ||||
| ) | ||||
|  |  | |||
|  | @ -3,10 +3,15 @@ | |||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <errno.h> | ||||
| #include <libinput.h> | ||||
| #include <wlr/session.h> | ||||
| #include <wlr/backend/interface.h> | ||||
| #include <wlr/backend/drm.h> | ||||
| #include <wlr/backend/libinput.h> | ||||
| #include <wlr/backend/multi.h> | ||||
| #include "backend/libinput.h" | ||||
| #include "backend/udev.h" | ||||
| #include "common/log.h" | ||||
| #include "backend/drm.h" | ||||
| 
 | ||||
| struct wlr_backend *wlr_backend_create(const struct wlr_backend_impl *impl, | ||||
| 		struct wlr_backend_state *state) { | ||||
|  | @ -17,14 +22,10 @@ struct wlr_backend *wlr_backend_create(const struct wlr_backend_impl *impl, | |||
| 	} | ||||
| 	backend->state = state; | ||||
| 	backend->impl = impl; | ||||
| 	wl_signal_init(&backend->events.input_add); | ||||
| 	wl_signal_init(&backend->events.input_remove); | ||||
| 	wl_signal_init(&backend->events.output_add); | ||||
| 	wl_signal_init(&backend->events.output_remove); | ||||
| 	wl_signal_init(&backend->events.keyboard_add); | ||||
| 	wl_signal_init(&backend->events.keyboard_remove); | ||||
| 	wl_signal_init(&backend->events.pointer_add); | ||||
| 	wl_signal_init(&backend->events.pointer_remove); | ||||
| 	wl_signal_init(&backend->events.touch_add); | ||||
| 	wl_signal_init(&backend->events.touch_remove); | ||||
| 	return backend; | ||||
| } | ||||
| 
 | ||||
|  | @ -51,12 +52,27 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display, | |||
| 		wlr_log(L_ERROR, "Failed to open DRM device"); | ||||
| 		goto error_udev; | ||||
| 	} | ||||
| 	struct wlr_backend *wlr; | ||||
| 	wlr = wlr_drm_backend_create(display, session, udev, gpu); | ||||
| 	if (!wlr) { | ||||
| 	struct wlr_backend *multi = wlr_multi_backend_create(); | ||||
| 	if (!multi) { | ||||
| 		goto error_gpu; | ||||
| 	} | ||||
| 	return wlr; | ||||
| 	struct wlr_backend *libinput = | ||||
| 		wlr_libinput_backend_create(display, session, udev); | ||||
| 	if (!libinput) { | ||||
| 		goto error_multi; | ||||
| 	} | ||||
| 	struct wlr_backend *drm = | ||||
| 		wlr_drm_backend_create(display, session, udev, gpu); | ||||
| 	if (!drm) { | ||||
| 		goto error_libinput; | ||||
| 	} | ||||
| 	wlr_multi_backend_add(multi, libinput); | ||||
| 	wlr_multi_backend_add(multi, drm); | ||||
| 	return multi; | ||||
| error_libinput: | ||||
| 	wlr_backend_destroy(libinput); | ||||
| error_multi: | ||||
| 	wlr_backend_destroy(multi); | ||||
| error_gpu: | ||||
| 	close(gpu); | ||||
| error_udev: | ||||
|  | @ -64,3 +80,7 @@ error_udev: | |||
| error: | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| struct libinput_device *wlr_libinput_get_device_handle(struct wlr_input_device *dev) { | ||||
| 	return dev->state->handle; | ||||
| } | ||||
|  |  | |||
|  | @ -112,8 +112,8 @@ static void wlr_drm_output_end(struct wlr_output_state *output) { | |||
| 	drmModePageFlip(renderer->fd, output->crtc, fb_id, DRM_MODE_PAGE_FLIP_EVENT, output); | ||||
| 	output->pageflip_pending = true; | ||||
| 
 | ||||
| 	output->bo_last = output->bo_current; | ||||
| 	output->bo_current = bo; | ||||
| 	output->bo[1] = output->bo[0]; | ||||
| 	output->bo[0] = bo; | ||||
| } | ||||
| 
 | ||||
| void wlr_drm_output_start_renderer(struct wlr_output_state *output) { | ||||
|  | @ -141,8 +141,8 @@ void wlr_drm_output_start_renderer(struct wlr_output_state *output) { | |||
| 	drmModePageFlip(renderer->fd, output->crtc, fb_id, | ||||
| 			DRM_MODE_PAGE_FLIP_EVENT, output); | ||||
| 
 | ||||
| 	output->bo_last = NULL; | ||||
| 	output->bo_current = bo; | ||||
| 	output->bo[1] = NULL; | ||||
| 	output->bo[0] = bo; | ||||
| } | ||||
| 
 | ||||
| static bool display_init_renderer(struct wlr_drm_renderer *renderer, | ||||
|  | @ -280,6 +280,63 @@ static void wlr_drm_output_transform(struct wlr_output_state *output, | |||
| 	output->wlr_output->transform = transform; | ||||
| } | ||||
| 
 | ||||
| static void wlr_drm_cursor_bo_update(struct wlr_output_state *output, | ||||
| 		uint32_t width, uint32_t height) { | ||||
| 	if (output->cursor_width == width && output->cursor_height == height) { | ||||
| 		return; | ||||
| 	} | ||||
| 	wlr_log(L_DEBUG, "Allocating new cursor bos"); | ||||
| 	struct wlr_backend_state *state = | ||||
| 		wl_container_of(output->renderer, state, renderer); | ||||
| 	for (size_t i = 0; i < 2; ++i) { | ||||
| 		output->cursor_bo[i] = gbm_bo_create(state->renderer.gbm, | ||||
| 				width, height, GBM_FORMAT_ARGB8888, | ||||
| 				GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE); | ||||
| 		if (!output->cursor_bo[i]) { | ||||
| 			wlr_log(L_ERROR, "Failed to create cursor bo"); | ||||
| 			return; | ||||
| 		} | ||||
| 		if (!get_fb_for_bo(state->fd, output->cursor_bo[i])) { | ||||
| 			wlr_log(L_ERROR, "Failed to create cursor fb"); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static bool wlr_drm_output_set_cursor(struct wlr_output_state *output, | ||||
| 		const uint8_t *buf, int32_t stride, uint32_t width, uint32_t height) { | ||||
| 	struct wlr_backend_state *state = | ||||
| 		wl_container_of(output->renderer, state, renderer); | ||||
| 	if (!buf) { | ||||
| 		drmModeSetCursor(state->fd, output->crtc, 0, 0, 0); | ||||
| 		return true; | ||||
| 	} | ||||
| 	wlr_drm_cursor_bo_update(output, width, height); | ||||
| 	struct gbm_bo *bo; | ||||
| 	output->current_cursor ^= 1; | ||||
| 	bo = output->cursor_bo[output->current_cursor]; | ||||
| 	uint32_t _buf[width * height]; | ||||
| 	memset(_buf, 0, sizeof(_buf)); | ||||
| 	for (size_t i = 0; i < height; ++i) { | ||||
| 		memcpy(_buf + i * width, | ||||
| 				buf + i * stride, | ||||
| 				width * 4); | ||||
| 	} | ||||
| 	if (gbm_bo_write(bo, _buf, sizeof(_buf)) < 0) { | ||||
| 		wlr_log(L_ERROR, "Failed to write cursor to bo"); | ||||
| 		return false; | ||||
| 	} | ||||
| 	return !drmModeSetCursor(state->fd, output->crtc, | ||||
| 			gbm_bo_get_handle(bo).s32, width, height); | ||||
| } | ||||
| 
 | ||||
| static bool wlr_drm_output_move_cursor(struct wlr_output_state *output, | ||||
| 		int x, int y) { | ||||
| 	struct wlr_backend_state *state = | ||||
| 		wl_container_of(output->renderer, state, renderer); | ||||
| 	return !drmModeMoveCursor(state->fd, output->crtc, x, y); | ||||
| } | ||||
| 
 | ||||
| static void wlr_drm_output_destroy(struct wlr_output_state *output) { | ||||
| 	wlr_drm_output_cleanup(output, true); | ||||
| 	free(output); | ||||
|  | @ -289,6 +346,8 @@ static struct wlr_output_impl output_impl = { | |||
| 	.enable = wlr_drm_output_enable, | ||||
| 	.set_mode = wlr_drm_output_set_mode, | ||||
| 	.transform = wlr_drm_output_transform, | ||||
| 	.set_cursor = wlr_drm_output_set_cursor, | ||||
| 	.move_cursor = wlr_drm_output_move_cursor, | ||||
| 	.destroy = wlr_drm_output_destroy, | ||||
| }; | ||||
| 
 | ||||
|  | @ -457,6 +516,29 @@ void wlr_drm_scan_connectors(struct wlr_backend_state *state) { | |||
| 			snprintf(wlr_output->name, sizeof(wlr_output->name), "%s-%"PRIu32, | ||||
| 				 conn_name[conn->connector_type], | ||||
| 				 conn->connector_type_id); | ||||
| 			wlr_output->phys_width = conn->mmWidth; | ||||
| 			wlr_output->phys_height = conn->mmHeight; | ||||
| 			switch (conn->subpixel) { | ||||
| 			case DRM_MODE_SUBPIXEL_UNKNOWN: | ||||
| 				wlr_output->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN; | ||||
| 				break; | ||||
| 			case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB: | ||||
| 				wlr_output->subpixel = WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB; | ||||
| 				break; | ||||
| 			case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR: | ||||
| 				wlr_output->subpixel = WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR; | ||||
| 				break; | ||||
| 			case DRM_MODE_SUBPIXEL_VERTICAL_RGB: | ||||
| 				wlr_output->subpixel = WL_OUTPUT_SUBPIXEL_VERTICAL_RGB; | ||||
| 				break; | ||||
| 			case DRM_MODE_SUBPIXEL_VERTICAL_BGR: | ||||
| 				wlr_output->subpixel = WL_OUTPUT_SUBPIXEL_VERTICAL_BGR; | ||||
| 				break; | ||||
| 			case DRM_MODE_SUBPIXEL_NONE: | ||||
| 			default: | ||||
| 				wlr_output->subpixel = WL_OUTPUT_SUBPIXEL_NONE; | ||||
| 				break; | ||||
| 			} | ||||
| 
 | ||||
| 			drmModeEncoder *curr_enc = drmModeGetEncoder(state->fd, conn->encoder_id); | ||||
| 			if (curr_enc) { | ||||
|  | @ -519,9 +601,9 @@ static void page_flip_handler(int fd, unsigned seq, | |||
| 	struct wlr_backend_state *state = | ||||
| 		wl_container_of(output->renderer, state, renderer); | ||||
| 
 | ||||
| 	if (output->bo_last) { | ||||
| 		gbm_surface_release_buffer(output->gbm, output->bo_last); | ||||
| 		output->bo_last = NULL; | ||||
| 	if (output->bo[1]) { | ||||
| 		gbm_surface_release_buffer(output->gbm, output->bo[1]); | ||||
| 		output->bo[1] = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	output->pageflip_pending = false; | ||||
|  |  | |||
|  | @ -0,0 +1,121 @@ | |||
| #include <stdlib.h> | ||||
| #include <assert.h> | ||||
| #include <libinput.h> | ||||
| #include <wlr/session.h> | ||||
| #include <wlr/backend/interface.h> | ||||
| #include "backend/udev.h" | ||||
| #include "backend/libinput.h" | ||||
| #include "common/log.h" | ||||
| 
 | ||||
| static int wlr_libinput_open_restricted(const char *path, | ||||
| 		int flags, void *_state) { | ||||
| 	struct wlr_backend_state *state = _state; | ||||
| 	return wlr_session_open_file(state->session, path); | ||||
| } | ||||
| 
 | ||||
| static void wlr_libinput_close_restricted(int fd, void *_state) { | ||||
| 	struct wlr_backend_state *state = _state; | ||||
| 	wlr_session_close_file(state->session, fd); | ||||
| } | ||||
| 
 | ||||
| static const struct libinput_interface libinput_impl = { | ||||
| 	.open_restricted = wlr_libinput_open_restricted, | ||||
| 	.close_restricted = wlr_libinput_close_restricted | ||||
| }; | ||||
| 
 | ||||
| static int wlr_libinput_readable(int fd, uint32_t mask, void *_state) { | ||||
| 	struct wlr_backend_state *state = _state; | ||||
| 	if (libinput_dispatch(state->libinput) != 0) { | ||||
| 		wlr_log(L_ERROR, "Failed to dispatch libinput"); | ||||
| 		// TODO: some kind of abort?
 | ||||
| 		return 0; | ||||
| 	} | ||||
| 	struct libinput_event *event; | ||||
| 	while ((event = libinput_get_event(state->libinput))) { | ||||
| 		wlr_libinput_event(state, event); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void wlr_libinput_log(struct libinput *libinput, | ||||
| 		enum libinput_log_priority priority, const char *fmt, va_list args) { | ||||
| 	_wlr_vlog(L_ERROR, fmt, args); | ||||
| } | ||||
| 
 | ||||
| static bool wlr_libinput_backend_init(struct wlr_backend_state *state) { | ||||
| 	wlr_log(L_DEBUG, "Initializing libinput"); | ||||
| 	state->libinput = libinput_udev_create_context(&libinput_impl, state, | ||||
| 			state->udev->udev); | ||||
| 	if (!state->libinput) { | ||||
| 		wlr_log(L_ERROR, "Failed to create libinput context"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: Let user customize seat used
 | ||||
| 	if (libinput_udev_assign_seat(state->libinput, "seat0") != 0) { | ||||
| 		wlr_log(L_ERROR, "Failed to assign libinput seat"); | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	// TODO: More sophisticated logging
 | ||||
| 	libinput_log_set_handler(state->libinput, wlr_libinput_log); | ||||
| 	libinput_log_set_priority(state->libinput, LIBINPUT_LOG_PRIORITY_ERROR); | ||||
| 
 | ||||
| 	struct wl_event_loop *event_loop = | ||||
| 		wl_display_get_event_loop(state->display); | ||||
| 	if (state->input_event) { | ||||
| 		wl_event_source_remove(state->input_event); | ||||
| 	} | ||||
| 	state->input_event = wl_event_loop_add_fd(event_loop, | ||||
| 			libinput_get_fd(state->libinput), WL_EVENT_READABLE, | ||||
| 			wlr_libinput_readable, state); | ||||
| 	if (!state->input_event) { | ||||
| 		wlr_log(L_ERROR, "Failed to create input event on event loop"); | ||||
| 		return false; | ||||
| 	} | ||||
| 	wlr_log(L_DEBUG, "libinput sucessfully initialized"); | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static void wlr_libinput_backend_destroy(struct wlr_backend_state *state) { | ||||
| 	// TODO
 | ||||
| } | ||||
| 
 | ||||
| static struct wlr_backend_impl backend_impl = { | ||||
| 	.init = wlr_libinput_backend_init, | ||||
| 	.destroy = wlr_libinput_backend_destroy | ||||
| }; | ||||
| 
 | ||||
| struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display, | ||||
| 		struct wlr_session *session, struct wlr_udev *udev) { | ||||
| 	assert(display && session && udev); | ||||
| 
 | ||||
| 	struct wlr_backend_state *state = calloc(1, sizeof(struct wlr_backend_state)); | ||||
| 	if (!state) { | ||||
| 		wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	struct wlr_backend *backend = wlr_backend_create(&backend_impl, state); | ||||
| 	if (!backend) { | ||||
| 		wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); | ||||
| 		goto error_state; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!(state->devices = list_create())) { | ||||
| 		wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); | ||||
| 		goto error_backend; | ||||
| 	} | ||||
| 
 | ||||
| 	state->backend = backend; | ||||
| 	state->session = session; | ||||
| 	state->udev = udev; | ||||
| 	state->display = display; | ||||
| 
 | ||||
| 	return backend; | ||||
| error_state: | ||||
| 	free(state); | ||||
| error_backend: | ||||
| 	wlr_backend_destroy(backend); | ||||
| 	return NULL; | ||||
| } | ||||
|  | @ -0,0 +1,188 @@ | |||
| #include <stdlib.h> | ||||
| #include <assert.h> | ||||
| #include <libinput.h> | ||||
| #include <wlr/session.h> | ||||
| #include <wlr/types.h> | ||||
| #include <wlr/common/list.h> | ||||
| #include "backend/libinput.h" | ||||
| #include "common/log.h" | ||||
| #include "types.h" | ||||
| 
 | ||||
| struct wlr_input_device *get_appropriate_device( | ||||
| 		enum wlr_input_device_type desired_type, | ||||
| 		struct libinput_device *device) { | ||||
| 	list_t *devices = libinput_device_get_user_data(device); | ||||
| 	if (!devices) { | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	for (size_t i = 0; i < devices->length; ++i) { | ||||
| 		struct wlr_input_device *dev = devices->items[i]; | ||||
| 		if (dev->type == desired_type) { | ||||
| 			return dev; | ||||
| 		} | ||||
| 	} | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static void wlr_libinput_device_destroy(struct wlr_input_device_state *state) { | ||||
| 	libinput_device_unref(state->handle); | ||||
| 	free(state); | ||||
| } | ||||
| 
 | ||||
| static struct wlr_input_device_impl input_device_impl = { | ||||
| 	.destroy = wlr_libinput_device_destroy | ||||
| }; | ||||
| 
 | ||||
| static struct wlr_input_device *allocate_device( | ||||
| 		struct wlr_backend_state *state, struct libinput_device *device, | ||||
| 		list_t *devices, enum wlr_input_device_type type) { | ||||
| 	int vendor = libinput_device_get_id_vendor(device); | ||||
| 	int product = libinput_device_get_id_product(device); | ||||
| 	const char *name = libinput_device_get_name(device); | ||||
| 	struct wlr_input_device_state *devstate = | ||||
| 		calloc(1, sizeof(struct wlr_input_device_state)); | ||||
| 	devstate->handle = device; | ||||
| 	libinput_device_ref(device); | ||||
| 	struct wlr_input_device *wlr_device = wlr_input_device_create( | ||||
| 		type, &input_device_impl, devstate, | ||||
| 		name, vendor, product); | ||||
| 	list_add(devices, wlr_device); | ||||
| 	list_add(state->devices, wlr_device); | ||||
| 	return wlr_device; | ||||
| } | ||||
| 
 | ||||
| static void handle_device_added(struct wlr_backend_state *state, | ||||
| 		struct libinput_device *device) { | ||||
| 	assert(state && device); | ||||
| 	/*
 | ||||
| 	 * Note: the wlr API exposes only devices with a single capability, because | ||||
| 	 * that meshes better with how Wayland does things and is a bit simpler. | ||||
| 	 * However, libinput devices often have multiple capabilities - in such | ||||
| 	 * cases we have to create several devices. | ||||
| 	 */ | ||||
| 	int vendor = libinput_device_get_id_vendor(device); | ||||
| 	int product = libinput_device_get_id_product(device); | ||||
| 	const char *name = libinput_device_get_name(device); | ||||
| 	list_t *devices = list_create(); | ||||
| 	wlr_log(L_DEBUG, "Added %s [%d:%d]", name, vendor, product); | ||||
| 
 | ||||
| 	if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_KEYBOARD)) { | ||||
| 		struct wlr_input_device *wlr_device = allocate_device(state, | ||||
| 				device, devices, WLR_INPUT_DEVICE_KEYBOARD); | ||||
| 		wlr_device->keyboard = wlr_libinput_keyboard_create(device); | ||||
| 		wl_signal_emit(&state->backend->events.input_add, wlr_device); | ||||
| 	} | ||||
| 	if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER)) { | ||||
| 		struct wlr_input_device *wlr_device = allocate_device(state, | ||||
| 				device, devices, WLR_INPUT_DEVICE_POINTER); | ||||
| 		wlr_device->pointer = wlr_libinput_pointer_create(device); | ||||
| 		wl_signal_emit(&state->backend->events.input_add, wlr_device); | ||||
| 	} | ||||
| 	if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_TOUCH)) { | ||||
| 		struct wlr_input_device *wlr_device = allocate_device(state, | ||||
| 				device, devices, WLR_INPUT_DEVICE_TOUCH); | ||||
| 		wlr_device->touch = wlr_libinput_touch_create(device); | ||||
| 		wl_signal_emit(&state->backend->events.input_add, wlr_device); | ||||
| 	} | ||||
| 	if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_TABLET_TOOL)) { | ||||
| 		struct wlr_input_device *wlr_device = allocate_device(state, | ||||
| 				device, devices, WLR_INPUT_DEVICE_TABLET_TOOL); | ||||
| 		wlr_device->tablet_tool = wlr_libinput_tablet_tool_create(device); | ||||
| 		wl_signal_emit(&state->backend->events.input_add, wlr_device); | ||||
| 	} | ||||
| 	if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_TABLET_PAD)) { | ||||
| 		struct wlr_input_device *wlr_device = allocate_device(state, | ||||
| 				device, devices, WLR_INPUT_DEVICE_TABLET_PAD); | ||||
| 		wlr_device->tablet_pad = wlr_libinput_tablet_pad_create(device); | ||||
| 		wl_signal_emit(&state->backend->events.input_add, wlr_device); | ||||
| 	} | ||||
| 	if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_GESTURE)) { | ||||
| 		// TODO
 | ||||
| 	} | ||||
| 	if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_SWITCH)) { | ||||
| 		// TODO
 | ||||
| 	} | ||||
| 
 | ||||
| 	if (devices->length > 0) { | ||||
| 		libinput_device_set_user_data(device, devices); | ||||
| 	} else { | ||||
| 		list_free(devices); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void handle_device_removed(struct wlr_backend_state *state, | ||||
| 		struct libinput_device *device) { | ||||
| 	wlr_log(L_DEBUG, "libinput device removed"); | ||||
| 	// TODO
 | ||||
| } | ||||
| 
 | ||||
| void wlr_libinput_event(struct wlr_backend_state *state, | ||||
| 		struct libinput_event *event) { | ||||
| 	assert(state && event); | ||||
| 	struct libinput *context = libinput_event_get_context(event); | ||||
| 	struct libinput_device *device = libinput_event_get_device(event); | ||||
| 	enum libinput_event_type event_type = libinput_event_get_type(event); | ||||
| 	(void)context; | ||||
| 	switch (event_type) { | ||||
| 	case LIBINPUT_EVENT_DEVICE_ADDED: | ||||
| 		handle_device_added(state, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_DEVICE_REMOVED: | ||||
| 		handle_device_removed(state, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_KEYBOARD_KEY: | ||||
| 		handle_keyboard_key(event, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_POINTER_MOTION: | ||||
| 		handle_pointer_motion(event, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: | ||||
| 		handle_pointer_motion_abs(event, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_POINTER_BUTTON: | ||||
| 		handle_pointer_button(event, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_POINTER_AXIS: | ||||
| 		handle_pointer_axis(event, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_TOUCH_DOWN: | ||||
| 		handle_touch_down(event, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_TOUCH_UP: | ||||
| 		handle_touch_up(event, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_TOUCH_MOTION: | ||||
| 		handle_touch_motion(event, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_TOUCH_CANCEL: | ||||
| 		handle_touch_cancel(event, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_TOUCH_FRAME: | ||||
| 		// no-op (at least for now)
 | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_TABLET_TOOL_AXIS: | ||||
| 		handle_tablet_tool_axis(event, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: | ||||
| 		handle_tablet_tool_proximity(event, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_TABLET_TOOL_TIP: | ||||
| 		handle_tablet_tool_tip(event, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_TABLET_TOOL_BUTTON: | ||||
| 		handle_tablet_tool_button(event, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_TABLET_PAD_BUTTON: | ||||
| 		handle_tablet_pad_button(event, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_TABLET_PAD_RING: | ||||
| 		handle_tablet_pad_ring(event, device); | ||||
| 		break; | ||||
| 	case LIBINPUT_EVENT_TABLET_PAD_STRIP: | ||||
| 		handle_tablet_pad_strip(event, device); | ||||
| 		break; | ||||
| 	default: | ||||
| 		wlr_log(L_DEBUG, "Unknown libinput event %d", event_type); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,65 @@ | |||
| #include <stdlib.h> | ||||
| #include <assert.h> | ||||
| #include <libinput.h> | ||||
| #include <wlr/session.h> | ||||
| #include <wlr/types.h> | ||||
| #include <wlr/common/list.h> | ||||
| #include "backend/libinput.h" | ||||
| #include "common/log.h" | ||||
| #include "types.h" | ||||
| 
 | ||||
| struct wlr_keyboard_state { | ||||
| 	struct libinput_device *device; | ||||
| }; | ||||
| 
 | ||||
| static void wlr_libinput_keyboard_set_leds(struct wlr_keyboard_state *kbstate, uint32_t leds) { | ||||
| 	libinput_device_led_update(kbstate->device, leds); | ||||
| } | ||||
| 
 | ||||
| static void wlr_libinput_keyboard_destroy(struct wlr_keyboard_state *kbstate) { | ||||
| 	libinput_device_unref(kbstate->device); | ||||
| 	free(kbstate); | ||||
| } | ||||
| 
 | ||||
| struct wlr_keyboard_impl impl = { | ||||
| 	.destroy = wlr_libinput_keyboard_destroy, | ||||
| 	.led_update = wlr_libinput_keyboard_set_leds | ||||
| }; | ||||
| 
 | ||||
| struct wlr_keyboard *wlr_libinput_keyboard_create( | ||||
| 		struct libinput_device *device) { | ||||
| 	assert(device); | ||||
| 	struct wlr_keyboard_state *kbstate = calloc(1, sizeof(struct wlr_keyboard_state)); | ||||
| 	kbstate->device = device; | ||||
| 	libinput_device_ref(device); | ||||
| 	libinput_device_led_update(device, 0); | ||||
| 	return wlr_keyboard_create(&impl, kbstate); | ||||
| } | ||||
| 
 | ||||
| void handle_keyboard_key(struct libinput_event *event, | ||||
| 		struct libinput_device *device) { | ||||
| 	struct wlr_input_device *dev = | ||||
| 		get_appropriate_device(WLR_INPUT_DEVICE_KEYBOARD, device); | ||||
| 	if (!dev) { | ||||
| 		wlr_log(L_DEBUG, "Got a keyboard event for a device with no keyboards?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	struct libinput_event_keyboard *kbevent = | ||||
| 		libinput_event_get_keyboard_event(event); | ||||
| 	struct wlr_keyboard_key *wlr_event = | ||||
| 		calloc(1, sizeof(struct wlr_keyboard_key)); | ||||
| 	wlr_event->time_sec = libinput_event_keyboard_get_time(kbevent); | ||||
| 	wlr_event->time_usec = libinput_event_keyboard_get_time_usec(kbevent); | ||||
| 	wlr_event->keycode = libinput_event_keyboard_get_key(kbevent); | ||||
| 	enum libinput_key_state state =  | ||||
| 		libinput_event_keyboard_get_key_state(kbevent); | ||||
| 	switch (state) { | ||||
| 	case LIBINPUT_KEY_STATE_RELEASED: | ||||
| 		wlr_event->state = WLR_KEY_RELEASED; | ||||
| 		break; | ||||
| 	case LIBINPUT_KEY_STATE_PRESSED: | ||||
| 		wlr_event->state = WLR_KEY_PRESSED; | ||||
| 		break; | ||||
| 	} | ||||
| 	wl_signal_emit(&dev->keyboard->events.key, wlr_event); | ||||
| } | ||||
|  | @ -0,0 +1,129 @@ | |||
| #include <stdlib.h> | ||||
| #include <assert.h> | ||||
| #include <libinput.h> | ||||
| #include <wlr/session.h> | ||||
| #include <wlr/types.h> | ||||
| #include <wlr/common/list.h> | ||||
| #include "backend/libinput.h" | ||||
| #include "common/log.h" | ||||
| #include "types.h" | ||||
| 
 | ||||
| struct wlr_pointer *wlr_libinput_pointer_create( | ||||
| 		struct libinput_device *device) { | ||||
| 	assert(device); | ||||
| 	return wlr_pointer_create(NULL, NULL); | ||||
| } | ||||
| 
 | ||||
| void handle_pointer_motion(struct libinput_event *event, | ||||
| 		struct libinput_device *device) { | ||||
| 	struct wlr_input_device *dev = | ||||
| 		get_appropriate_device(WLR_INPUT_DEVICE_POINTER, device); | ||||
| 	if (!dev) { | ||||
| 		wlr_log(L_DEBUG, "Got a pointer event for a device with no pointers?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	struct libinput_event_pointer *pevent = | ||||
| 		libinput_event_get_pointer_event(event); | ||||
| 	struct wlr_pointer_motion *wlr_event = | ||||
| 		calloc(1, sizeof(struct wlr_pointer_motion)); | ||||
| 	wlr_event->time_sec = libinput_event_pointer_get_time(pevent); | ||||
| 	wlr_event->time_usec = libinput_event_pointer_get_time_usec(pevent); | ||||
| 	wlr_event->delta_x = libinput_event_pointer_get_dx(pevent); | ||||
| 	wlr_event->delta_y = libinput_event_pointer_get_dy(pevent); | ||||
| 	wl_signal_emit(&dev->pointer->events.motion, wlr_event); | ||||
| } | ||||
| 
 | ||||
| void handle_pointer_motion_abs(struct libinput_event *event, | ||||
| 		struct libinput_device *device) { | ||||
| 	struct wlr_input_device *dev = | ||||
| 		get_appropriate_device(WLR_INPUT_DEVICE_POINTER, device); | ||||
| 	if (!dev) { | ||||
| 		wlr_log(L_DEBUG, "Got a pointer event for a device with no pointers?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	struct libinput_event_pointer *pevent = | ||||
| 		libinput_event_get_pointer_event(event); | ||||
| 	struct wlr_pointer_motion_absolute *wlr_event = | ||||
| 		calloc(1, sizeof(struct wlr_pointer_motion_absolute)); | ||||
| 	wlr_event->time_sec = libinput_event_pointer_get_time(pevent); | ||||
| 	wlr_event->time_usec = libinput_event_pointer_get_time_usec(pevent); | ||||
| 	wlr_event->x_mm = libinput_event_pointer_get_absolute_x(pevent); | ||||
| 	wlr_event->y_mm = libinput_event_pointer_get_absolute_y(pevent); | ||||
| 	libinput_device_get_size(device, &wlr_event->width_mm, &wlr_event->height_mm); | ||||
| 	wl_signal_emit(&dev->pointer->events.motion_absolute, wlr_event); | ||||
| } | ||||
| 
 | ||||
| void handle_pointer_button(struct libinput_event *event, | ||||
| 		struct libinput_device *device) { | ||||
| 	struct wlr_input_device *dev = | ||||
| 		get_appropriate_device(WLR_INPUT_DEVICE_POINTER, device); | ||||
| 	if (!dev) { | ||||
| 		wlr_log(L_DEBUG, "Got a pointer event for a device with no pointers?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	struct libinput_event_pointer *pevent = | ||||
| 		libinput_event_get_pointer_event(event); | ||||
| 	struct wlr_pointer_button *wlr_event = | ||||
| 		calloc(1, sizeof(struct wlr_pointer_button)); | ||||
| 	wlr_event->time_sec = libinput_event_pointer_get_time(pevent); | ||||
| 	wlr_event->time_usec = libinput_event_pointer_get_time_usec(pevent); | ||||
| 	wlr_event->button = libinput_event_pointer_get_button(pevent); | ||||
| 	switch (libinput_event_pointer_get_button_state(pevent)) { | ||||
| 	case LIBINPUT_BUTTON_STATE_PRESSED: | ||||
| 		wlr_event->state = WLR_BUTTON_PRESSED; | ||||
| 		break; | ||||
| 	case LIBINPUT_BUTTON_STATE_RELEASED: | ||||
| 		wlr_event->state = WLR_BUTTON_RELEASED; | ||||
| 		break; | ||||
| 	} | ||||
| 	wl_signal_emit(&dev->pointer->events.button, wlr_event); | ||||
| } | ||||
| 
 | ||||
| void handle_pointer_axis(struct libinput_event *event, | ||||
| 		struct libinput_device *device) { | ||||
| 	struct wlr_input_device *dev = | ||||
| 		get_appropriate_device(WLR_INPUT_DEVICE_POINTER, device); | ||||
| 	if (!dev) { | ||||
| 		wlr_log(L_DEBUG, "Got a pointer event for a device with no pointers?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	struct libinput_event_pointer *pevent = | ||||
| 		libinput_event_get_pointer_event(event); | ||||
| 	struct wlr_pointer_axis *wlr_event = | ||||
| 		calloc(1, sizeof(struct wlr_pointer_axis)); | ||||
| 	wlr_event->time_sec = libinput_event_pointer_get_time(pevent); | ||||
| 	wlr_event->time_usec = libinput_event_pointer_get_time_usec(pevent); | ||||
| 	switch (libinput_event_pointer_get_axis_source(pevent)) { | ||||
| 	case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL: | ||||
| 		wlr_event->source = WLR_AXIS_SOURCE_WHEEL; | ||||
| 		break; | ||||
| 	case LIBINPUT_POINTER_AXIS_SOURCE_FINGER: | ||||
| 		wlr_event->source = WLR_AXIS_SOURCE_FINGER; | ||||
| 		break; | ||||
| 	case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS: | ||||
| 		wlr_event->source = WLR_AXIS_SOURCE_CONTINUOUS; | ||||
| 		break; | ||||
| 	case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT: | ||||
| 		wlr_event->source = WLR_AXIS_SOURCE_WHEEL_TILT; | ||||
| 		break; | ||||
| 	} | ||||
| 	enum libinput_pointer_axis axies[] = { | ||||
| 		LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL, | ||||
| 		LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL, | ||||
| 	}; | ||||
| 	for (size_t i = 0; i < sizeof(axies) / sizeof(axies[0]); ++i) { | ||||
| 		if (libinput_event_pointer_has_axis(pevent, axies[i])) { | ||||
| 			switch (axies[i]) { | ||||
| 			case LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL: | ||||
| 				wlr_event->orientation = WLR_AXIS_ORIENTATION_VERTICAL; | ||||
| 				break; | ||||
| 			case LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL: | ||||
| 				wlr_event->orientation = WLR_AXIS_ORIENTATION_HORIZONTAL; | ||||
| 				break; | ||||
| 			} | ||||
| 			wlr_event->delta = libinput_event_pointer_get_axis_value( | ||||
| 					pevent, axies[i]); | ||||
| 		} | ||||
| 		wl_signal_emit(&dev->pointer->events.axis, wlr_event); | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,95 @@ | |||
| #include <stdlib.h> | ||||
| #include <assert.h> | ||||
| #include <libinput.h> | ||||
| #include <wlr/session.h> | ||||
| #include <wlr/types.h> | ||||
| #include <wlr/common/list.h> | ||||
| #include "backend/libinput.h" | ||||
| #include "common/log.h" | ||||
| #include "types.h" | ||||
| 
 | ||||
| struct wlr_tablet_pad *wlr_libinput_tablet_pad_create( | ||||
| 		struct libinput_device *device) { | ||||
| 	assert(device); | ||||
| 	return wlr_tablet_pad_create(NULL, NULL); | ||||
| } | ||||
| 
 | ||||
| void handle_tablet_pad_button(struct libinput_event *event, | ||||
| 		struct libinput_device *device) { | ||||
| 	struct wlr_input_device *dev = | ||||
| 		get_appropriate_device(WLR_INPUT_DEVICE_TABLET_PAD, device); | ||||
| 	if (!dev) { | ||||
| 		wlr_log(L_DEBUG, "Got a tablet pad event for a device with no tablet pad?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	struct libinput_event_tablet_pad *pevent = | ||||
| 		libinput_event_get_tablet_pad_event(event); | ||||
| 	struct wlr_tablet_pad_button *wlr_event = | ||||
| 		calloc(1, sizeof(struct wlr_tablet_pad_button)); | ||||
| 	wlr_event->time_sec = libinput_event_tablet_pad_get_time(pevent); | ||||
| 	wlr_event->time_usec = libinput_event_tablet_pad_get_time_usec(pevent); | ||||
| 	wlr_event->button = libinput_event_tablet_pad_get_button_number(pevent); | ||||
| 	switch (libinput_event_tablet_pad_get_button_state(pevent)) { | ||||
| 	case LIBINPUT_BUTTON_STATE_PRESSED: | ||||
| 		wlr_event->state = WLR_BUTTON_PRESSED; | ||||
| 		break; | ||||
| 	case LIBINPUT_BUTTON_STATE_RELEASED: | ||||
| 		wlr_event->state = WLR_BUTTON_RELEASED; | ||||
| 		break; | ||||
| 	} | ||||
| 	wl_signal_emit(&dev->tablet_pad->events.button, wlr_event); | ||||
| } | ||||
| 
 | ||||
| void handle_tablet_pad_ring(struct libinput_event *event, | ||||
| 		struct libinput_device *device) { | ||||
| 	struct wlr_input_device *dev = | ||||
| 		get_appropriate_device(WLR_INPUT_DEVICE_TABLET_PAD, device); | ||||
| 	if (!dev) { | ||||
| 		wlr_log(L_DEBUG, "Got a tablet pad event for a device with no tablet pad?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	struct libinput_event_tablet_pad *pevent = | ||||
| 		libinput_event_get_tablet_pad_event(event); | ||||
| 	struct wlr_tablet_pad_ring *wlr_event = | ||||
| 		calloc(1, sizeof(struct wlr_tablet_pad_ring)); | ||||
| 	wlr_event->time_sec = libinput_event_tablet_pad_get_time(pevent); | ||||
| 	wlr_event->time_usec = libinput_event_tablet_pad_get_time_usec(pevent); | ||||
| 	wlr_event->ring = libinput_event_tablet_pad_get_ring_number(pevent); | ||||
| 	wlr_event->position = libinput_event_tablet_pad_get_ring_position(pevent); | ||||
| 	switch (libinput_event_tablet_pad_get_ring_source(pevent)) { | ||||
| 	case LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN: | ||||
| 		wlr_event->source = WLR_TABLET_PAD_RING_SOURCE_UNKNOWN; | ||||
| 		break; | ||||
| 	case LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER: | ||||
| 		wlr_event->source = WLR_TABLET_PAD_RING_SOURCE_FINGER; | ||||
| 		break; | ||||
| 	} | ||||
| 	wl_signal_emit(&dev->tablet_pad->events.ring, wlr_event); | ||||
| } | ||||
| 
 | ||||
| void handle_tablet_pad_strip(struct libinput_event *event, | ||||
| 		struct libinput_device *device) { | ||||
| 	struct wlr_input_device *dev = | ||||
| 		get_appropriate_device(WLR_INPUT_DEVICE_TABLET_PAD, device); | ||||
| 	if (!dev) { | ||||
| 		wlr_log(L_DEBUG, "Got a tablet pad event for a device with no tablet pad?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	struct libinput_event_tablet_pad *pevent = | ||||
| 		libinput_event_get_tablet_pad_event(event); | ||||
| 	struct wlr_tablet_pad_strip *wlr_event = | ||||
| 		calloc(1, sizeof(struct wlr_tablet_pad_strip)); | ||||
| 	wlr_event->time_sec = libinput_event_tablet_pad_get_time(pevent); | ||||
| 	wlr_event->time_usec = libinput_event_tablet_pad_get_time_usec(pevent); | ||||
| 	wlr_event->strip = libinput_event_tablet_pad_get_strip_number(pevent); | ||||
| 	wlr_event->position = libinput_event_tablet_pad_get_strip_position(pevent); | ||||
| 	switch (libinput_event_tablet_pad_get_strip_source(pevent)) { | ||||
| 	case LIBINPUT_TABLET_PAD_STRIP_SOURCE_UNKNOWN: | ||||
| 		wlr_event->source = WLR_TABLET_PAD_STRIP_SOURCE_UNKNOWN; | ||||
| 		break; | ||||
| 	case LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER: | ||||
| 		wlr_event->source = WLR_TABLET_PAD_STRIP_SOURCE_FINGER; | ||||
| 		break; | ||||
| 	} | ||||
| 	wl_signal_emit(&dev->tablet_pad->events.strip, wlr_event); | ||||
| } | ||||
|  | @ -0,0 +1,150 @@ | |||
| #include <stdlib.h> | ||||
| #include <assert.h> | ||||
| #include <libinput.h> | ||||
| #include <wlr/session.h> | ||||
| #include <wlr/types.h> | ||||
| #include <wlr/common/list.h> | ||||
| #include "backend/libinput.h" | ||||
| #include "common/log.h" | ||||
| #include "types.h" | ||||
| 
 | ||||
| struct wlr_tablet_tool *wlr_libinput_tablet_tool_create( | ||||
| 		struct libinput_device *device) { | ||||
| 	assert(device); | ||||
| 	return wlr_tablet_tool_create(NULL, NULL); | ||||
| } | ||||
| 
 | ||||
| void handle_tablet_tool_axis(struct libinput_event *event, | ||||
| 		struct libinput_device *device) { | ||||
| 	struct wlr_input_device *dev = | ||||
| 		get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, device); | ||||
| 	if (!dev) { | ||||
| 		wlr_log(L_DEBUG, "Got a tablet tool event for a device with no tablet tools?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	struct libinput_event_tablet_tool *tevent = | ||||
| 		libinput_event_get_tablet_tool_event(event); | ||||
| 	struct wlr_tablet_tool_axis *wlr_event = | ||||
| 		calloc(1, sizeof(struct wlr_tablet_tool_axis)); | ||||
| 	wlr_event->time_sec = libinput_event_tablet_tool_get_time(tevent); | ||||
| 	wlr_event->time_usec = libinput_event_tablet_tool_get_time_usec(tevent); | ||||
| 	libinput_device_get_size(device, &wlr_event->width_mm, &wlr_event->height_mm); | ||||
| 	if (libinput_event_tablet_tool_x_has_changed(tevent)) { | ||||
| 		wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_X; | ||||
| 		wlr_event->x_mm = libinput_event_tablet_tool_get_x(tevent); | ||||
| 	} | ||||
| 	if (libinput_event_tablet_tool_y_has_changed(tevent)) { | ||||
| 		wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_Y; | ||||
| 		wlr_event->y_mm = libinput_event_tablet_tool_get_y(tevent); | ||||
| 	} | ||||
| 	if (libinput_event_tablet_tool_pressure_has_changed(tevent)) { | ||||
| 		wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_PRESSURE; | ||||
| 		wlr_event->pressure = libinput_event_tablet_tool_get_pressure(tevent); | ||||
| 	} | ||||
| 	if (libinput_event_tablet_tool_distance_has_changed(tevent)) { | ||||
| 		wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_DISTANCE; | ||||
| 		wlr_event->distance = libinput_event_tablet_tool_get_distance(tevent); | ||||
| 	} | ||||
| 	if (libinput_event_tablet_tool_tilt_x_has_changed(tevent)) { | ||||
| 		wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_TILT_X; | ||||
| 		wlr_event->tilt_x = libinput_event_tablet_tool_get_tilt_x(tevent); | ||||
| 	} | ||||
| 	if (libinput_event_tablet_tool_tilt_y_has_changed(tevent)) { | ||||
| 		wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_TILT_Y; | ||||
| 		wlr_event->tilt_y = libinput_event_tablet_tool_get_tilt_y(tevent); | ||||
| 	} | ||||
| 	if (libinput_event_tablet_tool_rotation_has_changed(tevent)) { | ||||
| 		wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_ROTATION; | ||||
| 		wlr_event->rotation = libinput_event_tablet_tool_get_rotation(tevent); | ||||
| 	} | ||||
| 	if (libinput_event_tablet_tool_slider_has_changed(tevent)) { | ||||
| 		wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_SLIDER; | ||||
| 		wlr_event->slider = libinput_event_tablet_tool_get_slider_position(tevent); | ||||
| 	} | ||||
| 	if (libinput_event_tablet_tool_wheel_has_changed(tevent)) { | ||||
| 		wlr_event->updated_axes |= WLR_TABLET_TOOL_AXIS_WHEEL; | ||||
| 		wlr_event->wheel_delta = libinput_event_tablet_tool_get_wheel_delta(tevent); | ||||
| 	} | ||||
| 	wl_signal_emit(&dev->tablet_tool->events.axis, wlr_event); | ||||
| } | ||||
| 
 | ||||
| void handle_tablet_tool_proximity(struct libinput_event *event, | ||||
| 		struct libinput_device *device) { | ||||
| 	struct wlr_input_device *dev = | ||||
| 		get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, device); | ||||
| 	if (!dev) { | ||||
| 		wlr_log(L_DEBUG, "Got a tablet tool event for a device with no tablet tools?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	struct libinput_event_tablet_tool *tevent = | ||||
| 		libinput_event_get_tablet_tool_event(event); | ||||
| 	struct wlr_tablet_tool_proximity *wlr_event = | ||||
| 		calloc(1, sizeof(struct wlr_tablet_tool_proximity)); | ||||
| 	wlr_event->time_sec = libinput_event_tablet_tool_get_time(tevent); | ||||
| 	wlr_event->time_usec = libinput_event_tablet_tool_get_time_usec(tevent); | ||||
| 	switch (libinput_event_tablet_tool_get_proximity_state(tevent)) { | ||||
| 	case LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT: | ||||
| 		wlr_event->state = WLR_TABLET_TOOL_PROXIMITY_OUT; | ||||
| 		break; | ||||
| 	case LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN: | ||||
| 		wlr_event->state = WLR_TABLET_TOOL_PROXIMITY_IN; | ||||
| 		handle_tablet_tool_axis(event, device); | ||||
| 		break; | ||||
| 	} | ||||
| 	wl_signal_emit(&dev->tablet_tool->events.proximity, wlr_event); | ||||
| } | ||||
| 
 | ||||
| void handle_tablet_tool_tip(struct libinput_event *event, | ||||
| 		struct libinput_device *device) { | ||||
| 	struct wlr_input_device *dev = | ||||
| 		get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, device); | ||||
| 	if (!dev) { | ||||
| 		wlr_log(L_DEBUG, "Got a tablet tool event for a device with no tablet tools?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	handle_tablet_tool_axis(event, device); | ||||
| 	struct libinput_event_tablet_tool *tevent = | ||||
| 		libinput_event_get_tablet_tool_event(event); | ||||
| 	struct wlr_tablet_tool_tip *wlr_event = | ||||
| 		calloc(1, sizeof(struct wlr_tablet_tool_tip)); | ||||
| 	wlr_event->time_sec = libinput_event_tablet_tool_get_time(tevent); | ||||
| 	wlr_event->time_usec = libinput_event_tablet_tool_get_time_usec(tevent); | ||||
| 	switch (libinput_event_tablet_tool_get_tip_state(tevent)) { | ||||
| 	case LIBINPUT_TABLET_TOOL_TIP_UP: | ||||
| 		wlr_event->state = WLR_TABLET_TOOL_TIP_UP; | ||||
| 		break; | ||||
| 	case LIBINPUT_TABLET_TOOL_TIP_DOWN: | ||||
| 		wlr_event->state = WLR_TABLET_TOOL_TIP_DOWN; | ||||
| 		break; | ||||
| 	} | ||||
| 	wl_signal_emit(&dev->tablet_tool->events.tip, wlr_event); | ||||
| } | ||||
| 
 | ||||
| void handle_tablet_tool_button(struct libinput_event *event, | ||||
| 		struct libinput_device *device) { | ||||
| 	struct wlr_input_device *dev = | ||||
| 		get_appropriate_device(WLR_INPUT_DEVICE_TABLET_TOOL, device); | ||||
| 	if (!dev) { | ||||
| 		wlr_log(L_DEBUG, "Got a tablet tool event for a device with no tablet tools?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	// Tip events contain axis information. We update this information
 | ||||
| 	// before we send the proximity event
 | ||||
| 	handle_tablet_tool_axis(event, device); | ||||
| 	struct libinput_event_tablet_tool *tevent = | ||||
| 		libinput_event_get_tablet_tool_event(event); | ||||
| 	struct wlr_tablet_tool_button *wlr_event = | ||||
| 		calloc(1, sizeof(struct wlr_tablet_tool_button)); | ||||
| 	wlr_event->time_sec = libinput_event_tablet_tool_get_time(tevent); | ||||
| 	wlr_event->time_usec = libinput_event_tablet_tool_get_time_usec(tevent); | ||||
| 	wlr_event->button = libinput_event_tablet_tool_get_button(tevent); | ||||
| 	switch (libinput_event_tablet_tool_get_button_state(tevent)) { | ||||
| 	case LIBINPUT_BUTTON_STATE_RELEASED: | ||||
| 		wlr_event->state = WLR_BUTTON_RELEASED; | ||||
| 		break; | ||||
| 	case LIBINPUT_BUTTON_STATE_PRESSED: | ||||
| 		wlr_event->state = WLR_BUTTON_PRESSED; | ||||
| 		break; | ||||
| 	} | ||||
| 	wl_signal_emit(&dev->tablet_tool->events.button, wlr_event); | ||||
| } | ||||
|  | @ -0,0 +1,93 @@ | |||
| #include <stdlib.h> | ||||
| #include <assert.h> | ||||
| #include <libinput.h> | ||||
| #include <wlr/session.h> | ||||
| #include <wlr/types.h> | ||||
| #include <wlr/common/list.h> | ||||
| #include "backend/libinput.h" | ||||
| #include "common/log.h" | ||||
| #include "types.h" | ||||
| 
 | ||||
| struct wlr_touch *wlr_libinput_touch_create( | ||||
| 		struct libinput_device *device) { | ||||
| 	assert(device); | ||||
| 	return wlr_touch_create(NULL, NULL); | ||||
| } | ||||
| 
 | ||||
| void handle_touch_down(struct libinput_event *event, | ||||
| 		struct libinput_device *device) { | ||||
| 	struct wlr_input_device *dev = | ||||
| 		get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, device); | ||||
| 	if (!dev) { | ||||
| 		wlr_log(L_DEBUG, "Got a touch event for a device with no touch?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	struct libinput_event_touch *tevent = | ||||
| 		libinput_event_get_touch_event(event); | ||||
| 	struct wlr_touch_down *wlr_event = | ||||
| 		calloc(1, sizeof(struct wlr_touch_down)); | ||||
| 	wlr_event->time_sec = libinput_event_touch_get_time(tevent); | ||||
| 	wlr_event->time_usec = libinput_event_touch_get_time_usec(tevent); | ||||
| 	wlr_event->slot = libinput_event_touch_get_slot(tevent); | ||||
| 	wlr_event->x_mm = libinput_event_touch_get_x(tevent); | ||||
| 	wlr_event->y_mm = libinput_event_touch_get_y(tevent); | ||||
| 	libinput_device_get_size(device, &wlr_event->width_mm, &wlr_event->height_mm); | ||||
| 	wl_signal_emit(&dev->touch->events.down, wlr_event); | ||||
| } | ||||
| 
 | ||||
| void handle_touch_up(struct libinput_event *event, | ||||
| 		struct libinput_device *device) { | ||||
| 	struct wlr_input_device *dev = | ||||
| 		get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, device); | ||||
| 	if (!dev) { | ||||
| 		wlr_log(L_DEBUG, "Got a touch event for a device with no touch?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	struct libinput_event_touch *tevent = | ||||
| 		libinput_event_get_touch_event(event); | ||||
| 	struct wlr_touch_up *wlr_event = | ||||
| 		calloc(1, sizeof(struct wlr_touch_up)); | ||||
| 	wlr_event->time_sec = libinput_event_touch_get_time(tevent); | ||||
| 	wlr_event->time_usec = libinput_event_touch_get_time_usec(tevent); | ||||
| 	wlr_event->slot = libinput_event_touch_get_slot(tevent); | ||||
| 	wl_signal_emit(&dev->touch->events.up, wlr_event); | ||||
| } | ||||
| 
 | ||||
| void handle_touch_motion(struct libinput_event *event, | ||||
| 		struct libinput_device *device) { | ||||
| 	struct wlr_input_device *dev = | ||||
| 		get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, device); | ||||
| 	if (!dev) { | ||||
| 		wlr_log(L_DEBUG, "Got a touch event for a device with no touch?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	struct libinput_event_touch *tevent = | ||||
| 		libinput_event_get_touch_event(event); | ||||
| 	struct wlr_touch_motion *wlr_event = | ||||
| 		calloc(1, sizeof(struct wlr_touch_motion)); | ||||
| 	wlr_event->time_sec = libinput_event_touch_get_time(tevent); | ||||
| 	wlr_event->time_usec = libinput_event_touch_get_time_usec(tevent); | ||||
| 	wlr_event->slot = libinput_event_touch_get_slot(tevent); | ||||
| 	wlr_event->x_mm = libinput_event_touch_get_x(tevent); | ||||
| 	wlr_event->y_mm = libinput_event_touch_get_y(tevent); | ||||
| 	libinput_device_get_size(device, &wlr_event->width_mm, &wlr_event->height_mm); | ||||
| 	wl_signal_emit(&dev->touch->events.motion, wlr_event); | ||||
| } | ||||
| 
 | ||||
| void handle_touch_cancel(struct libinput_event *event, | ||||
| 		struct libinput_device *device) { | ||||
| 	struct wlr_input_device *dev = | ||||
| 		get_appropriate_device(WLR_INPUT_DEVICE_TOUCH, device); | ||||
| 	if (!dev) { | ||||
| 		wlr_log(L_DEBUG, "Got a touch event for a device with no touch?"); | ||||
| 		return; | ||||
| 	} | ||||
| 	struct libinput_event_touch *tevent = | ||||
| 		libinput_event_get_touch_event(event); | ||||
| 	struct wlr_touch_cancel *wlr_event = | ||||
| 		calloc(1, sizeof(struct wlr_touch_cancel)); | ||||
| 	wlr_event->time_sec = libinput_event_touch_get_time(tevent); | ||||
| 	wlr_event->time_usec = libinput_event_touch_get_time_usec(tevent); | ||||
| 	wlr_event->slot = libinput_event_touch_get_slot(tevent); | ||||
| 	wl_signal_emit(&dev->touch->events.cancel, wlr_event); | ||||
| } | ||||
|  | @ -0,0 +1,107 @@ | |||
| #include <stdbool.h> | ||||
| #include <stdlib.h> | ||||
| #include <wlr/backend/interface.h> | ||||
| #include <wlr/common/log.h> | ||||
| #include "backend/multi.h" | ||||
| #include "common/log.h" | ||||
| 
 | ||||
| struct subbackend_state { | ||||
| 	struct wlr_backend *backend; | ||||
| 	struct wlr_backend *container; | ||||
| 	struct wl_listener input_add; | ||||
| 	struct wl_listener input_remove; | ||||
| 	struct wl_listener output_add; | ||||
| 	struct wl_listener output_remove; | ||||
| }; | ||||
| 
 | ||||
| static bool multi_backend_init(struct wlr_backend_state *state) { | ||||
| 	for (size_t i = 0; i < state->backends->length; ++i) { | ||||
| 		struct subbackend_state *sub = state->backends->items[i]; | ||||
| 		if (!wlr_backend_init(sub->backend)) { | ||||
| 			wlr_log(L_ERROR, "Failed to initialize backend %zd", i); | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static void multi_backend_destroy(struct wlr_backend_state *state) { | ||||
| 	for (size_t i = 0; i < state->backends->length; ++i) { | ||||
| 		struct subbackend_state *sub = state->backends->items[i]; | ||||
| 		wlr_backend_destroy(sub->backend); | ||||
| 		free(sub); | ||||
| 	} | ||||
| 	list_free(state->backends); | ||||
| 	free(state); | ||||
| } | ||||
| 
 | ||||
| struct wlr_backend_impl backend_impl = { | ||||
| 	.init = multi_backend_init, | ||||
| 	.destroy = multi_backend_destroy | ||||
| }; | ||||
| 
 | ||||
| struct wlr_backend *wlr_multi_backend_create() { | ||||
| 	struct wlr_backend_state *state = | ||||
| 		calloc(1, sizeof(struct wlr_backend_state)); | ||||
| 	if (!state) { | ||||
| 		wlr_log(L_ERROR, "Backend allocation failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	state->backends = list_create(); | ||||
| 	if (!state->backends) { | ||||
| 		free(state); | ||||
| 		wlr_log(L_ERROR, "Backend allocation failed"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	struct wlr_backend *backend = wlr_backend_create(&backend_impl, state); | ||||
| 	state->backend = backend; | ||||
| 	return backend; | ||||
| } | ||||
| 
 | ||||
| static void input_add_reemit(struct wl_listener *listener, void *data) { | ||||
| 	struct subbackend_state *state = wl_container_of(listener, | ||||
| 			state, input_add); | ||||
| 	wl_signal_emit(&state->container->events.input_add, data); | ||||
| } | ||||
| 
 | ||||
| static void input_remove_reemit(struct wl_listener *listener, void *data) { | ||||
| 	struct subbackend_state *state = wl_container_of(listener, | ||||
| 			state, input_remove); | ||||
| 	wl_signal_emit(&state->container->events.input_remove, data); | ||||
| } | ||||
| 
 | ||||
| static void output_add_reemit(struct wl_listener *listener, void *data) { | ||||
| 	struct subbackend_state *state = wl_container_of(listener, | ||||
| 			state, output_add); | ||||
| 	wl_signal_emit(&state->container->events.output_add, data); | ||||
| } | ||||
| 
 | ||||
| static void output_remove_reemit(struct wl_listener *listener, void *data) { | ||||
| 	struct subbackend_state *state = wl_container_of(listener, | ||||
| 			state, output_remove); | ||||
| 	wl_signal_emit(&state->container->events.output_remove, data); | ||||
| } | ||||
| 
 | ||||
| void wlr_multi_backend_add(struct wlr_backend *multi, | ||||
| 		struct wlr_backend *backend) { | ||||
| 	struct subbackend_state *sub = calloc(1, sizeof(struct subbackend_state)); | ||||
| 	sub->backend = backend; | ||||
| 	sub->container = multi; | ||||
| 
 | ||||
| 	sub->input_add.notify = input_add_reemit; | ||||
| 	sub->input_remove.notify = input_remove_reemit; | ||||
| 	sub->output_add.notify = output_add_reemit; | ||||
| 	sub->output_remove.notify = output_remove_reemit; | ||||
| 
 | ||||
| 	wl_list_init(&sub->input_add.link); | ||||
| 	wl_list_init(&sub->input_remove.link); | ||||
| 	wl_list_init(&sub->output_add.link); | ||||
| 	wl_list_init(&sub->output_remove.link); | ||||
| 
 | ||||
| 	wl_signal_add(&backend->events.input_add, &sub->input_add); | ||||
| 	wl_signal_add(&backend->events.input_remove, &sub->input_remove); | ||||
| 	wl_signal_add(&backend->events.output_add, &sub->output_add); | ||||
| 	wl_signal_add(&backend->events.output_remove, &sub->output_remove); | ||||
| 
 | ||||
| 	list_add(multi->state->backends, sub); | ||||
| } | ||||
|  | @ -1,19 +1,23 @@ | |||
| include_directories( | ||||
| 	${DRM_INCLUDE_DIRS} | ||||
|     ${CMAKE_CURRENT_SOURCE_DIR} | ||||
|     ${XKBCOMMON_INCLUDE_DIRS} | ||||
| ) | ||||
| 
 | ||||
| add_executable(simple | ||||
|     simple.c | ||||
|     shared.c | ||||
| ) | ||||
| 
 | ||||
| target_link_libraries(simple | ||||
|     wlr-backend | ||||
|     wlr-session | ||||
|     ${XKBCOMMON_LIBRARIES} | ||||
| ) | ||||
| 
 | ||||
| add_executable(rotation | ||||
|     rotation.c | ||||
|     shared.c | ||||
|     cat.c | ||||
| ) | ||||
| 
 | ||||
|  | @ -21,4 +25,43 @@ target_link_libraries(rotation | |||
|     wlr-backend | ||||
|     wlr-session | ||||
|     wlr-render | ||||
|     ${XKBCOMMON_LIBRARIES} | ||||
| ) | ||||
| 
 | ||||
| add_executable(pointer | ||||
|     pointer.c | ||||
|     shared.c | ||||
|     cat.c | ||||
| ) | ||||
| 
 | ||||
| target_link_libraries(pointer | ||||
|     wlr-backend | ||||
|     wlr-session | ||||
|     wlr-render | ||||
|     ${XKBCOMMON_LIBRARIES} | ||||
| ) | ||||
| 
 | ||||
| add_executable(touch | ||||
|     touch.c | ||||
|     shared.c | ||||
|     cat.c | ||||
| ) | ||||
| 
 | ||||
| target_link_libraries(touch | ||||
|     wlr-backend | ||||
|     wlr-session | ||||
|     wlr-render | ||||
|     ${XKBCOMMON_LIBRARIES} | ||||
| ) | ||||
| 
 | ||||
| add_executable(tablet | ||||
|     tablet.c | ||||
|     shared.c | ||||
| ) | ||||
| 
 | ||||
| target_link_libraries(tablet | ||||
|     wlr-backend | ||||
|     wlr-session | ||||
|     wlr-render | ||||
|     ${XKBCOMMON_LIBRARIES} | ||||
| ) | ||||
|  |  | |||
							
								
								
									
										4381
									
								
								example/cat.c
								
								
								
								
							
							
						
						
									
										4381
									
								
								example/cat.c
								
								
								
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,133 @@ | |||
| #define _POSIX_C_SOURCE 199309L | ||||
| #define _XOPEN_SOURCE 500 | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <time.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wayland-server-protocol.h> | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include <GLES3/gl3.h> | ||||
| #include <wlr/render/matrix.h> | ||||
| #include <wlr/render/gles3.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wlr/backend.h> | ||||
| #include <wlr/session.h> | ||||
| #include <wlr/types.h> | ||||
| #include <math.h> | ||||
| #include "shared.h" | ||||
| #include "cat.h" | ||||
| 
 | ||||
| struct sample_state { | ||||
| 	struct wlr_renderer *renderer; | ||||
| 	struct wlr_surface *cat_texture; | ||||
| 	int cur_x, cur_y; | ||||
| 	float default_color[4]; | ||||
| 	float clear_color[4]; | ||||
| }; | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
| 	wlr_renderer_begin(sample->renderer, wlr_output); | ||||
| 	glClearColor(sample->clear_color[0], sample->clear_color[1], | ||||
| 			sample->clear_color[2], sample->clear_color[3]); | ||||
| 	glClear(GL_COLOR_BUFFER_BIT); | ||||
| 
 | ||||
| 	float matrix[16]; | ||||
| 	wlr_surface_get_matrix(sample->cat_texture, &matrix, | ||||
| 		&wlr_output->transform_matrix, sample->cur_x, sample->cur_y); | ||||
| 	wlr_render_with_matrix(sample->renderer, | ||||
| 			sample->cat_texture, &matrix); | ||||
| 
 | ||||
| 	wlr_renderer_end(sample->renderer); | ||||
| } | ||||
| 
 | ||||
| static void handle_keyboard_key(struct keyboard_state *kbstate, | ||||
| 		xkb_keysym_t sym, enum wlr_key_state key_state) { | ||||
| 	if (sym == XKB_KEY_Escape) { | ||||
| 		kbstate->compositor->exit = true; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void handle_pointer_motion(struct pointer_state *pstate, | ||||
| 		double d_x, double d_y) { | ||||
| 	struct sample_state *state = pstate->compositor->data; | ||||
| 	state->cur_x += d_x; | ||||
| 	state->cur_y += d_y; | ||||
| } | ||||
| 
 | ||||
| static void handle_pointer_button(struct pointer_state *pstate, | ||||
| 		uint32_t button, enum wlr_button_state state) { | ||||
| 	struct sample_state *sample = pstate->compositor->data; | ||||
| 	float (*color)[4]; | ||||
| 	if (state == WLR_BUTTON_RELEASED) { | ||||
| 		color = &sample->default_color; | ||||
| 	} else { | ||||
| 		float red[4] = { 0.25f, 0.25f, 0.25f, 1 }; | ||||
| 		red[button % 3] = 1; | ||||
| 		color = &red; | ||||
| 	} | ||||
| 	memcpy(&sample->clear_color, color, sizeof(*color)); | ||||
| } | ||||
| 
 | ||||
| static void handle_pointer_axis(struct pointer_state *pstate, | ||||
| 	enum wlr_axis_source source, | ||||
| 	enum wlr_axis_orientation orientation, | ||||
| 	double delta) { | ||||
| 	struct sample_state *sample = pstate->compositor->data; | ||||
| 	for (size_t i = 0; i < 3; ++i) { | ||||
| 		sample->default_color[i] += delta > 0 ? -0.05f : 0.05f; | ||||
| 		if (sample->default_color[i] > 1.0f) { | ||||
| 			sample->default_color[i] = 1.0f; | ||||
| 		} | ||||
| 		if (sample->default_color[i] < 0.0f) { | ||||
| 			sample->default_color[i] = 0.0f; | ||||
| 		} | ||||
| 	} | ||||
| 	memcpy(&sample->clear_color, &sample->default_color, | ||||
| 			sizeof(sample->clear_color)); | ||||
| } | ||||
| 
 | ||||
| static void handle_output_add(struct output_state *ostate) { | ||||
| 	struct wlr_output *wlr_output = ostate->output; | ||||
| 	int width = 16, height = 16; | ||||
| 	if (!wlr_output_set_cursor(wlr_output, cat_tex.pixel_data, | ||||
| 			width * 4, width, height)) { | ||||
| 		fprintf(stderr, "Failed to set cursor\n"); | ||||
| 		return; | ||||
| 	} | ||||
| 	if (!wlr_output_move_cursor(wlr_output, 0, 0)) { | ||||
| 		fprintf(stderr, "Failed to move cursor\n"); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
| 	struct sample_state state = { | ||||
| 		.default_color = { 0.25f, 0.25f, 0.25f, 1 }, | ||||
| 		.clear_color = { 0.25f, 0.25f, 0.25f, 1 } | ||||
| 	}; | ||||
| 	struct compositor_state compositor; | ||||
| 
 | ||||
| 	compositor_init(&compositor); | ||||
| 	compositor.output_add_cb = handle_output_add; | ||||
| 	compositor.output_frame_cb = handle_output_frame; | ||||
| 	compositor.keyboard_key_cb = handle_keyboard_key; | ||||
| 	compositor.pointer_motion_cb = handle_pointer_motion; | ||||
| 	compositor.pointer_button_cb = handle_pointer_button; | ||||
| 	compositor.pointer_axis_cb = handle_pointer_axis; | ||||
| 
 | ||||
| 	state.renderer = wlr_gles3_renderer_init(); | ||||
| 	state.cat_texture = wlr_render_surface_init(state.renderer); | ||||
| 	wlr_surface_attach_pixels(state.cat_texture, GL_RGBA, | ||||
| 		cat_tex.width, cat_tex.height, cat_tex.pixel_data); | ||||
| 
 | ||||
| 	compositor.data = &state; | ||||
| 	compositor_run(&compositor); | ||||
| 
 | ||||
| 	wlr_surface_destroy(state.cat_texture); | ||||
| 	wlr_renderer_destroy(state.renderer); | ||||
| } | ||||
|  | @ -7,6 +7,7 @@ | |||
| #include <unistd.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wayland-server-protocol.h> | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include <GLES3/gl3.h> | ||||
| #include <wlr/render/matrix.h> | ||||
| #include <wlr/render/gles3.h> | ||||
|  | @ -15,24 +16,18 @@ | |||
| #include <wlr/session.h> | ||||
| #include <wlr/types.h> | ||||
| #include <math.h> | ||||
| #include "shared.h" | ||||
| #include "cat.h" | ||||
| 
 | ||||
| struct state { | ||||
| 	struct wl_listener output_add; | ||||
| 	struct wl_listener output_remove; | ||||
| 	struct wl_list outputs; | ||||
| struct sample_state { | ||||
| 	struct wl_list config; | ||||
| 	struct wlr_renderer *renderer; | ||||
| 	struct wlr_surface *cat_texture; | ||||
| }; | ||||
| 
 | ||||
| struct output_state { | ||||
| 	struct timespec last_frame; | ||||
| 	struct wl_list link; | ||||
| 	struct wlr_output *output; | ||||
| 	struct state *state; | ||||
| 	struct wl_listener frame; | ||||
| struct output_data { | ||||
| 	float x_offs, y_offs; | ||||
| 	float x_vel, y_vel; | ||||
| }; | ||||
| 
 | ||||
| struct output_config { | ||||
|  | @ -41,86 +36,93 @@ struct output_config { | |||
| 	struct wl_list link; | ||||
| }; | ||||
| 
 | ||||
| static void output_frame(struct wl_listener *listener, void *data) { | ||||
| 	struct output_state *ostate = wl_container_of(listener, ostate, frame); | ||||
| 	struct wlr_output *output = ostate->output; | ||||
| 	struct state *s = ostate->state; | ||||
| 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 output_data *odata = output->data; | ||||
| 	struct wlr_output *wlr_output = output->output; | ||||
| 
 | ||||
| 	int32_t width, height; | ||||
| 	wlr_output_effective_resolution(output, &width, &height); | ||||
| 	wlr_output_effective_resolution(wlr_output, &width, &height); | ||||
| 
 | ||||
| 	wlr_renderer_begin(s->renderer, output); | ||||
| 	wlr_renderer_begin(sample->renderer, wlr_output); | ||||
| 
 | ||||
| 	float matrix[16]; | ||||
| 	for (int y = -128 + (int)ostate->y_offs; y < height; y += 128) { | ||||
| 		for (int x = -128 + (int)ostate->x_offs; x < width; x += 128) { | ||||
| 			wlr_surface_get_matrix(s->cat_texture, &matrix, | ||||
| 				&output->transform_matrix, x, y); | ||||
| 			wlr_render_with_matrix(s->renderer, s->cat_texture, &matrix); | ||||
| 	for (int y = -128 + (int)odata->y_offs; y < height; y += 128) { | ||||
| 		for (int x = -128 + (int)odata->x_offs; x < width; x += 128) { | ||||
| 			wlr_surface_get_matrix(sample->cat_texture, &matrix, | ||||
| 				&wlr_output->transform_matrix, x, y); | ||||
| 			wlr_render_with_matrix(sample->renderer, | ||||
| 					sample->cat_texture, &matrix); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	wlr_renderer_end(s->renderer); | ||||
| 	wlr_renderer_end(sample->renderer); | ||||
| 
 | ||||
| 	struct timespec now; | ||||
| 	clock_gettime(CLOCK_MONOTONIC, &now); | ||||
| 	long ms = (now.tv_sec - ostate->last_frame.tv_sec) * 1000 + | ||||
| 		(now.tv_nsec - ostate->last_frame.tv_nsec) / 1000000; | ||||
| 	long ms = (ts->tv_sec - output->last_frame.tv_sec) * 1000 + | ||||
| 		(ts->tv_nsec - output->last_frame.tv_nsec) / 1000000; | ||||
| 	float seconds = ms / 1000.0f; | ||||
| 
 | ||||
| 	ostate->x_offs += 128 * seconds; | ||||
| 	ostate->y_offs += 128 * seconds; | ||||
| 	if (ostate->x_offs > 128) ostate->x_offs = 0; | ||||
| 	if (ostate->y_offs > 128) ostate->y_offs = 0; | ||||
| 	ostate->last_frame = now; | ||||
| 	odata->x_offs += odata->x_vel * seconds; | ||||
| 	odata->y_offs += odata->y_vel * seconds; | ||||
| 	if (odata->x_offs > 128) odata->x_offs = 0; | ||||
| 	if (odata->y_offs > 128) odata->y_offs = 0; | ||||
| } | ||||
| 
 | ||||
| static void output_add(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_output *output = data; | ||||
| 	struct state *state = wl_container_of(listener, state, output_add); | ||||
| 
 | ||||
| 	fprintf(stderr, "Output '%s' added\n", output->name); | ||||
| 	wlr_output_set_mode(output, output->modes->items[0]); | ||||
| 
 | ||||
| 	struct output_state *ostate = calloc(1, sizeof(struct output_state)); | ||||
| 
 | ||||
| 	clock_gettime(CLOCK_MONOTONIC, &ostate->last_frame); | ||||
| 	ostate->output = output; | ||||
| 	ostate->state = state; | ||||
| 	ostate->frame.notify = output_frame; | ||||
| 	ostate->x_offs = ostate->y_offs = 0; | ||||
| static void handle_output_add(struct output_state *output) { | ||||
| 	struct output_data *odata = calloc(1, sizeof(struct output_data)); | ||||
| 	odata->x_offs = odata->y_offs = 0; | ||||
| 	odata->x_vel = odata->y_vel = 128; | ||||
| 	output->data = odata; | ||||
| 	struct sample_state *state = output->compositor->data; | ||||
| 
 | ||||
| 	struct output_config *conf; | ||||
| 	wl_list_for_each(conf, &state->config, link) { | ||||
| 		if (strcmp(conf->name, output->name) == 0) { | ||||
| 			wlr_output_transform(ostate->output, conf->transform); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	wl_list_init(&ostate->frame.link); | ||||
| 	wl_signal_add(&output->events.frame, &ostate->frame); | ||||
| 	wl_list_insert(&state->outputs, &ostate->link); | ||||
| } | ||||
| 
 | ||||
| static void output_remove(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_output *output = data; | ||||
| 	struct state *state = wl_container_of(listener, state, output_remove); | ||||
| 	struct output_state *ostate; | ||||
| 
 | ||||
| 	wl_list_for_each(ostate, &state->outputs, link) { | ||||
| 		if (ostate->output == output) { | ||||
| 			wl_list_remove(&ostate->link); | ||||
| 			wl_list_remove(&ostate->frame.link); | ||||
| 			free(ostate); | ||||
| 		if (strcmp(conf->name, output->output->name) == 0) { | ||||
| 			wlr_output_transform(output->output, conf->transform); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static int timer_done(void *data) { | ||||
| 	*(bool *)data = true; | ||||
| 	return 1; | ||||
| static void handle_output_remove(struct output_state *output) { | ||||
| 	free(output->data); | ||||
| } | ||||
| 
 | ||||
| static void update_velocities(struct compositor_state *state, | ||||
| 		float x_diff, float y_diff) { | ||||
| 	struct output_state *output; | ||||
| 	wl_list_for_each(output, &state->outputs, link) { | ||||
| 		struct output_data *odata = output->data; | ||||
| 		odata->x_vel += x_diff; | ||||
| 		odata->y_vel += y_diff; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void handle_keyboard_key(struct keyboard_state *kbstate, | ||||
| 		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
 | ||||
| 	if (key_state == WLR_KEY_PRESSED) { | ||||
| 		switch (sym) { | ||||
| 		case XKB_KEY_Escape: | ||||
| 			kbstate->compositor->exit = true; | ||||
| 			break; | ||||
| 		case XKB_KEY_Left: | ||||
| 			update_velocities(kbstate->compositor, -16, 0); | ||||
| 			break; | ||||
| 		case XKB_KEY_Right: | ||||
| 			update_velocities(kbstate->compositor, 16, 0); | ||||
| 			break; | ||||
| 		case XKB_KEY_Up: | ||||
| 			update_velocities(kbstate->compositor, 0, -16); | ||||
| 			break; | ||||
| 		case XKB_KEY_Down: | ||||
| 			update_velocities(kbstate->compositor, 0, 16); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void usage(const char *name, int ret) { | ||||
|  | @ -190,59 +192,27 @@ static void parse_args(int argc, char *argv[], struct wl_list *config) { | |||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
| 	struct state state = { | ||||
| 		.output_add = { .notify = output_add }, | ||||
| 		.output_remove = { .notify = output_remove } | ||||
| 	}; | ||||
| 
 | ||||
| 	wl_list_init(&state.outputs); | ||||
| 	struct sample_state state = { 0 }; | ||||
| 	struct compositor_state compositor; | ||||
| 	wl_list_init(&state.config); | ||||
| 	wl_list_init(&state.output_add.link); | ||||
| 	wl_list_init(&state.output_remove.link); | ||||
| 
 | ||||
| 	parse_args(argc, argv, &state.config); | ||||
| 
 | ||||
| 	struct wl_display *display = wl_display_create(); | ||||
| 	struct wl_event_loop *event_loop = wl_display_get_event_loop(display); | ||||
| 
 | ||||
| 	struct wlr_session *session = wlr_session_start(display); | ||||
| 	if (!session) { | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	struct wlr_backend *wlr = wlr_backend_autocreate(display, session); | ||||
| 	if (!wlr) { | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	wl_signal_add(&wlr->events.output_add, &state.output_add); | ||||
| 	wl_signal_add(&wlr->events.output_remove, &state.output_remove); | ||||
| 
 | ||||
| 	if (!wlr_backend_init(wlr)) { | ||||
| 		return 1; | ||||
| 	} | ||||
| 	compositor_init(&compositor); | ||||
| 	compositor.output_add_cb = handle_output_add; | ||||
| 	compositor.output_remove_cb = handle_output_remove; | ||||
| 	compositor.output_frame_cb = handle_output_frame; | ||||
| 	compositor.keyboard_key_cb = handle_keyboard_key; | ||||
| 
 | ||||
| 	state.renderer = wlr_gles3_renderer_init(); | ||||
| 	state.cat_texture = wlr_render_surface_init(state.renderer); | ||||
| 	wlr_surface_attach_pixels(state.cat_texture, GL_RGB, | ||||
| 	wlr_surface_attach_pixels(state.cat_texture, GL_RGBA, | ||||
| 		cat_tex.width, cat_tex.height, cat_tex.pixel_data); | ||||
| 
 | ||||
| 	bool done = false; | ||||
| 	struct wl_event_source *timer = wl_event_loop_add_timer(event_loop, | ||||
| 		timer_done, &done); | ||||
| 	compositor.data = &state; | ||||
| 	compositor_run(&compositor); | ||||
| 
 | ||||
| 	wl_event_source_timer_update(timer, 30000); | ||||
| 
 | ||||
| 	while (!done) { | ||||
| 		wl_event_loop_dispatch(event_loop, 0); | ||||
| 	} | ||||
| 
 | ||||
| 	wl_event_source_remove(timer); | ||||
| 	wlr_backend_destroy(wlr); | ||||
| 	wlr_session_finish(session); | ||||
| 	wlr_surface_destroy(state.cat_texture); | ||||
| 	wlr_renderer_destroy(state.renderer); | ||||
| 	wl_display_destroy(display); | ||||
| 
 | ||||
| 	struct output_config *ptr, *tmp; | ||||
| 	wl_list_for_each_safe(ptr, tmp, &state.config, link) { | ||||
|  |  | |||
|  | @ -0,0 +1,475 @@ | |||
| #define _POSIX_C_SOURCE 199309L | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| #include <time.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <stdbool.h> | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include <wayland-server-protocol.h> | ||||
| #include <wlr/backend.h> | ||||
| #include <wlr/session.h> | ||||
| #include <wlr/types.h> | ||||
| #include "shared.h" | ||||
| 
 | ||||
| static void keyboard_led_update(struct keyboard_state *kbstate) { | ||||
| 	uint32_t leds = 0; | ||||
| 	for (uint32_t i = 0; i < WLR_LED_LAST; ++i) { | ||||
| 		if (xkb_state_led_index_is_active(kbstate->xkb_state, kbstate->leds[i])) { | ||||
| 			leds |= (1 << i); | ||||
| 		} | ||||
| 	} | ||||
| 	wlr_keyboard_led_update(kbstate->device->keyboard, leds); | ||||
| } | ||||
| 
 | ||||
| static void keyboard_key_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_keyboard_key *event = data; | ||||
| 	struct keyboard_state *kbstate = wl_container_of(listener, kbstate, key); | ||||
| 	uint32_t keycode = event->keycode + 8; | ||||
| 	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); | ||||
| 	for (int i = 0; i < nsyms; ++i) { | ||||
| 		xkb_keysym_t sym = syms[i]; | ||||
| 		char name[64]; | ||||
| 		int l = xkb_keysym_get_name(sym, name, sizeof(name)); | ||||
| 		if (l != -1 && l != sizeof(name)) { | ||||
| 			fprintf(stderr, "Key event: %s %s\n", name, | ||||
| 					key_state == WLR_KEY_PRESSED ? "pressed" : "released"); | ||||
| 		} | ||||
| 		if (kbstate->compositor->keyboard_key_cb) { | ||||
| 			kbstate->compositor->keyboard_key_cb(kbstate, sym, key_state); | ||||
| 		} | ||||
| 	} | ||||
| 	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) { | ||||
| 	struct keyboard_state *kbstate = calloc(sizeof(struct keyboard_state), 1); | ||||
| 	kbstate->device = device; | ||||
| 	kbstate->compositor = state; | ||||
| 	wl_list_init(&kbstate->key.link); | ||||
| 	kbstate->key.notify = keyboard_key_notify; | ||||
| 	wl_signal_add(&device->keyboard->events.key, &kbstate->key); | ||||
| 	wl_list_insert(&state->keyboards, &kbstate->link); | ||||
| 
 | ||||
| 	struct xkb_rule_names rules; | ||||
| 	memset(&rules, 0, sizeof(rules)); | ||||
| 	rules.rules = getenv("XKB_DEFAULT_RULES"); | ||||
| 	rules.model = getenv("XKB_DEFAULT_MODEL"); | ||||
| 	rules.layout = getenv("XKB_DEFAULT_LAYOUT"); | ||||
| 	rules.variant = getenv("XKB_DEFAULT_VARIANT"); | ||||
| 	rules.options = getenv("XKB_DEFAULT_OPTIONS"); | ||||
| 	struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); | ||||
| 	if (!context) { | ||||
| 		fprintf(stderr, "Failed to create XKB context\n"); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	kbstate->keymap = xkb_map_new_from_names( | ||||
| 			context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); | ||||
| 	if (!kbstate->keymap) { | ||||
| 		fprintf(stderr, "Failed to create XKB keymap\n"); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	xkb_context_unref(context); | ||||
| 	kbstate->xkb_state = xkb_state_new(kbstate->keymap); | ||||
| 	if (!kbstate->xkb_state) { | ||||
| 		fprintf(stderr, "Failed to create XKB state\n"); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	const char *led_names[3] = { | ||||
| 		XKB_LED_NAME_NUM, | ||||
| 		XKB_LED_NAME_CAPS, | ||||
| 		XKB_LED_NAME_SCROLL | ||||
| 	}; | ||||
| 	for (uint32_t i = 0; i < 3; ++i) { | ||||
| 		kbstate->leds[i] = xkb_map_led_get_index(kbstate->keymap, led_names[i]); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void pointer_motion_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_pointer_motion *event = data; | ||||
| 	struct pointer_state *pstate = wl_container_of(listener, pstate, motion); | ||||
| 	if (pstate->compositor->pointer_motion_cb) { | ||||
| 		pstate->compositor->pointer_motion_cb(pstate, | ||||
| 				event->delta_x, event->delta_y); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void pointer_button_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_pointer_button *event = data; | ||||
| 	struct pointer_state *pstate = wl_container_of(listener, pstate, button); | ||||
| 	if (pstate->compositor->pointer_button_cb) { | ||||
| 		pstate->compositor->pointer_button_cb(pstate, | ||||
| 				event->button, event->state); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void pointer_axis_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_pointer_axis *event = data; | ||||
| 	struct pointer_state *pstate = wl_container_of(listener, pstate, axis); | ||||
| 	if (pstate->compositor->pointer_axis_cb) { | ||||
| 		pstate->compositor->pointer_axis_cb(pstate, | ||||
| 				event->source, event->orientation, event->delta); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void pointer_add(struct wlr_input_device *device, struct compositor_state *state) { | ||||
| 	struct pointer_state *pstate = calloc(sizeof(struct pointer_state), 1); | ||||
| 	pstate->device = device; | ||||
| 	pstate->compositor = state; | ||||
| 	wl_list_init(&pstate->motion.link); | ||||
| 	wl_list_init(&pstate->motion_absolute.link); | ||||
| 	wl_list_init(&pstate->button.link); | ||||
| 	wl_list_init(&pstate->axis.link); | ||||
| 	pstate->motion.notify = pointer_motion_notify; | ||||
| 	pstate->button.notify = pointer_button_notify; | ||||
| 	pstate->axis.notify = pointer_axis_notify; | ||||
| 	wl_signal_add(&device->pointer->events.motion, &pstate->motion); | ||||
| 	wl_signal_add(&device->pointer->events.button, &pstate->button); | ||||
| 	wl_signal_add(&device->pointer->events.axis, &pstate->axis); | ||||
| 	wl_list_insert(&state->pointers, &pstate->link); | ||||
| } | ||||
| 
 | ||||
| static void touch_down_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_touch_down *event = data; | ||||
| 	struct touch_state *tstate = wl_container_of(listener, tstate, down); | ||||
| 	if (tstate->compositor->touch_down_cb) { | ||||
| 		tstate->compositor->touch_down_cb(tstate, event->slot, | ||||
| 			event->x_mm, event->y_mm, event->width_mm, event->height_mm); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void touch_motion_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_touch_motion *event = data; | ||||
| 	struct touch_state *tstate = wl_container_of(listener, tstate, motion); | ||||
| 	if (tstate->compositor->touch_motion_cb) { | ||||
| 		tstate->compositor->touch_motion_cb(tstate, event->slot, | ||||
| 			event->x_mm, event->y_mm, event->width_mm, event->height_mm); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void touch_up_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_touch_up *event = data; | ||||
| 	struct touch_state *tstate = wl_container_of(listener, tstate, up); | ||||
| 	if (tstate->compositor->touch_up_cb) { | ||||
| 		tstate->compositor->touch_up_cb(tstate, event->slot); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void touch_cancel_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_touch_cancel *event = data; | ||||
| 	struct touch_state *tstate = wl_container_of(listener, tstate, cancel); | ||||
| 	if (tstate->compositor->touch_cancel_cb) { | ||||
| 		tstate->compositor->touch_cancel_cb(tstate, event->slot); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void touch_add(struct wlr_input_device *device, struct compositor_state *state) { | ||||
| 	struct touch_state *tstate = calloc(sizeof(struct touch_state), 1); | ||||
| 	tstate->device = device; | ||||
| 	tstate->compositor = state; | ||||
| 	wl_list_init(&tstate->down.link); | ||||
| 	wl_list_init(&tstate->motion.link); | ||||
| 	wl_list_init(&tstate->up.link); | ||||
| 	wl_list_init(&tstate->cancel.link); | ||||
| 	tstate->down.notify = touch_down_notify; | ||||
| 	tstate->motion.notify = touch_motion_notify; | ||||
| 	tstate->up.notify = touch_up_notify; | ||||
| 	tstate->cancel.notify = touch_cancel_notify; | ||||
| 	wl_signal_add(&device->touch->events.down, &tstate->down); | ||||
| 	wl_signal_add(&device->touch->events.motion, &tstate->motion); | ||||
| 	wl_signal_add(&device->touch->events.up, &tstate->up); | ||||
| 	wl_signal_add(&device->touch->events.cancel, &tstate->cancel); | ||||
| 	wl_list_insert(&state->touch, &tstate->link); | ||||
| } | ||||
| 
 | ||||
| static void tablet_tool_axis_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_tablet_tool_axis *event = data; | ||||
| 	struct tablet_tool_state *tstate = wl_container_of(listener, tstate, axis); | ||||
| 	if (tstate->compositor->tool_axis_cb) { | ||||
| 		tstate->compositor->tool_axis_cb(tstate, event); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void tablet_tool_proximity_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_tablet_tool_proximity *event = data; | ||||
| 	struct tablet_tool_state *tstate = wl_container_of(listener, tstate, proximity); | ||||
| 	if (tstate->compositor->tool_proximity_cb) { | ||||
| 		tstate->compositor->tool_proximity_cb(tstate, event->state); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void tablet_tool_button_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_tablet_tool_button *event = data; | ||||
| 	struct tablet_tool_state *tstate = wl_container_of(listener, tstate, button); | ||||
| 	if (tstate->compositor->tool_button_cb) { | ||||
| 		tstate->compositor->tool_button_cb(tstate, event->button, event->state); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void tablet_tool_add(struct wlr_input_device *device, | ||||
| 		struct compositor_state *state) { | ||||
| 	struct tablet_tool_state *tstate = calloc(sizeof(struct tablet_tool_state), 1); | ||||
| 	tstate->device = device; | ||||
| 	tstate->compositor = state; | ||||
| 	wl_list_init(&tstate->axis.link); | ||||
| 	wl_list_init(&tstate->proximity.link); | ||||
| 	wl_list_init(&tstate->tip.link); | ||||
| 	wl_list_init(&tstate->button.link); | ||||
| 	tstate->axis.notify = tablet_tool_axis_notify; | ||||
| 	tstate->proximity.notify = tablet_tool_proximity_notify; | ||||
| 	//tstate->tip.notify = tablet_tool_tip_notify;
 | ||||
| 	tstate->button.notify = tablet_tool_button_notify; | ||||
| 	wl_signal_add(&device->tablet_tool->events.axis, &tstate->axis); | ||||
| 	wl_signal_add(&device->tablet_tool->events.proximity, &tstate->proximity); | ||||
| 	//wl_signal_add(&device->tablet_tool->events.tip, &tstate->tip);
 | ||||
| 	wl_signal_add(&device->tablet_tool->events.button, &tstate->button); | ||||
| 	wl_list_insert(&state->tablet_tools, &tstate->link); | ||||
| } | ||||
| 
 | ||||
| static void tablet_pad_button_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_tablet_pad_button *event = data; | ||||
| 	struct tablet_pad_state *pstate = wl_container_of(listener, pstate, button); | ||||
| 	if (pstate->compositor->pad_button_cb) { | ||||
| 		pstate->compositor->pad_button_cb(pstate, event->button, event->state); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void tablet_pad_add(struct wlr_input_device *device, | ||||
| 		struct compositor_state *state) { | ||||
| 	struct tablet_pad_state *pstate = calloc(sizeof(struct tablet_pad_state), 1); | ||||
| 	pstate->device = device; | ||||
| 	pstate->compositor = state; | ||||
| 	wl_list_init(&pstate->button.link); | ||||
| 	pstate->button.notify = tablet_pad_button_notify; | ||||
| 	wl_signal_add(&device->tablet_pad->events.button, &pstate->button); | ||||
| 	wl_list_insert(&state->tablet_pads, &pstate->link); | ||||
| } | ||||
| 
 | ||||
| static void input_add_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_input_device *device = data; | ||||
| 	struct compositor_state *state = wl_container_of(listener, state, input_add); | ||||
| 	switch (device->type) { | ||||
| 	case WLR_INPUT_DEVICE_KEYBOARD: | ||||
| 		keyboard_add(device, state); | ||||
| 		break; | ||||
| 	case WLR_INPUT_DEVICE_POINTER: | ||||
| 		pointer_add(device, state); | ||||
| 		break; | ||||
| 	case WLR_INPUT_DEVICE_TOUCH: | ||||
| 		touch_add(device, state); | ||||
| 		break; | ||||
| 	case WLR_INPUT_DEVICE_TABLET_TOOL: | ||||
| 		tablet_tool_add(device, state); | ||||
| 		break; | ||||
| 	case WLR_INPUT_DEVICE_TABLET_PAD: | ||||
| 		tablet_pad_add(device, state); | ||||
| 		break; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void keyboard_remove(struct wlr_input_device *device, struct compositor_state *state) { | ||||
| 	struct keyboard_state *kbstate = NULL, *_kbstate; | ||||
| 	wl_list_for_each(_kbstate, &state->keyboards, link) { | ||||
| 		if (_kbstate->device == device) { | ||||
| 			kbstate = _kbstate; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if (!kbstate) { | ||||
| 		return; | ||||
| 	} | ||||
| 	wl_list_remove(&kbstate->link); | ||||
| 	wl_list_remove(&kbstate->key.link); | ||||
| } | ||||
| 
 | ||||
| static void pointer_remove(struct wlr_input_device *device, struct compositor_state *state) { | ||||
| 	struct pointer_state *pstate = NULL, *_pstate; | ||||
| 	wl_list_for_each(_pstate, &state->pointers, link) { | ||||
| 		if (_pstate->device == device) { | ||||
| 			pstate = _pstate; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if (!pstate) { | ||||
| 		return; | ||||
| 	} | ||||
| 	wl_list_remove(&pstate->link); | ||||
| 	wl_list_remove(&pstate->motion.link); | ||||
| 	//wl_list_remove(&pstate->motion_absolute.link);
 | ||||
| 	wl_list_remove(&pstate->button.link); | ||||
| 	wl_list_remove(&pstate->axis.link); | ||||
| } | ||||
| 
 | ||||
| static void touch_remove(struct wlr_input_device *device, struct compositor_state *state) { | ||||
| 	struct touch_state *tstate = NULL, *_tstate; | ||||
| 	wl_list_for_each(_tstate, &state->touch, link) { | ||||
| 		if (_tstate->device == device) { | ||||
| 			tstate = _tstate; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if (!tstate) { | ||||
| 		return; | ||||
| 	} | ||||
| 	wl_list_remove(&tstate->link); | ||||
| 	wl_list_remove(&tstate->down.link); | ||||
| 	wl_list_remove(&tstate->motion.link); | ||||
| 	wl_list_remove(&tstate->up.link); | ||||
| 	wl_list_remove(&tstate->cancel.link); | ||||
| } | ||||
| 
 | ||||
| static void tablet_tool_remove(struct wlr_input_device *device, struct compositor_state *state) { | ||||
| 	struct tablet_tool_state *tstate = NULL, *_tstate; | ||||
| 	wl_list_for_each(_tstate, &state->tablet_tools, link) { | ||||
| 		if (_tstate->device == device) { | ||||
| 			tstate = _tstate; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if (!tstate) { | ||||
| 		return; | ||||
| 	} | ||||
| 	wl_list_remove(&tstate->link); | ||||
| 	wl_list_remove(&tstate->axis.link); | ||||
| 	wl_list_remove(&tstate->proximity.link); | ||||
| 	//wl_list_remove(&tstate->tip.link);
 | ||||
| 	wl_list_remove(&tstate->button.link); | ||||
| } | ||||
| 
 | ||||
| static void input_remove_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_input_device *device = data; | ||||
| 	struct compositor_state *state = wl_container_of(listener, state, input_add); | ||||
| 	switch (device->type) { | ||||
| 	case WLR_INPUT_DEVICE_KEYBOARD: | ||||
| 		keyboard_remove(device, state); | ||||
| 		break; | ||||
| 	case WLR_INPUT_DEVICE_POINTER: | ||||
| 		pointer_remove(device, state); | ||||
| 		break; | ||||
| 	case WLR_INPUT_DEVICE_TOUCH: | ||||
| 		touch_remove(device, state); | ||||
| 		break; | ||||
| 	case WLR_INPUT_DEVICE_TABLET_TOOL: | ||||
| 		tablet_tool_remove(device, state); | ||||
| 		break; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void output_frame_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct output_state *output = wl_container_of(listener, output, frame); | ||||
| 	struct compositor_state *compositor = output->compositor; | ||||
| 
 | ||||
| 	struct timespec now; | ||||
| 	clock_gettime(CLOCK_MONOTONIC, &now); | ||||
| 	if (compositor->output_frame_cb) { | ||||
| 		compositor->output_frame_cb(output, &now); | ||||
| 	} | ||||
| 
 | ||||
| 	output->last_frame = now; | ||||
| 	compositor->last_frame = now; | ||||
| } | ||||
| 
 | ||||
| static void output_add_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_output *output = data; | ||||
| 	struct compositor_state *state = wl_container_of(listener, state, output_add); | ||||
| 	fprintf(stderr, "Output '%s' added\n", output->name); | ||||
| 	fprintf(stderr, "%s %s %"PRId32"mm x %"PRId32"mm\n", output->make, output->model, | ||||
| 		output->phys_width, output->phys_height); | ||||
| 	wlr_output_set_mode(output, output->modes->items[0]); | ||||
| 	struct output_state *ostate = calloc(1, sizeof(struct output_state)); | ||||
| 	clock_gettime(CLOCK_MONOTONIC, &ostate->last_frame); | ||||
| 	ostate->output = output; | ||||
| 	ostate->compositor = state; | ||||
| 	ostate->frame.notify = output_frame_notify; | ||||
| 	wl_list_init(&ostate->frame.link); | ||||
| 	wl_signal_add(&output->events.frame, &ostate->frame); | ||||
| 	wl_list_insert(&state->outputs, &ostate->link); | ||||
| 	if (state->output_add_cb) { | ||||
| 		state->output_add_cb(ostate); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void output_remove_notify(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_output *output = data; | ||||
| 	struct compositor_state *state = wl_container_of(listener, state, output_remove); | ||||
| 	struct output_state *ostate = NULL, *_ostate; | ||||
| 	wl_list_for_each(_ostate, &state->outputs, link) { | ||||
| 		if (_ostate->output == output) { | ||||
| 			ostate = _ostate; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if (!ostate) { | ||||
| 		return; // We are unfamiliar with this output
 | ||||
| 	} | ||||
| 	if (state->output_remove_cb) { | ||||
| 		state->output_remove_cb(ostate); | ||||
| 	} | ||||
| 	wl_list_remove(&ostate->link); | ||||
| 	wl_list_remove(&ostate->frame.link); | ||||
| } | ||||
| 
 | ||||
| void compositor_init(struct compositor_state *state) { | ||||
| 	memset(state, 0, sizeof(struct compositor_state)); | ||||
| 
 | ||||
| 	state->display = wl_display_create(); | ||||
| 	state->event_loop = wl_display_get_event_loop(state->display); | ||||
| 	state->session = wlr_session_start(state->display); | ||||
| 	if (!state->session | ||||
| 			|| !state->display | ||||
| 			|| !state->event_loop) { | ||||
| 		exit(1); | ||||
| 	} | ||||
| 
 | ||||
| 	wl_list_init(&state->keyboards); | ||||
| 	wl_list_init(&state->pointers); | ||||
| 	wl_list_init(&state->touch); | ||||
| 	wl_list_init(&state->tablet_tools); | ||||
| 	wl_list_init(&state->tablet_pads); | ||||
| 	wl_list_init(&state->input_add.link); | ||||
| 	state->input_add.notify = input_add_notify; | ||||
| 	wl_list_init(&state->input_remove.link); | ||||
| 	state->input_remove.notify = input_remove_notify; | ||||
| 
 | ||||
| 	wl_list_init(&state->outputs); | ||||
| 	wl_list_init(&state->output_add.link); | ||||
| 	state->output_add.notify = output_add_notify; | ||||
| 	wl_list_init(&state->output_remove.link); | ||||
| 	state->output_remove.notify = output_remove_notify; | ||||
| 
 | ||||
| 	struct wlr_backend *wlr = wlr_backend_autocreate( | ||||
| 			state->display, state->session); | ||||
| 	if (!wlr) { | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	wl_signal_add(&wlr->events.input_add, &state->input_add); | ||||
| 	wl_signal_add(&wlr->events.input_remove, &state->input_remove); | ||||
| 	wl_signal_add(&wlr->events.output_add, &state->output_add); | ||||
| 	wl_signal_add(&wlr->events.output_remove, &state->output_remove); | ||||
| 	state->backend = wlr; | ||||
| 
 | ||||
| 	clock_gettime(CLOCK_MONOTONIC, &state->last_frame); | ||||
| } | ||||
| 
 | ||||
| void compositor_run(struct compositor_state *state) { | ||||
| 	if (!wlr_backend_init(state->backend)) { | ||||
| 		fprintf(stderr, "Failed to initialize backend\n"); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 
 | ||||
| 	while (!state->exit) { | ||||
| 		wl_event_loop_dispatch(state->event_loop, 0); | ||||
| 	} | ||||
| 
 | ||||
| 	wlr_backend_destroy(state->backend); | ||||
| 	wlr_session_finish(state->session); | ||||
| 	wl_display_destroy(state->display); | ||||
| } | ||||
|  | @ -0,0 +1,131 @@ | |||
| #ifndef _EXAMPLE_SHARED_H | ||||
| #define _EXAMPLE_SHARED_H | ||||
| #define _POSIX_C_SOURCE 199309L | ||||
| #include <time.h> | ||||
| #include <stdbool.h> | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include <wayland-server-protocol.h> | ||||
| #include <wlr/backend.h> | ||||
| #include <wlr/session.h> | ||||
| #include <wlr/types.h> | ||||
| 
 | ||||
| struct output_state { | ||||
| 	struct compositor_state *compositor; | ||||
| 	struct wlr_output *output; | ||||
| 	struct wl_listener frame; | ||||
| 	struct timespec last_frame; | ||||
| 	struct wl_list link; | ||||
| 	void *data; | ||||
| }; | ||||
| 
 | ||||
| struct keyboard_state { | ||||
| 	struct compositor_state *compositor; | ||||
| 	struct wlr_input_device *device; | ||||
| 	struct wl_listener key; | ||||
| 	struct wl_list link; | ||||
| 	struct xkb_keymap *keymap; | ||||
| 	struct xkb_state *xkb_state; | ||||
| 	xkb_led_index_t leds[WLR_LED_LAST]; | ||||
| 	void *data; | ||||
| }; | ||||
| 
 | ||||
| struct pointer_state { | ||||
| 	struct compositor_state *compositor; | ||||
| 	struct wlr_input_device *device; | ||||
| 	struct wl_listener motion; | ||||
| 	struct wl_listener motion_absolute; | ||||
| 	struct wl_listener button; | ||||
| 	struct wl_listener axis; | ||||
| 	struct wl_list link; | ||||
| 	void *data; | ||||
| }; | ||||
| 
 | ||||
| struct touch_state { | ||||
| 	struct compositor_state *compositor; | ||||
| 	struct wlr_input_device *device; | ||||
| 	struct wl_listener down; | ||||
| 	struct wl_listener up; | ||||
| 	struct wl_listener motion; | ||||
| 	struct wl_listener cancel; | ||||
| 	struct wl_list link; | ||||
| 	void *data; | ||||
| }; | ||||
| 
 | ||||
| struct tablet_tool_state { | ||||
| 	struct compositor_state *compositor; | ||||
| 	struct wlr_input_device *device; | ||||
| 	struct wl_listener axis; | ||||
| 	struct wl_listener proximity; | ||||
| 	struct wl_listener tip; | ||||
| 	struct wl_listener button; | ||||
| 	struct wl_list link; | ||||
| 	void *data; | ||||
| }; | ||||
| 
 | ||||
| struct tablet_pad_state { | ||||
| 	struct compositor_state *compositor; | ||||
| 	struct wlr_input_device *device; | ||||
| 	struct wl_listener button; | ||||
| 	struct wl_list link; | ||||
| 	void *data; | ||||
| }; | ||||
| 
 | ||||
| struct compositor_state { | ||||
| 	void (*output_add_cb)(struct output_state *s); | ||||
| 	void (*keyboard_add_cb)(struct keyboard_state *s); | ||||
| 	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 (*pointer_motion_cb)(struct pointer_state *s, | ||||
| 			double d_x, double d_y); | ||||
| 	void (*pointer_button_cb)(struct pointer_state *s, | ||||
| 			uint32_t button, enum wlr_button_state state); | ||||
| 	void (*pointer_axis_cb)(struct pointer_state *s, | ||||
| 		enum wlr_axis_source source, | ||||
| 		enum wlr_axis_orientation orientation, | ||||
| 		double delta); | ||||
| 	void (*touch_down_cb)(struct touch_state *s, int32_t slot, | ||||
| 		double x, double y, double width, double height); | ||||
| 	void (*touch_motion_cb)(struct touch_state *s, int32_t slot, | ||||
| 		double x, double y, double width, double height); | ||||
| 	void (*touch_up_cb)(struct touch_state *s, int32_t slot); | ||||
| 	void (*touch_cancel_cb)(struct touch_state *s, int32_t slot); | ||||
| 	void (*tool_axis_cb)(struct tablet_tool_state *s, | ||||
| 			struct wlr_tablet_tool_axis *event); | ||||
| 	void (*tool_proximity_cb)(struct tablet_tool_state *s, | ||||
| 			enum wlr_tablet_tool_proximity_state proximity); | ||||
| 	void (*tool_tip_cb)(struct tablet_tool_state *s, | ||||
| 			enum wlr_tablet_tool_tip_state state); | ||||
| 	void (*tool_button_cb)(struct tablet_tool_state *s, | ||||
| 			uint32_t button, enum wlr_button_state state); | ||||
| 	void (*pad_button_cb)(struct tablet_pad_state *s, | ||||
| 			uint32_t button, enum wlr_button_state state); | ||||
| 
 | ||||
| 	struct wl_display *display; | ||||
| 	struct wl_event_loop *event_loop; | ||||
| 	struct wlr_backend *backend; | ||||
| 	struct wlr_session *session; | ||||
| 
 | ||||
| 	struct wl_list keyboards; | ||||
| 	struct wl_list pointers; | ||||
| 	struct wl_list touch; | ||||
| 	struct wl_list tablet_tools; | ||||
| 	struct wl_list tablet_pads; | ||||
| 	struct wl_listener input_add; | ||||
| 	struct wl_listener input_remove; | ||||
| 
 | ||||
| 	struct timespec last_frame; | ||||
| 	struct wl_listener output_add; | ||||
| 	struct wl_listener output_remove; | ||||
| 	struct wl_list outputs; | ||||
| 
 | ||||
| 	bool exit; | ||||
| 	void *data; | ||||
| }; | ||||
| 
 | ||||
| void compositor_init(struct compositor_state *state); | ||||
| void compositor_run(struct compositor_state *state); | ||||
| 
 | ||||
| #endif | ||||
							
								
								
									
										155
									
								
								example/simple.c
								
								
								
								
							
							
						
						
									
										155
									
								
								example/simple.c
								
								
								
								
							|  | @ -1,4 +1,5 @@ | |||
| #define _POSIX_C_SOURCE 199309L | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <time.h> | ||||
|  | @ -8,152 +9,52 @@ | |||
| #include <wlr/backend.h> | ||||
| #include <wlr/session.h> | ||||
| #include <wlr/types.h> | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include "shared.h" | ||||
| 
 | ||||
| struct state { | ||||
| struct sample_state { | ||||
| 	float color[3]; | ||||
| 	int dec; | ||||
| 	struct timespec last_frame; | ||||
| 	struct wl_listener output_add; | ||||
| 	struct wl_listener output_remove; | ||||
| 	struct wl_list outputs; | ||||
| }; | ||||
| 
 | ||||
| struct output_state { | ||||
| 	struct wl_list link; | ||||
| 	struct wlr_output *output; | ||||
| 	struct state *state; | ||||
| 	struct wl_listener frame; | ||||
| }; | ||||
| void handle_output_frame(struct output_state *output, struct timespec *ts) { | ||||
| 	struct compositor_state *state = output->compositor; | ||||
| 	struct sample_state *sample = state->data; | ||||
| 
 | ||||
| void output_frame(struct wl_listener *listener, void *data) { | ||||
| 	struct output_state *ostate = wl_container_of(listener, ostate, frame); | ||||
| 	struct state *s = ostate->state; | ||||
| 	long ms = (ts->tv_sec - state->last_frame.tv_sec) * 1000 + | ||||
| 		(ts->tv_nsec - state->last_frame.tv_nsec) / 1000000; | ||||
| 	int inc = (sample->dec + 1) % 3; | ||||
| 
 | ||||
| 	struct timespec now; | ||||
| 	clock_gettime(CLOCK_MONOTONIC, &now); | ||||
| 	sample->color[inc] += ms / 2000.0f; | ||||
| 	sample->color[sample->dec] -= ms / 2000.0f; | ||||
| 
 | ||||
| 	long ms = (now.tv_sec - s->last_frame.tv_sec) * 1000 + | ||||
| 		(now.tv_nsec - s->last_frame.tv_nsec) / 1000000; | ||||
| 	int inc = (s->dec + 1) % 3; | ||||
| 
 | ||||
| 	s->color[inc] += ms / 2000.0f; | ||||
| 	s->color[s->dec] -= ms / 2000.0f; | ||||
| 
 | ||||
| 	if (s->color[s->dec] < 0.0f) { | ||||
| 		s->color[inc] = 1.0f; | ||||
| 		s->color[s->dec] = 0.0f; | ||||
| 		s->dec = inc; | ||||
| 	if (sample->color[sample->dec] < 0.0f) { | ||||
| 		sample->color[inc] = 1.0f; | ||||
| 		sample->color[sample->dec] = 0.0f; | ||||
| 		sample->dec = inc; | ||||
| 	} | ||||
| 
 | ||||
| 	s->last_frame = now; | ||||
| 
 | ||||
| 	glClearColor(s->color[0], s->color[1], s->color[2], 1.0); | ||||
| 	glClearColor(sample->color[0], sample->color[1], sample->color[2], 1.0); | ||||
| 	glClear(GL_COLOR_BUFFER_BIT); | ||||
| } | ||||
| 
 | ||||
| void output_add(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_output *output = data; | ||||
| 	struct state *state = wl_container_of(listener, state, output_add); | ||||
| 	fprintf(stderr, "Output '%s' added\n", output->name); | ||||
| 	fprintf(stderr, "%s %s %"PRId32"mm x %"PRId32"mm\n", output->make, output->model, | ||||
| 		output->phys_width, output->phys_height); | ||||
| 	wlr_output_set_mode(output, output->modes->items[0]); | ||||
| 	struct output_state *ostate = calloc(1, sizeof(struct output_state)); | ||||
| 	ostate->output = output; | ||||
| 	ostate->state = state; | ||||
| 	ostate->frame.notify = output_frame; | ||||
| 	wl_list_init(&ostate->frame.link); | ||||
| 	wl_signal_add(&output->events.frame, &ostate->frame); | ||||
| 	wl_list_insert(&state->outputs, &ostate->link); | ||||
| } | ||||
| 
 | ||||
| void output_remove(struct wl_listener *listener, void *data) { | ||||
| 	struct wlr_output *output = data; | ||||
| 	struct state *state = wl_container_of(listener, state, output_remove); | ||||
| 	struct output_state *ostate = NULL, *_ostate; | ||||
| 	wl_list_for_each(_ostate, &state->outputs, link) { | ||||
| 		if (_ostate->output == output) { | ||||
| 			ostate = _ostate; | ||||
| 			break; | ||||
| 		} | ||||
| static void handle_keyboard_key(struct keyboard_state *kbstate, | ||||
| 		xkb_keysym_t sym, enum wlr_key_state key_state) { | ||||
| 	if (sym == XKB_KEY_Escape) { | ||||
| 		kbstate->compositor->exit = true; | ||||
| 	} | ||||
| 	if (!ostate) { | ||||
| 		return; // We are unfamiliar with this output
 | ||||
| 	} | ||||
| 	wl_list_remove(&ostate->link); | ||||
| 	wl_list_remove(&ostate->frame.link); | ||||
| } | ||||
| 
 | ||||
| int timer_done(void *data) { | ||||
| 	*(bool *)data = true; | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| int enable_outputs(void *data) { | ||||
| 	struct state *state = data; | ||||
| 	struct output_state *ostate; | ||||
| 	wl_list_for_each(ostate, &state->outputs, link) { | ||||
| 		struct wlr_output *output = ostate->output; | ||||
| 		wlr_output_enable(output, true); | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| int disable_outputs(void *data) { | ||||
| 	struct state *state = data; | ||||
| 	struct output_state *ostate; | ||||
| 	wl_list_for_each(ostate, &state->outputs, link) { | ||||
| 		struct wlr_output *output = ostate->output; | ||||
| 		wlr_output_enable(output, false); | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| int main() { | ||||
| 	struct state state = { | ||||
| 	struct sample_state state = { | ||||
| 		.color = { 1.0, 0.0, 0.0 }, | ||||
| 		.dec = 0, | ||||
| 		.output_add = { .notify = output_add }, | ||||
| 		.output_remove = { .notify = output_remove } | ||||
| 	}; | ||||
| 	struct compositor_state compositor; | ||||
| 
 | ||||
| 	wl_list_init(&state.outputs); | ||||
| 	wl_list_init(&state.output_add.link); | ||||
| 	wl_list_init(&state.output_remove.link); | ||||
| 	clock_gettime(CLOCK_MONOTONIC, &state.last_frame); | ||||
| 
 | ||||
| 	struct wl_display *display = wl_display_create(); | ||||
| 	struct wl_event_loop *event_loop = wl_display_get_event_loop(display); | ||||
| 
 | ||||
| 	struct wlr_session *session = wlr_session_start(display); | ||||
| 	if (!session) { | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	struct wlr_backend *wlr = wlr_backend_autocreate(display, session); | ||||
| 	wl_signal_add(&wlr->events.output_add, &state.output_add); | ||||
| 	wl_signal_add(&wlr->events.output_remove, &state.output_remove); | ||||
| 	if (!wlr || !wlr_backend_init(wlr)) { | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	bool done = false; | ||||
| 	struct wl_event_source *timer = wl_event_loop_add_timer(event_loop, | ||||
| 		timer_done, &done); | ||||
| 	struct wl_event_source *timer_disable_outputs = | ||||
| 		wl_event_loop_add_timer(event_loop, disable_outputs, &state); | ||||
| 	struct wl_event_source *timer_enable_outputs = | ||||
| 		wl_event_loop_add_timer(event_loop, enable_outputs, &state); | ||||
| 
 | ||||
| 	wl_event_source_timer_update(timer, 20000); | ||||
| 	wl_event_source_timer_update(timer_disable_outputs, 5000); | ||||
| 	wl_event_source_timer_update(timer_enable_outputs, 10000); | ||||
| 
 | ||||
| 	while (!done) { | ||||
| 		wl_event_loop_dispatch(event_loop, 0); | ||||
| 	} | ||||
| 
 | ||||
| 	wl_event_source_remove(timer); | ||||
| 	wlr_backend_destroy(wlr); | ||||
| 	wl_display_destroy(display); | ||||
| 	compositor_init(&compositor); | ||||
| 	compositor.output_frame_cb = handle_output_frame; | ||||
| 	compositor.keyboard_key_cb = handle_keyboard_key; | ||||
| 	compositor.data = &state; | ||||
| 	compositor_run(&compositor); | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,164 @@ | |||
| #define _POSIX_C_SOURCE 199309L | ||||
| #define _XOPEN_SOURCE 500 | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <time.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wayland-server-protocol.h> | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include <GLES3/gl3.h> | ||||
| #include <wlr/render/matrix.h> | ||||
| #include <wlr/render/gles3.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wlr/backend.h> | ||||
| #include <wlr/session.h> | ||||
| #include <wlr/types.h> | ||||
| #include <math.h> | ||||
| #include "shared.h" | ||||
| #include "cat.h" | ||||
| 
 | ||||
| struct sample_state { | ||||
| 	struct wlr_renderer *renderer; | ||||
| 	bool proximity, tap, button; | ||||
| 	double distance; | ||||
| 	double pressure; | ||||
| 	double x_mm, y_mm; | ||||
| 	double width_mm, height_mm; | ||||
| 	struct wl_list link; | ||||
| 	float tool_color[4]; | ||||
| 	float pad_color[4]; | ||||
| }; | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
| 	int32_t width, height; | ||||
| 	wlr_output_effective_resolution(wlr_output, &width, &height); | ||||
| 
 | ||||
| 	wlr_renderer_begin(sample->renderer, wlr_output); | ||||
| 
 | ||||
| 	float matrix[16], view[16]; | ||||
| 	float distance = 0.8f * (1 - sample->distance); | ||||
| 	float tool_color[4] = { distance, distance, distance, 1 }; | ||||
| 	for (size_t i = 0; sample->button && i < 4; ++i) { | ||||
| 		tool_color[i] = sample->tool_color[i]; | ||||
| 	} | ||||
| 	float scale = 4; | ||||
| 
 | ||||
| 	float pad_width = sample->width_mm * scale; | ||||
| 	float pad_height = sample->height_mm * scale; | ||||
| 	float left = width / 2.0f - pad_width / 2.0f; | ||||
| 	float top = height / 2.0f - pad_height / 2.0f; | ||||
| 	wlr_matrix_translate(&matrix, left, top, 0); | ||||
| 	wlr_matrix_scale(&view, pad_width, pad_height, 1); | ||||
| 	wlr_matrix_mul(&matrix, &view, &view); | ||||
| 	wlr_matrix_mul(&wlr_output->transform_matrix, &view, &matrix); | ||||
| 	wlr_render_colored_quad(sample->renderer, &sample->pad_color, &matrix); | ||||
| 
 | ||||
| 	if (sample->proximity) { | ||||
| 		wlr_matrix_translate(&matrix, | ||||
| 				sample->x_mm * scale - 8 * (sample->pressure + 1) + left, | ||||
| 				sample->y_mm * scale - 8 * (sample->pressure + 1) + top, 0); | ||||
| 		wlr_matrix_scale(&view, | ||||
| 				16 * (sample->pressure + 1), | ||||
| 				16 * (sample->pressure + 1), 1); | ||||
| 		wlr_matrix_mul(&matrix, &view, &view); | ||||
| 		wlr_matrix_mul(&wlr_output->transform_matrix, &view, &matrix); | ||||
| 		wlr_render_colored_ellipse(sample->renderer, &tool_color, &matrix); | ||||
| 	} | ||||
| 
 | ||||
| 	wlr_renderer_end(sample->renderer); | ||||
| } | ||||
| 
 | ||||
| static void handle_keyboard_key(struct keyboard_state *kbstate, | ||||
| 		xkb_keysym_t sym, enum wlr_key_state key_state) { | ||||
| 	if (sym == XKB_KEY_Escape) { | ||||
| 		kbstate->compositor->exit = true; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void handle_tool_axis(struct tablet_tool_state *tstate, | ||||
| 			struct wlr_tablet_tool_axis *event) { | ||||
| 	struct sample_state *sample = tstate->compositor->data; | ||||
| 	sample->width_mm = event->width_mm; | ||||
| 	sample->height_mm = event->height_mm; | ||||
| 	if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X)) { | ||||
| 		sample->x_mm = event->x_mm; | ||||
| 	} | ||||
| 	if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { | ||||
| 		sample->y_mm = event->y_mm; | ||||
| 	} | ||||
| 	if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_DISTANCE)) { | ||||
| 		sample->distance = event->distance; | ||||
| 	} | ||||
| 	if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_PRESSURE)) { | ||||
| 		sample->pressure = event->pressure; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void handle_tool_proximity(struct tablet_tool_state *tstate, | ||||
| 		enum wlr_tablet_tool_proximity_state state) { | ||||
| 	struct sample_state *sample = tstate->compositor->data; | ||||
| 	sample->proximity = state == WLR_TABLET_TOOL_PROXIMITY_IN; | ||||
| } | ||||
| 
 | ||||
| static void handle_tool_button(struct tablet_tool_state *tstate, | ||||
| 		uint32_t button, enum wlr_button_state state) { | ||||
| 	struct sample_state *sample = tstate->compositor->data; | ||||
| 	if (state == WLR_BUTTON_RELEASED) { | ||||
| 		sample->button = false; | ||||
| 	} else { | ||||
| 		sample->button = true; | ||||
| 		for (size_t i = 0; i < 3; ++i) { | ||||
| 			if (button % 3 == i) { | ||||
| 				sample->tool_color[i] = 0; | ||||
| 			} else { | ||||
| 				sample->tool_color[i] = 1; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void handle_pad_button(struct tablet_pad_state *pstate, | ||||
| 		uint32_t button, enum wlr_button_state state) { | ||||
| 	struct sample_state *sample = pstate->compositor->data; | ||||
| 	float default_color[4] = { 0.75, 0.75, 0.75, 1.0 }; | ||||
| 	if (state == WLR_BUTTON_RELEASED) { | ||||
| 		memcpy(sample->pad_color, default_color, sizeof(default_color)); | ||||
| 	} else { | ||||
| 		for (size_t i = 0; i < 3; ++i) { | ||||
| 			if (button % 3 == i) { | ||||
| 				sample->pad_color[i] = 0; | ||||
| 			} else { | ||||
| 				sample->pad_color[i] = 1; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
| 	struct sample_state state = { | ||||
| 		.tool_color = { 1, 1, 1, 1 }, | ||||
| 		.pad_color = { 0.75, 0.75, 0.75, 1.0 } | ||||
| 	}; | ||||
| 	struct compositor_state compositor; | ||||
| 
 | ||||
| 	compositor_init(&compositor); | ||||
| 	compositor.output_frame_cb = handle_output_frame; | ||||
| 	compositor.keyboard_key_cb = handle_keyboard_key; | ||||
| 	compositor.tool_axis_cb = handle_tool_axis; | ||||
| 	compositor.tool_proximity_cb = handle_tool_proximity; | ||||
| 	compositor.tool_button_cb = handle_tool_button; | ||||
| 	compositor.pad_button_cb = handle_pad_button; | ||||
| 
 | ||||
| 	state.renderer = wlr_gles3_renderer_init(); | ||||
| 
 | ||||
| 	compositor.data = &state; | ||||
| 	compositor_run(&compositor); | ||||
| 
 | ||||
| 	wlr_renderer_destroy(state.renderer); | ||||
| } | ||||
|  | @ -0,0 +1,122 @@ | |||
| #define _POSIX_C_SOURCE 199309L | ||||
| #define _XOPEN_SOURCE 500 | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <time.h> | ||||
| #include <string.h> | ||||
| #include <unistd.h> | ||||
| #include <stdint.h> | ||||
| #include <math.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wayland-server-protocol.h> | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
| #include <GLES3/gl3.h> | ||||
| #include <wlr/common/list.h> | ||||
| #include <wlr/render/matrix.h> | ||||
| #include <wlr/render/gles3.h> | ||||
| #include <wlr/render.h> | ||||
| #include <wlr/backend.h> | ||||
| #include <wlr/session.h> | ||||
| #include <wlr/types.h> | ||||
| #include "shared.h" | ||||
| #include "cat.h" | ||||
| 
 | ||||
| struct sample_state { | ||||
| 	struct wlr_renderer *renderer; | ||||
| 	struct wlr_surface *cat_texture; | ||||
| 	list_t *touch_points; | ||||
| }; | ||||
| 
 | ||||
| struct touch_point { | ||||
| 	int32_t slot; | ||||
| 	double x, y; | ||||
| }; | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
| 	int32_t width, height; | ||||
| 	wlr_output_effective_resolution(wlr_output, &width, &height); | ||||
| 	wlr_renderer_begin(sample->renderer, wlr_output); | ||||
| 
 | ||||
| 	float matrix[16]; | ||||
| 	for (size_t i = 0; i < sample->touch_points->length; ++i) { | ||||
| 		struct touch_point *p = sample->touch_points->items[i]; | ||||
| 		wlr_surface_get_matrix(sample->cat_texture, &matrix, | ||||
| 			&wlr_output->transform_matrix, | ||||
| 			(int)(p->x * width) - sample->cat_texture->width / 2, | ||||
| 			(int)(p->y * height) - sample->cat_texture->height / 2); | ||||
| 		wlr_render_with_matrix(sample->renderer, | ||||
| 				sample->cat_texture, &matrix); | ||||
| 	} | ||||
| 
 | ||||
| 	wlr_renderer_end(sample->renderer); | ||||
| } | ||||
| 
 | ||||
| static void handle_keyboard_key(struct keyboard_state *kbstate, | ||||
| 		xkb_keysym_t sym, enum wlr_key_state key_state) { | ||||
| 	if (sym == XKB_KEY_Escape) { | ||||
| 		kbstate->compositor->exit = true; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void handle_touch_down(struct touch_state *tstate, int32_t slot, | ||||
| 		double x, double y, double width, double height) { | ||||
| 	struct sample_state *sample = tstate->compositor->data; | ||||
| 	struct touch_point *point = calloc(1, sizeof(struct touch_state)); | ||||
| 	point->slot = slot; | ||||
| 	point->x = x / width; | ||||
| 	point->y = y / height; | ||||
| 	list_add(sample->touch_points, point); | ||||
| } | ||||
| 
 | ||||
| static void handle_touch_up(struct touch_state *tstate, int32_t slot) { | ||||
| 	struct sample_state *sample = tstate->compositor->data; | ||||
| 	for (size_t i = 0; i < sample->touch_points->length; ++i) { | ||||
| 		struct touch_point *point = sample->touch_points->items[i]; | ||||
| 		if (point->slot == slot) { | ||||
| 			list_del(sample->touch_points, i); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void handle_touch_motion(struct touch_state *tstate, int32_t slot, | ||||
| 		double x, double y, double width, double height) { | ||||
| 	struct sample_state *sample = tstate->compositor->data; | ||||
| 	for (size_t i = 0; i < sample->touch_points->length; ++i) { | ||||
| 		struct touch_point *point = sample->touch_points->items[i]; | ||||
| 		if (point->slot == slot) { | ||||
| 			point->x = x / width; | ||||
| 			point->y = y / height; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) { | ||||
| 	struct sample_state state = { | ||||
| 		.touch_points = list_create() | ||||
| 	}; | ||||
| 	struct compositor_state compositor; | ||||
| 
 | ||||
| 	compositor_init(&compositor); | ||||
| 	compositor.output_frame_cb = handle_output_frame; | ||||
| 	compositor.keyboard_key_cb = handle_keyboard_key; | ||||
| 	compositor.touch_down_cb = handle_touch_down; | ||||
| 	compositor.touch_up_cb = handle_touch_up; | ||||
| 	compositor.touch_motion_cb = handle_touch_motion; | ||||
| 
 | ||||
| 	state.renderer = wlr_gles3_renderer_init(); | ||||
| 	state.cat_texture = wlr_render_surface_init(state.renderer); | ||||
| 	wlr_surface_attach_pixels(state.cat_texture, GL_RGBA, | ||||
| 		cat_tex.width, cat_tex.height, cat_tex.pixel_data); | ||||
| 
 | ||||
| 	compositor.data = &state; | ||||
| 	compositor_run(&compositor); | ||||
| 
 | ||||
| 	wlr_surface_destroy(state.cat_texture); | ||||
| 	wlr_renderer_destroy(state.renderer); | ||||
| } | ||||
|  | @ -73,10 +73,12 @@ struct wlr_output_state { | |||
| 	drmModeCrtc *old_crtc; | ||||
| 
 | ||||
| 	struct wlr_drm_renderer *renderer; | ||||
| 	struct gbm_surface *gbm; | ||||
| 	struct gbm_bo *bo_last; | ||||
| 	struct gbm_bo *bo_current; | ||||
| 	EGLSurface *egl; | ||||
| 	struct gbm_surface *gbm; | ||||
| 	struct gbm_bo *bo[2]; | ||||
| 	struct gbm_bo *cursor_bo[2]; | ||||
| 	int current_cursor; | ||||
| 	uint32_t cursor_width, cursor_height; | ||||
| 
 | ||||
| 	bool pageflip_pending; | ||||
| 	bool cleanup; | ||||
|  |  | |||
|  | @ -0,0 +1,80 @@ | |||
| #ifndef _WLR_BACKEND_LIBINPUT_INTERNAL_H | ||||
| #define _WLR_BACKEND_LIBINPUT_INTERNAL_H | ||||
| #include <libinput.h> | ||||
| #include <wlr/backend/interface.h> | ||||
| #include <wlr/common/list.h> | ||||
| #include <wayland-server-core.h> | ||||
| #include "backend/udev.h" | ||||
| #include "types.h" | ||||
| 
 | ||||
| struct wlr_backend_state { | ||||
| 	struct wlr_backend *backend; | ||||
| 	struct wlr_session *session; | ||||
| 	struct wlr_udev *udev; | ||||
| 	struct wl_display *display; | ||||
| 
 | ||||
| 	struct libinput *libinput; | ||||
| 	struct wl_event_source *input_event; | ||||
| 
 | ||||
| 	list_t *devices; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_input_device_state { | ||||
| 	struct libinput_device *handle; | ||||
| }; | ||||
| 
 | ||||
| void wlr_libinput_event(struct wlr_backend_state *state, | ||||
| 		struct libinput_event *event); | ||||
| 
 | ||||
| struct wlr_input_device *get_appropriate_device( | ||||
| 		enum wlr_input_device_type desired_type, | ||||
| 		struct libinput_device *device); | ||||
| 
 | ||||
| struct wlr_keyboard *wlr_libinput_keyboard_create( | ||||
| 		struct libinput_device *device); | ||||
| void handle_keyboard_key(struct libinput_event *event, | ||||
| 		struct libinput_device *device); | ||||
| 
 | ||||
| struct wlr_pointer *wlr_libinput_pointer_create( | ||||
| 		struct libinput_device *device); | ||||
| void handle_pointer_motion(struct libinput_event *event, | ||||
| 		struct libinput_device *device); | ||||
| void handle_pointer_motion_abs(struct libinput_event *event, | ||||
| 		struct libinput_device *device); | ||||
| void handle_pointer_button(struct libinput_event *event, | ||||
| 		struct libinput_device *device); | ||||
| void handle_pointer_axis(struct libinput_event *event, | ||||
| 		struct libinput_device *device); | ||||
| 
 | ||||
| struct wlr_touch *wlr_libinput_touch_create( | ||||
| 		struct libinput_device *device); | ||||
| void handle_touch_down(struct libinput_event *event, | ||||
| 		struct libinput_device *device); | ||||
| void handle_touch_up(struct libinput_event *event, | ||||
| 		struct libinput_device *device); | ||||
| void handle_touch_motion(struct libinput_event *event, | ||||
| 		struct libinput_device *device); | ||||
| void handle_touch_cancel(struct libinput_event *event, | ||||
| 		struct libinput_device *device); | ||||
| 
 | ||||
| struct wlr_tablet_tool *wlr_libinput_tablet_tool_create( | ||||
| 		struct libinput_device *device); | ||||
| void handle_tablet_tool_axis(struct libinput_event *event, | ||||
| 		struct libinput_device *device); | ||||
| void handle_tablet_tool_proximity(struct libinput_event *event, | ||||
| 		struct libinput_device *device); | ||||
| void handle_tablet_tool_tip(struct libinput_event *event, | ||||
| 		struct libinput_device *device); | ||||
| void handle_tablet_tool_button(struct libinput_event *event, | ||||
| 		struct libinput_device *device); | ||||
| 
 | ||||
| struct wlr_tablet_pad *wlr_libinput_tablet_pad_create( | ||||
| 		struct libinput_device *device); | ||||
| void handle_tablet_pad_button(struct libinput_event *event, | ||||
| 		struct libinput_device *device); | ||||
| void handle_tablet_pad_ring(struct libinput_event *event, | ||||
| 		struct libinput_device *device); | ||||
| void handle_tablet_pad_strip(struct libinput_event *event, | ||||
| 		struct libinput_device *device); | ||||
| 
 | ||||
| #endif | ||||
|  | @ -0,0 +1,13 @@ | |||
| #ifndef _WLR_MULTI_BACKEND_INTERNAL | ||||
| #define _WLR_MULTI_BACKEND_INTERNAL | ||||
| 
 | ||||
| #include <wlr/backend/interface.h> | ||||
| #include <wlr/backend/multi.h> | ||||
| #include <wlr/common/list.h> | ||||
| 
 | ||||
| struct wlr_backend_state { | ||||
| 	struct wlr_backend *backend; | ||||
| 	list_t *backends; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  | @ -13,6 +13,9 @@ struct wlr_surface_state { | |||
| 
 | ||||
| struct wlr_surface *gles3_surface_init(); | ||||
| 
 | ||||
| extern const GLchar quad_vertex_src[]; | ||||
| extern const GLchar quad_fragment_src[]; | ||||
| extern const GLchar ellipse_fragment_src[]; | ||||
| extern const GLchar vertex_src[]; | ||||
| extern const GLchar fragment_src_RGB[]; | ||||
| extern const GLchar fragment_src_RGBA[]; | ||||
|  |  | |||
|  | @ -11,6 +11,9 @@ struct wlr_output_impl { | |||
| 			struct wlr_output_mode *mode); | ||||
| 	void (*transform)(struct wlr_output_state *state, | ||||
| 			enum wl_output_transform transform); | ||||
| 	bool (*set_cursor)(struct wlr_output_state *state, | ||||
| 		const uint8_t *buf, int32_t stride, uint32_t width, uint32_t height); | ||||
| 	bool (*move_cursor)(struct wlr_output_state *state, int x, int y); | ||||
| 	void (*destroy)(struct wlr_output_state *state); | ||||
| }; | ||||
| 
 | ||||
|  | @ -18,4 +21,56 @@ struct wlr_output *wlr_output_create(struct wlr_output_impl *impl, | |||
| 		struct wlr_output_state *state); | ||||
| void wlr_output_free(struct wlr_output *output); | ||||
| 
 | ||||
| struct wlr_keyboard_impl { | ||||
| 	void (*destroy)(struct wlr_keyboard_state *state); | ||||
| 	void (*led_update)(struct wlr_keyboard_state *state, uint32_t leds); | ||||
| }; | ||||
| 
 | ||||
| struct wlr_keyboard *wlr_keyboard_create(struct wlr_keyboard_impl *impl, | ||||
| 		struct wlr_keyboard_state *state); | ||||
| void wlr_keyboard_destroy(struct wlr_keyboard *keyboard); | ||||
| 
 | ||||
| struct wlr_pointer_impl { | ||||
| 	void (*destroy)(struct wlr_pointer_state *state); | ||||
| }; | ||||
| 
 | ||||
| struct wlr_pointer *wlr_pointer_create(struct wlr_pointer_impl *impl, | ||||
| 		struct wlr_pointer_state *state); | ||||
| void wlr_pointer_destroy(struct wlr_pointer *pointer); | ||||
| 
 | ||||
| struct wlr_touch_impl { | ||||
| 	void (*destroy)(struct wlr_touch_state *state); | ||||
| }; | ||||
| 
 | ||||
| struct wlr_touch *wlr_touch_create(struct wlr_touch_impl *impl, | ||||
| 		struct wlr_touch_state *state); | ||||
| void wlr_touch_destroy(struct wlr_touch *touch); | ||||
| 
 | ||||
| struct wlr_tablet_tool_impl { | ||||
| 	void (*destroy)(struct wlr_tablet_tool_state *tool); | ||||
| }; | ||||
| 
 | ||||
| struct wlr_tablet_tool *wlr_tablet_tool_create(struct wlr_tablet_tool_impl *impl, | ||||
| 		struct wlr_tablet_tool_state *state); | ||||
| void wlr_tablet_tool_destroy(struct wlr_tablet_tool *tool); | ||||
| 
 | ||||
| struct wlr_tablet_pad_impl { | ||||
| 	void (*destroy)(struct wlr_tablet_pad_state *pad); | ||||
| }; | ||||
| 
 | ||||
| struct wlr_tablet_pad *wlr_tablet_pad_create(struct wlr_tablet_pad_impl *impl, | ||||
| 		struct wlr_tablet_pad_state *state); | ||||
| void wlr_tablet_pad_destroy(struct wlr_tablet_pad *pad); | ||||
| 
 | ||||
| struct wlr_input_device_impl { | ||||
| 	void (*destroy)(struct wlr_input_device_state *state); | ||||
| }; | ||||
| 
 | ||||
| struct wlr_input_device *wlr_input_device_create( | ||||
| 		enum wlr_input_device_type type, | ||||
| 		struct wlr_input_device_impl *impl, | ||||
| 		struct wlr_input_device_state *state, | ||||
| 		const char *name, int vendor, int product); | ||||
| void wlr_input_device_destroy(struct wlr_input_device *dev); | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -12,14 +12,10 @@ struct wlr_backend { | |||
| 	struct wlr_backend_state *state; | ||||
| 
 | ||||
| 	struct { | ||||
| 		struct wl_signal input_add; | ||||
| 		struct wl_signal input_remove; | ||||
| 		struct wl_signal output_add; | ||||
| 		struct wl_signal output_remove; | ||||
| 		struct wl_signal keyboard_add; | ||||
| 		struct wl_signal keyboard_remove; | ||||
| 		struct wl_signal pointer_add; | ||||
| 		struct wl_signal pointer_remove; | ||||
| 		struct wl_signal touch_add; | ||||
| 		struct wl_signal touch_remove; | ||||
| 	} events; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,15 @@ | |||
| #ifndef WLR_BACKEND_LIBINPUT_H | ||||
| #define WLR_BACKEND_LIBINPUT_H | ||||
| 
 | ||||
| #include <libinput.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/session.h> | ||||
| #include <wlr/backend.h> | ||||
| #include <wlr/backend/udev.h> | ||||
| #include <wlr/types.h> | ||||
| 
 | ||||
| struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display, | ||||
| 		struct wlr_session *session, struct wlr_udev *udev); | ||||
| struct libinput_device *wlr_libinput_get_device_handle(struct wlr_input_device *dev); | ||||
| 
 | ||||
| #endif | ||||
|  | @ -0,0 +1,10 @@ | |||
| #ifndef _WLR_BACKEND_MULTI_H | ||||
| #define _WLR_BACKEND_MULTI_H | ||||
| 
 | ||||
| #include <wlr/backend.h> | ||||
| 
 | ||||
| struct wlr_backend *wlr_multi_backend_create(); | ||||
| void wlr_multi_backend_add(struct wlr_backend *multi, | ||||
| 		struct wlr_backend *backend); | ||||
| 
 | ||||
| #endif | ||||
|  | @ -28,6 +28,16 @@ struct wlr_surface *wlr_render_surface_init(struct wlr_renderer *r); | |||
|  */ | ||||
| bool wlr_render_with_matrix(struct wlr_renderer *r, | ||||
| 		struct wlr_surface *surface, const float (*matrix)[16]); | ||||
| /**
 | ||||
|  * Renders a solid quad in the specified color. | ||||
|  */ | ||||
| void wlr_render_colored_quad(struct wlr_renderer *r, | ||||
| 		const float (*color)[4], const float (*matrix)[16]); | ||||
| /**
 | ||||
|  * Renders a solid ellipse in the specified color. | ||||
|  */ | ||||
| void wlr_render_colored_ellipse(struct wlr_renderer *r, | ||||
| 		const float (*color)[4], const float (*matrix)[16]); | ||||
| /**
 | ||||
|  * Destroys this wlr_renderer. Surfaces must be destroyed separately. | ||||
|  */ | ||||
|  |  | |||
|  | @ -19,6 +19,10 @@ struct wlr_renderer_impl { | |||
| 	struct wlr_surface *(*surface_init)(struct wlr_renderer_state *state); | ||||
| 	bool (*render_with_matrix)(struct wlr_renderer_state *state, | ||||
| 		struct wlr_surface *surface, const float (*matrix)[16]); | ||||
| 	void (*render_quad)(struct wlr_renderer_state *state, | ||||
| 			const float (*color)[4], const float (*matrix)[16]); | ||||
| 	void (*render_ellipse)(struct wlr_renderer_state *state, | ||||
| 			const float (*color)[4], const float (*matrix)[16]); | ||||
| 	void (*destroy)(struct wlr_renderer_state *state); | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ struct wlr_session { | |||
| struct wlr_session *wlr_session_start(struct wl_display *disp); | ||||
| void wlr_session_finish(struct wlr_session *session); | ||||
| int wlr_session_open_file(struct wlr_session *restrict session, | ||||
| 	const char *restrict path); | ||||
| 		const char *restrict path); | ||||
| void wlr_session_close_file(struct wlr_session *session, int fd); | ||||
| bool wlr_session_change_vt(struct wlr_session *session, int vt); | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ struct session_impl { | |||
| 	struct wlr_session *(*start)(struct wl_display *disp); | ||||
| 	void (*finish)(struct wlr_session *session); | ||||
| 	int (*open)(struct wlr_session *restrict session, | ||||
| 		const char *restrict path); | ||||
| 			const char *restrict path); | ||||
| 	void (*close)(struct wlr_session *session, int fd); | ||||
| 	bool (*change_vt)(struct wlr_session *session, int vt); | ||||
| }; | ||||
|  |  | |||
|  | @ -46,8 +46,303 @@ bool wlr_output_set_mode(struct wlr_output *output, | |||
| 		struct wlr_output_mode *mode); | ||||
| void wlr_output_transform(struct wlr_output *output, | ||||
| 		enum wl_output_transform transform); | ||||
| bool wlr_output_set_cursor(struct wlr_output *output, | ||||
| 		const uint8_t *buf, int32_t stride, uint32_t width, uint32_t height); | ||||
| bool wlr_output_move_cursor(struct wlr_output *output, int x, int y); | ||||
| void wlr_output_destroy(struct wlr_output *output); | ||||
| void wlr_output_effective_resolution(struct wlr_output *output, | ||||
| 		int *width, int *height); | ||||
| 
 | ||||
| enum WLR_KEYBOARD_LED { | ||||
| 	WLR_LED_NUM_LOCK = 1, | ||||
| 	WLR_LED_CAPS_LOCK = 2, | ||||
| 	WLR_LED_SCROLL_LOCK = 4, | ||||
| 	WLR_LED_LAST | ||||
| }; | ||||
| 
 | ||||
| struct wlr_keyboard_state; | ||||
| struct wlr_keyboard_impl; | ||||
| 
 | ||||
| struct wlr_keyboard { | ||||
| 	struct wlr_keyboard_state *state; | ||||
| 	struct wlr_keyboard_impl *impl; | ||||
| 	uint32_t leds; | ||||
| 
 | ||||
| 	struct { | ||||
| 		struct wl_signal key; | ||||
| 	} events; | ||||
| }; | ||||
| 
 | ||||
| void wlr_keyboard_led_update(struct wlr_keyboard *keyboard, uint32_t leds); | ||||
| 
 | ||||
| enum wlr_key_state { | ||||
| 	WLR_KEY_RELEASED, | ||||
| 	WLR_KEY_PRESSED, | ||||
| }; | ||||
| 
 | ||||
| struct wlr_keyboard_key { | ||||
| 	uint32_t time_sec; | ||||
| 	uint64_t time_usec; | ||||
| 	uint32_t keycode; | ||||
| 	enum wlr_key_state state; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_pointer_state; | ||||
| struct wlr_pointer_impl; | ||||
| 
 | ||||
| struct wlr_pointer { | ||||
| 	struct wlr_pointer_state *state; | ||||
| 	struct wlr_pointer_impl *impl; | ||||
| 
 | ||||
| 	struct { | ||||
| 		struct wl_signal motion; | ||||
| 		struct wl_signal motion_absolute; | ||||
| 		struct wl_signal button; | ||||
| 		struct wl_signal axis; | ||||
| 	} events; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_pointer_motion { | ||||
| 	uint32_t time_sec; | ||||
| 	uint64_t time_usec; | ||||
| 	double delta_x, delta_y; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_pointer_motion_absolute { | ||||
| 	uint32_t time_sec; | ||||
| 	uint64_t time_usec; | ||||
| 	double x_mm, y_mm; | ||||
| 	double width_mm, height_mm; | ||||
| }; | ||||
| 
 | ||||
| enum wlr_button_state { | ||||
| 	WLR_BUTTON_RELEASED, | ||||
| 	WLR_BUTTON_PRESSED, | ||||
| }; | ||||
| 
 | ||||
| struct wlr_pointer_button { | ||||
| 	uint32_t time_sec; | ||||
| 	uint64_t time_usec; | ||||
| 	uint32_t button; | ||||
| 	enum wlr_button_state state; | ||||
| }; | ||||
| 
 | ||||
| enum wlr_axis_source { | ||||
| 	WLR_AXIS_SOURCE_WHEEL, | ||||
| 	WLR_AXIS_SOURCE_FINGER, | ||||
| 	WLR_AXIS_SOURCE_CONTINUOUS, | ||||
| 	WLR_AXIS_SOURCE_WHEEL_TILT, | ||||
| }; | ||||
| 
 | ||||
| enum wlr_axis_orientation { | ||||
| 	WLR_AXIS_ORIENTATION_VERTICAL, | ||||
| 	WLR_AXIS_ORIENTATION_HORIZONTAL, | ||||
| }; | ||||
| 
 | ||||
| struct wlr_pointer_axis { | ||||
| 	uint32_t time_sec; | ||||
| 	uint64_t time_usec; | ||||
| 	enum wlr_axis_source source; | ||||
| 	enum wlr_axis_orientation orientation; | ||||
| 	double delta; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_touch_state; | ||||
| struct wlr_touch_impl; | ||||
| 
 | ||||
| struct wlr_touch { | ||||
| 	struct wlr_touch_state *state; | ||||
| 	struct wlr_touch_impl *impl; | ||||
| 
 | ||||
| 	struct { | ||||
| 		struct wl_signal down; | ||||
| 		struct wl_signal up; | ||||
| 		struct wl_signal motion; | ||||
| 		struct wl_signal cancel; | ||||
| 	} events; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_touch_down { | ||||
| 	uint32_t time_sec; | ||||
| 	uint64_t time_usec; | ||||
| 	int32_t slot; | ||||
| 	double x_mm, y_mm; | ||||
| 	double width_mm, height_mm; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_touch_up { | ||||
| 	uint32_t time_sec; | ||||
| 	uint64_t time_usec; | ||||
| 	int32_t slot; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_touch_motion { | ||||
| 	uint32_t time_sec; | ||||
| 	uint64_t time_usec; | ||||
| 	int32_t slot; | ||||
| 	double x_mm, y_mm; | ||||
| 	double width_mm, height_mm; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_touch_cancel { | ||||
| 	uint32_t time_sec; | ||||
| 	uint64_t time_usec; | ||||
| 	int32_t slot; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_tablet_tool_impl; | ||||
| struct wlr_tablet_tool_state; | ||||
| 
 | ||||
| struct wlr_tablet_tool { | ||||
| 	struct wlr_tablet_tool_impl *impl; | ||||
| 	struct wlr_tablet_tool_state *state; | ||||
| 
 | ||||
| 	struct { | ||||
| 		struct wl_signal axis; | ||||
| 		struct wl_signal proximity; | ||||
| 		struct wl_signal tip; | ||||
| 		struct wl_signal button; | ||||
| 	} events; | ||||
| }; | ||||
| 
 | ||||
| enum wlr_tablet_tool_axes { | ||||
| 	WLR_TABLET_TOOL_AXIS_X = 1, | ||||
| 	WLR_TABLET_TOOL_AXIS_Y = 2, | ||||
| 	WLR_TABLET_TOOL_AXIS_DISTANCE = 4, | ||||
| 	WLR_TABLET_TOOL_AXIS_PRESSURE = 8, | ||||
| 	WLR_TABLET_TOOL_AXIS_TILT_X = 16, | ||||
| 	WLR_TABLET_TOOL_AXIS_TILT_Y = 32, | ||||
| 	WLR_TABLET_TOOL_AXIS_ROTATION = 64, | ||||
| 	WLR_TABLET_TOOL_AXIS_SLIDER = 128, | ||||
| 	WLR_TABLET_TOOL_AXIS_WHEEL = 256, | ||||
| }; | ||||
| 
 | ||||
| struct wlr_tablet_tool_axis { | ||||
| 	uint32_t time_sec; | ||||
| 	uint64_t time_usec; | ||||
| 	uint32_t updated_axes; | ||||
| 	double x_mm, y_mm; | ||||
| 	double width_mm, height_mm; | ||||
| 	double pressure; | ||||
| 	double distance; | ||||
| 	double tilt_x, tilt_y; | ||||
| 	double rotation; | ||||
| 	double slider; | ||||
| 	double wheel_delta; | ||||
| }; | ||||
| 
 | ||||
| enum wlr_tablet_tool_proximity_state { | ||||
| 	WLR_TABLET_TOOL_PROXIMITY_OUT, | ||||
| 	WLR_TABLET_TOOL_PROXIMITY_IN, | ||||
| }; | ||||
| 
 | ||||
| struct wlr_tablet_tool_proximity { | ||||
| 	uint32_t time_sec; | ||||
| 	uint64_t time_usec; | ||||
| 	double x, y; | ||||
| 	double width_mm, height_mm; | ||||
| 	enum wlr_tablet_tool_proximity_state state; | ||||
| }; | ||||
| 
 | ||||
| enum wlr_tablet_tool_tip_state { | ||||
| 	WLR_TABLET_TOOL_TIP_UP, | ||||
| 	WLR_TABLET_TOOL_TIP_DOWN, | ||||
| }; | ||||
| 
 | ||||
| struct wlr_tablet_tool_tip { | ||||
| 	uint32_t time_sec; | ||||
| 	uint64_t time_usec; | ||||
| 	double x, y; | ||||
| 	double width_mm, height_mm; | ||||
| 	enum wlr_tablet_tool_tip_state state; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_tablet_tool_button { | ||||
| 	uint32_t time_sec; | ||||
| 	uint64_t time_usec; | ||||
| 	uint32_t button; | ||||
| 	enum wlr_button_state state; | ||||
| }; | ||||
| 
 | ||||
| // NOTE: the wlr tablet pad implementation does not currently support tablets
 | ||||
| // with more than one mode. I don't own any such hardware so I cannot test it
 | ||||
| // and it is too complicated to make a meaningful implementation of blindly.
 | ||||
| struct wlr_tablet_pad_impl; | ||||
| struct wlr_tablet_pad_state; | ||||
| 
 | ||||
| struct wlr_tablet_pad { | ||||
| 	struct wlr_tablet_pad_impl *impl; | ||||
| 	struct wlr_tablet_pad_state *state; | ||||
| 
 | ||||
| 	struct { | ||||
| 		struct wl_signal button; | ||||
| 		struct wl_signal ring; | ||||
| 		struct wl_signal strip; | ||||
| 	} events; | ||||
| }; | ||||
| 
 | ||||
| struct wlr_tablet_pad_button { | ||||
| 	uint32_t time_sec; | ||||
| 	uint64_t time_usec; | ||||
| 	uint32_t button; | ||||
| 	enum wlr_button_state state; | ||||
| }; | ||||
| 
 | ||||
| enum wlr_tablet_pad_ring_source { | ||||
| 	WLR_TABLET_PAD_RING_SOURCE_UNKNOWN, | ||||
| 	WLR_TABLET_PAD_RING_SOURCE_FINGER, | ||||
| }; | ||||
| 
 | ||||
| struct wlr_tablet_pad_ring { | ||||
| 	uint32_t time_sec; | ||||
| 	uint64_t time_usec; | ||||
| 	enum wlr_tablet_pad_ring_source source; | ||||
| 	uint32_t ring; | ||||
| 	double position; | ||||
| }; | ||||
| 
 | ||||
| enum wlr_tablet_pad_strip_source { | ||||
| 	WLR_TABLET_PAD_STRIP_SOURCE_UNKNOWN, | ||||
| 	WLR_TABLET_PAD_STRIP_SOURCE_FINGER, | ||||
| }; | ||||
| 
 | ||||
| struct wlr_tablet_pad_strip { | ||||
| 	uint32_t time_sec; | ||||
| 	uint64_t time_usec; | ||||
| 	enum wlr_tablet_pad_strip_source source; | ||||
| 	uint32_t strip; | ||||
| 	double position; | ||||
| }; | ||||
| 
 | ||||
| enum wlr_input_device_type { | ||||
| 	WLR_INPUT_DEVICE_KEYBOARD, | ||||
| 	WLR_INPUT_DEVICE_POINTER, | ||||
| 	WLR_INPUT_DEVICE_TOUCH, | ||||
| 	WLR_INPUT_DEVICE_TABLET_TOOL, | ||||
| 	WLR_INPUT_DEVICE_TABLET_PAD, | ||||
| 	WLR_INPUT_DEVICE_GESTURE, | ||||
| 	WLR_INPUT_DEVICE_SWITCH, | ||||
| }; | ||||
| 
 | ||||
| struct wlr_input_device_state; | ||||
| struct wlr_input_device_impl; | ||||
| 
 | ||||
| struct wlr_input_device { | ||||
| 	struct wlr_input_device_state *state; | ||||
| 	struct wlr_input_device_impl *impl; | ||||
| 
 | ||||
| 	enum wlr_input_device_type type; | ||||
| 	int vendor, product; | ||||
| 	char *name; | ||||
| 
 | ||||
| 	union { | ||||
| 		void *_device; | ||||
| 		struct wlr_keyboard *keyboard; | ||||
| 		struct wlr_pointer *pointer; | ||||
| 		struct wlr_touch *touch; | ||||
| 		struct wlr_tablet_tool *tablet_tool; | ||||
| 		struct wlr_tablet_pad *tablet_pad; | ||||
| 	}; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -13,6 +13,8 @@ | |||
| static struct { | ||||
| 	bool initialized; | ||||
| 	GLuint rgb, rgba; | ||||
| 	GLuint quad; | ||||
| 	GLuint ellipse; | ||||
| } shaders; | ||||
| static GLuint vao, vbo, ebo; | ||||
| 
 | ||||
|  | @ -28,6 +30,9 @@ static bool compile_shader(GLuint type, const GLchar *src, GLuint *shader) { | |||
| 		GL_CALL(glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &loglen)); | ||||
| 		GLchar msg[loglen]; | ||||
| 		GL_CALL(glGetShaderInfoLog(*shader, loglen, &loglen, msg)); | ||||
| 		wlr_log(L_ERROR, "Shader compilation failed"); | ||||
| 		wlr_log(L_ERROR, "%s", msg); | ||||
| 		exit(1); | ||||
| 		return false; | ||||
| 	} | ||||
| 	return true; | ||||
|  | @ -60,6 +65,12 @@ static void init_default_shaders() { | |||
| 	if (!compile_program(vertex_src, fragment_src_RGBA, &shaders.rgba)) { | ||||
| 		goto error; | ||||
| 	} | ||||
| 	if (!compile_program(quad_vertex_src, quad_fragment_src, &shaders.quad)) { | ||||
| 		goto error; | ||||
| 	} | ||||
| 	if (!compile_program(quad_vertex_src, ellipse_fragment_src, &shaders.ellipse)) { | ||||
| 		goto error; | ||||
| 	} | ||||
| 	return; | ||||
| error: | ||||
| 	wlr_log(L_ERROR, "Failed to set up default shaders!"); | ||||
|  | @ -141,6 +152,28 @@ static bool wlr_gles3_render_surface(struct wlr_renderer_state *state, | |||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static void wlr_gles3_render_quad(struct wlr_renderer_state *state, | ||||
| 		const float (*color)[4], const float (*matrix)[16]) { | ||||
| 	GL_CALL(glUseProgram(shaders.quad)); | ||||
| 	GL_CALL(glBindVertexArray(vao)); | ||||
| 	GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo)); | ||||
| 	GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)); | ||||
| 	GL_CALL(glUniformMatrix4fv(0, 1, GL_TRUE, *matrix)); | ||||
| 	GL_CALL(glUniform4f(1, (*color)[0], (*color)[1], (*color)[2], (*color)[3])); | ||||
| 	GL_CALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0)); | ||||
| } | ||||
| 
 | ||||
| static void wlr_gles3_render_ellipse(struct wlr_renderer_state *state, | ||||
| 		const float (*color)[4], const float (*matrix)[16]) { | ||||
| 	GL_CALL(glUseProgram(shaders.ellipse)); | ||||
| 	GL_CALL(glBindVertexArray(vao)); | ||||
| 	GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vbo)); | ||||
| 	GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo)); | ||||
| 	GL_CALL(glUniformMatrix4fv(0, 1, GL_TRUE, *matrix)); | ||||
| 	GL_CALL(glUniform4f(1, (*color)[0], (*color)[1], (*color)[2], (*color)[3])); | ||||
| 	GL_CALL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0)); | ||||
| } | ||||
| 
 | ||||
| static void wlr_gles3_destroy(struct wlr_renderer_state *state) { | ||||
| 	// no-op
 | ||||
| } | ||||
|  | @ -150,6 +183,8 @@ static struct wlr_renderer_impl wlr_renderer_impl = { | |||
| 	.end = wlr_gles3_end, | ||||
| 	.surface_init = wlr_gles3_surface_init, | ||||
| 	.render_with_matrix = wlr_gles3_render_surface, | ||||
| 	.render_quad = wlr_gles3_render_quad, | ||||
| 	.render_ellipse = wlr_gles3_render_ellipse, | ||||
| 	.destroy = wlr_gles3_destroy | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,28 +1,63 @@ | |||
| #include "render/gles3.h" | ||||
| #include <GLES3/gl3.h> | ||||
| 
 | ||||
| // Colored quads
 | ||||
| const GLchar quad_vertex_src[] = | ||||
| "uniform mat4 proj;" | ||||
| "uniform vec4 color;" | ||||
| "attribute vec2 pos;" | ||||
| "attribute vec2 texcoord;" | ||||
| "varying vec4 v_color;" | ||||
| "varying vec2 v_texcoord;" | ||||
| "void main() {" | ||||
| "  gl_Position = proj * vec4(pos, 0.0, 1.0);" | ||||
| "  v_color = color;" | ||||
| "  v_texcoord = texcoord;" | ||||
| "}"; | ||||
| 
 | ||||
| const GLchar quad_fragment_src[] = | ||||
| "precision mediump float;" | ||||
| "varying vec4 v_color;" | ||||
| "varying vec2 v_texcoord;" | ||||
| "void main() {" | ||||
| "  gl_FragColor = v_color;" | ||||
| "}"; | ||||
| 
 | ||||
| // Colored ellipses (TODO)
 | ||||
| 
 | ||||
| const GLchar ellipse_fragment_src[] = | ||||
| "precision mediump float;" | ||||
| "varying vec4 v_color;" | ||||
| "varying vec2 v_texcoord;" | ||||
| "void main() {" | ||||
| "  float l = length(v_texcoord - vec2(0.5, 0.5));" | ||||
| "  if (l > 0.5) discard;" | ||||
| "  gl_FragColor = v_color;" | ||||
| "}"; | ||||
| 
 | ||||
| // Textured quads
 | ||||
| const GLchar vertex_src[] = | ||||
| "uniform mat4 proj;\n" | ||||
| "attribute vec2 pos;\n" | ||||
| "attribute vec2 texcoord;\n" | ||||
| "varying vec2 v_texcoord;\n" | ||||
| "void main() {\n" | ||||
| "	gl_Position = proj * vec4(pos, 0.0, 1.0);\n" | ||||
| "	v_texcoord = texcoord;\n" | ||||
| "}\n"; | ||||
| "uniform mat4 proj;" | ||||
| "attribute vec2 pos;" | ||||
| "attribute vec2 texcoord;" | ||||
| "varying vec2 v_texcoord;" | ||||
| "void main() {" | ||||
| "	gl_Position = proj * vec4(pos, 0.0, 1.0);" | ||||
| "	v_texcoord = texcoord;" | ||||
| "}"; | ||||
| 
 | ||||
| const GLchar fragment_src_RGB[] = | ||||
| "precision mediump float;\n" | ||||
| "varying vec2 v_texcoord;\n" | ||||
| "uniform sampler2D tex;\n" | ||||
| "void main() {\n" | ||||
| "	gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0);\n" | ||||
| "}\n"; | ||||
| "precision mediump float;" | ||||
| "varying vec2 v_texcoord;" | ||||
| "uniform sampler2D tex;" | ||||
| "void main() {" | ||||
| "	gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0);" | ||||
| "}"; | ||||
| 
 | ||||
| const GLchar fragment_src_RGBA[] = | ||||
| "precision mediump float;\n" | ||||
| "varying vec2 v_texcoord;\n" | ||||
| "uniform sampler2D tex;\n" | ||||
| "void main() {\n" | ||||
| "	gl_FragColor = texture2D(tex, v_texcoord);\n" | ||||
| "}\n"; | ||||
| "precision mediump float;" | ||||
| "varying vec2 v_texcoord;" | ||||
| "uniform sampler2D tex;" | ||||
| "void main() {" | ||||
| "	gl_FragColor = texture2D(tex, v_texcoord);" | ||||
| "}"; | ||||
|  |  | |||
|  | @ -31,3 +31,13 @@ bool wlr_render_with_matrix(struct wlr_renderer *r, | |||
| 		struct wlr_surface *surface, const float (*matrix)[16]) { | ||||
| 	return r->impl->render_with_matrix(r->state, surface, matrix); | ||||
| } | ||||
| 
 | ||||
| void wlr_render_colored_quad(struct wlr_renderer *r, | ||||
| 		const float (*color)[4], const float (*matrix)[16]) { | ||||
| 	r->impl->render_quad(r->state, color, matrix); | ||||
| } | ||||
| 
 | ||||
| void wlr_render_colored_ellipse(struct wlr_renderer *r, | ||||
| 		const float (*color)[4], const float (*matrix)[16]) { | ||||
| 	r->impl->render_ellipse(r->state, color, matrix); | ||||
| } | ||||
|  |  | |||
|  | @ -28,8 +28,7 @@ struct logind_session { | |||
| }; | ||||
| 
 | ||||
| static int logind_take_device(struct wlr_session *restrict base, | ||||
| 	const char *restrict path) { | ||||
| 
 | ||||
| 		const char *restrict path) { | ||||
| 	struct logind_session *session = wl_container_of(base, session, base); | ||||
| 
 | ||||
| 	int ret; | ||||
|  |  | |||
|  | @ -5,6 +5,12 @@ include_directories( | |||
| 
 | ||||
| add_library(wlr-types | ||||
|     wlr_output.c | ||||
|     wlr_input_device.c | ||||
|     wlr_keyboard.c | ||||
|     wlr_pointer.c | ||||
|     wlr_touch.c | ||||
|     wlr_tablet_tool.c | ||||
|     wlr_tablet_pad.c | ||||
| ) | ||||
| 
 | ||||
| target_link_libraries(wlr-types | ||||
|  |  | |||
|  | @ -0,0 +1,43 @@ | |||
| #define _XOPEN_SOURCE 500 | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/types.h> | ||||
| #include <wlr/common/list.h> | ||||
| #include "common/log.h" | ||||
| #include "types.h" | ||||
| 
 | ||||
| struct wlr_input_device *wlr_input_device_create( | ||||
| 		enum wlr_input_device_type type, | ||||
| 		struct wlr_input_device_impl *impl, | ||||
| 		struct wlr_input_device_state *state, | ||||
| 		const char *name, int vendor, int product) { | ||||
| 	struct wlr_input_device *dev = calloc(1, sizeof(struct wlr_input_device)); | ||||
| 	dev->type = type; | ||||
| 	dev->impl = impl; | ||||
| 	dev->state = state; | ||||
| 	dev->name = strdup(name); | ||||
| 	dev->vendor = vendor; | ||||
| 	dev->product = product; | ||||
| 	return dev; | ||||
| } | ||||
| 
 | ||||
| void wlr_input_device_destroy(struct wlr_input_device *dev) { | ||||
| 	if (!dev) return; | ||||
| 	if (dev->impl && dev->impl->destroy && dev->state) { | ||||
| 		dev->impl->destroy(dev->state); | ||||
| 	} | ||||
| 	if (dev->_device) { | ||||
| 		switch (dev->type) { | ||||
| 		case WLR_INPUT_DEVICE_KEYBOARD: | ||||
| 			wlr_keyboard_destroy(dev->keyboard); | ||||
| 			break; | ||||
| 		default: | ||||
| 			wlr_log(L_DEBUG, "Warning: leaking memory %p %p %d", | ||||
| 					dev->_device, dev, dev->type); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	free(dev->name); | ||||
| 	free(dev); | ||||
| } | ||||
|  | @ -0,0 +1,29 @@ | |||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/types.h> | ||||
| #include <wlr/common/list.h> | ||||
| #include "types.h" | ||||
| 
 | ||||
| struct wlr_keyboard *wlr_keyboard_create(struct wlr_keyboard_impl *impl, | ||||
| 		struct wlr_keyboard_state *state) { | ||||
| 	struct wlr_keyboard *kb = calloc(1, sizeof(struct wlr_keyboard)); | ||||
| 	kb->impl = impl; | ||||
| 	kb->state = state; | ||||
| 	wl_signal_init(&kb->events.key); | ||||
| 	return kb; | ||||
| } | ||||
| 
 | ||||
| void wlr_keyboard_destroy(struct wlr_keyboard *kb) { | ||||
| 	if (!kb) return; | ||||
| 	if (kb->impl) { | ||||
| 		kb->impl->destroy(kb->state); | ||||
| 	} | ||||
| 	free(kb); | ||||
| } | ||||
| 
 | ||||
| void wlr_keyboard_led_update(struct wlr_keyboard *kb, uint32_t leds) { | ||||
| 	if (kb->impl) { | ||||
| 		kb->impl->led_update(kb->state, leds); | ||||
| 	} | ||||
| } | ||||
|  | @ -91,6 +91,15 @@ void wlr_output_transform(struct wlr_output *output, | |||
| 	output->impl->transform(output->state, transform); | ||||
| } | ||||
| 
 | ||||
| bool wlr_output_set_cursor(struct wlr_output *output, | ||||
| 		const uint8_t *buf, int32_t stride, uint32_t width, uint32_t height) { | ||||
| 	return output->impl->set_cursor(output->state, buf, stride, width, height); | ||||
| } | ||||
| 
 | ||||
| bool wlr_output_move_cursor(struct wlr_output *output, int x, int y) { | ||||
| 	return output->impl->move_cursor(output->state, x, y); | ||||
| } | ||||
| 
 | ||||
| void wlr_output_destroy(struct wlr_output *output) { | ||||
| 	if (!output) return; | ||||
| 	output->impl->destroy(output->state); | ||||
|  |  | |||
|  | @ -0,0 +1,26 @@ | |||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/types.h> | ||||
| #include <wlr/common/list.h> | ||||
| #include "types.h" | ||||
| 
 | ||||
| struct wlr_pointer *wlr_pointer_create(struct wlr_pointer_impl *impl, | ||||
| 		struct wlr_pointer_state *state) { | ||||
| 	struct wlr_pointer *pointer = calloc(1, sizeof(struct wlr_pointer)); | ||||
| 	pointer->impl = impl; | ||||
| 	pointer->state = state; | ||||
| 	wl_signal_init(&pointer->events.motion); | ||||
| 	wl_signal_init(&pointer->events.motion_absolute); | ||||
| 	wl_signal_init(&pointer->events.button); | ||||
| 	wl_signal_init(&pointer->events.axis); | ||||
| 	return pointer; | ||||
| } | ||||
| 
 | ||||
| void wlr_pointer_destroy(struct wlr_pointer *pointer) { | ||||
| 	if (!pointer) return; | ||||
| 	if (pointer->impl) { | ||||
| 		pointer->impl->destroy(pointer->state); | ||||
| 	} | ||||
| 	free(pointer); | ||||
| } | ||||
|  | @ -0,0 +1,25 @@ | |||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/types.h> | ||||
| #include <wlr/common/list.h> | ||||
| #include "types.h" | ||||
| 
 | ||||
| struct wlr_tablet_pad *wlr_tablet_pad_create(struct wlr_tablet_pad_impl *impl, | ||||
| 		struct wlr_tablet_pad_state *state) { | ||||
| 	struct wlr_tablet_pad *pad = calloc(1, sizeof(struct wlr_tablet_pad)); | ||||
| 	pad->impl = impl; | ||||
| 	pad->state = state; | ||||
| 	wl_signal_init(&pad->events.button); | ||||
| 	wl_signal_init(&pad->events.ring); | ||||
| 	wl_signal_init(&pad->events.strip); | ||||
| 	return pad; | ||||
| } | ||||
| 
 | ||||
| void wlr_tablet_pad_destroy(struct wlr_tablet_pad *pad) { | ||||
| 	if (!pad) return; | ||||
| 	if (pad->impl) { | ||||
| 		pad->impl->destroy(pad->state); | ||||
| 	} | ||||
| 	free(pad); | ||||
| } | ||||
|  | @ -0,0 +1,26 @@ | |||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/types.h> | ||||
| #include <wlr/common/list.h> | ||||
| #include "types.h" | ||||
| 
 | ||||
| struct wlr_tablet_tool *wlr_tablet_tool_create(struct wlr_tablet_tool_impl *impl, | ||||
| 		struct wlr_tablet_tool_state *state) { | ||||
| 	struct wlr_tablet_tool *tool = calloc(1, sizeof(struct wlr_tablet_tool)); | ||||
| 	tool->impl = impl; | ||||
| 	tool->state = state; | ||||
| 	wl_signal_init(&tool->events.axis); | ||||
| 	wl_signal_init(&tool->events.proximity); | ||||
| 	wl_signal_init(&tool->events.tip); | ||||
| 	wl_signal_init(&tool->events.button); | ||||
| 	return tool; | ||||
| } | ||||
| 
 | ||||
| void wlr_tablet_tool_destroy(struct wlr_tablet_tool *tool) { | ||||
| 	if (!tool) return; | ||||
| 	if (tool->impl) { | ||||
| 		tool->impl->destroy(tool->state); | ||||
| 	} | ||||
| 	free(tool); | ||||
| } | ||||
|  | @ -0,0 +1,26 @@ | |||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <wayland-server.h> | ||||
| #include <wlr/types.h> | ||||
| #include <wlr/common/list.h> | ||||
| #include "types.h" | ||||
| 
 | ||||
| struct wlr_touch *wlr_touch_create(struct wlr_touch_impl *impl, | ||||
| 		struct wlr_touch_state *state) { | ||||
| 	struct wlr_touch *touch = calloc(1, sizeof(struct wlr_touch)); | ||||
| 	touch->impl = impl; | ||||
| 	touch->state = state; | ||||
| 	wl_signal_init(&touch->events.down); | ||||
| 	wl_signal_init(&touch->events.up); | ||||
| 	wl_signal_init(&touch->events.motion); | ||||
| 	wl_signal_init(&touch->events.cancel); | ||||
| 	return touch; | ||||
| } | ||||
| 
 | ||||
| void wlr_touch_destroy(struct wlr_touch *touch) { | ||||
| 	if (!touch) return; | ||||
| 	if (touch->impl) { | ||||
| 		touch->impl->destroy(touch->state); | ||||
| 	} | ||||
| 	free(touch); | ||||
| } | ||||
		Loading…
	
		Reference in New Issue