Created
December 16, 2024 16:29
-
-
Save wilsonsilva/83852969bd0f33fe455ba29abb771c2c to your computer and use it in GitHub Desktop.
hello_wayland.c
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 <stdio.h> | |
#include <wayland-client.h> | |
int main(int argc, char *argv[]) { | |
struct wl_display *display = wl_display_connect(NULL); | |
if (!display) { | |
fprintf(stderr, "Failed to connect to Wayland display\n"); | |
return 1; | |
} | |
printf("Hello Wayland!\n"); | |
wl_display_disconnect(display); | |
return 0; | |
} |
Author
wilsonsilva
commented
Dec 16, 2024
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wayland-client.h>
#include <wayland-client-protocol.h>
#include <cairo/cairo.h>
#include <unistd.h>
#include "xdg-shell-client-protocol.h"
struct client_state {
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_surface *surface;
struct xdg_wm_base *xdg_wm_base;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
struct wl_shm *shm;
struct wl_buffer *buffer;
int width, height;
void *shm_data;
};
static void handle_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
{
xdg_wm_base_pong(xdg_wm_base, serial);
}
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
.ping = handle_ping,
};
static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial)
{
struct client_state *state = data;
xdg_surface_ack_configure(xdg_surface, serial);
}
static const struct xdg_surface_listener xdg_surface_listener = {
.configure = xdg_surface_configure,
};
static void registry_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
{
struct client_state *state = data;
if (strcmp(interface, wl_compositor_interface.name) == 0) {
state->compositor = wl_registry_bind(registry, name,
&wl_compositor_interface, 1);
} else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
state->xdg_wm_base = wl_registry_bind(registry, name,
&xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(state->xdg_wm_base,
&xdg_wm_base_listener, state);
} else if (strcmp(interface, wl_shm_interface.name) == 0) {
state->shm = wl_registry_bind(registry, name,
&wl_shm_interface, 1);
}
}
static void registry_global_remove(void *data, struct wl_registry *registry,
uint32_t name)
{
// Handle removal of global objects
}
static const struct wl_registry_listener registry_listener = {
.global = registry_global,
.global_remove = registry_global_remove,
};
static void create_window(struct client_state *state)
{
state->surface = wl_compositor_create_surface(state->compositor);
state->xdg_surface = xdg_wm_base_get_xdg_surface(state->xdg_wm_base,
state->surface);
xdg_surface_add_listener(state->xdg_surface, &xdg_surface_listener, state);
state->xdg_toplevel = xdg_surface_get_toplevel(state->xdg_surface);
xdg_toplevel_set_title(state->xdg_toplevel, "Hello Wayland!");
wl_surface_commit(state->surface);
}
static void draw_frame(struct client_state *state)
{
cairo_surface_t *cairo_surface;
cairo_t *cr;
// Create a Cairo surface
cairo_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
state->width, state->height);
cr = cairo_create(cairo_surface);
// Clear the surface
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_paint(cr);
// Draw text
cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 24.0);
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
cairo_move_to(cr, 20.0, 50.0);
cairo_show_text(cr, "Hello Wayland!");
// Clean up Cairo
cairo_destroy(cr);
cairo_surface_destroy(cairo_surface);
}
int main(int argc, char *argv[])
{
struct client_state state = { 0 };
state.width = 400;
state.height = 300;
state.display = wl_display_connect(NULL);
if (!state.display) {
fprintf(stderr, "Failed to connect to Wayland display\n");
return 1;
}
state.registry = wl_display_get_registry(state.display);
wl_registry_add_listener(state.registry, ®istry_listener, &state);
wl_display_roundtrip(state.display);
if (!state.compositor || !state.xdg_wm_base || !state.shm) {
fprintf(stderr, "Failed to bind required Wayland interfaces\n");
return 1;
}
create_window(&state);
draw_frame(&state);
while (wl_display_dispatch(state.display) != -1) {
// Main event loop
}
return 0;
}
CC = gcc
CFLAGS = $(shell pkg-config --cflags wayland-client cairo) -g
LDFLAGS = $(shell pkg-config --libs wayland-client cairo)
SOURCES = main.c xdg-shell-protocol.c
OBJECTS = $(SOURCES:.c=.o)
TARGET = hello_wayland
$(TARGET): $(OBJECTS)
$(CC) -o $@ $(OBJECTS) $(LDFLAGS)
%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)
clean:
rm -f $(TARGET) $(OBJECTS)
wayland-scanner private-code \
/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml \
xdg-shell-protocol.c
wayland-scanner client-header \
/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml \
xdg-shell-client-protocol.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wayland-client.h>
#include <wayland-client-protocol.h>
#include <cairo/cairo.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "xdg-shell-client-protocol.h"
struct client_state {
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_surface *surface;
struct xdg_wm_base *xdg_wm_base;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
struct wl_shm *shm;
struct wl_buffer *buffer;
int width, height;
void *shm_data;
bool configured;
};
static void handle_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
{
xdg_wm_base_pong(xdg_wm_base, serial);
}
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
.ping = handle_ping,
};
static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial)
{
struct client_state *state = data;
xdg_surface_ack_configure(xdg_surface, serial);
state->configured = true;
wl_surface_commit(state->surface);
}
static const struct xdg_surface_listener xdg_surface_listener = {
.configure = xdg_surface_configure,
};
static void xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
int32_t width, int32_t height,
struct wl_array *states)
{
// Handle window configuration
}
static void xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
{
// Handle window close request
}
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
.configure = xdg_toplevel_configure,
.close = xdg_toplevel_close,
};
static void registry_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
{
struct client_state *state = data;
if (strcmp(interface, wl_compositor_interface.name) == 0) {
state->compositor = wl_registry_bind(registry, name,
&wl_compositor_interface, 1);
} else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
state->xdg_wm_base = wl_registry_bind(registry, name,
&xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(state->xdg_wm_base,
&xdg_wm_base_listener, state);
} else if (strcmp(interface, wl_shm_interface.name) == 0) {
state->shm = wl_registry_bind(registry, name,
&wl_shm_interface, 1);
}
}
static void registry_global_remove(void *data, struct wl_registry *registry,
uint32_t name)
{
// Handle removal of global objects
}
static const struct wl_registry_listener registry_listener = {
.global = registry_global,
.global_remove = registry_global_remove,
};
static int create_shared_memory(size_t size)
{
int fd = memfd_create("buffer", 0);
if (fd < 0)
return -1;
if (ftruncate(fd, size) < 0) {
close(fd);
return -1;
}
return fd;
}
static struct wl_buffer *create_buffer(struct client_state *state)
{
int stride = state->width * 4;
int size = stride * state->height;
int fd = create_shared_memory(size);
if (fd < 0) {
return NULL;
}
state->shm_data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (state->shm_data == MAP_FAILED) {
close(fd);
return NULL;
}
struct wl_shm_pool *pool = wl_shm_create_pool(state->shm, fd, size);
struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0,
state->width, state->height,
stride, WL_SHM_FORMAT_ARGB8888);
wl_shm_pool_destroy(pool);
close(fd);
return buffer;
}
static void draw_frame(struct client_state *state)
{
if (!state->configured)
return;
if (state->buffer)
wl_buffer_destroy(state->buffer);
state->buffer = create_buffer(state);
if (!state->buffer)
return;
cairo_surface_t *surface = cairo_image_surface_create_for_data(state->shm_data,
CAIRO_FORMAT_ARGB32,
state->width,
state->height,
state->width * 4);
cairo_t *cr = cairo_create(surface);
// Clear the surface
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_paint(cr);
// Draw text
cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 24.0);
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
cairo_move_to(cr, 20.0, 50.0);
cairo_show_text(cr, "Hello Wayland!");
cairo_destroy(cr);
cairo_surface_destroy(surface);
wl_surface_attach(state->surface, state->buffer, 0, 0);
wl_surface_damage_buffer(state->surface, 0, 0, state->width, state->height);
wl_surface_commit(state->surface);
}
int main(int argc, char *argv[])
{
struct client_state state = { 0 };
state.width = 400;
state.height = 300;
state.configured = false;
state.display = wl_display_connect(NULL);
if (!state.display) {
fprintf(stderr, "Failed to connect to Wayland display\n");
return 1;
}
state.registry = wl_display_get_registry(state.display);
wl_registry_add_listener(state.registry, ®istry_listener, &state);
wl_display_roundtrip(state.display);
if (!state.compositor || !state.xdg_wm_base || !state.shm) {
fprintf(stderr, "Failed to bind required Wayland interfaces\n");
return 1;
}
state.surface = wl_compositor_create_surface(state.compositor);
state.xdg_surface = xdg_wm_base_get_xdg_surface(state.xdg_wm_base, state.surface);
xdg_surface_add_listener(state.xdg_surface, &xdg_surface_listener, &state);
state.xdg_toplevel = xdg_surface_get_toplevel(state.xdg_surface);
xdg_toplevel_add_listener(state.xdg_toplevel, &xdg_toplevel_listener, &state);
xdg_toplevel_set_title(state.xdg_toplevel, "Hello Wayland!");
wl_surface_commit(state.surface);
while (wl_display_dispatch(state.display) != -1) {
if (state.configured) {
draw_frame(&state);
state.configured = false;
}
}
return 0;
}
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <wayland-client.h>
#include <wayland-client-protocol.h>
#include <cairo/cairo.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/memfd.h>
#include "xdg-shell-client-protocol.h"
#ifndef MFD_CLOEXEC
#define MFD_CLOEXEC 1U
#endif
struct client_state {
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_surface *surface;
struct xdg_wm_base *xdg_wm_base;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
struct wl_shm *shm;
struct wl_buffer *buffer;
int width, height;
void *shm_data;
bool configured;
};
static void handle_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
{
xdg_wm_base_pong(xdg_wm_base, serial);
}
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
.ping = handle_ping,
};
static void xdg_surface_configure(void *data, struct xdg_surface *xdg_surface, uint32_t serial)
{
struct client_state *state = data;
xdg_surface_ack_configure(xdg_surface, serial);
state->configured = true;
wl_surface_commit(state->surface);
}
static const struct xdg_surface_listener xdg_surface_listener = {
.configure = xdg_surface_configure,
};
static void xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
int32_t width, int32_t height,
struct wl_array *states)
{
// Handle window configuration
}
static void xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
{
// Handle window close request
}
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
.configure = xdg_toplevel_configure,
.close = xdg_toplevel_close,
};
static void registry_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
{
struct client_state *state = data;
if (strcmp(interface, wl_compositor_interface.name) == 0) {
state->compositor = wl_registry_bind(registry, name,
&wl_compositor_interface, 1);
} else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
state->xdg_wm_base = wl_registry_bind(registry, name,
&xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(state->xdg_wm_base,
&xdg_wm_base_listener, state);
} else if (strcmp(interface, wl_shm_interface.name) == 0) {
state->shm = wl_registry_bind(registry, name,
&wl_shm_interface, 1);
}
}
static void registry_global_remove(void *data, struct wl_registry *registry,
uint32_t name)
{
// Handle removal of global objects
}
static const struct wl_registry_listener registry_listener = {
.global = registry_global,
.global_remove = registry_global_remove,
};
static int create_shared_memory(size_t size)
{
int fd;
#if defined(__linux__)
fd = memfd_create("buffer", MFD_CLOEXEC);
if (fd >= 0)
return fd;
#endif
char template[] = "/tmp/wayland-XXXXXX";
fd = mkstemp(template);
if (fd >= 0) {
unlink(template);
} else {
return -1;
}
if (ftruncate(fd, size) < 0) {
close(fd);
return -1;
}
return fd;
}
static struct wl_buffer *create_buffer(struct client_state *state)
{
int stride = state->width * 4;
int size = stride * state->height;
int fd = create_shared_memory(size);
if (fd < 0) {
return NULL;
}
state->shm_data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (state->shm_data == MAP_FAILED) {
close(fd);
return NULL;
}
struct wl_shm_pool *pool = wl_shm_create_pool(state->shm, fd, size);
struct wl_buffer *buffer = wl_shm_pool_create_buffer(pool, 0,
state->width, state->height,
stride, WL_SHM_FORMAT_ARGB8888);
wl_shm_pool_destroy(pool);
close(fd);
return buffer;
}
static void draw_frame(struct client_state *state)
{
if (!state->configured)
return;
if (state->buffer)
wl_buffer_destroy(state->buffer);
state->buffer = create_buffer(state);
if (!state->buffer)
return;
cairo_surface_t *surface = cairo_image_surface_create_for_data(state->shm_data,
CAIRO_FORMAT_ARGB32,
state->width,
state->height,
state->width * 4);
cairo_t *cr = cairo_create(surface);
// Clear the surface
cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
cairo_paint(cr);
// Draw text
cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 24.0);
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
cairo_move_to(cr, 20.0, 50.0);
cairo_show_text(cr, "Hello Wayland!");
cairo_destroy(cr);
cairo_surface_destroy(surface);
wl_surface_attach(state->surface, state->buffer, 0, 0);
wl_surface_damage_buffer(state->surface, 0, 0, state->width, state->height);
wl_surface_commit(state->surface);
}
int main(int argc, char *argv[])
{
struct client_state state = { 0 };
state.width = 400;
state.height = 300;
state.configured = false;
state.display = wl_display_connect(NULL);
if (!state.display) {
fprintf(stderr, "Failed to connect to Wayland display\n");
return 1;
}
state.registry = wl_display_get_registry(state.display);
wl_registry_add_listener(state.registry, ®istry_listener, &state);
wl_display_roundtrip(state.display);
if (!state.compositor || !state.xdg_wm_base || !state.shm) {
fprintf(stderr, "Failed to bind required Wayland interfaces\n");
return 1;
}
state.surface = wl_compositor_create_surface(state.compositor);
state.xdg_surface = xdg_wm_base_get_xdg_surface(state.xdg_wm_base, state.surface);
xdg_surface_add_listener(state.xdg_surface, &xdg_surface_listener, &state);
state.xdg_toplevel = xdg_surface_get_toplevel(state.xdg_surface);
xdg_toplevel_add_listener(state.xdg_toplevel, &xdg_toplevel_listener, &state);
xdg_toplevel_set_title(state.xdg_toplevel, "Hello Wayland!");
wl_surface_commit(state.surface);
while (wl_display_dispatch(state.display) != -1) {
if (state.configured) {
draw_frame(&state);
state.configured = false;
}
}
return 0;
}
CC = gcc
CFLAGS = $(shell pkg-config --cflags wayland-client cairo) -g
LDFLAGS = $(shell pkg-config --libs wayland-client cairo) -lrt
SOURCES = main.c xdg-shell-protocol.c
OBJECTS = $(SOURCES:.c=.o)
TARGET = hello_wayland
$(TARGET): $(OBJECTS)
$(CC) -o $@ $(OBJECTS) $(LDFLAGS)
%.o: %.c
$(CC) -c -o $@ $< $(CFLAGS)
clean:
rm -f $(TARGET) $(OBJECTS)
gcc -o hello_wayland main.c xdg-shell-protocol.c $(pkg-config --cflags --libs wayland-client cairo) -lrt
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment