Skip to content

Instantly share code, notes, and snippets.

@zjm1060
Last active December 30, 2024 07:43
Show Gist options
  • Select an option

  • Save zjm1060/70b3d4df423e34e8ab5b8151a0bb23b5 to your computer and use it in GitHub Desktop.

Select an option

Save zjm1060/70b3d4df423e34e8ab5b8151a0bb23b5 to your computer and use it in GitHub Desktop.
wayland wrapper
/*
* 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;
}
/*
* 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