From 9af0919f2a1e42ff4f6c2abc2ff03bfdeabcaef8 Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Sat, 8 Oct 2022 18:18:46 +0200 Subject: [PATCH 1/5] feat: use keyboard selection --- include/slurp.h | 8 ++- main.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++-- render.c | 36 ++++++++++++- slurp.1.scd | 16 ++++++ 4 files changed, 188 insertions(+), 8 deletions(-) diff --git a/include/slurp.h b/include/slurp.h index c2239e4..0d676eb 100644 --- a/include/slurp.h +++ b/include/slurp.h @@ -46,12 +46,16 @@ struct slurp_state { uint32_t border; uint32_t selection; uint32_t choice; + uint32_t font; + uint32_t choice_font; } colors; const char *font_family; + uint32_t font_size; uint32_t border_weight; bool display_dimensions; + bool display_labels; bool single_point; bool restrict_selection; struct wl_list boxes; // slurp_box::link @@ -99,6 +103,7 @@ struct slurp_seat { struct slurp_selection pointer_selection; struct slurp_selection touch_selection; + struct slurp_selection keyboard_selection; // pointer: struct wl_pointer *wl_pointer; @@ -118,6 +123,7 @@ bool box_intersect(const struct slurp_box *a, const struct slurp_box *b); static inline struct slurp_selection *slurp_seat_current_selection(struct slurp_seat *seat) { return seat->touch_selection.has_selection ? &seat->touch_selection : - &seat->pointer_selection; + seat->keyboard_selection.has_selection ? + &seat->keyboard_selection : &seat->pointer_selection; } #endif diff --git a/main.c b/main.c index 1eefc55..f513bfe 100644 --- a/main.c +++ b/main.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -18,6 +19,10 @@ #define BORDER_COLOR 0x000000FF #define SELECTION_COLOR 0x00000000 #define FONT_FAMILY "sans-serif" +#define FONT_SIZE 14 +#define FONT_COLOR 0xFFFFFFFF +#define CHOICE_FONT_COLOR 0xFCBA03FF +#define KEYBOAD_SELECTORS "abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ" static void noop() { // This space intentionally left blank @@ -72,6 +77,7 @@ static void move_seat(struct slurp_seat *seat, wl_fixed_t surface_x, static void seat_update_selection(struct slurp_seat *seat) { seat->pointer_selection.has_selection = false; + seat->keyboard_selection.has_selection = false; // find smallest box intersecting the cursor struct slurp_box *box; @@ -96,7 +102,9 @@ static void seat_set_outputs_dirty(struct slurp_seat *seat) { if (box_intersect(&output->logical_geometry, &seat->pointer_selection.selection) || box_intersect(&output->logical_geometry, - &seat->touch_selection.selection)) { + &seat->touch_selection.selection) || + box_intersect(&output->logical_geometry, + &seat->keyboard_selection.selection)) { set_output_dirty(output); } } @@ -136,7 +144,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->keyboard_selection.has_selection) { seat_set_outputs_dirty(seat); } @@ -291,6 +299,22 @@ static void recompute_selection(struct slurp_seat *seat) { } } +static void handle_keyboard_selection(struct slurp_seat *seat, char *key) { + seat->pointer_selection.has_selection = false; + seat->keyboard_selection.has_selection = false; + + struct slurp_box *box; + wl_list_for_each(box, &seat->state->boxes, link) { + if (!box->label || strncmp(key, box->label, strlen(key)) != 0) { + continue; + } + seat->keyboard_selection.selection = *box; + seat->keyboard_selection.has_selection = true; + seat_set_outputs_dirty(seat); + break; + } +} + static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, const uint32_t serial, const uint32_t time, const uint32_t key, const uint32_t key_state) { @@ -301,6 +325,11 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, switch (key_state) { case WL_KEYBOARD_KEY_STATE_PRESSED: switch (keysym) { + case XKB_KEY_Return: + if (state->restrict_selection && seat->keyboard_selection.has_selection) { + handle_selection_start(seat, &seat->keyboard_selection); + } + break; case XKB_KEY_Escape: seat->pointer_selection.has_selection = false; seat->touch_selection.has_selection = false; @@ -322,6 +351,24 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, recompute_selection(seat); } break; + default: + if (state->restrict_selection && state->display_labels) { + char *pressed_key; + int key_size; + key_size = xkb_state_key_get_utf8(seat->xkb_state, key + 8, NULL, 0) + 1; + if (key_size) { + pressed_key = (char *) malloc(key_size * sizeof(char)); + if (pressed_key == NULL) { + fprintf(stderr, "malloc failed\n"); + exit(EXIT_FAILURE); + } + xkb_state_key_get_utf8(seat->xkb_state, key + 8, pressed_key, key_size); + if (strstr(KEYBOAD_SELECTORS, pressed_key) != NULL) { + handle_keyboard_selection(seat, pressed_key); + } + free(pressed_key); + } + } } break; @@ -694,16 +741,21 @@ static const char usage[] = "\n" " -h Show help message and quit.\n" " -d Display dimensions of selection.\n" + " -l Display labels of restricted selections.\n" + " -L #rrggbbaa Set font color.\n" " -b #rrggbbaa Set background color.\n" " -c #rrggbbaa Set border color.\n" " -s #rrggbbaa Set selection color.\n" + " -S #rrggbbaa Set font color of selected labels.\n" " -B #rrggbbaa Set option box color.\n" " -F s Set the font family for the dimensions.\n" + " -g n Set font size.\n" " -w n Set border weight.\n" " -f s Set output format.\n" " -o Select a display output.\n" " -p Select a single point.\n" " -r Restrict selection to predefined boxes.\n" + " -x r:c Split the predefined box or display into the given amount of rows and columns.\n" " -a w:h Force aspect ratio.\n"; uint32_t parse_color(const char *color) { @@ -818,6 +870,24 @@ static void add_choice_box(struct slurp_state *state, wl_list_insert(state->boxes.prev, &b->link); } +static void split_box_into(struct slurp_state *state, struct slurp_box *box, int rows, int cols) { + int row, col, i = 0; + for (row = 0; row < rows; row++) { + for (col = 0; col < cols; col++) { + struct slurp_box split_box = {0}; + char label[2] = {'a', '\0'}; + split_box.x = box->x + (box->width / cols) * col; + split_box.y = box->y + (box->height / rows) * row; + split_box.width = box->width / cols; + split_box.height = box->height / rows; + strncpy(label, &KEYBOAD_SELECTORS[i], 1); + split_box.label = label; + add_choice_box(state, &split_box); + i++; + } + } +} + int main(int argc, char *argv[]) { int status = EXIT_SUCCESS; @@ -831,20 +901,25 @@ int main(int argc, char *argv[]) { .border = BORDER_COLOR, .selection = SELECTION_COLOR, .choice = BG_COLOR, + .font = FONT_COLOR, + .choice_font = CHOICE_FONT_COLOR, }, .border_weight = 2, .display_dimensions = false, + .display_labels = false, .restrict_selection = false, .fixed_aspect_ratio = false, .aspect_ratio = 0, - .font_family = FONT_FAMILY + .font_family = FONT_FAMILY, + .font_size = FONT_SIZE }; int opt; 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) { + bool split_rows_cols = false; + int w, h, r, c; + while ((opt = getopt(argc, argv, "hdlb:x:L:S:c:s:B:w:g:proa:f:F:")) != -1) { switch (opt) { case 'h': printf("%s", usage); @@ -852,6 +927,15 @@ int main(int argc, char *argv[]) { case 'd': state.display_dimensions = true; break; + case 'l': + state.display_labels = true; + break; + case 'L': + state.colors.font = parse_color(optarg); + break; + case 'S': + state.colors.choice_font = parse_color(optarg); + break; case 'b': state.colors.background = parse_color(optarg); break; @@ -870,6 +954,15 @@ int main(int argc, char *argv[]) { case 'F': state.font_family = optarg; break; + case 'g': + errno = 0; + char *endptr; + state.font_size = strtol(optarg, &endptr, 10); + if (*endptr || errno) { + fprintf(stderr, "Error: expected numeric argument for -g\n"); + exit(EXIT_FAILURE); + } + break; case 'w': { errno = 0; char *endptr; @@ -889,6 +982,22 @@ int main(int argc, char *argv[]) { case 'r': state.restrict_selection = true; break; + case 'x': + if (sscanf(optarg, "%d:%d", &r, &c) != 2) { + fprintf(stderr, "invalid format (must be rows:columns)\n"); + return EXIT_FAILURE; + } + if (r <= 0 || c <= 0) { + fprintf(stderr, "number of rows and columns must be greater than zero\n"); + return EXIT_FAILURE; + } + if ((uint32_t)(r * c) > strlen(KEYBOAD_SELECTORS)) { + fprintf(stderr, "rows times columns must not be greater than %zu\n", strlen(KEYBOAD_SELECTORS)); + return EXIT_FAILURE; + } + split_rows_cols = true; + state.restrict_selection = true; + break; case 'a': if (sscanf(optarg, "%d:%d", &w, &h) != 2) { fprintf(stderr, "invalid aspect ratio\n"); @@ -907,6 +1016,11 @@ int main(int argc, char *argv[]) { } } + if (output_boxes && split_rows_cols) { + fprintf(stderr, "-x and -o cannot be used together\n"); + return EXIT_FAILURE; + } + if (state.single_point && state.restrict_selection) { fprintf(stderr, "-p and -r cannot be used together\n"); return EXIT_FAILURE; @@ -923,6 +1037,11 @@ int main(int argc, char *argv[]) { fprintf(stderr, "invalid box format: %s\n", line); return EXIT_FAILURE; } + if (split_rows_cols) { + split_box_into(&state, &in_box, r, c); + free(in_box.label); + break; + } add_choice_box(&state, &in_box); free(in_box.label); } @@ -1041,6 +1160,13 @@ int main(int argc, char *argv[]) { } } + if (split_rows_cols && wl_list_empty(&state.boxes)) { + struct slurp_output *box_output; + wl_list_for_each(box_output, &state.outputs, link) { + split_box_into(&state, &box_output->logical_geometry, r, c); + } + } + struct slurp_seat *seat; wl_list_for_each(seat, &state.seats, link) { seat->cursor_surface = diff --git a/render.c b/render.c index d91f8a3..f51f2b3 100644 --- a/render.c +++ b/render.c @@ -1,11 +1,14 @@ #include #include #include +#include #include "pool-buffer.h" #include "render.h" #include "slurp.h" +#define CHAR_WIDTH_PX 10.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, @@ -36,6 +39,7 @@ void render(struct slurp_output *output) { // Draw option boxes from input struct slurp_box *choice_box; + cairo_text_extents_t extents; wl_list_for_each(choice_box, &state->boxes, link) { if (box_intersect(&output->logical_geometry, choice_box)) { @@ -43,6 +47,20 @@ void render(struct slurp_output *output) { box_layout_to_output(&b, output); draw_rect(cairo, &b, state->colors.choice); cairo_fill(cairo); + + // Draw label + if (state->display_labels && b.label) { + + cairo_select_font_face(cairo, state->font_family, + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size(cairo, state->font_size); + cairo_text_extents(cairo, b.label, &extents); + set_source_u32(cairo, state->colors.font); + cairo_move_to(cairo, b.x + (b.width - extents.width) / 2.0, + b.y + b.height / 2.0); + cairo_show_text(cairo, b.label); + } } } @@ -70,12 +88,26 @@ void render(struct slurp_output *output) { draw_rect(cairo, &b, state->colors.border); cairo_stroke(cairo); + // Draw label + if (state->display_labels && b.label) { + + cairo_select_font_face(cairo, state->font_family, + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size(cairo, state->font_size); + cairo_text_extents(cairo, b.label, &extents); + set_source_u32(cairo, state->colors.choice_font); + cairo_move_to(cairo, b.x + (b.width - extents.width) / 2.0, + b.y + b.height / 2.0); + cairo_show_text(cairo, b.label); + } + if (state->display_dimensions) { cairo_select_font_face(cairo, state->font_family, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cairo, 14); - set_source_u32(cairo, state->colors.border); + cairo_set_font_size(cairo, state->font_size); + set_source_u32(cairo, state->colors.font); // buffer of 12 can hold selections up to 99999x99999 char dimensions[12]; snprintf(dimensions, sizeof(dimensions), "%ix%i", diff --git a/slurp.1.scd b/slurp.1.scd index 6a93475..5df7f14 100644 --- a/slurp.1.scd +++ b/slurp.1.scd @@ -31,6 +31,12 @@ held, the selection is moved instead of being resized. *-d* Display dimensions of selection. +*-l* + Display labels of restricted selections. + +*-L* _color_ + Set font color. See *COLORS* for more detail. + *-b* _color_ Set background color. See *COLORS* for more detail. @@ -40,6 +46,9 @@ held, the selection is moved instead of being resized. *-s* _color_ Set selection color. See *COLORS* for more detail. +*-S* _color_ + Set font color of selected labels. See *COLORS* for more detail. + *-B* _color_ Set color for highlighting predefined rectangles from standard input when not selected. @@ -50,6 +59,9 @@ held, the selection is moved instead of being resized. to work are the standard generic CSS2 options: serif, sans-serif, monospace, cursive and fantasy. It defaults to the sans-serif family name. +*-g* _font size_ + Set font size. + *-w* _weight_ Set border weight. @@ -69,6 +81,10 @@ held, the selection is moved instead of being resized. from standard input, if *-o* is used, the rectangles of all display outputs. This option conflicts with *-p*. +*-x* _rows_:_columns_ + Split the predefined box or display into the given amount of rows and columns. + This implicitly sets *-r*. Conflicts with *-o*. + *-a* _width_:_height_ Force selections to have the given aspect ratio. This constraint is not applied to the predefined rectangles specified using *-o*. From abf0ca421964512b82612ef075972ee01eedd42b Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Sat, 8 Oct 2022 21:20:49 +0200 Subject: [PATCH 2/5] fix: not needed anymore --- render.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/render.c b/render.c index f51f2b3..fce1645 100644 --- a/render.c +++ b/render.c @@ -7,8 +7,6 @@ #include "render.h" #include "slurp.h" -#define CHAR_WIDTH_PX 10.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, From dee6581f065346978d4782184f54f9aff578995e Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Sun, 9 Oct 2022 11:22:05 +0200 Subject: [PATCH 3/5] fix: change -x to -m --- main.c | 8 ++++---- slurp.1.scd | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/main.c b/main.c index f513bfe..33d79d3 100644 --- a/main.c +++ b/main.c @@ -755,7 +755,7 @@ static const char usage[] = " -o Select a display output.\n" " -p Select a single point.\n" " -r Restrict selection to predefined boxes.\n" - " -x r:c Split the predefined box or display into the given amount of rows and columns.\n" + " -m r:c Split the predefined box or display into the given amount of rows and columns.\n" " -a w:h Force aspect ratio.\n"; uint32_t parse_color(const char *color) { @@ -919,7 +919,7 @@ int main(int argc, char *argv[]) { bool output_boxes = false; bool split_rows_cols = false; int w, h, r, c; - while ((opt = getopt(argc, argv, "hdlb:x:L:S:c:s:B:w:g:proa:f:F:")) != -1) { + while ((opt = getopt(argc, argv, "hdlb:m:L:S:c:s:B:w:g:proa:f:F:")) != -1) { switch (opt) { case 'h': printf("%s", usage); @@ -982,7 +982,7 @@ int main(int argc, char *argv[]) { case 'r': state.restrict_selection = true; break; - case 'x': + case 'm': if (sscanf(optarg, "%d:%d", &r, &c) != 2) { fprintf(stderr, "invalid format (must be rows:columns)\n"); return EXIT_FAILURE; @@ -1017,7 +1017,7 @@ int main(int argc, char *argv[]) { } if (output_boxes && split_rows_cols) { - fprintf(stderr, "-x and -o cannot be used together\n"); + fprintf(stderr, "-m and -o cannot be used together\n"); return EXIT_FAILURE; } diff --git a/slurp.1.scd b/slurp.1.scd index 5df7f14..7f83ed1 100644 --- a/slurp.1.scd +++ b/slurp.1.scd @@ -81,7 +81,7 @@ held, the selection is moved instead of being resized. from standard input, if *-o* is used, the rectangles of all display outputs. This option conflicts with *-p*. -*-x* _rows_:_columns_ +*-m* _rows_:_columns_ Split the predefined box or display into the given amount of rows and columns. This implicitly sets *-r*. Conflicts with *-o*. From 32cd15869b1e0f4137ef891a0c518208b6e7b007 Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Sun, 9 Oct 2022 11:48:44 +0200 Subject: [PATCH 4/5] fix: move box related functions to box.c --- box.c | 19 +++++++++++++++++++ include/box.h | 21 +++++++++++++++++++++ include/slurp.h | 10 +++------- 3 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 box.c create mode 100644 include/box.h diff --git a/box.c b/box.c new file mode 100644 index 0000000..4684a2d --- /dev/null +++ b/box.c @@ -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; +} diff --git a/include/box.h b/include/box.h new file mode 100644 index 0000000..41d6177 --- /dev/null +++ b/include/box.h @@ -0,0 +1,21 @@ +#ifndef _BOX_H +#define _BOX_H + +#include +#include +#include + +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 diff --git a/include/slurp.h b/include/slurp.h index 0d676eb..d7cdb83 100644 --- a/include/slurp.h +++ b/include/slurp.h @@ -5,19 +5,13 @@ #include #include +#include "box.h" #include "pool-buffer.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; @@ -48,6 +42,7 @@ struct slurp_state { uint32_t choice; uint32_t font; uint32_t choice_font; + uint32_t crosshair; } colors; const char *font_family; @@ -60,6 +55,7 @@ struct slurp_state { bool restrict_selection; struct wl_list boxes; // slurp_box::link bool fixed_aspect_ratio; + bool crosshair; double aspect_ratio; // h / w struct slurp_box result; From 5acdd9b602a9693e96b3a39003b61477dedb078c Mon Sep 17 00:00:00 2001 From: dadav <33197631+dadav@users.noreply.github.com> Date: Sun, 9 Oct 2022 11:49:00 +0200 Subject: [PATCH 5/5] feat: add crosshair --- main.c | 43 ++++++++++++++++++++----------------------- meson.build | 1 + render.c | 12 ++++++++++++ slurp.1.scd | 6 ++++++ 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/main.c b/main.c index 33d79d3..38053d8 100644 --- a/main.c +++ b/main.c @@ -18,6 +18,7 @@ #define BG_COLOR 0xFFFFFF40 #define BORDER_COLOR 0x000000FF #define SELECTION_COLOR 0x00000000 +#define CROSSAIR_COLOR 0x00FFFFFF #define FONT_FAMILY "sans-serif" #define FONT_SIZE 14 #define FONT_COLOR 0xFFFFFFFF @@ -30,24 +31,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; } @@ -97,14 +80,17 @@ 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) { + struct slurp_box *geometry = &output->logical_geometry; if (box_intersect(&output->logical_geometry, &seat->pointer_selection.selection) || box_intersect(&output->logical_geometry, &seat->touch_selection.selection) || box_intersect(&output->logical_geometry, - &seat->keyboard_selection.selection)) { + &seat->keyboard_selection.selection) || + (state->crosshair && in_box(geometry, seat->pointer_selection.x, seat->pointer_selection.y))) { set_output_dirty(output); } } @@ -144,7 +130,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 || seat->keyboard_selection.has_selection) { + if (seat->pointer_selection.has_selection || seat->keyboard_selection.has_selection || seat->state->crosshair) { seat_set_outputs_dirty(seat); } @@ -185,7 +171,7 @@ 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->pointer_selection.has_selection) { + if (seat->pointer_selection.has_selection || seat->keyboard_selection.has_selection || seat->state->crosshair) { seat_set_outputs_dirty(seat); } @@ -200,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 || seat->keyboard_selection.has_selection || seat->state->crosshair) { seat_set_outputs_dirty(seat); } } @@ -624,6 +610,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); @@ -745,6 +732,7 @@ static const char usage[] = " -L #rrggbbaa Set font color.\n" " -b #rrggbbaa Set background color.\n" " -c #rrggbbaa Set border color.\n" + " -X #rrggbbaa Set crosshair color.\n" " -s #rrggbbaa Set selection color.\n" " -S #rrggbbaa Set font color of selected labels.\n" " -B #rrggbbaa Set option box color.\n" @@ -756,6 +744,7 @@ static const char usage[] = " -p Select a single point.\n" " -r Restrict selection to predefined boxes.\n" " -m r:c Split the predefined box or display into the given amount of rows and columns.\n" + " -x Enable crosshair.\n" " -a w:h Force aspect ratio.\n"; uint32_t parse_color(const char *color) { @@ -902,6 +891,7 @@ int main(int argc, char *argv[]) { .selection = SELECTION_COLOR, .choice = BG_COLOR, .font = FONT_COLOR, + .crosshair = CROSSAIR_COLOR, .choice_font = CHOICE_FONT_COLOR, }, .border_weight = 2, @@ -910,6 +900,7 @@ int main(int argc, char *argv[]) { .restrict_selection = false, .fixed_aspect_ratio = false, .aspect_ratio = 0, + .crosshair = false, .font_family = FONT_FAMILY, .font_size = FONT_SIZE }; @@ -919,7 +910,7 @@ int main(int argc, char *argv[]) { bool output_boxes = false; bool split_rows_cols = false; int w, h, r, c; - while ((opt = getopt(argc, argv, "hdlb:m:L:S:c:s:B:w:g:proa:f:F:")) != -1) { + while ((opt = getopt(argc, argv, "hdlb:X:m:L:S:c:s:B:w:g:prxoa:f:F:")) != -1) { switch (opt) { case 'h': printf("%s", usage); @@ -933,6 +924,9 @@ int main(int argc, char *argv[]) { case 'L': state.colors.font = parse_color(optarg); break; + case 'X': + state.colors.crosshair = parse_color(optarg); + break; case 'S': state.colors.choice_font = parse_color(optarg); break; @@ -954,6 +948,9 @@ int main(int argc, char *argv[]) { case 'F': state.font_family = optarg; break; + case 'x': + state.crosshair = true; + break; case 'g': errno = 0; char *endptr; diff --git a/meson.build b/meson.build index 28c8c4c..e8cf263 100644 --- a/meson.build +++ b/meson.build @@ -28,6 +28,7 @@ executable( 'main.c', 'pool-buffer.c', 'render.c', + 'box.c' ]), dependencies: [ cairo, diff --git a/render.c b/render.c index fce1645..a262366 100644 --- a/render.c +++ b/render.c @@ -67,6 +67,18 @@ void render(struct slurp_output *output) { struct slurp_selection *current_selection = slurp_seat_current_selection(seat); + if (!current_selection->has_selection && state->crosshair) { + 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.crosshair); + 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; } diff --git a/slurp.1.scd b/slurp.1.scd index 7f83ed1..7e152f4 100644 --- a/slurp.1.scd +++ b/slurp.1.scd @@ -43,6 +43,9 @@ held, the selection is moved instead of being resized. *-c* _color_ Set border color. See *COLORS* for more detail. +*-X* _color_ + Set crosshair color. See *COLORS* for more detail. + *-s* _color_ Set selection color. See *COLORS* for more detail. @@ -85,6 +88,9 @@ held, the selection is moved instead of being resized. Split the predefined box or display into the given amount of rows and columns. This implicitly sets *-r*. Conflicts with *-o*. +*-x* + Enables the crosshair. + *-a* _width_:_height_ Force selections to have the given aspect ratio. This constraint is not applied to the predefined rectangles specified using *-o*.