Hello community, here is the log from the commit of package slurp for openSUSE:Factory checked in at 2019-06-04 12:14:25 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/slurp (Old) and /work/SRC/openSUSE:Factory/.slurp.new.5148 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "slurp" Tue Jun 4 12:14:25 2019 rev:4 rq:707381 version:1.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/slurp/slurp.changes 2019-02-25 17:58:40.706218280 +0100 +++ /work/SRC/openSUSE:Factory/.slurp.new.5148/slurp.changes 2019-06-04 12:14:29.743779422 +0200 @@ -1,0 +2,10 @@ +Tue Jun 4 06:12:14 UTC 2019 - [email protected] + +- Update to 1.2.0: + * It's now possible to provide a list of predefined + regions to choose from + * A single-pixel selection mode has been added + * Check out the README for some examples: + https://github.com/emersion/slurp#example-usage + +------------------------------------------------------------------- Old: ---- v1.1.0.tar.gz New: ---- v1.2.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ slurp.spec ++++++ --- /var/tmp/diff_new_pack.LrP5BX/_old 2019-06-04 12:14:31.207778942 +0200 +++ /var/tmp/diff_new_pack.LrP5BX/_new 2019-06-04 12:14:31.207778942 +0200 @@ -17,7 +17,7 @@ Name: slurp -Version: 1.1.0 +Version: 1.2.0 Release: 0 Summary: Wayland region selector License: MIT ++++++ v1.1.0.tar.gz -> v1.2.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.1.0/README.md new/slurp-1.2.0/README.md --- old/slurp-1.1.0/README.md 2019-02-23 19:47:52.000000000 +0100 +++ new/slurp-1.2.0/README.md 2019-06-02 12:07:19.000000000 +0200 @@ -21,6 +21,32 @@ build/slurp ``` +## Example usage + +Select a region and print it to stdout: + +```sh +slurp +``` + +Select a single point instead of a region: + +```sh +slurp -p +``` + +Select an output under Sway, using `swaymsg` and `jq`: + +```sh +swaymsg -t get_outputs | jq -r '.[] | select(.active) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | slurp +``` + +Select a window under Sway, using `swaymsg` and `jq`: + +```sh +swaymsg -t get_tree | jq -r '.. | (.nodes? // empty)[] | select(.pid and .visible) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | slurp +``` + ## Contributing Either [send GitHub pull requests][1] or [send patches on the mailing list][2]. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.1.0/include/slurp.h new/slurp-1.2.0/include/slurp.h --- old/slurp-1.1.0/include/slurp.h 2019-02-23 19:47:52.000000000 +0100 +++ new/slurp-1.2.0/include/slurp.h 2019-06-02 12:07:19.000000000 +0200 @@ -12,6 +12,7 @@ struct slurp_box { int32_t x, y; int32_t width, height; + struct wl_list link; }; struct slurp_state { @@ -34,6 +35,8 @@ uint32_t border_weight; bool display_dimensions; + bool single_point; + struct wl_list boxes; // slurp_box::link struct slurp_box result; }; @@ -78,8 +81,9 @@ struct slurp_output *current_output; int32_t x, y; int32_t pressed_x, pressed_y; + struct slurp_box selection; + bool has_selection; }; -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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.1.0/main.c new/slurp-1.2.0/main.c --- old/slurp-1.1.0/main.c 2019-02-23 19:47:52.000000000 +0100 +++ new/slurp-1.2.0/main.c 2019-06-02 12:07:19.000000000 +0200 @@ -18,10 +18,10 @@ 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); + 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, @@ -59,28 +59,67 @@ } 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)) { + if (box_intersect(&output->logical_geometry, &seat->selection)) { set_output_dirty(output); } } } +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 min(int a, int b) { + return (a < b) ? a : b; +} + 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) { + if (seat->has_selection) { seat_set_outputs_dirty(seat); } 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) { + switch (seat->button_state) { + case WL_POINTER_BUTTON_STATE_RELEASED: + seat->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)) { + continue; + } + seat->selection = *box; + seat->has_selection = true; + } + } + break; + case WL_POINTER_BUTTON_STATE_PRESSED: + seat->has_selection = true; + seat->selection.x = min(seat->pressed_x, seat->x); + seat->selection.y = min(seat->pressed_y, seat->y); + seat->selection.width = abs(seat->x - seat->pressed_x); + seat->selection.height = abs(seat->y - seat->pressed_y); + break; + } + + if (seat->has_selection) { seat_set_outputs_dirty(seat); } } @@ -95,11 +134,23 @@ switch (button_state) { case WL_POINTER_BUTTON_STATE_PRESSED: - seat->pressed_x = seat->x; - seat->pressed_y = seat->y; + if (state->single_point) { + state->result.x = seat->x; + state->result.y = seat->y; + state->result.width = state->result.height = 1; + state->running = false; + } else { + seat->pressed_x = seat->x; + seat->pressed_y = seat->y; + } break; case WL_POINTER_BUTTON_STATE_RELEASED: - seat_get_box(seat, &state->result); + if (state->single_point) { + break; + } + if (seat->has_selection) { + state->result = seat->selection; + } state->running = false; break; } @@ -113,23 +164,13 @@ .axis = noop, }; -static int min(int a, int b) { - return (a < b) ? a : b; -} - -void seat_get_box(struct slurp_seat *seat, struct slurp_box *result) { - result->x = min(seat->pressed_x, seat->x); - result->y = min(seat->pressed_y, seat->y); - result->width = abs(seat->x - seat->pressed_x); - result->height = abs(seat->y - seat->pressed_y); -} - static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t key_state) { struct slurp_seat *seat = data; struct slurp_state *state = seat->state; if (key_state == WL_KEYBOARD_KEY_STATE_PRESSED) { if (key == KEY_ESC) { + seat->has_selection = false; state->running = false; } } @@ -299,7 +340,8 @@ // Schedule a frame in case the output becomes dirty again output->frame_callback = wl_surface_frame(output->surface); - wl_callback_add_listener(output->frame_callback, &output_frame_listener, output); + wl_callback_add_listener(output->frame_callback, + &output_frame_listener, output); wl_surface_attach(output->surface, output->current_buffer->buffer, 0, 0); wl_surface_damage(output->surface, 0, 0, output->width, output->height); @@ -331,7 +373,8 @@ } output->frame_callback = wl_surface_frame(output->surface); - wl_callback_add_listener(output->frame_callback, &output_frame_listener, output); + wl_callback_add_listener(output->frame_callback, + &output_frame_listener, output); wl_surface_commit(output->surface); } @@ -394,7 +437,8 @@ 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); + state->xdg_output_manager = wl_registry_bind(registry, name, + &zxdg_output_manager_v1_interface, 1); } } @@ -412,7 +456,8 @@ " -c #rrggbbaa Set border color.\n" " -s #rrggbbaa Set selection color.\n" " -w n Set border weight.\n" - " -f s Set output format.\n"; + " -f s Set output format.\n" + " -p Select a single point.\n"; uint32_t parse_color(const char *color) { if (color[0] == '#') { @@ -432,12 +477,13 @@ return res; } -static void print_formatted_result(const struct slurp_box *result, const char *format) { - for (size_t i = 0; format[i] != 0; i++) { +static void print_formatted_result(const struct slurp_box *result, + const char *format) { + for (size_t i = 0; format[i] != '\0'; i++) { char c = format[i]; if (c == '%') { char next = format[i + 1]; - + i++; // Skip the next character (x, y, w or h) switch (next) { case 'x': @@ -452,14 +498,28 @@ case 'h': printf("%u", result->height); continue; + default: + // If no case was executed, revert i back - we don't need to + // skip the next character. + i--; } - i--; // If no case was executed, revert i back - we don't need to skip the next character. } printf("%c", c); } printf("\n"); } +static void add_choice_box(struct slurp_state *state, + const struct slurp_box *box) { + struct slurp_box *b = calloc(1, sizeof(struct slurp_box)); + if (b == NULL) { + fprintf(stderr, "allocation failed\n"); + return; + } + *b = *box; + wl_list_insert(state->boxes.prev, &b->link); +} + int main(int argc, char *argv[]) { struct slurp_state state = { .colors = { @@ -473,7 +533,7 @@ int opt; char *format = "%x,%y %wx%h"; - while ((opt = getopt(argc, argv, "hdb:c:s:w:f:")) != -1) { + while ((opt = getopt(argc, argv, "hdb:c:s:w:pf:")) != -1) { switch (opt) { case 'h': printf("%s", usage); @@ -502,6 +562,9 @@ exit(EXIT_FAILURE); } break; + case 'p': + state.single_point = true; + break; } default: printf("%s", usage); @@ -509,6 +572,14 @@ } } + wl_list_init(&state.boxes); + if (!isatty(STDIN_FILENO) && !state.single_point) { + struct slurp_box in_box = {0}; + while (fscanf(stdin, "%d,%d %dx%d\n", &in_box.x, &in_box.y, + &in_box.width, &in_box.height) == 4) { + add_choice_box(&state, &in_box); + } + } wl_list_init(&state.outputs); wl_list_init(&state.seats); @@ -520,7 +591,6 @@ state.registry = wl_display_get_registry(state.display); wl_registry_add_listener(state.registry, ®istry_listener, &state); - wl_display_dispatch(state.display); wl_display_roundtrip(state.display); if (state.compositor == NULL) { @@ -536,13 +606,27 @@ return EXIT_FAILURE; } if (state.xdg_output_manager == NULL) { - fprintf(stderr, "compositor doesn't support xdg-output. Guessing geometry from physical output size.\n"); + 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; } + const char *cursor_theme = getenv("XCURSOR_THEME"); + const char *cursor_size_str = getenv("XCURSOR_SIZE"); + int cursor_size = 24; + if (cursor_size_str != NULL) { + char *end; + errno = 0; + cursor_size = strtol(cursor_size_str, &end, 10); + if (errno != 0 || cursor_size_str[0] == '\0' || end[0] != '\0') { + fprintf(stderr, "invalid XCURSOR_SIZE value\n"); + return EXIT_FAILURE; + } + } + struct slurp_output *output; wl_list_for_each(output, &state.outputs, link) { output->surface = wl_compositor_create_surface(state.compositor); @@ -557,7 +641,8 @@ 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); + zxdg_output_v1_add_listener(output->xdg_output, + &xdg_output_listener, output); } else { // guess output->logical_geometry = output->geometry; @@ -574,8 +659,8 @@ zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, -1); wl_surface_commit(output->surface); - output->cursor_theme = - wl_cursor_theme_load(NULL, 24 * output->scale, state.shm); + output->cursor_theme = wl_cursor_theme_load(cursor_theme, + cursor_size * output->scale, state.shm); if (output->cursor_theme == NULL) { fprintf(stderr, "failed to load cursor theme\n"); return EXIT_FAILURE; @@ -620,11 +705,20 @@ wl_display_roundtrip(state.display); zwlr_layer_shell_v1_destroy(state.layer_shell); + if (state.xdg_output_manager != NULL) { + zxdg_output_manager_v1_destroy(state.xdg_output_manager); + } wl_compositor_destroy(state.compositor); wl_shm_destroy(state.shm); wl_registry_destroy(state.registry); wl_display_disconnect(state.display); + struct slurp_box *box, *box_tmp; + wl_list_for_each_safe(box, box_tmp, &state.boxes, link) { + wl_list_remove(&box->link); + free(box); + } + if (state.result.width == 0 && state.result.height == 0) { fprintf(stderr, "selection cancelled\n"); return EXIT_FAILURE; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.1.0/render.c new/slurp-1.2.0/render.c --- old/slurp-1.1.0/render.c 2019-02-23 19:47:52.000000000 +0100 +++ new/slurp-1.2.0/render.c 2019-06-02 12:07:19.000000000 +0200 @@ -28,15 +28,14 @@ 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) { + if (!seat->has_selection) { continue; } - struct slurp_box b; - seat_get_box(seat, &b); - if (!box_intersect(&output->logical_geometry, &b)) { + if(!box_intersect(&output->logical_geometry, &seat->selection)) { continue; } + struct slurp_box b = seat->selection; b.x -= output->logical_geometry.x; b.y -= output->logical_geometry.y; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.1.0/slurp.1.scd new/slurp-1.2.0/slurp.1.scd --- old/slurp-1.1.0/slurp.1.scd 2019-02-23 19:47:52.000000000 +0100 +++ new/slurp-1.2.0/slurp.1.scd 2019-06-02 12:07:19.000000000 +0200 @@ -14,6 +14,10 @@ which support the layer-shell protocol. It lets the user hold the pointer to select, or click to cancel the selection. +If the standard input is not a TTY, slurp will read a list of predefined +rectangles for quick selection. Each line must be in the form +"<x>,<y> <width>x<height>". + # OPTIONS *-h* @@ -37,6 +41,10 @@ *-f* _format_ Set format. See *FORMAT* for more detail. +*-p* + Select a single pixel instead of a rectangle. This mode ignores any + predefined rectangles read from the standard input. + # COLORS Colors may be specified in #RRGGBB or #RRGGBBAA format. The # is optional.
