Skip to content

Instantly share code, notes, and snippets.

@kraftwerk28
Last active April 19, 2022 15:02
Show Gist options
  • Save kraftwerk28/9851a1a0d0be3152de7623de235acedb to your computer and use it in GitHub Desktop.
Save kraftwerk28/9851a1a0d0be3152de7623de235acedb to your computer and use it in GitHub Desktop.
#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, &registry_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