Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support selection across multiple outputs #27

Merged
merged 8 commits into from
Feb 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion include/slurp.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "pool-buffer.h"
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"

struct slurp_box {
int32_t x, y;
Expand All @@ -21,6 +22,7 @@ struct slurp_state {
struct wl_shm *shm;
struct wl_compositor *compositor;
struct zwlr_layer_shell_v1 *layer_shell;
struct zxdg_output_manager_v1 *xdg_output_manager;
struct wl_list outputs; // slurp_output::link
struct wl_list seats; // slurp_seat::link

Expand All @@ -42,11 +44,14 @@ struct slurp_output {
struct wl_list link; // slurp_state::outputs

struct slurp_box geometry;
struct slurp_box logical_geometry;
int32_t scale;

struct wl_surface *surface;
struct zwlr_layer_surface_v1 *layer_surface;

struct zxdg_output_v1 *xdg_output;

struct wl_callback *frame_callback;
bool configured;
bool dirty;
Expand Down Expand Up @@ -76,5 +81,5 @@ struct slurp_seat {
};

void seat_get_box(struct slurp_seat *seat, struct slurp_box *result);

bool box_intersect(const struct slurp_box *a, const struct slurp_box *b);
#endif
98 changes: 83 additions & 15 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ static void noop() {

static void set_output_dirty(struct slurp_output *output);

bool box_intersect(const struct slurp_box *a, const struct slurp_box *b) {
return (a->x < b->x + b->width &&
a->x + a->width > b->x &&
a->y < b->y + b->height &&
a->height + a->y > b->y);
}

static struct slurp_output *output_from_surface(struct slurp_state *state,
struct wl_surface *surface);

Expand All @@ -28,13 +35,12 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
if (output == NULL) {
return;
}

seat->x = wl_fixed_to_int(surface_x);
seat->y = wl_fixed_to_int(surface_y);

// TODO: handle multiple overlapping outputs
seat->current_output = output;

seat->x = wl_fixed_to_int(surface_x) + seat->current_output->logical_geometry.x;
seat->y = wl_fixed_to_int(surface_y) + seat->current_output->logical_geometry.y;

wl_surface_set_buffer_scale(seat->cursor_surface, output->scale);
wl_surface_attach(seat->cursor_surface,
wl_cursor_image_get_buffer(output->cursor_image), 0, 0);
Expand All @@ -52,16 +58,30 @@ static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
seat->current_output = NULL;
}

static void seat_set_outputs_dirty(struct slurp_seat *seat) {
struct slurp_box box;
seat_get_box(seat, &box);
struct slurp_output *output;
wl_list_for_each(output, &seat->state->outputs, link) {
if (box_intersect(&output->logical_geometry, &box)) {
set_output_dirty(output);
}
}
}

static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
struct slurp_seat *seat = data;
// the places the cursor moved away from are also dirty
if (seat->button_state == WL_POINTER_BUTTON_STATE_PRESSED) {
seat_set_outputs_dirty(seat);
}

seat->x = wl_fixed_to_int(surface_x);
seat->y = wl_fixed_to_int(surface_y);
seat->x = wl_fixed_to_int(surface_x) + seat->current_output->logical_geometry.x;
seat->y = wl_fixed_to_int(surface_y) + seat->current_output->logical_geometry.y;

if (seat->button_state == WL_POINTER_BUTTON_STATE_PRESSED &&
seat->current_output != NULL) {
set_output_dirty(seat->current_output);
if (seat->button_state == WL_POINTER_BUTTON_STATE_PRESSED) {
seat_set_outputs_dirty(seat);
}
}

Expand All @@ -80,10 +100,6 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
break;
case WL_POINTER_BUTTON_STATE_RELEASED:
seat_get_box(seat, &state->result);
if (seat->current_output != NULL) {
state->result.x += seat->current_output->geometry.x;
state->result.y += seat->current_output->geometry.y;
}
state->running = false;
break;
}
Expand Down Expand Up @@ -181,6 +197,16 @@ static void output_handle_geometry(void *data, struct wl_output *wl_output,
output->geometry.y = y;
}

static void output_handle_mode(void *data, struct wl_output *wl_output,
uint32_t flags, int32_t width, int32_t height, int32_t refresh) {
struct slurp_output *output = data;
if ((flags & WL_OUTPUT_MODE_CURRENT) == 0) {
return;
}
output->geometry.width = width;
output->geometry.height = height;
}

static void output_handle_scale(void *data, struct wl_output *wl_output,
int32_t scale) {
struct slurp_output *output = data;
Expand All @@ -190,11 +216,32 @@ static void output_handle_scale(void *data, struct wl_output *wl_output,

static const struct wl_output_listener output_listener = {
.geometry = output_handle_geometry,
.mode = noop,
.mode = output_handle_mode,
.done = noop,
.scale = output_handle_scale,
};

static void xdg_output_handle_logical_position(void *data,
struct zxdg_output_v1 *xdg_output, int32_t x, int32_t y) {
struct slurp_output *output = data;
output->logical_geometry.x = x;
output->logical_geometry.y = y;
}
static void xdg_output_handle_logical_size(void *data,
struct zxdg_output_v1 *xdg_output, int32_t width, int32_t height) {
struct slurp_output *output = data;
output->logical_geometry.width = width;
output->logical_geometry.height = height;
}

static const struct zxdg_output_v1_listener xdg_output_listener = {
.logical_position = xdg_output_handle_logical_position,
.logical_size = xdg_output_handle_logical_size,
.done = noop,
.name = noop,
.description = noop,
};

static void create_output(struct slurp_state *state,
struct wl_output *wl_output) {
struct slurp_output *output = calloc(1, sizeof(struct slurp_output));
Expand All @@ -219,6 +266,9 @@ static void destroy_output(struct slurp_output *output) {
finish_buffer(&output->buffers[1]);
wl_cursor_theme_destroy(output->cursor_theme);
zwlr_layer_surface_v1_destroy(output->layer_surface);
if (output->xdg_output) {
zxdg_output_v1_destroy(output->xdg_output);
}
wl_surface_destroy(output->surface);
if (output->frame_callback) {
wl_callback_destroy(output->frame_callback);
Expand Down Expand Up @@ -343,6 +393,8 @@ static void handle_global(void *data, struct wl_registry *registry,
struct wl_output *wl_output =
wl_registry_bind(registry, name, &wl_output_interface, 3);
create_output(state, wl_output);
} else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) {
state->xdg_output_manager = wl_registry_bind(registry, name, &zxdg_output_manager_v1_interface, 1);
}
}

Expand Down Expand Up @@ -450,6 +502,9 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "compositor doesn't support zwlr_layer_shell_v1\n");
return EXIT_FAILURE;
}
if (state.xdg_output_manager == NULL) {
fprintf(stderr, "compositor doesn't support xdg-output. Guessing geometry from physical output size.\n");
}
if (wl_list_empty(&state.outputs)) {
fprintf(stderr, "no wl_output\n");
return EXIT_FAILURE;
Expand All @@ -464,7 +519,18 @@ int main(int argc, char *argv[]) {
state.layer_shell, output->surface, output->wl_output,
ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "selection");
zwlr_layer_surface_v1_add_listener(output->layer_surface,
&layer_surface_listener, output);
&layer_surface_listener, output);

if (state.xdg_output_manager) {
output->xdg_output = zxdg_output_manager_v1_get_xdg_output(
state.xdg_output_manager, output->wl_output);
zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output);
} else {
// guess
output->logical_geometry = output->geometry;
output->logical_geometry.width /= output->scale;
output->logical_geometry.height /= output->scale;
}

zwlr_layer_surface_v1_set_anchor(output->layer_surface,
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
Expand Down Expand Up @@ -494,6 +560,8 @@ int main(int argc, char *argv[]) {
}
output->cursor_image = cursor->images[0];
}
// second roundtrip for xdg-output
wl_display_roundtrip(state.display);

struct slurp_seat *seat;
wl_list_for_each(seat, &state.seats, link) {
Expand Down
8 changes: 6 additions & 2 deletions render.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,17 @@ void render(struct slurp_output *output) {
struct slurp_seat *seat;
wl_list_for_each(seat, &state->seats, link) {
if (!seat->wl_pointer) continue;
if (seat->button_state != WL_POINTER_BUTTON_STATE_PRESSED ||
seat->current_output != output) {
if (seat->button_state != WL_POINTER_BUTTON_STATE_PRESSED) {
continue;
}

struct slurp_box b;
seat_get_box(seat, &b);
if (!box_intersect(&output->logical_geometry, &b)) {
continue;
}
b.x -= output->logical_geometry.x;
b.y -= output->logical_geometry.y;

// Draw border
set_source_u32(cairo, state->colors.selection);
Expand Down