From 0e75d157f52db45a1af350574bd95cccbd09fa57 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 9 Jun 2017 17:31:21 -0400 Subject: Initialize keyboards from libinput --- example/simple.c | 87 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 28 deletions(-) (limited to 'example/simple.c') diff --git a/example/simple.c b/example/simple.c index 21f333c7..3206b3fa 100644 --- a/example/simple.c +++ b/example/simple.c @@ -13,16 +13,29 @@ struct state { float color[3]; int dec; struct timespec last_frame; + + struct wl_list keyboards; + struct wl_listener input_add; + struct wl_listener input_remove; + struct wl_listener output_add; struct wl_listener output_remove; struct wl_list outputs; }; struct output_state { - struct wl_list link; - struct wlr_output *output; struct state *state; + struct wlr_output *output; struct wl_listener frame; + struct wl_list link; +}; + +struct keyboard_state { + struct state *state; + struct wlr_input_device *device; + struct wl_listener key; + struct wl_listener mods; + struct wl_list link; }; void output_frame(struct wl_listener *listener, void *data) { @@ -84,28 +97,44 @@ void output_remove(struct wl_listener *listener, void *data) { wl_list_remove(&ostate->frame.link); } -int timer_done(void *data) { - *(bool *)data = true; - return 1; +void input_add(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct state *state = wl_container_of(listener, state, input_add); + if (device->type != WLR_INPUT_DEVICE_KEYBOARD) { + return; + } + fprintf(stderr, "Keyboard '%s' (%d:%d) added\n", device->name, + device->vendor, device->product); + struct keyboard_state *kbstate = calloc(sizeof(struct keyboard_state), 1); + kbstate->device = device; + wl_list_init(&kbstate->key.link); + wl_list_init(&kbstate->mods.link); + wl_list_insert(&state->keyboards, &kbstate->link); } -int enable_outputs(void *data) { - struct state *state = data; - struct output_state *ostate; - wl_list_for_each(ostate, &state->outputs, link) { - struct wlr_output *output = ostate->output; - wlr_output_enable(output, true); +void input_remove(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct state *state = wl_container_of(listener, state, input_add); + if (device->type != WLR_INPUT_DEVICE_KEYBOARD) { + return; } - return 1; + struct keyboard_state *kbstate = NULL, *_kbstate; + wl_list_for_each(_kbstate, &state->keyboards, link) { + if (_kbstate->device == device) { + kbstate = kbstate; + break; + } + } + if (!kbstate) { + return; // We are unfamiliar with this keyboard + } + wl_list_remove(&kbstate->link); + //wl_list_remove(&kbstate->key.link); + //wl_list_remove(&kbstate->mods.link); } -int disable_outputs(void *data) { - struct state *state = data; - struct output_state *ostate; - wl_list_for_each(ostate, &state->outputs, link) { - struct wlr_output *output = ostate->output; - wlr_output_enable(output, false); - } +int timer_done(void *data) { + *(bool *)data = true; return 1; } @@ -113,12 +142,18 @@ int main() { struct state state = { .color = { 1.0, 0.0, 0.0 }, .dec = 0, + .input_add = { .notify = input_add }, + .input_remove = { .notify = input_remove }, .output_add = { .notify = output_add }, .output_remove = { .notify = output_remove } }; + wl_list_init(&state.keyboards); + wl_list_init(&state.input_add.link); + wl_list_init(&state.input_remove.link); + wl_list_init(&state.outputs); - wl_list_init(&state.output_add.link); + wl_list_init(&state.output_remove.link); wl_list_init(&state.output_remove.link); clock_gettime(CLOCK_MONOTONIC, &state.last_frame); @@ -131,6 +166,8 @@ int main() { } struct wlr_backend *wlr = wlr_backend_autocreate(display, session); + wl_signal_add(&wlr->events.input_add, &state.input_add); + wl_signal_add(&wlr->events.input_remove, &state.input_remove); wl_signal_add(&wlr->events.output_add, &state.output_add); wl_signal_add(&wlr->events.output_remove, &state.output_remove); if (!wlr || !wlr_backend_init(wlr)) { @@ -140,14 +177,8 @@ int main() { bool done = false; struct wl_event_source *timer = wl_event_loop_add_timer(event_loop, timer_done, &done); - struct wl_event_source *timer_disable_outputs = - wl_event_loop_add_timer(event_loop, disable_outputs, &state); - struct wl_event_source *timer_enable_outputs = - wl_event_loop_add_timer(event_loop, enable_outputs, &state); - - wl_event_source_timer_update(timer, 20000); - wl_event_source_timer_update(timer_disable_outputs, 5000); - wl_event_source_timer_update(timer_enable_outputs, 10000); + + wl_event_source_timer_update(timer, 10000); while (!done) { wl_event_loop_dispatch(event_loop, 0); -- cgit v1.2.3 From 59ceaf507e9a7c80e04460d1ae4946ce7b6f56ac Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 9 Jun 2017 17:52:11 -0400 Subject: Handle key presses --- backend/libinput/backend.c | 14 +++++++++--- backend/libinput/events.c | 56 ++++++++++++++++++++++++++++++++++++++++++---- example/simple.c | 9 ++++++++ include/wlr/types.h | 26 ++++++++++++++++++--- 4 files changed, 95 insertions(+), 10 deletions(-) (limited to 'example/simple.c') diff --git a/backend/libinput/backend.c b/backend/libinput/backend.c index 3af08875..dc018b10 100644 --- a/backend/libinput/backend.c +++ b/backend/libinput/backend.c @@ -99,7 +99,12 @@ struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display, struct wlr_backend *backend = wlr_backend_create(&backend_impl, state); if (!backend) { wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); - return NULL; + goto error_state; + } + + if (!(state->keyboards = list_create())) { + wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); + goto error_backend; } state->backend = backend; @@ -107,7 +112,10 @@ struct wlr_backend *wlr_libinput_backend_create(struct wl_display *display, state->udev = udev; state->display = display; - state->keyboards = list_create(); - return backend; +error_state: + free(state); +error_backend: + wlr_backend_destroy(backend); + return NULL; } diff --git a/backend/libinput/events.c b/backend/libinput/events.c index b4816928..c31632b5 100644 --- a/backend/libinput/events.c +++ b/backend/libinput/events.c @@ -8,6 +8,22 @@ #include "common/log.h" #include "types.h" +static struct wlr_input_device *get_appropriate_device( + enum wlr_input_device_type desired_type, + struct libinput_device *device) { + list_t *devices = libinput_device_get_user_data(device); + if (!devices) { + return NULL; + } + for (size_t i = 0; i < devices->length; ++i) { + struct wlr_input_device *dev = devices->items[i]; + if (dev->type == desired_type) { + return dev; + } + } + return NULL; +} + static void wlr_libinput_keyboard_destroy(struct wlr_keyboard_state *state) { free(state); } @@ -22,10 +38,39 @@ static struct wlr_keyboard *wlr_libinput_keyboard_create( struct wlr_keyboard_state *kbstate = calloc(1, sizeof(struct wlr_keyboard_state)); kbstate->handle = device; + libinput_device_ref(device); return wlr_keyboard_create(&keyboard_impl, kbstate); } -static void device_added(struct wlr_backend_state *state, +static void handle_keyboard_key(struct libinput_event *event, + struct libinput_device *device) { + struct wlr_input_device *dev = + get_appropriate_device(WLR_INPUT_DEVICE_KEYBOARD, device); + if (!dev) { + wlr_log(L_DEBUG, "Got a keyboard event for a device with no keyboards?"); + return; + } + struct libinput_event_keyboard *kbevent = + libinput_event_get_keyboard_event(event); + struct wlr_keyboard_key *wlr_event = + calloc(1, sizeof(struct wlr_keyboard_key)); + wlr_event->time_sec = libinput_event_keyboard_get_time(kbevent); + wlr_event->time_usec = libinput_event_keyboard_get_time_usec(kbevent); + wlr_event->keycode = libinput_event_keyboard_get_key(kbevent); + enum libinput_key_state state = + libinput_event_keyboard_get_key_state(kbevent); + switch (state) { + case LIBINPUT_KEY_STATE_RELEASED: + wlr_event->state = WLR_KEY_RELEASED; + break; + case LIBINPUT_KEY_STATE_PRESSED: + wlr_event->state = WLR_KEY_PRESSED; + break; + } + wl_signal_emit(&dev->keyboard->events.key, wlr_event); +} + +static void handle_device_added(struct wlr_backend_state *state, struct libinput_device *device) { assert(state && device); /* @@ -73,7 +118,7 @@ static void device_added(struct wlr_backend_state *state, } } -static void device_removed(struct wlr_backend_state *state, +static void handle_device_removed(struct wlr_backend_state *state, struct libinput_device *device) { wlr_log(L_DEBUG, "libinput device removed"); // TODO @@ -88,10 +133,13 @@ void wlr_libinput_event(struct wlr_backend_state *state, (void)context; switch (event_type) { case LIBINPUT_EVENT_DEVICE_ADDED: - device_added(state, device); + handle_device_added(state, device); break; case LIBINPUT_EVENT_DEVICE_REMOVED: - device_removed(state, device); + handle_device_removed(state, device); + break; + case LIBINPUT_EVENT_KEYBOARD_KEY: + handle_keyboard_key(event, device); break; default: wlr_log(L_DEBUG, "Unknown libinput event %d", event_type); diff --git a/example/simple.c b/example/simple.c index 3206b3fa..660c56a6 100644 --- a/example/simple.c +++ b/example/simple.c @@ -97,6 +97,13 @@ void output_remove(struct wl_listener *listener, void *data) { wl_list_remove(&ostate->frame.link); } +static void keyboard_key(struct wl_listener *listener, void *data) { + struct wlr_keyboard_key *event = data; + struct keyboard_state *kbstate = wl_container_of(listener, kbstate, key); + fprintf(stderr, "Key event: %u %s\n", event->keycode, + event->state == WLR_KEY_PRESSED ? "pressed" : "released"); +} + void input_add(struct wl_listener *listener, void *data) { struct wlr_input_device *device = data; struct state *state = wl_container_of(listener, state, input_add); @@ -109,6 +116,8 @@ void input_add(struct wl_listener *listener, void *data) { kbstate->device = device; wl_list_init(&kbstate->key.link); wl_list_init(&kbstate->mods.link); + kbstate->key.notify = keyboard_key; + wl_signal_add(&device->keyboard->events.key, &kbstate->key); wl_list_insert(&state->keyboards, &kbstate->link); } diff --git a/include/wlr/types.h b/include/wlr/types.h index a65b5d9c..e2f3075f 100644 --- a/include/wlr/types.h +++ b/include/wlr/types.h @@ -65,6 +65,18 @@ struct wlr_keyboard { } events; }; +enum wlr_key_state { + WLR_KEY_RELEASED, + WLR_KEY_PRESSED, +}; + +struct wlr_keyboard_key { + uint32_t time_sec; + uint64_t time_usec; + uint32_t keycode; + enum wlr_key_state state; +}; + struct wlr_pointer_state; struct wlr_pointer_impl; @@ -81,20 +93,26 @@ struct wlr_pointer { }; struct wlr_pointer_motion { + uint32_t time_sec; + uint64_t time_usec; double delta_x, delta_y; }; struct wlr_pointer_motion_absolute { + uint32_t time_sec; + uint64_t time_usec; double x_mm, y_mm; double width_mm, height_mm; }; enum wlr_button_state { - WLR_BUTTON_DEPRESSED, - WLR_BUTTON_RELEASED + WLR_BUTTON_RELEASED, + WLR_BUTTON_PRESSED, }; struct wlr_pointer_button { + uint32_t time_sec; + uint64_t time_usec; uint32_t button; enum wlr_button_state state; }; @@ -108,10 +126,12 @@ enum wlr_axis_source { enum wlr_axis_orientation { WLR_AXIS_ORIENTATION_VERTICAL, - WLR_AXIS_ORIENTATION_HORIZONTAL + WLR_AXIS_ORIENTATION_HORIZONTAL, }; struct wlr_pointer_axis { + uint32_t time_sec; + uint64_t time_usec; enum wlr_axis_source source; enum wlr_axis_orientation orientation; double delta; -- cgit v1.2.3 From 12612572ef9af9686e24bb9af81c31c82bb1f765 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Fri, 9 Jun 2017 17:54:40 -0400 Subject: Exit sample on key press --- example/simple.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) (limited to 'example/simple.c') diff --git a/example/simple.c b/example/simple.c index 660c56a6..c9561a7c 100644 --- a/example/simple.c +++ b/example/simple.c @@ -12,6 +12,7 @@ struct state { float color[3]; int dec; + bool exit; struct timespec last_frame; struct wl_list keyboards; @@ -102,6 +103,7 @@ static void keyboard_key(struct wl_listener *listener, void *data) { struct keyboard_state *kbstate = wl_container_of(listener, kbstate, key); fprintf(stderr, "Key event: %u %s\n", event->keycode, event->state == WLR_KEY_PRESSED ? "pressed" : "released"); + kbstate->state->exit = true; } void input_add(struct wl_listener *listener, void *data) { @@ -110,10 +112,9 @@ void input_add(struct wl_listener *listener, void *data) { if (device->type != WLR_INPUT_DEVICE_KEYBOARD) { return; } - fprintf(stderr, "Keyboard '%s' (%d:%d) added\n", device->name, - device->vendor, device->product); struct keyboard_state *kbstate = calloc(sizeof(struct keyboard_state), 1); kbstate->device = device; + kbstate->state = state; wl_list_init(&kbstate->key.link); wl_list_init(&kbstate->mods.link); kbstate->key.notify = keyboard_key; @@ -138,19 +139,15 @@ void input_remove(struct wl_listener *listener, void *data) { return; // We are unfamiliar with this keyboard } wl_list_remove(&kbstate->link); - //wl_list_remove(&kbstate->key.link); + wl_list_remove(&kbstate->key.link); //wl_list_remove(&kbstate->mods.link); } -int timer_done(void *data) { - *(bool *)data = true; - return 1; -} - int main() { struct state state = { .color = { 1.0, 0.0, 0.0 }, .dec = 0, + .exit = false, .input_add = { .notify = input_add }, .input_remove = { .notify = input_remove }, .output_add = { .notify = output_add }, @@ -183,17 +180,10 @@ int main() { return 1; } - bool done = false; - struct wl_event_source *timer = wl_event_loop_add_timer(event_loop, - timer_done, &done); - - wl_event_source_timer_update(timer, 10000); - - while (!done) { + while (!state.exit) { wl_event_loop_dispatch(event_loop, 0); } - wl_event_source_remove(timer); wlr_backend_destroy(wlr); wl_display_destroy(display); } -- cgit v1.2.3 From 5dd96c077238b314162570655ea970ba6c2f8693 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Mon, 12 Jun 2017 21:53:41 -0400 Subject: Incorporate XKBCommon into example --- CMake/FindXKBCommon.cmake | 19 ++++++++++++++ CMakeLists.txt | 1 + backend/libinput/keyboard.c | 1 + example/CMakeLists.txt | 3 +++ example/simple.c | 64 ++++++++++++++++++++++++++++++++++++++++----- include/wlr/types.h | 3 --- types/wlr_keyboard.c | 1 - 7 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 CMake/FindXKBCommon.cmake (limited to 'example/simple.c') diff --git a/CMake/FindXKBCommon.cmake b/CMake/FindXKBCommon.cmake new file mode 100644 index 00000000..30ac503a --- /dev/null +++ b/CMake/FindXKBCommon.cmake @@ -0,0 +1,19 @@ +# - Find XKBCommon +# Once done, this will define +# +# XKBCOMMON_FOUND - System has XKBCommon +# XKBCOMMON_INCLUDE_DIRS - The XKBCommon include directories +# XKBCOMMON_LIBRARIES - The libraries needed to use XKBCommon +# XKBCOMMON_DEFINITIONS - Compiler switches required for using XKBCommon + +find_package(PkgConfig) +pkg_check_modules(PC_XKBCOMMON QUIET xkbcommon) +find_path(XKBCOMMON_INCLUDE_DIRS NAMES xkbcommon/xkbcommon.h HINTS ${PC_XKBCOMMON_INCLUDE_DIRS}) +find_library(XKBCOMMON_LIBRARIES NAMES xkbcommon HINTS ${PC_XKBCOMMON_LIBRARY_DIRS}) + +set(XKBCOMMON_DEFINITIONS ${PC_XKBCOMMON_CFLAGS_OTHER}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(XKBCOMMON DEFAULT_MSG XKBCOMMON_LIBRARIES XKBCOMMON_INCLUDE_DIRS) +mark_as_advanced(XKBCOMMON_LIBRARIES XKBCOMMON_INCLUDE_DIRS) + diff --git a/CMakeLists.txt b/CMakeLists.txt index ae1dc9a1..353e96fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ find_package(GLESv2 REQUIRED) find_package(DRM REQUIRED) find_package(GBM REQUIRED) find_package(LibInput REQUIRED) +find_package(XKBCommon REQUIRED) find_package(Udev REQUIRED) find_package(Systemd) diff --git a/backend/libinput/keyboard.c b/backend/libinput/keyboard.c index 158ded28..9ad41a78 100644 --- a/backend/libinput/keyboard.c +++ b/backend/libinput/keyboard.c @@ -11,6 +11,7 @@ struct wlr_keyboard *wlr_libinput_keyboard_create( struct libinput_device *device) { assert(device); + libinput_device_led_update(device, 0); return wlr_keyboard_create(NULL, NULL); } diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index e8f7ec72..bf9efd64 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -1,6 +1,7 @@ include_directories( ${DRM_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR} + ${XKBCOMMON_INCLUDE_DIRS} ) add_executable(simple @@ -10,6 +11,7 @@ add_executable(simple target_link_libraries(simple wlr-backend wlr-session + ${XKBCOMMON_LIBRARIES} ) add_executable(rotation @@ -21,4 +23,5 @@ target_link_libraries(rotation wlr-backend wlr-session wlr-render + ${XKBCOMMON_LIBRARIES} ) diff --git a/example/simple.c b/example/simple.c index c9561a7c..89f74330 100644 --- a/example/simple.c +++ b/example/simple.c @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 199309L +#include #include #include #include @@ -8,12 +9,15 @@ #include #include #include +#include struct state { float color[3]; int dec; bool exit; struct timespec last_frame; + struct xkb_keymap *keymap; + struct xkb_state *xkb_state; struct wl_list keyboards; struct wl_listener input_add; @@ -35,7 +39,6 @@ struct keyboard_state { struct state *state; struct wlr_input_device *device; struct wl_listener key; - struct wl_listener mods; struct wl_list link; }; @@ -98,12 +101,30 @@ void output_remove(struct wl_listener *listener, void *data) { wl_list_remove(&ostate->frame.link); } +static void handle_keysym(struct state *state, xkb_keysym_t sym, + enum wlr_key_state key_state) { + char name[64]; + int l = xkb_keysym_get_name(sym, name, sizeof(name)); + if (l != -1 && l != sizeof(name)) { + fprintf(stderr, "Key event: %s %s\n", name, + key_state == WLR_KEY_PRESSED ? "pressed" : "released"); + } + if (sym == XKB_KEY_Escape) { + state->exit = true; + } +} + static void keyboard_key(struct wl_listener *listener, void *data) { struct wlr_keyboard_key *event = data; struct keyboard_state *kbstate = wl_container_of(listener, kbstate, key); - fprintf(stderr, "Key event: %u %s\n", event->keycode, - event->state == WLR_KEY_PRESSED ? "pressed" : "released"); - kbstate->state->exit = true; + uint32_t keycode = event->keycode + 8; + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms(kbstate->state->xkb_state, keycode, &syms); + for (int i = 0; i < nsyms; ++i) { + handle_keysym(kbstate->state, syms[i], event->state); + } + xkb_state_update_key(kbstate->state->xkb_state, keycode, + event->state == WLR_KEY_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP); } void input_add(struct wl_listener *listener, void *data) { @@ -116,7 +137,6 @@ void input_add(struct wl_listener *listener, void *data) { kbstate->device = device; kbstate->state = state; wl_list_init(&kbstate->key.link); - wl_list_init(&kbstate->mods.link); kbstate->key.notify = keyboard_key; wl_signal_add(&device->keyboard->events.key, &kbstate->key); wl_list_insert(&state->keyboards, &kbstate->link); @@ -140,7 +160,12 @@ void input_remove(struct wl_listener *listener, void *data) { } wl_list_remove(&kbstate->link); wl_list_remove(&kbstate->key.link); - //wl_list_remove(&kbstate->mods.link); +} + +static int timer_done(void *data) { + struct state *state = data; + state->exit = true; + return 1; } int main() { @@ -151,9 +176,30 @@ int main() { .input_add = { .notify = input_add }, .input_remove = { .notify = input_remove }, .output_add = { .notify = output_add }, - .output_remove = { .notify = output_remove } + .output_remove = { .notify = output_remove }, }; + struct xkb_rule_names rules; + memset(&rules, 0, sizeof(rules)); + rules.rules = getenv("XKB_DEFAULT_RULES"); + rules.model = getenv("XKB_DEFAULT_MODEL"); + rules.layout = getenv("XKB_DEFAULT_LAYOUT"); + rules.variant = getenv("XKB_DEFAULT_VARIANT"); + rules.options = getenv("XKB_DEFAULT_OPTIONS"); + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + fprintf(stderr, "Failed to create XKB context\n"); + return 1; + } + state.keymap = + xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!state.keymap) { + fprintf(stderr, "Failed to create XKB keymap\n"); + return 1; + } + xkb_context_unref(context); + state.xkb_state = xkb_state_new(state.keymap); + wl_list_init(&state.keyboards); wl_list_init(&state.input_add.link); wl_list_init(&state.input_remove.link); @@ -179,6 +225,10 @@ int main() { if (!wlr || !wlr_backend_init(wlr)) { return 1; } + struct wl_event_source *timer = wl_event_loop_add_timer(event_loop, + timer_done, &state); + + wl_event_source_timer_update(timer, 30000); while (!state.exit) { wl_event_loop_dispatch(event_loop, 0); diff --git a/include/wlr/types.h b/include/wlr/types.h index 389989e8..af23152c 100644 --- a/include/wlr/types.h +++ b/include/wlr/types.h @@ -50,8 +50,6 @@ void wlr_output_destroy(struct wlr_output *output); void wlr_output_effective_resolution(struct wlr_output *output, int *width, int *height); -// TODO: keymaps - struct wlr_keyboard_state; struct wlr_keyboard_impl; @@ -61,7 +59,6 @@ struct wlr_keyboard { struct { struct wl_signal key; - struct wl_signal mods; } events; }; diff --git a/types/wlr_keyboard.c b/types/wlr_keyboard.c index d102311b..db4f7ca7 100644 --- a/types/wlr_keyboard.c +++ b/types/wlr_keyboard.c @@ -11,7 +11,6 @@ struct wlr_keyboard *wlr_keyboard_create(struct wlr_keyboard_impl *impl, kb->impl = impl; kb->state = state; wl_signal_init(&kb->events.key); - wl_signal_init(&kb->events.mods); return kb; } -- cgit v1.2.3 From 6bf7e095cf23b570c1fa0e295f9d950404867a22 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Mon, 12 Jun 2017 22:33:55 -0400 Subject: Flesh out keyboard support in examples --- example/rotation.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++------ example/simple.c | 10 ---- 2 files changed, 140 insertions(+), 27 deletions(-) (limited to 'example/simple.c') diff --git a/example/rotation.c b/example/rotation.c index 12778f8e..24c9f494 100644 --- a/example/rotation.c +++ b/example/rotation.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -18,10 +19,19 @@ #include "cat.h" struct state { + struct wl_list config; + struct xkb_keymap *keymap; + struct xkb_state *xkb_state; + bool exit; + + struct wl_list keyboards; + struct wl_listener input_add; + struct wl_listener input_remove; + + struct wl_list outputs; struct wl_listener output_add; struct wl_listener output_remove; - struct wl_list outputs; - struct wl_list config; + struct wlr_renderer *renderer; struct wlr_surface *cat_texture; }; @@ -33,6 +43,7 @@ struct output_state { struct state *state; struct wl_listener frame; float x_offs, y_offs; + float x_vel, y_vel; }; struct output_config { @@ -41,6 +52,13 @@ struct output_config { struct wl_list link; }; +struct keyboard_state { + struct state *state; + struct wlr_input_device *device; + struct wl_listener key; + struct wl_list link; +}; + static void output_frame(struct wl_listener *listener, void *data) { struct output_state *ostate = wl_container_of(listener, ostate, frame); struct wlr_output *output = ostate->output; @@ -68,8 +86,8 @@ static void output_frame(struct wl_listener *listener, void *data) { (now.tv_nsec - ostate->last_frame.tv_nsec) / 1000000; float seconds = ms / 1000.0f; - ostate->x_offs += 128 * seconds; - ostate->y_offs += 128 * seconds; + ostate->x_offs += ostate->x_vel * seconds; + ostate->y_offs += ostate->y_vel * seconds; if (ostate->x_offs > 128) ostate->x_offs = 0; if (ostate->y_offs > 128) ostate->y_offs = 0; ostate->last_frame = now; @@ -89,6 +107,7 @@ static void output_add(struct wl_listener *listener, void *data) { ostate->state = state; ostate->frame.notify = output_frame; ostate->x_offs = ostate->y_offs = 0; + ostate->x_vel = ostate->y_vel = 128; struct output_config *conf; wl_list_for_each(conf, &state->config, link) { @@ -118,9 +137,91 @@ static void output_remove(struct wl_listener *listener, void *data) { } } -static int timer_done(void *data) { - *(bool *)data = true; - return 1; +static void update_velocities(struct state *state, float x_diff, float y_diff) { + struct output_state *ostate; + wl_list_for_each(ostate, &state->outputs, link) { + ostate->x_vel += x_diff; + ostate->y_vel += y_diff; + } +} + +static void handle_keysym(struct state *state, xkb_keysym_t sym, + enum wlr_key_state key_state) { + char name[64]; + int l = xkb_keysym_get_name(sym, name, sizeof(name)); + if (l != -1 && l != sizeof(name)) { + fprintf(stderr, "Key event: %s %s\n", name, + key_state == WLR_KEY_PRESSED ? "pressed" : "released"); + } + // NOTE: It may be better to simply refer to our key state during each frame + // and make this change in pixels/sec^2 + if (key_state == WLR_KEY_PRESSED) { + switch (sym) { + case XKB_KEY_Escape: + state->exit = true; + break; + case XKB_KEY_Left: + update_velocities(state, -16, 0); + break; + case XKB_KEY_Right: + update_velocities(state, 16, 0); + break; + case XKB_KEY_Up: + update_velocities(state, 0, -16); + break; + case XKB_KEY_Down: + update_velocities(state, 0, 16); + break; + } + } +} + +static void keyboard_key(struct wl_listener *listener, void *data) { + struct wlr_keyboard_key *event = data; + struct keyboard_state *kbstate = wl_container_of(listener, kbstate, key); + uint32_t keycode = event->keycode + 8; + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms(kbstate->state->xkb_state, keycode, &syms); + for (int i = 0; i < nsyms; ++i) { + handle_keysym(kbstate->state, syms[i], event->state); + } + xkb_state_update_key(kbstate->state->xkb_state, keycode, + event->state == WLR_KEY_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP); +} + +void input_add(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct state *state = wl_container_of(listener, state, input_add); + if (device->type != WLR_INPUT_DEVICE_KEYBOARD) { + return; + } + struct keyboard_state *kbstate = calloc(sizeof(struct keyboard_state), 1); + kbstate->device = device; + kbstate->state = state; + wl_list_init(&kbstate->key.link); + kbstate->key.notify = keyboard_key; + wl_signal_add(&device->keyboard->events.key, &kbstate->key); + wl_list_insert(&state->keyboards, &kbstate->link); +} + +void input_remove(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct state *state = wl_container_of(listener, state, input_add); + if (device->type != WLR_INPUT_DEVICE_KEYBOARD) { + return; + } + struct keyboard_state *kbstate = NULL, *_kbstate; + wl_list_for_each(_kbstate, &state->keyboards, link) { + if (_kbstate->device == device) { + kbstate = kbstate; + break; + } + } + if (!kbstate) { + return; // We are unfamiliar with this keyboard + } + wl_list_remove(&kbstate->link); + wl_list_remove(&kbstate->key.link); } static void usage(const char *name, int ret) { @@ -191,10 +292,38 @@ static void parse_args(int argc, char *argv[], struct wl_list *config) { int main(int argc, char *argv[]) { struct state state = { + .exit = false, + .input_add = { .notify = input_add }, + .input_remove = { .notify = input_remove }, .output_add = { .notify = output_add }, .output_remove = { .notify = output_remove } }; + struct xkb_rule_names rules; + memset(&rules, 0, sizeof(rules)); + rules.rules = getenv("XKB_DEFAULT_RULES"); + rules.model = getenv("XKB_DEFAULT_MODEL"); + rules.layout = getenv("XKB_DEFAULT_LAYOUT"); + rules.variant = getenv("XKB_DEFAULT_VARIANT"); + rules.options = getenv("XKB_DEFAULT_OPTIONS"); + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + fprintf(stderr, "Failed to create XKB context\n"); + return 1; + } + state.keymap = + xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!state.keymap) { + fprintf(stderr, "Failed to create XKB keymap\n"); + return 1; + } + xkb_context_unref(context); + state.xkb_state = xkb_state_new(state.keymap); + + wl_list_init(&state.keyboards); + wl_list_init(&state.input_add.link); + wl_list_init(&state.input_remove.link); + wl_list_init(&state.outputs); wl_list_init(&state.config); wl_list_init(&state.output_add.link); @@ -215,10 +344,11 @@ int main(int argc, char *argv[]) { return 1; } + wl_signal_add(&wlr->events.input_add, &state.input_add); + wl_signal_add(&wlr->events.input_remove, &state.input_remove); wl_signal_add(&wlr->events.output_add, &state.output_add); wl_signal_add(&wlr->events.output_remove, &state.output_remove); - - if (!wlr_backend_init(wlr)) { + if (!wlr || !wlr_backend_init(wlr)) { printf("Failed to initialize backend, bailing out\n"); return 1; } @@ -228,17 +358,10 @@ int main(int argc, char *argv[]) { wlr_surface_attach_pixels(state.cat_texture, GL_RGB, cat_tex.width, cat_tex.height, cat_tex.pixel_data); - bool done = false; - struct wl_event_source *timer = wl_event_loop_add_timer(event_loop, - timer_done, &done); - - wl_event_source_timer_update(timer, 30000); - - while (!done) { + while (!state.exit) { wl_event_loop_dispatch(event_loop, 0); } - wl_event_source_remove(timer); wlr_backend_destroy(wlr); wlr_session_finish(session); wlr_surface_destroy(state.cat_texture); diff --git a/example/simple.c b/example/simple.c index 89f74330..331a0d08 100644 --- a/example/simple.c +++ b/example/simple.c @@ -162,12 +162,6 @@ void input_remove(struct wl_listener *listener, void *data) { wl_list_remove(&kbstate->key.link); } -static int timer_done(void *data) { - struct state *state = data; - state->exit = true; - return 1; -} - int main() { struct state state = { .color = { 1.0, 0.0, 0.0 }, @@ -225,10 +219,6 @@ int main() { if (!wlr || !wlr_backend_init(wlr)) { return 1; } - struct wl_event_source *timer = wl_event_loop_add_timer(event_loop, - timer_done, &state); - - wl_event_source_timer_update(timer, 30000); while (!state.exit) { wl_event_loop_dispatch(event_loop, 0); -- cgit v1.2.3 From 0dbfe56c892f400a015c37d1f3574c8f9c985030 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Tue, 13 Jun 2017 10:13:11 -0400 Subject: Simplify examples --- example/CMakeLists.txt | 2 + example/rotation.c | 269 +++++++++++-------------------------------------- example/shared.c | 203 +++++++++++++++++++++++++++++++++++++ example/shared.h | 61 +++++++++++ example/simple.c | 219 +++++----------------------------------- 5 files changed, 349 insertions(+), 405 deletions(-) create mode 100644 example/shared.c create mode 100644 example/shared.h (limited to 'example/simple.c') diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index bf9efd64..f659e5bb 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories( add_executable(simple simple.c + shared.c ) target_link_libraries(simple @@ -16,6 +17,7 @@ target_link_libraries(simple add_executable(rotation rotation.c + shared.c cat.c ) diff --git a/example/rotation.c b/example/rotation.c index 24c9f494..2634ea03 100644 --- a/example/rotation.c +++ b/example/rotation.c @@ -16,32 +16,17 @@ #include #include #include +#include "shared.h" #include "cat.h" -struct state { +struct sample_state { struct wl_list config; - struct xkb_keymap *keymap; - struct xkb_state *xkb_state; - bool exit; - - struct wl_list keyboards; - struct wl_listener input_add; - struct wl_listener input_remove; - - struct wl_list outputs; - struct wl_listener output_add; - struct wl_listener output_remove; - + // TODO: Move renderer into shared struct wlr_renderer *renderer; struct wlr_surface *cat_texture; }; -struct output_state { - struct timespec last_frame; - struct wl_list link; - struct wlr_output *output; - struct state *state; - struct wl_listener frame; +struct output_data { float x_offs, y_offs; float x_vel, y_vel; }; @@ -52,176 +37,93 @@ struct output_config { struct wl_list link; }; -struct keyboard_state { - struct state *state; - struct wlr_input_device *device; - struct wl_listener key; - struct wl_list link; -}; - -static void output_frame(struct wl_listener *listener, void *data) { - struct output_state *ostate = wl_container_of(listener, ostate, frame); - struct wlr_output *output = ostate->output; - struct state *s = ostate->state; +static void handle_output_frame(struct output_state *output, struct timespec *ts) { + struct compositor_state *state = output->compositor; + struct sample_state *sample = state->data; + struct output_data *odata = output->data; + struct wlr_output *wlr_output = output->output; int32_t width, height; - wlr_output_effective_resolution(output, &width, &height); + wlr_output_effective_resolution(wlr_output, &width, &height); - wlr_renderer_begin(s->renderer, output); + wlr_renderer_begin(sample->renderer, wlr_output); float matrix[16]; - for (int y = -128 + (int)ostate->y_offs; y < height; y += 128) { - for (int x = -128 + (int)ostate->x_offs; x < width; x += 128) { - wlr_surface_get_matrix(s->cat_texture, &matrix, - &output->transform_matrix, x, y); - wlr_render_with_matrix(s->renderer, s->cat_texture, &matrix); + for (int y = -128 + (int)odata->y_offs; y < height; y += 128) { + for (int x = -128 + (int)odata->x_offs; x < width; x += 128) { + wlr_surface_get_matrix(sample->cat_texture, &matrix, + &wlr_output->transform_matrix, x, y); + wlr_render_with_matrix(sample->renderer, + sample->cat_texture, &matrix); } } - wlr_renderer_end(s->renderer); + wlr_renderer_end(sample->renderer); - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - long ms = (now.tv_sec - ostate->last_frame.tv_sec) * 1000 + - (now.tv_nsec - ostate->last_frame.tv_nsec) / 1000000; + long ms = (ts->tv_sec - output->last_frame.tv_sec) * 1000 + + (ts->tv_nsec - output->last_frame.tv_nsec) / 1000000; float seconds = ms / 1000.0f; - ostate->x_offs += ostate->x_vel * seconds; - ostate->y_offs += ostate->y_vel * seconds; - if (ostate->x_offs > 128) ostate->x_offs = 0; - if (ostate->y_offs > 128) ostate->y_offs = 0; - ostate->last_frame = now; + odata->x_offs += odata->x_vel * seconds; + odata->y_offs += odata->y_vel * seconds; + if (odata->x_offs > 128) odata->x_offs = 0; + if (odata->y_offs > 128) odata->y_offs = 0; } -static void output_add(struct wl_listener *listener, void *data) { - struct wlr_output *output = data; - struct state *state = wl_container_of(listener, state, output_add); - - fprintf(stderr, "Output '%s' added\n", output->name); - wlr_output_set_mode(output, output->modes->items[0]); - - struct output_state *ostate = calloc(1, sizeof(struct output_state)); - - clock_gettime(CLOCK_MONOTONIC, &ostate->last_frame); - ostate->output = output; - ostate->state = state; - ostate->frame.notify = output_frame; - ostate->x_offs = ostate->y_offs = 0; - ostate->x_vel = ostate->y_vel = 128; +static void handle_output_add(struct output_state *output) { + struct output_data *odata = calloc(1, sizeof(struct output_data)); + odata->x_offs = odata->y_offs = 0; + odata->x_vel = odata->y_vel = 128; + output->data = odata; + struct sample_state *state = output->compositor->data; struct output_config *conf; wl_list_for_each(conf, &state->config, link) { - if (strcmp(conf->name, output->name) == 0) { - wlr_output_transform(ostate->output, conf->transform); + if (strcmp(conf->name, output->output->name) == 0) { + wlr_output_transform(output->output, conf->transform); break; } } - - wl_list_init(&ostate->frame.link); - wl_signal_add(&output->events.frame, &ostate->frame); - wl_list_insert(&state->outputs, &ostate->link); } -static void output_remove(struct wl_listener *listener, void *data) { - struct wlr_output *output = data; - struct state *state = wl_container_of(listener, state, output_remove); - struct output_state *ostate; - - wl_list_for_each(ostate, &state->outputs, link) { - if (ostate->output == output) { - wl_list_remove(&ostate->link); - wl_list_remove(&ostate->frame.link); - free(ostate); - break; - } - } +static void handle_output_remove(struct output_state *output) { + free(output->data); } -static void update_velocities(struct state *state, float x_diff, float y_diff) { - struct output_state *ostate; - wl_list_for_each(ostate, &state->outputs, link) { - ostate->x_vel += x_diff; - ostate->y_vel += y_diff; +static void update_velocities(struct compositor_state *state, + float x_diff, float y_diff) { + struct output_state *output; + wl_list_for_each(output, &state->outputs, link) { + struct output_data *odata = output->data; + odata->x_vel += x_diff; + odata->y_vel += y_diff; } } -static void handle_keysym(struct state *state, xkb_keysym_t sym, - enum wlr_key_state key_state) { - char name[64]; - int l = xkb_keysym_get_name(sym, name, sizeof(name)); - if (l != -1 && l != sizeof(name)) { - fprintf(stderr, "Key event: %s %s\n", name, - key_state == WLR_KEY_PRESSED ? "pressed" : "released"); - } +static void handle_keyboard_key(struct keyboard_state *kbstate, + xkb_keysym_t sym, enum wlr_key_state key_state) { // NOTE: It may be better to simply refer to our key state during each frame // and make this change in pixels/sec^2 + // Also, key repeat if (key_state == WLR_KEY_PRESSED) { switch (sym) { case XKB_KEY_Escape: - state->exit = true; + kbstate->compositor->exit = true; break; case XKB_KEY_Left: - update_velocities(state, -16, 0); + update_velocities(kbstate->compositor, -16, 0); break; case XKB_KEY_Right: - update_velocities(state, 16, 0); + update_velocities(kbstate->compositor, 16, 0); break; case XKB_KEY_Up: - update_velocities(state, 0, -16); + update_velocities(kbstate->compositor, 0, -16); break; case XKB_KEY_Down: - update_velocities(state, 0, 16); - break; - } - } -} - -static void keyboard_key(struct wl_listener *listener, void *data) { - struct wlr_keyboard_key *event = data; - struct keyboard_state *kbstate = wl_container_of(listener, kbstate, key); - uint32_t keycode = event->keycode + 8; - const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(kbstate->state->xkb_state, keycode, &syms); - for (int i = 0; i < nsyms; ++i) { - handle_keysym(kbstate->state, syms[i], event->state); - } - xkb_state_update_key(kbstate->state->xkb_state, keycode, - event->state == WLR_KEY_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP); -} - -void input_add(struct wl_listener *listener, void *data) { - struct wlr_input_device *device = data; - struct state *state = wl_container_of(listener, state, input_add); - if (device->type != WLR_INPUT_DEVICE_KEYBOARD) { - return; - } - struct keyboard_state *kbstate = calloc(sizeof(struct keyboard_state), 1); - kbstate->device = device; - kbstate->state = state; - wl_list_init(&kbstate->key.link); - kbstate->key.notify = keyboard_key; - wl_signal_add(&device->keyboard->events.key, &kbstate->key); - wl_list_insert(&state->keyboards, &kbstate->link); -} - -void input_remove(struct wl_listener *listener, void *data) { - struct wlr_input_device *device = data; - struct state *state = wl_container_of(listener, state, input_add); - if (device->type != WLR_INPUT_DEVICE_KEYBOARD) { - return; - } - struct keyboard_state *kbstate = NULL, *_kbstate; - wl_list_for_each(_kbstate, &state->keyboards, link) { - if (_kbstate->device == device) { - kbstate = kbstate; + update_velocities(kbstate->compositor, 0, 16); break; } } - if (!kbstate) { - return; // We are unfamiliar with this keyboard - } - wl_list_remove(&kbstate->link); - wl_list_remove(&kbstate->key.link); } static void usage(const char *name, int ret) { @@ -291,82 +193,27 @@ static void parse_args(int argc, char *argv[], struct wl_list *config) { } int main(int argc, char *argv[]) { - struct state state = { - .exit = false, - .input_add = { .notify = input_add }, - .input_remove = { .notify = input_remove }, - .output_add = { .notify = output_add }, - .output_remove = { .notify = output_remove } - }; - - struct xkb_rule_names rules; - memset(&rules, 0, sizeof(rules)); - rules.rules = getenv("XKB_DEFAULT_RULES"); - rules.model = getenv("XKB_DEFAULT_MODEL"); - rules.layout = getenv("XKB_DEFAULT_LAYOUT"); - rules.variant = getenv("XKB_DEFAULT_VARIANT"); - rules.options = getenv("XKB_DEFAULT_OPTIONS"); - struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (!context) { - fprintf(stderr, "Failed to create XKB context\n"); - return 1; - } - state.keymap = - xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); - if (!state.keymap) { - fprintf(stderr, "Failed to create XKB keymap\n"); - return 1; - } - xkb_context_unref(context); - state.xkb_state = xkb_state_new(state.keymap); - - wl_list_init(&state.keyboards); - wl_list_init(&state.input_add.link); - wl_list_init(&state.input_remove.link); - - wl_list_init(&state.outputs); + struct sample_state state = { 0 }; + struct compositor_state compositor; wl_list_init(&state.config); - wl_list_init(&state.output_add.link); - wl_list_init(&state.output_remove.link); - parse_args(argc, argv, &state.config); - struct wl_display *display = wl_display_create(); - struct wl_event_loop *event_loop = wl_display_get_event_loop(display); - - struct wlr_session *session = wlr_session_start(display); - if (!session) { - return 1; - } - - struct wlr_backend *wlr = wlr_backend_autocreate(display, session); - if (!wlr) { - return 1; - } - - wl_signal_add(&wlr->events.input_add, &state.input_add); - wl_signal_add(&wlr->events.input_remove, &state.input_remove); - wl_signal_add(&wlr->events.output_add, &state.output_add); - wl_signal_add(&wlr->events.output_remove, &state.output_remove); - if (!wlr || !wlr_backend_init(wlr)) { - printf("Failed to initialize backend, bailing out\n"); - return 1; - } + compositor_init(&compositor); + compositor.output_add_cb = handle_output_add; + compositor.output_remove_cb = handle_output_remove; + compositor.output_frame_cb = handle_output_frame; + compositor.keyboard_key_cb = handle_keyboard_key; state.renderer = wlr_gles3_renderer_init(); state.cat_texture = wlr_render_surface_init(state.renderer); wlr_surface_attach_pixels(state.cat_texture, GL_RGB, cat_tex.width, cat_tex.height, cat_tex.pixel_data); - while (!state.exit) { - wl_event_loop_dispatch(event_loop, 0); - } + compositor.data = &state; + compositor_run(&compositor); - wlr_backend_destroy(wlr); - wlr_session_finish(session); wlr_surface_destroy(state.cat_texture); wlr_renderer_destroy(state.renderer); - wl_display_destroy(display); struct output_config *ptr, *tmp; wl_list_for_each_safe(ptr, tmp, &state.config, link) { diff --git a/example/shared.c b/example/shared.c new file mode 100644 index 00000000..58266214 --- /dev/null +++ b/example/shared.c @@ -0,0 +1,203 @@ +#define _POSIX_C_SOURCE 199309L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "shared.h" + +static void keyboard_key_notify(struct wl_listener *listener, void *data) { + struct wlr_keyboard_key *event = data; + struct keyboard_state *kbstate = wl_container_of(listener, kbstate, key); + uint32_t keycode = event->keycode + 8; + enum wlr_key_state key_state = event->state; + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms(kbstate->xkb_state, keycode, &syms); + for (int i = 0; i < nsyms; ++i) { + xkb_keysym_t sym = syms[i]; + char name[64]; + int l = xkb_keysym_get_name(sym, name, sizeof(name)); + if (l != -1 && l != sizeof(name)) { + fprintf(stderr, "Key event: %s %s\n", name, + key_state == WLR_KEY_PRESSED ? "pressed" : "released"); + } + if (kbstate->compositor->keyboard_key_cb) { + kbstate->compositor->keyboard_key_cb(kbstate, sym, key_state); + } + } + xkb_state_update_key(kbstate->xkb_state, keycode, + event->state == WLR_KEY_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP); +} + +static void input_add_notify(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct compositor_state *state = wl_container_of(listener, state, input_add); + if (device->type != WLR_INPUT_DEVICE_KEYBOARD) { + return; + } + struct keyboard_state *kbstate = calloc(sizeof(struct keyboard_state), 1); + kbstate->device = device; + kbstate->compositor = state; + wl_list_init(&kbstate->key.link); + kbstate->key.notify = keyboard_key_notify; + wl_signal_add(&device->keyboard->events.key, &kbstate->key); + wl_list_insert(&state->keyboards, &kbstate->link); + + struct xkb_rule_names rules; + memset(&rules, 0, sizeof(rules)); + rules.rules = getenv("XKB_DEFAULT_RULES"); + rules.model = getenv("XKB_DEFAULT_MODEL"); + rules.layout = getenv("XKB_DEFAULT_LAYOUT"); + rules.variant = getenv("XKB_DEFAULT_VARIANT"); + rules.options = getenv("XKB_DEFAULT_OPTIONS"); + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + fprintf(stderr, "Failed to create XKB context\n"); + exit(1); + } + kbstate->keymap = xkb_map_new_from_names( + context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!kbstate->keymap) { + fprintf(stderr, "Failed to create XKB keymap\n"); + exit(1); + } + xkb_context_unref(context); + kbstate->xkb_state = xkb_state_new(kbstate->keymap); + if (!kbstate->xkb_state) { + fprintf(stderr, "Failed to create XKB state\n"); + exit(1); + } +} + +static void input_remove_notify(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct compositor_state *state = wl_container_of(listener, state, input_add); + if (device->type != WLR_INPUT_DEVICE_KEYBOARD) { + return; + } + struct keyboard_state *kbstate = NULL, *_kbstate; + wl_list_for_each(_kbstate, &state->keyboards, link) { + if (_kbstate->device == device) { + kbstate = kbstate; + break; + } + } + if (!kbstate) { + return; // We are unfamiliar with this keyboard + } + wl_list_remove(&kbstate->link); + wl_list_remove(&kbstate->key.link); +} + +static void output_frame_notify(struct wl_listener *listener, void *data) { + struct output_state *output = wl_container_of(listener, output, frame); + struct compositor_state *compositor = output->compositor; + + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + if (compositor->output_frame_cb) { + compositor->output_frame_cb(output, &now); + } + + output->last_frame = now; + compositor->last_frame = now; +} + +static void output_add_notify(struct wl_listener *listener, void *data) { + struct wlr_output *output = data; + struct compositor_state *state = wl_container_of(listener, state, output_add); + fprintf(stderr, "Output '%s' added\n", output->name); + fprintf(stderr, "%s %s %"PRId32"mm x %"PRId32"mm\n", output->make, output->model, + output->phys_width, output->phys_height); + wlr_output_set_mode(output, output->modes->items[0]); + struct output_state *ostate = calloc(1, sizeof(struct output_state)); + clock_gettime(CLOCK_MONOTONIC, &ostate->last_frame); + ostate->output = output; + ostate->compositor = state; + ostate->frame.notify = output_frame_notify; + wl_list_init(&ostate->frame.link); + wl_signal_add(&output->events.frame, &ostate->frame); + wl_list_insert(&state->outputs, &ostate->link); + if (state->output_add_cb) { + state->output_add_cb(ostate); + } +} + +static void output_remove_notify(struct wl_listener *listener, void *data) { + struct wlr_output *output = data; + struct compositor_state *state = wl_container_of(listener, state, output_remove); + struct output_state *ostate = NULL, *_ostate; + wl_list_for_each(_ostate, &state->outputs, link) { + if (_ostate->output == output) { + ostate = _ostate; + break; + } + } + if (!ostate) { + return; // We are unfamiliar with this output + } + if (state->output_remove_cb) { + state->output_remove_cb(ostate); + } + wl_list_remove(&ostate->link); + wl_list_remove(&ostate->frame.link); +} + +void compositor_init(struct compositor_state *state) { + memset(state, 0, sizeof(struct compositor_state)); + + state->display = wl_display_create(); + state->event_loop = wl_display_get_event_loop(state->display); + state->session = wlr_session_start(state->display); + if (!state->session + || !state->display + || !state->event_loop) { + exit(1); + } + + wl_list_init(&state->keyboards); + wl_list_init(&state->input_add.link); + state->input_add.notify = input_add_notify; + wl_list_init(&state->input_remove.link); + state->input_remove.notify = input_remove_notify; + + wl_list_init(&state->outputs); + wl_list_init(&state->output_add.link); + state->output_add.notify = output_add_notify; + wl_list_init(&state->output_remove.link); + state->output_remove.notify = output_remove_notify; + + struct wlr_backend *wlr = wlr_backend_autocreate( + state->display, state->session); + if (!wlr) { + exit(1); + } + wl_signal_add(&wlr->events.input_add, &state->input_add); + wl_signal_add(&wlr->events.input_remove, &state->input_remove); + wl_signal_add(&wlr->events.output_add, &state->output_add); + wl_signal_add(&wlr->events.output_remove, &state->output_remove); + state->backend = wlr; + + clock_gettime(CLOCK_MONOTONIC, &state->last_frame); +} + +void compositor_run(struct compositor_state *state) { + if (!wlr_backend_init(state->backend)) { + fprintf(stderr, "Failed to initialize backend\n"); + exit(1); + } + + while (!state->exit) { + wl_event_loop_dispatch(state->event_loop, 0); + } + + wlr_backend_destroy(state->backend); + wlr_session_finish(state->session); + wl_display_destroy(state->display); +} diff --git a/example/shared.h b/example/shared.h new file mode 100644 index 00000000..bafbee16 --- /dev/null +++ b/example/shared.h @@ -0,0 +1,61 @@ +#ifndef _EXAMPLE_SHARED_H +#define _EXAMPLE_SHARED_H +#define _POSIX_C_SOURCE 199309L +#include +#include +#include +#include +#include +#include +#include + +struct output_state { + struct compositor_state *compositor; + struct wlr_output *output; + struct wl_listener frame; + struct timespec last_frame; + struct wl_list link; + void *data; +}; + +struct keyboard_state { + struct compositor_state *compositor; + struct wlr_input_device *device; + struct wl_listener key; + struct wl_list link; + struct xkb_keymap *keymap; + struct xkb_state *xkb_state; + void *data; +}; + +struct compositor_state { + void (*output_add_cb)(struct output_state *s); + void (*keyboard_add_cb)(struct keyboard_state *s); + void (*output_frame_cb)(struct output_state *s, struct timespec *ts); + void (*output_remove_cb)(struct output_state *s); + void (*keyboard_remove_cb)(struct keyboard_state *s); + void (*keyboard_key_cb)(struct keyboard_state *s, xkb_keysym_t sym, + enum wlr_key_state key_state); + + struct wl_display *display; + struct wl_event_loop *event_loop; + struct wlr_backend *backend; + struct wlr_session *session; + + struct wl_list keyboards; + struct wl_listener input_add; + struct wl_listener input_remove; + + struct timespec last_frame; + struct wl_listener output_add; + struct wl_listener output_remove; + struct wl_list outputs; + + bool exit; + void *data; +}; + +void compositor_init(struct compositor_state *state); +void compositor_run(struct compositor_state *state); + +#endif diff --git a/example/simple.c b/example/simple.c index 331a0d08..5a5a1300 100644 --- a/example/simple.c +++ b/example/simple.c @@ -10,220 +10,51 @@ #include #include #include +#include "shared.h" -struct state { +struct sample_state { float color[3]; int dec; - bool exit; - struct timespec last_frame; - struct xkb_keymap *keymap; - struct xkb_state *xkb_state; - - struct wl_list keyboards; - struct wl_listener input_add; - struct wl_listener input_remove; - - struct wl_listener output_add; - struct wl_listener output_remove; - struct wl_list outputs; -}; - -struct output_state { - struct state *state; - struct wlr_output *output; - struct wl_listener frame; - struct wl_list link; -}; - -struct keyboard_state { - struct state *state; - struct wlr_input_device *device; - struct wl_listener key; - struct wl_list link; }; -void output_frame(struct wl_listener *listener, void *data) { - struct output_state *ostate = wl_container_of(listener, ostate, frame); - struct state *s = ostate->state; - - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); +void handle_output_frame(struct output_state *output, struct timespec *ts) { + struct compositor_state *state = output->compositor; + struct sample_state *sample = state->data; - long ms = (now.tv_sec - s->last_frame.tv_sec) * 1000 + - (now.tv_nsec - s->last_frame.tv_nsec) / 1000000; - int inc = (s->dec + 1) % 3; + long ms = (ts->tv_sec - state->last_frame.tv_sec) * 1000 + + (ts->tv_nsec - state->last_frame.tv_nsec) / 1000000; + int inc = (sample->dec + 1) % 3; - s->color[inc] += ms / 2000.0f; - s->color[s->dec] -= ms / 2000.0f; + sample->color[inc] += ms / 2000.0f; + sample->color[sample->dec] -= ms / 2000.0f; - if (s->color[s->dec] < 0.0f) { - s->color[inc] = 1.0f; - s->color[s->dec] = 0.0f; - s->dec = inc; + if (sample->color[sample->dec] < 0.0f) { + sample->color[inc] = 1.0f; + sample->color[sample->dec] = 0.0f; + sample->dec = inc; } - s->last_frame = now; - - glClearColor(s->color[0], s->color[1], s->color[2], 1.0); + glClearColor(sample->color[0], sample->color[1], sample->color[2], 1.0); glClear(GL_COLOR_BUFFER_BIT); } -void output_add(struct wl_listener *listener, void *data) { - struct wlr_output *output = data; - struct state *state = wl_container_of(listener, state, output_add); - fprintf(stderr, "Output '%s' added\n", output->name); - fprintf(stderr, "%s %s %"PRId32"mm x %"PRId32"mm\n", output->make, output->model, - output->phys_width, output->phys_height); - wlr_output_set_mode(output, output->modes->items[0]); - struct output_state *ostate = calloc(1, sizeof(struct output_state)); - ostate->output = output; - ostate->state = state; - ostate->frame.notify = output_frame; - wl_list_init(&ostate->frame.link); - wl_signal_add(&output->events.frame, &ostate->frame); - wl_list_insert(&state->outputs, &ostate->link); -} - -void output_remove(struct wl_listener *listener, void *data) { - struct wlr_output *output = data; - struct state *state = wl_container_of(listener, state, output_remove); - struct output_state *ostate = NULL, *_ostate; - wl_list_for_each(_ostate, &state->outputs, link) { - if (_ostate->output == output) { - ostate = _ostate; - break; - } - } - if (!ostate) { - return; // We are unfamiliar with this output - } - wl_list_remove(&ostate->link); - wl_list_remove(&ostate->frame.link); -} - -static void handle_keysym(struct state *state, xkb_keysym_t sym, - enum wlr_key_state key_state) { - char name[64]; - int l = xkb_keysym_get_name(sym, name, sizeof(name)); - if (l != -1 && l != sizeof(name)) { - fprintf(stderr, "Key event: %s %s\n", name, - key_state == WLR_KEY_PRESSED ? "pressed" : "released"); - } +static void handle_keyboard_key(struct keyboard_state *kbstate, + xkb_keysym_t sym, enum wlr_key_state key_state) { if (sym == XKB_KEY_Escape) { - state->exit = true; - } -} - -static void keyboard_key(struct wl_listener *listener, void *data) { - struct wlr_keyboard_key *event = data; - struct keyboard_state *kbstate = wl_container_of(listener, kbstate, key); - uint32_t keycode = event->keycode + 8; - const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(kbstate->state->xkb_state, keycode, &syms); - for (int i = 0; i < nsyms; ++i) { - handle_keysym(kbstate->state, syms[i], event->state); - } - xkb_state_update_key(kbstate->state->xkb_state, keycode, - event->state == WLR_KEY_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP); -} - -void input_add(struct wl_listener *listener, void *data) { - struct wlr_input_device *device = data; - struct state *state = wl_container_of(listener, state, input_add); - if (device->type != WLR_INPUT_DEVICE_KEYBOARD) { - return; - } - struct keyboard_state *kbstate = calloc(sizeof(struct keyboard_state), 1); - kbstate->device = device; - kbstate->state = state; - wl_list_init(&kbstate->key.link); - kbstate->key.notify = keyboard_key; - wl_signal_add(&device->keyboard->events.key, &kbstate->key); - wl_list_insert(&state->keyboards, &kbstate->link); -} - -void input_remove(struct wl_listener *listener, void *data) { - struct wlr_input_device *device = data; - struct state *state = wl_container_of(listener, state, input_add); - if (device->type != WLR_INPUT_DEVICE_KEYBOARD) { - return; + kbstate->compositor->exit = true; } - struct keyboard_state *kbstate = NULL, *_kbstate; - wl_list_for_each(_kbstate, &state->keyboards, link) { - if (_kbstate->device == device) { - kbstate = kbstate; - break; - } - } - if (!kbstate) { - return; // We are unfamiliar with this keyboard - } - wl_list_remove(&kbstate->link); - wl_list_remove(&kbstate->key.link); } int main() { - struct state state = { + struct sample_state state = { .color = { 1.0, 0.0, 0.0 }, .dec = 0, - .exit = false, - .input_add = { .notify = input_add }, - .input_remove = { .notify = input_remove }, - .output_add = { .notify = output_add }, - .output_remove = { .notify = output_remove }, }; + struct compositor_state compositor; - struct xkb_rule_names rules; - memset(&rules, 0, sizeof(rules)); - rules.rules = getenv("XKB_DEFAULT_RULES"); - rules.model = getenv("XKB_DEFAULT_MODEL"); - rules.layout = getenv("XKB_DEFAULT_LAYOUT"); - rules.variant = getenv("XKB_DEFAULT_VARIANT"); - rules.options = getenv("XKB_DEFAULT_OPTIONS"); - struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (!context) { - fprintf(stderr, "Failed to create XKB context\n"); - return 1; - } - state.keymap = - xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); - if (!state.keymap) { - fprintf(stderr, "Failed to create XKB keymap\n"); - return 1; - } - xkb_context_unref(context); - state.xkb_state = xkb_state_new(state.keymap); - - wl_list_init(&state.keyboards); - wl_list_init(&state.input_add.link); - wl_list_init(&state.input_remove.link); - - wl_list_init(&state.outputs); - wl_list_init(&state.output_remove.link); - wl_list_init(&state.output_remove.link); - clock_gettime(CLOCK_MONOTONIC, &state.last_frame); - - struct wl_display *display = wl_display_create(); - struct wl_event_loop *event_loop = wl_display_get_event_loop(display); - - struct wlr_session *session = wlr_session_start(display); - if (!session) { - return 1; - } - - struct wlr_backend *wlr = wlr_backend_autocreate(display, session); - wl_signal_add(&wlr->events.input_add, &state.input_add); - wl_signal_add(&wlr->events.input_remove, &state.input_remove); - wl_signal_add(&wlr->events.output_add, &state.output_add); - wl_signal_add(&wlr->events.output_remove, &state.output_remove); - if (!wlr || !wlr_backend_init(wlr)) { - return 1; - } - - while (!state.exit) { - wl_event_loop_dispatch(event_loop, 0); - } - - wlr_backend_destroy(wlr); - wl_display_destroy(display); + compositor_init(&compositor); + compositor.output_frame_cb = handle_output_frame; + compositor.keyboard_key_cb = handle_keyboard_key; + compositor.data = &state; + compositor_run(&compositor); } -- cgit v1.2.3