#include #include #include #include #include #include #include #include #include #include #include #include "wayland.h" #include "drw.h" #include "xdg-shell-client-protocol.h" /* macro definitions */ #define match_then_bind(obj, inter, ver) \ if (strcmp(interface, inter.name) == 0) { \ obj = wl_registry_bind(registry, name, &inter, ver); #define end_match } #define or_match } else /* struct definitions */ typedef struct { unsigned width; unsigned height; struct { struct wl_surface *wl; struct xdg_surface *xdg; struct xdg_toplevel *toplevel; } surface; Canvas *canvas; Font *font; } Window; static void setup(); static void buffer_release(void *data, struct wl_buffer *buffer); static void draw_frame(); static void surface_configure(void *data, struct xdg_surface *surface, uint32_t serial); static void toplevel_configure(void *data, struct xdg_toplevel *toplevel, int32_t width, int32_t height, struct wl_array *clients); static void toplevel_close(void *data, struct xdg_toplevel *toplevel); static void wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial); static void registry_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version); static void registry_global_remove(void *data, struct wl_registry *registry, uint32_t name); static void seat_capabilities(void *dat, struct wl_seat *seat, uint32_t capabilities); static void keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size); static void keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t client); static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); static void keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay); static void handle_keyboard_event(); static void pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y); static void pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface); static void pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y); static void pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state); static void pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value); static void dummy() {} /* global variables */ static const struct wl_registry_listener registry_listener = { .global = registry_global, .global_remove = registry_global_remove, }; static const struct wl_buffer_listener buffer_listener = { .release = buffer_release, }; static const struct xdg_surface_listener surface_listener = { .configure = surface_configure, }; static const struct xdg_toplevel_listener toplevel_listener = { .configure = toplevel_configure, .close = toplevel_close, .configure_bounds = dummy, .wm_capabilities = dummy }; static const struct xdg_wm_base_listener wm_base_listener = { .ping = wm_base_ping, }; static const struct wl_seat_listener seat_listener = { .capabilities = seat_capabilities, .name = dummy }; static const struct wl_keyboard_listener keyboard_listener = { .keymap = keyboard_keymap, .key = keyboard_key, .modifiers = keyboard_modifiers, .repeat_info = keyboard_repeat_info, .enter = dummy, .leave = dummy, }; const struct wl_pointer_listener pointer_listener = { .enter = pointer_enter, .leave = pointer_leave, .motion = pointer_motion, .button = pointer_button, .axis = pointer_axis, .axis_discrete = dummy, .axis_source = dummy, .axis_stop = dummy, .axis_value120 = dummy, .frame = dummy, }; Client client = { 0 }; Window win = { 0 }; int running = 1; #include "config.h" /* function implementation */ void buffer_release(void *data, struct wl_buffer *buffer) { wl_buffer_destroy(buffer); } void draw_frame() { draw_rect(win.canvas, 0, 0, win.width, win.height, 0xff00ff00); } void surface_configure(void *data, struct xdg_surface *surface, uint32_t serial) { xdg_surface_ack_configure(surface, serial); fprintf(stderr, "configure\n"); if (win.canvas != 0) { free_drw(win.canvas); } win.canvas = create_drw(client.shm, win.width, win.height); draw_frame(); wl_surface_attach(win.surface.wl, win.canvas->buffer, 0, 0); wl_surface_damage_buffer(win.surface.wl, 0, 0, win.width, win.height); wl_surface_commit(win.surface.wl); } void toplevel_configure(void *data, struct xdg_toplevel *toplevel, int32_t width, int32_t height, struct wl_array *clients) { if (width == 0 || height == 0) { win.width = 800; win.height = 600; } else { win.width = width; win.height = height; } } void toplevel_close(void *data, struct xdg_toplevel *toplevel) { running = 0; } void wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial) { xdg_wm_base_pong(wm_base, serial); } void registry_global(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { match_then_bind(client.shm, wl_shm_interface, 1) or_match match_then_bind(client.compositor, wl_compositor_interface, 4) or_match match_then_bind(client.wm_base, xdg_wm_base_interface, 1) or_match match_then_bind(client.seat, wl_seat_interface, 7) wl_seat_add_listener(client.seat, &seat_listener, &client); end_match } void registry_global_remove(void *data, struct wl_registry *registry, uint32_t name) { /* TODO: Check if this is necessary */ } void seat_capabilities(void *data, struct wl_seat *seat, uint32_t capabilities) { int has_keyboard = capabilities & WL_SEAT_CAPABILITY_KEYBOARD; if (has_keyboard && client.kb.keyboard == 0) { client.kb.keyboard = wl_seat_get_keyboard(client.seat); wl_keyboard_add_listener(client.kb.keyboard, &keyboard_listener, &client); } else { wl_keyboard_release(client.kb.keyboard); client.kb.keyboard = 0; } } void keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size) { char *key_shm; struct xkb_keymap *keymap; struct xkb_state *state; if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) return; key_shm = mmap(0, size, PROT_READ, MAP_SHARED, fd, 0); if (key_shm == MAP_FAILED) return; keymap = xkb_keymap_new_from_string(client.kb.context, key_shm, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS ); munmap(key_shm, size); close(fd); state = xkb_state_new(keymap); xkb_keymap_unref(client.kb.keymap); xkb_state_unref(client.kb.state); client.kb.state = state; client.kb.keymap = keymap; } void keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) { struct itimerspec spec = { 0 }; uint32_t keycode = key + 8; client.kb.event.sym = xkb_state_key_get_one_sym(client.kb.state, keycode); client.kb.event.state = state; handle_keyboard_event(); if (client.kb.event.state == WL_KEYBOARD_KEY_STATE_PRESSED && client.kb.repeat.period >= 0) { spec.it_value.tv_sec = client.kb.repeat.delay / 1000; spec.it_value.tv_nsec = (client.kb.repeat.delay % 1000) * 1000000; timerfd_settime(client.kb.repeat.timer, 0, &spec, 0); } else if (client.kb.event.state == WL_KEYBOARD_KEY_STATE_RELEASED) { timerfd_settime(client.kb.repeat.timer, 0, &spec, 0); } } void keyboard_modifiers(void *data, struct wl_keyboard *keybaord, uint32_t serial, uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { xkb_state_update_mask(client.kb.state, depressed, latched, locked, 0, 0, group); client.kb.event.mods.alt = xkb_state_mod_name_is_active( client.kb.state, XKB_MOD_NAME_ALT, XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED ); client.kb.event.mods.ctrl = xkb_state_mod_name_is_active( client.kb.state, XKB_MOD_NAME_CTRL, XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED ); client.kb.event.mods.shift = xkb_state_mod_name_is_active( client.kb.state, XKB_MOD_NAME_SHIFT, XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED ); } void keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay) { client.kb.repeat.delay = delay; if (rate > 0) client.kb.repeat.period = 1000 / rate; else client.kb.repeat.period = -1; } void handle_keyboard_event() { char buf[8]; if (client.kb.event.state == WL_KEYBOARD_KEY_STATE_PRESSED) { if (xkb_keysym_to_utf8(client.kb.event.sym, buf, sizeof(buf))) { fprintf(stderr, "keypress: %s\n", buf); } } } void pointer_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y) { fprintf(stderr, "pointer enter: (%i, %i)\n", x, y); } void pointer_leave(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface) { fprintf(stderr, "pointer leave\n"); } void pointer_motion(void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y) { fprintf(stderr, "pointer motion: (%i, %i)\n", x, y); } void pointer_button(void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { fprintf(stderr, "pointer button: (b: %i, s: %i)\n", button, state); } void pointer_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { fprintf(stderr, "pointer axis: (a: %i, v: %i)\n", axis, value); } void setup() { client.kb.repeat.timer = timerfd_create(CLOCK_MONOTONIC, 0); client.kb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); client.display = wl_display_connect(0); client.registry = wl_display_get_registry(client.display); wl_registry_add_listener(client.registry, ®istry_listener, &client); wl_display_roundtrip(client.display); xdg_wm_base_add_listener(client.wm_base, &wm_base_listener, &client); wl_display_roundtrip(client.display); client.pointer.pointer = wl_seat_get_pointer(client.seat); wl_pointer_add_listener(client.pointer.pointer, &pointer_listener, &client); win.surface.wl = wl_compositor_create_surface(client.compositor); win.surface.xdg = xdg_wm_base_get_xdg_surface(client.wm_base, win.surface.wl); xdg_surface_add_listener(win.surface.xdg, &surface_listener, &win); win.surface.toplevel = xdg_surface_get_toplevel(win.surface.xdg); xdg_toplevel_add_listener(win.surface.toplevel, &toplevel_listener, &win); xdg_toplevel_set_title(win.surface.toplevel, "swt"); wl_surface_commit(win.surface.wl); } int main() { struct itimerspec spec = { 0 }; struct pollfd fds[2]; setup(); fds[0].fd = wl_display_get_fd(client.display); fds[0].events = POLLIN; fds[1].fd = client.kb.repeat.timer; fds[1].events = POLLIN; while (running) { if (wl_display_flush(client.display) < 0) { if (errno == EAGAIN) continue; break; } if (poll(fds, sizeof(fds) / sizeof(*fds), -1) < 0) { if (errno == EAGAIN) continue; break; } if (fds[0].revents & POLLIN) { if (wl_display_dispatch(client.display) < 0) { running = 0; } } if (fds[1].revents & POLLIN) { handle_keyboard_event(); spec.it_value.tv_sec = client.kb.repeat.period / 1000; spec.it_value.tv_nsec = (client.kb.repeat.period % 1000) / 1000000; timerfd_settime(client.kb.repeat.timer, 0, &spec, 0); } } wl_display_disconnect(client.display); return 0; }