diff --git a/include/wlr/types/wlr_output_layout.h b/include/wlr/types/wlr_output_layout.h index 78127f19..9cccd53c 100644 --- a/include/wlr/types/wlr_output_layout.h +++ b/include/wlr/types/wlr_output_layout.h @@ -9,6 +9,11 @@ struct wlr_output_layout_state; struct wlr_output_layout { struct wl_list outputs; struct wlr_output_layout_state *state; + + struct { + struct wl_signal change; + struct wl_signal destroy; + } events; }; struct wlr_output_layout_output_state; diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 476af619..8751e5c3 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -34,11 +34,15 @@ struct wlr_cursor_device { }; struct wlr_cursor_state { + struct wlr_cursor *cursor; struct wl_list devices; struct wlr_output_layout *layout; struct wlr_xcursor *xcursor; struct wlr_output *mapped_output; struct wlr_box *mapped_box; + + struct wl_listener layout_change; + struct wl_listener layout_destroy; }; struct wlr_cursor *wlr_cursor_create() { @@ -55,6 +59,7 @@ struct wlr_cursor *wlr_cursor_create() { return NULL; } + cur->state->cursor = cur; cur->state->mapped_output = NULL; wl_list_init(&cur->state->devices); @@ -83,7 +88,20 @@ struct wlr_cursor *wlr_cursor_create() { return cur; } +static void wlr_cursor_detach_output_layout(struct wlr_cursor *cur) { + if (!cur->state->layout) { + return; + } + + wl_list_remove(&cur->state->layout_destroy.link); + wl_list_remove(&cur->state->layout_change.link); + + cur->state->layout = NULL; +} + void wlr_cursor_destroy(struct wlr_cursor *cur) { + wlr_cursor_detach_output_layout(cur); + 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); @@ -430,8 +448,42 @@ void wlr_cursor_detach_input_device(struct wlr_cursor *cur, } } +static void handle_layout_destroy(struct wl_listener *listener, void *data) { + struct wlr_cursor_state *state = + wl_container_of(listener, state, layout_change); + wlr_cursor_detach_output_layout(state->cursor); +} + +static void handle_layout_change(struct wl_listener *listener, void *data) { + struct wlr_cursor_state *state = + wl_container_of(listener, state, layout_change); + struct wlr_output_layout *layout = data; + if (!wlr_output_layout_contains_point(layout, NULL, state->cursor->x, + state->cursor->y)) { + // the output we were on has gone away so go to the closest boundary + // point + double x, y; + wlr_output_layout_closest_point(layout, NULL, state->cursor->x, + state->cursor->y, &x, &y); + + wlr_cursor_warp_unchecked(state->cursor, x, y); + } +} + void wlr_cursor_attach_output_layout(struct wlr_cursor *cur, struct wlr_output_layout *l) { + wlr_cursor_detach_output_layout(cur); + + if (l == NULL) { + return; + } + + wl_signal_add(&l->events.change, &cur->state->layout_change); + cur->state->layout_change.notify = handle_layout_change; + + wl_signal_add(&l->events.destroy, &cur->state->layout_destroy); + cur->state->layout_destroy.notify = handle_layout_destroy; + cur->state->layout = l; } diff --git a/types/wlr_output_layout.c b/types/wlr_output_layout.c index b189bd46..97fc8a68 100644 --- a/types/wlr_output_layout.c +++ b/types/wlr_output_layout.c @@ -28,6 +28,10 @@ struct wlr_output_layout *wlr_output_layout_init() { layout->state = calloc(1, sizeof(struct wlr_output_layout_state)); layout->state->_box = calloc(1, sizeof(struct wlr_box)); wl_list_init(&layout->outputs); + + wl_signal_init(&layout->events.change); + wl_signal_init(&layout->events.destroy); + return layout; } @@ -46,6 +50,8 @@ void wlr_output_layout_destroy(struct wlr_output_layout *layout) { return; } + wl_signal_emit(&layout->events.destroy, layout); + struct wlr_output_layout_output *_output, *temp = NULL; wl_list_for_each_safe(_output, temp, &layout->outputs, link) { wlr_output_layout_output_destroy(_output); @@ -69,7 +75,7 @@ static struct wlr_box *wlr_output_layout_output_get_box( /** * This must be called whenever the layout changes to reconfigure the auto - * configured outputs. + * configured outputs and emit the `changed` event. * * Auto configured outputs are placed to the right of the north east corner of * the rightmost output in the layout in a horizontal line. @@ -108,6 +114,8 @@ static void wlr_output_layout_reconfigure(struct wlr_output_layout *layout) { l_output->y = max_x_y; max_x += box->width; } + + wl_signal_emit(&layout->events.change, layout); } static void handle_output_resolution(struct wl_listener *listener, void *data) {