Skip to content

Crosshairs #95

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

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
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
19 changes: 19 additions & 0 deletions box.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "box.h"

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;
}

bool in_box(const struct slurp_box *box, int32_t x, int32_t y) {
return box->x <= x
&& box->x + box->width > x
&& box->y <= y
&& box->y + box->height > y;
}

int32_t box_size(const struct slurp_box *box) {
return box->width * box->height;
}
21 changes: 21 additions & 0 deletions include/box.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#ifndef _BOX_H
#define _BOX_H

#include <stdbool.h>
#include <stdint.h>
#include <wayland-client.h>

struct slurp_box {
int32_t x, y;
int32_t width, height;
char *label;
struct wl_list link;
};

bool box_intersect(const struct slurp_box *a, const struct slurp_box *b);

bool in_box(const struct slurp_box *box, int32_t x, int32_t y);

int32_t box_size(const struct slurp_box *box);

#endif
9 changes: 2 additions & 7 deletions include/slurp.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,14 @@
#include <stdint.h>
#include <wayland-client.h>

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

#define TOUCH_ID_EMPTY -1

struct slurp_box {
int32_t x, y;
int32_t width, height;
char *label;
struct wl_list link;
};

struct slurp_selection {
struct slurp_output *current_output;
int32_t x, y;
Expand Down Expand Up @@ -56,6 +50,7 @@ struct slurp_state {
bool display_dimensions;
bool single_point;
bool restrict_selection;
bool crosshairs;
struct wl_list boxes; // slurp_box::link
bool fixed_aspect_ratio;
double aspect_ratio; // h / w
Expand Down
51 changes: 22 additions & 29 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,6 @@ 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 bool in_box(const struct slurp_box *box, int32_t x, int32_t y) {
return box->x <= x
&& box->x + box->width > x
&& box->y <= y
&& box->y + box->height > y;
}

static int32_t box_size(const struct slurp_box *box) {
return box->width * box->height;
}

static int max(int a, int b) {
return (a > b) ? a : b;
}
Expand Down Expand Up @@ -91,12 +73,13 @@ static void seat_update_selection(struct slurp_seat *seat) {
}

static void seat_set_outputs_dirty(struct slurp_seat *seat) {
struct slurp_state *state = seat->state;
struct slurp_output *output;
wl_list_for_each(output, &seat->state->outputs, link) {
if (box_intersect(&output->logical_geometry,
&seat->pointer_selection.selection) ||
box_intersect(&output->logical_geometry,
&seat->touch_selection.selection)) {
struct slurp_box *geometry = &output->logical_geometry;
if (box_intersect(geometry, &seat->pointer_selection.selection) ||
box_intersect(geometry, &seat->touch_selection.selection) ||
(state->crosshairs && in_box(geometry, seat->pointer_selection.x, seat->pointer_selection.y))) {
set_output_dirty(output);
}
}
Expand Down Expand Up @@ -136,7 +119,7 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
}

// the places the cursor moved away from are also dirty
if (seat->pointer_selection.has_selection) {
if (seat->pointer_selection.has_selection || seat->state->crosshairs) {
seat_set_outputs_dirty(seat);
}

Expand Down Expand Up @@ -185,8 +168,10 @@ static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer,
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;
struct slurp_state *state = seat->state;

// the places the cursor moved away from are also dirty
if (seat->pointer_selection.has_selection) {
if (seat->pointer_selection.has_selection || state->crosshairs) {
seat_set_outputs_dirty(seat);
}

Expand All @@ -201,7 +186,7 @@ static void pointer_handle_motion(void *data, struct wl_pointer *wl_pointer,
break;
}

if (seat->pointer_selection.has_selection) {
if (seat->pointer_selection.has_selection || state->crosshairs) {
seat_set_outputs_dirty(seat);
}
}
Expand Down Expand Up @@ -351,8 +336,11 @@ static void keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboar
const uint32_t mods_latched, const uint32_t mods_locked,
const uint32_t group) {
struct slurp_seat *seat = data;
xkb_state_update_mask(seat->xkb_state, mods_depressed, mods_latched,
mods_locked, 0, 0, group);
// Avoid segfault if this is called before we initialize the keyboard state
if (seat->xkb_state) {
xkb_state_update_mask(seat->xkb_state, mods_depressed, mods_latched,
mods_locked, 0, 0, group);
}
}

static const struct wl_keyboard_listener keyboard_listener = {
Expand Down Expand Up @@ -586,6 +574,7 @@ static void send_frame(struct slurp_output *output) {

cairo_identity_matrix(output->current_buffer->cairo);
cairo_scale(output->current_buffer->cairo, output->scale, output->scale);
cairo_translate(output->current_buffer->cairo, -output->logical_geometry.x, -output->logical_geometry.y);

render(output);

Expand Down Expand Up @@ -713,7 +702,8 @@ static const char usage[] =
" -o Select a display output.\n"
" -p Select a single point.\n"
" -r Restrict selection to predefined boxes.\n"
" -a w:h Force aspect ratio.\n";
" -a w:h Force aspect ratio.\n"
" -x Display crosshairs across active display output.\n";

uint32_t parse_color(const char *color) {
if (color[0] == '#') {
Expand Down Expand Up @@ -892,7 +882,7 @@ int main(int argc, char *argv[]) {
char *format = "%x,%y %wx%h\n";
bool output_boxes = false;
int w, h;
while ((opt = getopt(argc, argv, "hdb:c:s:B:w:proa:f:F:")) != -1) {
while ((opt = getopt(argc, argv, "hdb:c:s:B:w:proa:f:F:x")) != -1) {
switch (opt) {
case 'h':
printf("%s", usage);
Expand Down Expand Up @@ -949,6 +939,9 @@ int main(int argc, char *argv[]) {
state.fixed_aspect_ratio = true;
state.aspect_ratio = (double) h / w;
break;
case 'x':
state.crosshairs = true;
break;
default:
printf("%s", usage);
return EXIT_FAILURE;
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ executable(
'main.c',
'pool-buffer.c',
'render.c',
'box.c',
protos_src,
],
dependencies: [
Expand Down
34 changes: 19 additions & 15 deletions render.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@ static void draw_rect(cairo_t *cairo, struct slurp_box *box, uint32_t color) {
box->width, box->height);
}

static void box_layout_to_output(struct slurp_box *box, struct slurp_output *output) {
box->x -= output->logical_geometry.x;
box->y -= output->logical_geometry.y;
}

void render(struct slurp_output *output) {
struct slurp_state *state = output->state;
struct pool_buffer *buffer = output->current_buffer;
Expand All @@ -39,9 +34,7 @@ void render(struct slurp_output *output) {
wl_list_for_each(choice_box, &state->boxes, link) {
if (box_intersect(&output->logical_geometry,
choice_box)) {
struct slurp_box b = *choice_box;
box_layout_to_output(&b, output);
draw_rect(cairo, &b, state->colors.choice);
draw_rect(cairo, choice_box, state->colors.choice);
cairo_fill(cairo);
}
}
Expand All @@ -51,6 +44,18 @@ void render(struct slurp_output *output) {
struct slurp_selection *current_selection =
slurp_seat_current_selection(seat);

if (!current_selection->has_selection && state->crosshairs) {
struct slurp_box *output_box = &output->logical_geometry;
if (in_box(output_box, current_selection->x, current_selection->y)) {

set_source_u32(cairo, state->colors.border);
cairo_rectangle(cairo, output_box->x, current_selection->y, output->logical_geometry.width, 1);
cairo_fill(cairo);
cairo_rectangle(cairo, current_selection->x, output->logical_geometry.y, 1, output->logical_geometry.height);
cairo_fill(cairo);
}
}

if (!current_selection->has_selection) {
continue;
}
Expand All @@ -59,15 +64,14 @@ void render(struct slurp_output *output) {
&current_selection->selection)) {
continue;
}
struct slurp_box b = current_selection->selection;
box_layout_to_output(&b, output);
struct slurp_box *sel_box = &current_selection->selection;

draw_rect(cairo, &b, state->colors.selection);
draw_rect(cairo, sel_box, state->colors.selection);
cairo_fill(cairo);

// Draw border
cairo_set_line_width(cairo, state->border_weight);
draw_rect(cairo, &b, state->colors.border);
draw_rect(cairo, sel_box, state->colors.border);
cairo_stroke(cairo);

if (state->display_dimensions) {
Expand All @@ -79,9 +83,9 @@ void render(struct slurp_output *output) {
// 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,
b.y + b.height + 20);
sel_box->width, sel_box->height);
cairo_move_to(cairo, sel_box->x + sel_box->width + 10,
sel_box->y + sel_box->height + 20);
cairo_show_text(cairo, dimensions);
}
}
Expand Down
4 changes: 4 additions & 0 deletions slurp.1.scd
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ held, the selection is moved instead of being resized.
Force selections to have the given aspect ratio. This constraint is not
applied to the predefined rectangles specified using *-o*.

*-x*
Draw fullscreen crosshairs on the display output containing the cursor until
a selection is started. This help aligning the origin of the selection.

# COLORS

Colors may be specified in #RRGGBB or #RRGGBBAA format. The # is optional.
Expand Down