From e3d47376dc9a7ffef3823cb2b4db78296e3cf717 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 20 Aug 2017 16:02:39 -0400 Subject: [PATCH 01/34] add wlr_cursor basic implementation --- backend/drm/drm.c | 27 +++++ examples/pointer.c | 162 +++++++++++++++++--------- examples/shared.c | 4 + examples/shared.h | 2 + include/wlr/types/wlr_cursor.h | 81 +++++++++++++ types/meson.build | 1 + types/wlr_cursor.c | 206 +++++++++++++++++++++++++++++++++ 7 files changed, 430 insertions(+), 53 deletions(-) create mode 100644 include/wlr/types/wlr_cursor.h create mode 100644 types/wlr_cursor.c diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 332926b9..5b24e05f 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -598,6 +598,8 @@ static bool wlr_drm_output_set_cursor(struct wlr_output *_output, wlr_matrix_texture(plane->matrix, plane->width, plane->height, output->output.transform ^ WL_OUTPUT_TRANSFORM_FLIPPED_180); + // TODO the image needs to be rotated depending on the output rotation + plane->wlr_rend = wlr_gles2_renderer_create(&backend->backend); if (!plane->wlr_rend) { return false; @@ -651,6 +653,31 @@ static bool wlr_drm_output_move_cursor(struct wlr_output *_output, struct wlr_drm_output *output = (struct wlr_drm_output *)_output; struct wlr_drm_backend *backend = wl_container_of(output->renderer, backend, renderer); + + int width, height, tmp; + wlr_output_effective_resolution(_output, &width, &height); + + switch (_output->transform) { + case WL_OUTPUT_TRANSFORM_NORMAL: + // nothing to do + break; + case WL_OUTPUT_TRANSFORM_270: + tmp = x; + x = y; + y = -(tmp - width); + break; + case WL_OUTPUT_TRANSFORM_90: + tmp = x; + x = -(y - height); + y = tmp; + break; + default: + // TODO other transformations + wlr_log(L_ERROR, "TODO: handle surface to crtc for transformation = %d", + _output->transform); + break; + } + return backend->iface->crtc_move_cursor(backend, output->crtc, x, y); } diff --git a/examples/pointer.c b/examples/pointer.c index 12253b62..0092c633 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -16,16 +17,27 @@ #include #include #include +#include #include +#include #include #include "shared.h" #include "cat.h" struct sample_state { - struct wlr_xcursor *cursor; + struct compositor_state *compositor; + struct example_config *config; + struct wlr_xcursor *xcursor; + struct wlr_cursor *cursor; double cur_x, cur_y; float default_color[4]; float clear_color[4]; + struct wlr_output_layout *layout; + + struct wl_listener cursor_motion; + struct wl_listener cursor_motion_absolute; + struct wl_listener cursor_button; + struct wl_listener cursor_axis; }; static void handle_output_frame(struct output_state *output, struct timespec *ts) { @@ -42,59 +54,95 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_swap_buffers(wlr_output); } -static void handle_pointer_motion(struct pointer_state *pstate, - double d_x, double d_y) { - struct sample_state *state = pstate->compositor->data; - state->cur_x += d_x; - state->cur_y += d_y; +static void handle_output_add(struct output_state *ostate) { + struct sample_state *sample = ostate->compositor->data; + struct wlr_output *wlr_output = ostate->output; + struct wlr_xcursor_image *image = sample->xcursor->images[0]; - struct wlr_xcursor_image *image = state->cursor->images[0]; + wlr_output_layout_destroy(sample->layout); + sample->layout = configure_layout(sample->config, &ostate->compositor->outputs); + wlr_cursor_attach_output_layout(sample->cursor, sample->layout); - struct output_state *output; - wl_list_for_each(output, &pstate->compositor->outputs, link) { - wlr_output_move_cursor(output->output, - state->cur_x - image->hotspot_x, - state->cur_y - image->hotspot_y); + if (!wlr_output_set_cursor(wlr_output, image->buffer, + image->width, image->width, image->height)) { + wlr_log(L_DEBUG, "Failed to set hardware cursor"); + return; + } + if (!wlr_output_move_cursor(wlr_output, 0, 0)) { + wlr_log(L_DEBUG, "Failed to move hardware cursor"); } } -static void handle_pointer_motion_absolute(struct pointer_state *pstate, - double x, double y) { - struct sample_state *state = pstate->compositor->data; - state->cur_x = x; - state->cur_y = y; +static void handle_output_remove(struct output_state *ostate) { + struct sample_state *sample = ostate->compositor->data; + wlr_output_layout_destroy(sample->layout); + sample->layout = configure_layout(sample->config, &ostate->compositor->outputs); + wlr_cursor_attach_output_layout(sample->cursor, sample->layout); +} + +static void handle_output_resolution(struct compositor_state *state, + struct output_state *ostate) { + struct sample_state *sample = ostate->compositor->data; + wlr_output_layout_destroy(sample->layout); + sample->layout = configure_layout(sample->config, &ostate->compositor->outputs); + wlr_cursor_attach_output_layout(sample->cursor, sample->layout); +} + +static void handle_input_add(struct compositor_state *state, struct + wlr_input_device *device) { + struct sample_state *sample = state->data; + + // TODO handle other input devices + if (device->type == WLR_INPUT_DEVICE_POINTER) { + wlr_cursor_attach_input_device(sample->cursor, device); + } +} + +static void handle_cursor_motion(struct wl_listener *listener, void *data) { + struct sample_state *sample = wl_container_of(listener, sample, cursor_motion); + struct wlr_event_pointer_motion *event = data; + wlr_cursor_move(sample->cursor, event->delta_x, event->delta_y); +} + +static void handle_cursor_motion_absolute(struct wl_listener *listener, void *data) { + struct sample_state *sample = wl_container_of(listener, sample, cursor_motion_absolute); + struct wlr_event_pointer_motion_absolute *event = data; + + sample->cur_x = event->x_mm; + sample->cur_y = event->y_mm; - struct wlr_xcursor_image *image = state->cursor->images[0]; + struct wlr_xcursor_image *image = sample->xcursor->images[0]; struct output_state *output; - wl_list_for_each(output, &pstate->compositor->outputs, link) { + wl_list_for_each(output, &sample->compositor->outputs, link) { wlr_output_move_cursor(output->output, - state->cur_x - image->hotspot_x, - state->cur_y - image->hotspot_y); + sample->cur_x - image->hotspot_x, + sample->cur_y - image->hotspot_y); } } -static void handle_pointer_button(struct pointer_state *pstate, - uint32_t button, enum wlr_button_state state) { - struct sample_state *sample = pstate->compositor->data; +static void handle_cursor_button(struct wl_listener *listener, void *data) { + struct sample_state *sample = wl_container_of(listener, sample, cursor_button); + struct wlr_event_pointer_button *event = data; + float (*color)[4]; - if (state == WLR_BUTTON_RELEASED) { + if (event->state == WLR_BUTTON_RELEASED) { color = &sample->default_color; + memcpy(&sample->clear_color, color, sizeof(*color)); } else { float red[4] = { 0.25f, 0.25f, 0.25f, 1 }; - red[button % 3] = 1; + red[event->button % 3] = 1; color = &red; + memcpy(&sample->clear_color, color, sizeof(*color)); } - memcpy(&sample->clear_color, color, sizeof(*color)); } -static void handle_pointer_axis(struct pointer_state *pstate, - enum wlr_axis_source source, - enum wlr_axis_orientation orientation, - double delta) { - struct sample_state *sample = pstate->compositor->data; +static void handle_cursor_axis(struct wl_listener *listener, void *data) { + struct sample_state *sample = wl_container_of(listener, sample, cursor_axis); + struct wlr_event_pointer_axis *event = data; + for (size_t i = 0; i < 3; ++i) { - sample->default_color[i] += delta > 0 ? -0.05f : 0.05f; + sample->default_color[i] += event->delta > 0 ? -0.05f : 0.05f; if (sample->default_color[i] > 1.0f) { sample->default_color[i] = 1.0f; } @@ -102,52 +150,60 @@ static void handle_pointer_axis(struct pointer_state *pstate, sample->default_color[i] = 0.0f; } } + memcpy(&sample->clear_color, &sample->default_color, sizeof(sample->clear_color)); } -static void handle_output_add(struct output_state *ostate) { - struct sample_state *state = ostate->compositor->data; - struct wlr_output *wlr_output = ostate->output; - struct wlr_xcursor_image *image = state->cursor->images[0]; - if (!wlr_output_set_cursor(wlr_output, image->buffer, - image->width, image->width, image->height)) { - wlr_log(L_DEBUG, "Failed to set hardware cursor"); - return; - } - if (!wlr_output_move_cursor(wlr_output, 0, 0)) { - wlr_log(L_DEBUG, "Failed to move hardware cursor"); - } -} - int main(int argc, char *argv[]) { struct sample_state state = { .default_color = { 0.25f, 0.25f, 0.25f, 1 }, .clear_color = { 0.25f, 0.25f, 0.25f, 1 } }; + + state.config = parse_args(argc, argv); + state.cursor = wlr_cursor_init(); + + wl_signal_add(&state.cursor->events.motion, &state.cursor_motion); + state.cursor_motion.notify = handle_cursor_motion; + + wl_signal_add(&state.cursor->events.motion_absolute, &state.cursor_motion_absolute); + state.cursor_motion_absolute.notify = handle_cursor_motion_absolute; + + wl_signal_add(&state.cursor->events.button, &state.cursor_button); + state.cursor_button.notify = handle_cursor_button; + + wl_signal_add(&state.cursor->events.axis, &state.cursor_axis); + state.cursor_axis.notify = handle_cursor_axis; + struct compositor_state compositor = { 0 }; compositor.data = &state; compositor.output_add_cb = handle_output_add; + compositor.output_remove_cb = handle_output_remove; + compositor.output_resolution_cb = handle_output_resolution; compositor.output_frame_cb = handle_output_frame; - compositor.pointer_motion_cb = handle_pointer_motion; - compositor.pointer_motion_absolute_cb = handle_pointer_motion_absolute; - compositor.pointer_button_cb = handle_pointer_button; - compositor.pointer_axis_cb = handle_pointer_axis; + compositor.input_add_cb = handle_input_add; + + state.compositor = &compositor; struct wlr_xcursor_theme *theme = wlr_xcursor_theme_load("default", 16); if (!theme) { wlr_log(L_ERROR, "Failed to load cursor theme"); return 1; } - state.cursor = wlr_xcursor_theme_get_cursor(theme, "left_ptr"); - if (!state.cursor) { + state.xcursor = wlr_xcursor_theme_get_cursor(theme, "left_ptr"); + if (!state.xcursor) { wlr_log(L_ERROR, "Failed to load left_ptr cursor"); return 1; } + wlr_cursor_set_xcursor(state.cursor, state.xcursor); + compositor_init(&compositor); wl_display_run(compositor.display); compositor_fini(&compositor); wlr_xcursor_theme_destroy(theme); + example_config_destroy(state.config); + wlr_cursor_destroy(state.cursor); } diff --git a/examples/shared.c b/examples/shared.c index f37140cf..1dad8016 100644 --- a/examples/shared.c +++ b/examples/shared.c @@ -441,6 +441,10 @@ static void input_add_notify(struct wl_listener *listener, void *data) { default: break; } + + if (state->input_add_cb) { + state->input_add_cb(state, device); + } } static void keyboard_remove(struct wlr_input_device *device, struct compositor_state *state) { diff --git a/examples/shared.h b/examples/shared.h index d8007753..d9972ffd 100644 --- a/examples/shared.h +++ b/examples/shared.h @@ -93,6 +93,8 @@ struct tablet_pad_state { }; struct compositor_state { + void (*input_add_cb)(struct compositor_state *compositor, + struct wlr_input_device *device); 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); diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h new file mode 100644 index 00000000..1ea089ef --- /dev/null +++ b/include/wlr/types/wlr_cursor.h @@ -0,0 +1,81 @@ +#ifndef _WLR_TYPES_CURSOR_H +#define _WLR_TYPES_CURSOR_H +#include +#include +#include +#include +#include + +struct wlr_cursor_state; +//struct wlr_cursor_impl *; + +struct wlr_cursor { + struct wlr_cursor_state *state; + //struct wlr_cursor_impl *impl; + int x, y; + + struct { + struct wl_signal motion; + struct wl_signal motion_absolute; + struct wl_signal button; + struct wl_signal axis; + } events; +}; + +struct wlr_cursor *wlr_cursor_init(); + +void wlr_cursor_destroy(struct wlr_cursor *cur); + +void wlr_cursor_set_xcursor(struct wlr_cursor *cur, struct wlr_xcursor *xcur); + +void wlr_cursor_warp(struct wlr_cursor *cur, double x, double y); + +void wlr_cursor_move(struct wlr_cursor *cur, double delta_x, double delta_y); + +/** + * Attaches this input device to this cursor. The input device must be one of: + * + * - WLR_INPUT_DEVICE_POINTER + * - WLR_INPUT_DEVICE_TOUCH + * - WLR_INPUT_DEVICE_TABLET_TOOL + */ +void wlr_cursor_attach_input_device(struct wlr_cursor *cur, + struct wlr_input_device *dev); + +void wlr_cursor_detach_input_device(struct wlr_cursor *cur, + struct wlr_input_device *dev); +/** + * Uses the given layout to establish the boundaries and movement semantics of + * this cursor. Cursors without an output layout allow infinite movement in any + * direction and do not support absolute input events. + */ +void wlr_cursor_attach_output_layout(struct wlr_cursor *cur, + struct wlr_output_layout *l); + +/** + * Attaches this cursor to the given output, which must be among the outputs in + * the current output_layout for this cursor. This call is invalid for a cursor + * without an associated output layout. + */ +void wlr_cursor_map_to_output(struct wlr_cursor *cur, struct wlr_output *output); + +/** + * Maps all input from a specific input device to a given output. The input + * device must be attached to this cursor and the output must be among the + * outputs in the attached output layout. + */ +void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, + struct wlr_input_device *dev, struct wlr_output *output); + +/** + * Maps this cursor to an arbitrary region on the associated wlr_output_layout. + */ +//void wlr_cursor_map_to_region(struct wlr_cursor *cur, struct wlr_geometry *geo); + +/** + * Maps inputs from this input device to an arbitrary region on the associated + * wlr_output_layout. + */ +//void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, struct wlr_input_device *dev, struct wlr_geometry *geo); + +#endif diff --git a/types/meson.build b/types/meson.build index 83b4647c..3992c6e9 100644 --- a/types/meson.build +++ b/types/meson.build @@ -6,6 +6,7 @@ lib_wlr_types = static_library('wlr_types', files( 'wlr_output.c', 'wlr_output_layout.c', 'wlr_pointer.c', + 'wlr_cursor.c', 'wlr_region.c', 'wlr_seat.c', 'wlr_surface.c', diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c new file mode 100644 index 00000000..ed53fa7e --- /dev/null +++ b/types/wlr_cursor.c @@ -0,0 +1,206 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +struct wlr_cursor_device { + struct wlr_cursor *cursor; + struct wlr_input_device *device; + struct wl_list link; + + struct wl_listener motion; + struct wl_listener motion_absolute; + struct wl_listener button; + struct wl_listener axis; +}; + +struct wlr_cursor_state { + struct wl_list devices; + struct wlr_output_layout *layout; + struct wlr_xcursor *xcursor; +}; + +struct wlr_cursor *wlr_cursor_init() { + struct wlr_cursor *cur = calloc(1, sizeof(struct wlr_cursor)); + if (!cur) { + wlr_log(L_ERROR, "Failed to allocate wlr_cursor"); + return NULL; + } + + cur->state = calloc(1, sizeof(struct wlr_cursor_state)); + if (!cur->state) { + wlr_log(L_ERROR, "Failed to allocate wlr_cursor_state"); + return NULL; + } + + wl_list_init(&cur->state->devices); + + wl_signal_init(&cur->events.motion); + wl_signal_init(&cur->events.motion_absolute); + wl_signal_init(&cur->events.button); + wl_signal_init(&cur->events.axis); + + cur->x = 100; + cur->y = 100; + + return cur; +} + +void wlr_cursor_destroy(struct wlr_cursor *cur) { + struct wlr_cursor_device *device; + wl_list_for_each(device, &cur->state->devices, link) { + wl_list_remove(&device->link); + free(device); + } + + free(cur); +} + +void wlr_cursor_set_xcursor(struct wlr_cursor *cur, struct wlr_xcursor *xcur) { + cur->state->xcursor = xcur; +} + +void wlr_cursor_warp(struct wlr_cursor *cur, double x, double y) { +} + +void wlr_cursor_move(struct wlr_cursor *cur, double delta_x, double delta_y) { + //struct wlr_output *current_output; + //current_output = wlr_output_layout_output_at(cur->state->layout, cur->x, cur->y); + + // TODO handle no layout + assert(cur->state->layout); + // TODO handle layout boundaries + double new_x = cur->x + delta_x; + double new_y = cur->y + delta_y; + int hotspot_x = 0; + int hotspot_y = 0; + + if (cur->state->xcursor && cur->state->xcursor->image_count > 0) { + struct wlr_xcursor_image *image = cur->state->xcursor->images[0]; + hotspot_x = image->hotspot_x; + hotspot_y = image->hotspot_y; + } + + struct wlr_output *output; + output = wlr_output_layout_output_at(cur->state->layout, new_x, new_y); + + if (output) { + int output_x = new_x; + int output_y = new_y; + + // TODO fix double to int rounding issues + wlr_output_layout_output_coords(cur->state->layout, output, &output_x, &output_y); + wlr_output_move_cursor(output, output_x - hotspot_x, output_y - hotspot_y); + + cur->x = new_x; + cur->y = new_y; + } +} + +static void handle_pointer_motion(struct wl_listener *listener, void *data) { + struct wlr_event_pointer_motion *event = data; + struct wlr_cursor_device *device = wl_container_of(listener, device, motion); + wl_signal_emit(&device->cursor->events.motion, event); +} + +static void handle_pointer_motion_absolute(struct wl_listener *listener, void *data) { + struct wlr_event_pointer_motion_absolute *event = data; + struct wlr_cursor_device *device = wl_container_of(listener, device, motion_absolute); + wl_signal_emit(&device->cursor->events.motion_absolute, event); +} + +static void handle_pointer_button(struct wl_listener *listener, void *data) { + struct wlr_event_pointer_button *event = data; + struct wlr_cursor_device *device = wl_container_of(listener, device, button); + wl_signal_emit(&device->cursor->events.button, event); +} + +static void handle_pointer_axis(struct wl_listener *listener, void *data) { + struct wlr_event_pointer_axis *event = data; + struct wlr_cursor_device *device = wl_container_of(listener, device, axis); + wl_signal_emit(&device->cursor->events.axis, event); +} + +void wlr_cursor_attach_input_device(struct wlr_cursor *cur, + struct wlr_input_device *dev) { + if (dev->type != WLR_INPUT_DEVICE_POINTER && + dev->type != WLR_INPUT_DEVICE_TOUCH && + dev->type != WLR_INPUT_DEVICE_TABLET_TOOL) { + wlr_log(L_ERROR, "only device types of pointer, touch or tablet tool are" + "supported"); + return; + } + + // TODO support other device types + if (dev->type != WLR_INPUT_DEVICE_POINTER) { + wlr_log(L_ERROR, "TODO: support touch and tablet tool devices"); + return; + } + + // make sure it is not already attached + struct wlr_cursor_device *_dev; + wl_list_for_each(_dev, &cur->state->devices, link) { + if (_dev->device == dev) { + return; + } + } + + struct wlr_cursor_device *device = calloc(1, sizeof(struct wlr_cursor_device)); + if (!device) { + wlr_log(L_ERROR, "Failed to allocate wlr_cursor_device"); + return; + } + + device->cursor = cur; + device->device = dev; + + // listen to events + wl_signal_add(&dev->pointer->events.motion, &device->motion); + device->motion.notify = handle_pointer_motion; + + wl_signal_add(&dev->pointer->events.motion_absolute, &device->motion_absolute); + device->motion_absolute.notify = handle_pointer_motion_absolute; + + wl_signal_add(&dev->pointer->events.button, &device->button); + device->button.notify = handle_pointer_button; + + wl_signal_add(&dev->pointer->events.axis, &device->axis); + device->axis.notify = handle_pointer_axis; + + wl_list_insert(&cur->state->devices, &device->link); +} + +void wlr_cursor_detach_input_device(struct wlr_cursor *cur, + struct wlr_input_device *dev) { + struct wlr_cursor_device *target_device = NULL, *_device = NULL; + wl_list_for_each(_device, &cur->state->devices, link) { + if (_device->device == dev) { + target_device = _device; + break; + } + } + + if (target_device) { + wl_list_remove(&target_device->link); + free(target_device); + } +} + +void wlr_cursor_attach_output_layout(struct wlr_cursor *cur, + struct wlr_output_layout *l) { + cur->state->layout = l; +} + +void wlr_cursor_map_to_output(struct wlr_cursor *cur, + struct wlr_output *output) { + wlr_log(L_DEBUG, "TODO: map to output"); +} + +void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, + struct wlr_input_device *dev, struct wlr_output *output) { + wlr_log(L_DEBUG, "TODO map input to output"); +} From 9978349903f8cc31c6dbf4a807c1f456ccecd5a4 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 24 Aug 2017 09:04:19 -0400 Subject: [PATCH 02/34] use safe for_each when freeing cursor devices --- types/wlr_cursor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index ed53fa7e..93ba3478 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -51,8 +51,8 @@ struct wlr_cursor *wlr_cursor_init() { } void wlr_cursor_destroy(struct wlr_cursor *cur) { - struct wlr_cursor_device *device; - wl_list_for_each(device, &cur->state->devices, link) { + struct wlr_cursor_device *device, *tmp = NULL; + wl_list_for_each_safe(device, tmp, &cur->state->devices, link) { wl_list_remove(&device->link); free(device); } From 431e1ddeca29cc12699d3da6073f4d6b3f97530e Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 24 Aug 2017 09:18:42 -0400 Subject: [PATCH 03/34] smooth pointer transitioning between outputs --- types/wlr_cursor.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 93ba3478..af977632 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -85,16 +85,20 @@ void wlr_cursor_move(struct wlr_cursor *cur, double delta_x, double delta_y) { hotspot_y = image->hotspot_y; } - struct wlr_output *output; - output = wlr_output_layout_output_at(cur->state->layout, new_x, new_y); - - if (output) { - int output_x = new_x; - int output_y = new_y; - - // TODO fix double to int rounding issues - wlr_output_layout_output_coords(cur->state->layout, output, &output_x, &output_y); - wlr_output_move_cursor(output, output_x - hotspot_x, output_y - hotspot_y); + if (wlr_output_layout_output_at(cur->state->layout, new_x, new_y)) { + //struct wlr_output *output; + //output = wlr_output_layout_output_at(cur->state->layout, new_x, new_y); + struct wlr_output_layout_output *l_output; + wl_list_for_each(l_output, &cur->state->layout->outputs, link) { + int output_x = new_x; + int output_y = new_y; + + // TODO fix double to int rounding issues + wlr_output_layout_output_coords(cur->state->layout, + l_output->output, &output_x, &output_y); + wlr_output_move_cursor(l_output->output, output_x - hotspot_x, + output_y - hotspot_y); + } cur->x = new_x; cur->y = new_y; From dd68f680e4bda23a723fc68aca9586ae3d3a018a Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 24 Aug 2017 10:11:57 -0400 Subject: [PATCH 04/34] handle cursor to output edge cases --- include/wlr/types/wlr_output_layout.h | 6 ++++ types/wlr_cursor.c | 34 +++++++++++--------- types/wlr_output_layout.c | 46 +++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 15 deletions(-) diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index f6a1efdd..52cc9423 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -46,4 +46,10 @@ bool wlr_output_layout_contains_point(struct wlr_output_layout *layout, bool wlr_output_layout_intersects(struct wlr_output_layout *layout, struct wlr_output *reference, int x1, int y1, int x2, int y2); +/** + * Get the closest boundary point of this layout from the given point. + */ +void wlr_output_layout_closest_boundary(struct wlr_output_layout *layout, + int x, int y, int *dest_x, int *dest_y); + #endif diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index af977632..84224ac9 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -73,7 +73,7 @@ void wlr_cursor_move(struct wlr_cursor *cur, double delta_x, double delta_y) { // TODO handle no layout assert(cur->state->layout); - // TODO handle layout boundaries + double new_x = cur->x + delta_x; double new_y = cur->y + delta_y; int hotspot_x = 0; @@ -85,24 +85,28 @@ void wlr_cursor_move(struct wlr_cursor *cur, double delta_x, double delta_y) { hotspot_y = image->hotspot_y; } - if (wlr_output_layout_output_at(cur->state->layout, new_x, new_y)) { - //struct wlr_output *output; - //output = wlr_output_layout_output_at(cur->state->layout, new_x, new_y); - struct wlr_output_layout_output *l_output; - wl_list_for_each(l_output, &cur->state->layout->outputs, link) { - int output_x = new_x; - int output_y = new_y; + if (!wlr_output_layout_output_at(cur->state->layout, new_x, new_y)) { + int closest_x, closest_y; + wlr_output_layout_closest_boundary(cur->state->layout, new_x, new_y, + &closest_x, &closest_y); + new_x = closest_x; + new_y = closest_y; + } + + struct wlr_output_layout_output *l_output; + wl_list_for_each(l_output, &cur->state->layout->outputs, link) { + int output_x = new_x; + int output_y = new_y; - // TODO fix double to int rounding issues - wlr_output_layout_output_coords(cur->state->layout, + // TODO fix double to int rounding issues + wlr_output_layout_output_coords(cur->state->layout, l_output->output, &output_x, &output_y); - wlr_output_move_cursor(l_output->output, output_x - hotspot_x, + wlr_output_move_cursor(l_output->output, output_x - hotspot_x, output_y - hotspot_y); - } - - cur->x = new_x; - cur->y = new_y; } + + cur->x = new_x; + cur->y = new_y; } static void handle_pointer_motion(struct wl_listener *listener, void *data) { diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 2e2032b3..3593eae6 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -126,3 +127,48 @@ void wlr_output_layout_output_coords(struct wlr_output_layout *layout, } } } + +static double get_distance(double x1, double y1, double x2, double y2) { + double distance; + distance = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + return distance; +} + +void wlr_output_layout_closest_boundary(struct wlr_output_layout *layout, + int x, int y, int *dest_x, int *dest_y) { + int min_x = INT_MAX, min_y = INT_MAX, min_distance = INT_MAX; + struct wlr_output_layout_output *l_output; + wl_list_for_each(l_output, &layout->outputs, link) { + int width, height, output_x, output_y, output_distance; + wlr_output_effective_resolution(l_output->output, &width, &height); + + // find the closest x point + if (x < l_output->x) { + output_x = l_output->x; + } else if (x > l_output->x + width) { + output_x = l_output->x + width; + } else { + output_x = x; + } + + // find closest y point + if (y < l_output->y) { + output_y = l_output->y; + } else if (y > l_output->y + height) { + output_y = l_output->y + height; + } else { + output_y = y; + } + + // calculate distance + output_distance = get_distance(output_x, output_y, x, y); + if (output_distance < min_distance) { + min_x = output_x; + min_y = output_y; + min_distance = output_distance; + } + } + + *dest_x = min_x; + *dest_y = min_y; +} From 0cba06dcef791d8dc1702270cae2915936380a46 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 24 Aug 2017 10:42:05 -0400 Subject: [PATCH 05/34] implement wlr_cursor_warp --- include/wlr/types/wlr_cursor.h | 11 ++++++- types/wlr_cursor.c | 54 +++++++++++++++++++--------------- 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index 1ea089ef..380d8a6f 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -28,8 +28,17 @@ void wlr_cursor_destroy(struct wlr_cursor *cur); void wlr_cursor_set_xcursor(struct wlr_cursor *cur, struct wlr_xcursor *xcur); -void wlr_cursor_warp(struct wlr_cursor *cur, double x, double y); +/** + * Warp the cursor to the given x and y in layout coordinates. If x and y are + * out of the layout boundaries or constraints, no warp will happen. + * + * Returns true when the mouse warp was successful. + */ +bool wlr_cursor_warp(struct wlr_cursor *cur, double x, double y); +/** + * Move the cursor in the direction of the given x and y coordinates. + */ void wlr_cursor_move(struct wlr_cursor *cur, double delta_x, double delta_y); /** diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 84224ac9..948ab550 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -64,18 +64,11 @@ void wlr_cursor_set_xcursor(struct wlr_cursor *cur, struct wlr_xcursor *xcur) { cur->state->xcursor = xcur; } -void wlr_cursor_warp(struct wlr_cursor *cur, double x, double y) { -} - -void wlr_cursor_move(struct wlr_cursor *cur, double delta_x, double delta_y) { - //struct wlr_output *current_output; - //current_output = wlr_output_layout_output_at(cur->state->layout, cur->x, cur->y); - - // TODO handle no layout - assert(cur->state->layout); +bool wlr_cursor_warp(struct wlr_cursor *cur, double x, double y) { + if (!wlr_output_layout_output_at(cur->state->layout, x, y)) { + return false; + } - double new_x = cur->x + delta_x; - double new_y = cur->y + delta_y; int hotspot_x = 0; int hotspot_y = 0; @@ -85,28 +78,41 @@ void wlr_cursor_move(struct wlr_cursor *cur, double delta_x, double delta_y) { hotspot_y = image->hotspot_y; } - if (!wlr_output_layout_output_at(cur->state->layout, new_x, new_y)) { - int closest_x, closest_y; - wlr_output_layout_closest_boundary(cur->state->layout, new_x, new_y, - &closest_x, &closest_y); - new_x = closest_x; - new_y = closest_y; - } struct wlr_output_layout_output *l_output; wl_list_for_each(l_output, &cur->state->layout->outputs, link) { - int output_x = new_x; - int output_y = new_y; + int output_x = x; + int output_y = y; // TODO fix double to int rounding issues wlr_output_layout_output_coords(cur->state->layout, - l_output->output, &output_x, &output_y); + l_output->output, &output_x, &output_y); wlr_output_move_cursor(l_output->output, output_x - hotspot_x, - output_y - hotspot_y); + output_y - hotspot_y); + } + + return true; +} + +void wlr_cursor_move(struct wlr_cursor *cur, double delta_x, double delta_y) { + // TODO handle no layout + assert(cur->state->layout); + + int x = cur->x + delta_x; + int y = cur->y + delta_y; + + if (!wlr_output_layout_output_at(cur->state->layout, x, y)) { + int closest_x, closest_y; + wlr_output_layout_closest_boundary(cur->state->layout, x, y, &closest_x, + &closest_y); + x = closest_x; + y = closest_y; } - cur->x = new_x; - cur->y = new_y; + if (wlr_cursor_warp(cur, x, y)) { + cur->x = x; + cur->y = y; + } } static void handle_pointer_motion(struct wl_listener *listener, void *data) { From f69a7afd369d4febdd2c14519bf11dab65fccc24 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 24 Aug 2017 10:53:11 -0400 Subject: [PATCH 06/34] assert cursor layout for move and warp functions --- types/wlr_cursor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 948ab550..9a303d37 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -65,6 +65,7 @@ void wlr_cursor_set_xcursor(struct wlr_cursor *cur, struct wlr_xcursor *xcur) { } bool wlr_cursor_warp(struct wlr_cursor *cur, double x, double y) { + assert(cur->state->layout); if (!wlr_output_layout_output_at(cur->state->layout, x, y)) { return false; } @@ -95,7 +96,6 @@ bool wlr_cursor_warp(struct wlr_cursor *cur, double x, double y) { } void wlr_cursor_move(struct wlr_cursor *cur, double delta_x, double delta_y) { - // TODO handle no layout assert(cur->state->layout); int x = cur->x + delta_x; From a4810203ccfcdba2460331b46d7be4d9535f904a Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 24 Aug 2017 11:46:40 -0400 Subject: [PATCH 07/34] change output layout coords to double type --- examples/output-layout.c | 4 ++-- include/wlr/types/wlr_output_layout.h | 2 +- types/wlr_cursor.c | 5 ++--- types/wlr_output_layout.c | 10 +++++----- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/examples/output-layout.c b/examples/output-layout.c index 0dcbc1f8..041d5788 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -49,8 +49,8 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts float matrix[16]; // transform global coordinates to local coordinates - int local_x = sample->x_offs; - int local_y = sample->y_offs; + double local_x = sample->x_offs; + double local_y = sample->y_offs; wlr_output_layout_output_coords(sample->layout, output->output, &local_x, &local_y); diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index 52cc9423..9094f02f 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -38,7 +38,7 @@ void wlr_output_layout_remove(struct wlr_output_layout *layout, * coordinates relative to the given reference output. */ void wlr_output_layout_output_coords(struct wlr_output_layout *layout, - struct wlr_output *reference, int *x, int *y); + struct wlr_output *reference, double *x, double *y); bool wlr_output_layout_contains_point(struct wlr_output_layout *layout, struct wlr_output *reference, int x, int y); diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 9a303d37..c9937c73 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -82,10 +82,9 @@ bool wlr_cursor_warp(struct wlr_cursor *cur, double x, double y) { struct wlr_output_layout_output *l_output; wl_list_for_each(l_output, &cur->state->layout->outputs, link) { - int output_x = x; - int output_y = y; + double output_x = x; + double output_y = y; - // TODO fix double to int rounding issues wlr_output_layout_output_coords(cur->state->layout, l_output->output, &output_x, &output_y); wlr_output_move_cursor(l_output->output, output_x - hotspot_x, diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 3593eae6..a26a4794 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -113,16 +113,16 @@ void wlr_output_layout_remove(struct wlr_output_layout *layout, } void wlr_output_layout_output_coords(struct wlr_output_layout *layout, - struct wlr_output *reference, int *x, int *y) { + struct wlr_output *reference, double *x, double *y) { assert(layout && reference); - int src_x = *x; - int src_y = *y; + double src_x = *x; + double src_y = *y; struct wlr_output_layout_output *_output; wl_list_for_each(_output, &layout->outputs, link) { if (_output->output == reference) { - *x = src_x - _output->x; - *y = src_y - _output->y; + *x = src_x - (double)_output->x; + *y = src_y - (double)_output->y; return; } } From 13e895d943eca5e86f68230c5ca503090866aafc Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 24 Aug 2017 12:30:34 -0400 Subject: [PATCH 08/34] implement wlr_cursor_map_to_output --- include/wlr/types/wlr_output_layout.h | 7 ++++-- types/wlr_cursor.c | 31 ++++++++++++++++++++------- types/wlr_output_layout.c | 12 ++++++++--- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index 9094f02f..144c2d5a 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -47,9 +47,12 @@ bool wlr_output_layout_intersects(struct wlr_output_layout *layout, struct wlr_output *reference, int x1, int y1, int x2, int y2); /** - * Get the closest boundary point of this layout from the given point. + * Get the closest boundary point of this layout from the given point from the + * reference output. If reference is NULL, gets the closest boundary point from + * the entire layout. */ void wlr_output_layout_closest_boundary(struct wlr_output_layout *layout, - int x, int y, int *dest_x, int *dest_y); + struct wlr_output *reference, double x, double y, double *dest_x, + double *dest_y); #endif diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index c9937c73..affdcdeb 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -22,6 +22,7 @@ struct wlr_cursor_state { struct wl_list devices; struct wlr_output_layout *layout; struct wlr_xcursor *xcursor; + struct wlr_output *mapped_output; }; struct wlr_cursor *wlr_cursor_init() { @@ -37,6 +38,8 @@ struct wlr_cursor *wlr_cursor_init() { return NULL; } + cur->state->mapped_output = NULL; + wl_list_init(&cur->state->devices); wl_signal_init(&cur->events.motion); @@ -66,7 +69,16 @@ void wlr_cursor_set_xcursor(struct wlr_cursor *cur, struct wlr_xcursor *xcur) { bool wlr_cursor_warp(struct wlr_cursor *cur, double x, double y) { assert(cur->state->layout); - if (!wlr_output_layout_output_at(cur->state->layout, x, y)) { + struct wlr_output *output; + output = wlr_output_layout_output_at(cur->state->layout, x, y); + + if (!output) { + return false; + } + + if (cur->state->mapped_output && + !wlr_output_layout_contains_point(cur->state->layout, + cur->state->mapped_output, x, y)) { return false; } @@ -97,13 +109,16 @@ bool wlr_cursor_warp(struct wlr_cursor *cur, double x, double y) { void wlr_cursor_move(struct wlr_cursor *cur, double delta_x, double delta_y) { assert(cur->state->layout); - int x = cur->x + delta_x; - int y = cur->y + delta_y; + double x = cur->x + delta_x; + double y = cur->y + delta_y; + + struct wlr_output *output; + output = wlr_output_layout_output_at(cur->state->layout, x, y); - if (!wlr_output_layout_output_at(cur->state->layout, x, y)) { - int closest_x, closest_y; - wlr_output_layout_closest_boundary(cur->state->layout, x, y, &closest_x, - &closest_y); + if (!output || (cur->state->mapped_output && cur->state->mapped_output != output)) { + double closest_x, closest_y; + wlr_output_layout_closest_boundary(cur->state->layout, + cur->state->mapped_output, x, y, &closest_x, &closest_y); x = closest_x; y = closest_y; } @@ -210,7 +225,7 @@ void wlr_cursor_attach_output_layout(struct wlr_cursor *cur, void wlr_cursor_map_to_output(struct wlr_cursor *cur, struct wlr_output *output) { - wlr_log(L_DEBUG, "TODO: map to output"); + cur->state->mapped_output = output; } void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index a26a4794..5e2067da 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -135,11 +135,17 @@ static double get_distance(double x1, double y1, double x2, double y2) { } void wlr_output_layout_closest_boundary(struct wlr_output_layout *layout, - int x, int y, int *dest_x, int *dest_y) { - int min_x = INT_MAX, min_y = INT_MAX, min_distance = INT_MAX; + struct wlr_output *reference, double x, double y, double *dest_x, + double *dest_y) { + double min_x = INT_MAX, min_y = INT_MAX, min_distance = INT_MAX; struct wlr_output_layout_output *l_output; wl_list_for_each(l_output, &layout->outputs, link) { - int width, height, output_x, output_y, output_distance; + if (reference != NULL && reference != l_output->output) { + continue; + } + + int width, height; + double output_x, output_y, output_distance; wlr_output_effective_resolution(l_output->output, &width, &height); // find the closest x point From 98f4cdfccb7d2ace2929bca45f0479b3472b96ac Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 24 Aug 2017 14:35:55 -0400 Subject: [PATCH 09/34] implement wlr_cursor_map_input_to_output --- backend/libinput/pointer.c | 4 +++ backend/wayland/wl_seat.c | 3 ++ examples/pointer.c | 33 ++++++++++++++++- include/wlr/types/wlr_cursor.h | 12 +++++-- include/wlr/types/wlr_pointer.h | 4 +++ types/wlr_cursor.c | 63 ++++++++++++++++++++++++++------- 6 files changed, 104 insertions(+), 15 deletions(-) diff --git a/backend/libinput/pointer.c b/backend/libinput/pointer.c index 8bda205d..005c9516 100644 --- a/backend/libinput/pointer.c +++ b/backend/libinput/pointer.c @@ -30,6 +30,7 @@ void handle_pointer_motion(struct libinput_event *event, struct libinput_event_pointer *pevent = libinput_event_get_pointer_event(event); struct wlr_event_pointer_motion wlr_event = { 0 }; + wlr_event.device = wlr_dev; wlr_event.time_sec = libinput_event_pointer_get_time(pevent); wlr_event.time_usec = libinput_event_pointer_get_time_usec(pevent); wlr_event.delta_x = libinput_event_pointer_get_dx(pevent); @@ -48,6 +49,7 @@ void handle_pointer_motion_abs(struct libinput_event *event, struct libinput_event_pointer *pevent = libinput_event_get_pointer_event(event); struct wlr_event_pointer_motion_absolute wlr_event = { 0 }; + wlr_event.device = wlr_dev; wlr_event.time_sec = libinput_event_pointer_get_time(pevent); wlr_event.time_usec = libinput_event_pointer_get_time_usec(pevent); wlr_event.x_mm = libinput_event_pointer_get_absolute_x(pevent); @@ -67,6 +69,7 @@ void handle_pointer_button(struct libinput_event *event, struct libinput_event_pointer *pevent = libinput_event_get_pointer_event(event); struct wlr_event_pointer_button wlr_event = { 0 }; + wlr_event.device = wlr_dev; wlr_event.time_sec = libinput_event_pointer_get_time(pevent); wlr_event.time_usec = libinput_event_pointer_get_time_usec(pevent); wlr_event.button = libinput_event_pointer_get_button(pevent); @@ -92,6 +95,7 @@ void handle_pointer_axis(struct libinput_event *event, struct libinput_event_pointer *pevent = libinput_event_get_pointer_event(event); struct wlr_event_pointer_axis wlr_event = { 0 }; + wlr_event.device = wlr_dev; wlr_event.time_sec = libinput_event_pointer_get_time(pevent); wlr_event.time_usec = libinput_event_pointer_get_time_usec(pevent); switch (libinput_event_pointer_get_axis_source(pevent)) { diff --git a/backend/wayland/wl_seat.c b/backend/wayland/wl_seat.c index a4cc0ba5..3e6982a0 100644 --- a/backend/wayland/wl_seat.c +++ b/backend/wayland/wl_seat.c @@ -51,6 +51,7 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer, wl_egl_window_get_attached_size(wlr_wl_pointer->current_output->egl_window, &width, &height); struct wlr_event_pointer_motion_absolute wlr_event; + wlr_event.device = dev; wlr_event.time_sec = time / 1000; wlr_event.time_usec = time * 1000; wlr_event.width_mm = width; @@ -66,6 +67,7 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, assert(dev && dev->pointer); struct wlr_event_pointer_button wlr_event; + wlr_event.device = dev; wlr_event.button = button; wlr_event.state = state; wlr_event.time_sec = time / 1000; @@ -80,6 +82,7 @@ static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, struct wlr_wl_pointer *wlr_wl_pointer = (struct wlr_wl_pointer *)dev->pointer; struct wlr_event_pointer_axis wlr_event; + wlr_event.device = dev; wlr_event.delta = value; wlr_event.orientation = axis; wlr_event.time_sec = time / 1000; diff --git a/examples/pointer.c b/examples/pointer.c index 0092c633..95e28bb2 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -24,6 +24,11 @@ #include "shared.h" #include "cat.h" +struct sample_input_device { + struct wlr_input_device *device; + struct wl_list link; +}; + struct sample_state { struct compositor_state *compositor; struct example_config *config; @@ -33,6 +38,7 @@ struct sample_state { float default_color[4]; float clear_color[4]; struct wlr_output_layout *layout; + struct wl_list devices; struct wl_listener cursor_motion; struct wl_listener cursor_motion_absolute; @@ -63,6 +69,16 @@ static void handle_output_add(struct output_state *ostate) { sample->layout = configure_layout(sample->config, &ostate->compositor->outputs); wlr_cursor_attach_output_layout(sample->cursor, sample->layout); + /* + // TODO configuration + if (strcmp("DP-1", ostate->output->name) == 0) { + struct sample_input_device *dev; + wl_list_for_each(dev, &sample->devices, link) { + wlr_cursor_map_input_to_output(sample->cursor, dev->device, ostate->output); + } + } + */ + if (!wlr_output_set_cursor(wlr_output, image->buffer, image->width, image->width, image->height)) { wlr_log(L_DEBUG, "Failed to set hardware cursor"); @@ -94,6 +110,20 @@ static void handle_input_add(struct compositor_state *state, struct // TODO handle other input devices if (device->type == WLR_INPUT_DEVICE_POINTER) { + struct sample_input_device *s_device = calloc(1, sizeof(struct sample_input_device)); + s_device->device = device; + wl_list_insert(&sample->devices, &s_device->link); + + /* + // TODO configuration + struct output_state *ostate; + wl_list_for_each(ostate, &sample->compositor->outputs, link) { + if (strcmp(ostate->output->name, "DP-1") == 0) { + wlr_cursor_map_input_to_output(sample->cursor, device, ostate->output); + } + } + */ + wlr_cursor_attach_input_device(sample->cursor, device); } } @@ -101,7 +131,7 @@ static void handle_input_add(struct compositor_state *state, struct static void handle_cursor_motion(struct wl_listener *listener, void *data) { struct sample_state *sample = wl_container_of(listener, sample, cursor_motion); struct wlr_event_pointer_motion *event = data; - wlr_cursor_move(sample->cursor, event->delta_x, event->delta_y); + wlr_cursor_move(sample->cursor, event->device, event->delta_x, event->delta_y); } static void handle_cursor_motion_absolute(struct wl_listener *listener, void *data) { @@ -163,6 +193,7 @@ int main(int argc, char *argv[]) { state.config = parse_args(argc, argv); state.cursor = wlr_cursor_init(); + wl_list_init(&state.devices); wl_signal_add(&state.cursor->events.motion, &state.cursor_motion); state.cursor_motion.notify = handle_cursor_motion; diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index 380d8a6f..64a75e4f 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -32,14 +32,22 @@ void wlr_cursor_set_xcursor(struct wlr_cursor *cur, struct wlr_xcursor *xcur); * Warp the cursor to the given x and y in layout coordinates. If x and y are * out of the layout boundaries or constraints, no warp will happen. * + * `dev` may be passed to respect device mapping constraints. If `dev` is NULL, + * device mapping constraints will be ignored. + * * Returns true when the mouse warp was successful. */ -bool wlr_cursor_warp(struct wlr_cursor *cur, double x, double y); +bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev, + double x, double y); /** * Move the cursor in the direction of the given x and y coordinates. + * + * `dev` may be passed to respect device mapping constraints. If `dev` is NULL, + * device mapping constraints will be ignored. */ -void wlr_cursor_move(struct wlr_cursor *cur, double delta_x, double delta_y); +void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, + double delta_x, double delta_y); /** * Attaches this input device to this cursor. The input device must be one of: diff --git a/include/wlr/types/wlr_pointer.h b/include/wlr/types/wlr_pointer.h index 13a2d045..9153963a 100644 --- a/include/wlr/types/wlr_pointer.h +++ b/include/wlr/types/wlr_pointer.h @@ -20,12 +20,14 @@ struct wlr_pointer { }; struct wlr_event_pointer_motion { + struct wlr_input_device *device; uint32_t time_sec; uint64_t time_usec; double delta_x, delta_y; }; struct wlr_event_pointer_motion_absolute { + struct wlr_input_device *device; uint32_t time_sec; uint64_t time_usec; double x_mm, y_mm; @@ -33,6 +35,7 @@ struct wlr_event_pointer_motion_absolute { }; struct wlr_event_pointer_button { + struct wlr_input_device *device; uint32_t time_sec; uint64_t time_usec; uint32_t button; @@ -52,6 +55,7 @@ enum wlr_axis_orientation { }; struct wlr_event_pointer_axis { + struct wlr_input_device *device; uint32_t time_sec; uint64_t time_usec; enum wlr_axis_source source; diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index affdcdeb..6917526e 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -11,6 +11,7 @@ struct wlr_cursor_device { struct wlr_cursor *cursor; struct wlr_input_device *device; struct wl_list link; + struct wlr_output *mapped_output; struct wl_listener motion; struct wl_listener motion_absolute; @@ -54,8 +55,8 @@ struct wlr_cursor *wlr_cursor_init() { } void wlr_cursor_destroy(struct wlr_cursor *cur) { - struct wlr_cursor_device *device, *tmp = NULL; - wl_list_for_each_safe(device, tmp, &cur->state->devices, link) { + struct wlr_cursor_device *device, *device_tmp = NULL; + wl_list_for_each_safe(device, device_tmp, &cur->state->devices, link) { wl_list_remove(&device->link); free(device); } @@ -67,18 +68,41 @@ void wlr_cursor_set_xcursor(struct wlr_cursor *cur, struct wlr_xcursor *xcur) { cur->state->xcursor = xcur; } -bool wlr_cursor_warp(struct wlr_cursor *cur, double x, double y) { +static struct wlr_cursor_device *get_cursor_device(struct wlr_cursor *cur, + struct wlr_input_device *device) { + struct wlr_cursor_device *c_device, *ret = NULL; + wl_list_for_each(c_device, &cur->state->devices, link) { + if (c_device->device == device) { + ret = c_device; + break; + } + } + + return ret; +} + +bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev, + double x, double y) { assert(cur->state->layout); struct wlr_output *output; output = wlr_output_layout_output_at(cur->state->layout, x, y); + struct wlr_output *mapped_output = NULL; + struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); + + if (c_device && c_device->mapped_output) { + mapped_output = c_device->mapped_output; + } else { + mapped_output = cur->state->mapped_output; + } + if (!output) { return false; } - if (cur->state->mapped_output && - !wlr_output_layout_contains_point(cur->state->layout, - cur->state->mapped_output, x, y)) { + if (mapped_output && + !wlr_output_layout_contains_point(cur->state->layout, mapped_output, + x, y)) { return false; } @@ -106,8 +130,17 @@ bool wlr_cursor_warp(struct wlr_cursor *cur, double x, double y) { return true; } -void wlr_cursor_move(struct wlr_cursor *cur, double delta_x, double delta_y) { +void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, + double delta_x, double delta_y) { assert(cur->state->layout); + struct wlr_output *mapped_output = NULL; + struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); + + if (c_device && c_device->mapped_output) { + mapped_output = c_device->mapped_output; + } else { + mapped_output = cur->state->mapped_output; + } double x = cur->x + delta_x; double y = cur->y + delta_y; @@ -115,15 +148,15 @@ void wlr_cursor_move(struct wlr_cursor *cur, double delta_x, double delta_y) { struct wlr_output *output; output = wlr_output_layout_output_at(cur->state->layout, x, y); - if (!output || (cur->state->mapped_output && cur->state->mapped_output != output)) { + if (!output || (mapped_output && mapped_output != output)) { double closest_x, closest_y; - wlr_output_layout_closest_boundary(cur->state->layout, - cur->state->mapped_output, x, y, &closest_x, &closest_y); + wlr_output_layout_closest_boundary(cur->state->layout, mapped_output, x, + y, &closest_x, &closest_y); x = closest_x; y = closest_y; } - if (wlr_cursor_warp(cur, x, y)) { + if (wlr_cursor_warp(cur, dev, x, y)) { cur->x = x; cur->y = y; } @@ -230,5 +263,11 @@ void wlr_cursor_map_to_output(struct wlr_cursor *cur, void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, struct wlr_input_device *dev, struct wlr_output *output) { - wlr_log(L_DEBUG, "TODO map input to output"); + struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); + if (!c_device) { + wlr_log(L_ERROR, "Cannot map device \"%s\" to output (not found in this cursor)", dev->name); + return; + } + + c_device->mapped_output = output; } From 54f87146c3755653bbbe076c86b4b85c23a0989d Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 24 Aug 2017 15:26:51 -0400 Subject: [PATCH 10/34] refactor example config and add ini.c --- examples/config.c | 146 +++++++++++++++++++++++++++++ examples/config.h | 25 +++++ examples/ini.c | 195 +++++++++++++++++++++++++++++++++++++++ examples/ini.h | 93 +++++++++++++++++++ examples/meson.build | 2 +- examples/output-layout.c | 1 + examples/pointer.c | 1 + examples/rotation.c | 1 + examples/shared.c | 139 ---------------------------- examples/shared.h | 18 ---- 10 files changed, 463 insertions(+), 158 deletions(-) create mode 100644 examples/config.c create mode 100644 examples/config.h create mode 100644 examples/ini.c create mode 100644 examples/ini.h diff --git a/examples/config.c b/examples/config.c new file mode 100644 index 00000000..4f70faf0 --- /dev/null +++ b/examples/config.c @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include "shared.h" +#include "config.h" + +static void usage(const char *name, int ret) { + fprintf(stderr, + "usage: %s [-d [-r | -f]]*\n" + "\n" + " -o The name of the DRM display. e.g. DVI-I-1.\n" + " -r The rotation counter clockwise. Valid values are 90, 180, 270.\n" + " -x The X-axis coordinate position of this output in the layout.\n" + " -y The Y-axis coordinate position of this output in the layout.\n" + " -f Flip the output along the vertical axis.\n", name); + + exit(ret); +} + +struct example_config *parse_args(int argc, char *argv[]) { + struct example_config *config = calloc(1, sizeof(struct example_config)); + wl_list_init(&config->outputs); + struct output_config *oc = NULL; + + int c; + while ((c = getopt(argc, argv, "o:r:x:y:fh")) != -1) { + switch (c) { + case 'o': + oc = calloc(1, sizeof(*oc)); + oc->name = optarg; + oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; + wl_list_insert(&config->outputs, &oc->link); + break; + case 'r': + if (!oc) { + fprintf(stderr, "You must specify an output first\n"); + usage(argv[0], 1); + } + + if (oc->transform != WL_OUTPUT_TRANSFORM_NORMAL + && oc->transform != WL_OUTPUT_TRANSFORM_FLIPPED) { + fprintf(stderr, "Rotation for %s already specified\n", oc->name); + usage(argv[0], 1); + } + + if (strcmp(optarg, "90") == 0) { + oc->transform += WL_OUTPUT_TRANSFORM_90; + } else if (strcmp(optarg, "180") == 0) { + oc->transform += WL_OUTPUT_TRANSFORM_180; + } else if (strcmp(optarg, "270") == 0) { + oc->transform += WL_OUTPUT_TRANSFORM_270; + } else { + fprintf(stderr, "Invalid rotation '%s'\n", optarg); + usage(argv[0], 1); + } + break; + case 'x': + if (!oc) { + fprintf(stderr, "You must specify an output first\n"); + usage(argv[0], 1); + } + oc->x = strtol(optarg, NULL, 0); + break; + case 'y': + if (!oc) { + fprintf(stderr, "You must specify an output first\n"); + usage(argv[0], 1); + } + oc->y = strtol(optarg, NULL, 0); + break; + case 'f': + if (!oc) { + fprintf(stderr, "You must specify an output first\n"); + usage(argv[0], 1); + } + + if (oc->transform >= WL_OUTPUT_TRANSFORM_FLIPPED) { + fprintf(stderr, "Flip for %s already specified\n", oc->name); + usage(argv[0], 1); + } + + oc->transform += WL_OUTPUT_TRANSFORM_FLIPPED; + break; + case 'h': + case '?': + usage(argv[0], c != 'h'); + } + } + + return config; +} + +void example_config_destroy(struct example_config *config) { + struct output_config *oc, *tmp = NULL; + wl_list_for_each_safe(oc, tmp, &config->outputs, link) { + free(oc); + } + free(config); +} + +struct wlr_output_layout *configure_layout(struct example_config *config, struct wl_list *outputs) { + struct wlr_output_layout *layout = wlr_output_layout_init(); + int max_x = INT_MIN; + int max_x_y = INT_MIN; // y value for the max_x output + + // first add all the configured outputs + struct output_state *output; + wl_list_for_each(output, outputs, link) { + struct output_config *conf; + wl_list_for_each(conf, &config->outputs, link) { + if (strcmp(conf->name, output->output->name) == 0) { + wlr_output_layout_add(layout, output->output, + conf->x, conf->y); + wlr_output_transform(output->output, conf->transform); + int width, height; + wlr_output_effective_resolution(output->output, &width, &height); + if (conf->x + width > max_x) { + max_x = conf->x + width; + max_x_y = conf->y; + } + break; + } + } + } + + if (max_x == INT_MIN) { + // couldn't find a configured output + max_x = 0; + max_x_y = 0; + } + + // now add all the other configured outputs in a sensible position + wl_list_for_each(output, outputs, link) { + if (wlr_output_layout_get(layout, output->output)) { + continue; + } + wlr_output_layout_add(layout, output->output, max_x, max_x_y); + int width, height; + wlr_output_effective_resolution(output->output, &width, &height); + max_x += width; + } + + return layout; +} + diff --git a/examples/config.h b/examples/config.h new file mode 100644 index 00000000..1ecadd81 --- /dev/null +++ b/examples/config.h @@ -0,0 +1,25 @@ +#ifndef _EXAMPLE_CONFIG_H +#define _EXAMPLE_CONFIG_H +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif +#include + +struct output_config { + char *name; + enum wl_output_transform transform; + int x, y; + struct wl_list link; +}; + +struct example_config { + struct wl_list outputs; +}; + +struct example_config *parse_args(int argc, char *argv[]); + +void example_config_destroy(struct example_config *config); + +struct wlr_output_layout *configure_layout(struct example_config *config, + struct wl_list *outputs); +#endif diff --git a/examples/ini.c b/examples/ini.c new file mode 100644 index 00000000..6be9c44a --- /dev/null +++ b/examples/ini.c @@ -0,0 +1,195 @@ +/* inih -- simple .INI file parser + +inih is released under the New BSD license (see LICENSE.txt). Go to the project +home page for more info: + +https://github.com/benhoyt/inih + +*/ + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include + +#include "ini.h" + +#if !INI_USE_STACK +#include +#endif + +#define MAX_SECTION 50 +#define MAX_NAME 50 + +/* Strip whitespace chars off end of given string, in place. Return s. */ +static char* rstrip(char* s) +{ + char* p = s + strlen(s); + while (p > s && isspace((unsigned char)(*--p))) + *p = '\0'; + return s; +} + +/* Return pointer to first non-whitespace char in given string. */ +static char* lskip(const char* s) +{ + while (*s && isspace((unsigned char)(*s))) + s++; + return (char*)s; +} + +/* Return pointer to first char (of chars) or inline comment in given string, + or pointer to null at end of string if neither found. Inline comment must + be prefixed by a whitespace character to register as a comment. */ +static char* find_chars_or_comment(const char* s, const char* chars) +{ +#if INI_ALLOW_INLINE_COMMENTS + int was_space = 0; + while (*s && (!chars || !strchr(chars, *s)) && + !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) { + was_space = isspace((unsigned char)(*s)); + s++; + } +#else + while (*s && (!chars || !strchr(chars, *s))) { + s++; + } +#endif + return (char*)s; +} + +/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ +static char* strncpy0(char* dest, const char* src, size_t size) +{ + strncpy(dest, src, size); + dest[size - 1] = '\0'; + return dest; +} + +/* See documentation in header file. */ +int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, + void* user) +{ + /* Uses a fair bit of stack (use heap instead if you need to) */ +#if INI_USE_STACK + char line[INI_MAX_LINE]; +#else + char* line; +#endif + char section[MAX_SECTION] = ""; + char prev_name[MAX_NAME] = ""; + + char* start; + char* end; + char* name; + char* value; + int lineno = 0; + int error = 0; + +#if !INI_USE_STACK + line = (char*)malloc(INI_MAX_LINE); + if (!line) { + return -2; + } +#endif + + /* Scan through stream line by line */ + while (reader(line, INI_MAX_LINE, stream) != NULL) { + lineno++; + + start = line; +#if INI_ALLOW_BOM + if (lineno == 1 && (unsigned char)start[0] == 0xEF && + (unsigned char)start[1] == 0xBB && + (unsigned char)start[2] == 0xBF) { + start += 3; + } +#endif + start = lskip(rstrip(start)); + + if (*start == ';' || *start == '#') { + /* Per Python configparser, allow both ; and # comments at the + start of a line */ + } +#if INI_ALLOW_MULTILINE + else if (*prev_name && *start && start > line) { + /* Non-blank line with leading whitespace, treat as continuation + of previous name's value (as per Python configparser). */ + if (!handler(user, section, prev_name, start) && !error) + error = lineno; + } +#endif + else if (*start == '[') { + /* A "[section]" line */ + end = find_chars_or_comment(start + 1, "]"); + if (*end == ']') { + *end = '\0'; + strncpy0(section, start + 1, sizeof(section)); + *prev_name = '\0'; + } + else if (!error) { + /* No ']' found on section line */ + error = lineno; + } + } + else if (*start) { + /* Not a comment, must be a name[=:]value pair */ + end = find_chars_or_comment(start, "=:"); + if (*end == '=' || *end == ':') { + *end = '\0'; + name = rstrip(start); + value = lskip(end + 1); +#if INI_ALLOW_INLINE_COMMENTS + end = find_chars_or_comment(value, NULL); + if (*end) + *end = '\0'; +#endif + rstrip(value); + + /* Valid name[=:]value pair found, call handler */ + strncpy0(prev_name, name, sizeof(prev_name)); + if (!handler(user, section, name, value) && !error) + error = lineno; + memset(value, 0, strlen(value)); + } + else if (!error) { + /* No '=' or ':' found on name[=:]value line */ + error = lineno; + } + } + +#if INI_STOP_ON_FIRST_ERROR + if (error) + break; +#endif + } + +#if !INI_USE_STACK + free(line); +#endif + + return error; +} + +/* See documentation in header file. */ +int ini_parse_file(FILE* file, ini_handler handler, void* user) +{ + return ini_parse_stream((ini_reader)fgets, file, handler, user); +} + +/* See documentation in header file. */ +int ini_parse(const char* filename, ini_handler handler, void* user) +{ + FILE* file; + int error; + + file = fopen(filename, "r"); + if (!file) + return -1; + error = ini_parse_file(file, handler, user); + fclose(file); + return error; +} diff --git a/examples/ini.h b/examples/ini.h new file mode 100644 index 00000000..2804255b --- /dev/null +++ b/examples/ini.h @@ -0,0 +1,93 @@ +/* inih -- simple .INI file parser + +inih is released under the New BSD license (see LICENSE.txt). Go to the project +home page for more info: + +https://github.com/benhoyt/inih + +*/ + +#ifndef __INI_H__ +#define __INI_H__ + +/* Make this header file easier to include in C++ code */ +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Typedef for prototype of handler function. */ +typedef int (*ini_handler)(void* user, const char* section, + const char* name, const char* value); + +/* Typedef for prototype of fgets-style reader function. */ +typedef char* (*ini_reader)(char* str, int num, void* stream); + +/* Parse given INI-style file. May have [section]s, name=value pairs + (whitespace stripped), and comments starting with ';' (semicolon). Section + is "" if name=value pair parsed before any section heading. name:value + pairs are also supported as a concession to Python's configparser. + + For each name=value pair parsed, call handler function with given user + pointer as well as section, name, and value (data only valid for duration + of handler call). Handler should return nonzero on success, zero on error. + + Returns 0 on success, line number of first error on parse error (doesn't + stop on first error), -1 on file open error, or -2 on memory allocation + error (only when INI_USE_STACK is zero). +*/ +int ini_parse(const char* filename, ini_handler handler, void* user); + +/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't + close the file when it's finished -- the caller must do that. */ +int ini_parse_file(FILE* file, ini_handler handler, void* user); + +/* Same as ini_parse(), but takes an ini_reader function pointer instead of + filename. Used for implementing custom or string-based I/O. */ +int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, + void* user); + +/* Nonzero to allow multi-line value parsing, in the style of Python's + configparser. If allowed, ini_parse() will call the handler with the same + name for each subsequent line parsed. */ +#ifndef INI_ALLOW_MULTILINE +#define INI_ALLOW_MULTILINE 1 +#endif + +/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of + the file. See http://code.google.com/p/inih/issues/detail?id=21 */ +#ifndef INI_ALLOW_BOM +#define INI_ALLOW_BOM 1 +#endif + +/* Nonzero to allow inline comments (with valid inline comment characters + specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match + Python 3.2+ configparser behaviour. */ +#ifndef INI_ALLOW_INLINE_COMMENTS +#define INI_ALLOW_INLINE_COMMENTS 1 +#endif +#ifndef INI_INLINE_COMMENT_PREFIXES +#define INI_INLINE_COMMENT_PREFIXES ";" +#endif + +/* Nonzero to use stack, zero to use heap (malloc/free). */ +#ifndef INI_USE_STACK +#define INI_USE_STACK 1 +#endif + +/* Stop parsing on first error (default is to keep parsing). */ +#ifndef INI_STOP_ON_FIRST_ERROR +#define INI_STOP_ON_FIRST_ERROR 0 +#endif + +/* Maximum line length for any line in INI file. */ +#ifndef INI_MAX_LINE +#define INI_MAX_LINE 2000 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __INI_H__ */ diff --git a/examples/meson.build b/examples/meson.build index d4d96984..8fda974f 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -1,5 +1,5 @@ lib_shared = static_library('shared', - ['shared.c', 'cat.c'], + ['shared.c', 'cat.c', 'ini.c', 'config.c'], dependencies: wlroots) executable('simple', 'simple.c', dependencies: wlroots, link_with: lib_shared) diff --git a/examples/output-layout.c b/examples/output-layout.c index 041d5788..90ad558f 100644 --- a/examples/output-layout.c +++ b/examples/output-layout.c @@ -22,6 +22,7 @@ #include #include #include "shared.h" +#include "config.h" #include "cat.h" struct sample_state { diff --git a/examples/pointer.c b/examples/pointer.c index 95e28bb2..fcf9805f 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -22,6 +22,7 @@ #include #include #include "shared.h" +#include "config.h" #include "cat.h" struct sample_input_device { diff --git a/examples/rotation.c b/examples/rotation.c index 1dcbc80f..2596e492 100644 --- a/examples/rotation.c +++ b/examples/rotation.c @@ -19,6 +19,7 @@ #include #include #include "shared.h" +#include "config.h" #include "cat.h" struct sample_state { diff --git a/examples/shared.c b/examples/shared.c index 1dad8016..f9d687e3 100644 --- a/examples/shared.c +++ b/examples/shared.c @@ -18,145 +18,6 @@ #include #include "shared.h" -static void usage(const char *name, int ret) { - fprintf(stderr, - "usage: %s [-d [-r | -f]]*\n" - "\n" - " -o The name of the DRM display. e.g. DVI-I-1.\n" - " -r The rotation counter clockwise. Valid values are 90, 180, 270.\n" - " -x The X-axis coordinate position of this output in the layout.\n" - " -y The Y-axis coordinate position of this output in the layout.\n" - " -f Flip the output along the vertical axis.\n", name); - - exit(ret); -} - -struct example_config *parse_args(int argc, char *argv[]) { - struct example_config *config = calloc(1, sizeof(struct example_config)); - wl_list_init(&config->outputs); - struct output_config *oc = NULL; - - int c; - while ((c = getopt(argc, argv, "o:r:x:y:fh")) != -1) { - switch (c) { - case 'o': - oc = calloc(1, sizeof(*oc)); - oc->name = optarg; - oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; - wl_list_insert(&config->outputs, &oc->link); - break; - case 'r': - if (!oc) { - fprintf(stderr, "You must specify an output first\n"); - usage(argv[0], 1); - } - - if (oc->transform != WL_OUTPUT_TRANSFORM_NORMAL - && oc->transform != WL_OUTPUT_TRANSFORM_FLIPPED) { - fprintf(stderr, "Rotation for %s already specified\n", oc->name); - usage(argv[0], 1); - } - - if (strcmp(optarg, "90") == 0) { - oc->transform += WL_OUTPUT_TRANSFORM_90; - } else if (strcmp(optarg, "180") == 0) { - oc->transform += WL_OUTPUT_TRANSFORM_180; - } else if (strcmp(optarg, "270") == 0) { - oc->transform += WL_OUTPUT_TRANSFORM_270; - } else { - fprintf(stderr, "Invalid rotation '%s'\n", optarg); - usage(argv[0], 1); - } - break; - case 'x': - if (!oc) { - fprintf(stderr, "You must specify an output first\n"); - usage(argv[0], 1); - } - oc->x = strtol(optarg, NULL, 0); - break; - case 'y': - if (!oc) { - fprintf(stderr, "You must specify an output first\n"); - usage(argv[0], 1); - } - oc->y = strtol(optarg, NULL, 0); - break; - case 'f': - if (!oc) { - fprintf(stderr, "You must specify an output first\n"); - usage(argv[0], 1); - } - - if (oc->transform >= WL_OUTPUT_TRANSFORM_FLIPPED) { - fprintf(stderr, "Flip for %s already specified\n", oc->name); - usage(argv[0], 1); - } - - oc->transform += WL_OUTPUT_TRANSFORM_FLIPPED; - break; - case 'h': - case '?': - usage(argv[0], c != 'h'); - } - } - - return config; -} - -void example_config_destroy(struct example_config *config) { - struct output_config *oc, *tmp = NULL; - wl_list_for_each_safe(oc, tmp, &config->outputs, link) { - free(oc); - } - free(config); -} - -struct wlr_output_layout *configure_layout(struct example_config *config, struct wl_list *outputs) { - struct wlr_output_layout *layout = wlr_output_layout_init(); - int max_x = INT_MIN; - int max_x_y = INT_MIN; // y value for the max_x output - - // first add all the configured outputs - struct output_state *output; - wl_list_for_each(output, outputs, link) { - struct output_config *conf; - wl_list_for_each(conf, &config->outputs, link) { - if (strcmp(conf->name, output->output->name) == 0) { - wlr_output_layout_add(layout, output->output, - conf->x, conf->y); - wlr_output_transform(output->output, conf->transform); - int width, height; - wlr_output_effective_resolution(output->output, &width, &height); - if (conf->x + width > max_x) { - max_x = conf->x + width; - max_x_y = conf->y; - } - break; - } - } - } - - if (max_x == INT_MIN) { - // couldn't find a configured output - max_x = 0; - max_x_y = 0; - } - - // now add all the other configured outputs in a sensible position - wl_list_for_each(output, outputs, link) { - if (wlr_output_layout_get(layout, output->output)) { - continue; - } - wlr_output_layout_add(layout, output->output, max_x, max_x_y); - int width, height; - wlr_output_effective_resolution(output->output, &width, &height); - max_x += width; - } - - return layout; -} - static void keyboard_led_update(struct keyboard_state *kbstate) { uint32_t leds = 0; diff --git a/examples/shared.h b/examples/shared.h index d9972ffd..06108494 100644 --- a/examples/shared.h +++ b/examples/shared.h @@ -12,24 +12,6 @@ #include #include -struct output_config { - char *name; - enum wl_output_transform transform; - int x, y; - struct wl_list link; -}; - -struct example_config { - struct wl_list outputs; -}; - -struct example_config *parse_args(int argc, char *argv[]); - -void example_config_destroy(struct example_config *config); - -struct wlr_output_layout *configure_layout(struct example_config *config, - struct wl_list *outputs); - struct output_state { struct compositor_state *compositor; struct wlr_output *output; From b3a43e226140d9b5d49c4ed24798e3f3006dcae5 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Fri, 25 Aug 2017 08:06:38 -0400 Subject: [PATCH 11/34] add configuration file --- .gitignore | 1 + examples/config.c | 154 +++++++++++++++++++------------ examples/config.h | 1 + examples/wlr-example.ini.example | 33 +++++++ 4 files changed, 128 insertions(+), 61 deletions(-) create mode 100644 examples/wlr-example.ini.example diff --git a/.gitignore b/.gitignore index ce85118c..d4edde88 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ test/ build/ .lvimrc wayland-*-protocol.* +wlr-example.ini diff --git a/examples/config.c b/examples/config.c index 4f70faf0..bca2b44b 100644 --- a/examples/config.c +++ b/examples/config.c @@ -1,86 +1,88 @@ +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif #include #include #include #include +#include +#include #include "shared.h" #include "config.h" +#include "ini.h" static void usage(const char *name, int ret) { fprintf(stderr, - "usage: %s [-d [-r | -f]]*\n" + "usage: %s [-C ]\n" "\n" - " -o The name of the DRM display. e.g. DVI-I-1.\n" - " -r The rotation counter clockwise. Valid values are 90, 180, 270.\n" - " -x The X-axis coordinate position of this output in the layout.\n" - " -y The Y-axis coordinate position of this output in the layout.\n" - " -f Flip the output along the vertical axis.\n", name); + " -C Path to the configuration file (default: wlr-example.ini).\n" + " See `examples/wlr-example.ini.example` for config file documentation.\n", name); exit(ret); } -struct example_config *parse_args(int argc, char *argv[]) { - struct example_config *config = calloc(1, sizeof(struct example_config)); - wl_list_init(&config->outputs); - struct output_config *oc = NULL; +static const char *output_prefix = "output:"; - int c; - while ((c = getopt(argc, argv, "o:r:x:y:fh")) != -1) { - switch (c) { - case 'o': - oc = calloc(1, sizeof(*oc)); - oc->name = optarg; - oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; - wl_list_insert(&config->outputs, &oc->link); - break; - case 'r': - if (!oc) { - fprintf(stderr, "You must specify an output first\n"); - usage(argv[0], 1); - } +static int config_ini_handler(void *user, const char *section, const char *name, const char *value) { + struct example_config *config = user; + if (strncmp(output_prefix, section, strlen(output_prefix)) == 0) { + const char *output_name = section + strlen(output_prefix); + struct output_config *oc; + bool found = false; - if (oc->transform != WL_OUTPUT_TRANSFORM_NORMAL - && oc->transform != WL_OUTPUT_TRANSFORM_FLIPPED) { - fprintf(stderr, "Rotation for %s already specified\n", oc->name); - usage(argv[0], 1); + wl_list_for_each(oc, &config->outputs, link) { + if (strcmp(oc->name, output_name) == 0) { + found = true; + break; } + } + + if (!found) { + oc = calloc(1, sizeof(struct output_config)); + oc->name = strdup(output_name); + oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; + wl_list_insert(&config->outputs, &oc->link); + } - if (strcmp(optarg, "90") == 0) { - oc->transform += WL_OUTPUT_TRANSFORM_90; - } else if (strcmp(optarg, "180") == 0) { - oc->transform += WL_OUTPUT_TRANSFORM_180; - } else if (strcmp(optarg, "270") == 0) { - oc->transform += WL_OUTPUT_TRANSFORM_270; + if (strcmp(name, "x") == 0) { + oc->x = strtol(value, NULL, 10); + } else if (strcmp(name, "y") == 0) { + oc->y = strtol(value, NULL, 10); + } else if (strcmp(name, "rotate") == 0) { + if (strcmp(value, "90") == 0) { + oc->transform = WL_OUTPUT_TRANSFORM_90; + } else if (strcmp(value, "180") == 0) { + oc->transform = WL_OUTPUT_TRANSFORM_180; + } else if (strcmp(value, "270") == 0) { + oc->transform = WL_OUTPUT_TRANSFORM_270; + } else if (strcmp(value, "flipped") == 0) { + oc->transform = WL_OUTPUT_TRANSFORM_FLIPPED; + } else if (strcmp(value, "flipped-90") == 0) { + oc->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90; + } else if (strcmp(value, "flipped-180") == 0) { + oc->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180; + } else if (strcmp(value, "flipped-270") == 0) { + oc->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270; } else { - fprintf(stderr, "Invalid rotation '%s'\n", optarg); - usage(argv[0], 1); - } - break; - case 'x': - if (!oc) { - fprintf(stderr, "You must specify an output first\n"); - usage(argv[0], 1); - } - oc->x = strtol(optarg, NULL, 0); - break; - case 'y': - if (!oc) { - fprintf(stderr, "You must specify an output first\n"); - usage(argv[0], 1); - } - oc->y = strtol(optarg, NULL, 0); - break; - case 'f': - if (!oc) { - fprintf(stderr, "You must specify an output first\n"); - usage(argv[0], 1); + wlr_log(L_ERROR, "got unknown transform value: %s", value); } + } + } else { + wlr_log(L_ERROR, "got unknown config section: %s", section); + } - if (oc->transform >= WL_OUTPUT_TRANSFORM_FLIPPED) { - fprintf(stderr, "Flip for %s already specified\n", oc->name); - usage(argv[0], 1); - } + return 1; +} + +struct example_config *parse_args(int argc, char *argv[]) { + struct example_config *config = calloc(1, sizeof(struct example_config)); + wl_list_init(&config->outputs); - oc->transform += WL_OUTPUT_TRANSFORM_FLIPPED; + int c; + while ((c = getopt(argc, argv, "C:h")) != -1) { + switch (c) { + case 'C': + config->config_path = strdup(optarg); break; case 'h': case '?': @@ -88,14 +90,44 @@ struct example_config *parse_args(int argc, char *argv[]) { } } + if (!config->config_path) { + // get the config path from the current directory + char cwd[1024]; + if (getcwd(cwd, sizeof(cwd)) != NULL) { + char buf[1024]; + sprintf(buf, "%s/%s", cwd, "wlr-example.ini"); + config->config_path = strdup(buf); + } else { + wlr_log(L_ERROR, "could not get cwd"); + exit(1); + } + } + + int result = ini_parse(config->config_path, config_ini_handler, config); + + if (result == -1) { + wlr_log(L_ERROR, "Could not find config file at %s", config->config_path); + exit(1); + } else if (result == -2) { + wlr_log(L_ERROR, "Could not allocate memory to parse config file"); + exit(1); + } else if (result != 0) { + wlr_log(L_ERROR, "Could not parse config file"); + exit(1); + } + return config; } void example_config_destroy(struct example_config *config) { struct output_config *oc, *tmp = NULL; wl_list_for_each_safe(oc, tmp, &config->outputs, link) { + free(oc->name); free(oc); } + if (config->config_path) { + free(config->config_path); + } free(config); } diff --git a/examples/config.h b/examples/config.h index 1ecadd81..d02d1a2c 100644 --- a/examples/config.h +++ b/examples/config.h @@ -14,6 +14,7 @@ struct output_config { struct example_config { struct wl_list outputs; + char *config_path; }; struct example_config *parse_args(int argc, char *argv[]); diff --git a/examples/wlr-example.ini.example b/examples/wlr-example.ini.example new file mode 100644 index 00000000..283439f0 --- /dev/null +++ b/examples/wlr-example.ini.example @@ -0,0 +1,33 @@ +# Configuration +# ------------- +# Some examples will read a configuration file. Not all examples will use all of +# the configuration options. The configuration file will be loaded from +# `wlr-example.ini` from the current directory or the path can be specified by the +# `-C` option given on the command line. +# +# Output configuration +# ~~~~~~~~~~~~~~~~~~~~ +# Each output is specified in a section named [output:{NAME}] where NAME is the +# drm name for this output. +# +# Value "x" specifies the x-coordinate in the output layout. +# +# Value "y" specifies the y-coordinate in the output layout. +# +# Value "rotate" specifies output rotation and can be 90, 180, 270, flipped, +# flipped-90, flipped-180, or flipped-270 +[output:HDMI-A-1] +x=3000 +y=0 +rotate=90 + +[output:DP-1] +x=0 +y=0 +rotate=270 + +[output:DVI-D-1] +x=1080 +y=232 + +# vim:filetype=dosini From 699d489f936826a808f955c47442342e850bfc1b Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Fri, 25 Aug 2017 08:58:02 -0400 Subject: [PATCH 12/34] add cursor configuration --- examples/config.c | 9 +++++++++ examples/config.h | 4 ++++ examples/pointer.c | 9 +++++++++ examples/wlr-example.ini.example | 7 +++++++ 4 files changed, 29 insertions(+) diff --git a/examples/config.c b/examples/config.c index bca2b44b..909a2463 100644 --- a/examples/config.c +++ b/examples/config.c @@ -67,6 +67,12 @@ static int config_ini_handler(void *user, const char *section, const char *name, wlr_log(L_ERROR, "got unknown transform value: %s", value); } } + } else if (strcmp(section, "cursor") == 0) { + if (strcmp(name, "map-to-output") == 0) { + config->cursor.mapped_output = strdup(value); + } else { + wlr_log(L_ERROR, "got unknown cursor config: %s", name); + } } else { wlr_log(L_ERROR, "got unknown config section: %s", section); } @@ -128,6 +134,9 @@ void example_config_destroy(struct example_config *config) { if (config->config_path) { free(config->config_path); } + if (config->cursor.mapped_output) { + free(config->cursor.mapped_output); + } free(config); } diff --git a/examples/config.h b/examples/config.h index d02d1a2c..c5f0c8dd 100644 --- a/examples/config.h +++ b/examples/config.h @@ -13,6 +13,10 @@ struct output_config { }; struct example_config { + struct { + char *mapped_output; + } cursor; + struct wl_list outputs; char *config_path; }; diff --git a/examples/pointer.c b/examples/pointer.c index fcf9805f..88fdaef7 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -70,6 +70,11 @@ static void handle_output_add(struct output_state *ostate) { sample->layout = configure_layout(sample->config, &ostate->compositor->outputs); wlr_cursor_attach_output_layout(sample->cursor, sample->layout); + char *mapped_output = sample->config->cursor.mapped_output; + if (mapped_output && strcmp(mapped_output, wlr_output->name) == 0) { + wlr_cursor_map_to_output(sample->cursor, wlr_output); + } + /* // TODO configuration if (strcmp("DP-1", ostate->output->name) == 0) { @@ -95,6 +100,10 @@ static void handle_output_remove(struct output_state *ostate) { wlr_output_layout_destroy(sample->layout); sample->layout = configure_layout(sample->config, &ostate->compositor->outputs); wlr_cursor_attach_output_layout(sample->cursor, sample->layout); + + if (strcmp(sample->config->cursor.mapped_output, ostate->output->name) == 0) { + wlr_cursor_map_to_output(sample->cursor, NULL); + } } static void handle_output_resolution(struct compositor_state *state, diff --git a/examples/wlr-example.ini.example b/examples/wlr-example.ini.example index 283439f0..a9dff591 100644 --- a/examples/wlr-example.ini.example +++ b/examples/wlr-example.ini.example @@ -30,4 +30,11 @@ rotate=270 x=1080 y=232 +# Cursor Configuration +# ~~~~~~~~~~~~~~~~~~~~ +# Value "map-to-output" specifies the output to which the cursor is +# constrained. +[cursor] +map-to-output=HDMI-A-1 + # vim:filetype=dosini From d0cf8d0d01b12d359be5c4216ef5f0bdbdfee622 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Fri, 25 Aug 2017 09:40:01 -0400 Subject: [PATCH 13/34] add device configuration --- examples/config.c | 42 ++++++++++++++++++++++-- examples/config.h | 7 ++++ examples/pointer.c | 55 ++++++++++++++++++++------------ examples/wlr-example.ini.example | 9 ++++++ 4 files changed, 91 insertions(+), 22 deletions(-) diff --git a/examples/config.c b/examples/config.c index 909a2463..31aaa6d7 100644 --- a/examples/config.c +++ b/examples/config.c @@ -22,6 +22,7 @@ static void usage(const char *name, int ret) { } static const char *output_prefix = "output:"; +static const char *device_prefix = "device:"; static int config_ini_handler(void *user, const char *section, const char *name, const char *value) { struct example_config *config = user; @@ -73,6 +74,32 @@ static int config_ini_handler(void *user, const char *section, const char *name, } else { wlr_log(L_ERROR, "got unknown cursor config: %s", name); } + } else if (strncmp(device_prefix, section, strlen(device_prefix)) == 0) { + const char *device_name = section + strlen(device_prefix); + struct device_config *dc; + bool found = false; + + wl_list_for_each(dc, &config->devices, link) { + if (strcmp(dc->name, device_name) == 0) { + found = true; + break; + } + } + + if (!found) { + dc = calloc(1, sizeof(struct device_config)); + dc->name = strdup(device_name); + wl_list_insert(&config->devices, &dc->link); + } + + if (strcmp(name, "map-to-output") == 0) { + if (dc->mapped_output) { + free(dc->mapped_output); + } + dc->mapped_output = strdup(value); + } else { + wlr_log(L_ERROR, "got unknown device config: %s", name); + } } else { wlr_log(L_ERROR, "got unknown config section: %s", section); } @@ -83,6 +110,7 @@ static int config_ini_handler(void *user, const char *section, const char *name, struct example_config *parse_args(int argc, char *argv[]) { struct example_config *config = calloc(1, sizeof(struct example_config)); wl_list_init(&config->outputs); + wl_list_init(&config->devices); int c; while ((c = getopt(argc, argv, "C:h")) != -1) { @@ -126,11 +154,21 @@ struct example_config *parse_args(int argc, char *argv[]) { } void example_config_destroy(struct example_config *config) { - struct output_config *oc, *tmp = NULL; - wl_list_for_each_safe(oc, tmp, &config->outputs, link) { + struct output_config *oc, *otmp = NULL; + wl_list_for_each_safe(oc, otmp, &config->outputs, link) { free(oc->name); free(oc); } + + struct device_config *dc, *dtmp = NULL; + wl_list_for_each_safe(dc, dtmp, &config->devices, link) { + free(dc->name); + if (dc->mapped_output) { + free(dc->mapped_output); + } + free(dc); + } + if (config->config_path) { free(config->config_path); } diff --git a/examples/config.h b/examples/config.h index c5f0c8dd..e1765c57 100644 --- a/examples/config.h +++ b/examples/config.h @@ -12,12 +12,19 @@ struct output_config { struct wl_list link; }; +struct device_config { + char *name; + char *mapped_output; + struct wl_list link; +}; + struct example_config { struct { char *mapped_output; } cursor; struct wl_list outputs; + struct wl_list devices; char *config_path; }; diff --git a/examples/pointer.c b/examples/pointer.c index 88fdaef7..bec71dff 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -61,30 +61,50 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_swap_buffers(wlr_output); } +static void configure_devices(struct sample_state *sample) { + struct sample_input_device *dev; + // reset device to output mappings + wl_list_for_each(dev, &sample->devices, link) { + wlr_cursor_map_input_to_output(sample->cursor, dev->device, NULL); + } + + struct output_state *ostate; + wl_list_for_each(ostate, &sample->compositor->outputs, link) { + struct device_config *dc; + wl_list_for_each(dc, &sample->config->devices, link) { + // configure device to output mappings + if (dc->mapped_output && + strcmp(dc->mapped_output, ostate->output->name) == 0) { + wl_list_for_each(dev, &sample->devices, link) { + if (strcmp(dev->device->name, dc->name) == 0) { + wlr_cursor_map_input_to_output(sample->cursor, + dev->device, ostate->output); + } + } + } + } + } +} + static void handle_output_add(struct output_state *ostate) { struct sample_state *sample = ostate->compositor->data; struct wlr_output *wlr_output = ostate->output; struct wlr_xcursor_image *image = sample->xcursor->images[0]; + // reset layout wlr_output_layout_destroy(sample->layout); sample->layout = configure_layout(sample->config, &ostate->compositor->outputs); wlr_cursor_attach_output_layout(sample->cursor, sample->layout); + // cursor configuration char *mapped_output = sample->config->cursor.mapped_output; if (mapped_output && strcmp(mapped_output, wlr_output->name) == 0) { wlr_cursor_map_to_output(sample->cursor, wlr_output); } - /* - // TODO configuration - if (strcmp("DP-1", ostate->output->name) == 0) { - struct sample_input_device *dev; - wl_list_for_each(dev, &sample->devices, link) { - wlr_cursor_map_input_to_output(sample->cursor, dev->device, ostate->output); - } - } - */ + configure_devices(sample); + // TODO move to wlr_cursor if (!wlr_output_set_cursor(wlr_output, image->buffer, image->width, image->width, image->height)) { wlr_log(L_DEBUG, "Failed to set hardware cursor"); @@ -101,6 +121,8 @@ static void handle_output_remove(struct output_state *ostate) { sample->layout = configure_layout(sample->config, &ostate->compositor->outputs); wlr_cursor_attach_output_layout(sample->cursor, sample->layout); + configure_devices(sample); + if (strcmp(sample->config->cursor.mapped_output, ostate->output->name) == 0) { wlr_cursor_map_to_output(sample->cursor, NULL); } @@ -122,19 +144,10 @@ static void handle_input_add(struct compositor_state *state, struct if (device->type == WLR_INPUT_DEVICE_POINTER) { struct sample_input_device *s_device = calloc(1, sizeof(struct sample_input_device)); s_device->device = device; - wl_list_insert(&sample->devices, &s_device->link); - - /* - // TODO configuration - struct output_state *ostate; - wl_list_for_each(ostate, &sample->compositor->outputs, link) { - if (strcmp(ostate->output->name, "DP-1") == 0) { - wlr_cursor_map_input_to_output(sample->cursor, device, ostate->output); - } - } - */ + wl_list_insert(&sample->devices, &s_device->link); wlr_cursor_attach_input_device(sample->cursor, device); + configure_devices(sample); } } @@ -224,6 +237,8 @@ int main(int argc, char *argv[]) { compositor.output_resolution_cb = handle_output_resolution; compositor.output_frame_cb = handle_output_frame; compositor.input_add_cb = handle_input_add; + // TODO input_remove_cb + //compositor.input_remove_cb = handle_input_add; state.compositor = &compositor; diff --git a/examples/wlr-example.ini.example b/examples/wlr-example.ini.example index a9dff591..ffb6229e 100644 --- a/examples/wlr-example.ini.example +++ b/examples/wlr-example.ini.example @@ -37,4 +37,13 @@ y=232 [cursor] map-to-output=HDMI-A-1 +# Device Configuration +# ~~~~~~~~~~~~~~~~~~~~ +# Each device is specified in a section named [device:{NAME}] where NAME is the +# name given to this device. See a log file for device names. +# +# Value "map-to-output" specifies the output to which the device is constrained. +[device:Razer Razer DeathAdder 2013] +map-to-output=DP-1 + # vim:filetype=dosini From 0a97b68278a621882c712b55ffe851101e5902d0 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Fri, 25 Aug 2017 13:26:13 -0400 Subject: [PATCH 14/34] implement cursor and device geometry mapping --- examples/config.c | 75 ++++++++++++++++++++++++++++++++ examples/config.h | 2 + examples/pointer.c | 15 +++++-- examples/wlr-example.ini.example | 8 ++++ include/wlr/types/wlr_cursor.h | 6 ++- include/wlr/types/wlr_geometry.h | 12 +++++ types/meson.build | 1 + types/wlr_cursor.c | 35 +++++++++++++++ types/wlr_geometry.c | 36 +++++++++++++++ types/wlr_output_layout.c | 1 + 10 files changed, 186 insertions(+), 5 deletions(-) create mode 100644 include/wlr/types/wlr_geometry.h create mode 100644 types/wlr_geometry.c diff --git a/examples/config.c b/examples/config.c index 31aaa6d7..829350c1 100644 --- a/examples/config.c +++ b/examples/config.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "shared.h" #include "config.h" #include "ini.h" @@ -21,6 +22,64 @@ static void usage(const char *name, int ret) { exit(ret); } +static struct wlr_geometry *parse_geometry(const char *str) { + // format: {width}x{height}+{x}+{y} + if (strlen(str) > 255l) { + wlr_log(L_ERROR, "cannot parse geometry string, too long"); + return NULL; + } + + char *buf = strdup(str); + struct wlr_geometry *geo = calloc(1, sizeof(struct wlr_geometry)); + + bool has_width, has_height, has_x, has_y; + char *pch = strtok(buf, "x+"); + while (pch != NULL) { + errno = 0; + char *endptr; + long val = strtol(pch, &endptr, 0); + + if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) + || (errno != 0 && val == 0)) { + goto invalid_input; + } + + if (endptr == pch) { + goto invalid_input; + } + + if (!has_width) { + geo->width = val; + has_width = true; + } else if (!has_height) { + geo->height = val; + has_height = true; + } else if (!has_x) { + geo->x = val; + has_x = true; + } else if (!has_y) { + geo->y = val; + has_y = true; + } else { + goto invalid_input; + } + pch = strtok(NULL, "x+"); + } + + if (!has_width || !has_height || !has_x || !has_y) { + goto invalid_input; + } + + free(buf); + return geo; + +invalid_input: + wlr_log(L_ERROR, "could not parse geometry string: %s", str); + free(buf); + free(geo); + return NULL; +} + static const char *output_prefix = "output:"; static const char *device_prefix = "device:"; @@ -71,6 +130,11 @@ static int config_ini_handler(void *user, const char *section, const char *name, } else if (strcmp(section, "cursor") == 0) { if (strcmp(name, "map-to-output") == 0) { config->cursor.mapped_output = strdup(value); + } else if (strcmp(name, "geometry") == 0) { + if (config->cursor.mapped_geo) { + free(config->cursor.mapped_geo); + } + config->cursor.mapped_geo = parse_geometry(value); } else { wlr_log(L_ERROR, "got unknown cursor config: %s", name); } @@ -97,6 +161,11 @@ static int config_ini_handler(void *user, const char *section, const char *name, free(dc->mapped_output); } dc->mapped_output = strdup(value); + } else if (strcmp(name, "geometry") == 0) { + if (dc->mapped_geo) { + free(dc->mapped_geo); + } + dc->mapped_geo = parse_geometry(value); } else { wlr_log(L_ERROR, "got unknown device config: %s", name); } @@ -166,6 +235,9 @@ void example_config_destroy(struct example_config *config) { if (dc->mapped_output) { free(dc->mapped_output); } + if (dc->mapped_geo) { + free(dc->mapped_geo); + } free(dc); } @@ -175,6 +247,9 @@ void example_config_destroy(struct example_config *config) { if (config->cursor.mapped_output) { free(config->cursor.mapped_output); } + if (config->cursor.mapped_geo) { + free(config->cursor.mapped_geo); + } free(config); } diff --git a/examples/config.h b/examples/config.h index e1765c57..cd19dc5e 100644 --- a/examples/config.h +++ b/examples/config.h @@ -15,12 +15,14 @@ struct output_config { struct device_config { char *name; char *mapped_output; + struct wlr_geometry *mapped_geo; struct wl_list link; }; struct example_config { struct { char *mapped_output; + struct wlr_geometry *mapped_geo; } cursor; struct wl_list outputs; diff --git a/examples/pointer.c b/examples/pointer.c index bec71dff..9492adab 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -63,14 +63,21 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts static void configure_devices(struct sample_state *sample) { struct sample_input_device *dev; - // reset device to output mappings + struct device_config *dc; + + // reset device mappings wl_list_for_each(dev, &sample->devices, link) { wlr_cursor_map_input_to_output(sample->cursor, dev->device, NULL); + wl_list_for_each(dc, &sample->config->devices, link) { + if (strcmp(dev->device->name, dc->name) == 0) { + wlr_cursor_map_input_to_region(sample->cursor, dev->device, + dc->mapped_geo); + } + } } struct output_state *ostate; wl_list_for_each(ostate, &sample->compositor->outputs, link) { - struct device_config *dc; wl_list_for_each(dc, &sample->config->devices, link) { // configure device to output mappings if (dc->mapped_output && @@ -123,7 +130,8 @@ static void handle_output_remove(struct output_state *ostate) { configure_devices(sample); - if (strcmp(sample->config->cursor.mapped_output, ostate->output->name) == 0) { + char *mapped_output = sample->config->cursor.mapped_output; + if (mapped_output && strcmp(mapped_output, ostate->output->name) == 0) { wlr_cursor_map_to_output(sample->cursor, NULL); } } @@ -216,6 +224,7 @@ int main(int argc, char *argv[]) { state.config = parse_args(argc, argv); state.cursor = wlr_cursor_init(); + wlr_cursor_map_to_region(state.cursor, state.config->cursor.mapped_geo); wl_list_init(&state.devices); wl_signal_add(&state.cursor->events.motion, &state.cursor_motion); diff --git a/examples/wlr-example.ini.example b/examples/wlr-example.ini.example index ffb6229e..1698e0c6 100644 --- a/examples/wlr-example.ini.example +++ b/examples/wlr-example.ini.example @@ -34,8 +34,12 @@ y=232 # ~~~~~~~~~~~~~~~~~~~~ # Value "map-to-output" specifies the output to which the cursor is # constrained. +# +# Value "geometry" specifies the geometry (widthxheight+x+y) to which the cursor +# is constrained. [cursor] map-to-output=HDMI-A-1 +geometry=500x700+50+50 # Device Configuration # ~~~~~~~~~~~~~~~~~~~~ @@ -43,7 +47,11 @@ map-to-output=HDMI-A-1 # name given to this device. See a log file for device names. # # Value "map-to-output" specifies the output to which the device is constrained. +# +# Value "geometry" specifies the geometry (widthxheight+x+y) to which the device +# is constrained. [device:Razer Razer DeathAdder 2013] map-to-output=DP-1 +geometry=500x700+50+50 # vim:filetype=dosini diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index 64a75e4f..30495d44 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -4,6 +4,7 @@ #include #include #include +#include #include struct wlr_cursor_state; @@ -87,12 +88,13 @@ void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, /** * Maps this cursor to an arbitrary region on the associated wlr_output_layout. */ -//void wlr_cursor_map_to_region(struct wlr_cursor *cur, struct wlr_geometry *geo); +void wlr_cursor_map_to_region(struct wlr_cursor *cur, struct wlr_geometry *geo); /** * Maps inputs from this input device to an arbitrary region on the associated * wlr_output_layout. */ -//void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, struct wlr_input_device *dev, struct wlr_geometry *geo); +void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, + struct wlr_input_device *dev, struct wlr_geometry *geo); #endif diff --git a/include/wlr/types/wlr_geometry.h b/include/wlr/types/wlr_geometry.h new file mode 100644 index 00000000..3e218bed --- /dev/null +++ b/include/wlr/types/wlr_geometry.h @@ -0,0 +1,12 @@ +#ifndef _WLR_TYPES_GEOMETRY_H +#define _WLR_TYPES_GEOMETRY_H + +struct wlr_geometry { + int x, y; + int width, height; +}; + +void wlr_geometry_closest_boundary(struct wlr_geometry *geo, double x, double y, + int *dest_x, int *dest_y, double *distance); + +#endif diff --git a/types/meson.build b/types/meson.build index 3992c6e9..d0ed85fe 100644 --- a/types/meson.build +++ b/types/meson.build @@ -16,6 +16,7 @@ lib_wlr_types = static_library('wlr_types', files( 'wlr_xdg_shell_v6.c', 'wlr_wl_shell.c', 'wlr_compositor.c', + 'wlr_geometry.c', ), include_directories: wlr_inc, dependencies: [wayland_server, pixman, wlr_protos]) diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 6917526e..c0b2b6ae 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -12,6 +12,7 @@ struct wlr_cursor_device { struct wlr_input_device *device; struct wl_list link; struct wlr_output *mapped_output; + struct wlr_geometry *mapped_geometry; struct wl_listener motion; struct wl_listener motion_absolute; @@ -24,6 +25,7 @@ struct wlr_cursor_state { struct wlr_output_layout *layout; struct wlr_xcursor *xcursor; struct wlr_output *mapped_output; + struct wlr_geometry *mapped_geometry; }; struct wlr_cursor *wlr_cursor_init() { @@ -145,6 +147,25 @@ void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, double x = cur->x + delta_x; double y = cur->y + delta_y; + // cursor geometry constraints + if (cur->state->mapped_geometry) { + int closest_x, closest_y; + wlr_geometry_closest_boundary(cur->state->mapped_geometry, x, y, + &closest_x, &closest_y, NULL); + x = closest_x; + y = closest_y; + } + + // device constraints + if (c_device->mapped_geometry) { + int closest_x, closest_y; + wlr_geometry_closest_boundary(c_device->mapped_geometry, x, y, + &closest_x, &closest_y, NULL); + x = closest_x; + y = closest_y; + } + + // layout constraints struct wlr_output *output; output = wlr_output_layout_output_at(cur->state->layout, x, y); @@ -271,3 +292,17 @@ void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, c_device->mapped_output = output; } + +void wlr_cursor_map_to_region(struct wlr_cursor *cur, struct wlr_geometry *geo) { + cur->state->mapped_geometry = geo; +} + +void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, + struct wlr_input_device *dev, struct wlr_geometry *geo) { + struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); + if (!c_device) { + wlr_log(L_ERROR, "Cannot map device \"%s\" to geometry (not found in this cursor)", dev->name); + return; + } + c_device->mapped_geometry = geo; +} diff --git a/types/wlr_geometry.c b/types/wlr_geometry.c new file mode 100644 index 00000000..8358d887 --- /dev/null +++ b/types/wlr_geometry.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include + +static double get_distance(double x1, double y1, double x2, double y2) { + double distance; + distance = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); + return distance; +} + +void wlr_geometry_closest_boundary(struct wlr_geometry *geo, double x, double y, + int *dest_x, int *dest_y, double *distance) { + // find the closest x point + if (x < geo->x) { + *dest_x = geo->x; + } else if (x > geo->x + geo->width) { + *dest_x = geo->x + geo->width; + } else { + *dest_x = x; + } + + // find closest y point + if (y < geo->y) { + *dest_y = geo->y; + } else if (y > geo->y + geo->height) { + *dest_y = geo->y + geo->height; + } else { + *dest_y = y; + } + + // calculate distance + if (distance) { + *distance = get_distance(*dest_x, *dest_y, x, y); + } +} diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 5e2067da..7dcb4651 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -149,6 +149,7 @@ void wlr_output_layout_closest_boundary(struct wlr_output_layout *layout, wlr_output_effective_resolution(l_output->output, &width, &height); // find the closest x point + // TODO use wlr_geometry_closest_boundary if (x < l_output->x) { output_x = l_output->x; } else if (x > l_output->x + width) { From dc7e32552dd47f400aa2d7c1f8355b89376ae60e Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 26 Aug 2017 11:53:16 -0400 Subject: [PATCH 15/34] config: fix uninitialized variables and accept trailing for geom --- examples/config.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/config.c b/examples/config.c index 829350c1..1bd4672e 100644 --- a/examples/config.c +++ b/examples/config.c @@ -32,7 +32,11 @@ static struct wlr_geometry *parse_geometry(const char *str) { char *buf = strdup(str); struct wlr_geometry *geo = calloc(1, sizeof(struct wlr_geometry)); - bool has_width, has_height, has_x, has_y; + bool has_width = false; + bool has_height = false; + bool has_x = false; + bool has_y = false; + char *pch = strtok(buf, "x+"); while (pch != NULL) { errno = 0; @@ -61,7 +65,7 @@ static struct wlr_geometry *parse_geometry(const char *str) { geo->y = val; has_y = true; } else { - goto invalid_input; + break; } pch = strtok(NULL, "x+"); } From ac503a47a71e2ab5d149a1bb9184d424609c7da7 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 26 Aug 2017 11:55:24 -0400 Subject: [PATCH 16/34] intersect cursor and device regions --- include/wlr/types/wlr_geometry.h | 6 ++++ types/wlr_cursor.c | 33 ++++++++++++------- types/wlr_geometry.c | 54 ++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 11 deletions(-) diff --git a/include/wlr/types/wlr_geometry.h b/include/wlr/types/wlr_geometry.h index 3e218bed..7ac2f843 100644 --- a/include/wlr/types/wlr_geometry.h +++ b/include/wlr/types/wlr_geometry.h @@ -1,5 +1,6 @@ #ifndef _WLR_TYPES_GEOMETRY_H #define _WLR_TYPES_GEOMETRY_H +#include struct wlr_geometry { int x, y; @@ -9,4 +10,9 @@ struct wlr_geometry { void wlr_geometry_closest_boundary(struct wlr_geometry *geo, double x, double y, int *dest_x, int *dest_y, double *distance); +bool wlr_geometry_intersection(struct wlr_geometry *geo_a, + struct wlr_geometry *geo_b, struct wlr_geometry **dest); + +bool wlr_geometry_contains_point(struct wlr_geometry *geo, int x, int y); + #endif diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index c0b2b6ae..28d9f8c9 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -147,19 +147,20 @@ void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, double x = cur->x + delta_x; double y = cur->y + delta_y; - // cursor geometry constraints - if (cur->state->mapped_geometry) { - int closest_x, closest_y; - wlr_geometry_closest_boundary(cur->state->mapped_geometry, x, y, - &closest_x, &closest_y, NULL); - x = closest_x; - y = closest_y; - } + // geometry constraints + struct wlr_geometry *constraints = NULL; + if (cur->state->mapped_geometry != NULL || + c_device->mapped_geometry != NULL) { + constraints = calloc(1, sizeof(struct wlr_geometry)); + + if (!wlr_geometry_intersection(cur->state->mapped_geometry, + c_device->mapped_geometry, &constraints)) { + // TODO handle no possible movement + goto out; + } - // device constraints - if (c_device->mapped_geometry) { int closest_x, closest_y; - wlr_geometry_closest_boundary(c_device->mapped_geometry, x, y, + wlr_geometry_closest_boundary(constraints, x, y, &closest_x, &closest_y, NULL); x = closest_x; y = closest_y; @@ -177,10 +178,20 @@ void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, y = closest_y; } + if (constraints && !wlr_geometry_contains_point(constraints, x, y)) { + // TODO handle no possible movement + goto out; + } + if (wlr_cursor_warp(cur, dev, x, y)) { cur->x = x; cur->y = y; } + +out: + if (constraints) { + free(constraints); + } } static void handle_pointer_motion(struct wl_listener *listener, void *data) { diff --git a/types/wlr_geometry.c b/types/wlr_geometry.c index 8358d887..be4a80eb 100644 --- a/types/wlr_geometry.c +++ b/types/wlr_geometry.c @@ -1,7 +1,9 @@ #include #include #include +#include #include +#include static double get_distance(double x1, double y1, double x2, double y2) { double distance; @@ -34,3 +36,55 @@ void wlr_geometry_closest_boundary(struct wlr_geometry *geo, double x, double y, *distance = get_distance(*dest_x, *dest_y, x, y); } } + +#ifndef max +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +static bool wlr_geometry_empty(struct wlr_geometry *geo) { + return geo == NULL || geo->width < 0 || geo->height < 0; +} + +bool wlr_geometry_intersection(struct wlr_geometry *geo_a, + struct wlr_geometry *geo_b, struct wlr_geometry **geo_dest) { + struct wlr_geometry *dest = *geo_dest; + bool a_empty = wlr_geometry_empty(geo_a); + bool b_empty = wlr_geometry_empty(geo_b); + + if (a_empty && b_empty) { + return false; + } else if (a_empty) { + dest->x = geo_b->x; + dest->y = geo_b->y; + dest->height = geo_b->height; + dest->width = geo_b->width; + return true; + } else if (b_empty) { + dest->x = geo_a->x; + dest->y = geo_a->y; + dest->height = geo_a->height; + dest->width = geo_a->width; + return true; + } + + int x1 = max(geo_a->x, geo_b->x); + int y1 = max(geo_a->y, geo_b->y); + int x2 = min(geo_a->x + geo_a->width, geo_b->x + geo_b->width); + int y2 = min(geo_a->y + geo_a->height, geo_b->y + geo_b->height); + + dest->x = x1; + dest->y = y1; + dest->width = x2 - x1; + dest->height = y2 - y1; + + return !wlr_geometry_empty(dest); +} + +bool wlr_geometry_contains_point(struct wlr_geometry *geo, int x, int y) { + return x >= geo->x && x <= geo->x + geo->width && + y >= geo->y && y <= geo->y + geo->height; +} From ed126b0881413dc3c855abf313c62e2f3abad4aa Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 27 Aug 2017 11:34:25 -0400 Subject: [PATCH 17/34] add touch events --- examples/pointer.c | 91 ++++++++++++++++++++++++++++++++-- include/wlr/types/wlr_cursor.h | 5 ++ types/wlr_cursor.c | 83 ++++++++++++++++++++++++++----- 3 files changed, 163 insertions(+), 16 deletions(-) diff --git a/examples/pointer.c b/examples/pointer.c index 9492adab..bae205f5 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -45,8 +45,27 @@ struct sample_state { struct wl_listener cursor_motion_absolute; struct wl_listener cursor_button; struct wl_listener cursor_axis; + + struct wl_listener touch_motion; + struct wl_listener touch_up; + struct wl_listener touch_down; + struct wl_listener touch_cancel; + list_t *touch_points; +}; + +struct touch_point { + int32_t slot; + double x, y; }; +static void warp_to_touch(struct sample_state *sample) { + wlr_log(L_DEBUG, "TODO: warp to touch"); + for (size_t i = 0; i < sample->touch_points->length; ++i) { + struct touch_point *point = sample->touch_points->items[i]; + wlr_log(L_DEBUG, "have point x=%f,y=%f", point->x, point->y); + } +} + static void handle_output_frame(struct output_state *output, struct timespec *ts) { struct compositor_state *state = output->compositor; struct sample_state *sample = state->data; @@ -149,8 +168,10 @@ static void handle_input_add(struct compositor_state *state, struct struct sample_state *sample = state->data; // TODO handle other input devices - if (device->type == WLR_INPUT_DEVICE_POINTER) { - struct sample_input_device *s_device = calloc(1, sizeof(struct sample_input_device)); + if (device->type == WLR_INPUT_DEVICE_POINTER || + device->type == WLR_INPUT_DEVICE_TOUCH) { + struct sample_input_device *s_device; + s_device = calloc(1, sizeof(struct sample_input_device)); s_device->device = device; wl_list_insert(&sample->devices, &s_device->link); @@ -216,10 +237,60 @@ static void handle_cursor_axis(struct wl_listener *listener, void *data) { sizeof(sample->clear_color)); } +static void handle_touch_up(struct wl_listener *listener, void *data) { + struct sample_state *sample = wl_container_of(listener, sample, touch_up); + struct wlr_event_touch_up *event = data; + for (size_t i = 0; i < sample->touch_points->length; ++i) { + struct touch_point *point = sample->touch_points->items[i]; + if (point->slot == event->slot) { + list_del(sample->touch_points, i); + break; + } + } + + warp_to_touch(sample); +} + +static void handle_touch_down(struct wl_listener *listener, void *data) { + struct sample_state *sample = wl_container_of(listener, sample, touch_down); + struct wlr_event_touch_down *event = data; + struct touch_point *point = calloc(1, sizeof(struct touch_state)); + point->slot = event->slot; + point->x = event->x_mm / event->width_mm; + point->y = event->y_mm / event->height_mm; + if (list_add(sample->touch_points, point) == -1) { + free(point); + } + + warp_to_touch(sample); +} + +static void handle_touch_motion(struct wl_listener *listener, void *data) { + struct sample_state *sample = wl_container_of(listener, sample, touch_motion); + struct wlr_event_touch_motion *event = data; + for (size_t i = 0; i < sample->touch_points->length; ++i) { + struct touch_point *point = sample->touch_points->items[i]; + if (point->slot == event->slot) { + point->x = event->x_mm / event->width_mm; + point->y = event->y_mm / event->height_mm; + break; + } + } + + warp_to_touch(sample); +} + +static void handle_touch_cancel(struct wl_listener *listener, void *data) { + //struct sample_state *sample = wl_container_of(listener, sample, touch_cancel); + //struct wlr_event_touch_cancel *event = data; + wlr_log(L_DEBUG, "TODO: touch cancel"); +} + int main(int argc, char *argv[]) { struct sample_state state = { .default_color = { 0.25f, 0.25f, 0.25f, 1 }, - .clear_color = { 0.25f, 0.25f, 0.25f, 1 } + .clear_color = { 0.25f, 0.25f, 0.25f, 1 }, + .touch_points = list_create(), }; state.config = parse_args(argc, argv); @@ -227,6 +298,7 @@ int main(int argc, char *argv[]) { wlr_cursor_map_to_region(state.cursor, state.config->cursor.mapped_geo); wl_list_init(&state.devices); + // pointer events wl_signal_add(&state.cursor->events.motion, &state.cursor_motion); state.cursor_motion.notify = handle_cursor_motion; @@ -239,6 +311,19 @@ int main(int argc, char *argv[]) { wl_signal_add(&state.cursor->events.axis, &state.cursor_axis); state.cursor_axis.notify = handle_cursor_axis; + // touch events + wl_signal_add(&state.cursor->events.touch_up, &state.touch_up); + state.touch_up.notify = handle_touch_up; + + wl_signal_add(&state.cursor->events.touch_down, &state.touch_down); + state.touch_down.notify = handle_touch_down; + + wl_signal_add(&state.cursor->events.touch_motion, &state.touch_motion); + state.touch_motion.notify = handle_touch_motion; + + wl_signal_add(&state.cursor->events.touch_cancel, &state.touch_cancel); + state.touch_cancel.notify = handle_touch_cancel; + struct compositor_state compositor = { 0 }; compositor.data = &state; compositor.output_add_cb = handle_output_add; diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index 30495d44..ad5c52a4 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -20,6 +20,11 @@ struct wlr_cursor { struct wl_signal motion_absolute; struct wl_signal button; struct wl_signal axis; + + struct wl_signal touch_up; + struct wl_signal touch_down; + struct wl_signal touch_motion; + struct wl_signal touch_cancel; } events; }; diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 28d9f8c9..f9e1fcc9 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -18,6 +18,11 @@ struct wlr_cursor_device { struct wl_listener motion_absolute; struct wl_listener button; struct wl_listener axis; + + struct wl_listener touch_down; + struct wl_listener touch_up; + struct wl_listener touch_motion; + struct wl_listener touch_cancel; }; struct wlr_cursor_state { @@ -45,11 +50,18 @@ struct wlr_cursor *wlr_cursor_init() { wl_list_init(&cur->state->devices); + // pointer signals wl_signal_init(&cur->events.motion); wl_signal_init(&cur->events.motion_absolute); wl_signal_init(&cur->events.button); wl_signal_init(&cur->events.axis); + // touch signals + wl_signal_init(&cur->events.touch_up); + wl_signal_init(&cur->events.touch_down); + wl_signal_init(&cur->events.touch_motion); + wl_signal_init(&cur->events.touch_cancel); + cur->x = 100; cur->y = 100; @@ -218,19 +230,48 @@ static void handle_pointer_axis(struct wl_listener *listener, void *data) { wl_signal_emit(&device->cursor->events.axis, event); } +static void handle_touch_up(struct wl_listener *listener, void *data) { + struct wlr_event_touch_up *event = data; + struct wlr_cursor_device *device; + device = wl_container_of(listener, device, touch_up); + wl_signal_emit(&device->cursor->events.touch_up, event); +} + +static void handle_touch_down(struct wl_listener *listener, void *data) { + struct wlr_event_touch_down *event = data; + struct wlr_cursor_device *device; + device = wl_container_of(listener, device, touch_down); + wl_signal_emit(&device->cursor->events.touch_down, event); +} + +static void handle_touch_motion(struct wl_listener *listener, void *data) { + struct wlr_event_touch_motion *event = data; + struct wlr_cursor_device *device; + device = wl_container_of(listener, device, touch_motion); + wl_signal_emit(&device->cursor->events.touch_motion, event); +} + +static void handle_touch_cancel(struct wl_listener *listener, void *data) { + struct wlr_event_touch_cancel *event = data; + struct wlr_cursor_device *device; + device = wl_container_of(listener, device, touch_cancel); + wl_signal_emit(&device->cursor->events.touch_cancel, event); +} + void wlr_cursor_attach_input_device(struct wlr_cursor *cur, struct wlr_input_device *dev) { if (dev->type != WLR_INPUT_DEVICE_POINTER && dev->type != WLR_INPUT_DEVICE_TOUCH && dev->type != WLR_INPUT_DEVICE_TABLET_TOOL) { - wlr_log(L_ERROR, "only device types of pointer, touch or tablet tool are" - "supported"); + wlr_log(L_ERROR, "only device types of pointer, touch or tablet tool" + "are supported"); return; } // TODO support other device types - if (dev->type != WLR_INPUT_DEVICE_POINTER) { - wlr_log(L_ERROR, "TODO: support touch and tablet tool devices"); + if (dev->type != WLR_INPUT_DEVICE_POINTER && + dev->type != WLR_INPUT_DEVICE_TOUCH) { + wlr_log(L_ERROR, "TODO: support tablet tool devices"); return; } @@ -242,7 +283,8 @@ void wlr_cursor_attach_input_device(struct wlr_cursor *cur, } } - struct wlr_cursor_device *device = calloc(1, sizeof(struct wlr_cursor_device)); + struct wlr_cursor_device *device; + device = calloc(1, sizeof(struct wlr_cursor_device)); if (!device) { wlr_log(L_ERROR, "Failed to allocate wlr_cursor_device"); return; @@ -252,17 +294,32 @@ void wlr_cursor_attach_input_device(struct wlr_cursor *cur, device->device = dev; // listen to events - wl_signal_add(&dev->pointer->events.motion, &device->motion); - device->motion.notify = handle_pointer_motion; - wl_signal_add(&dev->pointer->events.motion_absolute, &device->motion_absolute); - device->motion_absolute.notify = handle_pointer_motion_absolute; + if (dev->type == WLR_INPUT_DEVICE_POINTER) { + wl_signal_add(&dev->pointer->events.motion, &device->motion); + device->motion.notify = handle_pointer_motion; + + wl_signal_add(&dev->pointer->events.motion_absolute, &device->motion_absolute); + device->motion_absolute.notify = handle_pointer_motion_absolute; - wl_signal_add(&dev->pointer->events.button, &device->button); - device->button.notify = handle_pointer_button; + wl_signal_add(&dev->pointer->events.button, &device->button); + device->button.notify = handle_pointer_button; - wl_signal_add(&dev->pointer->events.axis, &device->axis); - device->axis.notify = handle_pointer_axis; + wl_signal_add(&dev->pointer->events.axis, &device->axis); + device->axis.notify = handle_pointer_axis; + } else if (dev->type == WLR_INPUT_DEVICE_TOUCH) { + wl_signal_add(&dev->touch->events.motion, &device->touch_motion); + device->touch_motion.notify = handle_touch_motion; + + wl_signal_add(&dev->touch->events.down, &device->touch_down); + device->touch_down.notify = handle_touch_down; + + wl_signal_add(&dev->touch->events.up, &device->touch_up); + device->touch_up.notify = handle_touch_up; + + wl_signal_add(&dev->touch->events.cancel, &device->touch_cancel); + device->touch_cancel.notify = handle_touch_cancel; + } wl_list_insert(&cur->state->devices, &device->link); } From c91469767631c84375678f3428a43c355d2c9742 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 27 Aug 2017 11:44:55 -0400 Subject: [PATCH 18/34] add device to touch events --- backend/libinput/touch.c | 4 ++++ include/wlr/types/wlr_touch.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/backend/libinput/touch.c b/backend/libinput/touch.c index 9e08d028..2f300482 100644 --- a/backend/libinput/touch.c +++ b/backend/libinput/touch.c @@ -30,6 +30,7 @@ void handle_touch_down(struct libinput_event *event, struct libinput_event_touch *tevent = libinput_event_get_touch_event(event); struct wlr_event_touch_down wlr_event = { 0 }; + wlr_event.device = wlr_dev; wlr_event.time_sec = libinput_event_touch_get_time(tevent); wlr_event.time_usec = libinput_event_touch_get_time_usec(tevent); wlr_event.slot = libinput_event_touch_get_slot(tevent); @@ -50,6 +51,7 @@ void handle_touch_up(struct libinput_event *event, struct libinput_event_touch *tevent = libinput_event_get_touch_event(event); struct wlr_event_touch_up wlr_event = { 0 }; + wlr_event.device = wlr_dev; wlr_event.time_sec = libinput_event_touch_get_time(tevent); wlr_event.time_usec = libinput_event_touch_get_time_usec(tevent); wlr_event.slot = libinput_event_touch_get_slot(tevent); @@ -67,6 +69,7 @@ void handle_touch_motion(struct libinput_event *event, struct libinput_event_touch *tevent = libinput_event_get_touch_event(event); struct wlr_event_touch_motion wlr_event = { 0 }; + wlr_event.device = wlr_dev; wlr_event.time_sec = libinput_event_touch_get_time(tevent); wlr_event.time_usec = libinput_event_touch_get_time_usec(tevent); wlr_event.slot = libinput_event_touch_get_slot(tevent); @@ -87,6 +90,7 @@ void handle_touch_cancel(struct libinput_event *event, struct libinput_event_touch *tevent = libinput_event_get_touch_event(event); struct wlr_event_touch_cancel wlr_event = { 0 }; + wlr_event.device = wlr_dev; wlr_event.time_sec = libinput_event_touch_get_time(tevent); wlr_event.time_usec = libinput_event_touch_get_time_usec(tevent); wlr_event.slot = libinput_event_touch_get_slot(tevent); diff --git a/include/wlr/types/wlr_touch.h b/include/wlr/types/wlr_touch.h index 93069fcb..1a27cad3 100644 --- a/include/wlr/types/wlr_touch.h +++ b/include/wlr/types/wlr_touch.h @@ -19,6 +19,7 @@ struct wlr_touch { }; struct wlr_event_touch_down { + struct wlr_input_device *device; uint32_t time_sec; uint64_t time_usec; int32_t slot; @@ -27,12 +28,14 @@ struct wlr_event_touch_down { }; struct wlr_event_touch_up { + struct wlr_input_device *device; uint32_t time_sec; uint64_t time_usec; int32_t slot; }; struct wlr_event_touch_motion { + struct wlr_input_device *device; uint32_t time_sec; uint64_t time_usec; int32_t slot; @@ -41,6 +44,7 @@ struct wlr_event_touch_motion { }; struct wlr_event_touch_cancel { + struct wlr_input_device *device; uint32_t time_sec; uint64_t time_usec; int32_t slot; From 5e06d61e4238f7e2ebc9ac4750ff477423b02279 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 27 Aug 2017 17:35:12 -0400 Subject: [PATCH 19/34] implement touch up and touch down --- examples/pointer.c | 20 ++++-- include/wlr/types/wlr_cursor.h | 3 + include/wlr/types/wlr_geometry.h | 2 + include/wlr/types/wlr_output_layout.h | 13 ++++ types/wlr_cursor.c | 92 +++++++++++++++++++++------ types/wlr_geometry.c | 22 ++----- types/wlr_output_layout.c | 89 ++++++++++++++++++++++---- 7 files changed, 189 insertions(+), 52 deletions(-) diff --git a/examples/pointer.c b/examples/pointer.c index bae205f5..98b4735a 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -58,12 +58,20 @@ struct touch_point { double x, y; }; -static void warp_to_touch(struct sample_state *sample) { - wlr_log(L_DEBUG, "TODO: warp to touch"); +static void warp_to_touch(struct sample_state *sample, struct wlr_input_device *dev) { + if (sample->touch_points->length == 0) { + return; + } + + double x = 0, y = 0; for (size_t i = 0; i < sample->touch_points->length; ++i) { struct touch_point *point = sample->touch_points->items[i]; - wlr_log(L_DEBUG, "have point x=%f,y=%f", point->x, point->y); + x += point->x; + y += point->y; } + x /= sample->touch_points->length; + y /= sample->touch_points->length; + wlr_cursor_warp_absolute(sample->cursor, dev, x, y); } static void handle_output_frame(struct output_state *output, struct timespec *ts) { @@ -248,7 +256,7 @@ static void handle_touch_up(struct wl_listener *listener, void *data) { } } - warp_to_touch(sample); + warp_to_touch(sample, event->device); } static void handle_touch_down(struct wl_listener *listener, void *data) { @@ -262,7 +270,7 @@ static void handle_touch_down(struct wl_listener *listener, void *data) { free(point); } - warp_to_touch(sample); + warp_to_touch(sample, event->device); } static void handle_touch_motion(struct wl_listener *listener, void *data) { @@ -277,7 +285,7 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) { } } - warp_to_touch(sample); + warp_to_touch(sample, event->device); } static void handle_touch_cancel(struct wl_listener *listener, void *data) { diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index ad5c52a4..4ba7b25f 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -46,6 +46,9 @@ void wlr_cursor_set_xcursor(struct wlr_cursor *cur, struct wlr_xcursor *xcur); bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev, double x, double y); +void wlr_cursor_warp_absolute(struct wlr_cursor *cur, + struct wlr_input_device *dev, double x_mm, double y_mm); + /** * Move the cursor in the direction of the given x and y coordinates. * diff --git a/include/wlr/types/wlr_geometry.h b/include/wlr/types/wlr_geometry.h index 7ac2f843..cac75431 100644 --- a/include/wlr/types/wlr_geometry.h +++ b/include/wlr/types/wlr_geometry.h @@ -15,4 +15,6 @@ bool wlr_geometry_intersection(struct wlr_geometry *geo_a, bool wlr_geometry_contains_point(struct wlr_geometry *geo, int x, int y); +bool wlr_geometry_empty(struct wlr_geometry *geo); + #endif diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index 144c2d5a..0d157f56 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -4,14 +4,20 @@ #include #include +struct wlr_output_layout_state; + struct wlr_output_layout { struct wl_list outputs; + struct wlr_output_layout_state *state; }; +struct wlr_output_layout_output_state; + struct wlr_output_layout_output { struct wlr_output *output; int x, y; struct wl_list link; + struct wlr_output_layout_output_state *state; }; struct wlr_output_layout *wlr_output_layout_init(); @@ -55,4 +61,11 @@ void wlr_output_layout_closest_boundary(struct wlr_output_layout *layout, struct wlr_output *reference, double x, double y, double *dest_x, double *dest_y); +/** + * Get the geometry of the layout for the given reference output. If `reference` + * is NULL, the geometry will be for the extents of the entire layout. + */ +struct wlr_geometry *wlr_output_layout_get_geometry( + struct wlr_output_layout *layout, struct wlr_output *reference); + #endif diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index f9e1fcc9..f315727f 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -95,6 +96,29 @@ static struct wlr_cursor_device *get_cursor_device(struct wlr_cursor *cur, return ret; } +static void wlr_cursor_warp_unchecked(struct wlr_cursor *cur, double x, double y) { + int hotspot_x = 0; + int hotspot_y = 0; + + if (cur->state->xcursor && cur->state->xcursor->image_count > 0) { + struct wlr_xcursor_image *image = cur->state->xcursor->images[0]; + hotspot_x = image->hotspot_x; + hotspot_y = image->hotspot_y; + } + + + struct wlr_output_layout_output *l_output; + wl_list_for_each(l_output, &cur->state->layout->outputs, link) { + double output_x = x; + double output_y = y; + + wlr_output_layout_output_coords(cur->state->layout, + l_output->output, &output_x, &output_y); + wlr_output_move_cursor(l_output->output, output_x - hotspot_x, + output_y - hotspot_y); + } +} + bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev, double x, double y) { assert(cur->state->layout); @@ -120,28 +144,59 @@ bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev, return false; } - int hotspot_x = 0; - int hotspot_y = 0; + wlr_cursor_warp_unchecked(cur, x, y); + return true; +} - if (cur->state->xcursor && cur->state->xcursor->image_count > 0) { - struct wlr_xcursor_image *image = cur->state->xcursor->images[0]; - hotspot_x = image->hotspot_x; - hotspot_y = image->hotspot_y; +void wlr_cursor_warp_absolute(struct wlr_cursor *cur, + struct wlr_input_device *dev, double x_mm, double y_mm) { + // convert from absolute to global coordinates + assert(cur->state->layout); + struct wlr_output *mapped_output = NULL; + struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); + + if (c_device && c_device->mapped_output) { + mapped_output = c_device->mapped_output; + } else { + mapped_output = cur->state->mapped_output; } + struct wlr_geometry *constraints = calloc(1, sizeof(struct wlr_geometry)); + // XXX how do we express infinite regions? + constraints->x = INT_MIN / 2; + constraints->y = INT_MIN / 2; + constraints->width = INT_MAX; + constraints->height = INT_MAX; - struct wlr_output_layout_output *l_output; - wl_list_for_each(l_output, &cur->state->layout->outputs, link) { - double output_x = x; - double output_y = y; + if (cur->state->mapped_geometry) { + wlr_geometry_intersection(cur->state->mapped_geometry, constraints, + &constraints); + } + if (c_device->mapped_geometry) { + wlr_geometry_intersection(c_device->mapped_geometry, constraints, + &constraints); + } + struct wlr_geometry *geo; + if (mapped_output) { + geo = wlr_output_layout_get_geometry(cur->state->layout, mapped_output); + wlr_geometry_intersection(geo, constraints, &constraints); + } + geo = wlr_output_layout_get_geometry(cur->state->layout, NULL); + wlr_geometry_intersection(geo, constraints, &constraints); - wlr_output_layout_output_coords(cur->state->layout, - l_output->output, &output_x, &output_y); - wlr_output_move_cursor(l_output->output, output_x - hotspot_x, - output_y - hotspot_y); + if (wlr_geometry_empty(constraints)) { + goto out; } - return true; + double x = constraints->width * x_mm + constraints->x; + double y = constraints->height * y_mm + constraints->y; + + wlr_cursor_warp_unchecked(cur, x, y); + +out: + if (constraints) { + free(constraints); + } } void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, @@ -195,10 +250,9 @@ void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, goto out; } - if (wlr_cursor_warp(cur, dev, x, y)) { - cur->x = x; - cur->y = y; - } + wlr_cursor_warp_unchecked(cur, x, y); + cur->x = x; + cur->y = y; out: if (constraints) { diff --git a/types/wlr_geometry.c b/types/wlr_geometry.c index be4a80eb..32dbb81f 100644 --- a/types/wlr_geometry.c +++ b/types/wlr_geometry.c @@ -45,8 +45,8 @@ void wlr_geometry_closest_boundary(struct wlr_geometry *geo, double x, double y, #define min(a,b) ((a) < (b) ? (a) : (b)) #endif -static bool wlr_geometry_empty(struct wlr_geometry *geo) { - return geo == NULL || geo->width < 0 || geo->height < 0; +bool wlr_geometry_empty(struct wlr_geometry *geo) { + return geo == NULL || geo->width <= 0 || geo->height <= 0; } bool wlr_geometry_intersection(struct wlr_geometry *geo_a, @@ -55,20 +55,12 @@ bool wlr_geometry_intersection(struct wlr_geometry *geo_a, bool a_empty = wlr_geometry_empty(geo_a); bool b_empty = wlr_geometry_empty(geo_b); - if (a_empty && b_empty) { + if (a_empty || b_empty) { + dest->x = 0; + dest->y = 0; + dest->width = -100; + dest->height = -100; return false; - } else if (a_empty) { - dest->x = geo_b->x; - dest->y = geo_b->y; - dest->height = geo_b->height; - dest->width = geo_b->width; - return true; - } else if (b_empty) { - dest->x = geo_a->x; - dest->y = geo_a->y; - dest->height = geo_a->height; - dest->width = geo_a->width; - return true; } int x1 = max(geo_a->x, geo_b->x); diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 7dcb4651..0b5e0411 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -1,16 +1,35 @@ #include #include #include +#include #include #include #include +struct wlr_output_layout_state { + struct wlr_geometry *_geo; +}; + +struct wlr_output_layout_output_state { + struct wlr_geometry *_geo; +}; + struct wlr_output_layout *wlr_output_layout_init() { struct wlr_output_layout *layout = calloc(1, sizeof(struct wlr_output_layout)); + layout->state = calloc(1, sizeof(struct wlr_output_layout_state)); + layout->state->_geo = calloc(1, sizeof(struct wlr_geometry)); wl_list_init(&layout->outputs); return layout; } +static void wlr_output_layout_output_destroy( + struct wlr_output_layout_output *l_output) { + wl_list_remove(&l_output->link); + free(l_output->state->_geo); + free(l_output->state); + free(l_output); +} + void wlr_output_layout_destroy(struct wlr_output_layout *layout) { if (!layout) { return; @@ -18,20 +37,24 @@ void wlr_output_layout_destroy(struct wlr_output_layout *layout) { struct wlr_output_layout_output *_output, *temp = NULL; wl_list_for_each_safe(_output, temp, &layout->outputs, link) { - wl_list_remove(&_output->link); - free(_output); + wlr_output_layout_output_destroy(_output); } + free(layout->state->_geo); + free(layout->state); free(layout); } void wlr_output_layout_add(struct wlr_output_layout *layout, struct wlr_output *output, int x, int y) { - struct wlr_output_layout_output *layout_output = calloc(1, sizeof(struct wlr_output_layout_output)); - layout_output->output = output; - layout_output->x = x; - layout_output->y = y; - wl_list_insert(&layout->outputs, &layout_output->link); + struct wlr_output_layout_output *l_output; + l_output= calloc(1, sizeof(struct wlr_output_layout_output)); + l_output->state = calloc(1, sizeof(struct wlr_output_layout_output_state)); + l_output->state->_geo = calloc(1, sizeof(struct wlr_geometry)); + l_output->output = output; + l_output->x = x; + l_output->y = y; + wl_list_insert(&layout->outputs, &l_output->link); } struct wlr_output_layout_output *wlr_output_layout_get( @@ -104,11 +127,10 @@ void wlr_output_layout_move(struct wlr_output_layout *layout, void wlr_output_layout_remove(struct wlr_output_layout *layout, struct wlr_output *output) { - struct wlr_output_layout_output *layout_output = - wlr_output_layout_get(layout, output); - if (layout_output) { - wl_list_remove(&layout_output->link); - free(layout_output); + struct wlr_output_layout_output *l_output; + l_output= wlr_output_layout_get(layout, output); + if (l_output) { + wlr_output_layout_output_destroy(l_output); } } @@ -179,3 +201,46 @@ void wlr_output_layout_closest_boundary(struct wlr_output_layout *layout, *dest_x = min_x; *dest_y = min_y; } + +struct wlr_geometry *wlr_output_layout_get_geometry( + struct wlr_output_layout *layout, struct wlr_output *reference) { + struct wlr_output_layout_output *l_output; + if (reference) { + // output extents + l_output= wlr_output_layout_get(layout, reference); + l_output->state->_geo->x = l_output->x; + l_output->state->_geo->y = l_output->y; + wlr_output_effective_resolution(reference, + &l_output->state->_geo->width, &l_output->state->_geo->height); + return l_output->state->_geo; + } else { + // layout extents + int min_x = INT_MAX, min_y = INT_MAX; + int max_x = INT_MIN, max_y = INT_MIN; + wl_list_for_each(l_output, &layout->outputs, link) { + int width, height; + wlr_output_effective_resolution(l_output->output, &width, &height); + if (l_output->x < min_x) { + min_x = l_output->x; + } + if (l_output->y < min_y) { + min_y = l_output->y; + } + if (l_output->x + width > max_x) { + max_x = l_output->x + width; + } + if (l_output->y + height > max_y) { + max_y = l_output->y + height; + } + } + + layout->state->_geo->x = min_x; + layout->state->_geo->y = min_y; + layout->state->_geo->width = max_x - min_x; + layout->state->_geo->height = max_y - min_y; + + return layout->state->_geo; + } + + // not reached +} From 0dc3aecfd4db39953503ccdc82ab44ace03c7f44 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 27 Aug 2017 20:10:46 -0400 Subject: [PATCH 20/34] refactor device mapping calculation --- types/wlr_cursor.c | 188 +++++++++++++++++--------------------- types/wlr_geometry.c | 8 +- types/wlr_output_layout.c | 12 ++- 3 files changed, 98 insertions(+), 110 deletions(-) diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index f315727f..f183e64a 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -97,6 +97,7 @@ static struct wlr_cursor_device *get_cursor_device(struct wlr_cursor *cur, } static void wlr_cursor_warp_unchecked(struct wlr_cursor *cur, double x, double y) { + assert(cur->state->layout); int hotspot_x = 0; int hotspot_y = 0; @@ -119,145 +120,111 @@ static void wlr_cursor_warp_unchecked(struct wlr_cursor *cur, double x, double y } } -bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev, - double x, double y) { +/** + * Get the most specific mapping box for the device in this order: + * + * 1. device geometry mapping + * 2. device output mapping + * 3. cursor geometry mapping + * 4. cursor output mapping + * + * Absolute movement for touch and pen devices will be relative to this box and + * pointer movement will be constrained to this box. + * + * If none of these are set, returns NULL and absolute movement should be + * relative to the extents of the layout. + */ +static struct wlr_geometry *get_mapping(struct wlr_cursor *cur, + struct wlr_input_device *dev) { assert(cur->state->layout); - struct wlr_output *output; - output = wlr_output_layout_output_at(cur->state->layout, x, y); - - struct wlr_output *mapped_output = NULL; struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); - if (c_device && c_device->mapped_output) { - mapped_output = c_device->mapped_output; - } else { - mapped_output = cur->state->mapped_output; + if (c_device) { + if (c_device->mapped_geometry) { + return c_device->mapped_geometry; + } + if (c_device->mapped_output) { + return wlr_output_layout_get_geometry(cur->state->layout, + c_device->mapped_output); + } } - if (!output) { - return false; + if (cur->state->mapped_geometry) { + return cur->state->mapped_geometry; } - - if (mapped_output && - !wlr_output_layout_contains_point(cur->state->layout, mapped_output, - x, y)) { - return false; + if(cur->state->mapped_output) { + return wlr_output_layout_get_geometry(cur->state->layout, + cur->state->mapped_output); } - wlr_cursor_warp_unchecked(cur, x, y); - return true; + return NULL; } -void wlr_cursor_warp_absolute(struct wlr_cursor *cur, - struct wlr_input_device *dev, double x_mm, double y_mm) { - // convert from absolute to global coordinates +bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev, + double x, double y) { assert(cur->state->layout); - struct wlr_output *mapped_output = NULL; - struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); + bool result = false; - if (c_device && c_device->mapped_output) { - mapped_output = c_device->mapped_output; - } else { - mapped_output = cur->state->mapped_output; + struct wlr_geometry *mapping = get_mapping(cur, dev); + + if (mapping) { + if (wlr_geometry_contains_point(mapping, x, y)) { + wlr_cursor_warp_unchecked(cur, x, y); + result = true; + } + } else if (wlr_output_layout_contains_point(cur->state->layout, NULL, x, y)) { + wlr_cursor_warp_unchecked(cur, x, y); + result = true; } - struct wlr_geometry *constraints = calloc(1, sizeof(struct wlr_geometry)); - // XXX how do we express infinite regions? - constraints->x = INT_MIN / 2; - constraints->y = INT_MIN / 2; - constraints->width = INT_MAX; - constraints->height = INT_MAX; + return result; +} - if (cur->state->mapped_geometry) { - wlr_geometry_intersection(cur->state->mapped_geometry, constraints, - &constraints); - } - if (c_device->mapped_geometry) { - wlr_geometry_intersection(c_device->mapped_geometry, constraints, - &constraints); - } - struct wlr_geometry *geo; - if (mapped_output) { - geo = wlr_output_layout_get_geometry(cur->state->layout, mapped_output); - wlr_geometry_intersection(geo, constraints, &constraints); - } - geo = wlr_output_layout_get_geometry(cur->state->layout, NULL); - wlr_geometry_intersection(geo, constraints, &constraints); +void wlr_cursor_warp_absolute(struct wlr_cursor *cur, + struct wlr_input_device *dev, double x_mm, double y_mm) { + assert(cur->state->layout); - if (wlr_geometry_empty(constraints)) { - goto out; + struct wlr_geometry *mapping = get_mapping(cur, dev); + if (!mapping) { + mapping = wlr_output_layout_get_geometry(cur->state->layout, NULL); } - double x = constraints->width * x_mm + constraints->x; - double y = constraints->height * y_mm + constraints->y; + double x = mapping->width * x_mm + mapping->x; + double y = mapping->height * y_mm + mapping->y; wlr_cursor_warp_unchecked(cur, x, y); - -out: - if (constraints) { - free(constraints); - } } void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, double delta_x, double delta_y) { assert(cur->state->layout); - struct wlr_output *mapped_output = NULL; - struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); - - if (c_device && c_device->mapped_output) { - mapped_output = c_device->mapped_output; - } else { - mapped_output = cur->state->mapped_output; - } double x = cur->x + delta_x; double y = cur->y + delta_y; - // geometry constraints - struct wlr_geometry *constraints = NULL; - if (cur->state->mapped_geometry != NULL || - c_device->mapped_geometry != NULL) { - constraints = calloc(1, sizeof(struct wlr_geometry)); + struct wlr_geometry *mapping = get_mapping(cur, dev); - if (!wlr_geometry_intersection(cur->state->mapped_geometry, - c_device->mapped_geometry, &constraints)) { - // TODO handle no possible movement - goto out; + if (mapping) { + int boundary_x, boundary_y; + if (!wlr_geometry_contains_point(mapping, x, y)) { + wlr_geometry_closest_boundary(mapping, x, y, &boundary_x, + &boundary_y, NULL); + x = boundary_x; + y = boundary_y; + } + } else { + if (!wlr_output_layout_contains_point(cur->state->layout, NULL, x, y)) { + double boundary_x, boundary_y; + wlr_output_layout_closest_boundary(cur->state->layout, NULL, x, y, + &boundary_x, &boundary_y); + x = boundary_x; + y = boundary_y; } - - int closest_x, closest_y; - wlr_geometry_closest_boundary(constraints, x, y, - &closest_x, &closest_y, NULL); - x = closest_x; - y = closest_y; - } - - // layout constraints - struct wlr_output *output; - output = wlr_output_layout_output_at(cur->state->layout, x, y); - - if (!output || (mapped_output && mapped_output != output)) { - double closest_x, closest_y; - wlr_output_layout_closest_boundary(cur->state->layout, mapped_output, x, - y, &closest_x, &closest_y); - x = closest_x; - y = closest_y; - } - - if (constraints && !wlr_geometry_contains_point(constraints, x, y)) { - // TODO handle no possible movement - goto out; } wlr_cursor_warp_unchecked(cur, x, y); cur->x = x; cur->y = y; - -out: - if (constraints) { - free(constraints); - } } static void handle_pointer_motion(struct wl_listener *listener, void *data) { @@ -416,15 +383,28 @@ void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, } void wlr_cursor_map_to_region(struct wlr_cursor *cur, struct wlr_geometry *geo) { + if (geo && wlr_geometry_empty(geo)) { + wlr_log(L_ERROR, "cannot map cursor to an empty region"); + return; + } + cur->state->mapped_geometry = geo; } void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, struct wlr_input_device *dev, struct wlr_geometry *geo) { + if (geo && wlr_geometry_empty(geo)) { + wlr_log(L_ERROR, "cannot map device \"%s\" input to an empty region", + dev->name); + return; + } + struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); if (!c_device) { - wlr_log(L_ERROR, "Cannot map device \"%s\" to geometry (not found in this cursor)", dev->name); + wlr_log(L_ERROR, "Cannot map device \"%s\" to geometry (not found in" + "this cursor)", dev->name); return; } + c_device->mapped_geometry = geo; } diff --git a/types/wlr_geometry.c b/types/wlr_geometry.c index 32dbb81f..4f532d6f 100644 --- a/types/wlr_geometry.c +++ b/types/wlr_geometry.c @@ -77,6 +77,10 @@ bool wlr_geometry_intersection(struct wlr_geometry *geo_a, } bool wlr_geometry_contains_point(struct wlr_geometry *geo, int x, int y) { - return x >= geo->x && x <= geo->x + geo->width && - y >= geo->y && y <= geo->y + geo->height; + if (wlr_geometry_empty(geo)) { + return false; + } else { + return x >= geo->x && x <= geo->x + geo->width && + y >= geo->y && y <= geo->y + geo->height; + } } diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 0b5e0411..4062c107 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -76,10 +76,14 @@ static bool output_contains_point( struct wlr_output_layout_output *l_output, bool wlr_output_layout_contains_point(struct wlr_output_layout *layout, struct wlr_output *reference, int x, int y) { - struct wlr_output_layout_output *layout_output = wlr_output_layout_get(layout, reference); - int width, height; - wlr_output_effective_resolution(layout_output->output, &width, &height); - return output_contains_point(layout_output, x, y, width, height); + if (reference) { + struct wlr_output_layout_output *layout_output = wlr_output_layout_get(layout, reference); + int width, height; + wlr_output_effective_resolution(layout_output->output, &width, &height); + return output_contains_point(layout_output, x, y, width, height); + } else { + return !!wlr_output_layout_output_at(layout, x, y); + } } bool wlr_output_layout_intersects(struct wlr_output_layout *layout, From df0ee7f25ff628360f38d87b8a74daaa2cc742a8 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 28 Aug 2017 08:42:39 -0400 Subject: [PATCH 21/34] implement tablet tool devices --- backend/libinput/tablet_tool.c | 4 ++ examples/pointer.c | 4 +- include/wlr/types/wlr_cursor.h | 5 +++ include/wlr/types/wlr_tablet_tool.h | 4 ++ types/wlr_cursor.c | 61 +++++++++++++++++++++++++---- 5 files changed, 69 insertions(+), 9 deletions(-) diff --git a/backend/libinput/tablet_tool.c b/backend/libinput/tablet_tool.c index 8b3d34ed..472e8506 100644 --- a/backend/libinput/tablet_tool.c +++ b/backend/libinput/tablet_tool.c @@ -30,6 +30,7 @@ void handle_tablet_tool_axis(struct libinput_event *event, struct libinput_event_tablet_tool *tevent = libinput_event_get_tablet_tool_event(event); struct wlr_event_tablet_tool_axis wlr_event = { 0 }; + wlr_event.device = wlr_dev; wlr_event.time_sec = libinput_event_tablet_tool_get_time(tevent); wlr_event.time_usec = libinput_event_tablet_tool_get_time_usec(tevent); libinput_device_get_size(libinput_dev, &wlr_event.width_mm, &wlr_event.height_mm); @@ -83,6 +84,7 @@ void handle_tablet_tool_proximity(struct libinput_event *event, struct libinput_event_tablet_tool *tevent = libinput_event_get_tablet_tool_event(event); struct wlr_event_tablet_tool_proximity wlr_event = { 0 }; + wlr_event.device = wlr_dev; wlr_event.time_sec = libinput_event_tablet_tool_get_time(tevent); wlr_event.time_usec = libinput_event_tablet_tool_get_time_usec(tevent); switch (libinput_event_tablet_tool_get_proximity_state(tevent)) { @@ -109,6 +111,7 @@ void handle_tablet_tool_tip(struct libinput_event *event, struct libinput_event_tablet_tool *tevent = libinput_event_get_tablet_tool_event(event); struct wlr_event_tablet_tool_tip wlr_event = { 0 }; + wlr_event.device = wlr_dev; wlr_event.time_sec = libinput_event_tablet_tool_get_time(tevent); wlr_event.time_usec = libinput_event_tablet_tool_get_time_usec(tevent); switch (libinput_event_tablet_tool_get_tip_state(tevent)) { @@ -134,6 +137,7 @@ void handle_tablet_tool_button(struct libinput_event *event, struct libinput_event_tablet_tool *tevent = libinput_event_get_tablet_tool_event(event); struct wlr_event_tablet_tool_button wlr_event = { 0 }; + wlr_event.device = wlr_dev; wlr_event.time_sec = libinput_event_tablet_tool_get_time(tevent); wlr_event.time_usec = libinput_event_tablet_tool_get_time_usec(tevent); wlr_event.button = libinput_event_tablet_tool_get_button(tevent); diff --git a/examples/pointer.c b/examples/pointer.c index 98b4735a..3863c0e8 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -175,9 +175,9 @@ static void handle_input_add(struct compositor_state *state, struct wlr_input_device *device) { struct sample_state *sample = state->data; - // TODO handle other input devices if (device->type == WLR_INPUT_DEVICE_POINTER || - device->type == WLR_INPUT_DEVICE_TOUCH) { + device->type == WLR_INPUT_DEVICE_TOUCH || + device->type == WLR_INPUT_DEVICE_TABLET_TOOL) { struct sample_input_device *s_device; s_device = calloc(1, sizeof(struct sample_input_device)); s_device->device = device; diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index 4ba7b25f..35c2ff8e 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -25,6 +25,11 @@ struct wlr_cursor { struct wl_signal touch_down; struct wl_signal touch_motion; struct wl_signal touch_cancel; + + struct wl_signal tablet_tool_axis; + struct wl_signal tablet_tool_proximity; + struct wl_signal tablet_tool_tip; + struct wl_signal tablet_tool_button; } events; }; diff --git a/include/wlr/types/wlr_tablet_tool.h b/include/wlr/types/wlr_tablet_tool.h index dcb9c191..98fd82c0 100644 --- a/include/wlr/types/wlr_tablet_tool.h +++ b/include/wlr/types/wlr_tablet_tool.h @@ -32,6 +32,7 @@ enum wlr_tablet_tool_axes { }; struct wlr_event_tablet_tool_axis { + struct wlr_input_device *device; uint32_t time_sec; uint64_t time_usec; uint32_t updated_axes; @@ -51,6 +52,7 @@ enum wlr_tablet_tool_proximity_state { }; struct wlr_event_tablet_tool_proximity { + struct wlr_input_device *device; uint32_t time_sec; uint64_t time_usec; double x, y; @@ -64,6 +66,7 @@ enum wlr_tablet_tool_tip_state { }; struct wlr_event_tablet_tool_tip { + struct wlr_input_device *device; uint32_t time_sec; uint64_t time_usec; double x, y; @@ -72,6 +75,7 @@ struct wlr_event_tablet_tool_tip { }; struct wlr_event_tablet_tool_button { + struct wlr_input_device *device; uint32_t time_sec; uint64_t time_usec; uint32_t button; diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index f183e64a..c62fba9b 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -24,6 +24,11 @@ struct wlr_cursor_device { struct wl_listener touch_up; struct wl_listener touch_motion; struct wl_listener touch_cancel; + + struct wl_listener tablet_tool_axis; + struct wl_listener tablet_tool_proximity; + struct wl_listener tablet_tool_tip; + struct wl_listener tablet_tool_button; }; struct wlr_cursor_state { @@ -63,6 +68,12 @@ struct wlr_cursor *wlr_cursor_init() { wl_signal_init(&cur->events.touch_motion); wl_signal_init(&cur->events.touch_cancel); + // tablet tool signals + wl_signal_init(&cur->events.tablet_tool_tip); + wl_signal_init(&cur->events.tablet_tool_axis); + wl_signal_init(&cur->events.tablet_tool_button); + wl_signal_init(&cur->events.tablet_tool_proximity); + cur->x = 100; cur->y = 100; @@ -279,6 +290,34 @@ static void handle_touch_cancel(struct wl_listener *listener, void *data) { wl_signal_emit(&device->cursor->events.touch_cancel, event); } +static void handle_tablet_tool_tip(struct wl_listener *listener, void *data) { + struct wlr_event_tablet_tool_tip *event = data; + struct wlr_cursor_device *device; + device = wl_container_of(listener, device, tablet_tool_tip); + wl_signal_emit(&device->cursor->events.tablet_tool_tip, event); +} + +static void handle_tablet_tool_axis(struct wl_listener *listener, void *data) { + struct wlr_event_tablet_tool_axis *event = data; + struct wlr_cursor_device *device; + device = wl_container_of(listener, device, tablet_tool_axis); + wl_signal_emit(&device->cursor->events.tablet_tool_axis, event); +} + +static void handle_tablet_tool_button(struct wl_listener *listener, void *data) { + struct wlr_event_tablet_tool_button *event = data; + struct wlr_cursor_device *device; + device = wl_container_of(listener, device, tablet_tool_button); + wl_signal_emit(&device->cursor->events.tablet_tool_button, event); +} + +static void handle_tablet_tool_proximity(struct wl_listener *listener, void *data) { + struct wlr_event_tablet_tool_proximity *event = data; + struct wlr_cursor_device *device; + device = wl_container_of(listener, device, tablet_tool_proximity); + wl_signal_emit(&device->cursor->events.tablet_tool_proximity, event); +} + void wlr_cursor_attach_input_device(struct wlr_cursor *cur, struct wlr_input_device *dev) { if (dev->type != WLR_INPUT_DEVICE_POINTER && @@ -289,13 +328,6 @@ void wlr_cursor_attach_input_device(struct wlr_cursor *cur, return; } - // TODO support other device types - if (dev->type != WLR_INPUT_DEVICE_POINTER && - dev->type != WLR_INPUT_DEVICE_TOUCH) { - wlr_log(L_ERROR, "TODO: support tablet tool devices"); - return; - } - // make sure it is not already attached struct wlr_cursor_device *_dev; wl_list_for_each(_dev, &cur->state->devices, link) { @@ -340,6 +372,21 @@ void wlr_cursor_attach_input_device(struct wlr_cursor *cur, wl_signal_add(&dev->touch->events.cancel, &device->touch_cancel); device->touch_cancel.notify = handle_touch_cancel; + } else if (dev->type == WLR_INPUT_DEVICE_TABLET_TOOL) { + wl_signal_add(&dev->tablet_tool->events.tip, &device->tablet_tool_tip); + device->tablet_tool_tip.notify = handle_tablet_tool_tip; + + wl_signal_add(&dev->tablet_tool->events.proximity, + &device->tablet_tool_proximity); + device->tablet_tool_proximity.notify = handle_tablet_tool_proximity; + + wl_signal_add(&dev->tablet_tool->events.axis, + &device->tablet_tool_axis); + device->tablet_tool_axis.notify = handle_tablet_tool_axis; + + wl_signal_add(&dev->tablet_tool->events.button, + &device->tablet_tool_button); + device->tablet_tool_button.notify = handle_tablet_tool_button; } wl_list_insert(&cur->state->devices, &device->link); From 5c845f14ed72bcdbd45a2e719223c441846f62ad Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 28 Aug 2017 10:29:53 -0400 Subject: [PATCH 22/34] handle input device destroy --- examples/pointer.c | 15 +++++++++++++-- examples/shared.c | 5 +++++ examples/shared.h | 2 ++ include/wlr/types/wlr_input_device.h | 4 ++++ types/wlr_cursor.c | 11 +++++++++++ types/wlr_input_device.c | 4 ++++ 6 files changed, 39 insertions(+), 2 deletions(-) diff --git a/examples/pointer.c b/examples/pointer.c index 3863c0e8..8ad18442 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -188,6 +188,18 @@ static void handle_input_add(struct compositor_state *state, struct } } +static void handle_input_remove(struct compositor_state *state, struct + wlr_input_device *device) { + struct sample_state *sample = state->data; + struct sample_input_device *s_device, *tmp = NULL; + wl_list_for_each_safe(s_device, tmp, &sample->devices, link) { + if (s_device->device == device) { + wl_list_remove(&s_device->link); + free(s_device); + } + } +} + static void handle_cursor_motion(struct wl_listener *listener, void *data) { struct sample_state *sample = wl_container_of(listener, sample, cursor_motion); struct wlr_event_pointer_motion *event = data; @@ -339,8 +351,7 @@ int main(int argc, char *argv[]) { compositor.output_resolution_cb = handle_output_resolution; compositor.output_frame_cb = handle_output_frame; compositor.input_add_cb = handle_input_add; - // TODO input_remove_cb - //compositor.input_remove_cb = handle_input_add; + compositor.input_remove_cb = handle_input_remove; state.compositor = &compositor; diff --git a/examples/shared.c b/examples/shared.c index f9d687e3..0346c96d 100644 --- a/examples/shared.c +++ b/examples/shared.c @@ -401,6 +401,11 @@ static void tablet_pad_remove(struct wlr_input_device *device, struct compositor 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_remove); + + if (state->input_remove_cb) { + state->input_remove_cb(state, device); + } + switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD: keyboard_remove(device, state); diff --git a/examples/shared.h b/examples/shared.h index 06108494..7cf4db63 100644 --- a/examples/shared.h +++ b/examples/shared.h @@ -77,6 +77,8 @@ struct tablet_pad_state { struct compositor_state { void (*input_add_cb)(struct compositor_state *compositor, struct wlr_input_device *device); + void (*input_remove_cb)(struct compositor_state *compositor, + struct wlr_input_device *device); 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); diff --git a/include/wlr/types/wlr_input_device.h b/include/wlr/types/wlr_input_device.h index 642892ff..5a41ce9d 100644 --- a/include/wlr/types/wlr_input_device.h +++ b/include/wlr/types/wlr_input_device.h @@ -40,6 +40,10 @@ struct wlr_input_device { struct wlr_tablet_pad *tablet_pad; }; + struct { + struct wl_signal destroy; + } events; + void *data; }; diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index c62fba9b..ff19bb2b 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -29,6 +29,8 @@ struct wlr_cursor_device { struct wl_listener tablet_tool_proximity; struct wl_listener tablet_tool_tip; struct wl_listener tablet_tool_button; + + struct wl_listener destroy; }; struct wlr_cursor_state { @@ -318,6 +320,12 @@ static void handle_tablet_tool_proximity(struct wl_listener *listener, void *dat wl_signal_emit(&device->cursor->events.tablet_tool_proximity, event); } +static void handle_device_destroy(struct wl_listener *listener, void *data) { + struct wlr_cursor_device *c_device; + c_device = wl_container_of(listener, c_device, destroy); + wlr_cursor_detach_input_device(c_device->cursor, c_device->device); +} + void wlr_cursor_attach_input_device(struct wlr_cursor *cur, struct wlr_input_device *dev) { if (dev->type != WLR_INPUT_DEVICE_POINTER && @@ -348,6 +356,9 @@ void wlr_cursor_attach_input_device(struct wlr_cursor *cur, // listen to events + wl_signal_add(&dev->events.destroy, &device->destroy); + device->destroy.notify = handle_device_destroy; + if (dev->type == WLR_INPUT_DEVICE_POINTER) { wl_signal_add(&dev->pointer->events.motion, &device->motion); device->motion.notify = handle_pointer_motion; diff --git a/types/wlr_input_device.c b/types/wlr_input_device.c index 409e8bd1..002c2b54 100644 --- a/types/wlr_input_device.c +++ b/types/wlr_input_device.c @@ -20,12 +20,16 @@ void wlr_input_device_init(struct wlr_input_device *dev, dev->name = strdup(name); dev->vendor = vendor; dev->product = product; + + wl_signal_init(&dev->events.destroy); } void wlr_input_device_destroy(struct wlr_input_device *dev) { if (!dev) { return; } + + wl_signal_emit(&dev->events.destroy, dev); if (dev->_device) { switch (dev->type) { From ab1a12b17463757cbbed4ad472797a8ed699671b Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 28 Aug 2017 11:07:21 -0400 Subject: [PATCH 23/34] fix formatting in types/meson.build --- types/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/meson.build b/types/meson.build index d0ed85fe..8b8b215b 100644 --- a/types/meson.build +++ b/types/meson.build @@ -16,7 +16,7 @@ lib_wlr_types = static_library('wlr_types', files( 'wlr_xdg_shell_v6.c', 'wlr_wl_shell.c', 'wlr_compositor.c', - 'wlr_geometry.c', + 'wlr_geometry.c', ), include_directories: wlr_inc, dependencies: [wayland_server, pixman, wlr_protos]) From 4fbe322fa6fcdbfda6b7006869358fdb47caff6e Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 28 Aug 2017 11:07:54 -0400 Subject: [PATCH 24/34] fix memory errors --- examples/pointer.c | 2 +- examples/touch.c | 2 +- types/wlr_cursor.c | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/pointer.c b/examples/pointer.c index 8ad18442..936bfb6a 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -274,7 +274,7 @@ static void handle_touch_up(struct wl_listener *listener, void *data) { static void handle_touch_down(struct wl_listener *listener, void *data) { struct sample_state *sample = wl_container_of(listener, sample, touch_down); struct wlr_event_touch_down *event = data; - struct touch_point *point = calloc(1, sizeof(struct touch_state)); + struct touch_point *point = calloc(1, sizeof(struct touch_point)); point->slot = event->slot; point->x = event->x_mm / event->width_mm; point->y = event->y_mm / event->height_mm; diff --git a/examples/touch.c b/examples/touch.c index 7e8d9827..40fc4ca2 100644 --- a/examples/touch.c +++ b/examples/touch.c @@ -61,7 +61,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts static void handle_touch_down(struct touch_state *tstate, int32_t slot, double x, double y, double width, double height) { struct sample_state *sample = tstate->compositor->data; - struct touch_point *point = calloc(1, sizeof(struct touch_state)); + struct touch_point *point = calloc(1, sizeof(struct touch_point)); point->slot = slot; point->x = x / width; point->y = y / height; diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index ff19bb2b..9f93d0d7 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -51,6 +51,7 @@ struct wlr_cursor *wlr_cursor_init() { cur->state = calloc(1, sizeof(struct wlr_cursor_state)); if (!cur->state) { wlr_log(L_ERROR, "Failed to allocate wlr_cursor_state"); + free(cur); return NULL; } From 30611894f2c411830a57e813c441e901068ff033 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Mon, 28 Aug 2017 22:12:35 -0400 Subject: [PATCH 25/34] Implement tablet_tool support in pointer example --- examples/pointer.c | 20 ++++++++++++++++++++ include/wlr/types/wlr_tablet_tool.h | 4 ++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/examples/pointer.c b/examples/pointer.c index 936bfb6a..f808d9ab 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -51,6 +51,11 @@ struct sample_state { struct wl_listener touch_down; struct wl_listener touch_cancel; list_t *touch_points; + + struct wl_listener tablet_tool_axis; + struct wl_listener tablet_tool_proxmity; + struct wl_listener tablet_tool_tip; + struct wl_listener tablet_tool_button; }; struct touch_point { @@ -306,6 +311,17 @@ static void handle_touch_cancel(struct wl_listener *listener, void *data) { wlr_log(L_DEBUG, "TODO: touch cancel"); } +static void handle_tablet_tool_axis(struct wl_listener *listener, void *data) { + struct sample_state *sample = wl_container_of(listener, sample, tablet_tool_axis); + struct wlr_event_tablet_tool_axis *event = data; + if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X) + && (event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { + wlr_cursor_warp_absolute(sample->cursor, event->device, + event->x_mm / event->width_mm, + event->y_mm / event->height_mm); + } +} + int main(int argc, char *argv[]) { struct sample_state state = { .default_color = { 0.25f, 0.25f, 0.25f, 1 }, @@ -344,6 +360,10 @@ int main(int argc, char *argv[]) { wl_signal_add(&state.cursor->events.touch_cancel, &state.touch_cancel); state.touch_cancel.notify = handle_touch_cancel; + // tool events + wl_signal_add(&state.cursor->events.tablet_tool_axis, &state.tablet_tool_axis); + state.tablet_tool_axis.notify = handle_tablet_tool_axis; + struct compositor_state compositor = { 0 }; compositor.data = &state; compositor.output_add_cb = handle_output_add; diff --git a/include/wlr/types/wlr_tablet_tool.h b/include/wlr/types/wlr_tablet_tool.h index 98fd82c0..9090828a 100644 --- a/include/wlr/types/wlr_tablet_tool.h +++ b/include/wlr/types/wlr_tablet_tool.h @@ -55,7 +55,7 @@ struct wlr_event_tablet_tool_proximity { struct wlr_input_device *device; uint32_t time_sec; uint64_t time_usec; - double x, y; + double x_mm, y_mm; double width_mm, height_mm; enum wlr_tablet_tool_proximity_state state; }; @@ -69,7 +69,7 @@ struct wlr_event_tablet_tool_tip { struct wlr_input_device *device; uint32_t time_sec; uint64_t time_usec; - double x, y; + double x_mm, y_mm; double width_mm, height_mm; enum wlr_tablet_tool_tip_state state; }; From 1193dd564bddfe75e972ae0d17715bee8645d273 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 29 Aug 2017 08:32:02 -0400 Subject: [PATCH 26/34] config fixes --- examples/config.c | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/examples/config.c b/examples/config.c index 1bd4672e..b99f130d 100644 --- a/examples/config.c +++ b/examples/config.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include "shared.h" @@ -16,15 +17,17 @@ static void usage(const char *name, int ret) { fprintf(stderr, "usage: %s [-C ]\n" "\n" - " -C Path to the configuration file (default: wlr-example.ini).\n" - " See `examples/wlr-example.ini.example` for config file documentation.\n", name); + " -C Path to the configuration file\n" + " (default: wlr-example.ini).\n" + " See `examples/wlr-example.ini.example` for config\n" + " file documentation.\n", name); exit(ret); } static struct wlr_geometry *parse_geometry(const char *str) { // format: {width}x{height}+{x}+{y} - if (strlen(str) > 255l) { + if (strlen(str) > 255) { wlr_log(L_ERROR, "cannot parse geometry string, too long"); return NULL; } @@ -43,8 +46,8 @@ static struct wlr_geometry *parse_geometry(const char *str) { char *endptr; long val = strtol(pch, &endptr, 0); - if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) - || (errno != 0 && val == 0)) { + if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || + (errno != 0 && val == 0)) { goto invalid_input; } @@ -70,7 +73,7 @@ static struct wlr_geometry *parse_geometry(const char *str) { pch = strtok(NULL, "x+"); } - if (!has_width || !has_height || !has_x || !has_y) { + if (!has_width || !has_height) { goto invalid_input; } @@ -87,7 +90,8 @@ invalid_input: static const char *output_prefix = "output:"; static const char *device_prefix = "device:"; -static int config_ini_handler(void *user, const char *section, const char *name, const char *value) { +static int config_ini_handler(void *user, const char *section, const char *name, + const char *value) { struct example_config *config = user; if (strncmp(output_prefix, section, strlen(output_prefix)) == 0) { const char *output_name = section + strlen(output_prefix); @@ -133,11 +137,10 @@ static int config_ini_handler(void *user, const char *section, const char *name, } } else if (strcmp(section, "cursor") == 0) { if (strcmp(name, "map-to-output") == 0) { + free(config->cursor.mapped_output); config->cursor.mapped_output = strdup(value); } else if (strcmp(name, "geometry") == 0) { - if (config->cursor.mapped_geo) { - free(config->cursor.mapped_geo); - } + free(config->cursor.mapped_geo); config->cursor.mapped_geo = parse_geometry(value); } else { wlr_log(L_ERROR, "got unknown cursor config: %s", name); @@ -161,14 +164,10 @@ static int config_ini_handler(void *user, const char *section, const char *name, } if (strcmp(name, "map-to-output") == 0) { - if (dc->mapped_output) { - free(dc->mapped_output); - } + free(dc->mapped_output); dc->mapped_output = strdup(value); } else if (strcmp(name, "geometry") == 0) { - if (dc->mapped_geo) { - free(dc->mapped_geo); - } + free(dc->mapped_geo); dc->mapped_geo = parse_geometry(value); } else { wlr_log(L_ERROR, "got unknown device config: %s", name); @@ -199,10 +198,10 @@ struct example_config *parse_args(int argc, char *argv[]) { if (!config->config_path) { // get the config path from the current directory - char cwd[1024]; + char cwd[MAXPATHLEN]; if (getcwd(cwd, sizeof(cwd)) != NULL) { - char buf[1024]; - sprintf(buf, "%s/%s", cwd, "wlr-example.ini"); + char buf[MAXPATHLEN]; + snprintf(buf, MAXPATHLEN, "%s/%s", cwd, "wlr-example.ini"); config->config_path = strdup(buf); } else { wlr_log(L_ERROR, "could not get cwd"); @@ -213,7 +212,8 @@ struct example_config *parse_args(int argc, char *argv[]) { int result = ini_parse(config->config_path, config_ini_handler, config); if (result == -1) { - wlr_log(L_ERROR, "Could not find config file at %s", config->config_path); + wlr_log(L_ERROR, "Could not find config file at %s", + config->config_path); exit(1); } else if (result == -2) { wlr_log(L_ERROR, "Could not allocate memory to parse config file"); @@ -257,7 +257,8 @@ void example_config_destroy(struct example_config *config) { free(config); } -struct wlr_output_layout *configure_layout(struct example_config *config, struct wl_list *outputs) { +struct wlr_output_layout *configure_layout(struct example_config *config, + struct wl_list *outputs) { struct wlr_output_layout *layout = wlr_output_layout_init(); int max_x = INT_MIN; int max_x_y = INT_MIN; // y value for the max_x output @@ -272,7 +273,8 @@ struct wlr_output_layout *configure_layout(struct example_config *config, struct conf->x, conf->y); wlr_output_transform(output->output, conf->transform); int width, height; - wlr_output_effective_resolution(output->output, &width, &height); + wlr_output_effective_resolution(output->output, &width, + &height); if (conf->x + width > max_x) { max_x = conf->x + width; max_x_y = conf->y; @@ -301,4 +303,3 @@ struct wlr_output_layout *configure_layout(struct example_config *config, struct return layout; } - From 34f4a7b972a667e2e7490f4822ca142143529227 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 29 Aug 2017 09:52:11 -0400 Subject: [PATCH 27/34] pointer.c: fix formatting --- examples/pointer.c | 66 +++++++++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/examples/pointer.c b/examples/pointer.c index f808d9ab..100feccc 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -63,7 +63,8 @@ struct touch_point { double x, y; }; -static void warp_to_touch(struct sample_state *sample, struct wlr_input_device *dev) { +static void warp_to_touch(struct sample_state *sample, + struct wlr_input_device *dev) { if (sample->touch_points->length == 0) { return; } @@ -79,7 +80,8 @@ static void warp_to_touch(struct sample_state *sample, struct wlr_input_device * wlr_cursor_warp_absolute(sample->cursor, dev, x, y); } -static void handle_output_frame(struct output_state *output, struct timespec *ts) { +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 wlr_output *wlr_output = output->output; @@ -87,7 +89,7 @@ static void handle_output_frame(struct output_state *output, struct timespec *ts wlr_output_make_current(wlr_output); glClearColor(sample->clear_color[0], sample->clear_color[1], - sample->clear_color[2], sample->clear_color[3]); + sample->clear_color[2], sample->clear_color[3]); glClear(GL_COLOR_BUFFER_BIT); wlr_output_swap_buffers(wlr_output); @@ -132,7 +134,8 @@ static void handle_output_add(struct output_state *ostate) { // reset layout wlr_output_layout_destroy(sample->layout); - sample->layout = configure_layout(sample->config, &ostate->compositor->outputs); + sample->layout = + configure_layout(sample->config, &ostate->compositor->outputs); wlr_cursor_attach_output_layout(sample->cursor, sample->layout); // cursor configuration @@ -155,9 +158,10 @@ static void handle_output_add(struct output_state *ostate) { } static void handle_output_remove(struct output_state *ostate) { - struct sample_state *sample = ostate->compositor->data; + struct sample_state *sample = ostate->compositor->data; wlr_output_layout_destroy(sample->layout); - sample->layout = configure_layout(sample->config, &ostate->compositor->outputs); + sample->layout = + configure_layout(sample->config, &ostate->compositor->outputs); wlr_cursor_attach_output_layout(sample->cursor, sample->layout); configure_devices(sample); @@ -172,12 +176,13 @@ static void handle_output_resolution(struct compositor_state *state, struct output_state *ostate) { struct sample_state *sample = ostate->compositor->data; wlr_output_layout_destroy(sample->layout); - sample->layout = configure_layout(sample->config, &ostate->compositor->outputs); + sample->layout = + configure_layout(sample->config, &ostate->compositor->outputs); wlr_cursor_attach_output_layout(sample->cursor, sample->layout); } -static void handle_input_add(struct compositor_state *state, struct - wlr_input_device *device) { +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 || @@ -193,8 +198,8 @@ static void handle_input_add(struct compositor_state *state, struct } } -static void handle_input_remove(struct compositor_state *state, struct - wlr_input_device *device) { +static void handle_input_remove(struct compositor_state *state, + struct wlr_input_device *device) { struct sample_state *sample = state->data; struct sample_input_device *s_device, *tmp = NULL; wl_list_for_each_safe(s_device, tmp, &sample->devices, link) { @@ -206,13 +211,17 @@ static void handle_input_remove(struct compositor_state *state, struct } static void handle_cursor_motion(struct wl_listener *listener, void *data) { - struct sample_state *sample = wl_container_of(listener, sample, cursor_motion); + struct sample_state *sample = + wl_container_of(listener, sample, cursor_motion); struct wlr_event_pointer_motion *event = data; - wlr_cursor_move(sample->cursor, event->device, event->delta_x, event->delta_y); + wlr_cursor_move(sample->cursor, event->device, event->delta_x, + event->delta_y); } -static void handle_cursor_motion_absolute(struct wl_listener *listener, void *data) { - struct sample_state *sample = wl_container_of(listener, sample, cursor_motion_absolute); +static void handle_cursor_motion_absolute(struct wl_listener *listener, + void *data) { + struct sample_state *sample = + wl_container_of(listener, sample, cursor_motion_absolute); struct wlr_event_pointer_motion_absolute *event = data; sample->cur_x = event->x_mm; @@ -229,7 +238,8 @@ static void handle_cursor_motion_absolute(struct wl_listener *listener, void *da } static void handle_cursor_button(struct wl_listener *listener, void *data) { - struct sample_state *sample = wl_container_of(listener, sample, cursor_button); + struct sample_state *sample = + wl_container_of(listener, sample, cursor_button); struct wlr_event_pointer_button *event = data; float (*color)[4]; @@ -245,7 +255,8 @@ static void handle_cursor_button(struct wl_listener *listener, void *data) { } static void handle_cursor_axis(struct wl_listener *listener, void *data) { - struct sample_state *sample = wl_container_of(listener, sample, cursor_axis); + struct sample_state *sample = + wl_container_of(listener, sample, cursor_axis); struct wlr_event_pointer_axis *event = data; for (size_t i = 0; i < 3; ++i) { @@ -291,7 +302,8 @@ static void handle_touch_down(struct wl_listener *listener, void *data) { } static void handle_touch_motion(struct wl_listener *listener, void *data) { - struct sample_state *sample = wl_container_of(listener, sample, touch_motion); + struct sample_state *sample = + wl_container_of(listener, sample, touch_motion); struct wlr_event_touch_motion *event = data; for (size_t i = 0; i < sample->touch_points->length; ++i) { struct touch_point *point = sample->touch_points->items[i]; @@ -306,19 +318,17 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) { } static void handle_touch_cancel(struct wl_listener *listener, void *data) { - //struct sample_state *sample = wl_container_of(listener, sample, touch_cancel); - //struct wlr_event_touch_cancel *event = data; wlr_log(L_DEBUG, "TODO: touch cancel"); } static void handle_tablet_tool_axis(struct wl_listener *listener, void *data) { - struct sample_state *sample = wl_container_of(listener, sample, tablet_tool_axis); + struct sample_state *sample = + wl_container_of(listener, sample, tablet_tool_axis); struct wlr_event_tablet_tool_axis *event = data; - if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X) - && (event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { + if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X) && + (event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { wlr_cursor_warp_absolute(sample->cursor, event->device, - event->x_mm / event->width_mm, - event->y_mm / event->height_mm); + event->x_mm / event->width_mm, event->y_mm / event->height_mm); } } @@ -338,7 +348,8 @@ int main(int argc, char *argv[]) { wl_signal_add(&state.cursor->events.motion, &state.cursor_motion); state.cursor_motion.notify = handle_cursor_motion; - wl_signal_add(&state.cursor->events.motion_absolute, &state.cursor_motion_absolute); + wl_signal_add(&state.cursor->events.motion_absolute, + &state.cursor_motion_absolute); state.cursor_motion_absolute.notify = handle_cursor_motion_absolute; wl_signal_add(&state.cursor->events.button, &state.cursor_button); @@ -361,7 +372,8 @@ int main(int argc, char *argv[]) { state.touch_cancel.notify = handle_touch_cancel; // tool events - wl_signal_add(&state.cursor->events.tablet_tool_axis, &state.tablet_tool_axis); + wl_signal_add(&state.cursor->events.tablet_tool_axis, + &state.tablet_tool_axis); state.tablet_tool_axis.notify = handle_tablet_tool_axis; struct compositor_state compositor = { 0 }; From 3449777a8d3fec597c40b29540800d6addd7a05e Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 29 Aug 2017 09:59:03 -0400 Subject: [PATCH 28/34] wlr_output_layout.c: fix style --- include/wlr/types/wlr_output_layout.h | 8 ++-- types/wlr_output_layout.c | 59 ++++++++++++++------------- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index 0d157f56..dfb5234d 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -7,16 +7,16 @@ struct wlr_output_layout_state; struct wlr_output_layout { - struct wl_list outputs; + struct wl_list outputs; struct wlr_output_layout_state *state; }; struct wlr_output_layout_output_state; struct wlr_output_layout_output { - struct wlr_output *output; - int x, y; - struct wl_list link; + struct wlr_output *output; + int x, y; + struct wl_list link; struct wlr_output_layout_output_state *state; }; diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index 4062c107..b097b1b8 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -15,7 +15,8 @@ struct wlr_output_layout_output_state { }; struct wlr_output_layout *wlr_output_layout_init() { - struct wlr_output_layout *layout = calloc(1, sizeof(struct wlr_output_layout)); + struct wlr_output_layout *layout = + calloc(1, sizeof(struct wlr_output_layout)); layout->state = calloc(1, sizeof(struct wlr_output_layout_state)); layout->state->_geo = calloc(1, sizeof(struct wlr_geometry)); wl_list_init(&layout->outputs); @@ -24,10 +25,10 @@ struct wlr_output_layout *wlr_output_layout_init() { static void wlr_output_layout_output_destroy( struct wlr_output_layout_output *l_output) { - wl_list_remove(&l_output->link); - free(l_output->state->_geo); - free(l_output->state); - free(l_output); + wl_list_remove(&l_output->link); + free(l_output->state->_geo); + free(l_output->state); + free(l_output); } void wlr_output_layout_destroy(struct wlr_output_layout *layout) { @@ -59,10 +60,10 @@ void wlr_output_layout_add(struct wlr_output_layout *layout, struct wlr_output_layout_output *wlr_output_layout_get( struct wlr_output_layout *layout, struct wlr_output *reference) { - struct wlr_output_layout_output *_output; - wl_list_for_each(_output, &layout->outputs, link) { - if (_output->output == reference) { - return _output; + struct wlr_output_layout_output *l_output; + wl_list_for_each(l_output, &layout->outputs, link) { + if (l_output->output == reference) { + return l_output; } } return NULL; @@ -77,7 +78,8 @@ static bool output_contains_point( struct wlr_output_layout_output *l_output, bool wlr_output_layout_contains_point(struct wlr_output_layout *layout, struct wlr_output *reference, int x, int y) { if (reference) { - struct wlr_output_layout_output *layout_output = wlr_output_layout_get(layout, reference); + struct wlr_output_layout_output *layout_output = + wlr_output_layout_get(layout, reference); int width, height; wlr_output_effective_resolution(layout_output->output, &width, &height); return output_contains_point(layout_output, x, y, width, height); @@ -88,7 +90,8 @@ bool wlr_output_layout_contains_point(struct wlr_output_layout *layout, bool wlr_output_layout_intersects(struct wlr_output_layout *layout, struct wlr_output *reference, int x1, int y1, int x2, int y2) { - struct wlr_output_layout_output *l_output = wlr_output_layout_get(layout, reference); + struct wlr_output_layout_output *l_output = + wlr_output_layout_get(layout, reference); if (!l_output) { return false; } @@ -104,15 +107,15 @@ bool wlr_output_layout_intersects(struct wlr_output_layout *layout, struct wlr_output *wlr_output_layout_output_at(struct wlr_output_layout *layout, double x, double y) { - struct wlr_output_layout_output *_output; - wl_list_for_each(_output, &layout->outputs, link) { - if (_output->output) { + struct wlr_output_layout_output *l_output; + wl_list_for_each(l_output, &layout->outputs, link) { + if (l_output->output) { int width, height; - wlr_output_effective_resolution(_output->output, &width, &height); - bool has_x = x >= _output->x && x <= _output->x + width; - bool has_y = y >= _output->y && y <= _output->y + height; + wlr_output_effective_resolution(l_output->output, &width, &height); + bool has_x = x >= l_output->x && x <= l_output->x + width; + bool has_y = y >= l_output->y && y <= l_output->y + height; if (has_x && has_y) { - return _output->output; + return l_output->output; } } } @@ -121,11 +124,11 @@ struct wlr_output *wlr_output_layout_output_at(struct wlr_output_layout *layout, void wlr_output_layout_move(struct wlr_output_layout *layout, struct wlr_output *output, int x, int y) { - struct wlr_output_layout_output *layout_output = - wlr_output_layout_get(layout, output); - if (layout_output) { - layout_output->x = x; - layout_output->y = y; + struct wlr_output_layout_output *l_output = + wlr_output_layout_get(layout, output); + if (l_output) { + l_output->x = x; + l_output->y = y; } } @@ -144,11 +147,11 @@ void wlr_output_layout_output_coords(struct wlr_output_layout *layout, double src_x = *x; double src_y = *y; - struct wlr_output_layout_output *_output; - wl_list_for_each(_output, &layout->outputs, link) { - if (_output->output == reference) { - *x = src_x - (double)_output->x; - *y = src_y - (double)_output->y; + struct wlr_output_layout_output *l_output; + wl_list_for_each(l_output, &layout->outputs, link) { + if (l_output->output == reference) { + *x = src_x - (double)l_output->x; + *y = src_y - (double)l_output->y; return; } } From 1fb8bc9340d157dffd354ea18f8521e279021750 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 29 Aug 2017 10:31:39 -0400 Subject: [PATCH 29/34] wlr_cursor.c: fix formatting --- include/wlr/types/wlr_cursor.h | 23 +++++++++++----------- types/wlr_cursor.c | 35 ++++++++++++++++++++++------------ 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index 35c2ff8e..b91c195e 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -8,15 +8,13 @@ #include struct wlr_cursor_state; -//struct wlr_cursor_impl *; struct wlr_cursor { - struct wlr_cursor_state *state; - //struct wlr_cursor_impl *impl; - int x, y; + struct wlr_cursor_state *state; + int x, y; - struct { - struct wl_signal motion; + struct { + struct wl_signal motion; struct wl_signal motion_absolute; struct wl_signal button; struct wl_signal axis; @@ -30,7 +28,7 @@ struct wlr_cursor { struct wl_signal tablet_tool_proximity; struct wl_signal tablet_tool_tip; struct wl_signal tablet_tool_button; - } events; + } events; }; struct wlr_cursor *wlr_cursor_init(); @@ -71,24 +69,25 @@ void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, * - WLR_INPUT_DEVICE_TABLET_TOOL */ void wlr_cursor_attach_input_device(struct wlr_cursor *cur, - struct wlr_input_device *dev); + struct wlr_input_device *dev); void wlr_cursor_detach_input_device(struct wlr_cursor *cur, - struct wlr_input_device *dev); + struct wlr_input_device *dev); /** * Uses the given layout to establish the boundaries and movement semantics of * this cursor. Cursors without an output layout allow infinite movement in any * direction and do not support absolute input events. */ void wlr_cursor_attach_output_layout(struct wlr_cursor *cur, - struct wlr_output_layout *l); + struct wlr_output_layout *l); /** * Attaches this cursor to the given output, which must be among the outputs in * the current output_layout for this cursor. This call is invalid for a cursor * without an associated output layout. */ -void wlr_cursor_map_to_output(struct wlr_cursor *cur, struct wlr_output *output); +void wlr_cursor_map_to_output(struct wlr_cursor *cur, + struct wlr_output *output); /** * Maps all input from a specific input device to a given output. The input @@ -96,7 +95,7 @@ void wlr_cursor_map_to_output(struct wlr_cursor *cur, struct wlr_output *output) * outputs in the attached output layout. */ void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, - struct wlr_input_device *dev, struct wlr_output *output); + struct wlr_input_device *dev, struct wlr_output *output); /** * Maps this cursor to an arbitrary region on the associated wlr_output_layout. diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 9f93d0d7..9a9a28b8 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -110,7 +110,8 @@ static struct wlr_cursor_device *get_cursor_device(struct wlr_cursor *cur, return ret; } -static void wlr_cursor_warp_unchecked(struct wlr_cursor *cur, double x, double y) { +static void wlr_cursor_warp_unchecked(struct wlr_cursor *cur, + double x, double y) { assert(cur->state->layout); int hotspot_x = 0; int hotspot_y = 0; @@ -166,7 +167,7 @@ static struct wlr_geometry *get_mapping(struct wlr_cursor *cur, if (cur->state->mapped_geometry) { return cur->state->mapped_geometry; } - if(cur->state->mapped_output) { + if (cur->state->mapped_output) { return wlr_output_layout_get_geometry(cur->state->layout, cur->state->mapped_output); } @@ -186,7 +187,8 @@ bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev, wlr_cursor_warp_unchecked(cur, x, y); result = true; } - } else if (wlr_output_layout_contains_point(cur->state->layout, NULL, x, y)) { + } else if (wlr_output_layout_contains_point(cur->state->layout, NULL, + x, y)) { wlr_cursor_warp_unchecked(cur, x, y); result = true; } @@ -243,19 +245,23 @@ void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, static void handle_pointer_motion(struct wl_listener *listener, void *data) { struct wlr_event_pointer_motion *event = data; - struct wlr_cursor_device *device = wl_container_of(listener, device, motion); + struct wlr_cursor_device *device = + wl_container_of(listener, device, motion); wl_signal_emit(&device->cursor->events.motion, event); } -static void handle_pointer_motion_absolute(struct wl_listener *listener, void *data) { +static void handle_pointer_motion_absolute(struct wl_listener *listener, + void *data) { struct wlr_event_pointer_motion_absolute *event = data; - struct wlr_cursor_device *device = wl_container_of(listener, device, motion_absolute); + struct wlr_cursor_device *device = + wl_container_of(listener, device, motion_absolute); wl_signal_emit(&device->cursor->events.motion_absolute, event); } static void handle_pointer_button(struct wl_listener *listener, void *data) { struct wlr_event_pointer_button *event = data; - struct wlr_cursor_device *device = wl_container_of(listener, device, button); + struct wlr_cursor_device *device = + wl_container_of(listener, device, button); wl_signal_emit(&device->cursor->events.button, event); } @@ -307,14 +313,16 @@ static void handle_tablet_tool_axis(struct wl_listener *listener, void *data) { wl_signal_emit(&device->cursor->events.tablet_tool_axis, event); } -static void handle_tablet_tool_button(struct wl_listener *listener, void *data) { +static void handle_tablet_tool_button(struct wl_listener *listener, + void *data) { struct wlr_event_tablet_tool_button *event = data; struct wlr_cursor_device *device; device = wl_container_of(listener, device, tablet_tool_button); wl_signal_emit(&device->cursor->events.tablet_tool_button, event); } -static void handle_tablet_tool_proximity(struct wl_listener *listener, void *data) { +static void handle_tablet_tool_proximity(struct wl_listener *listener, + void *data) { struct wlr_event_tablet_tool_proximity *event = data; struct wlr_cursor_device *device; device = wl_container_of(listener, device, tablet_tool_proximity); @@ -364,7 +372,8 @@ void wlr_cursor_attach_input_device(struct wlr_cursor *cur, wl_signal_add(&dev->pointer->events.motion, &device->motion); device->motion.notify = handle_pointer_motion; - wl_signal_add(&dev->pointer->events.motion_absolute, &device->motion_absolute); + wl_signal_add(&dev->pointer->events.motion_absolute, + &device->motion_absolute); device->motion_absolute.notify = handle_pointer_motion_absolute; wl_signal_add(&dev->pointer->events.button, &device->button); @@ -434,14 +443,16 @@ void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, struct wlr_input_device *dev, struct wlr_output *output) { struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); if (!c_device) { - wlr_log(L_ERROR, "Cannot map device \"%s\" to output (not found in this cursor)", dev->name); + wlr_log(L_ERROR, "Cannot map device \"%s\" to output" + "(not found in this cursor)", dev->name); return; } c_device->mapped_output = output; } -void wlr_cursor_map_to_region(struct wlr_cursor *cur, struct wlr_geometry *geo) { +void wlr_cursor_map_to_region(struct wlr_cursor *cur, + struct wlr_geometry *geo) { if (geo && wlr_geometry_empty(geo)) { wlr_log(L_ERROR, "cannot map cursor to an empty region"); return; From a51b76083e589214320f30c8792d6b2666ef21d2 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 29 Aug 2017 10:42:23 -0400 Subject: [PATCH 30/34] rename wlr_cursor_init to wlr_cursor_create --- examples/pointer.c | 2 +- include/wlr/types/wlr_cursor.h | 2 +- types/wlr_cursor.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/pointer.c b/examples/pointer.c index 100feccc..5341c72c 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -340,7 +340,7 @@ int main(int argc, char *argv[]) { }; state.config = parse_args(argc, argv); - state.cursor = wlr_cursor_init(); + state.cursor = wlr_cursor_create(); wlr_cursor_map_to_region(state.cursor, state.config->cursor.mapped_geo); wl_list_init(&state.devices); diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index b91c195e..ef3b8dbb 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -31,7 +31,7 @@ struct wlr_cursor { } events; }; -struct wlr_cursor *wlr_cursor_init(); +struct wlr_cursor *wlr_cursor_create(); void wlr_cursor_destroy(struct wlr_cursor *cur); diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 9a9a28b8..4bbf897b 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -41,7 +41,7 @@ struct wlr_cursor_state { struct wlr_geometry *mapped_geometry; }; -struct wlr_cursor *wlr_cursor_init() { +struct wlr_cursor *wlr_cursor_create() { struct wlr_cursor *cur = calloc(1, sizeof(struct wlr_cursor)); if (!cur) { wlr_log(L_ERROR, "Failed to allocate wlr_cursor"); From 9b65d0b3f0030bf2103cd7d65448f727c62de468 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 29 Aug 2017 12:08:49 -0400 Subject: [PATCH 31/34] refactor and rename wlr_geometry to wlr_box --- examples/config.c | 34 +++++------ examples/config.h | 4 +- examples/pointer.c | 4 +- include/wlr/types/wlr_box.h | 20 +++++++ include/wlr/types/wlr_cursor.h | 6 +- include/wlr/types/wlr_geometry.h | 20 ------- include/wlr/types/wlr_output_layout.h | 6 +- types/meson.build | 2 +- types/wlr_box.c | 67 +++++++++++++++++++++ types/wlr_cursor.c | 52 ++++++++-------- types/wlr_geometry.c | 86 --------------------------- types/wlr_output_layout.c | 36 +++++------ 12 files changed, 159 insertions(+), 178 deletions(-) create mode 100644 include/wlr/types/wlr_box.h delete mode 100644 include/wlr/types/wlr_geometry.h create mode 100644 types/wlr_box.c delete mode 100644 types/wlr_geometry.c diff --git a/examples/config.c b/examples/config.c index b99f130d..a1ed5d5a 100644 --- a/examples/config.c +++ b/examples/config.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include "shared.h" #include "config.h" #include "ini.h" @@ -25,7 +25,7 @@ static void usage(const char *name, int ret) { exit(ret); } -static struct wlr_geometry *parse_geometry(const char *str) { +static struct wlr_box *parse_geometry(const char *str) { // format: {width}x{height}+{x}+{y} if (strlen(str) > 255) { wlr_log(L_ERROR, "cannot parse geometry string, too long"); @@ -33,7 +33,7 @@ static struct wlr_geometry *parse_geometry(const char *str) { } char *buf = strdup(str); - struct wlr_geometry *geo = calloc(1, sizeof(struct wlr_geometry)); + struct wlr_box *box = calloc(1, sizeof(struct wlr_box)); bool has_width = false; bool has_height = false; @@ -56,16 +56,16 @@ static struct wlr_geometry *parse_geometry(const char *str) { } if (!has_width) { - geo->width = val; + box->width = val; has_width = true; } else if (!has_height) { - geo->height = val; + box->height = val; has_height = true; } else if (!has_x) { - geo->x = val; + box->x = val; has_x = true; } else if (!has_y) { - geo->y = val; + box->y = val; has_y = true; } else { break; @@ -78,12 +78,12 @@ static struct wlr_geometry *parse_geometry(const char *str) { } free(buf); - return geo; + return box; invalid_input: wlr_log(L_ERROR, "could not parse geometry string: %s", str); free(buf); - free(geo); + free(box); return NULL; } @@ -140,8 +140,8 @@ static int config_ini_handler(void *user, const char *section, const char *name, free(config->cursor.mapped_output); config->cursor.mapped_output = strdup(value); } else if (strcmp(name, "geometry") == 0) { - free(config->cursor.mapped_geo); - config->cursor.mapped_geo = parse_geometry(value); + free(config->cursor.mapped_box); + config->cursor.mapped_box = parse_geometry(value); } else { wlr_log(L_ERROR, "got unknown cursor config: %s", name); } @@ -167,8 +167,8 @@ static int config_ini_handler(void *user, const char *section, const char *name, free(dc->mapped_output); dc->mapped_output = strdup(value); } else if (strcmp(name, "geometry") == 0) { - free(dc->mapped_geo); - dc->mapped_geo = parse_geometry(value); + free(dc->mapped_box); + dc->mapped_box = parse_geometry(value); } else { wlr_log(L_ERROR, "got unknown device config: %s", name); } @@ -239,8 +239,8 @@ void example_config_destroy(struct example_config *config) { if (dc->mapped_output) { free(dc->mapped_output); } - if (dc->mapped_geo) { - free(dc->mapped_geo); + if (dc->mapped_box) { + free(dc->mapped_box); } free(dc); } @@ -251,8 +251,8 @@ void example_config_destroy(struct example_config *config) { if (config->cursor.mapped_output) { free(config->cursor.mapped_output); } - if (config->cursor.mapped_geo) { - free(config->cursor.mapped_geo); + if (config->cursor.mapped_box) { + free(config->cursor.mapped_box); } free(config); } diff --git a/examples/config.h b/examples/config.h index cd19dc5e..2a69c4f4 100644 --- a/examples/config.h +++ b/examples/config.h @@ -15,14 +15,14 @@ struct output_config { struct device_config { char *name; char *mapped_output; - struct wlr_geometry *mapped_geo; + struct wlr_box *mapped_box; struct wl_list link; }; struct example_config { struct { char *mapped_output; - struct wlr_geometry *mapped_geo; + struct wlr_box *mapped_box; } cursor; struct wl_list outputs; diff --git a/examples/pointer.c b/examples/pointer.c index 5341c72c..d9a06339 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -105,7 +105,7 @@ static void configure_devices(struct sample_state *sample) { wl_list_for_each(dc, &sample->config->devices, link) { if (strcmp(dev->device->name, dc->name) == 0) { wlr_cursor_map_input_to_region(sample->cursor, dev->device, - dc->mapped_geo); + dc->mapped_box); } } } @@ -341,7 +341,7 @@ int main(int argc, char *argv[]) { state.config = parse_args(argc, argv); state.cursor = wlr_cursor_create(); - wlr_cursor_map_to_region(state.cursor, state.config->cursor.mapped_geo); + wlr_cursor_map_to_region(state.cursor, state.config->cursor.mapped_box); wl_list_init(&state.devices); // pointer events diff --git a/include/wlr/types/wlr_box.h b/include/wlr/types/wlr_box.h new file mode 100644 index 00000000..e2b1ab4e --- /dev/null +++ b/include/wlr/types/wlr_box.h @@ -0,0 +1,20 @@ +#ifndef _WLR_TYPES_GEOMETRY_H +#define _WLR_TYPES_GEOMETRY_H +#include + +struct wlr_box { + int x, y; + int width, height; +}; + +void wlr_box_closest_point(struct wlr_box *box, double x, double y, + double *dest_x, double *dest_y); + +bool wlr_box_intersection(struct wlr_box *box_a, + struct wlr_box *box_b, struct wlr_box **dest); + +bool wlr_box_contains_point(struct wlr_box *box, double x, double y); + +bool wlr_box_empty(struct wlr_box *box); + +#endif diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index ef3b8dbb..5fc0ec76 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include struct wlr_cursor_state; @@ -100,13 +100,13 @@ void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, /** * Maps this cursor to an arbitrary region on the associated wlr_output_layout. */ -void wlr_cursor_map_to_region(struct wlr_cursor *cur, struct wlr_geometry *geo); +void wlr_cursor_map_to_region(struct wlr_cursor *cur, struct wlr_box *box); /** * Maps inputs from this input device to an arbitrary region on the associated * wlr_output_layout. */ void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, - struct wlr_input_device *dev, struct wlr_geometry *geo); + struct wlr_input_device *dev, struct wlr_box *box); #endif diff --git a/include/wlr/types/wlr_geometry.h b/include/wlr/types/wlr_geometry.h deleted file mode 100644 index cac75431..00000000 --- a/include/wlr/types/wlr_geometry.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _WLR_TYPES_GEOMETRY_H -#define _WLR_TYPES_GEOMETRY_H -#include - -struct wlr_geometry { - int x, y; - int width, height; -}; - -void wlr_geometry_closest_boundary(struct wlr_geometry *geo, double x, double y, - int *dest_x, int *dest_y, double *distance); - -bool wlr_geometry_intersection(struct wlr_geometry *geo_a, - struct wlr_geometry *geo_b, struct wlr_geometry **dest); - -bool wlr_geometry_contains_point(struct wlr_geometry *geo, int x, int y); - -bool wlr_geometry_empty(struct wlr_geometry *geo); - -#endif diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index dfb5234d..794fc491 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -62,10 +62,10 @@ void wlr_output_layout_closest_boundary(struct wlr_output_layout *layout, double *dest_y); /** - * Get the geometry of the layout for the given reference output. If `reference` - * is NULL, the geometry will be for the extents of the entire layout. + * Get the box of the layout for the given reference output. If `reference` + * is NULL, the box will be for the extents of the entire layout. */ -struct wlr_geometry *wlr_output_layout_get_geometry( +struct wlr_box *wlr_output_layout_get_box( struct wlr_output_layout *layout, struct wlr_output *reference); #endif diff --git a/types/meson.build b/types/meson.build index 8b8b215b..56390475 100644 --- a/types/meson.build +++ b/types/meson.build @@ -16,7 +16,7 @@ lib_wlr_types = static_library('wlr_types', files( 'wlr_xdg_shell_v6.c', 'wlr_wl_shell.c', 'wlr_compositor.c', - 'wlr_geometry.c', + 'wlr_box.c', ), include_directories: wlr_inc, dependencies: [wayland_server, pixman, wlr_protos]) diff --git a/types/wlr_box.c b/types/wlr_box.c new file mode 100644 index 00000000..7e981833 --- /dev/null +++ b/types/wlr_box.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include +#include + +void wlr_box_closest_point(struct wlr_box *box, double x, double y, + double *dest_x, double *dest_y) { + // find the closest x point + if (x < box->x) { + *dest_x = box->x; + } else if (x > box->x + box->width) { + *dest_x = box->x + box->width; + } else { + *dest_x = x; + } + + // find closest y point + if (y < box->y) { + *dest_y = box->y; + } else if (y > box->y + box->height) { + *dest_y = box->y + box->height; + } else { + *dest_y = y; + } +} + +bool wlr_box_empty(struct wlr_box *box) { + return box == NULL || box->width <= 0 || box->height <= 0; +} + +bool wlr_box_intersection(struct wlr_box *box_a, + struct wlr_box *box_b, struct wlr_box **box_dest) { + struct wlr_box *dest = *box_dest; + bool a_empty = wlr_box_empty(box_a); + bool b_empty = wlr_box_empty(box_b); + + if (a_empty || b_empty) { + dest->x = 0; + dest->y = 0; + dest->width = -100; + dest->height = -100; + return false; + } + + int x1 = fmax(box_a->x, box_b->x); + int y1 = fmax(box_a->y, box_b->y); + int x2 = fmin(box_a->x + box_a->width, box_b->x + box_b->width); + int y2 = fmin(box_a->y + box_a->height, box_b->y + box_b->height); + + dest->x = x1; + dest->y = y1; + dest->width = x2 - x1; + dest->height = y2 - y1; + + return !wlr_box_empty(dest); +} + +bool wlr_box_contains_point(struct wlr_box *box, double x, double y) { + if (wlr_box_empty(box)) { + return false; + } else { + return x >= box->x && x <= box->x + box->width && + y >= box->y && y <= box->y + box->height; + } +} diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 4bbf897b..bc546b15 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -13,7 +13,7 @@ struct wlr_cursor_device { struct wlr_input_device *device; struct wl_list link; struct wlr_output *mapped_output; - struct wlr_geometry *mapped_geometry; + struct wlr_box *mapped_box; struct wl_listener motion; struct wl_listener motion_absolute; @@ -38,7 +38,7 @@ struct wlr_cursor_state { struct wlr_output_layout *layout; struct wlr_xcursor *xcursor; struct wlr_output *mapped_output; - struct wlr_geometry *mapped_geometry; + struct wlr_box *mapped_box; }; struct wlr_cursor *wlr_cursor_create() { @@ -149,26 +149,26 @@ static void wlr_cursor_warp_unchecked(struct wlr_cursor *cur, * If none of these are set, returns NULL and absolute movement should be * relative to the extents of the layout. */ -static struct wlr_geometry *get_mapping(struct wlr_cursor *cur, +static struct wlr_box *get_mapping(struct wlr_cursor *cur, struct wlr_input_device *dev) { assert(cur->state->layout); struct wlr_cursor_device *c_device = get_cursor_device(cur, dev); if (c_device) { - if (c_device->mapped_geometry) { - return c_device->mapped_geometry; + if (c_device->mapped_box) { + return c_device->mapped_box; } if (c_device->mapped_output) { - return wlr_output_layout_get_geometry(cur->state->layout, + return wlr_output_layout_get_box(cur->state->layout, c_device->mapped_output); } } - if (cur->state->mapped_geometry) { - return cur->state->mapped_geometry; + if (cur->state->mapped_box) { + return cur->state->mapped_box; } if (cur->state->mapped_output) { - return wlr_output_layout_get_geometry(cur->state->layout, + return wlr_output_layout_get_box(cur->state->layout, cur->state->mapped_output); } @@ -180,10 +180,10 @@ bool wlr_cursor_warp(struct wlr_cursor *cur, struct wlr_input_device *dev, assert(cur->state->layout); bool result = false; - struct wlr_geometry *mapping = get_mapping(cur, dev); + struct wlr_box *mapping = get_mapping(cur, dev); if (mapping) { - if (wlr_geometry_contains_point(mapping, x, y)) { + if (wlr_box_contains_point(mapping, x, y)) { wlr_cursor_warp_unchecked(cur, x, y); result = true; } @@ -200,9 +200,9 @@ void wlr_cursor_warp_absolute(struct wlr_cursor *cur, struct wlr_input_device *dev, double x_mm, double y_mm) { assert(cur->state->layout); - struct wlr_geometry *mapping = get_mapping(cur, dev); + struct wlr_box *mapping = get_mapping(cur, dev); if (!mapping) { - mapping = wlr_output_layout_get_geometry(cur->state->layout, NULL); + mapping = wlr_output_layout_get_box(cur->state->layout, NULL); } double x = mapping->width * x_mm + mapping->x; @@ -218,15 +218,15 @@ void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, double x = cur->x + delta_x; double y = cur->y + delta_y; - struct wlr_geometry *mapping = get_mapping(cur, dev); + struct wlr_box *mapping = get_mapping(cur, dev); if (mapping) { - int boundary_x, boundary_y; - if (!wlr_geometry_contains_point(mapping, x, y)) { - wlr_geometry_closest_boundary(mapping, x, y, &boundary_x, - &boundary_y, NULL); - x = boundary_x; - y = boundary_y; + double closest_x, closest_y; + if (!wlr_box_contains_point(mapping, x, y)) { + wlr_box_closest_point(mapping, x, y, &closest_x, + &closest_y); + x = closest_x; + y = closest_y; } } else { if (!wlr_output_layout_contains_point(cur->state->layout, NULL, x, y)) { @@ -452,18 +452,18 @@ void wlr_cursor_map_input_to_output(struct wlr_cursor *cur, } void wlr_cursor_map_to_region(struct wlr_cursor *cur, - struct wlr_geometry *geo) { - if (geo && wlr_geometry_empty(geo)) { + struct wlr_box *box) { + if (box && wlr_box_empty(box)) { wlr_log(L_ERROR, "cannot map cursor to an empty region"); return; } - cur->state->mapped_geometry = geo; + cur->state->mapped_box = box; } void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, - struct wlr_input_device *dev, struct wlr_geometry *geo) { - if (geo && wlr_geometry_empty(geo)) { + struct wlr_input_device *dev, struct wlr_box *box) { + if (box && wlr_box_empty(box)) { wlr_log(L_ERROR, "cannot map device \"%s\" input to an empty region", dev->name); return; @@ -476,5 +476,5 @@ void wlr_cursor_map_input_to_region(struct wlr_cursor *cur, return; } - c_device->mapped_geometry = geo; + c_device->mapped_box = box; } diff --git a/types/wlr_geometry.c b/types/wlr_geometry.c deleted file mode 100644 index 4f532d6f..00000000 --- a/types/wlr_geometry.c +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include -#include -#include -#include -#include - -static double get_distance(double x1, double y1, double x2, double y2) { - double distance; - distance = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); - return distance; -} - -void wlr_geometry_closest_boundary(struct wlr_geometry *geo, double x, double y, - int *dest_x, int *dest_y, double *distance) { - // find the closest x point - if (x < geo->x) { - *dest_x = geo->x; - } else if (x > geo->x + geo->width) { - *dest_x = geo->x + geo->width; - } else { - *dest_x = x; - } - - // find closest y point - if (y < geo->y) { - *dest_y = geo->y; - } else if (y > geo->y + geo->height) { - *dest_y = geo->y + geo->height; - } else { - *dest_y = y; - } - - // calculate distance - if (distance) { - *distance = get_distance(*dest_x, *dest_y, x, y); - } -} - -#ifndef max -#define max(a,b) ((a) > (b) ? (a) : (b)) -#endif - -#ifndef min -#define min(a,b) ((a) < (b) ? (a) : (b)) -#endif - -bool wlr_geometry_empty(struct wlr_geometry *geo) { - return geo == NULL || geo->width <= 0 || geo->height <= 0; -} - -bool wlr_geometry_intersection(struct wlr_geometry *geo_a, - struct wlr_geometry *geo_b, struct wlr_geometry **geo_dest) { - struct wlr_geometry *dest = *geo_dest; - bool a_empty = wlr_geometry_empty(geo_a); - bool b_empty = wlr_geometry_empty(geo_b); - - if (a_empty || b_empty) { - dest->x = 0; - dest->y = 0; - dest->width = -100; - dest->height = -100; - return false; - } - - int x1 = max(geo_a->x, geo_b->x); - int y1 = max(geo_a->y, geo_b->y); - int x2 = min(geo_a->x + geo_a->width, geo_b->x + geo_b->width); - int y2 = min(geo_a->y + geo_a->height, geo_b->y + geo_b->height); - - dest->x = x1; - dest->y = y1; - dest->width = x2 - x1; - dest->height = y2 - y1; - - return !wlr_geometry_empty(dest); -} - -bool wlr_geometry_contains_point(struct wlr_geometry *geo, int x, int y) { - if (wlr_geometry_empty(geo)) { - return false; - } else { - return x >= geo->x && x <= geo->x + geo->width && - y >= geo->y && y <= geo->y + geo->height; - } -} diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index b097b1b8..ba2c158a 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -1,24 +1,24 @@ #include #include #include -#include +#include #include #include #include struct wlr_output_layout_state { - struct wlr_geometry *_geo; + struct wlr_box *_box; }; struct wlr_output_layout_output_state { - struct wlr_geometry *_geo; + struct wlr_box *_box; }; struct wlr_output_layout *wlr_output_layout_init() { struct wlr_output_layout *layout = calloc(1, sizeof(struct wlr_output_layout)); layout->state = calloc(1, sizeof(struct wlr_output_layout_state)); - layout->state->_geo = calloc(1, sizeof(struct wlr_geometry)); + layout->state->_box = calloc(1, sizeof(struct wlr_box)); wl_list_init(&layout->outputs); return layout; } @@ -26,7 +26,7 @@ struct wlr_output_layout *wlr_output_layout_init() { static void wlr_output_layout_output_destroy( struct wlr_output_layout_output *l_output) { wl_list_remove(&l_output->link); - free(l_output->state->_geo); + free(l_output->state->_box); free(l_output->state); free(l_output); } @@ -41,7 +41,7 @@ void wlr_output_layout_destroy(struct wlr_output_layout *layout) { wlr_output_layout_output_destroy(_output); } - free(layout->state->_geo); + free(layout->state->_box); free(layout->state); free(layout); } @@ -51,7 +51,7 @@ void wlr_output_layout_add(struct wlr_output_layout *layout, struct wlr_output_layout_output *l_output; l_output= calloc(1, sizeof(struct wlr_output_layout_output)); l_output->state = calloc(1, sizeof(struct wlr_output_layout_output_state)); - l_output->state->_geo = calloc(1, sizeof(struct wlr_geometry)); + l_output->state->_box = calloc(1, sizeof(struct wlr_box)); l_output->output = output; l_output->x = x; l_output->y = y; @@ -178,7 +178,7 @@ void wlr_output_layout_closest_boundary(struct wlr_output_layout *layout, wlr_output_effective_resolution(l_output->output, &width, &height); // find the closest x point - // TODO use wlr_geometry_closest_boundary + // TODO use wlr_box_closest_boundary if (x < l_output->x) { output_x = l_output->x; } else if (x > l_output->x + width) { @@ -209,17 +209,17 @@ void wlr_output_layout_closest_boundary(struct wlr_output_layout *layout, *dest_y = min_y; } -struct wlr_geometry *wlr_output_layout_get_geometry( +struct wlr_box *wlr_output_layout_get_box( struct wlr_output_layout *layout, struct wlr_output *reference) { struct wlr_output_layout_output *l_output; if (reference) { // output extents l_output= wlr_output_layout_get(layout, reference); - l_output->state->_geo->x = l_output->x; - l_output->state->_geo->y = l_output->y; + l_output->state->_box->x = l_output->x; + l_output->state->_box->y = l_output->y; wlr_output_effective_resolution(reference, - &l_output->state->_geo->width, &l_output->state->_geo->height); - return l_output->state->_geo; + &l_output->state->_box->width, &l_output->state->_box->height); + return l_output->state->_box; } else { // layout extents int min_x = INT_MAX, min_y = INT_MAX; @@ -241,12 +241,12 @@ struct wlr_geometry *wlr_output_layout_get_geometry( } } - layout->state->_geo->x = min_x; - layout->state->_geo->y = min_y; - layout->state->_geo->width = max_x - min_x; - layout->state->_geo->height = max_y - min_y; + layout->state->_box->x = min_x; + layout->state->_box->y = min_y; + layout->state->_box->width = max_x - min_x; + layout->state->_box->height = max_y - min_y; - return layout->state->_geo; + return layout->state->_box; } // not reached From b6031d106525706db6eef03d2a500259357ecb69 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 29 Aug 2017 12:32:17 -0400 Subject: [PATCH 32/34] refactor wlr_output_layout_closest_point --- include/wlr/types/wlr_output_layout.h | 7 ++-- types/wlr_cursor.c | 10 +++--- types/wlr_output_layout.c | 49 +++++++++------------------ 3 files changed, 24 insertions(+), 42 deletions(-) diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index 794fc491..b1253eb1 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -53,11 +53,10 @@ bool wlr_output_layout_intersects(struct wlr_output_layout *layout, struct wlr_output *reference, int x1, int y1, int x2, int y2); /** - * Get the closest boundary point of this layout from the given point from the - * reference output. If reference is NULL, gets the closest boundary point from - * the entire layout. + * Get the closest point on this layout from the given point from the reference + * output. If reference is NULL, gets the closest point from the entire layout. */ -void wlr_output_layout_closest_boundary(struct wlr_output_layout *layout, +void wlr_output_layout_closest_point(struct wlr_output_layout *layout, struct wlr_output *reference, double x, double y, double *dest_x, double *dest_y); diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index bc546b15..f9be0a7a 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -230,11 +230,11 @@ void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, } } else { if (!wlr_output_layout_contains_point(cur->state->layout, NULL, x, y)) { - double boundary_x, boundary_y; - wlr_output_layout_closest_boundary(cur->state->layout, NULL, x, y, - &boundary_x, &boundary_y); - x = boundary_x; - y = boundary_y; + double layout_x, layout_y; + wlr_output_layout_closest_point(cur->state->layout, NULL, x, y, + &layout_x, &layout_y); + x = layout_x; + y = layout_y; } } diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index ba2c158a..7c98837d 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -157,47 +158,33 @@ void wlr_output_layout_output_coords(struct wlr_output_layout *layout, } } -static double get_distance(double x1, double y1, double x2, double y2) { - double distance; - distance = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); - return distance; +static struct wlr_box *wlr_output_layout_output_get_box( + struct wlr_output_layout_output *l_output) { + l_output->state->_box->x = l_output->x; + l_output->state->_box->y = l_output->y; + wlr_output_effective_resolution(l_output->output, + &l_output->state->_box->width, &l_output->state->_box->height); + return l_output->state->_box; } -void wlr_output_layout_closest_boundary(struct wlr_output_layout *layout, +void wlr_output_layout_closest_point(struct wlr_output_layout *layout, struct wlr_output *reference, double x, double y, double *dest_x, double *dest_y) { - double min_x = INT_MAX, min_y = INT_MAX, min_distance = INT_MAX; + double min_x = DBL_MAX, min_y = DBL_MAX, min_distance = DBL_MAX; struct wlr_output_layout_output *l_output; wl_list_for_each(l_output, &layout->outputs, link) { if (reference != NULL && reference != l_output->output) { continue; } - int width, height; double output_x, output_y, output_distance; - wlr_output_effective_resolution(l_output->output, &width, &height); - - // find the closest x point - // TODO use wlr_box_closest_boundary - if (x < l_output->x) { - output_x = l_output->x; - } else if (x > l_output->x + width) { - output_x = l_output->x + width; - } else { - output_x = x; - } + struct wlr_box *box = wlr_output_layout_output_get_box(l_output); + wlr_box_closest_point(box, x, y, &output_x, &output_y); - // find closest y point - if (y < l_output->y) { - output_y = l_output->y; - } else if (y > l_output->y + height) { - output_y = l_output->y + height; - } else { - output_y = y; - } + // calculate squared distance suitable for comparison + output_distance = + (x - output_x) * (x - output_x) + (y - output_y) * (y - output_y); - // calculate distance - output_distance = get_distance(output_x, output_y, x, y); if (output_distance < min_distance) { min_x = output_x; min_y = output_y; @@ -215,11 +202,7 @@ struct wlr_box *wlr_output_layout_get_box( if (reference) { // output extents l_output= wlr_output_layout_get(layout, reference); - l_output->state->_box->x = l_output->x; - l_output->state->_box->y = l_output->y; - wlr_output_effective_resolution(reference, - &l_output->state->_box->width, &l_output->state->_box->height); - return l_output->state->_box; + return wlr_output_layout_output_get_box(l_output); } else { // layout extents int min_x = INT_MAX, min_y = INT_MAX; From 6699024b445a152e78670549efabe024cd670e99 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 29 Aug 2017 12:43:33 -0400 Subject: [PATCH 33/34] handle empty config file --- examples/config.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/config.c b/examples/config.c index a1ed5d5a..954edb06 100644 --- a/examples/config.c +++ b/examples/config.c @@ -212,9 +212,7 @@ struct example_config *parse_args(int argc, char *argv[]) { int result = ini_parse(config->config_path, config_ini_handler, config); if (result == -1) { - wlr_log(L_ERROR, "Could not find config file at %s", - config->config_path); - exit(1); + wlr_log(L_DEBUG, "No config file found. Using empty config."); } else if (result == -2) { wlr_log(L_ERROR, "Could not allocate memory to parse config file"); exit(1); From d9ab631f5d540d67d927e9d0975e2adb782e2e87 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Tue, 29 Aug 2017 12:48:45 -0400 Subject: [PATCH 34/34] bugfix: set cursor coords on warp_unchecked --- types/wlr_cursor.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index f9be0a7a..476af619 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -133,6 +133,9 @@ static void wlr_cursor_warp_unchecked(struct wlr_cursor *cur, wlr_output_move_cursor(l_output->output, output_x - hotspot_x, output_y - hotspot_y); } + + cur->x = x; + cur->y = y; } /** @@ -239,8 +242,6 @@ void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, } wlr_cursor_warp_unchecked(cur, x, y); - cur->x = x; - cur->y = y; } static void handle_pointer_motion(struct wl_listener *listener, void *data) {