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 @@
                        &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) {
@@ -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
 

Reply via email to