Last active
December 30, 2024 07:43
-
-
Save zjm1060/70b3d4df423e34e8ab5b8151a0bb23b5 to your computer and use it in GitHub Desktop.
wayland wrapper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * display.c | |
| * | |
| * Created on: 2024年11月27日 | |
| * Author: zjm09 | |
| */ | |
| #define _GNU_SOURCE // for O_TMPFILE | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <fcntl.h> | |
| #include <time.h> | |
| #include <errno.h> | |
| #include <semaphore.h> | |
| #include <sys/mman.h> | |
| #include <sys/time.h> | |
| #include <sys/timerfd.h> | |
| #include <linux/input-event-codes.h> | |
| #include <wayland-client.h> | |
| #include <wayland-client-protocol.h> | |
| #include <xkbcommon/xkbcommon.h> | |
| #include <pthread.h> | |
| #include <poll.h> | |
| #include "xdg-shell-client-protocol.h" | |
| #include "display.h" | |
| enum mod_bit { | |
| MOD_SHIFT = 1<<0, | |
| MOD_CAPS = 1<<1, | |
| MOD_CTRL = 1<<2, | |
| MOD_ALT = 1<<3, | |
| MOD_MOD2 = 1<<4, | |
| MOD_MOD3 = 1<<5, | |
| MOD_LOGO = 1<<6, | |
| MOD_MOD5 = 1<<7, | |
| }; | |
| enum mask { | |
| MASK_SHIFT, | |
| MASK_CAPS, | |
| MASK_CTRL, | |
| MASK_ALT, | |
| MASK_MOD2, | |
| MASK_MOD3, | |
| MASK_LOGO, | |
| MASK_MOD5, | |
| MASK_LAST | |
| }; | |
| struct buffer { | |
| struct wl_buffer *buffer; | |
| void *shm_data; | |
| int busy; | |
| }; | |
| struct xkb { | |
| struct xkb_state *state; | |
| struct xkb_context *context; | |
| struct xkb_keymap *keymap; | |
| xkb_mod_mask_t masks[MASK_LAST]; | |
| }; | |
| struct pointer_event { | |
| uint32_t event_mask; | |
| wl_fixed_t surface_x, surface_y; | |
| uint32_t button, state; | |
| uint32_t time; | |
| uint32_t serial; | |
| struct { | |
| int valid; | |
| wl_fixed_t value; | |
| int32_t discrete; | |
| } axes[2]; | |
| uint32_t axis_source; | |
| }; | |
| struct touch_point { | |
| int valid; | |
| int32_t id; | |
| uint32_t event_mask; | |
| wl_fixed_t surface_x, surface_y; | |
| wl_fixed_t surface_start_x, surface_start_y; | |
| wl_fixed_t major, minor; | |
| wl_fixed_t orientation; | |
| }; | |
| struct touch_event { | |
| uint32_t time; | |
| uint32_t serial; | |
| uint16_t active; | |
| struct touch_point points[MAX_TOUCH_POINT]; | |
| }; | |
| struct input { | |
| int repeat_fd; | |
| struct wl_keyboard *keyboard; | |
| struct wl_pointer *pointer; | |
| struct wl_touch *touch; | |
| struct pointer_event pointer_event; | |
| struct touch_event touch_event; | |
| struct xkb xkb; | |
| xkb_keysym_t sym; | |
| uint32_t code; | |
| uint32_t modifiers; | |
| xkb_keysym_t repeat_sym; | |
| uint32_t repeat_key; | |
| int32_t repeat_rate_sec; | |
| int32_t repeat_rate_nsec; | |
| int32_t repeat_delay_sec; | |
| int32_t repeat_delay_nsec; | |
| struct { | |
| void (*key)(enum wl_keyboard_key_state state, xkb_keysym_t sym, uint32_t code); | |
| } notify; | |
| int key_pending; | |
| }; | |
| struct wayland_ctx { | |
| /*wayland vars*/ | |
| struct wl_display *wl_display; | |
| struct wl_registry *wl_registry; | |
| struct wl_shm *wl_shm; | |
| struct wl_compositor *wl_compositor; | |
| struct xdg_wm_base *xdg_wm_base; | |
| struct wl_seat* wl_seat; | |
| struct wl_surface *wl_surface; | |
| struct xdg_surface *xdg_surface; | |
| struct xdg_toplevel *xdg_toplevel; | |
| // struct wl_buffer *wl_buffer; | |
| struct buffer buffers[2]; | |
| struct input input; | |
| struct{ | |
| struct wl_callback *wl_callback; | |
| void (*user_callback)(void *, void *); | |
| void *data; | |
| }frame_callback; | |
| int width,height; | |
| // int32_t *data; | |
| void *user_ctx; | |
| }; | |
| const char *BM_XKB_MASK_NAMES[MASK_LAST] = { | |
| XKB_MOD_NAME_SHIFT, | |
| XKB_MOD_NAME_CAPS, | |
| XKB_MOD_NAME_CTRL, | |
| XKB_MOD_NAME_ALT, | |
| "Mod2", | |
| "Mod3", | |
| XKB_MOD_NAME_LOGO, | |
| "Mod5", | |
| }; | |
| const enum mod_bit BM_XKB_MODS[MASK_LAST] = { | |
| MOD_SHIFT, | |
| MOD_CAPS, | |
| MOD_CTRL, | |
| MOD_ALT, | |
| MOD_MOD2, | |
| MOD_MOD3, | |
| MOD_LOGO, | |
| MOD_MOD5 | |
| }; | |
| static void wayland_xdg_wm_base_ping (void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial) | |
| { | |
| xdg_wm_base_pong (xdg_wm_base, serial); | |
| } | |
| static struct xdg_wm_base_listener wayland_xdg_wm_base_listener = | |
| { | |
| .ping = wayland_xdg_wm_base_ping | |
| }; | |
| //WAYLAND KEYBOARD INTERFACE | |
| static void wayland_keyboard_keymap (void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) | |
| { | |
| struct input *input = data; | |
| if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { | |
| close(fd); | |
| return; | |
| } | |
| char *map_str; | |
| if ((map_str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) { | |
| close(fd); | |
| return; | |
| } | |
| if(input->xkb.context == NULL){ | |
| input->xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); | |
| } | |
| struct xkb_keymap *keymap = xkb_keymap_new_from_string(input->xkb.context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0); | |
| munmap(map_str, size); | |
| close(fd); | |
| if (!keymap) { | |
| fprintf(stderr, "failed to compile keymap\n"); | |
| return; | |
| } | |
| struct xkb_state *state; | |
| if (!(state = xkb_state_new(keymap))) { | |
| fprintf(stderr, "failed to create XKB state\n"); | |
| xkb_keymap_unref(keymap); | |
| return; | |
| } | |
| xkb_keymap_unref(input->xkb.keymap); | |
| xkb_state_unref(input->xkb.state); | |
| input->xkb.keymap = keymap; | |
| input->xkb.state = state; | |
| for (uint32_t i = 0; i < MASK_LAST; ++i) | |
| input->xkb.masks[i] = 1 << xkb_keymap_mod_get_index(input->xkb.keymap, BM_XKB_MASK_NAMES[i]); | |
| } | |
| static void wayland_keyboard_enter (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) | |
| { | |
| } | |
| static void wayland_keyboard_leave (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface) | |
| { | |
| struct input *input = data; | |
| struct itimerspec its; | |
| its.it_interval.tv_sec = 0; | |
| its.it_interval.tv_nsec = 0; | |
| its.it_value.tv_sec = 0; | |
| its.it_value.tv_nsec = 0; | |
| timerfd_settime(input->repeat_fd, 0, &its, NULL); | |
| } | |
| static void | |
| press(struct input *input, xkb_keysym_t sym, uint32_t key, enum wl_keyboard_key_state state) | |
| { | |
| if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { | |
| input->sym = sym; | |
| input->code = key + 8; | |
| input->key_pending = 1; | |
| } else if (!input->key_pending) { | |
| input->sym = XKB_KEY_NoSymbol; | |
| input->code = 0; | |
| } | |
| // printf("key: %d %d\n", key, state); | |
| if (input->notify.key) | |
| input->notify.key(state, sym, key); | |
| } | |
| static void wayland_keyboard_key (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state_w) | |
| { | |
| struct input *input = data; | |
| enum wl_keyboard_key_state state = state_w; | |
| if (!input->xkb.state) | |
| return; | |
| xkb_keysym_t sym = xkb_state_key_get_one_sym(input->xkb.state, key + 8); | |
| press(input, sym, key, state); | |
| if (state == WL_KEYBOARD_KEY_STATE_PRESSED && xkb_keymap_key_repeats(input->xkb.keymap, input->code)) { | |
| struct itimerspec its; | |
| input->repeat_sym = sym; | |
| input->repeat_key = key; | |
| its.it_interval.tv_sec = input->repeat_rate_sec; | |
| its.it_interval.tv_nsec = input->repeat_rate_nsec; | |
| its.it_value.tv_sec = input->repeat_delay_sec; | |
| its.it_value.tv_nsec = input->repeat_delay_nsec; | |
| timerfd_settime(input->repeat_fd, 0, &its, NULL); | |
| } else if (state == WL_KEYBOARD_KEY_STATE_RELEASED && key == input->repeat_key) { | |
| struct itimerspec its; | |
| its.it_interval.tv_sec = 0; | |
| its.it_interval.tv_nsec = 0; | |
| its.it_value.tv_sec = 0; | |
| its.it_value.tv_nsec = 0; | |
| timerfd_settime(input->repeat_fd, 0, &its, NULL); | |
| } | |
| } | |
| static void wayland_keyboard_modifiers (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) | |
| { | |
| struct input *input = data; | |
| if (!input->xkb.keymap) | |
| return; | |
| xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched, mods_locked, 0, 0, group); | |
| xkb_mod_mask_t mask = xkb_state_serialize_mods(input->xkb.state, XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED); | |
| input->modifiers = 0; | |
| for (uint32_t i = 0; i < MASK_LAST; ++i) { | |
| if (mask & input->xkb.masks[i]) | |
| input->modifiers |= BM_XKB_MODS[i]; | |
| } | |
| } | |
| static void keyboard_repeat(void *data) | |
| { | |
| struct input *input = data; | |
| uint64_t exp; | |
| if (read(input->repeat_fd, &exp, sizeof(exp)) != sizeof(exp)) | |
| return; | |
| if (input->notify.key) | |
| input->notify.key(WL_KEYBOARD_KEY_STATE_PRESSED, input->repeat_sym, input->repeat_key + 8); | |
| press(input, input->repeat_sym, input->repeat_key, WL_KEYBOARD_KEY_STATE_PRESSED); | |
| } | |
| static void set_repeat_info(struct input *input, int32_t rate, int32_t delay) | |
| { | |
| input->repeat_rate_sec = input->repeat_rate_nsec = 0; | |
| input->repeat_delay_sec = input->repeat_delay_nsec = 0; | |
| /* a rate of zero disables any repeating, regardless of the delay's value */ | |
| if (rate == 0) | |
| return; | |
| if (rate == 1) | |
| input->repeat_rate_sec = 1; | |
| else | |
| input->repeat_rate_nsec = 1000000000 / rate; | |
| input->repeat_delay_sec = delay / 1000; | |
| delay -= (input->repeat_delay_sec * 1000); | |
| input->repeat_delay_nsec = delay * 1000 * 1000; | |
| } | |
| static struct wl_keyboard_listener wayland_keyboard_listener = | |
| { | |
| .keymap = wayland_keyboard_keymap, | |
| .enter = wayland_keyboard_enter, | |
| .leave = wayland_keyboard_leave, | |
| .key = wayland_keyboard_key, | |
| .modifiers = wayland_keyboard_modifiers | |
| }; | |
| //WAYLAND POINTER INTERFACE (mouse/touchpad) | |
| static void wayland_pointer_enter (void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) | |
| { | |
| struct input *input = data; | |
| input->pointer_event.event_mask |= POINTER_EVENT_ENTER; | |
| input->pointer_event.serial = serial; | |
| input->pointer_event.surface_x = surface_x, | |
| input->pointer_event.surface_y = surface_y; | |
| } | |
| static void wayland_pointer_leave (void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) | |
| { | |
| struct input *input = data; | |
| input->pointer_event.serial = serial; | |
| input->pointer_event.event_mask |= POINTER_EVENT_LEAVE; | |
| } | |
| static void wayland_pointer_motion (void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) | |
| { | |
| struct input *input = data; | |
| input->pointer_event.event_mask |= POINTER_EVENT_MOTION; | |
| input->pointer_event.time = time; | |
| input->pointer_event.surface_x = surface_x, | |
| input->pointer_event.surface_y = surface_y; | |
| } | |
| static void wayland_pointer_button (void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) | |
| { | |
| struct input *input = data; | |
| input->pointer_event.event_mask |= POINTER_EVENT_BUTTON; | |
| input->pointer_event.time = time; | |
| input->pointer_event.serial = serial; | |
| input->pointer_event.button = button, | |
| input->pointer_event.state |= state; | |
| } | |
| static void wayland_pointer_axis (void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) | |
| { | |
| struct input *input = data; | |
| input->pointer_event.event_mask |= POINTER_EVENT_AXIS; | |
| input->pointer_event.time = time; | |
| input->pointer_event.axes[axis].valid = 1; | |
| input->pointer_event.axes[axis].value = value; | |
| } | |
| static void wayland_pointer_handle_axis_source(void *data, struct wl_pointer *wl_pointer, | |
| uint32_t axis_source) | |
| { | |
| (void)wl_pointer; | |
| struct input *input = data; | |
| input->pointer_event.event_mask |= POINTER_EVENT_AXIS_SOURCE; | |
| input->pointer_event.axis_source = axis_source; | |
| } | |
| static void wayland_pointer_handle_axis_stop(void *data, struct wl_pointer *wl_pointer, | |
| uint32_t time, uint32_t axis) | |
| { | |
| (void)wl_pointer; | |
| struct input *input = data; | |
| input->pointer_event.time = time; | |
| input->pointer_event.event_mask |= POINTER_EVENT_AXIS_STOP; | |
| input->pointer_event.axes[axis].valid = 1; | |
| } | |
| static void wayland_pointer_handle_axis_discrete(void *data, struct wl_pointer *wl_pointer, | |
| uint32_t axis, int32_t discrete) | |
| { | |
| (void)wl_pointer; | |
| struct input *input = data; | |
| input->pointer_event.event_mask |= POINTER_EVENT_AXIS_DISCRETE; | |
| input->pointer_event.axes[axis].valid = 1; | |
| input->pointer_event.axes[axis].discrete = discrete; | |
| } | |
| static void wayland_pointer_handle_frame(void *data, struct wl_pointer *wl_pointer) | |
| { | |
| (void) data, (void) wl_pointer; | |
| } | |
| static struct wl_pointer_listener wayland_pointer_listener = | |
| { | |
| .enter = wayland_pointer_enter, | |
| .leave = wayland_pointer_leave, | |
| .motion = wayland_pointer_motion, | |
| .button = wayland_pointer_button, | |
| .axis = wayland_pointer_axis, | |
| .frame = wayland_pointer_handle_frame, | |
| .axis_source = wayland_pointer_handle_axis_source, | |
| .axis_stop = wayland_pointer_handle_axis_stop, | |
| .axis_discrete = wayland_pointer_handle_axis_discrete, | |
| }; | |
| static struct touch_point *get_touch_point(struct input *input, int32_t id) | |
| { | |
| struct touch_event *touch = &input->touch_event; | |
| int invalid = -1; | |
| for (size_t i = 0; i < MAX_TOUCH_POINT; ++i) { | |
| if (touch->points[i].id == id) { | |
| invalid = i; | |
| } | |
| if (invalid == -1 && !touch->points[i].valid) { | |
| invalid = i; | |
| } | |
| } | |
| if (invalid == -1) { | |
| return NULL; | |
| } | |
| touch->points[invalid].id = id; | |
| return &touch->points[invalid]; | |
| } | |
| static void reset_all_start_position(struct input *input) | |
| { | |
| struct touch_event *event = &input->touch_event; | |
| for (size_t i = 0; i < MAX_TOUCH_POINT; ++i) { | |
| struct touch_point *point = &event->points[i]; | |
| if (!point->valid) | |
| continue; | |
| point->surface_start_x = point->surface_x; | |
| point->surface_start_y = point->surface_y; | |
| } | |
| } | |
| static void revalidate_all_released(struct input *input) | |
| { | |
| struct touch_event *event = &input->touch_event; | |
| for (size_t i = 0; i < MAX_TOUCH_POINT; ++i) { | |
| struct touch_point *point = &event->points[i]; | |
| if (!point->valid && point->event_mask & TOUCH_EVENT_DOWN) | |
| point->valid = 1; | |
| } | |
| } | |
| static void wayland_touch_handle_down(void *data, struct wl_touch *wl_touch, uint32_t serial, | |
| uint32_t time, struct wl_surface *surface, int32_t id, | |
| wl_fixed_t x, wl_fixed_t y) | |
| { | |
| (void) wl_touch, (void) surface; | |
| struct input *input = data; | |
| struct touch_point *point = get_touch_point(input, id); | |
| if (point == NULL) { | |
| return; | |
| } | |
| point->valid = 1; | |
| point->event_mask = TOUCH_EVENT_DOWN; | |
| point->surface_x = x, | |
| point->surface_y = y; | |
| input->touch_event.time = time; | |
| input->touch_event.serial = serial; | |
| input->touch_event.active += 1; | |
| revalidate_all_released(input); | |
| reset_all_start_position(input); | |
| } | |
| static void wayland_touch_handle_up(void *data, struct wl_touch *wl_touch, uint32_t serial, | |
| uint32_t time, int32_t id) | |
| { | |
| (void) time, (void) wl_touch, (void) serial; | |
| struct input *input = data; | |
| struct touch_point *point = get_touch_point(input, id); | |
| if (point == NULL) { | |
| return; | |
| } | |
| point->event_mask |= TOUCH_EVENT_UP; | |
| input->touch_event.active -= 1; | |
| reset_all_start_position(input); | |
| } | |
| static void wayland_touch_handle_motion(void *data, struct wl_touch *wl_touch, uint32_t time, | |
| int32_t id, wl_fixed_t x, wl_fixed_t y) | |
| { | |
| (void) wl_touch; | |
| struct input *input = data; | |
| struct touch_point *point = get_touch_point(input, id); | |
| if (point == NULL) { | |
| return; | |
| } | |
| point->event_mask |= TOUCH_EVENT_MOTION; | |
| point->surface_x = x, point->surface_y = y; | |
| input->touch_event.time = time; | |
| } | |
| static void wayland_touch_handle_cancel(void *data, struct wl_touch *wl_touch) | |
| { | |
| (void) wl_touch, (void) data; | |
| } | |
| static void wayland_touch_handle_shape(void *data, struct wl_touch *wl_touch, | |
| int32_t id, wl_fixed_t major, wl_fixed_t minor) | |
| { | |
| (void) wl_touch; | |
| struct input *input = data; | |
| struct touch_point *point = get_touch_point(input, id); | |
| if (point == NULL) { | |
| return; | |
| } | |
| point->event_mask |= TOUCH_EVENT_SHAPE; | |
| point->major = major, point->minor = minor; | |
| } | |
| static void wayland_touch_handle_orientation(void *data, struct wl_touch *wl_touch, | |
| int32_t id, wl_fixed_t orientation) | |
| { | |
| (void) wl_touch; | |
| struct input *input = data; | |
| struct touch_point *point = get_touch_point(input, id); | |
| if (point == NULL) { | |
| return; | |
| } | |
| point->event_mask |= TOUCH_EVENT_ORIENTATION; | |
| point->orientation = orientation; | |
| } | |
| static void wayland_touch_handle_frame(void *data, struct wl_touch *wl_touch) | |
| { | |
| (void) data, (void) wl_touch; | |
| } | |
| static const struct wl_touch_listener wl_touch_listener = { | |
| .down = wayland_touch_handle_down, | |
| .up = wayland_touch_handle_up, | |
| .motion = wayland_touch_handle_motion, | |
| .frame = wayland_touch_handle_frame, | |
| .cancel = wayland_touch_handle_cancel, | |
| .shape = wayland_touch_handle_shape, | |
| .orientation = wayland_touch_handle_orientation, | |
| }; | |
| static void seat_capabilities (void *data, struct wl_seat *seat, uint32_t capabilities) | |
| { | |
| struct wayland_ctx* ctx = (struct wayland_ctx*)data; | |
| struct input *input = &ctx->input; | |
| if (capabilities & WL_SEAT_CAPABILITY_POINTER) { | |
| input->pointer = wl_seat_get_pointer (seat); | |
| wl_pointer_add_listener (input->pointer, &wayland_pointer_listener, &ctx->input); | |
| } | |
| if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { | |
| input->keyboard = wl_seat_get_keyboard (seat); | |
| wl_keyboard_add_listener (input->keyboard, &wayland_keyboard_listener, &ctx->input); | |
| } | |
| if(capabilities & WL_SEAT_CAPABILITY_TOUCH) { | |
| input->touch = wl_seat_get_touch(seat); | |
| wl_touch_add_listener(input->touch, &wl_touch_listener, &ctx->input); | |
| } | |
| } | |
| static struct wl_seat_listener seat_listener = | |
| { | |
| .capabilities = seat_capabilities | |
| }; | |
| //WAYLAND OUTPUT INTERFACE | |
| static void wayland_output_cb_geometry(void *data, struct wl_output *wl_output, int x, int y, int w, int h, int subpixel, const char *make, const char *model, int transform) | |
| { | |
| printf("wl_output geometry x=%d, y=%d, w=%d, h=%d make=%s, model=%s \n", x,y,w,h, make, model); | |
| } | |
| static void wayland_output_cb_mode(void *data, struct wl_output *wl_output, unsigned int flags, int w, int h, int refresh) | |
| { | |
| } | |
| static void wayland_output_cb_done(void *data, struct wl_output *output) | |
| { | |
| } | |
| static void wayland_output_cb_scale(void *data, struct wl_output *output, int scale) | |
| { | |
| } | |
| static const struct wl_output_listener wayland_output_listener = | |
| { | |
| .geometry = wayland_output_cb_geometry, | |
| .mode = wayland_output_cb_mode, | |
| .done = wayland_output_cb_done, | |
| .scale = wayland_output_cb_scale | |
| }; | |
| static void registry_global(void *data, struct wl_registry *wl_registry, uint32_t name, const char *interface, uint32_t version) | |
| { | |
| struct wayland_ctx *ctx = (struct wayland_ctx *)data; | |
| if (!strcmp(interface,"wl_compositor")) { | |
| ctx->wl_compositor = wl_registry_bind (ctx->wl_registry, name, &wl_compositor_interface, 1); | |
| } else if (!strcmp(interface,"xdg_wm_base")) { | |
| ctx->xdg_wm_base = wl_registry_bind (ctx->wl_registry, name, &xdg_wm_base_interface, 1); | |
| xdg_wm_base_add_listener (ctx->xdg_wm_base, &wayland_xdg_wm_base_listener, ctx); | |
| } else if (!strcmp(interface,"wl_shm")) { | |
| ctx->wl_shm = wl_registry_bind (ctx->wl_registry, name, &wl_shm_interface, 1); | |
| } else if (!strcmp(interface,"wl_seat")) { | |
| ctx->wl_seat = wl_registry_bind (ctx->wl_registry, name, &wl_seat_interface, 1); | |
| wl_seat_add_listener (ctx->wl_seat, &seat_listener, ctx); | |
| } else if (!strcmp(interface, "wl_output")) { | |
| struct wl_output *wl_output = wl_registry_bind(ctx->wl_registry, name, &wl_output_interface, 1); | |
| wl_output_add_listener(wl_output, &wayland_output_listener, NULL); | |
| } | |
| } | |
| static void | |
| registry_global_remove(void *data, | |
| struct wl_registry *wl_registry, uint32_t name) | |
| { | |
| /* This space deliberately left blank */ | |
| } | |
| static struct wl_registry_listener wayland_registry_listener = | |
| { | |
| .global = registry_global, | |
| .global_remove = registry_global_remove, | |
| }; | |
| static void wayland_xdg_surface_configure (void *data, struct xdg_surface *xdg_surface, uint32_t serial) | |
| { | |
| xdg_surface_ack_configure(xdg_surface, serial); | |
| } | |
| static struct xdg_surface_listener wayland_xdg_surface_listener = | |
| { | |
| &wayland_xdg_surface_configure, | |
| }; | |
| static void wayland_xdg_toplevel_configure (void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states) | |
| { | |
| struct wayland_ctx *ctx = (struct wayland_ctx *)data; | |
| } | |
| static void wayland_xdg_toplevel_close (void *data, struct xdg_toplevel *xdg_toplevel) | |
| { | |
| struct wayland_ctx *ctx = (struct wayland_ctx *)data; | |
| } | |
| static struct xdg_toplevel_listener wayland_xdg_toplevel_listener = | |
| { | |
| &wayland_xdg_toplevel_configure, | |
| &wayland_xdg_toplevel_close | |
| }; | |
| static void frame_callback(void *data, struct wl_callback *callback, uint32_t time); | |
| static const struct wl_callback_listener frame_listener = { | |
| .done = frame_callback | |
| }; | |
| static int create_shm_buffer(void *data, struct buffer *buffer, | |
| int width, int height, uint32_t format); | |
| static struct buffer *display_next_buffer(void *data) | |
| { | |
| struct wayland_ctx *ctx = (struct wayland_ctx *)data; | |
| struct buffer *buffer; | |
| int ret = 0; | |
| if (!ctx->buffers[0].busy) | |
| buffer = &ctx->buffers[0]; | |
| else if (!ctx->buffers[1].busy) | |
| buffer = &ctx->buffers[1]; | |
| else | |
| return NULL; | |
| if (!buffer->buffer) { | |
| ret = create_shm_buffer(ctx, buffer, | |
| ctx->width, ctx->height, | |
| WL_SHM_FORMAT_XRGB8888); | |
| if (ret < 0) | |
| return NULL; | |
| /* paint the padding */ | |
| memset(buffer->shm_data, 0xff, | |
| ctx->width * ctx->height * 4); | |
| } | |
| return buffer; | |
| } | |
| static void frame_callback(void *data, struct wl_callback *callback, uint32_t time) | |
| { | |
| // (void)time; | |
| // struct window *window = data; | |
| struct wayland_ctx *ctx = (struct wayland_ctx *)data; | |
| struct buffer *buffer = display_next_buffer(data); | |
| if(!buffer){ | |
| fprintf(stderr, | |
| !callback ? "Failed to create the first buffer.\n" : | |
| "Both buffers busy at frame_callback(). Server bug?\n"); | |
| } | |
| if(ctx->frame_callback.user_callback) | |
| ctx->frame_callback.user_callback(buffer->shm_data, ctx->frame_callback.data); | |
| if(callback) | |
| wl_callback_destroy(callback); | |
| wl_surface_attach(ctx->wl_surface, buffer->buffer, 0, 0); | |
| wl_surface_damage(ctx->wl_surface, 0, 0, ctx->width, ctx->height); | |
| ctx->frame_callback.wl_callback = wl_surface_frame(ctx->wl_surface); | |
| wl_callback_add_listener(ctx->frame_callback.wl_callback, &frame_listener, ctx); | |
| wl_surface_commit(ctx->wl_surface); | |
| buffer->busy = 1; | |
| // printf("%s, %d\n", __func__, time); | |
| } | |
| static void buffer_release(void *data, struct wl_buffer *wl_buffer) | |
| { | |
| struct buffer *buffer = data; | |
| buffer->busy = 0; | |
| } | |
| static const struct wl_buffer_listener buffer_listener = | |
| { | |
| buffer_release | |
| }; | |
| static int create_shm_buffer(void *data, struct buffer *buffer, | |
| int width, int height, uint32_t format) | |
| { | |
| struct wl_shm_pool *pool; | |
| int fd, size, stride; | |
| struct wayland_ctx *ctx = (struct wayland_ctx *)data; | |
| void *pData; | |
| stride = width * 4; | |
| size = stride * height; | |
| // fd = os_create_anonymous_file(size); | |
| char *xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR"); | |
| fd = open (xdg_runtime_dir, O_TMPFILE|O_RDWR|O_EXCL, 0600); | |
| ftruncate (fd, size); | |
| if (fd < 0) { | |
| fprintf(stderr, "creating a buffer file for %d B failed: %s\n", | |
| size, strerror(errno)); | |
| return -1; | |
| } | |
| pData = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); | |
| if (pData == MAP_FAILED) { | |
| fprintf(stderr, "mmap failed: %s\n", strerror(errno)); | |
| close(fd); | |
| return -1; | |
| } | |
| pool = wl_shm_create_pool(ctx->wl_shm, fd, size); | |
| buffer->buffer = wl_shm_pool_create_buffer(pool, 0, | |
| width, height, | |
| stride, format); | |
| wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer); | |
| wl_shm_pool_destroy(pool); | |
| close(fd); | |
| buffer->shm_data = pData; | |
| return 0; | |
| } | |
| void display_schedule_render(void *data) | |
| { | |
| struct wayland_ctx *ctx = (struct wayland_ctx *)data; | |
| ctx->frame_callback.wl_callback = wl_surface_frame(ctx->wl_surface); | |
| wl_callback_add_listener(ctx->frame_callback.wl_callback, &frame_listener, ctx); | |
| } | |
| void *display_init(int width, int height) | |
| { | |
| struct wayland_ctx *ctx = (struct wayland_ctx *)calloc(1, sizeof(struct wayland_ctx)); | |
| if(ctx){ | |
| ctx->wl_display = wl_display_connect (NULL); | |
| if(ctx->wl_display == NULL){ | |
| printf("no wayland display found. do you have wayland composer running? \n"); | |
| goto err_dispaly; | |
| } | |
| ctx->input.repeat_fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); | |
| ctx->wl_registry = wl_display_get_registry (ctx->wl_display); | |
| wl_registry_add_listener (ctx->wl_registry, &wayland_registry_listener, ctx); | |
| wl_display_roundtrip (ctx->wl_display); | |
| ctx->wl_surface = wl_compositor_create_surface (ctx->wl_compositor); | |
| ctx->xdg_surface = xdg_wm_base_get_xdg_surface(ctx->xdg_wm_base, ctx->wl_surface); | |
| xdg_surface_add_listener (ctx->xdg_surface, &wayland_xdg_surface_listener, ctx); | |
| ctx->xdg_toplevel = xdg_surface_get_toplevel(ctx->xdg_surface); | |
| xdg_toplevel_add_listener (ctx->xdg_toplevel, &wayland_xdg_toplevel_listener, ctx); | |
| ctx->frame_callback.wl_callback = wl_surface_frame(ctx->wl_surface); | |
| wl_callback_add_listener(ctx->frame_callback.wl_callback, &frame_listener, ctx); | |
| // display_schedule_render(ctx); | |
| set_repeat_info(&ctx->input, 40, 400); | |
| wl_surface_commit (ctx->wl_surface); | |
| ctx->width = width; | |
| ctx->height = height; | |
| // size_t size = width * height * 4; | |
| // char *xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR"); | |
| // int fd = open (xdg_runtime_dir, O_TMPFILE|O_RDWR|O_EXCL, 0600); | |
| // ftruncate (fd, size); | |
| // ctx->data = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); | |
| // | |
| // struct wl_shm_pool *pool = wl_shm_create_pool (ctx->wl_shm, fd, size); | |
| // ctx->wl_buffer = wl_shm_pool_create_buffer (pool, 0, width, height, width*4, WL_SHM_FORMAT_XRGB8888); | |
| // wl_shm_pool_destroy (pool); | |
| // close (fd); | |
| // | |
| // wl_buffer_add_listener(ctx->wl_buffer , &buffer_listener, ctx); | |
| wl_display_roundtrip (ctx->wl_display); | |
| struct buffer *buffer = display_next_buffer(ctx); | |
| int32_t *data = buffer->shm_data; | |
| buffer->busy = 1; | |
| for (int y = 0; y < height; y++){ | |
| for (int x = 0; x < width; x++){ | |
| int pix_idx = y * width + x; | |
| data[pix_idx] = 0xFF000000; | |
| } | |
| } | |
| wl_surface_attach (ctx->wl_surface, buffer->buffer, 0, 0); | |
| wl_surface_commit (ctx->wl_surface); | |
| } | |
| return (void *)ctx; | |
| err_dispaly: | |
| free(ctx); | |
| return NULL; | |
| } | |
| static sem_t xSem; | |
| static void display_frame_done(void *data) | |
| { | |
| sem_t *xSem = data; | |
| sem_post(xSem); | |
| } | |
| static void *display_process(void *data) | |
| { | |
| struct wayland_ctx *ctx = (struct wayland_ctx *)data; | |
| int nfds = 0; | |
| while(1){ | |
| while (wl_display_prepare_read(ctx->wl_display) == -1) { | |
| wl_display_dispatch_pending(ctx->wl_display); | |
| } | |
| wl_display_flush(ctx->wl_display); | |
| struct pollfd pfd[2]; | |
| pfd[0].fd = wl_display_get_fd(ctx->wl_display); | |
| pfd[0].events = POLLIN; | |
| pfd[1].fd = ctx->input.repeat_fd; | |
| pfd[1].events = POLLIN; | |
| if (poll(pfd, 2, -1) > 0) { | |
| if(pfd[1].revents & POLLIN){ | |
| keyboard_repeat(&ctx->input); | |
| } | |
| if ((pfd[0].revents & POLLIN) == 0) { | |
| wl_display_cancel_read(ctx->wl_display); | |
| // break; | |
| }else{ | |
| wl_display_read_events(ctx->wl_display); | |
| wl_display_dispatch_pending(ctx->wl_display); | |
| } | |
| }else{ | |
| if (errno != EINTR) { | |
| wl_display_cancel_read(ctx->wl_display); | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| void display_start_async(void *data) | |
| { | |
| pthread_t t; | |
| sem_init(&xSem,0,0); | |
| sem_post(&xSem); | |
| pthread_create(&t, NULL, display_process, data); | |
| pthread_setname_np(t, "display"); | |
| } | |
| void display_set_fram_callback(void *data, void (*callback)(void *, void *), void *param) | |
| { | |
| struct wayland_ctx *ctx = (struct wayland_ctx *)data; | |
| ctx->frame_callback.user_callback = callback; | |
| ctx->frame_callback.data = param; | |
| } | |
| int32_t *display_get_frame_buffer(void *data) | |
| { | |
| struct buffer *buffer = display_next_buffer(data); | |
| return buffer->shm_data; | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * display.h | |
| * | |
| * Created on: 2024年11月27日 | |
| * Author: zjm09 | |
| */ | |
| #ifndef DISPLAY_H_ | |
| #define DISPLAY_H_ | |
| #ifdef __cplusplus | |
| extern "C" { | |
| #endif | |
| #define MAX_TOUCH_POINT (5) | |
| #define POINTER_EVENT_ENTER (1 << 1) | |
| #define POINTER_EVENT_LEAVE (1 << 2) | |
| #define POINTER_EVENT_MOTION (1 << 3) | |
| #define POINTER_EVENT_BUTTON (1 << 4) | |
| #define POINTER_EVENT_AXIS (1 << 5) | |
| #define POINTER_EVENT_AXIS_SOURCE (1 << 6) | |
| #define POINTER_EVENT_AXIS_STOP (1 << 7) | |
| #define POINTER_EVENT_AXIS_DISCRETE (1 << 8) | |
| #define TOUCH_EVENT_DOWN (1 << 0) | |
| #define TOUCH_EVENT_UP (1 << 1) | |
| #define TOUCH_EVENT_MOTION (1 << 2) | |
| #define TOUCH_EVENT_CANCEL (1 << 3) | |
| #define TOUCH_EVENT_SHAPE (1 << 4) | |
| #define TOUCH_EVENT_ORIENTATION (1 << 5) | |
| void *display_init(int width, int height); | |
| void display_set_fram_callback(void *data, void (*callback)(void *, void *), void *param); | |
| void display_start_async(void *data); | |
| int32_t *display_get_frame_buffer(void *data); | |
| #ifdef __cplusplus | |
| } | |
| #endif | |
| #endif /* DISPLAY_H_ */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment