Hello community,

here is the log from the commit of package slurp for openSUSE:Factory checked 
in at 2020-10-18 16:31:53
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/slurp (Old)
 and      /work/SRC/openSUSE:Factory/.slurp.new.3486 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "slurp"

Sun Oct 18 16:31:53 2020 rev:5 rq:842187 version:1.3.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/slurp/slurp.changes      2019-06-04 
12:14:29.743779422 +0200
+++ /work/SRC/openSUSE:Factory/.slurp.new.3486/slurp.changes    2020-10-18 
16:33:31.812814190 +0200
@@ -1,0 +2,11 @@
+Fri Oct 16 19:26:29 UTC 2020 - Michael Vetter <mvet...@suse.com>
+
+- Update to 1.3.0:
+  * Touch input is now supported
+  * The current selection can now be moved by holding the Space key
+  * Choice boxes specified on stdin can now be labelled
+  * A new format option prints the name of the output
+  * The new -o option allows to add all outputs as choice boxes
+  * The new -r option forces the user to select one of the choice boxes
+
+-------------------------------------------------------------------

Old:
----
  v1.2.0.tar.gz

New:
----
  v1.3.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ slurp.spec ++++++
--- /var/tmp/diff_new_pack.QskGsR/_old  2020-10-18 16:33:36.980816490 +0200
+++ /var/tmp/diff_new_pack.QskGsR/_new  2020-10-18 16:33:36.984816492 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package slurp
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -12,12 +12,12 @@
 # license that conforms to the Open Source Definition (Version 1.9)
 # published by the Open Source Initiative.
 
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
+# Please submit bugfixes or comments via https://bugs.opensuse.org/
 #
 
 
 Name:           slurp
-Version:        1.2.0
+Version:        1.3.0
 Release:        0
 Summary:        Wayland region selector
 License:        MIT
@@ -30,6 +30,7 @@
 BuildRequires:  pkgconfig(cairo)
 BuildRequires:  pkgconfig(wayland-client)
 BuildRequires:  pkgconfig(wayland-protocols) >= 1.14
+BuildRequires:  pkgconfig(xkbcommon)
 
 %description
 Tool to select a region in a Wayland compositor.

++++++ v1.2.0.tar.gz -> v1.3.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slurp-1.2.0/.build.yml new/slurp-1.3.0/.build.yml
--- old/slurp-1.2.0/.build.yml  2019-06-02 12:07:19.000000000 +0200
+++ new/slurp-1.3.0/.build.yml  2020-10-16 16:55:45.000000000 +0200
@@ -4,6 +4,7 @@
   - wayland
   - wayland-protocols
   - cairo
+  - libxkbcommon
 sources:
   - https://github.com/emerison/slurp
 tasks:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slurp-1.2.0/README.md new/slurp-1.3.0/README.md
--- old/slurp-1.2.0/README.md   2019-06-02 12:07:19.000000000 +0200
+++ new/slurp-1.3.0/README.md   2020-10-16 16:55:45.000000000 +0200
@@ -5,17 +5,20 @@
 
 It currently works on Sway 1.0.
 
+Join the IRC channel: ##emersion on Freenode.
+
 ## Building
 
 Install dependencies:
 * meson
 * wayland
 * cairo
+* libxkbcommon
 * scdoc (optional: man pages)
 
 Then run:
 
-```shell
+```sh
 meson build
 ninja -C build
 build/slurp
@@ -44,7 +47,7 @@
 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
+swaymsg -t get_tree | jq -r '.. | select(.pid? and .visible?) | .rect | 
"\(.x),\(.y) \(.width)x\(.height)"' | slurp
 ```
 
 ## Contributing
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slurp-1.2.0/include/slurp.h 
new/slurp-1.3.0/include/slurp.h
--- old/slurp-1.2.0/include/slurp.h     2019-06-02 12:07:19.000000000 +0200
+++ new/slurp-1.3.0/include/slurp.h     2020-10-16 16:55:45.000000000 +0200
@@ -9,14 +9,26 @@
 #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_state {
        bool running;
+       bool edit_anchor;
 
        struct wl_display *display;
        struct wl_registry *registry;
@@ -27,15 +39,19 @@
        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;
 
        uint32_t border_weight;
        bool display_dimensions;
        bool single_point;
+       bool restrict_selection;
        struct wl_list boxes; // slurp_box::link
 
        struct slurp_box result;
@@ -75,14 +91,22 @@
        // 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;
-       struct slurp_output *current_output;
-       int32_t x, y;
-       int32_t pressed_x, pressed_y;
-       struct slurp_box selection;
-       bool has_selection;
+
+       // 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);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slurp-1.2.0/main.c new/slurp-1.3.0/main.c
--- old/slurp-1.2.0/main.c      2019-06-02 12:07:19.000000000 +0200
+++ new/slurp-1.3.0/main.c      2020-10-16 16:55:45.000000000 +0200
@@ -1,20 +1,26 @@
-#define _POSIX_C_SOURCE 2
+#define _POSIX_C_SOURCE 200809L
+
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/mman.h>
 #include <unistd.h>
 #include <wayland-cursor.h>
+#include <xkbcommon/xkbcommon.h>
 #include <linux/input-event-codes.h>
 
 #include "slurp.h"
 #include "render.h"
 
+#define BG_COLOR 0xFFFFFF40
+#define BORDER_COLOR 0x000000FF
+#define SELECTION_COLOR 0x00000000
+
 static void noop() {
        // This space intentionally left blank
 }
 
-
 static void set_output_dirty(struct slurp_output *output);
 
 bool box_intersect(const struct slurp_box *a, const struct slurp_box *b) {
@@ -24,9 +30,76 @@
                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 min(int a, int b) {
+       return (a < b) ? a : b;
+}
+
+static int max(int a, int b) {
+       return (a > b) ? a : b;
+}
+
 static struct slurp_output *output_from_surface(struct slurp_state *state,
        struct wl_surface *surface);
 
+static void move_seat(struct slurp_seat *seat, wl_fixed_t surface_x,
+               wl_fixed_t surface_y,
+               struct slurp_selection *current_selection) {
+       int x = wl_fixed_to_int(surface_x) +
+               current_selection->current_output->logical_geometry.x;
+       int y = wl_fixed_to_int(surface_y) + 
current_selection->current_output->logical_geometry.y;
+
+       if (seat->state->edit_anchor) {
+               current_selection->anchor_x += x - current_selection->x;
+               current_selection->anchor_y += y - current_selection->y;
+       }
+
+       current_selection->x = x;
+       current_selection->y = y;
+}
+
+static void seat_update_selection(struct slurp_seat *seat) {
+       seat->pointer_selection.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->pointer_selection.x,
+                          seat->pointer_selection.y)) {
+                       if (seat->pointer_selection.has_selection &&
+                               box_size(
+                                       &seat->pointer_selection.selection) <
+                                       box_size(box)) {
+                               continue;
+                       }
+                       seat->pointer_selection.selection = *box;
+                       seat->pointer_selection.has_selection = true;
+               }
+       }
+}
+
+static void seat_set_outputs_dirty(struct slurp_seat *seat) {
+       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)) {
+                       set_output_dirty(output);
+               }
+       }
+}
+
 static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
                uint32_t serial, struct wl_surface *surface,
                wl_fixed_t surface_x, wl_fixed_t surface_y) {
@@ -36,10 +109,11 @@
                return;
        }
        // TODO: handle multiple overlapping outputs
-       seat->current_output = output;
+       seat->pointer_selection.current_output = output;
 
-       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;
+       move_seat(seat, surface_x, surface_y, &seat->pointer_selection);
+       seat_update_selection(seat);
+       seat_set_outputs_dirty(seat);
 
        wl_surface_set_buffer_scale(seat->cursor_surface, output->scale);
        wl_surface_attach(seat->cursor_surface,
@@ -55,103 +129,94 @@
        struct slurp_seat *seat = data;
 
        // TODO: handle multiple overlapping outputs
-       seat->current_output = NULL;
+       seat->pointer_selection.current_output = NULL;
 }
 
-static void seat_set_outputs_dirty(struct slurp_seat *seat) {
-       struct slurp_output *output;
-       wl_list_for_each(output, &seat->state->outputs, link) {
-               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 handle_active_selection_motion(struct slurp_seat *seat, struct 
slurp_selection *current_selection) {
+       int32_t anchor_x = max(0, current_selection->anchor_x);
+       int32_t anchor_y = max(0, current_selection->anchor_y);
+       current_selection->selection.x = min(anchor_x, current_selection->x);
+       current_selection->selection.y = min(anchor_y, current_selection->y);
+       // selection includes the seat and anchor positions
+       current_selection->selection.width =
+               abs(current_selection->x - anchor_x) + 1;
+       current_selection->selection.height =
+               abs(current_selection->y - anchor_y) + 1;
 }
 
 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->has_selection) {
+       if (seat->pointer_selection.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;
+       move_seat(seat, surface_x, surface_y, &seat->pointer_selection);
 
        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;
-                       }
-               }
+               seat_update_selection(seat);
                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);
+       case WL_POINTER_BUTTON_STATE_PRESSED:;
+               handle_active_selection_motion(seat, &seat->pointer_selection);
                break;
        }
 
-       if (seat->has_selection) {
+       if (seat->pointer_selection.has_selection) {
                seat_set_outputs_dirty(seat);
        }
 }
 
+static void handle_selection_start(struct slurp_seat *seat,
+                                  struct slurp_selection *current_selection) {
+       struct slurp_state *state = seat->state;
+
+       if (state->single_point) {
+               state->result.x = current_selection->x;
+               state->result.y = current_selection->y;
+               state->result.width = state->result.height = 1;
+               state->running = false;
+       } else if (state->restrict_selection) {
+               if (current_selection->has_selection) {
+                       state->result = current_selection->selection;
+                       state->running = false;
+               }
+       } else {
+               current_selection->has_selection = true;
+               current_selection->anchor_x = current_selection->x;
+               current_selection->anchor_y = current_selection->y;
+       }
+}
+
+static void handle_selection_end(struct slurp_seat *seat,
+                                struct slurp_selection *current_selection) {
+       struct slurp_state *state = seat->state;
+       if (state->single_point || state->restrict_selection) {
+               return;
+       }
+       if (current_selection->has_selection) {
+               state->result = current_selection->selection;
+       }
+       state->running = false;
+}
+
 static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
                uint32_t serial, uint32_t time, uint32_t button,
                uint32_t button_state) {
        struct slurp_seat *seat = data;
-       struct slurp_state *state = seat->state;
+       if (seat->touch_selection.has_selection) {
+               return;
+       }
 
        seat->button_state = button_state;
 
        switch (button_state) {
        case WL_POINTER_BUTTON_STATE_PRESSED:
-               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;
-               }
+               handle_selection_start(seat, &seat->pointer_selection);
                break;
        case WL_POINTER_BUTTON_STATE_RELEASED:
-               if (state->single_point) {
-                       break;
-               }
-               if (seat->has_selection) {
-                       state->result = seat->selection;
-               }
-               state->running = false;
+               handle_selection_end(seat, &seat->pointer_selection);
                break;
        }
 }
@@ -164,26 +229,138 @@
        .axis = noop,
 };
 
+static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard,
+               const uint32_t format, const int32_t fd, const uint32_t size) {
+       struct slurp_seat *seat = data;
+       switch (format) {
+       case WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP:
+               seat->xkb_keymap = 
xkb_keymap_new_from_names(seat->state->xkb_context, NULL, 
XKB_KEYMAP_COMPILE_NO_FLAGS);
+               break;
+       case WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1:;
+               void *buffer;
+               if ((buffer = mmap(NULL, size - 1, PROT_READ, MAP_PRIVATE, fd, 
0)) == MAP_FAILED) {
+                       fprintf(stderr, "mmap failed\n");
+                       exit(EXIT_FAILURE);
+               }
+               seat->xkb_keymap =
+                       xkb_keymap_new_from_buffer(seat->state->xkb_context,
+                                       buffer, size - 1,
+                                       XKB_KEYMAP_FORMAT_TEXT_V1,
+                                       XKB_KEYMAP_COMPILE_NO_FLAGS);
+               munmap(buffer, size - 1);
+               close(fd);
+               break;
+       }
+       seat->xkb_state = xkb_state_new(seat->xkb_keymap);
+}
+
 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) {
+               const uint32_t serial, const uint32_t time, const uint32_t key,
+               const 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;
+       const xkb_keysym_t keysym = xkb_state_key_get_one_sym(seat->xkb_state, 
key + 8);
+
+       switch (key_state) {
+       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;
+                       break;
+
+               case XKB_KEY_space:
+                       if (!seat->pointer_selection.has_selection &&
+                                       !seat->touch_selection.has_selection) {
+                               break;
+                       }
+                       state->edit_anchor = true;
+                       break;
                }
+               break;
+
+       case WL_KEYBOARD_KEY_STATE_RELEASED:
+               if (keysym == XKB_KEY_space) {
+                       state->edit_anchor = false;
+               }
+               break;
        }
+
+}
+
+static void keyboard_handle_modifiers(void *data, struct wl_keyboard 
*wl_keyboard,
+               const uint32_t serial, const uint32_t mods_depressed,
+               const uint32_t mods_latched, const uint32_t mods_locked,
+               const uint32_t group) {
+       struct slurp_seat *seat = data;
+       xkb_state_update_mask(seat->xkb_state, mods_depressed, mods_latched,
+                       mods_locked, 0, 0, group);
 }
 
 static const struct wl_keyboard_listener keyboard_listener = {
-       .keymap = noop,
+       .keymap = keyboard_handle_keymap,
        .enter = noop,
        .leave = noop,
        .key = keyboard_handle_key,
-       .modifiers = noop,
+       .modifiers = keyboard_handle_modifiers,
 };
 
+static void touch_handle_down(void *data, struct wl_touch *touch,
+               uint32_t serial, uint32_t time,
+               struct wl_surface *surface, int32_t id,
+               wl_fixed_t x, wl_fixed_t y) {
+       struct slurp_seat *seat = data;
+       if (seat->pointer_selection.has_selection) {
+               return;
+       }
+       if (seat->touch_id == TOUCH_ID_EMPTY) {
+               seat->touch_id = id;
+               seat->touch_selection.current_output =
+                       output_from_surface(seat->state, surface);
+               move_seat(seat, x, y, &seat->touch_selection);
+               handle_selection_start(seat, &seat->touch_selection);
+       }
+}
+
+static void touch_clear_state(struct slurp_seat *seat) {
+       seat->touch_id = TOUCH_ID_EMPTY;
+       seat->touch_selection.current_output = NULL;
+}
+
+static void touch_handle_up(void *data, struct wl_touch *touch, uint32_t 
serial,
+               uint32_t time, int32_t id) {
+       struct slurp_seat *seat = data;
+       handle_selection_end(seat, &seat->touch_selection);
+       touch_clear_state(seat);
+}
+
+static void touch_handle_motion(void *data, struct wl_touch *touch,
+               uint32_t time, int32_t id, wl_fixed_t x,
+               wl_fixed_t y) {
+       struct slurp_seat *seat = data;
+       if (seat->touch_id == id) {
+               move_seat(seat, x, y, &seat->touch_selection);
+               handle_active_selection_motion(seat, &seat->touch_selection);
+               seat_set_outputs_dirty(seat);
+       }
+}
+
+static void touch_handle_cancel(void *data, struct wl_touch *touch) {
+       struct slurp_seat *seat = data;
+       touch_clear_state(seat);
+}
+
+static const struct wl_touch_listener touch_listener = {
+       .down = touch_handle_down,
+       .up = touch_handle_up,
+       .frame = noop,
+       .motion = touch_handle_motion,
+       .orientation = noop,
+       .shape = noop,
+       .cancel = touch_handle_cancel,
+};
 
 static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
                uint32_t capabilities) {
@@ -197,6 +374,10 @@
                seat->wl_keyboard = wl_seat_get_keyboard(wl_seat);
                wl_keyboard_add_listener(seat->wl_keyboard, &keyboard_listener, 
seat);
        }
+       if (capabilities & WL_SEAT_CAPABILITY_TOUCH) {
+               seat->wl_touch = wl_seat_get_touch(wl_seat);
+               wl_touch_add_listener(seat->wl_touch, &touch_listener, seat);
+       }
 }
 
 static const struct wl_seat_listener seat_listener = {
@@ -211,6 +392,7 @@
        }
        seat->state = state;
        seat->wl_seat = wl_seat;
+       seat->touch_id = TOUCH_ID_EMPTY;
        wl_list_insert(&state->seats, &seat->link);
        wl_seat_add_listener(wl_seat, &seat_listener, seat);
 }
@@ -224,6 +406,8 @@
        if (seat->wl_keyboard) {
                wl_keyboard_destroy(seat->wl_keyboard);
        }
+       xkb_state_unref(seat->xkb_state);
+       xkb_keymap_unref(seat->xkb_keymap);
        wl_seat_destroy(seat->wl_seat);
        free(seat);
 }
@@ -268,6 +452,7 @@
        output->logical_geometry.x = x;
        output->logical_geometry.y = y;
 }
+
 static void xdg_output_handle_logical_size(void *data,
                struct zxdg_output_v1 *xdg_output, int32_t width, int32_t 
height) {
        struct slurp_output *output = data;
@@ -275,11 +460,16 @@
        output->logical_geometry.height = height;
 }
 
+static void xdg_output_handle_name(void *data, struct zxdg_output_v1 
*xdg_output, const char *name) {
+       struct slurp_output *output = data;
+       output->logical_geometry.label = strdup(name);
+}
+
 static const struct zxdg_output_v1_listener xdg_output_listener = {
        .logical_position = xdg_output_handle_logical_position,
        .logical_size = xdg_output_handle_logical_size,
        .done = noop,
-       .name = noop,
+       .name = xdg_output_handle_name,
        .description = noop,
 };
 
@@ -315,6 +505,7 @@
                wl_callback_destroy(output->frame_callback);
        }
        wl_output_destroy(output->wl_output);
+       free(output->logical_geometry.label);
        free(output);
 }
 
@@ -438,7 +629,7 @@
                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);
+                       &zxdg_output_manager_v1_interface, 2);
        }
 }
 
@@ -455,9 +646,12 @@
        "  -b #rrggbbaa Set background color.\n"
        "  -c #rrggbbaa Set border color.\n"
        "  -s #rrggbbaa Set selection color.\n"
+       "  -B #rrggbbaa Set option box color.\n"
        "  -w n         Set border weight.\n"
        "  -f s         Set output format.\n"
-       "  -p           Select a single point.\n";
+       "  -o           Select a display output.\n"
+       "  -p           Select a single point.\n"
+       "  -r           Restrict selection to predefined boxes.\n";
 
 uint32_t parse_color(const char *color) {
        if (color[0] == '#') {
@@ -477,7 +671,23 @@
        return res;
 }
 
-static void print_formatted_result(const struct slurp_box *result,
+static void print_output_name(const struct slurp_box *result, struct wl_list 
*outputs) {
+       struct slurp_output *output;
+       wl_list_for_each(output, outputs, link) {
+               // For now just use the top-left corner
+               struct slurp_box *geometry = &output->logical_geometry;
+               if (in_box(geometry, result->x, result->y)) {
+                       if (geometry->label) {
+                               printf("%s", geometry->label);
+                               return;
+                       }
+                       break;
+               }
+       }
+       printf("<unknown>");
+}
+
+static void print_formatted_result(const struct slurp_box *result, struct 
wl_list *outputs,
                const char *format) {
        for (size_t i = 0; format[i] != '\0'; i++) {
                char c = format[i];
@@ -487,16 +697,24 @@
                        i++; // Skip the next character (x, y, w or h)
                        switch (next) {
                        case 'x':
-                               printf("%u", result->x);
+                               printf("%d", result->x);
                                continue;
                        case 'y':
-                               printf("%u", result->y);
+                               printf("%d", result->y);
                                continue;
                        case 'w':
-                               printf("%u", result->width);
+                               printf("%d", result->width);
                                continue;
                        case 'h':
-                               printf("%u", result->height);
+                               printf("%d", result->height);
+                               continue;
+                       case 'l':
+                               if (result->label) {
+                                       printf("%s", result->label);
+                               }
+                               continue;
+                       case 'o':
+                               print_output_name(result, outputs);
                                continue;
                        default:
                                // If no case was executed, revert i back - we 
don't need to
@@ -506,7 +724,7 @@
                }
                printf("%c", c);
        }
-       printf("\n");
+    fflush(stdout);
 }
 
 static void add_choice_box(struct slurp_state *state,
@@ -517,23 +735,32 @@
                return;
        }
        *b = *box;
+       // copy label, so that this has ownership of its label
+       if (box->label) {
+               b->label = strdup(box->label);
+       }
        wl_list_insert(state->boxes.prev, &b->link);
 }
 
 int main(int argc, char *argv[]) {
+       int status = EXIT_SUCCESS;
+
        struct slurp_state state = {
                .colors = {
-                       .background = 0xFFFFFF40,
-                       .border = 0x000000FF,
-                       .selection = 0x00000000,
+                       .background = BG_COLOR,
+                       .border = BORDER_COLOR,
+                       .selection = SELECTION_COLOR,
+                       .choice = BG_COLOR,
                },
                .border_weight = 2,
                .display_dimensions = false,
+               .restrict_selection = false,
        };
 
        int opt;
-       char *format = "%x,%y %wx%h";
-       while ((opt = getopt(argc, argv, "hdb:c:s:w:pf:")) != -1) {
+       char *format = "%x,%y %wx%h\n";
+       bool output_boxes = false;
+       while ((opt = getopt(argc, argv, "hdb:c:s:B:w:prof:")) != -1) {
                switch (opt) {
                case 'h':
                        printf("%s", usage);
@@ -550,6 +777,9 @@
                case 's':
                        state.colors.selection = parse_color(optarg);
                        break;
+               case 'B':
+                       state.colors.choice = parse_color(optarg);
+                       break;
                case 'f':
                        format = optarg;
                        break;
@@ -562,23 +792,42 @@
                                exit(EXIT_FAILURE);
                        }
                        break;
+               }
                case 'p':
                        state.single_point = true;
                        break;
-               }
+               case 'o':
+                       output_boxes = true;
+                       break;
+               case 'r':
+                       state.restrict_selection = true;
+                       break;
                default:
                        printf("%s", usage);
                        return EXIT_FAILURE;
                }
        }
 
+       if (state.single_point && state.restrict_selection) {
+               fprintf(stderr, "-p and -r cannot be used together\n");
+               return EXIT_FAILURE;
+       }
+
        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) {
+               char *line = NULL;
+               size_t line_size = 0;
+               while (getline(&line, &line_size, stdin) >= 0) {
+                       struct slurp_box in_box = {0};
+                       if (sscanf(line, "%d,%d %dx%d %m[^\n]", &in_box.x, 
&in_box.y,
+                                       &in_box.width, &in_box.height, 
&in_box.label) < 4) {
+                               fprintf(stderr, "invalid box format: %s\n", 
line);
+                               return EXIT_FAILURE;
+                       }
                        add_choice_box(&state, &in_box);
+                       free(in_box.label);
                }
+               free(line);
        }
        wl_list_init(&state.outputs);
        wl_list_init(&state.seats);
@@ -589,6 +838,11 @@
                return EXIT_FAILURE;
        }
 
+       if ((state.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS)) == 
NULL) {
+               fprintf(stderr, "xkb_context_new failed\n");
+               return EXIT_FAILURE;
+       }
+
        state.registry = wl_display_get_registry(state.display);
        wl_registry_add_listener(state.registry, &registry_listener, &state);
        wl_display_roundtrip(state.display);
@@ -681,6 +935,13 @@
        // second roundtrip for xdg-output
        wl_display_roundtrip(state.display);
 
+       if (output_boxes) {
+               struct slurp_output *box_output;
+               wl_list_for_each(box_output, &state.outputs, link) {
+                       add_choice_box(&state, &box_output->logical_geometry);
+               }
+       }
+
        struct slurp_seat *seat;
        wl_list_for_each(seat, &state.seats, link) {
                seat->cursor_surface =
@@ -692,6 +953,14 @@
                // This space intentionally left blank
        }
 
+
+       if (state.result.width == 0 && state.result.height == 0) {
+               fprintf(stderr, "selection cancelled\n");
+               status = EXIT_FAILURE;
+       } else {
+               print_formatted_result(&state.result, &state.outputs, format);
+       }
+
        struct slurp_output *output_tmp;
        wl_list_for_each_safe(output, output_tmp, &state.outputs, link) {
                destroy_output(output);
@@ -711,19 +980,15 @@
        wl_compositor_destroy(state.compositor);
        wl_shm_destroy(state.shm);
        wl_registry_destroy(state.registry);
+       xkb_context_unref(state.xkb_context);
        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->label);
                free(box);
        }
 
-       if (state.result.width == 0 && state.result.height == 0) {
-               fprintf(stderr, "selection cancelled\n");
-               return EXIT_FAILURE;
-       }
-
-       print_formatted_result(&state.result, format);
-       return EXIT_SUCCESS;
+       return status;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slurp-1.2.0/meson.build new/slurp-1.3.0/meson.build
--- old/slurp-1.2.0/meson.build 2019-06-02 12:07:19.000000000 +0200
+++ new/slurp-1.3.0/meson.build 2020-10-16 16:55:45.000000000 +0200
@@ -1,7 +1,7 @@
 project(
        'slurp',
        'c',
-       version: '1.1.0',
+       version: '1.3.0',
        license: 'MIT',
        meson_version: '>=0.48.0',
        default_options: [
@@ -22,6 +22,7 @@
 wayland_client = dependency('wayland-client')
 wayland_cursor = dependency('wayland-cursor')
 wayland_protos = dependency('wayland-protocols', version: '>=1.14')
+xkbcommon = dependency('xkbcommon')
 
 subdir('protocol')
 
@@ -38,6 +39,7 @@
                realtime,
                wayland_client,
                wayland_cursor,
+               xkbcommon,
        ],
        include_directories: [slurp_inc],
        install: true,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slurp-1.2.0/render.c new/slurp-1.3.0/render.c
--- old/slurp-1.2.0/render.c    2019-06-02 12:07:19.000000000 +0200
+++ new/slurp-1.3.0/render.c    2020-10-16 16:55:45.000000000 +0200
@@ -7,11 +7,21 @@
 #include "slurp.h"
 
 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,
-               (color >> (1*8) & 0xFF) / 255.0,
-               (color >> (0*8) & 0xFF) / 255.0);
+       cairo_set_source_rgba(cairo, (color >> (3 * 8) & 0xFF) / 255.0,
+               (color >> (2 * 8) & 0xFF) / 255.0,
+               (color >> (1 * 8) & 0xFF) / 255.0,
+               (color >> (0 * 8) & 0xFF) / 255.0);
+}
+
+static void draw_rect(cairo_t *cairo, struct slurp_box *box, uint32_t color, 
int32_t scale) {
+       set_source_u32(cairo, color);
+       cairo_rectangle(cairo, box->x * scale, box->y * scale,
+                       box->width * scale, box->height * scale);
+}
+
+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) {
@@ -25,40 +35,55 @@
        set_source_u32(cairo, state->colors.background);
        cairo_paint(cairo);
 
+       // Draw option boxes from input
+       struct slurp_box *choice_box;
+       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, scale);
+                       cairo_fill(cairo);
+               }
+       }
+
        struct slurp_seat *seat;
        wl_list_for_each(seat, &state->seats, link) {
-               if (!seat->wl_pointer) continue;
-               if (!seat->has_selection) {
+               struct slurp_selection *current_selection =
+                       seat->touch_selection.has_selection ?
+                               &seat->touch_selection :
+                               &seat->pointer_selection;
+
+               if (!current_selection->has_selection) {
                        continue;
                }
 
-               if(!box_intersect(&output->logical_geometry, &seat->selection)) 
{
+               if (!box_intersect(&output->logical_geometry,
+                       &current_selection->selection)) {
                        continue;
                }
-               struct slurp_box b = seat->selection;
-               b.x -= output->logical_geometry.x;
-               b.y -= output->logical_geometry.y;
+               struct slurp_box b = current_selection->selection;
+               box_layout_to_output(&b, output);
 
-               // Draw border
-               set_source_u32(cairo, state->colors.selection);
-               cairo_rectangle(cairo, b.x * scale, b.y * scale,
-                       b.width * scale, b.height * scale);
+               draw_rect(cairo, &b, state->colors.selection, scale);
                cairo_fill(cairo);
 
-               set_source_u32(cairo, state->colors.border);
+               // Draw border
                cairo_set_line_width(cairo, state->border_weight * scale);
-               cairo_rectangle(cairo, b.x * scale, b.y * scale,
-                       b.width * scale, b.height * scale);
+               draw_rect(cairo, &b, state->colors.border, scale);
                cairo_stroke(cairo);
 
                if (state->display_dimensions) {
-                       cairo_select_font_face(cairo, "Sans", 
CAIRO_FONT_SLANT_NORMAL,
-                               CAIRO_FONT_WEIGHT_NORMAL);
+                       cairo_select_font_face(cairo, "Sans",
+                                              CAIRO_FONT_SLANT_NORMAL,
+                                              CAIRO_FONT_WEIGHT_NORMAL);
                        cairo_set_font_size(cairo, 14 * scale);
                        // 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) * scale, (b.y 
+ b.height + 20) * scale);
+                       snprintf(dimensions, sizeof(dimensions), "%ix%i",
+                                b.width, b.height);
+                       cairo_move_to(cairo, (b.x + b.width + 10) * scale,
+                                     (b.y + b.height + 20) * scale);
                        cairo_show_text(cairo, dimensions);
                }
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/slurp-1.2.0/slurp.1.scd new/slurp-1.3.0/slurp.1.scd
--- old/slurp-1.2.0/slurp.1.scd 2019-06-02 12:07:19.000000000 +0200
+++ new/slurp-1.3.0/slurp.1.scd 2020-10-16 16:55:45.000000000 +0200
@@ -14,9 +14,14 @@
 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>".
+If the standard input is not a TTY or the -r option is used, slurp will read a
+list of predefined rectangles for quick selection. Each line must be in the 
form
+"<x>,<y> <width>x<height> [label]". The label is optional and can be any string
+that doesn't contain newlines. It can be accessed using the "%l" sequence in a
+format string.
+
+If the _Esc_ key is pressed, selection is cancelled. If the _Space_ key is
+held, the selection is moved instead of being resized.
 
 # OPTIONS
 
@@ -35,6 +40,10 @@
 *-s* _color_
        Set selection color. See *COLORS* for more detail.
 
+*-B* _color_
+       Set color for highlighting predefined rectangles from standard input 
when not
+       selected.
+
 *-w* _weight_
        Set border weight.
 
@@ -45,6 +54,15 @@
        Select a single pixel instead of a rectangle. This mode ignores any
        predefined rectangles read from the standard input.
 
+*-o*
+       Add predefined rectangles for all outputs, as if provided on standard 
input.
+       The label will be the name of the output.
+
+*-r*
+       Require the user to select one of the predefined rectangles. These can 
come
+       from standard input, if *-o* is used, the rectangles of all display 
outputs.
+       This option conflicts with *-p*.
+
 # COLORS
 
 Colors may be specified in #RRGGBB or #RRGGBBAA format. The # is optional.
@@ -61,7 +79,12 @@
 
 %h     The height of the selection
 
-The default format is "%x,%y %wx%h".
+%l     Label included with region from stdin
+
+%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".
 
 # AUTHORS
 


Reply via email to