Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package slurp for openSUSE:Factory checked in at 2026-01-26 11:05:46 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/slurp (Old) and /work/SRC/openSUSE:Factory/.slurp.new.1928 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "slurp" Mon Jan 26 11:05:46 2026 rev:10 rq:1329061 version:1.6.0 Changes: -------- --- /work/SRC/openSUSE:Factory/slurp/slurp.changes 2023-12-15 21:48:08.656047912 +0100 +++ /work/SRC/openSUSE:Factory/.slurp.new.1928/slurp.changes 2026-01-26 11:05:52.362907299 +0100 @@ -1,0 +2,20 @@ +Sun Jan 25 10:22:25 UTC 2026 - Michael Vetter <[email protected]> + +- Update to 1.6.0: + * Make a single click equivalent to point selection + * Add support for crosshairs with the -x option + * Prevent multiple instances of slurp running for the same wayland session at once + * Only use shift to lock aspect ratio when resizing current selection + * Add example how to select windows without border under Sway #150 + * fix handling cursor_shape_manager #151 + * Fix weird :; code style #158 + * slurp.1.scd: add missing documentation for the default values #168 + * Update link to grim in README #172 + * Enable Shift key only while resizing current selection #132 + * feat: Use a lockfile to prevent multiple instances #174 + * Crosshairs #95 + * Add documentation of how to use backslash escapes. #103 + * Fix wl_callback use-after-free in send_frame() #180 + * Makes a single click equivalent to a point selection #129 + +------------------------------------------------------------------- Old: ---- v1.5.0.tar.gz New: ---- v1.6.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ slurp.spec ++++++ --- /var/tmp/diff_new_pack.qBuuHJ/_old 2026-01-26 11:05:52.986933407 +0100 +++ /var/tmp/diff_new_pack.qBuuHJ/_new 2026-01-26 11:05:52.990933575 +0100 @@ -1,7 +1,7 @@ # # spec file for package slurp # -# Copyright (c) 2023 SUSE LLC +# Copyright (c) 2026 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: slurp -Version: 1.5.0 +Version: 1.6.0 Release: 0 Summary: Wayland region selector License: MIT ++++++ v1.5.0.tar.gz -> v1.6.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.5.0/.gitignore new/slurp-1.6.0/.gitignore --- old/slurp-1.5.0/.gitignore 2023-12-14 11:55:54.000000000 +0100 +++ new/slurp-1.6.0/.gitignore 2025-11-27 18:36:47.000000000 +0100 @@ -1,54 +1 @@ -# Prerequisites -*.d - -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf - -/build +/subprojects/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.5.0/README.md new/slurp-1.6.0/README.md --- old/slurp-1.5.0/README.md 2023-12-14 11:55:54.000000000 +0100 +++ new/slurp-1.6.0/README.md 2025-11-27 18:36:47.000000000 +0100 @@ -51,6 +51,11 @@ swaymsg -t get_tree | jq -r '.. | select(.pid? and .visible?) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | slurp ``` +Select a window without border under Sway, using `swaymsg` and `jq`: + +```sh +swaymsg -t get_tree | jq -r '.. | select(.pid? and .visible?) | "\(.rect.x+.window_rect.x),\(.rect.y+.window_rect.y) \(.window_rect.width)x\(.window_rect.height)"' | slurp +``` ## Contributing Either [send GitHub pull requests][GitHub] or [send patches on the mailing list][ML]. @@ -59,7 +64,7 @@ MIT -[grim]: https://sr.ht/~emersion/grim/ +[grim]: https://gitlab.freedesktop.org/emersion/grim [IRC]: https://web.libera.chat/gamja/#emersion [GitHub]: https://github.com/emersion/slurp [ML]: https://lists.sr.ht/%7Eemersion/public-inbox diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.5.0/box.c new/slurp-1.6.0/box.c --- old/slurp-1.5.0/box.c 1970-01-01 01:00:00.000000000 +0100 +++ new/slurp-1.6.0/box.c 2025-11-27 18:36:47.000000000 +0100 @@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.5.0/include/box.h new/slurp-1.6.0/include/box.h --- old/slurp-1.5.0/include/box.h 1970-01-01 01:00:00.000000000 +0100 +++ new/slurp-1.6.0/include/box.h 2025-11-27 18:36:47.000000000 +0100 @@ -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 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.5.0/include/lock.h new/slurp-1.6.0/include/lock.h --- old/slurp-1.5.0/include/lock.h 1970-01-01 01:00:00.000000000 +0100 +++ new/slurp-1.6.0/include/lock.h 2025-11-27 18:36:47.000000000 +0100 @@ -0,0 +1,6 @@ +#ifndef _LOCK_H +#define _LOCK_H + +bool acquire_lock(); + +#endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.5.0/include/slurp.h new/slurp-1.6.0/include/slurp.h --- old/slurp-1.5.0/include/slurp.h 2023-12-14 11:55:54.000000000 +0100 +++ new/slurp-1.6.0/include/slurp.h 2025-11-27 18:36:47.000000000 +0100 @@ -5,121 +5,117 @@ #include <stdint.h> #include <wayland-client.h> -#include "pool-buffer.h" +#include "box.h" #include "cursor-shape-v1-client-protocol.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; - int32_t anchor_x, anchor_y; - struct slurp_box selection; - bool has_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; + bool running; + bool edit_anchor; - struct wl_display *display; - struct wl_registry *registry; - struct wl_shm *shm; - struct wl_compositor *compositor; - struct zwlr_layer_shell_v1 *layer_shell; - struct zxdg_output_manager_v1 *xdg_output_manager; - struct wp_cursor_shape_manager_v1 *cursor_shape_manager; - struct wl_list outputs; // slurp_output::link - struct wl_list seats; // slurp_seat::link - - struct xkb_context *xkb_context; - - struct { - uint32_t background; - uint32_t border; - uint32_t selection; - uint32_t choice; - } colors; - - const char *font_family; - - uint32_t border_weight; - bool display_dimensions; - bool single_point; - bool restrict_selection; - struct wl_list boxes; // slurp_box::link - bool fixed_aspect_ratio; - double aspect_ratio; // h / w + struct wl_display *display; + struct wl_registry *registry; + struct wl_shm *shm; + struct wl_compositor *compositor; + struct zwlr_layer_shell_v1 *layer_shell; + struct zxdg_output_manager_v1 *xdg_output_manager; + struct wp_cursor_shape_manager_v1 *cursor_shape_manager; + struct wl_list outputs; // slurp_output::link + struct wl_list seats; // slurp_seat::link + + struct xkb_context *xkb_context; + + struct { + uint32_t background; + uint32_t border; + uint32_t selection; + uint32_t choice; + } colors; + + const char *font_family; + + uint32_t border_weight; + bool display_dimensions; + bool single_point; + bool restrict_selection; + bool crosshairs; + bool resizing_selection; + struct wl_list boxes; // slurp_box::link + bool fixed_aspect_ratio; + double aspect_ratio; // h / w - struct slurp_box result; + struct slurp_box result; }; struct slurp_output { - struct wl_output *wl_output; - struct slurp_state *state; - struct wl_list link; // slurp_state::outputs - - struct slurp_box geometry; - struct slurp_box logical_geometry; - int32_t scale; - - struct wl_surface *surface; - struct zwlr_layer_surface_v1 *layer_surface; - - struct zxdg_output_v1 *xdg_output; - - struct wl_callback *frame_callback; - bool configured; - bool dirty; - int32_t width, height; - struct pool_buffer buffers[2]; - struct pool_buffer *current_buffer; + struct wl_output *wl_output; + struct slurp_state *state; + struct wl_list link; // slurp_state::outputs + + struct slurp_box geometry; + struct slurp_box logical_geometry; + int32_t scale; + + struct wl_surface *surface; + struct zwlr_layer_surface_v1 *layer_surface; + + struct zxdg_output_v1 *xdg_output; + + struct wl_callback *frame_callback; + bool configured; + bool dirty; + int32_t width, height; + struct pool_buffer buffers[2]; + struct pool_buffer *current_buffer; - struct wl_cursor_theme *cursor_theme; - struct wl_cursor_image *cursor_image; + struct wl_cursor_theme *cursor_theme; + struct wl_cursor_image *cursor_image; }; struct slurp_seat { - struct wl_surface *cursor_surface; - struct slurp_state *state; - struct wl_seat *wl_seat; - struct wl_list link; // slurp_state::seats - - // keyboard: - struct wl_keyboard *wl_keyboard; - - //selection (pointer/touch): - - struct slurp_selection pointer_selection; - struct slurp_selection touch_selection; - - // pointer: - struct wl_pointer *wl_pointer; - enum wl_pointer_button_state button_state; - - // keymap: - struct xkb_keymap *xkb_keymap; - struct xkb_state *xkb_state; - - // touch: - struct wl_touch *wl_touch; - int32_t touch_id; + struct wl_surface *cursor_surface; + struct slurp_state *state; + struct wl_seat *wl_seat; + struct wl_list link; // slurp_state::seats + + // keyboard: + struct wl_keyboard *wl_keyboard; + + // selection (pointer/touch): + + struct slurp_selection pointer_selection; + struct slurp_selection touch_selection; + + // pointer: + struct wl_pointer *wl_pointer; + enum wl_pointer_button_state button_state; + + // keymap: + struct xkb_keymap *xkb_keymap; + struct xkb_state *xkb_state; + + // touch: + struct wl_touch *wl_touch; + int32_t touch_id; }; 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; +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; } #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.5.0/lock.c new/slurp-1.6.0/lock.c --- old/slurp-1.5.0/lock.c 1970-01-01 01:00:00.000000000 +0100 +++ new/slurp-1.6.0/lock.c 2025-11-27 18:36:47.000000000 +0100 @@ -0,0 +1,56 @@ +#include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/file.h> + +#include "lock.h" + +// Maximum path length for the lock file +#define MAX_PATH_SIZE 512 + +/** + * Calculate the path to use for the lock file and store it in + * path. + * + * Return false if no path could be determined. + */ +bool get_lockfile_path(char path[MAX_PATH_SIZE]) { + char *runtime_dir = getenv("XDG_RUNTIME_DIR"); + if (!runtime_dir) { + // Use the /tmp directory if we couldn't get a normal runtime dir + runtime_dir = "/tmp"; + } + char *display = getenv("WAYLAND_DISPLAY"); + if (!display) { + fprintf(stderr, "No wayland session found\n"); + return false; + } + + if (snprintf(path, MAX_PATH_SIZE, "%s/slurp-%s.lock", runtime_dir, display) >= MAX_PATH_SIZE) { + fprintf(stderr, "lockfile path was too long\n"); + return false; + } + + return true; +} + +bool acquire_lock() { + char lockfile[MAX_PATH_SIZE]; + if (!get_lockfile_path(lockfile)) { + return false; + } + // Open the lock file for write, creating with user read/write if necessary + int fd = open(lockfile, O_WRONLY|O_CREAT, 00600); + if (fd == -1) { + fprintf(stderr, "failed to open lock file\n"); + return false; + } + if (flock(fd, LOCK_EX|LOCK_NB)) { + fprintf(stderr, "another slurp process is running for this wayland session\n"); + return false; + } + return true; +} + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.5.0/main.c new/slurp-1.6.0/main.c --- old/slurp-1.5.0/main.c 2023-12-14 11:55:54.000000000 +0100 +++ new/slurp-1.6.0/main.c 2025-11-27 18:36:47.000000000 +0100 @@ -13,6 +13,7 @@ #include "slurp.h" #include "render.h" +#include "lock.h" #define BG_COLOR 0xFFFFFF40 #define BORDER_COLOR 0x000000FF @@ -25,24 +26,6 @@ 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; } @@ -91,12 +74,13 @@ } 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); } } @@ -107,6 +91,8 @@ return; } + seat->state->resizing_selection = true; + int32_t anchor_x = current_selection->anchor_x; int32_t anchor_y = current_selection->anchor_y; int32_t dist_x = current_selection->x - anchor_x; @@ -136,7 +122,7 @@ } // 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); } @@ -149,7 +135,7 @@ case WL_POINTER_BUTTON_STATE_RELEASED: seat_update_selection(seat); break; - case WL_POINTER_BUTTON_STATE_PRESSED:; + case WL_POINTER_BUTTON_STATE_PRESSED: handle_active_selection_motion(seat, &seat->pointer_selection); break; } @@ -185,8 +171,10 @@ 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); } @@ -196,12 +184,12 @@ case WL_POINTER_BUTTON_STATE_RELEASED: seat_update_selection(seat); break; - case WL_POINTER_BUTTON_STATE_PRESSED:; + case WL_POINTER_BUTTON_STATE_PRESSED: handle_active_selection_motion(seat, &seat->pointer_selection); break; } - if (seat->pointer_selection.has_selection) { + if (seat->pointer_selection.has_selection || state->crosshairs) { seat_set_outputs_dirty(seat); } } @@ -234,7 +222,20 @@ } if (current_selection->has_selection) { state->result = current_selection->selection; + } else { + state->result.x = current_selection->x; + state->result.y = current_selection->y; + state->result.width = state->result.height = 1; } + state->resizing_selection = false; + state->running = false; +} + +static void handle_selection_cancelled(struct slurp_seat *seat) { + struct slurp_state *state = seat->state; + seat->pointer_selection.has_selection = false; + seat->touch_selection.has_selection = false; + state->edit_anchor = false; state->running = false; } @@ -247,13 +248,19 @@ } seat->button_state = button_state; - - switch (button_state) { - case WL_POINTER_BUTTON_STATE_PRESSED: - handle_selection_start(seat, &seat->pointer_selection); + switch (button) { + case BTN_LEFT: + switch (button_state) { + case WL_POINTER_BUTTON_STATE_PRESSED: + handle_selection_start(seat, &seat->pointer_selection); + break; + case WL_POINTER_BUTTON_STATE_RELEASED: + handle_selection_end(seat, &seat->pointer_selection); + break; + } break; - case WL_POINTER_BUTTON_STATE_RELEASED: - handle_selection_end(seat, &seat->pointer_selection); + default: //other mouse buttons cancel the selection + handle_selection_cancelled(seat); break; } } @@ -311,10 +318,7 @@ case WL_KEYBOARD_KEY_STATE_PRESSED: switch (keysym) { case XKB_KEY_Escape: - seat->pointer_selection.has_selection = false; - seat->touch_selection.has_selection = false; - state->edit_anchor = false; - state->running = false; + handle_selection_cancelled(seat); break; case XKB_KEY_space: @@ -328,7 +332,9 @@ case XKB_KEY_Shift_R: if (!state->fixed_aspect_ratio) { state->aspect_ratio = 1; - recompute_selection(seat); + if (state->resizing_selection) { + recompute_selection(seat); + } } break; } @@ -339,7 +345,9 @@ state->edit_anchor = false; } else if (!state->fixed_aspect_ratio && (keysym == XKB_KEY_Shift_L || keysym == XKB_KEY_Shift_R)) { state->aspect_ratio = 0; - recompute_selection(seat); + if (state->resizing_selection) { + recompute_selection(seat); + } } break; } @@ -551,7 +559,9 @@ wl_list_remove(&output->link); finish_buffer(&output->buffers[0]); finish_buffer(&output->buffers[1]); - wl_cursor_theme_destroy(output->cursor_theme); + if (output->cursor_theme) { + wl_cursor_theme_destroy(output->cursor_theme); + } zwlr_layer_surface_v1_destroy(output->layer_surface); if (output->xdg_output) { zxdg_output_v1_destroy(output->xdg_output); @@ -586,10 +596,14 @@ 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); // Schedule a frame in case the output becomes dirty again + if (output->frame_callback) { + wl_callback_destroy(output->frame_callback); + } output->frame_callback = wl_surface_frame(output->surface); wl_callback_add_listener(output->frame_callback, &output_frame_listener, output); @@ -690,6 +704,9 @@ } 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, 2); + } else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) { + state->cursor_shape_manager = wl_registry_bind(registry, name, + &wp_cursor_shape_manager_v1_interface, 1); } } @@ -713,7 +730,8 @@ " -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] == '#') { @@ -869,10 +887,6 @@ int main(int argc, char *argv[]) { int status = EXIT_SUCCESS; - char *result_str = 0; - size_t length; - FILE *stream = open_memstream(&result_str, &length); - struct slurp_state state = { .colors = { .background = BG_COLOR, @@ -883,6 +897,7 @@ .border_weight = 2, .display_dimensions = false, .restrict_selection = false, + .resizing_selection = false, .fixed_aspect_ratio = false, .aspect_ratio = 0, .font_family = FONT_FAMILY @@ -892,7 +907,7 @@ 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); @@ -949,6 +964,9 @@ 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; @@ -960,6 +978,11 @@ return EXIT_FAILURE; } + if (!acquire_lock()) { + // acquire_lock prints an appropriate error message itself + return EXIT_FAILURE; + } + wl_list_init(&state.boxes); if (!isatty(STDIN_FILENO) && !state.single_point) { char *line = NULL; @@ -1072,10 +1095,13 @@ // This space intentionally left blank } + char *result_str = 0; + size_t length; if (state.result.width == 0 && state.result.height == 0) { fprintf(stderr, "selection cancelled\n"); status = EXIT_FAILURE; } else { + FILE *stream = open_memstream(&result_str, &length); print_formatted_result(stream, &state, format); fclose(stream); } @@ -1096,6 +1122,9 @@ if (state.xdg_output_manager != NULL) { zxdg_output_manager_v1_destroy(state.xdg_output_manager); } + if (state.cursor_shape_manager != NULL) { + wp_cursor_shape_manager_v1_destroy(state.cursor_shape_manager); + } wl_compositor_destroy(state.compositor); wl_shm_destroy(state.shm); wl_registry_destroy(state.registry); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.5.0/meson.build new/slurp-1.6.0/meson.build --- old/slurp-1.5.0/meson.build 2023-12-14 11:55:54.000000000 +0100 +++ new/slurp-1.6.0/meson.build 2025-11-27 18:36:47.000000000 +0100 @@ -24,8 +24,10 @@ 'slurp', [ 'main.c', + 'lock.c', 'pool-buffer.c', 'render.c', + 'box.c', protos_src, ], dependencies: [ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.5.0/render.c new/slurp-1.6.0/render.c --- old/slurp-1.5.0/render.c 2023-12-14 11:55:54.000000000 +0100 +++ new/slurp-1.6.0/render.c 2025-11-27 18:36:47.000000000 +0100 @@ -19,11 +19,6 @@ 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; @@ -39,9 +34,7 @@ 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); } } @@ -51,6 +44,18 @@ 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; } @@ -59,15 +64,14 @@ ¤t_selection->selection)) { continue; } - struct slurp_box b = current_selection->selection; - box_layout_to_output(&b, output); + struct slurp_box *sel_box = ¤t_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) { @@ -79,9 +83,9 @@ // 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); } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.5.0/slurp.1.scd new/slurp-1.6.0/slurp.1.scd --- old/slurp-1.5.0/slurp.1.scd 2023-12-14 11:55:54.000000000 +0100 +++ new/slurp-1.6.0/slurp.1.scd 2025-11-27 18:36:47.000000000 +0100 @@ -32,17 +32,17 @@ Display dimensions of selection. *-b* _color_ - Set background color. See *COLORS* for more detail. + Set background color. Default is #FFFFFF40. See *COLORS* for more detail. *-c* _color_ - Set border color. See *COLORS* for more detail. + Set border color. Default is #000000FF. See *COLORS* for more detail. *-s* _color_ - Set selection color. See *COLORS* for more detail. + Set selection color. Default is #00000000. See *COLORS* for more detail. *-B* _color_ Set color for highlighting predefined rectangles from standard input when not - selected. + selected. Default is #FFFFFF40. *-F* _font family_ Set the font family name when displaying the dimensions box. Only useful @@ -51,7 +51,7 @@ monospace, cursive and fantasy. It defaults to the sans-serif family name. *-w* _weight_ - Set border weight. + Set border weight. Default is 2. *-f* _format_ Set format. See *FORMAT* for more detail. @@ -73,6 +73,10 @@ 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. @@ -106,7 +110,7 @@ %o The name of the output containing the top left corner, or "<unknown>" if not known -The default format is "%x,%y %wx%h\\n". +The default format is "%x,%y %wx%h" followed by a newline. # KEYBOARD CONTROLS
