Skip to content

Commit

Permalink
separated pointer and touch selection states
Browse files Browse the repository at this point in the history
  • Loading branch information
gg-rewrite committed Apr 11, 2020
1 parent 8d2117c commit 8eb5a82
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 55 deletions.
15 changes: 13 additions & 2 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,13 @@ struct slurp_seat {
struct wl_keyboard *wl_keyboard;

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

// pointer:
struct wl_pointer *wl_pointer;
Expand All @@ -101,4 +111,5 @@ struct slurp_seat {
};

bool box_intersect(const struct slurp_box *a, const struct slurp_box *b);
struct slurp_selection* seat_get_current_selection(struct slurp_seat* seat);
#endif
115 changes: 80 additions & 35 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,37 @@ bool box_intersect(const struct slurp_box *a, const struct slurp_box *b) {
a->height + a->y > b->y;
}

struct slurp_selection *seat_get_current_selection(struct slurp_seat *seat) {
if (seat->pointer_selection.has_selection) {
return &seat->pointer_selection;
} else if (seat->touch_selection.has_selection) {
return &seat->touch_selection;
} else {
return NULL;
}
}

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,
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;
struct slurp_selection *current_selection =
seat_get_current_selection(seat);
if (current_selection == NULL) {
//return;
current_selection = &seat->pointer_selection; //still need to track the mouse coordinates;
}
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,7 +68,7 @@ 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);

Expand All @@ -70,13 +86,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 @@ -102,40 +121,51 @@ static int max(int a, int 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);
struct slurp_selection *current_selection =
seat_get_current_selection(seat);
if (current_selection == NULL) {
return;
}
int32_t anchor_x = max(0, current_selection->anchor_x);
int32_t anchor_y = max(0, current_selection->anchor_y);
//current_selection->has_selection = true;
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);

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)) {
wl_list_for_each(box, &seat->state->boxes, link)
{
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;
Expand All @@ -144,31 +174,36 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
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) {
struct slurp_state *state = seat->state;
struct slurp_selection *current_selection = seat_get_current_selection(seat);
if (current_selection == NULL) {
return;
}
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) {
struct slurp_selection *current_selection = seat_get_current_selection(seat);
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,11 +212,15 @@ 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:
seat->pointer_selection.has_selection = true;
handle_selection_start(seat);
break;
case WL_POINTER_BUTTON_STATE_RELEASED:
Expand Down Expand Up @@ -234,13 +273,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,18 +320,22 @@ 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);
seat->touch_selection.has_selection = true;
move_seat(seat, x, y);
handle_selection_start(seat);
}
}

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,
Expand Down
47 changes: 29 additions & 18 deletions render.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@
#include "render.h"
#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);
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);
}

void render(struct slurp_output *output) {
void render(struct slurp_output *output)
{
struct slurp_state *state = output->state;
struct pool_buffer *buffer = output->current_buffer;
cairo_t *cairo = buffer->cairo;
Expand All @@ -26,39 +27,49 @@ void render(struct slurp_output *output) {
cairo_paint(cairo);

struct slurp_seat *seat;
wl_list_for_each(seat, &state->seats, link) {
if (!seat->wl_pointer) continue;
if (!seat->has_selection) {
wl_list_for_each(seat, &state->seats, link)
{
struct slurp_selection *current_selection =
seat_get_current_selection(seat);
if (current_selection == NULL)
continue;
if (!seat->wl_pointer)
continue;
if (!current_selection->has_selection) {
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

0 comments on commit 8eb5a82

Please sign in to comment.