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

separated pointer and touch selection states #55

Merged
merged 1 commit into from
Apr 15, 2020
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
16 changes: 11 additions & 5 deletions include/slurp.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ struct slurp_box {
struct wl_list link;
};

struct slurp_selection {
struct slurp_output *current_output;
int32_t x, y;
int32_t anchor_x, anchor_y;
struct slurp_box selection;
bool has_selection;
};

struct slurp_state {
bool running;
bool edit_anchor;
Expand Down Expand Up @@ -81,11 +89,9 @@ struct slurp_seat {
struct wl_keyboard *wl_keyboard;

//selection (pointer/touch):
struct slurp_output *current_output;
int32_t x, y;
int32_t anchor_x, anchor_y;
struct slurp_box selection;
bool has_selection;

struct slurp_selection pointer_selection;
struct slurp_selection touch_selection;

// pointer:
struct wl_pointer *wl_pointer;
Expand Down
117 changes: 69 additions & 48 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,19 @@ static struct slurp_output *output_from_surface(struct slurp_state *state,
struct wl_surface *surface);

static void move_seat(struct slurp_seat *seat, wl_fixed_t surface_x,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function should probably take a struct slurp_selection *. When called from the pointer event handler, it'd be called with pointer_selection. When called from the touch event handler, it'd be called with touch_selection.

Copy link
Contributor Author

@gg-rewrite gg-rewrite Apr 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also called from move_seat and render who have to determine which selection is active right now.

The code to do that will be identical for all the occurrencies so I moved it to a separate function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

b3be2eb

On second thought I've just added the slurp_selection argument to the relevant functions (move_seat, handle_selection*) and made a simple check in render as it was the only place left. seat_get_current_selection is thus unneeded and all the crutches are gone.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

wl_fixed_t surface_y) {
int x = wl_fixed_to_int(surface_x) + seat->current_output->logical_geometry.x;
int y = wl_fixed_to_int(surface_y) + seat->current_output->logical_geometry.y;
wl_fixed_t surface_y,
struct slurp_selection *current_selection) {
int x = wl_fixed_to_int(surface_x) +
current_selection->current_output->logical_geometry.x;
int y = wl_fixed_to_int(surface_y) + current_selection->current_output->logical_geometry.y;

if (seat->state->edit_anchor) {
seat->anchor_x += x - seat->x;
seat->anchor_y += y - seat->y;
current_selection->anchor_x += x - current_selection->x;
current_selection->anchor_y += y - current_selection->y;
}

seat->x = x;
seat->y = y;
current_selection->x = x;
current_selection->y = y;
}

static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
Expand All @@ -52,9 +54,9 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
return;
}
// TODO: handle multiple overlapping outputs
seat->current_output = output;
seat->pointer_selection.current_output = output;

move_seat(seat, surface_x, surface_y);
move_seat(seat, surface_x, surface_y, &seat->pointer_selection);

wl_surface_set_buffer_scale(seat->cursor_surface, output->scale);
wl_surface_attach(seat->cursor_surface,
Expand All @@ -70,13 +72,16 @@ static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
struct slurp_seat *seat = data;

// TODO: handle multiple overlapping outputs
seat->current_output = NULL;
seat->pointer_selection.current_output = NULL;
}

static void seat_set_outputs_dirty(struct slurp_seat *seat) {
struct slurp_output *output;
wl_list_for_each(output, &seat->state->outputs, link) {
if (box_intersect(&output->logical_geometry, &seat->selection)) {
if (box_intersect(&output->logical_geometry,
&seat->pointer_selection.selection) ||
box_intersect(&output->logical_geometry,
&seat->touch_selection.selection)) {
set_output_dirty(output);
}
}
Expand All @@ -101,74 +106,82 @@ static int max(int a, int b) {
return (a > b) ? a : b;
}

static void handle_active_selection_motion(struct slurp_seat *seat) {
int32_t anchor_x = max(0, seat->anchor_x);
int32_t anchor_y = max(0, seat->anchor_y);
seat->has_selection = true;
seat->selection.x = min(anchor_x, seat->x);
seat->selection.y = min(anchor_y, seat->y);
static void handle_active_selection_motion(struct slurp_seat *seat, struct slurp_selection *current_selection) {
int32_t anchor_x = max(0, current_selection->anchor_x);
int32_t anchor_y = max(0, current_selection->anchor_y);
current_selection->selection.x = min(anchor_x, current_selection->x);
current_selection->selection.y = min(anchor_y, current_selection->y);
// selection includes the seat and anchor positions
seat->selection.width = abs(seat->x - anchor_x) + 1;
seat->selection.height = abs(seat->y - anchor_y) + 1;
current_selection->selection.width =
abs(current_selection->x - anchor_x) + 1;
current_selection->selection.height =
abs(current_selection->y - anchor_y) + 1;
}

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->has_selection) {
if (seat->pointer_selection.has_selection) {
seat_set_outputs_dirty(seat);
}

move_seat(seat, surface_x, surface_y);
move_seat(seat, surface_x, surface_y, &seat->pointer_selection);

switch (seat->button_state) {
case WL_POINTER_BUTTON_STATE_RELEASED:
seat->has_selection = false;
seat->pointer_selection.has_selection = false;

// find smallest box intersecting the cursor
struct slurp_box *box;
wl_list_for_each(box, &seat->state->boxes, link) {
if (in_box(box, seat->x, seat->y)) {
if (seat->has_selection &&
box_size(&seat->selection) < box_size(box)) {
if (in_box(box, seat->pointer_selection.x,
seat->pointer_selection.y)) {
if (seat->pointer_selection.has_selection &&
box_size(
&seat->pointer_selection.selection) <
box_size(box)) {
continue;
}
seat->selection = *box;
seat->has_selection = true;
seat->pointer_selection.selection = *box;
seat->pointer_selection.has_selection = true;
}
}
break;
case WL_POINTER_BUTTON_STATE_PRESSED:;
handle_active_selection_motion(seat);
handle_active_selection_motion(seat, &seat->pointer_selection);
break;
}

if (seat->has_selection) {
if (seat->pointer_selection.has_selection) {
seat_set_outputs_dirty(seat);
}
}

static void handle_selection_start(struct slurp_seat *seat) {
static void handle_selection_start(struct slurp_seat *seat,
struct slurp_selection *current_selection) {
struct slurp_state *state = seat->state;
current_selection->has_selection = true;

if (state->single_point) {
state->result.x = seat->x;
state->result.y = seat->y;
state->result.x = current_selection->x;
state->result.y = current_selection->y;
state->result.width = state->result.height = 1;
state->running = false;
} else {
seat->anchor_x = seat->x;
seat->anchor_y = seat->y;
current_selection->anchor_x = current_selection->x;
current_selection->anchor_y = current_selection->y;
}
}

static void handle_selection_end(struct slurp_seat *seat) {
static void handle_selection_end(struct slurp_seat *seat,
struct slurp_selection *current_selection) {
struct slurp_state *state = seat->state;
if (state->single_point) {
return;
}
if (seat->has_selection) {
state->result = seat->selection;
if (current_selection->has_selection) {
state->result = current_selection->selection;
}
state->running = false;
}
Expand All @@ -177,15 +190,18 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, uint32_t time, uint32_t button,
uint32_t button_state) {
struct slurp_seat *seat = data;
if (seat->touch_selection.has_selection) {
return;
}

seat->button_state = button_state;

switch (button_state) {
case WL_POINTER_BUTTON_STATE_PRESSED:
handle_selection_start(seat);
handle_selection_start(seat, &seat->pointer_selection);
break;
case WL_POINTER_BUTTON_STATE_RELEASED:
handle_selection_end(seat);
handle_selection_end(seat, &seat->pointer_selection);
break;
}
}
Expand Down Expand Up @@ -234,13 +250,15 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard,
case WL_KEYBOARD_KEY_STATE_PRESSED:
switch (keysym) {
case XKB_KEY_Escape:
seat->has_selection = false;
seat->pointer_selection.has_selection = false;
seat->touch_selection.has_selection = false;
state->edit_anchor = false;
state->running = false;
break;

case XKB_KEY_space:
if (!seat->has_selection) {
if (!seat->pointer_selection.has_selection &&
!seat->touch_selection.has_selection) {
break;
}
state->edit_anchor = true;
Expand Down Expand Up @@ -279,24 +297,27 @@ static void touch_handle_down(void *data, struct wl_touch *touch,
struct wl_surface *surface, int32_t id,
wl_fixed_t x, wl_fixed_t y) {
struct slurp_seat *seat = data;
if (seat->pointer_selection.has_selection) {
return;
}
if (seat->touch_id == TOUCH_ID_EMPTY) {
seat->touch_id = id;
seat->current_output =
seat->touch_selection.current_output =
output_from_surface(seat->state, surface);
move_seat(seat, x, y);
handle_selection_start(seat);
move_seat(seat, x, y, &seat->touch_selection);
handle_selection_start(seat, &seat->touch_selection);
}
}

static void touch_clear_state(struct slurp_seat *seat) {
seat->touch_id = TOUCH_ID_EMPTY;
seat->current_output = NULL;
seat->touch_selection.current_output = NULL;
}

static void touch_handle_up(void *data, struct wl_touch *touch, uint32_t serial,
uint32_t time, int32_t id) {
struct slurp_seat *seat = data;
handle_selection_end(seat);
handle_selection_end(seat, &seat->touch_selection);
touch_clear_state(seat);
}

Expand All @@ -305,8 +326,8 @@ static void touch_handle_motion(void *data, struct wl_touch *touch,
wl_fixed_t y) {
struct slurp_seat *seat = data;
if (seat->touch_id == id) {
move_seat(seat, x, y);
handle_active_selection_motion(seat);
move_seat(seat, x, y, &seat->touch_selection);
handle_active_selection_motion(seat, &seat->touch_selection);
seat_set_outputs_dirty(seat);
}
}
Expand Down
39 changes: 23 additions & 16 deletions render.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@
#include "slurp.h"

static void set_source_u32(cairo_t *cairo, uint32_t color) {
cairo_set_source_rgba(cairo,
(color >> (3*8) & 0xFF) / 255.0,
(color >> (2*8) & 0xFF) / 255.0,
(color >> (1*8) & 0xFF) / 255.0,
(color >> (0*8) & 0xFF) / 255.0);
cairo_set_source_rgba(cairo, (color >> (3 * 8) & 0xFF) / 255.0,
(color >> (2 * 8) & 0xFF) / 255.0,
(color >> (1 * 8) & 0xFF) / 255.0,
(color >> (0 * 8) & 0xFF) / 255.0);
}

void render(struct slurp_output *output) {
Expand All @@ -27,38 +26,46 @@ 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->has_selection) {
struct slurp_selection *current_selection =
seat->touch_selection.has_selection ?
&seat->touch_selection :
&seat->pointer_selection;

if (!seat->wl_pointer) {
continue;
}

if(!box_intersect(&output->logical_geometry, &seat->selection)) {

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

// Draw border
set_source_u32(cairo, state->colors.selection);
cairo_rectangle(cairo, b.x * scale, b.y * scale,
b.width * scale, b.height * scale);
b.width * scale, b.height * scale);
cairo_fill(cairo);

set_source_u32(cairo, state->colors.border);
cairo_set_line_width(cairo, state->border_weight * scale);
cairo_rectangle(cairo, b.x * scale, b.y * scale,
b.width * scale, b.height * scale);
b.width * scale, b.height * scale);
cairo_stroke(cairo);

if (state->display_dimensions) {
cairo_select_font_face(cairo, "Sans", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_select_font_face(cairo, "Sans",
CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size(cairo, 14 * scale);
// buffer of 12 can hold selections up to 99999x99999
char dimensions[12];
snprintf(dimensions, sizeof(dimensions), "%ix%i", b.width, b.height);
cairo_move_to(cairo, (b.x + b.width + 10) * scale, (b.y + b.height + 20) * scale);
snprintf(dimensions, sizeof(dimensions), "%ix%i",
b.width, b.height);
cairo_move_to(cairo, (b.x + b.width + 10) * scale,
(b.y + b.height + 20) * scale);
cairo_show_text(cairo, dimensions);
}
}
Expand Down