Update Files
This commit is contained in:
		| @ -0,0 +1,52 @@ | ||||
| #include "wayland.h" | ||||
|  | ||||
| void kinc_wayland_display_init(void) { | ||||
| 	// This is a no-op because displays are already registered in kinc_wayland_init, | ||||
| 	// which should be called before this function is ever invoked | ||||
| } | ||||
|  | ||||
| int kinc_wayland_display_primary(void) { | ||||
| 	return 0; // TODO | ||||
| } | ||||
|  | ||||
| int kinc_wayland_count_displays(void) { | ||||
| 	return wl_ctx.num_displays; | ||||
| } | ||||
|  | ||||
| bool kinc_wayland_display_available(int display_index) { | ||||
| 	if (display_index >= MAXIMUM_DISPLAYS) { | ||||
| 		return false; | ||||
| 	} | ||||
| 	struct kinc_wl_display *display = &wl_ctx.displays[display_index]; | ||||
| 	return display->output != NULL; | ||||
| } | ||||
|  | ||||
| const char *kinc_wayland_display_name(int display_index) { | ||||
| 	if (display_index >= MAXIMUM_DISPLAYS) | ||||
| 		display_index = 0; | ||||
| 	struct kinc_wl_display *display = &wl_ctx.displays[display_index]; | ||||
| 	return display->name; | ||||
| } | ||||
|  | ||||
| kinc_display_mode_t kinc_wayland_display_current_mode(int display_index) { | ||||
| 	if (display_index >= MAXIMUM_DISPLAYS) | ||||
| 		display_index = 0; | ||||
| 	struct kinc_wl_display *display = &wl_ctx.displays[display_index]; | ||||
| 	return display->modes[display->current_mode]; | ||||
| } | ||||
|  | ||||
| int kinc_wayland_display_count_available_modes(int display_index) { | ||||
| 	if (display_index >= MAXIMUM_DISPLAYS) | ||||
| 		display_index = 0; | ||||
| 	struct kinc_wl_display *display = &wl_ctx.displays[display_index]; | ||||
| 	return display->num_modes; | ||||
| } | ||||
|  | ||||
| kinc_display_mode_t kinc_wayland_display_available_mode(int display_index, int mode_index) { | ||||
| 	if (display_index >= MAXIMUM_DISPLAYS) | ||||
| 		display_index = 0; | ||||
| 	struct kinc_wl_display *display = &wl_ctx.displays[display_index]; | ||||
| 	if (mode_index >= display->num_modes) | ||||
| 		mode_index = 0; | ||||
| 	return display->modes[mode_index]; | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -0,0 +1,54 @@ | ||||
| #ifndef KINC_WL_FN | ||||
| #define KINC_WL_FN(ret, name, args) | ||||
| #endif | ||||
|  | ||||
| KINC_WL_FUN(void, wl_event_queue_destroy, (struct wl_event_queue * queue)) | ||||
| #if KINC_WL_CHECK_VERSION(1, 20, 0) | ||||
| KINC_WL_FUN(struct wl_proxy *, wl_proxy_marshal_flags, | ||||
|             (struct wl_proxy * proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, ...)) | ||||
| KINC_WL_FUN(struct wl_proxy *, wl_proxy_marshal_array_flags, | ||||
|             (struct wl_proxy * proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, union wl_argument *args)) | ||||
| #endif | ||||
| KINC_WL_FUN(void, wl_proxy_marshal, (struct wl_proxy * p, uint32_t opcode, ...)) | ||||
| KINC_WL_FUN(void, wl_proxy_marshal_array, (struct wl_proxy * p, uint32_t opcode, union wl_argument *args)) | ||||
| KINC_WL_FUN(struct wl_proxy *, wl_proxy_create, (struct wl_proxy * factory, const struct wl_interface *interface)) | ||||
| KINC_WL_FUN(void *, wl_proxy_create_wrapper, (void *proxy)) | ||||
| KINC_WL_FUN(void, wl_proxy_wrapper_destroy, (void *proxy_wrapper)) | ||||
| KINC_WL_FUN(struct wl_proxy *, wl_proxy_marshal_constructor, (struct wl_proxy * proxy, uint32_t opcode, const struct wl_interface *interface, ...)) | ||||
| KINC_WL_FUN(struct wl_proxy *, wl_proxy_marshal_constructor_versioned, | ||||
|             (struct wl_proxy * proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, ...)) | ||||
| KINC_WL_FUN(struct wl_proxy *, wl_proxy_marshal_array_constructor, | ||||
|             (struct wl_proxy * proxy, uint32_t opcode, union wl_argument *args, const struct wl_interface *interface)) | ||||
| KINC_WL_FUN(struct wl_proxy *, wl_proxy_marshal_array_constructor_versioned, | ||||
|             (struct wl_proxy * proxy, uint32_t opcode, union wl_argument *args, const struct wl_interface *interface, uint32_t version)) | ||||
| KINC_WL_FUN(void, wl_proxy_destroy, (struct wl_proxy * proxy)) | ||||
| KINC_WL_FUN(int, wl_proxy_add_listener, (struct wl_proxy * proxy, void (**implementation)(void), void *data)) | ||||
| KINC_WL_FUN(const void *, wl_proxy_get_listener, (struct wl_proxy * proxy)) | ||||
| KINC_WL_FUN(int, wl_proxy_add_dispatcher, (struct wl_proxy * proxy, wl_dispatcher_func_t dispatcher_func, const void *dispatcher_data, void *data)) | ||||
| KINC_WL_FUN(void, wl_proxy_set_user_data, (struct wl_proxy * proxy, void *user_data)) | ||||
| KINC_WL_FUN(void *, wl_proxy_get_user_data, (struct wl_proxy * proxy)) | ||||
| KINC_WL_FUN(uint32_t, wl_proxy_get_version, (struct wl_proxy * proxy)) | ||||
| KINC_WL_FUN(uint32_t, wl_proxy_get_id, (struct wl_proxy * proxy)) | ||||
| KINC_WL_FUN(void, wl_proxy_set_tag, (struct wl_proxy * proxy, const char *const *tag)) | ||||
| KINC_WL_FUN(const char *const *, wl_proxy_get_tag, (struct wl_proxy * proxy)) | ||||
| KINC_WL_FUN(const char *, wl_proxy_get_class, (struct wl_proxy * proxy)) | ||||
| KINC_WL_FUN(void, wl_proxy_set_queue, (struct wl_proxy * proxy, struct wl_event_queue *queue)) | ||||
| KINC_WL_FUN(struct wl_display *, wl_display_connect, (const char *name)) | ||||
| KINC_WL_FUN(struct wl_display *, wl_display_connect_to_fd, (int fd)) | ||||
| KINC_WL_FUN(void, wl_display_disconnect, (struct wl_display * display)) | ||||
| KINC_WL_FUN(int, wl_display_get_fd, (struct wl_display * display)) | ||||
| KINC_WL_FUN(int, wl_display_dispatch, (struct wl_display * display)) | ||||
| KINC_WL_FUN(int, wl_display_dispatch_queue, (struct wl_display * display, struct wl_event_queue *queue)) | ||||
| KINC_WL_FUN(int, wl_display_dispatch_queue_pending, (struct wl_display * display, struct wl_event_queue *queue)) | ||||
| KINC_WL_FUN(int, wl_display_dispatch_pending, (struct wl_display * display)) | ||||
| KINC_WL_FUN(int, wl_display_get_error, (struct wl_display * display)) | ||||
| KINC_WL_FUN(uint32_t, wl_display_get_protocol_error, (struct wl_display * display, const struct wl_interface **interface, uint32_t *id)) | ||||
| KINC_WL_FUN(int, wl_display_flush, (struct wl_display * display)) | ||||
| KINC_WL_FUN(int, wl_display_roundtrip_queue, (struct wl_display * display, struct wl_event_queue *queue)) | ||||
| KINC_WL_FUN(int, wl_display_roundtrip, (struct wl_display * display)) | ||||
| KINC_WL_FUN(struct wl_event_queue *, wl_display_create_queue, (struct wl_display * display)) | ||||
| KINC_WL_FUN(int, wl_display_prepare_read_queue, (struct wl_display * display, struct wl_event_queue *queue)) | ||||
| KINC_WL_FUN(int, wl_display_prepare_read, (struct wl_display * display)) | ||||
| KINC_WL_FUN(void, wl_display_cancel_read, (struct wl_display * display)) | ||||
| KINC_WL_FUN(int, wl_display_read_events, (struct wl_display * display)) | ||||
| KINC_WL_FUN(void, wl_log_set_handler_client, (wl_log_func_t handler)) | ||||
| @ -0,0 +1,367 @@ | ||||
| #pragma once | ||||
| #ifndef _GNU_SOURCE | ||||
| #define _GNU_SOURCE // put this here too, to make clangd happy | ||||
| #endif | ||||
| #include <kinc/display.h> | ||||
| #include <kinc/log.h> | ||||
| #include <kinc/system.h> | ||||
|  | ||||
| #include <wayland-client-core.h> | ||||
| #include <wayland-cursor.h> | ||||
|  | ||||
| #define KINC_WL_CHECK_VERSION(x, y, z)                                                                                                                         \ | ||||
| 	(WAYLAND_VERSION_MAJOR > x || (WAYLAND_VERSION_MAJOR == x && WAYLAND_VERSION_MINOR > y) ||                                                                 \ | ||||
| 	 (WAYLAND_VERSION_MAJOR == x && WAYLAND_VERSION_MINOR == y && WAYLAND_VERSION_MICRO >= z)) | ||||
|  | ||||
| struct wl_surface; | ||||
|  | ||||
| struct kinc_wl_procs { | ||||
| #define KINC_WL_FUN(ret, name, args) ret(*_##name) args; | ||||
| #include "wayland-funs.h" | ||||
| #undef KINC_WL_FUN | ||||
|  | ||||
| 	struct wl_cursor_theme *(*_wl_cursor_theme_load)(const char *name, int size, struct wl_shm *shm); | ||||
| 	void (*_wl_cursor_theme_destroy)(struct wl_cursor_theme *theme); | ||||
| 	struct wl_cursor *(*_wl_cursor_theme_get_cursor)(struct wl_cursor_theme *theme, const char *name); | ||||
| 	struct wl_buffer *(*_wl_cursor_image_get_buffer)(struct wl_cursor_image *image); | ||||
| 	int (*_wl_cursor_frame)(struct wl_cursor *cursor, uint32_t time); | ||||
| 	int (*_wl_cursor_frame_and_duration)(struct wl_cursor *cursor, uint32_t time, uint32_t *duration); | ||||
|  | ||||
| #ifdef KINC_EGL | ||||
| 	struct wl_egl_window *(*_wl_egl_window_create)(struct wl_surface *surface, int width, int height); | ||||
| 	void (*_wl_egl_window_destroy)(struct wl_egl_window *egl_window); | ||||
| 	void (*_wl_egl_window_resize)(struct wl_egl_window *egl_window, int width, int height, int dx, int dy); | ||||
| 	void (*_wl_egl_window_get_attached_size)(struct wl_egl_window *egl_window, int *width, int *height); | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| #define wl_event_queue_destroy wl._wl_event_queue_destroy | ||||
| #define wl_proxy_marshal_flags wl._wl_proxy_marshal_flags | ||||
| #define wl_proxy_marshal_array_flags wl._wl_proxy_marshal_array_flags | ||||
| #define wl_proxy_marshal wl._wl_proxy_marshal | ||||
| #define wl_proxy_marshal_array wl._wl_proxy_marshal_array | ||||
| #define wl_proxy_create wl._wl_proxy_create | ||||
| #define wl_proxy_create_wrapper wl._wl_proxy_create_wrapper | ||||
| #define wl_proxy_wrapper_destroy wl._wl_proxy_wrapper_destroy | ||||
| #define wl_proxy_marshal_constructor wl._wl_proxy_marshal_constructor | ||||
| #define wl_proxy_marshal_constructor_versioned wl._wl_proxy_marshal_constructor_versioned | ||||
| #define wl_proxy_marshal_array_constructor wl._wl_proxy_marshal_array_constructor | ||||
| #define wl_proxy_marshal_array_constructor_versioned wl._wl_proxy_marshal_array_constructor_versioned | ||||
| #define wl_proxy_destroy wl._wl_proxy_destroy | ||||
| #define wl_proxy_add_listener wl._wl_proxy_add_listener | ||||
| #define wl_proxy_get_listener wl._wl_proxy_get_listener | ||||
| #define wl_proxy_add_dispatcher wl._wl_proxy_add_dispatcher | ||||
| #define wl_proxy_set_user_data wl._wl_proxy_set_user_data | ||||
| #define wl_proxy_get_user_data wl._wl_proxy_get_user_data | ||||
| #define wl_proxy_get_version wl._wl_proxy_get_version | ||||
| #define wl_proxy_get_id wl._wl_proxy_get_id | ||||
| #define wl_proxy_set_tag wl._wl_proxy_set_tag | ||||
| #define wl_proxy_get_tag wl._wl_proxy_get_tag | ||||
| #define wl_proxy_get_class wl._wl_proxy_get_class | ||||
| #define wl_proxy_set_queue wl._wl_proxy_set_queue | ||||
| #define wl_display_connect wl._wl_display_connect | ||||
| #define wl_display_connect_to_fd wl._wl_display_connect_to_fd | ||||
| #define wl_display_disconnect wl._wl_display_disconnect | ||||
| #define wl_display_get_fd wl._wl_display_get_fd | ||||
| #define wl_display_dispatch wl._wl_display_dispatch | ||||
| #define wl_display_dispatch_queue wl._wl_display_dispatch_queue | ||||
| #define wl_display_dispatch_queue_pending wl._wl_display_dispatch_queue_pending | ||||
| #define wl_display_dispatch_pending wl._wl_display_dispatch_pending | ||||
| #define wl_display_get_error wl._wl_display_get_error | ||||
| #define wl_display_get_protocol_error wl._wl_display_get_protocol_error | ||||
| #define wl_display_flush wl._wl_display_flush | ||||
| #define wl_display_roundtrip_queue wl._wl_display_roundtrip_queue | ||||
| #define wl_display_roundtrip wl._wl_display_roundtrip | ||||
| #define wl_display_create_queue wl._wl_display_create_queue | ||||
| #define wl_display_prepare_read_queue wl._wl_display_prepare_read_queue | ||||
| #define wl_display_prepare_read wl._wl_display_prepare_read | ||||
| #define wl_display_cancel_read wl._wl_display_cancel_read | ||||
| #define wl_display_read_events wl._wl_display_read_events | ||||
| #define wl_log_set_handler_client wl._wl_log_set_handler_client | ||||
|  | ||||
| #define wl_cursor_theme_load wl._wl_cursor_theme_load | ||||
| #define wl_cursor_theme_destroy wl._wl_cursor_theme_destroy | ||||
| #define wl_cursor_theme_get_cursor wl._wl_cursor_theme_get_cursor | ||||
| #define wl_cursor_image_get_buffer wl._wl_cursor_image_get_buffer | ||||
| #define wl_cursor_frame wl._wl_cursor_frame | ||||
| #define wl_cursor_frame_and_duration wl._wl_cursor_frame_and_duration | ||||
|  | ||||
| #define wl_egl_window_create wl._wl_egl_window_create | ||||
| #define wl_egl_window_destroy wl._wl_egl_window_destroy | ||||
| #define wl_egl_window_resize wl._wl_egl_window_resize | ||||
|  | ||||
| extern struct kinc_wl_procs wl; | ||||
|  | ||||
| #include <wayland-client-protocol.h> | ||||
| #include <wayland-generated/wayland-pointer-constraint.h> | ||||
| #include <wayland-generated/wayland-relative-pointer.h> | ||||
| #include <wayland-generated/wayland-tablet.h> | ||||
| #include <wayland-generated/wayland-viewporter.h> | ||||
| #include <wayland-generated/xdg-decoration.h> | ||||
| #include <wayland-generated/xdg-shell.h> | ||||
|  | ||||
| #include <xkbcommon/xkbcommon.h> | ||||
|  | ||||
| struct kinc_xkb_procs { | ||||
| 	struct xkb_context *(*xkb_context_new)(enum xkb_context_flags flags); | ||||
| 	void (*xkb_context_unref)(struct xkb_context *context); | ||||
| 	struct xkb_keymap *(*xkb_keymap_new_from_string)(struct xkb_context *context, const char *string, enum xkb_keymap_format format, | ||||
| 	                                                 enum xkb_keymap_compile_flags flags); | ||||
| 	struct xkb_state *(*xkb_state_new)(struct xkb_keymap *keymap); | ||||
| 	xkb_keysym_t (*xkb_state_key_get_one_sym)(struct xkb_state *state, xkb_keycode_t key); | ||||
| 	uint32_t (*xkb_state_key_get_utf32)(struct xkb_state *state, xkb_keycode_t key); | ||||
| 	xkb_mod_mask_t (*xkb_state_serialize_mods)(struct xkb_state *state, enum xkb_state_component components); | ||||
| 	enum xkb_state_component (*xkb_state_update_mask)(struct xkb_state *state, xkb_mod_mask_t depressed_mods, xkb_mod_mask_t latched_mods, | ||||
| 	                                                  xkb_mod_mask_t locked_mods, xkb_layout_index_t depressed_layout, xkb_layout_index_t latched_layout, | ||||
| 	                                                  xkb_layout_index_t locked_layout); | ||||
| 	int (*xkb_state_mod_name_is_active)(struct xkb_state *state, const char *name, enum xkb_state_component type); | ||||
| 	int (*xkb_keymap_key_repeats)(struct xkb_keymap *keymap, xkb_keycode_t key); | ||||
| }; | ||||
|  | ||||
| extern struct kinc_xkb_procs wl_xkb; | ||||
|  | ||||
| #include <kinc/display.h> | ||||
| #include <kinc/global.h> | ||||
| #include <kinc/system.h> | ||||
| #include <kinc/window.h> | ||||
|  | ||||
| #define MAXIMUM_WINDOWS 16 | ||||
| #define MAXIMUM_DISPLAYS 16 | ||||
| #define MAXIMUM_DISPLAY_MODES 16 | ||||
|  | ||||
| struct kinc_wl_decoration { | ||||
| 	struct wl_surface *surface; | ||||
| 	struct wl_subsurface *subsurface; | ||||
| 	struct wp_viewport *viewport; | ||||
| }; | ||||
|  | ||||
| enum kinc_wl_decoration_focus { | ||||
| 	KINC_WL_DECORATION_FOCUS_MAIN, | ||||
| 	KINC_WL_DECORATION_FOCUS_TOP, | ||||
| 	KINC_WL_DECORATION_FOCUS_LEFT, | ||||
| 	KINC_WL_DECORATION_FOCUS_RIGHT, | ||||
| 	KINC_WL_DECORATION_FOCUS_BOTTOM, | ||||
| 	KINC_WL_DECORATION_FOCUS_CLOSE_BUTTON, | ||||
| 	KINC_WL_DECORATION_FOCUS_MAX_BUTTON, | ||||
| 	KINC_WL_DECORATION_FOCUS_MIN_BUTTON | ||||
| }; | ||||
|  | ||||
| #define KINC_WL_DECORATION_WIDTH 10 | ||||
|  | ||||
| #define KINC_WL_DECORATION_TOP_X 0 | ||||
| #define KINC_WL_DECORATION_TOP_Y -(KINC_WL_DECORATION_TOP_HEIGHT) | ||||
| #define KINC_WL_DECORATION_TOP_WIDTH window->width | ||||
| #define KINC_WL_DECORATION_TOP_HEIGHT KINC_WL_DECORATION_WIDTH * 3 | ||||
|  | ||||
| #define KINC_WL_DECORATION_LEFT_X -10 | ||||
| #define KINC_WL_DECORATION_LEFT_Y -(KINC_WL_DECORATION_TOP_HEIGHT) | ||||
| #define KINC_WL_DECORATION_LEFT_WIDTH KINC_WL_DECORATION_WIDTH | ||||
| #define KINC_WL_DECORATION_LEFT_HEIGHT window->height + KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT | ||||
|  | ||||
| #define KINC_WL_DECORATION_RIGHT_X window->width | ||||
| #define KINC_WL_DECORATION_RIGHT_Y -(KINC_WL_DECORATION_TOP_HEIGHT) | ||||
| #define KINC_WL_DECORATION_RIGHT_WIDTH 10 | ||||
| #define KINC_WL_DECORATION_RIGHT_HEIGHT window->height + KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT | ||||
|  | ||||
| #define KINC_WL_DECORATION_BOTTOM_X 0 | ||||
| #define KINC_WL_DECORATION_BOTTOM_Y window->height | ||||
| #define KINC_WL_DECORATION_BOTTOM_WIDTH window->width | ||||
| #define KINC_WL_DECORATION_BOTTOM_HEIGHT KINC_WL_DECORATION_WIDTH | ||||
|  | ||||
| #define KINC_WL_DECORATION_CLOSE_X window->width - 10 | ||||
| #define KINC_WL_DECORATION_CLOSE_Y -20 | ||||
| #define KINC_WL_DECORATION_CLOSE_WIDTH 9 | ||||
| #define KINC_WL_DECORATION_CLOSE_HEIGHT 9 | ||||
|  | ||||
| struct kinc_wl_window { | ||||
| 	int display_index; | ||||
| 	int window_id; | ||||
| 	int width; | ||||
| 	int height; | ||||
| 	kinc_window_mode_t mode; | ||||
| 	struct wl_surface *surface; | ||||
| 	struct xdg_surface *xdg_surface; | ||||
| 	struct xdg_toplevel *toplevel; | ||||
| 	struct zxdg_toplevel_decoration_v1 *xdg_decoration; | ||||
|  | ||||
| 	bool configured; | ||||
|  | ||||
| 	struct { | ||||
| 		bool server_side; | ||||
| 		enum kinc_wl_decoration_focus focus; | ||||
| 		struct kinc_wl_decoration top; | ||||
| 		struct kinc_wl_decoration left; | ||||
| 		struct kinc_wl_decoration right; | ||||
| 		struct kinc_wl_decoration bottom; | ||||
|  | ||||
| 		struct kinc_wl_decoration close; | ||||
| 		struct kinc_wl_decoration max; | ||||
| 		struct kinc_wl_decoration min; | ||||
|  | ||||
| 		struct wl_buffer *dec_buffer; | ||||
| 		struct wl_buffer *close_buffer; | ||||
| 		struct wl_buffer *max_buffer; | ||||
| 		struct wl_buffer *min_buffer; | ||||
| 	} decorations; | ||||
| #ifdef KINC_EGL | ||||
| 	struct wl_egl_window *egl_window; | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| struct kinc_wl_display { | ||||
| 	struct wl_output *output; | ||||
| 	int index; | ||||
| 	int current_mode; | ||||
| 	int num_modes; | ||||
| 	char name[64]; | ||||
| 	int x; | ||||
| 	int y; | ||||
| 	int physical_width; | ||||
| 	int physical_height; | ||||
| 	int subpixel; | ||||
| 	enum wl_output_transform transform; | ||||
| 	enum wl_output_subpixel scale; | ||||
| 	kinc_display_mode_t modes[MAXIMUM_DISPLAY_MODES]; | ||||
| }; | ||||
|  | ||||
| struct kinc_wl_mouse { | ||||
| 	struct kinc_wl_seat *seat; | ||||
| 	int current_window; | ||||
| 	int x; | ||||
| 	int y; | ||||
| 	int enter_serial; | ||||
| 	const char *previous_cursor_name; | ||||
| 	struct wl_pointer *pointer; | ||||
| 	struct wl_surface *surface; | ||||
| 	bool hidden; | ||||
| 	bool locked; | ||||
| 	struct zwp_locked_pointer_v1 *lock; | ||||
| 	struct zwp_relative_pointer_v1 *relative; | ||||
| 	int serial; | ||||
| }; | ||||
|  | ||||
| struct kinc_wl_keyboard { | ||||
| 	struct kinc_wl_seat *seat; | ||||
| 	struct wl_keyboard *keyboard; | ||||
| 	struct xkb_keymap *keymap; | ||||
| 	struct xkb_state *state; | ||||
| 	bool ctrlDown; | ||||
|  | ||||
| 	int repeat_delay; | ||||
| 	int repeat_rate; | ||||
|  | ||||
| 	int timerfd; | ||||
|  | ||||
| 	int last_key_code; | ||||
| 	int last_character; | ||||
| }; | ||||
|  | ||||
| struct kinc_wl_data_offer { | ||||
| 	struct wl_data_offer *id; | ||||
|  | ||||
| 	int mime_type_count; | ||||
| 	char **mime_types; | ||||
|  | ||||
| 	uint32_t source_actions; | ||||
| 	uint32_t dnd_action; | ||||
|  | ||||
| 	void (*callback)(void *data, size_t data_size, void *user_data); | ||||
| 	void *user_data; | ||||
| 	int read_fd; | ||||
|  | ||||
| 	void *buffer; | ||||
| 	size_t buf_size; | ||||
| 	size_t buf_pos; | ||||
|  | ||||
| 	struct kinc_wl_data_offer *next; | ||||
| }; | ||||
|  | ||||
| struct kinc_wl_data_source { | ||||
| 	struct wl_data_source *source; | ||||
| 	const char **mime_types; | ||||
| 	int num_mime_types; | ||||
| 	void *data; | ||||
| 	size_t data_size; | ||||
| }; | ||||
|  | ||||
| struct kinc_wl_tablet_tool { | ||||
| 	struct zwp_tablet_tool_v2 *id; | ||||
| 	enum zwp_tablet_tool_v2_type type; | ||||
| 	uint32_t capabilities; | ||||
| 	uint64_t hardware_serial; | ||||
| 	uint64_t hardware_id_wacom; | ||||
|  | ||||
| 	int current_window; | ||||
| 	int x; | ||||
| 	int y; | ||||
| 	float current_pressure; | ||||
| 	float current_distance; | ||||
|  | ||||
| 	void (*press)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/); | ||||
| 	void (*move)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/); | ||||
| 	void (*release)(int /*window*/, int /*x*/, int /*y*/, float /*pressure*/); | ||||
|  | ||||
| 	struct kinc_wl_tablet_seat *seat; | ||||
| 	struct kinc_wl_tablet_tool *next; | ||||
| }; | ||||
|  | ||||
| struct kinc_wl_tablet { | ||||
| 	struct zwp_tablet_v2 *id; | ||||
| 	struct kinc_wl_tablet_seat *seat; | ||||
| 	struct kinc_wl_tablet *next; | ||||
| }; | ||||
|  | ||||
| struct kinc_wl_tablet_seat { | ||||
| 	struct zwp_tablet_seat_v2 *seat; | ||||
| 	struct kinc_wl_tablet *tablets; | ||||
| 	struct kinc_wl_tablet_tool *tablet_tools; | ||||
| }; | ||||
|  | ||||
| struct kinc_wl_seat { | ||||
| 	struct wl_seat *seat; | ||||
| 	struct kinc_wl_keyboard keyboard; | ||||
| 	struct kinc_wl_mouse mouse; | ||||
| 	struct wl_touch *touch; | ||||
| 	struct kinc_wl_tablet_seat tablet_seat; | ||||
| 	struct wl_data_device *data_device; | ||||
| 	struct kinc_wl_data_offer *current_selection_offer; | ||||
| 	struct kinc_wl_data_offer *current_dnd_offer; | ||||
| 	int current_serial; | ||||
| 	uint32_t capabilities; | ||||
| 	char name[64]; | ||||
| }; | ||||
|  | ||||
| struct wayland_context { | ||||
| 	struct xkb_context *xkb_context; | ||||
|  | ||||
| 	struct wl_display *display; | ||||
| 	struct wl_shm *shm; | ||||
| 	struct wl_registry *registry; | ||||
| 	struct wl_compositor *compositor; | ||||
| 	struct wl_subcompositor *subcompositor; | ||||
| 	struct wp_viewporter *viewporter; | ||||
| 	struct kinc_wl_seat seat; | ||||
| 	struct xdg_wm_base *xdg_wm_base; | ||||
| 	struct zxdg_decoration_manager_v1 *decoration_manager; | ||||
| 	struct wl_data_device_manager *data_device_manager; | ||||
| 	struct zwp_tablet_manager_v2 *tablet_manager; | ||||
| 	struct zwp_pointer_constraints_v1 *pointer_constraints; | ||||
| 	struct zwp_relative_pointer_manager_v1 *relative_pointer_manager; | ||||
| 	struct wl_cursor_theme *cursor_theme; | ||||
| 	int cursor_size; | ||||
| 	int num_windows; | ||||
| 	struct kinc_wl_window windows[MAXIMUM_WINDOWS]; | ||||
| 	int num_displays; | ||||
| 	struct kinc_wl_display displays[MAXIMUM_DISPLAYS]; | ||||
|  | ||||
| 	struct kinc_wl_data_offer *data_offer_queue; | ||||
| }; | ||||
|  | ||||
| extern struct wayland_context wl_ctx; | ||||
|  | ||||
| struct kinc_wl_data_source *kinc_wl_create_data_source(struct kinc_wl_seat *seat, const char *mime_types[], int num_mime_types, void *data, size_t data_size); | ||||
| void kinc_wl_data_source_destroy(struct kinc_wl_data_source *data_source); | ||||
| void kinc_wl_data_offer_accept(struct kinc_wl_data_offer *offer, void (*callback)(void *data, size_t data_size, void *user_data), void *user_data); | ||||
| void kinc_wl_destroy_data_offer(struct kinc_wl_data_offer *offer); | ||||
| void kinc_wayland_set_selection(struct kinc_wl_seat *seat, const char *text, int serial); | ||||
| void kinc_wayland_window_destroy(int window_index); | ||||
| @ -0,0 +1,469 @@ | ||||
| #include "wayland.h" | ||||
|  | ||||
| #include <kinc/image.h> | ||||
| #include <kinc/window.h> | ||||
|  | ||||
| // for all that shared memory stuff later on | ||||
| #include <errno.h> | ||||
| #include <fcntl.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <sys/mman.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #ifdef KINC_EGL | ||||
| #define EGL_NO_PLATFORM_SPECIFIC_TYPES | ||||
| #include <EGL/egl.h> | ||||
| #endif | ||||
|  | ||||
| static void xdg_surface_handle_configure(void *data, struct xdg_surface *surface, uint32_t serial) { | ||||
| 	xdg_surface_ack_configure(surface, serial); | ||||
| 	struct kinc_wl_window *window = data; | ||||
| 	window->configured = true; | ||||
| } | ||||
|  | ||||
| void kinc_internal_resize(int, int, int); | ||||
| void kinc_wayland_destroy_decoration(struct kinc_wl_decoration *); | ||||
| void kinc_wayland_resize_decoration(struct kinc_wl_decoration *, int x, int y, int width, int height); | ||||
| static void xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *toplevel, int32_t width, int32_t height, struct wl_array *states) { | ||||
| 	struct kinc_wl_window *window = data; | ||||
| 	if ((width <= 0 || height <= 0) || (width == window->width + (KINC_WL_DECORATION_WIDTH * 2) && | ||||
| 	                                    height == window->height + KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT)) { | ||||
| 		return; | ||||
| 	} | ||||
| 	if (window->decorations.server_side) { | ||||
| 		window->width = width; | ||||
| 		window->height = height; | ||||
| 	} | ||||
| 	else { | ||||
| 		window->width = width - (KINC_WL_DECORATION_WIDTH * 2); | ||||
| 		window->height = height - KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT; | ||||
| 	} | ||||
|  | ||||
| 	enum xdg_toplevel_state *state; | ||||
| 	wl_array_for_each(state, states) { | ||||
| 		switch (*state) { | ||||
| 		case XDG_TOPLEVEL_STATE_ACTIVATED: | ||||
| 			kinc_internal_foreground_callback(); | ||||
| 			break; | ||||
| 		case XDG_TOPLEVEL_STATE_RESIZING: | ||||
| 			break; | ||||
| 		case XDG_TOPLEVEL_STATE_MAXIMIZED: | ||||
| 			break; | ||||
| 		default: | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	kinc_internal_resize(window->window_id, window->width, window->height); | ||||
| 	kinc_internal_call_resize_callback(window->window_id, window->width, window->height); | ||||
| 	if (window->decorations.server_side) { | ||||
| 		xdg_surface_set_window_geometry(window->xdg_surface, 0, 0, window->width, window->height); | ||||
| 	} | ||||
| 	else { | ||||
| 		xdg_surface_set_window_geometry(window->xdg_surface, KINC_WL_DECORATION_LEFT_X, KINC_WL_DECORATION_TOP_Y, | ||||
| 		                                window->width + (KINC_WL_DECORATION_WIDTH * 2), | ||||
| 		                                window->height + KINC_WL_DECORATION_TOP_HEIGHT + KINC_WL_DECORATION_BOTTOM_HEIGHT); | ||||
| 	} | ||||
| #ifdef KINC_EGL | ||||
| 	wl_egl_window_resize(window->egl_window, window->width, window->height, 0, 0); | ||||
| #endif | ||||
|  | ||||
| 	kinc_wayland_resize_decoration(&window->decorations.top, KINC_WL_DECORATION_TOP_X, KINC_WL_DECORATION_TOP_Y, KINC_WL_DECORATION_TOP_WIDTH, | ||||
| 	                               KINC_WL_DECORATION_TOP_HEIGHT); | ||||
| 	kinc_wayland_resize_decoration(&window->decorations.left, KINC_WL_DECORATION_LEFT_X, KINC_WL_DECORATION_LEFT_Y, KINC_WL_DECORATION_LEFT_WIDTH, | ||||
| 	                               KINC_WL_DECORATION_LEFT_HEIGHT); | ||||
| 	kinc_wayland_resize_decoration(&window->decorations.right, KINC_WL_DECORATION_RIGHT_X, KINC_WL_DECORATION_RIGHT_Y, KINC_WL_DECORATION_RIGHT_WIDTH, | ||||
| 	                               KINC_WL_DECORATION_RIGHT_HEIGHT); | ||||
| 	kinc_wayland_resize_decoration(&window->decorations.bottom, KINC_WL_DECORATION_BOTTOM_X, KINC_WL_DECORATION_BOTTOM_Y, KINC_WL_DECORATION_BOTTOM_WIDTH, | ||||
| 	                               KINC_WL_DECORATION_BOTTOM_HEIGHT); | ||||
| 	kinc_wayland_resize_decoration(&window->decorations.close, KINC_WL_DECORATION_CLOSE_X, KINC_WL_DECORATION_CLOSE_Y, KINC_WL_DECORATION_CLOSE_WIDTH, | ||||
| 	                               KINC_WL_DECORATION_CLOSE_HEIGHT); | ||||
| } | ||||
|  | ||||
| void kinc_wayland_window_destroy(int window_index); | ||||
|  | ||||
| static void xdg_toplevel_handle_close(void *data, struct xdg_toplevel *xdg_toplevel) { | ||||
| 	struct kinc_wl_window *window = data; | ||||
| 	if (kinc_internal_call_close_callback(window->window_id)) { | ||||
| 		kinc_window_destroy(window->window_id); | ||||
| 		if (wl_ctx.num_windows <= 0) { | ||||
| 			// no windows left, stop | ||||
| 			kinc_stop(); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int create_shm_fd(off_t size) { | ||||
| 	int fd = -1; | ||||
| #if defined(__linux__) | ||||
| #if defined(__GLIBC__) && !__GLIBC_PREREQ(2, 27) | ||||
| #else | ||||
| 	// memfd_create is available since glibc 2.27 and musl 1.1.20 | ||||
| 	// the syscall is available since linux 3.17 | ||||
| 	// at the time of writing (04/02/2022) these requirements are fullfilled for the "LTS" versions of the following distributions | ||||
| 	// Ubuntu 18.04 | ||||
| 	// Debian Stretch | ||||
| 	// Alpine 3.12 | ||||
| 	// Fedora 34 | ||||
|  | ||||
| 	fd = memfd_create("kinc-wayland-shm", MFD_CLOEXEC | MFD_ALLOW_SEALING); | ||||
| 	if (fd >= 0) { | ||||
| 		fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL); | ||||
| 		int ret = posix_fallocate(fd, 0, size); | ||||
| 		if (ret != 0) { | ||||
| 			close(fd); | ||||
| 			errno = ret; | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
| 	else // fall back to a temp file | ||||
| #endif | ||||
| #endif | ||||
| 	{ | ||||
|  | ||||
| 		static const char template[] = "/kinc-shared-XXXXXX"; | ||||
|  | ||||
| 		const char *path = getenv("XDG_RUNTIME_DIR"); | ||||
| 		if (!path) { | ||||
| 			errno = ENOENT; | ||||
| 			return -1; | ||||
| 		} | ||||
|  | ||||
| 		char *name = malloc(strlen(path) + sizeof(template)); | ||||
| 		strcpy(name, path); | ||||
| 		strcat(name, template); | ||||
|  | ||||
| 		fd = mkostemp(name, O_CLOEXEC); | ||||
| 		if (fd >= 0) | ||||
| 			unlink(name); | ||||
|  | ||||
| 		free(name); | ||||
| 		if (fd < 0) | ||||
| 			return -1; | ||||
|  | ||||
| 		int ret = ftruncate(fd, size); | ||||
| 		if (ret != 0) { | ||||
| 			close(fd); | ||||
| 			errno = ret; | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return fd; | ||||
| } | ||||
|  | ||||
| struct wl_buffer *kinc_wayland_create_shm_buffer(const kinc_image_t *image) { | ||||
| 	int stride = image->width * 4; | ||||
| 	int length = image->width * image->height * 4; | ||||
|  | ||||
| 	const int fd = create_shm_fd(length); | ||||
| 	if (fd < 0) { | ||||
| 		kinc_log(KINC_LOG_LEVEL_ERROR, "Wayland: Creating a buffer file for %d B failed: %s", length, strerror(errno)); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	void *data = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | ||||
| 	if (data == MAP_FAILED) { | ||||
| 		kinc_log(KINC_LOG_LEVEL_ERROR, "Wayland: mmap failed: %s", strerror(errno)); | ||||
| 		close(fd); | ||||
| 		return NULL; | ||||
| 	} | ||||
|  | ||||
| 	struct wl_shm_pool *pool = wl_shm_create_pool(wl_ctx.shm, fd, length); | ||||
|  | ||||
| 	close(fd); | ||||
| 	memcpy(data, image->data, image->width * image->height * 4); | ||||
|  | ||||
| 	struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0, image->width, image->height, stride, WL_SHM_FORMAT_ARGB8888); | ||||
| 	munmap(data, length); | ||||
| 	wl_shm_pool_destroy(pool); | ||||
|  | ||||
| 	return buffer; | ||||
| } | ||||
|  | ||||
| static int grey_data[] = {0xFF333333}; | ||||
|  | ||||
| static int close_data[] = { | ||||
|     0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, | ||||
|     0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, | ||||
|     0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, | ||||
|     0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, | ||||
|     0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, | ||||
|     0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0x00000000, | ||||
|     0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, | ||||
| }; | ||||
|  | ||||
| // image format is argb32, but kinc does not have that, so let's lie to it | ||||
|  | ||||
| static kinc_image_t grey_image = { | ||||
|     1, 1, 0, KINC_IMAGE_FORMAT_RGBA32, 0, KINC_IMAGE_COMPRESSION_NONE, grey_data, sizeof(grey_data), | ||||
| }; | ||||
| static kinc_image_t close_image = { | ||||
|     9, 9, 0, KINC_IMAGE_FORMAT_RGBA32, 0, KINC_IMAGE_COMPRESSION_NONE, close_data, sizeof(close_data), | ||||
| }; | ||||
|  | ||||
| void kinc_wayland_create_decoration(struct kinc_wl_decoration *decoration, struct wl_surface *parent, struct wl_buffer *buffer, bool opaque, int x, int y, | ||||
|                                     int width, int height) { | ||||
| 	decoration->surface = wl_compositor_create_surface(wl_ctx.compositor); | ||||
| 	decoration->subsurface = wl_subcompositor_get_subsurface(wl_ctx.subcompositor, decoration->surface, parent); | ||||
| 	wl_subsurface_set_position(decoration->subsurface, x, y); | ||||
| 	decoration->viewport = wp_viewporter_get_viewport(wl_ctx.viewporter, decoration->surface); | ||||
| 	wp_viewport_set_destination(decoration->viewport, width, height); | ||||
| 	if (buffer) | ||||
| 		wl_surface_attach(decoration->surface, buffer, 0, 0); | ||||
|  | ||||
| 	if (opaque) { | ||||
| 		struct wl_region *region = wl_compositor_create_region(wl_ctx.compositor); | ||||
| 		wl_region_add(region, 0, 0, width, height); | ||||
| 		wl_surface_set_opaque_region(decoration->surface, region); | ||||
| 		wl_surface_commit(decoration->surface); | ||||
| 		wl_region_destroy(region); | ||||
| 	} | ||||
| 	else | ||||
| 		wl_surface_commit(decoration->surface); | ||||
| } | ||||
|  | ||||
| void kinc_wayland_resize_decoration(struct kinc_wl_decoration *decoration, int x, int y, int width, int height) { | ||||
| 	if (decoration->surface) { | ||||
| 		wl_subsurface_set_position(decoration->subsurface, x, y); | ||||
| 		wp_viewport_set_destination(decoration->viewport, width, height); | ||||
| 		wl_surface_commit(decoration->surface); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void kinc_wayland_destroy_decoration(struct kinc_wl_decoration *decoration) { | ||||
| 	if (decoration->subsurface) | ||||
| 		wl_subsurface_destroy(decoration->subsurface); | ||||
| 	if (decoration->surface) | ||||
| 		wl_surface_destroy(decoration->surface); | ||||
| 	if (decoration->viewport) | ||||
| 		wp_viewport_destroy(decoration->viewport); | ||||
| 	decoration->surface = NULL; | ||||
| 	decoration->subsurface = NULL; | ||||
| 	decoration->viewport = NULL; | ||||
| } | ||||
|  | ||||
| void kinc_wayland_destroy_decorations(struct kinc_wl_window *window) { | ||||
| 	kinc_wayland_destroy_decoration(&window->decorations.top); | ||||
| 	kinc_wayland_destroy_decoration(&window->decorations.left); | ||||
| 	kinc_wayland_destroy_decoration(&window->decorations.right); | ||||
| 	kinc_wayland_destroy_decoration(&window->decorations.bottom); | ||||
| 	kinc_wayland_destroy_decoration(&window->decorations.close); | ||||
| } | ||||
|  | ||||
| void kinc_wayland_create_decorations(struct kinc_wl_window *window) { | ||||
| 	if (!window->decorations.dec_buffer) { | ||||
| 		window->decorations.dec_buffer = kinc_wayland_create_shm_buffer(&grey_image); | ||||
| 		window->decorations.close_buffer = kinc_wayland_create_shm_buffer(&close_image); | ||||
| 		window->decorations.max_buffer = kinc_wayland_create_shm_buffer(&grey_image); | ||||
| 		window->decorations.min_buffer = kinc_wayland_create_shm_buffer(&grey_image); | ||||
| 	} | ||||
| 	kinc_wayland_create_decoration(&window->decorations.top, window->surface, window->decorations.dec_buffer, true, KINC_WL_DECORATION_TOP_X, | ||||
| 	                               KINC_WL_DECORATION_TOP_Y, KINC_WL_DECORATION_TOP_WIDTH, KINC_WL_DECORATION_TOP_HEIGHT); | ||||
| 	kinc_wayland_create_decoration(&window->decorations.left, window->surface, window->decorations.dec_buffer, true, KINC_WL_DECORATION_LEFT_X, | ||||
| 	                               KINC_WL_DECORATION_LEFT_Y, KINC_WL_DECORATION_LEFT_WIDTH, KINC_WL_DECORATION_LEFT_HEIGHT); | ||||
| 	kinc_wayland_create_decoration(&window->decorations.right, window->surface, window->decorations.dec_buffer, true, KINC_WL_DECORATION_RIGHT_X, | ||||
| 	                               KINC_WL_DECORATION_RIGHT_Y, KINC_WL_DECORATION_RIGHT_WIDTH, KINC_WL_DECORATION_RIGHT_HEIGHT); | ||||
| 	kinc_wayland_create_decoration(&window->decorations.bottom, window->surface, window->decorations.dec_buffer, true, KINC_WL_DECORATION_BOTTOM_X, | ||||
| 	                               KINC_WL_DECORATION_BOTTOM_Y, KINC_WL_DECORATION_BOTTOM_WIDTH, KINC_WL_DECORATION_BOTTOM_HEIGHT); | ||||
| 	kinc_wayland_create_decoration(&window->decorations.close, window->surface, window->decorations.close_buffer, true, KINC_WL_DECORATION_CLOSE_X, | ||||
| 	                               KINC_WL_DECORATION_CLOSE_Y, KINC_WL_DECORATION_CLOSE_WIDTH, KINC_WL_DECORATION_CLOSE_HEIGHT); | ||||
| } | ||||
|  | ||||
| void xdg_toplevel_decoration_configure(void *data, struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode) { | ||||
| 	struct kinc_wl_window *window = data; | ||||
|  | ||||
| 	if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE) { | ||||
| 		window->decorations.server_side = false; | ||||
| 		if (window->decorations.top.surface) { | ||||
| 			kinc_wayland_destroy_decorations(window); | ||||
| 		} | ||||
| 		if (window->mode == KINC_WINDOW_MODE_WINDOW) { | ||||
| 			kinc_wayland_create_decorations(window); | ||||
| 		} | ||||
| 	} | ||||
| 	else if (mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) { | ||||
| 		window->decorations.server_side = true; | ||||
| 		if (window->decorations.top.surface) { | ||||
| 			kinc_wayland_destroy_decorations(window); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void wl_surface_handle_enter(void *data, struct wl_surface *wl_surface, struct wl_output *output) { | ||||
| 	struct kinc_wl_window *window = wl_surface_get_user_data(wl_surface); | ||||
| 	struct kinc_wl_display *display = wl_output_get_user_data(output); | ||||
|  | ||||
| 	if (display && window) { | ||||
| 		window->display_index = display->index; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void wl_surface_handle_leave(void *data, struct wl_surface *wl_surface, struct wl_output *output) {} | ||||
|  | ||||
| static const struct wl_surface_listener wl_surface_listener = { | ||||
|     wl_surface_handle_enter, | ||||
|     wl_surface_handle_leave, | ||||
| }; | ||||
|  | ||||
| static const struct xdg_surface_listener xdg_surface_listener = { | ||||
|     xdg_surface_handle_configure, | ||||
| }; | ||||
|  | ||||
| static const struct xdg_toplevel_listener xdg_toplevel_listener = { | ||||
|     xdg_toplevel_handle_configure, | ||||
|     xdg_toplevel_handle_close, | ||||
| }; | ||||
|  | ||||
| static const struct zxdg_toplevel_decoration_v1_listener xdg_toplevel_decoration_listener = { | ||||
|     xdg_toplevel_decoration_configure, | ||||
| }; | ||||
|  | ||||
| void kinc_wayland_window_set_title(int window_index, const char *title); | ||||
| void kinc_wayland_window_change_mode(int window_index, kinc_window_mode_t mode); | ||||
|  | ||||
| int kinc_wayland_window_create(kinc_window_options_t *win, kinc_framebuffer_options_t *frame) { | ||||
| 	int window_index = -1; | ||||
| 	for (int i = 0; i < MAXIMUM_WINDOWS; i++) { | ||||
| 		if (wl_ctx.windows[i].surface == NULL) { | ||||
| 			window_index = i; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if (window_index == -1) { | ||||
| 		kinc_log(KINC_LOG_LEVEL_ERROR, "Too much windows (maximum is %i)", MAXIMUM_WINDOWS); | ||||
| 		exit(1); | ||||
| 	} | ||||
| 	struct kinc_wl_window *window = &wl_ctx.windows[window_index]; | ||||
| 	window->window_id = window_index; | ||||
| 	window->width = win->width; | ||||
| 	window->height = win->height; | ||||
| 	window->mode = KINC_WINDOW_MODE_WINDOW; | ||||
| 	window->surface = wl_compositor_create_surface(wl_ctx.compositor); | ||||
| 	wl_surface_set_user_data(window->surface, window); | ||||
| 	wl_surface_add_listener(window->surface, &wl_surface_listener, NULL); | ||||
|  | ||||
| 	window->xdg_surface = xdg_wm_base_get_xdg_surface(wl_ctx.xdg_wm_base, window->surface); | ||||
| 	xdg_surface_add_listener(window->xdg_surface, &xdg_surface_listener, window); | ||||
|  | ||||
| 	window->toplevel = xdg_surface_get_toplevel(window->xdg_surface); | ||||
| 	xdg_toplevel_add_listener(window->toplevel, &xdg_toplevel_listener, window); | ||||
|  | ||||
| 	kinc_wayland_window_set_title(window_index, win->title); | ||||
|  | ||||
| 	if (wl_ctx.decoration_manager) { | ||||
| 		window->xdg_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(wl_ctx.decoration_manager, window->toplevel); | ||||
| #ifdef KINC_WAYLAND_FORCE_CSD | ||||
| 		zxdg_toplevel_decoration_v1_set_mode(window->xdg_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); | ||||
| #endif | ||||
| 		zxdg_toplevel_decoration_v1_add_listener(window->xdg_decoration, &xdg_toplevel_decoration_listener, window); | ||||
| 	} | ||||
| 	else { | ||||
| 		window->decorations.server_side = false; | ||||
| 		kinc_wayland_create_decorations(window); | ||||
| 	} | ||||
|  | ||||
| #ifdef KINC_EGL | ||||
| 	window->egl_window = wl_egl_window_create(window->surface, window->width, window->height); | ||||
| #endif | ||||
| 	wl_surface_commit(window->surface); | ||||
| 	kinc_wayland_window_change_mode(window_index, win->mode); | ||||
| 	wl_ctx.num_windows++; | ||||
|  | ||||
| 	while (!window->configured) { | ||||
| 		wl_display_roundtrip(wl_ctx.display); | ||||
| 	} | ||||
|  | ||||
| 	return window_index; | ||||
| } | ||||
|  | ||||
| void kinc_wayland_window_destroy(int window_index) { | ||||
| 	struct kinc_wl_window *window = &wl_ctx.windows[window_index]; | ||||
| #ifdef KINC_EGL | ||||
| 	wl_egl_window_destroy(window->egl_window); | ||||
| #endif | ||||
| 	if (window->xdg_decoration) { | ||||
| 		zxdg_toplevel_decoration_v1_destroy(window->xdg_decoration); | ||||
| 	} | ||||
|  | ||||
| 	xdg_toplevel_destroy(window->toplevel); | ||||
| 	xdg_surface_destroy(window->xdg_surface); | ||||
| 	wl_surface_destroy(window->surface); | ||||
| 	*window = (struct kinc_wl_window){0}; | ||||
| 	wl_ctx.num_windows--; | ||||
| } | ||||
|  | ||||
| void kinc_wayland_window_set_title(int window_index, const char *title) { | ||||
| 	struct kinc_wl_window *window = &wl_ctx.windows[window_index]; | ||||
| 	xdg_toplevel_set_title(window->toplevel, title == NULL ? "" : title); | ||||
| } | ||||
|  | ||||
| int kinc_wayland_window_x(int window_index) { | ||||
| 	kinc_log(KINC_LOG_LEVEL_ERROR, "Wayland does not support getting the window position."); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int kinc_wayland_window_y(int window_index) { | ||||
| 	kinc_log(KINC_LOG_LEVEL_ERROR, "Wayland does not support getting the window position."); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void kinc_wayland_window_move(int window_index, int x, int y) { | ||||
| 	kinc_log(KINC_LOG_LEVEL_ERROR, "Wayland does not support setting the window position."); | ||||
| } | ||||
|  | ||||
| int kinc_wayland_window_width(int window_index) { | ||||
| 	return wl_ctx.windows[window_index].width; | ||||
| } | ||||
|  | ||||
| int kinc_wayland_window_height(int window_index) { | ||||
| 	return wl_ctx.windows[window_index].height; | ||||
| } | ||||
|  | ||||
| void kinc_wayland_window_resize(int window_index, int width, int height) { | ||||
| 	kinc_log(KINC_LOG_LEVEL_WARNING, "TODO: resizing windows"); | ||||
| } | ||||
|  | ||||
| void kinc_wayland_window_show(int window_index) { | ||||
| 	kinc_log(KINC_LOG_LEVEL_ERROR, "Wayland does not support unhiding windows."); | ||||
| } | ||||
|  | ||||
| void kinc_wayland_window_hide(int window_index) { | ||||
| 	kinc_log(KINC_LOG_LEVEL_ERROR, "Wayland does not support hiding windows."); | ||||
| } | ||||
|  | ||||
| kinc_window_mode_t kinc_wayland_window_get_mode(int window_index) { | ||||
| 	return wl_ctx.windows[window_index].mode; | ||||
| } | ||||
|  | ||||
| void kinc_wayland_window_change_mode(int window_index, kinc_window_mode_t mode) { | ||||
| 	struct kinc_wl_window *window = &wl_ctx.windows[window_index]; | ||||
| 	if (mode == window->mode) { | ||||
| 		return; | ||||
| 	} | ||||
| 	switch (mode) { | ||||
| 	case KINC_WINDOW_MODE_WINDOW: | ||||
| 		if (window->mode == KINC_WINDOW_MODE_FULLSCREEN || window->mode == KINC_WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { | ||||
| 			window->mode = KINC_WINDOW_MODE_WINDOW; | ||||
| 			xdg_toplevel_unset_fullscreen(window->toplevel); | ||||
| 		} | ||||
| 		break; | ||||
| 	case KINC_WINDOW_MODE_FULLSCREEN: | ||||
| 	case KINC_WINDOW_MODE_EXCLUSIVE_FULLSCREEN: | ||||
| 		if (window->mode == KINC_WINDOW_MODE_WINDOW) { | ||||
| 			window->mode = mode; | ||||
| 			struct kinc_wl_display *display = &wl_ctx.displays[window->display_index]; | ||||
| 			xdg_toplevel_set_fullscreen(window->toplevel, display->output); | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int kinc_wayland_window_display(int window_index) { | ||||
| 	struct kinc_wl_window *window = &wl_ctx.windows[window_index]; | ||||
| 	return window->display_index; | ||||
| } | ||||
|  | ||||
| int kinc_wayland_count_windows() { | ||||
| 	return wl_ctx.num_windows; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user