diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index ff60e5bf..aaa71a14 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -1,4 +1,4 @@ -#define _POSIX_C_SOURCE 199309L +#define _POSIX_C_SOURCE 200112L #define _XOPEN_SOURCE 500 #include #include @@ -22,13 +22,23 @@ #include #include #include -#include "support/config.h" -#include "support/shared.h" -struct sample_state; +struct sample_state { + struct wl_display *display; + struct wlr_xcursor *xcursor; + float default_color[4]; + float clear_color[4]; + struct wlr_output_layout *layout; + struct wl_list cursors; // sample_cursor::link + struct wl_list pointers; // sample_pointer::link + struct wl_list outputs; // sample_output::link + struct timespec last_frame; + struct wl_listener new_output; + struct wl_listener new_input; +}; struct sample_cursor { - struct sample_state *state; + struct sample_state *sample; struct wlr_input_device *device; struct wlr_cursor *cursor; struct wl_list link; @@ -37,22 +47,52 @@ struct sample_cursor { struct wl_listener cursor_motion_absolute; struct wl_listener cursor_button; struct wl_listener cursor_axis; + struct wl_listener destroy; }; -struct sample_state { - struct compositor_state *compositor; - struct example_config *config; - struct wlr_xcursor *xcursor; - float default_color[4]; - float clear_color[4]; - struct wlr_output_layout *layout; - struct wl_list cursors; // sample_cursor::link +struct sample_pointer { + struct wlr_input_device *device; + struct wl_list link; }; -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 sample_output { + struct sample_state *sample; + struct wlr_output *output; + struct wl_listener frame; + struct wl_listener destroy; + struct wl_list link; +}; + +struct sample_keyboard { + struct sample_state *sample; + struct wlr_input_device *device; + struct wl_listener key; + struct wl_listener destroy; +}; + +void configure_cursor(struct wlr_cursor *cursor, struct wlr_input_device *device, + struct sample_state *sample) { + struct sample_output *output; + wlr_log(L_ERROR, "Configuring cursor %p for device %p", cursor, device); + + // reset mappings + wlr_cursor_map_to_output(cursor, NULL); + wlr_cursor_detach_input_device(cursor, device); + wlr_cursor_map_input_to_output(cursor, device, NULL); + + wlr_cursor_attach_input_device(cursor, device); + + // configure device to output mappings + wl_list_for_each(output, &sample->outputs, link) { + wlr_cursor_map_to_output(cursor, output->output); + + wlr_cursor_map_input_to_output(cursor, device, output->output); + } +} + +void output_frame_notify(struct wl_listener *listener, void *data) { + struct sample_output *output = wl_container_of(listener, output, frame); + struct sample_state *sample = output->sample; struct wlr_output *wlr_output = output->output; wlr_output_make_current(wlr_output, NULL); @@ -64,46 +104,6 @@ static void handle_output_frame(struct output_state *output, wlr_output_swap_buffers(wlr_output, NULL, NULL); } -static void handle_output_add(struct output_state *ostate) { - struct sample_state *sample = ostate->compositor->data; - - struct output_config *o_config = - example_config_get_output(sample->config, ostate->output); - - if (o_config) { - wlr_output_set_transform(ostate->output, o_config->transform); - wlr_output_layout_add(sample->layout, ostate->output, o_config->x, - o_config->y); - } else { - wlr_output_layout_add_auto(sample->layout, ostate->output); - } - - struct sample_cursor *cursor; - wl_list_for_each(cursor, &sample->cursors, link) { - example_config_configure_cursor(sample->config, cursor->cursor, - sample->compositor); - - struct wlr_xcursor_image *image = sample->xcursor->images[0]; - wlr_cursor_set_image(cursor->cursor, image->buffer, image->width, - image->width, image->height, image->hotspot_x, image->hotspot_y, 0); - - wlr_cursor_warp(cursor->cursor, NULL, cursor->cursor->x, - cursor->cursor->y); - } -} - -static void handle_output_remove(struct output_state *ostate) { - struct sample_state *sample = ostate->compositor->data; - - wlr_output_layout_remove(sample->layout, ostate->output); - - struct sample_cursor *cursor; - wl_list_for_each(cursor, &sample->cursors, link) { - example_config_configure_cursor(sample->config, cursor->cursor, - sample->compositor); - } -} - static void handle_cursor_motion(struct wl_listener *listener, void *data) { struct sample_cursor *cursor = wl_container_of(listener, cursor, cursor_motion); @@ -120,39 +120,6 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener, wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x, event->y); } -static void handle_input_add(struct compositor_state *state, - struct wlr_input_device *device) { - struct sample_state *sample = state->data; - - if (device->type != WLR_INPUT_DEVICE_POINTER) { - return; - } - - struct sample_cursor *cursor = calloc(1, sizeof(struct sample_cursor)); - cursor->state = sample; - cursor->device = device; - - cursor->cursor = wlr_cursor_create(); - wlr_cursor_attach_output_layout(cursor->cursor, sample->layout); - wlr_cursor_map_to_region(cursor->cursor, sample->config->cursor.mapped_box); - - wl_signal_add(&cursor->cursor->events.motion, &cursor->cursor_motion); - cursor->cursor_motion.notify = handle_cursor_motion; - wl_signal_add(&cursor->cursor->events.motion_absolute, - &cursor->cursor_motion_absolute); - cursor->cursor_motion_absolute.notify = handle_cursor_motion_absolute; - - wlr_cursor_attach_input_device(cursor->cursor, device); - example_config_configure_cursor(sample->config, cursor->cursor, - sample->compositor); - - struct wlr_xcursor_image *image = sample->xcursor->images[0]; - wlr_cursor_set_image(cursor->cursor, image->buffer, image->width * 4, - image->width, image->height, image->hotspot_x, image->hotspot_y, 0); - - wl_list_insert(&sample->cursors, &cursor->link); -} - static void cursor_destroy(struct sample_cursor *cursor) { wl_list_remove(&cursor->link); wl_list_remove(&cursor->cursor_motion.link); @@ -161,9 +128,10 @@ static void cursor_destroy(struct sample_cursor *cursor) { free(cursor); } -static void handle_input_remove(struct compositor_state *state, - struct wlr_input_device *device) { - struct sample_state *sample = state->data; +void input_remove_notify(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct sample_cursor *sample_cursor = wl_container_of(listener, sample_cursor, destroy); + struct sample_state *sample = sample_cursor->sample; struct sample_cursor *cursor; wl_list_for_each(cursor, &sample->cursors, link) { if (cursor->device == device) { @@ -171,29 +139,181 @@ static void handle_input_remove(struct compositor_state *state, break; } } + struct sample_pointer *pointer; + wl_list_for_each(pointer, &sample->pointers, link) { + if (pointer->device == device) { + free(pointer); + break; + } + } +} + +void output_remove_notify(struct wl_listener *listener, void *data) { + struct sample_output *sample_output = wl_container_of(listener, sample_output, destroy); + struct sample_state *sample = sample_output->sample; + wl_list_remove(&sample_output->frame.link); + wl_list_remove(&sample_output->destroy.link); + wl_list_remove(&sample_output->link); + free(sample_output); + + struct sample_cursor *cursor; + wl_list_for_each(cursor, &sample->cursors, link) { + configure_cursor(cursor->cursor, cursor->device, sample); + } +} + +void new_output_notify(struct wl_listener *listener, void *data) { + struct wlr_output *output = data; + struct sample_state *sample = wl_container_of(listener, sample, new_output); + struct sample_output *sample_output = calloc(1, sizeof(struct sample_output)); + if (wl_list_length(&output->modes) > 0) { + struct wlr_output_mode *mode = wl_container_of((&output->modes)->prev, mode, link); + wlr_output_set_mode(output, mode); + } + sample_output->output = output; + sample_output->sample = sample; + wl_signal_add(&output->events.frame, &sample_output->frame); + sample_output->frame.notify = output_frame_notify; + wl_signal_add(&output->events.destroy, &sample_output->destroy); + sample_output->destroy.notify = output_remove_notify; + + wlr_output_layout_add_auto(sample->layout, output); + + + struct sample_cursor *cursor; + wl_list_for_each(cursor, &sample->cursors, link) { + configure_cursor(cursor->cursor, cursor->device, sample); + + struct wlr_xcursor_image *image = sample->xcursor->images[0]; + wlr_cursor_set_image(cursor->cursor, image->buffer, image->width * 4, + image->width, image->height, image->hotspot_x, image->hotspot_y, 0); + + wlr_cursor_warp(cursor->cursor, NULL, cursor->cursor->x, + cursor->cursor->y); + } + wl_list_insert(&sample->outputs, &sample_output->link); +} + +void keyboard_key_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, key); + struct sample_state *sample = keyboard->sample; + struct wlr_event_keyboard_key *event = data; + uint32_t keycode = event->keycode + 8; + const xkb_keysym_t *syms; + int nsyms = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + keycode, &syms); + for (int i = 0; i < nsyms; i++) { + xkb_keysym_t sym = syms[i]; + if (sym == XKB_KEY_Escape) { + wl_display_terminate(sample->display); + } + } +} + +void keyboard_destroy_notify(struct wl_listener *listener, void *data) { + struct sample_keyboard *keyboard = wl_container_of(listener, keyboard, destroy); + wl_list_remove(&keyboard->destroy.link); + wl_list_remove(&keyboard->key.link); + free(keyboard); +} + +void new_input_notify(struct wl_listener *listener, void *data) { + struct wlr_input_device *device = data; + struct sample_state *sample = wl_container_of(listener, sample, new_input); + struct sample_keyboard *keyboard; + struct xkb_rule_names rules; + struct xkb_context *context; + struct sample_cursor *cursor = 0; + struct sample_pointer *pointer = 0; + struct wlr_xcursor_image *image; + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + keyboard = calloc(1, sizeof(struct sample_keyboard)); + keyboard->device = device; + keyboard->sample = sample; + wl_signal_add(&device->events.destroy, &keyboard->destroy); + keyboard->destroy.notify = keyboard_destroy_notify; + wl_signal_add(&device->keyboard->events.key, &keyboard->key); + keyboard->key.notify = keyboard_key_notify; + 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"); + context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + wlr_log(L_ERROR, "Failed to create XKB context"); + exit(1); + } + wlr_keyboard_set_keymap(device->keyboard, xkb_map_new_from_names(context, + &rules, XKB_KEYMAP_COMPILE_NO_FLAGS)); + xkb_context_unref(context); + break; + case WLR_INPUT_DEVICE_POINTER: + cursor = calloc(1, sizeof(struct sample_cursor)); + pointer = calloc(1, sizeof(struct sample_pointer)); + pointer->device = device; + cursor->sample = sample; + cursor->device = device; + + cursor->cursor = wlr_cursor_create(); + + wlr_cursor_attach_output_layout(cursor->cursor, sample->layout); + + wl_signal_add(&cursor->cursor->events.motion, &cursor->cursor_motion); + cursor->cursor_motion.notify = handle_cursor_motion; + wl_signal_add(&cursor->cursor->events.motion_absolute, + &cursor->cursor_motion_absolute); + cursor->cursor_motion_absolute.notify = handle_cursor_motion_absolute; + + wlr_cursor_attach_input_device(cursor->cursor, device); + configure_cursor(cursor->cursor, device, sample); + + image = sample->xcursor->images[0]; + wlr_cursor_set_image(cursor->cursor, image->buffer, image->width * 4, + image->width, image->height, image->hotspot_x, image->hotspot_y, 0); + + wl_list_insert(&sample->cursors, &cursor->link); + wl_list_insert(&sample->pointers, &pointer->link); + break; + default: + break; + } } int main(int argc, char *argv[]) { wlr_log_init(L_DEBUG, NULL); + struct wl_display *display = wl_display_create(); struct sample_state state = { .default_color = { 0.25f, 0.25f, 0.25f, 1 }, .clear_color = { 0.25f, 0.25f, 0.25f, 1 }, + .display = display, }; - + struct wlr_backend *wlr = wlr_backend_autocreate(display); + if (!wlr) { + exit(1); + } wl_list_init(&state.cursors); + wl_list_init(&state.pointers); + wl_list_init(&state.outputs); - state.config = parse_args(argc, argv); state.layout = wlr_output_layout_create(); - struct compositor_state compositor = { 0 }; - compositor.data = &state; - compositor.output_add_cb = handle_output_add; - compositor.output_remove_cb = handle_output_remove; - compositor.output_frame_cb = handle_output_frame; - compositor.input_add_cb = handle_input_add; - compositor.input_remove_cb = handle_input_remove; + wl_signal_add(&wlr->events.new_output, &state.new_output); + state.new_output.notify = new_output_notify; + wl_signal_add(&wlr->events.new_input, &state.new_input); + state.new_input.notify = new_input_notify; - state.compositor = &compositor; + clock_gettime(CLOCK_MONOTONIC, &state.last_frame); + + const char *socket = wl_display_add_socket_auto(display); + if (!socket) { + wlr_log_errno(L_ERROR, "Unable to open wayland socket"); + wlr_backend_destroy(wlr); + exit(1); + } + setenv("_WAYLAND_DISPLAY", socket, true); struct wlr_xcursor_theme *theme = wlr_xcursor_theme_load("default", 16); if (!theme) { @@ -206,14 +326,13 @@ int main(int argc, char *argv[]) { return 1; } - compositor_init(&compositor); - if (!wlr_backend_start(compositor.backend)) { + if (!wlr_backend_start(wlr)) { wlr_log(L_ERROR, "Failed to start backend"); - wlr_backend_destroy(compositor.backend); + wlr_backend_destroy(wlr); exit(1); } - wl_display_run(compositor.display); - compositor_fini(&compositor); + wl_display_run(display); + wl_display_destroy(display); struct sample_cursor *cursor, *tmp_cursor; wl_list_for_each_safe(cursor, tmp_cursor, &state.cursors, link) { @@ -221,6 +340,5 @@ int main(int argc, char *argv[]) { } wlr_xcursor_theme_destroy(theme); - example_config_destroy(state.config); wlr_output_layout_destroy(state.layout); }