Created
April 17, 2022 17:00
-
-
Save kraftwerk28/ec9f8b3e3eb93d5ed028048525ec3e88 to your computer and use it in GitHub Desktop.
xdg activation v1 demo
This file contains 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 <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