Initial commit

master
itycodes 4 days ago
commit 9cd1f0e572

@ -0,0 +1,34 @@
.PHONY: all clean
CC = gcc
CLIBS = -lwayland-client -lcairo
CDEBUG = -g -fsanitize=address
CFLAGS = $(CLIBS) $(CDEBUG)
SRC = main.c
OUT = hello
PROTOCOL_NAMES = $(foreach proto, $(wildcard protocols/*), $(notdir $(basename $(proto))))
PROTOCOL_IMPLS = $(foreach proto, $(PROTOCOL_NAMES), $(addsuffix .prot.c,$(proto)))
PROTOCOL_HEADERS = $(foreach proto, $(PROTOCOL_NAMES), $(addsuffix .prot.h,$(proto)))
PROTOCOLS = $(PROTOCOL_IMPLS) $(PROTOCOL_HEADERS)
%.prot.c: protocols/%.xml
wayland-scanner private-code $< $@
%.prot.h: protocols/%.xml
wayland-scanner client-header $< $@
all: $(OUT)
clean:
rm -f $(OUT)
rm -f $(PROTOCOLS)
run: all
./$(OUT)
$(OUT): $(PROTOCOLS) $(SRC)
$(CC) $(PROTOCOL_IMPLS) $(SRC) $(CFLAGS) -o $(OUT)

@ -0,0 +1 @@
A simple Wayland hello world.

231
main.c

@ -0,0 +1,231 @@
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/mman.h>
#include <wayland-client-core.h>
#include <wayland-client-protocol.h>
#include <wayland-client.h>
#include <cairo/cairo.h>
#include "xdg-shell.prot.h"
// Not included in any standard header
// Thus, declaring manually.
// See memfd_create(2).
int memfd_create(const char* name, unsigned int flags);
#define ASSERT(cond, msg)\
if(!(cond)) {\
fprintf(stderr, "Runtime assertion %s at %s:%d failed: %s\n", #cond, __FILE__, __LINE__, msg);\
exit(-1);\
}
typedef struct state {
struct wl_shm* wl_shm;
struct wl_compositor* wl_compositor;
struct xdg_wm_base* xdg_wm_base;
struct wl_surface* surface;
struct wl_buffer* buffer;
uint32_t conf_x;
uint32_t conf_y;
uint32_t curr_x;
uint32_t curr_y;
cairo_surface_t* sfc;
cairo_t* ctx;
void* shm_data;
int shm_fd;
uint8_t should_close;
} state_t;
state_t state;
void noop_wl_registry(void* data, struct wl_registry* object, uint32_t serial) {}
void noop_xdg_toplevel(void* data, struct xdg_toplevel* object, uint32_t serial) {}
void handle_global(
void* data,
struct wl_registry* registry,
uint32_t name,
const char* interface,
uint32_t version) {
if(strcmp(interface, wl_shm_interface.name) == 0) {
state.wl_shm = wl_registry_bind(registry, name, &wl_shm_interface, version);
}
if(strcmp(interface, wl_compositor_interface.name) == 0) {
state.wl_compositor = wl_registry_bind(registry, name, &wl_compositor_interface, version);
}
if(strcmp(interface, xdg_wm_base_interface.name) == 0) {
state.xdg_wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, version);
}
}
void handle_global_remove(
void* data,
struct wl_registry* registry,
uint32_t name) {
// Who cares
}
const struct wl_registry_listener reg_callbacks = {
.global = handle_global,
.global_remove = noop_wl_registry,
};
void resize_buffer(int32_t, int32_t);
void draw();
static void xdg_surface_handle_configure(
void *data,
struct xdg_surface* xdg_surface,
uint32_t serial) {
xdg_surface_ack_configure(xdg_surface, serial);
static uint8_t configured;
if (configured) {
wl_surface_commit(state.surface);
} else {
configured = 1;
}
}
void xdg_toplevel_handle_configure(void *data,
struct xdg_toplevel *xdg_toplevel,
int32_t width,
int32_t height,
struct wl_array *states) {
if(width == 0 || height == 0) return;
state.conf_x = width;
state.conf_y = height;
printf("x: %d y: %d\n", width, height);
}
void xdg_toplevel_handle_configure_bounds(void *data,
struct xdg_toplevel *xdg_toplevel,
int32_t width,
int32_t height) {
}
void xdg_toplevel_handle_wm_capabilities(void *data,
struct xdg_toplevel *xdg_toplevel,
struct wl_array *capabilities) {
}
static void xdg_toplevel_handle_close(
void *data,
struct xdg_toplevel* xdg_surface) {
state.should_close = 1;
}
const struct xdg_surface_listener xdg_surface_listener = {
.configure = xdg_surface_handle_configure,
};
const struct xdg_toplevel_listener xdg_toplevel_listener = {
.configure = xdg_toplevel_handle_configure,
.close = xdg_toplevel_handle_close,
.configure_bounds = xdg_toplevel_handle_configure_bounds,
.wm_capabilities = xdg_toplevel_handle_wm_capabilities,
};
void resize_buffer(int32_t width, int32_t height) {
// Buffer params
int chan = 4;
int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
int size = height * stride;
state.curr_x = width;
state.curr_y = height;
// Create & map memfd
close(state.shm_fd);
state.shm_fd = memfd_create("wl_shm data", 0);
ASSERT(state.shm_fd != -1, "Failed to create memfd.");
ASSERT(ftruncate(state.shm_fd, size) != -1, "Failed to ftruncate the memfd.");
state.shm_data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, state.shm_fd, 0);
ASSERT(state.shm_data != MAP_FAILED, "Failed to mmap the memfd.");
// Make pool from memfd
struct wl_shm_pool* pool = wl_shm_create_pool(state.wl_shm, state.shm_fd, size);
ASSERT(pool != NULL, "Failed to create the wl_shm_pool.");
// Allocate full Wayland buffer
state.buffer = wl_shm_pool_create_buffer(pool, 0, width, height, chan * width, WL_SHM_FORMAT_ARGB8888);
ASSERT(state.buffer != NULL, "Failed to create the wl_buffer.");
wl_shm_pool_destroy(pool);
// Debugging data
memset(state.shm_data, 00, size);
cairo_destroy(state.ctx);
cairo_surface_destroy(state.sfc);
// Initialize cairo
state.sfc = cairo_image_surface_create_for_data(state.shm_data, CAIRO_FORMAT_ARGB32, width, height, stride);
ASSERT(cairo_surface_status(state.sfc) == CAIRO_STATUS_SUCCESS, "Failed to create the cairo surface.");
state.ctx = cairo_create(state.sfc);
}
void draw() {
// Paint background
cairo_set_source_rgba(state.ctx, 0.87, 0.68, 0.76, 1.0);
cairo_paint(state.ctx);
cairo_surface_flush(state.sfc);
// Commit buffer
wl_surface_damage_buffer(state.surface, 0, 0, INT32_MAX, INT32_MAX);
wl_surface_attach(state.surface, state.buffer, 0, 0);
wl_surface_commit(state.surface);
}
int main() {
// Connect
struct wl_display* dpy = wl_display_connect(NULL);
ASSERT(dpy != NULL, "Unable to connect to Wayland");
// Fetch globals
struct wl_registry* registry = wl_display_get_registry(dpy);
wl_registry_add_listener(registry, &reg_callbacks, NULL);
wl_display_roundtrip(dpy);
ASSERT(state.wl_shm != NULL, "core.wl_shm not supported.");
ASSERT(state.wl_compositor != NULL, "core.wl_compositor not supported.");
ASSERT(state.xdg_wm_base != NULL, "xdg_shell.xdg_wm_base not supported.");
resize_buffer(3440, 1440);
// Create Wayland surface
state.surface = wl_compositor_create_surface(state.wl_compositor);
ASSERT(state.surface != NULL, "Failed to create the wl_surface.");
struct xdg_surface* xdg_surface = xdg_wm_base_get_xdg_surface(state.xdg_wm_base, state.surface);
ASSERT(xdg_surface != NULL, "Failed to create the xdg_surface.");
struct xdg_toplevel* xdg_toplevel = xdg_surface_get_toplevel(xdg_surface);
ASSERT(xdg_toplevel != NULL, "Failed to create the xdg_toplevel.");
xdg_toplevel_set_title(xdg_toplevel, "Hello, world!");
xdg_surface_add_listener(xdg_surface, &xdg_surface_listener, NULL);
xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, NULL);
wl_surface_commit(state.surface);
wl_display_dispatch(dpy);
// Attach Wayland buffer to Wayland surface
wl_surface_attach(state.surface, state.buffer, 0, 0);
wl_surface_commit(state.surface);
wl_display_dispatch(dpy);
// Loop until should close
while(!state.should_close) {
wl_display_dispatch(dpy);
//printf("Refresh\n");
if(state.curr_x != state.conf_x || state.curr_y != state.conf_y) {
resize_buffer(state.conf_x, state.conf_y);
draw();
}
}
return 0;
}

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save