Hello community, here is the log from the commit of package slurp for openSUSE:Factory checked in at 2019-02-25 17:58:30 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/slurp (Old) and /work/SRC/openSUSE:Factory/.slurp.new.28833 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "slurp" Mon Feb 25 17:58:30 2019 rev:3 rq:678842 version:1.1.0 Changes: -------- --- /work/SRC/openSUSE:Factory/slurp/slurp.changes 2019-02-14 14:33:52.703638429 +0100 +++ /work/SRC/openSUSE:Factory/.slurp.new.28833/slurp.changes 2019-02-25 17:58:40.706218280 +0100 @@ -1,0 +2,10 @@ +Mon Feb 25 09:06:57 UTC 2019 - [email protected] + +- Update to 1.1.0: + * Add man-pages option like swaywm/sway@ba16f16e4d5a + * Display alpha in usage + * Add user-defined output formatting (#33) + * Abort on escape (#25) + * Support selection across multiple outputs (#27) + +------------------------------------------------------------------- Old: ---- v1.0.1.tar.gz New: ---- v1.1.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ slurp.spec ++++++ --- /var/tmp/diff_new_pack.P0IhaH/_old 2019-02-25 17:58:43.386215661 +0100 +++ /var/tmp/diff_new_pack.P0IhaH/_new 2019-02-25 17:58:43.390215656 +0100 @@ -17,7 +17,7 @@ Name: slurp -Version: 1.0.1 +Version: 1.1.0 Release: 0 Summary: Wayland region selector License: MIT ++++++ v1.0.1.tar.gz -> v1.1.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.0.1/include/slurp.h new/slurp-1.1.0/include/slurp.h --- old/slurp-1.0.1/include/slurp.h 2019-02-12 21:24:23.000000000 +0100 +++ new/slurp-1.1.0/include/slurp.h 2019-02-23 19:47:52.000000000 +0100 @@ -7,6 +7,7 @@ #include "pool-buffer.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h" +#include "xdg-output-unstable-v1-client-protocol.h" struct slurp_box { int32_t x, y; @@ -21,8 +22,8 @@ struct wl_shm *shm; struct wl_compositor *compositor; struct zwlr_layer_shell_v1 *layer_shell; + struct zxdg_output_manager_v1 *xdg_output_manager; struct wl_list outputs; // slurp_output::link - struct wl_list pointers; // slurp_pointer::link struct wl_list seats; // slurp_seat::link struct { @@ -43,11 +44,14 @@ 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; @@ -59,25 +63,23 @@ struct wl_cursor_image *cursor_image; }; -struct slurp_pointer { +struct slurp_seat { + struct wl_surface *cursor_surface; struct slurp_state *state; - struct wl_pointer *wl_pointer; - struct wl_list link; // slurp_state::pointers + struct wl_seat *wl_seat; + struct wl_list link; // slurp_state::seats - int32_t x, y; - int32_t pressed_x, pressed_y; + // keyboard: + struct wl_keyboard *wl_keyboard; + + // pointer: + struct wl_pointer *wl_pointer; enum wl_pointer_button_state button_state; struct slurp_output *current_output; - - struct wl_surface *cursor_surface; -}; - -struct slurp_seat { - struct wl_seat *wl_seat; - struct wl_list link; // slurp_state::seats + int32_t x, y; + int32_t pressed_x, pressed_y; }; -void pointer_get_box(struct slurp_pointer *pointer, int *x, int *y, - int *width, int *height); - +void seat_get_box(struct slurp_seat *seat, struct slurp_box *result); +bool box_intersect(const struct slurp_box *a, const struct slurp_box *b); #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.0.1/main.c new/slurp-1.1.0/main.c --- old/slurp-1.0.1/main.c 2019-02-12 21:24:23.000000000 +0100 +++ new/slurp-1.1.0/main.c 2019-02-23 19:47:52.000000000 +0100 @@ -17,74 +17,89 @@ 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 struct slurp_output *output_from_surface(struct slurp_state *state, struct wl_surface *surface); 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) { - struct slurp_pointer *pointer = data; - struct slurp_output *output = output_from_surface(pointer->state, surface); + struct slurp_seat *seat = data; + struct slurp_output *output = output_from_surface(seat->state, surface); if (output == NULL) { return; } - - pointer->x = wl_fixed_to_int(surface_x); - pointer->y = wl_fixed_to_int(surface_y); - // TODO: handle multiple overlapping outputs - pointer->current_output = output; + seat->current_output = output; - wl_surface_set_buffer_scale(pointer->cursor_surface, output->scale); - wl_surface_attach(pointer->cursor_surface, + 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; + + wl_surface_set_buffer_scale(seat->cursor_surface, output->scale); + wl_surface_attach(seat->cursor_surface, wl_cursor_image_get_buffer(output->cursor_image), 0, 0); - wl_pointer_set_cursor(wl_pointer, serial, pointer->cursor_surface, + wl_pointer_set_cursor(wl_pointer, serial, seat->cursor_surface, output->cursor_image->hotspot_x / output->scale, output->cursor_image->hotspot_y / output->scale); - wl_surface_commit(pointer->cursor_surface); + wl_surface_commit(seat->cursor_surface); } static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface) { - struct slurp_pointer *pointer = data; + struct slurp_seat *seat = data; // TODO: handle multiple overlapping outputs - pointer->current_output = NULL; + seat->current_output = NULL; +} + +static void seat_set_outputs_dirty(struct slurp_seat *seat) { + struct slurp_box box; + seat_get_box(seat, &box); + struct slurp_output *output; + wl_list_for_each(output, &seat->state->outputs, link) { + if (box_intersect(&output->logical_geometry, &box)) { + set_output_dirty(output); + } + } } 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_pointer *pointer = data; + struct slurp_seat *seat = data; + // the places the cursor moved away from are also dirty + if (seat->button_state == WL_POINTER_BUTTON_STATE_PRESSED) { + seat_set_outputs_dirty(seat); + } - pointer->x = wl_fixed_to_int(surface_x); - pointer->y = wl_fixed_to_int(surface_y); + seat->x = wl_fixed_to_int(surface_x) + seat->current_output->logical_geometry.x; + seat->y = wl_fixed_to_int(surface_y) + seat->current_output->logical_geometry.y; - if (pointer->button_state == WL_POINTER_BUTTON_STATE_PRESSED && - pointer->current_output != NULL) { - set_output_dirty(pointer->current_output); + if (seat->button_state == WL_POINTER_BUTTON_STATE_PRESSED) { + seat_set_outputs_dirty(seat); } } 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_pointer *pointer = data; - struct slurp_state *state = pointer->state; + struct slurp_seat *seat = data; + struct slurp_state *state = seat->state; - pointer->button_state = button_state; + seat->button_state = button_state; switch (button_state) { case WL_POINTER_BUTTON_STATE_PRESSED: - pointer->pressed_x = pointer->x; - pointer->pressed_y = pointer->y; + seat->pressed_x = seat->x; + seat->pressed_y = seat->y; break; case WL_POINTER_BUTTON_STATE_RELEASED: - pointer_get_box(pointer, &state->result.x, &state->result.y, - &state->result.width, &state->result.height); - if (pointer->current_output != NULL) { - state->result.x += pointer->current_output->geometry.x; - state->result.y += pointer->current_output->geometry.y; - } + seat_get_box(seat, &state->result); state->running = false; break; } @@ -98,47 +113,48 @@ .axis = noop, }; -static void create_pointer(struct slurp_state *state, - struct wl_pointer *wl_pointer) { - struct slurp_pointer *pointer = calloc(1, sizeof(struct slurp_pointer)); - if (pointer == NULL) { - fprintf(stderr, "allocation failed\n"); - return; - } - pointer->state = state; - pointer->wl_pointer = wl_pointer; - wl_list_insert(&state->pointers, &pointer->link); - - wl_pointer_add_listener(wl_pointer, &pointer_listener, pointer); +static int min(int a, int b) { + return (a < b) ? a : b; } -static void destroy_pointer(struct slurp_pointer *pointer) { - wl_list_remove(&pointer->link); - wl_surface_destroy(pointer->cursor_surface); - wl_pointer_destroy(pointer->wl_pointer); - free(pointer); +void seat_get_box(struct slurp_seat *seat, struct slurp_box *result) { + result->x = min(seat->pressed_x, seat->x); + result->y = min(seat->pressed_y, seat->y); + result->width = abs(seat->x - seat->pressed_x); + result->height = abs(seat->y - seat->pressed_y); } -static int min(int a, int b) { - return (a < b) ? a : b; +static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, + uint32_t serial, uint32_t time, uint32_t key, uint32_t key_state) { + struct slurp_seat *seat = data; + struct slurp_state *state = seat->state; + if (key_state == WL_KEYBOARD_KEY_STATE_PRESSED) { + if (key == KEY_ESC) { + state->running = false; + } + } } -void pointer_get_box(struct slurp_pointer *pointer, int *x, int *y, - int *width, int *height) { - *x = min(pointer->pressed_x, pointer->x); - *y = min(pointer->pressed_y, pointer->y); - *width = abs(pointer->x - pointer->pressed_x); - *height = abs(pointer->y - pointer->pressed_y); -} +static const struct wl_keyboard_listener keyboard_listener = { + .keymap = noop, + .enter = noop, + .leave = noop, + .key = keyboard_handle_key, + .modifiers = noop, +}; -static void seat_handle_capabilities(void *data, struct wl_seat *seat, +static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities) { - struct slurp_state *state = data; + struct slurp_seat *seat = data; if (capabilities & WL_SEAT_CAPABILITY_POINTER) { - struct wl_pointer *wl_pointer = wl_seat_get_pointer(seat); - create_pointer(state, wl_pointer); + seat->wl_pointer = wl_seat_get_pointer(wl_seat); + wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, seat); + } + if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { + seat->wl_keyboard = wl_seat_get_keyboard(wl_seat); + wl_keyboard_add_listener(seat->wl_keyboard, &keyboard_listener, seat); } } @@ -152,13 +168,21 @@ fprintf(stderr, "allocation failed\n"); return; } + seat->state = state; seat->wl_seat = wl_seat; wl_list_insert(&state->seats, &seat->link); - wl_seat_add_listener(wl_seat, &seat_listener, state); + wl_seat_add_listener(wl_seat, &seat_listener, seat); } static void destroy_seat(struct slurp_seat *seat) { wl_list_remove(&seat->link); + wl_surface_destroy(seat->cursor_surface); + if (seat->wl_pointer) { + wl_pointer_destroy(seat->wl_pointer); + } + if (seat->wl_keyboard) { + wl_keyboard_destroy(seat->wl_keyboard); + } wl_seat_destroy(seat->wl_seat); free(seat); } @@ -173,6 +197,16 @@ output->geometry.y = y; } +static void output_handle_mode(void *data, struct wl_output *wl_output, + uint32_t flags, int32_t width, int32_t height, int32_t refresh) { + struct slurp_output *output = data; + if ((flags & WL_OUTPUT_MODE_CURRENT) == 0) { + return; + } + output->geometry.width = width; + output->geometry.height = height; +} + static void output_handle_scale(void *data, struct wl_output *wl_output, int32_t scale) { struct slurp_output *output = data; @@ -182,11 +216,32 @@ static const struct wl_output_listener output_listener = { .geometry = output_handle_geometry, - .mode = noop, + .mode = output_handle_mode, .done = noop, .scale = output_handle_scale, }; +static void xdg_output_handle_logical_position(void *data, + struct zxdg_output_v1 *xdg_output, int32_t x, int32_t y) { + struct slurp_output *output = data; + 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; + output->logical_geometry.width = width; + output->logical_geometry.height = height; +} + +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, + .description = noop, +}; + static void create_output(struct slurp_state *state, struct wl_output *wl_output) { struct slurp_output *output = calloc(1, sizeof(struct slurp_output)); @@ -211,6 +266,9 @@ finish_buffer(&output->buffers[1]); 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); + } wl_surface_destroy(output->surface); if (output->frame_callback) { wl_callback_destroy(output->frame_callback); @@ -335,6 +393,8 @@ struct wl_output *wl_output = wl_registry_bind(registry, name, &wl_output_interface, 3); create_output(state, wl_output); + } else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) { + state->xdg_output_manager = wl_registry_bind(registry, name, &zxdg_output_manager_v1_interface, 1); } } @@ -346,12 +406,13 @@ static const char usage[] = "Usage: slurp [options...]\n" "\n" - " -h Show help message and quit.\n" - " -d Display dimensions of selection.\n" - " -b #rrggbb Set background color.\n" - " -c #rrggbb Set border color.\n" - " -s #rrggbb Set selection color.\n" - " -w n Set border weight.\n"; + " -h Show help message and quit.\n" + " -d Display dimensions of selection.\n" + " -b #rrggbbaa Set background color.\n" + " -c #rrggbbaa Set border color.\n" + " -s #rrggbbaa Set selection color.\n" + " -w n Set border weight.\n" + " -f s Set output format.\n"; uint32_t parse_color(const char *color) { if (color[0] == '#') { @@ -371,6 +432,34 @@ return res; } +static void print_formatted_result(const struct slurp_box *result, const char *format) { + for (size_t i = 0; format[i] != 0; i++) { + char c = format[i]; + if (c == '%') { + char next = format[i + 1]; + + i++; // Skip the next character (x, y, w or h) + switch (next) { + case 'x': + printf("%u", result->x); + continue; + case 'y': + printf("%u", result->y); + continue; + case 'w': + printf("%u", result->width); + continue; + case 'h': + printf("%u", result->height); + continue; + } + i--; // If no case was executed, revert i back - we don't need to skip the next character. + } + printf("%c", c); + } + printf("\n"); +} + int main(int argc, char *argv[]) { struct slurp_state state = { .colors = { @@ -383,7 +472,8 @@ }; int opt; - while ((opt = getopt(argc, argv, "hdb:c:s:w:")) != -1) { + char *format = "%x,%y %wx%h"; + while ((opt = getopt(argc, argv, "hdb:c:s:w:f:")) != -1) { switch (opt) { case 'h': printf("%s", usage); @@ -400,6 +490,9 @@ case 's': state.colors.selection = parse_color(optarg); break; + case 'f': + format = optarg; + break; case 'w': { errno = 0; char *endptr; @@ -417,7 +510,6 @@ } wl_list_init(&state.outputs); - wl_list_init(&state.pointers); wl_list_init(&state.seats); state.display = wl_display_connect(NULL); @@ -443,6 +535,9 @@ fprintf(stderr, "compositor doesn't support zwlr_layer_shell_v1\n"); return EXIT_FAILURE; } + if (state.xdg_output_manager == NULL) { + fprintf(stderr, "compositor doesn't support xdg-output. Guessing geometry from physical output size.\n"); + } if (wl_list_empty(&state.outputs)) { fprintf(stderr, "no wl_output\n"); return EXIT_FAILURE; @@ -457,13 +552,25 @@ state.layer_shell, output->surface, output->wl_output, ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "selection"); zwlr_layer_surface_v1_add_listener(output->layer_surface, - &layer_surface_listener, output); + &layer_surface_listener, output); + + if (state.xdg_output_manager) { + output->xdg_output = zxdg_output_manager_v1_get_xdg_output( + state.xdg_output_manager, output->wl_output); + zxdg_output_v1_add_listener(output->xdg_output, &xdg_output_listener, output); + } else { + // guess + output->logical_geometry = output->geometry; + output->logical_geometry.width /= output->scale; + output->logical_geometry.height /= output->scale; + } zwlr_layer_surface_v1_set_anchor(output->layer_surface, ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM); + zwlr_layer_surface_v1_set_keyboard_interactivity(output->layer_surface, true); zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, -1); wl_surface_commit(output->surface); @@ -486,10 +593,12 @@ } output->cursor_image = cursor->images[0]; } + // second roundtrip for xdg-output + wl_display_roundtrip(state.display); - struct slurp_pointer *pointer; - wl_list_for_each(pointer, &state.pointers, link) { - pointer->cursor_surface = + struct slurp_seat *seat; + wl_list_for_each(seat, &state.seats, link) { + seat->cursor_surface = wl_compositor_create_surface(state.compositor); } @@ -498,15 +607,11 @@ // This space intentionally left blank } - struct slurp_pointer *pointer_tmp; - wl_list_for_each_safe(pointer, pointer_tmp, &state.pointers, link) { - destroy_pointer(pointer); - } struct slurp_output *output_tmp; wl_list_for_each_safe(output, output_tmp, &state.outputs, link) { destroy_output(output); } - struct slurp_seat *seat, *seat_tmp; + struct slurp_seat *seat_tmp; wl_list_for_each_safe(seat, seat_tmp, &state.seats, link) { destroy_seat(seat); } @@ -525,7 +630,6 @@ return EXIT_FAILURE; } - printf("%d,%d %dx%d\n", state.result.x, state.result.y, - state.result.width, state.result.height); + print_formatted_result(&state.result, format); return EXIT_SUCCESS; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.0.1/meson.build new/slurp-1.1.0/meson.build --- old/slurp-1.0.1/meson.build 2019-02-12 21:24:23.000000000 +0100 +++ new/slurp-1.1.0/meson.build 2019-02-23 19:47:52.000000000 +0100 @@ -1,9 +1,9 @@ project( 'slurp', 'c', - version: '1.0.1', + version: '1.1.0', license: 'MIT', - meson_version: '>=0.43.0', + meson_version: '>=0.48.0', default_options: [ 'c_std=c11', 'warning_level=2', @@ -43,7 +43,7 @@ install: true, ) -scdoc = find_program('scdoc', required: false) +scdoc = find_program('scdoc', required: get_option('man-pages')) if scdoc.found() sh = find_program('sh') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.0.1/meson_options.txt new/slurp-1.1.0/meson_options.txt --- old/slurp-1.0.1/meson_options.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/slurp-1.1.0/meson_options.txt 2019-02-23 19:47:52.000000000 +0100 @@ -0,0 +1 @@ +option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/slurp-1.0.1/render.c new/slurp-1.1.0/render.c --- old/slurp-1.0.1/render.c 2019-02-12 21:24:23.000000000 +0100 +++ new/slurp-1.1.0/render.c 2019-02-23 19:47:52.000000000 +0100 @@ -25,26 +25,31 @@ set_source_u32(cairo, state->colors.background); cairo_paint(cairo); - struct slurp_pointer *pointer; - wl_list_for_each(pointer, &state->pointers, link) { - if (pointer->button_state != WL_POINTER_BUTTON_STATE_PRESSED || - pointer->current_output != output) { + struct slurp_seat *seat; + wl_list_for_each(seat, &state->seats, link) { + if (!seat->wl_pointer) continue; + if (seat->button_state != WL_POINTER_BUTTON_STATE_PRESSED) { continue; } - int x, y, width, height; - pointer_get_box(pointer, &x, &y, &width, &height); + struct slurp_box b; + seat_get_box(seat, &b); + if (!box_intersect(&output->logical_geometry, &b)) { + continue; + } + b.x -= output->logical_geometry.x; + b.y -= output->logical_geometry.y; // Draw border set_source_u32(cairo, state->colors.selection); - cairo_rectangle(cairo, x * scale, y * scale, - width * scale, height * scale); + cairo_rectangle(cairo, b.x * scale, b.y * scale, + b.width * scale, b.height * scale); cairo_fill(cairo); set_source_u32(cairo, state->colors.border); cairo_set_line_width(cairo, state->border_weight * scale); - cairo_rectangle(cairo, x * scale, y * scale, - width * scale, height * scale); + cairo_rectangle(cairo, b.x * scale, b.y * scale, + b.width * scale, b.height * scale); cairo_stroke(cairo); if (state->display_dimensions) { @@ -53,8 +58,8 @@ 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", width, height); - cairo_move_to(cairo, (x + width + 10) * scale, (y + 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.0.1/slurp.1.scd new/slurp-1.1.0/slurp.1.scd --- old/slurp-1.0.1/slurp.1.scd 2019-02-12 21:24:23.000000000 +0100 +++ new/slurp-1.1.0/slurp.1.scd 2019-02-23 19:47:52.000000000 +0100 @@ -34,10 +34,27 @@ *-w* _weight_ Set border weight. +*-f* _format_ + Set format. See *FORMAT* for more detail. + # COLORS Colors may be specified in #RRGGBB or #RRGGBBAA format. The # is optional. +# FORMAT + +Interpreted sequences are: + +%x The x-coordinate of the selection + +%y The y-coordinate of the selection + +%w The width of the selection + +%h The height of the selection + +The default format is "%x,%y %wx%h". + # AUTHORS Maintained by Simon Ser <[email protected]>, who is assisted by other
