Last active
April 19, 2022 15:02
-
-
Save kraftwerk28/9851a1a0d0be3152de7623de235acedb to your computer and use it in GitHub Desktop.
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
#include <assert.h> | |
#include <fcntl.h> /* For O_* constants */ | |
#include <signal.h> | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <string.h> | |
#include <sys/mman.h> | |
#include <sys/stat.h> /* For mode constants */ | |
#include <unistd.h> | |
#include <wayland-client.h> | |
#include <wayland-server.h> | |
#include "xdg-shell-protocol.h" | |
static struct wl_display *display = NULL; | |
static struct wl_registry *registry = NULL; | |
static struct wl_compositor *compositor = NULL; | |
static struct xdg_wm_base *wm_base = NULL; | |
static struct wl_shm *wl_shm = NULL; | |
static struct wl_surface *surface = NULL; | |
static struct wl_callback *surface_callback = NULL; | |
static struct xdg_surface *xdg_surface = NULL; | |
static struct xdg_toplevel *xdg_toplevel = NULL; | |
static struct wl_event_loop *loop = NULL; | |
static bool running = true; | |
static void noop() { | |
} | |
int wl_event_loop_fd_func(int fd, uint32_t mask, void *data) { | |
if (mask & WL_EVENT_READABLE) { | |
wl_display_dispatch(display); | |
} | |
return 0; | |
} | |
int wl_event_loop_signal_func(int signal_number, void *data) { | |
fprintf(stderr, "\nCaught signal\n"); | |
running = false; | |
return 0; | |
} | |
int wl_event_loop_timer_func(void *data) { | |
fprintf(stderr, "Timed out\n"); | |
running = false; | |
return 0; | |
} | |
void wl_registry_on_global( | |
void *data, struct wl_registry *wl_registry, uint32_t name, | |
const char *interface, uint32_t version) { | |
if (strcmp(interface, wl_compositor_interface.name) == 0) { | |
compositor = | |
wl_registry_bind(registry, name, &wl_compositor_interface, version); | |
} else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { | |
wm_base = | |
wl_registry_bind(registry, name, &xdg_wm_base_interface, version); | |
} else if (strcmp(interface, wl_shm_interface.name) == 0) { | |
wl_shm = wl_registry_bind(registry, name, &wl_shm_interface, version); | |
} | |
} | |
static struct wl_registry_listener registry_l = {wl_registry_on_global, noop}; | |
void xdg_surface_on_configure( | |
void *data, struct xdg_surface *xdg_surface, uint32_t serial) { | |
xdg_surface_ack_configure(xdg_surface, serial); | |
wl_surface_attach(surface, (struct wl_buffer *)data, 0, 0); | |
wl_surface_damage(surface, 0, 0, 500, 500); | |
wl_surface_commit(surface); | |
} | |
static struct xdg_surface_listener xdg_surface_l = {xdg_surface_on_configure}; | |
static struct wl_callback_listener surface_callback_l; | |
void wl_callback_on_done( | |
void *data, struct wl_callback *wl_callback, uint32_t callback_data) { | |
wl_callback_destroy(surface_callback); | |
surface_callback = wl_surface_frame(surface); | |
wl_callback_add_listener(surface_callback, &surface_callback_l, data); | |
fprintf(stderr, "frame\n"); | |
wl_surface_attach(surface, (struct wl_buffer *)data, 0, 0); | |
wl_surface_damage(surface, 0, 0, 500, 500); | |
wl_surface_commit(surface); | |
} | |
void xdg_toplevel_on_close(void *data, struct xdg_toplevel *xdg_toplevel) { | |
running = false; | |
} | |
static struct xdg_toplevel_listener xdg_toplevel_l = { | |
.configure = noop, | |
.close = xdg_toplevel_on_close, | |
.configure_bounds = noop, | |
}; | |
static int create_shmem(const int pool_size, int *fd, uint8_t **raw) { | |
const char *shm_name = "/wl_shm-xdg-activation-test"; | |
shm_unlink(shm_name); | |
int shm_fd = shm_open(shm_name, O_RDWR | O_CREAT | O_EXCL, 0600); | |
if (shm_fd < 0) { | |
perror("shm_open"); | |
return 1; | |
} | |
if (ftruncate(shm_fd, pool_size) < 0) { | |
return 1; | |
} | |
*fd = shm_fd; | |
*raw = mmap(NULL, pool_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); | |
return 0; | |
} | |
void wl_buffer_on_release(void *data, struct wl_buffer *wl_buffer) { | |
wl_buffer_destroy(wl_buffer); | |
} | |
static struct wl_buffer_listener wl_buffer_l = {wl_buffer_on_release}; | |
int main(int argc, char *argv[]) { | |
display = wl_display_connect(NULL); | |
registry = wl_display_get_registry(display); | |
wl_registry_add_listener(registry, ®istry_l, NULL); | |
// Wait for globals to appear | |
wl_display_roundtrip(display); | |
int shmfd; | |
uint8_t *raw; | |
const int width = 500, height = 500, bpp = sizeof(uint32_t); | |
const int pool_size = width * height * bpp; | |
assert(create_shmem(pool_size, &shmfd, &raw) == 0); | |
for (int i = 0; i < height; i++) { | |
for (int j = 0; j < width; j++) { | |
((uint32_t *)raw)[i * width + j] = 0x00ff0000; | |
} | |
} | |
assert(munmap(raw, pool_size) == 0); | |
struct wl_shm_pool *pool = wl_shm_create_pool(wl_shm, shmfd, pool_size); | |
assert(close(shmfd) == 0); | |
struct wl_buffer *buf = wl_shm_pool_create_buffer( | |
pool, 0, width, height, width * bpp, WL_SHM_FORMAT_XRGB8888); | |
// wl_buffer_add_listener(buf, &wl_buffer_l, NULL); | |
wl_shm_pool_destroy(pool); | |
surface = wl_compositor_create_surface(compositor); | |
xdg_surface = xdg_wm_base_get_xdg_surface(wm_base, surface); | |
xdg_surface_add_listener(xdg_surface, &xdg_surface_l, buf); | |
xdg_toplevel = xdg_surface_get_toplevel(xdg_surface); | |
xdg_toplevel_set_title(xdg_toplevel, "Sample app"); | |
xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_l, buf); | |
surface_callback_l.done = wl_callback_on_done; | |
surface_callback = wl_surface_frame(surface); | |
wl_callback_add_listener(surface_callback, &surface_callback_l, buf); | |
wl_surface_commit(surface); | |
loop = wl_event_loop_create(); | |
struct wl_event_source *fd_src = wl_event_loop_add_fd( | |
loop, wl_display_get_fd(display), WL_EVENT_READABLE, | |
wl_event_loop_fd_func, NULL); | |
struct wl_event_source *sig_src = | |
wl_event_loop_add_signal(loop, SIGINT, wl_event_loop_signal_func, NULL); | |
struct wl_event_source *timer_src = | |
wl_event_loop_add_timer(loop, wl_event_loop_timer_func, NULL); | |
wl_event_source_timer_update(timer_src, 2000); | |
wl_display_roundtrip(display); | |
while (wl_event_loop_dispatch(loop, -1) >= 0 && running) { | |
wl_display_flush(display); | |
} | |
wl_event_source_remove(fd_src); | |
wl_event_source_remove(sig_src); | |
wl_event_source_remove(timer_src); | |
wl_event_loop_destroy(loop); | |
wl_display_disconnect(display); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment