Skip to content

Instantly share code, notes, and snippets.

@kraftwerk28
Created April 17, 2022 17:00
Show Gist options
  • Save kraftwerk28/ec9f8b3e3eb93d5ed028048525ec3e88 to your computer and use it in GitHub Desktop.
Save kraftwerk28/ec9f8b3e3eb93d5ed028048525ec3e88 to your computer and use it in GitHub Desktop.
xdg activation v1 demo
#include <fcntl.h>
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <wayland-client.h>
#include "xdg-activation-v1-protocol.h"
#include "xdg-shell-protocol.h"
struct app_state {
// Globals
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_shm *wl_shm;
struct xdg_wm_base *xdg_wm_base;
struct xdg_activation_v1 *xav1;
// Non-globals
struct wl_surface *main_surface;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
struct wl_buffer *wl_surface_buffer;
uint8_t *raw_surface_buffer;
bool running;
const char *app_id;
};
typedef struct app_state app_state_t;
void xdg_wm_base_on_ping(
void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial) {
xdg_wm_base_pong(xdg_wm_base, serial);
}
#define BIND(iface, state_ptr, ...) \
do { \
if (strcmp(interface, iface.name) == 0) { \
state_ptr = wl_registry_bind(wl_registry, name, &iface, version); \
__VA_ARGS__; \
return; \
} \
} while (0);
void wl_surface_on_enter(
void *data, struct wl_surface *wl_surface, struct wl_output *output) {
printf("Surface enter\n");
}
void wl_surface_on_leave(
void *data, struct wl_surface *wl_surface, struct wl_output *output) {
printf("Surface leave\n");
}
void wl_display_on_global(
void *data, struct wl_registry *wl_registry, uint32_t name,
const char *interface, uint32_t version) {
struct app_state *state = data;
BIND(wl_compositor_interface, state->compositor);
BIND(xdg_wm_base_interface, state->xdg_wm_base);
BIND(xdg_activation_v1_interface, state->xav1);
BIND(wl_shm_interface, state->wl_shm);
}
void wl_display_on_global_remove(
void *data, struct wl_registry *wl_registry, uint32_t name) {
// Noop
}
void wl_buffer_on_release(void *data, struct wl_buffer *wl_buffer) {
wl_buffer_destroy(wl_buffer);
}
void print_current_thread_name() {
// TODO
}
void xdg_surface_on_configure(
void *data, struct xdg_surface *xdg_surface, uint32_t serial) {
app_state_t *state = data;
printf("xdg surface configure\n");
xdg_surface_ack_configure(xdg_surface, serial);
wl_surface_attach(state->main_surface, state->wl_surface_buffer, 0, 0);
wl_surface_commit(state->main_surface);
}
void xdg_toplevel_on_close(void *data, struct xdg_toplevel *xdg_toplevel) {
((app_state_t *)data)->running = false;
}
void xdg_toplevel_on_configure(
void *data, struct xdg_toplevel *xdg_toplevel, int32_t width,
int32_t height, struct wl_array *states) {
}
void xdg_toplevel_on_configure_bounds(
void *data, struct xdg_toplevel *xdg_toplevel, int32_t width,
int32_t height) {
printf("xdg toplevel bounds: %dx%d px\n", width, height);
}
int create_sh_mem(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;
}
int parse_opts(int argc, char *argv[], app_state_t *state) {
int o;
while ((o = getopt(argc, argv, "a:")) >= 0) {
switch (o) {
case 'a':
state->app_id = optarg;
break;
default:
return 1;
}
}
return 0;
}
int main(int argc, char *argv[]) {
struct app_state state = {0};
if (parse_opts(argc, argv, &state) > 0) {
return 1;
}
state.running = true;
state.display = wl_display_connect(NULL);
state.registry = wl_display_get_registry(state.display);
static struct wl_registry_listener wl_registry_l = {
.global = wl_display_on_global,
.global_remove = wl_display_on_global_remove,
};
wl_registry_add_listener(state.registry, &wl_registry_l, &state);
wl_display_roundtrip(state.display);
static struct xdg_wm_base_listener xdg_wm_base_l = {
.ping = xdg_wm_base_on_ping,
};
xdg_wm_base_add_listener(state.xdg_wm_base, &xdg_wm_base_l, &state);
const int surface_width = 500, surface_height = 500;
const int stride = surface_width * 4;
const int pool_size = surface_width * stride * 2;
int shm_fd;
create_sh_mem(pool_size, &shm_fd, &state.raw_surface_buffer);
struct wl_shm_pool *wl_shm_pool =
wl_shm_create_pool(state.wl_shm, shm_fd, pool_size);
close(shm_fd);
state.wl_surface_buffer = wl_shm_pool_create_buffer(
wl_shm_pool, 0, surface_width, surface_height, stride,
WL_SHM_FORMAT_XRGB8888);
wl_shm_pool_destroy(wl_shm_pool);
state.main_surface = wl_compositor_create_surface(state.compositor);
static struct wl_surface_listener wl_surface_l = {
.enter = wl_surface_on_enter,
.leave = wl_surface_on_leave,
};
wl_surface_add_listener(state.main_surface, &wl_surface_l, &state);
state.xdg_surface =
xdg_wm_base_get_xdg_surface(state.xdg_wm_base, state.main_surface);
struct xdg_surface_listener xdg_surface_l = {
.configure = xdg_surface_on_configure,
};
xdg_surface_add_listener(state.xdg_surface, &xdg_surface_l, &state);
state.xdg_toplevel = xdg_surface_get_toplevel(state.xdg_surface);
if (state.app_id) {
xdg_toplevel_set_app_id(state.xdg_toplevel, state.app_id);
}
xdg_toplevel_set_title(state.xdg_toplevel, "xdg activation demo");
static struct xdg_toplevel_listener xdg_toplevel_l = {
.close = xdg_toplevel_on_close,
.configure = xdg_toplevel_on_configure,
.configure_bounds = xdg_toplevel_on_configure_bounds,
};
xdg_toplevel_add_listener(state.xdg_toplevel, &xdg_toplevel_l, &state);
wl_surface_commit(state.main_surface);
while (wl_display_dispatch(state.display) >= 0 && state.running) {
}
wl_buffer_destroy(state.wl_surface_buffer);
xdg_wm_base_destroy(state.xdg_wm_base);
wl_shm_destroy(state.wl_shm);
xdg_activation_v1_destroy(state.xav1);
wl_surface_destroy(state.main_surface);
xdg_surface_destroy(state.xdg_surface);
wl_registry_destroy(state.registry);
wl_display_disconnect(state.display);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment