feat: add --cursor-size flag for standalone pointer size
New --cursor-size N (8..128px, both --cursor-size N and --cursor-size=N forms) sizing the standalone wlr_cursor. Precedence: CLI flag over $XCURSOR_SIZE over the 24px default. Out-of-range, missing or non-numeric values are startup errors (rc 2) naming the flag, matching the existing --start-cmd-index/--tab-groups handling. Nested mode is unaffected (the host draws the pointer there); the flag is silently ignored. Help text, README usage + cursor-shapes section, and a test_cursor_size_flag_errors regression test included. Verified: debug + release builds warning-free; cursor_size + tab-groups flag-error tests pass; --cursor-size 32 boots headless, --cursor-size 999 exits rc 2.
This commit is contained in:
parent
1c1bc5a230
commit
b04f6a2826
3 changed files with 83 additions and 4 deletions
|
|
@ -75,7 +75,7 @@ install works too.
|
|||
## Usage
|
||||
|
||||
```
|
||||
kick [--start-cmd-index N] [--focus-priority] [prog...]
|
||||
kick [--start-cmd-index N] [--focus-priority] [--cursor-size N] [prog...]
|
||||
```
|
||||
|
||||
Each `<prog>` is one shell command; quote it when it takes arguments, e.g.
|
||||
|
|
@ -428,10 +428,12 @@ version 1). Nested clients that switch the pointer's cursor shape are honoured:
|
|||
|
||||
- **Standalone** mode applies the requested shape to the compositor's own
|
||||
cursor, looked up in the current `XCURSOR_THEME` (so e.g. GTK's text cursor
|
||||
works over a galculator entry).
|
||||
works over a galculator entry). Pass `--cursor-size N` (8..128px,
|
||||
default 24 or `$XCURSOR_SIZE` when set) to size that cursor.
|
||||
- **Nested** mode has no cursor of its own: the shape is forwarded to the host
|
||||
compositor's pointer via `wp_cursor_shape_device_v1.set_shape`, and the host
|
||||
(which draws the cursor over our window) applies it.
|
||||
(which draws the cursor over our window) applies it. `--cursor-size` is
|
||||
ignored there.
|
||||
|
||||
The shape is remembered per tab and the cursor is reset to `default` when you
|
||||
switch to a tab whose client last asked for nothing (or asked for `default`),
|
||||
|
|
|
|||
49
kick.c
49
kick.c
|
|
@ -928,6 +928,11 @@ static bool opt_focus_priority = false;
|
|||
text row. Off by default. */
|
||||
static bool opt_overlay_previews = false;
|
||||
|
||||
/* --cursor-size N: standalone pointer size in px (8..128). -1 means unset:
|
||||
fall back to $XCURSOR_SIZE, then the 24px default. Nested mode has no
|
||||
cursor of its own (the host draws the pointer), so it is ignored there. */
|
||||
static int opt_cursor_size = -1;
|
||||
|
||||
/* ===================== Clipboard bridge ===================== */
|
||||
|
||||
enum bridge_backend {
|
||||
|
|
@ -13901,6 +13906,13 @@ int main(int argc, char *argv[]) {
|
|||
"that starts\n"
|
||||
" focused; without it the "
|
||||
"last command does.\n"
|
||||
" --cursor-size N Standalone pointer size "
|
||||
"in px (8..128;\n"
|
||||
" default 24, or "
|
||||
"$XCURSOR_SIZE when set).\n"
|
||||
" Ignored when nested: the "
|
||||
"host draws the\n"
|
||||
" pointer there.\n"
|
||||
" --tab-groups on|off How a client's related "
|
||||
"windows group with their tab:\n"
|
||||
" 'on' (default) stacks them "
|
||||
|
|
@ -14101,6 +14113,37 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
start_cmd_index = (int)idx - 1;
|
||||
continue;
|
||||
} else if (strcmp(argv[i], "--cursor-size") == 0) {
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr, "kick: --cursor-size needs a "
|
||||
"value, e.g. --cursor-size 32\n");
|
||||
free(appv);
|
||||
return 2;
|
||||
}
|
||||
const char *n = argv[++i];
|
||||
char *end = NULL;
|
||||
long sz = strtol(n, &end, 10);
|
||||
if (end == n || *end != '\0' || sz < 8 || sz > 128) {
|
||||
fprintf(stderr, "kick: bad --cursor-size '%s' "
|
||||
"(use 8..128, e.g. --cursor-size 32)\n", n);
|
||||
free(appv);
|
||||
return 2;
|
||||
}
|
||||
opt_cursor_size = (int)sz;
|
||||
continue;
|
||||
} else if (strncmp(argv[i], "--cursor-size=",
|
||||
sizeof("--cursor-size=") - 1) == 0) {
|
||||
const char *n = argv[i] + sizeof("--cursor-size=") - 1;
|
||||
char *end = NULL;
|
||||
long sz = strtol(n, &end, 10);
|
||||
if (end == n || *end != '\0' || sz < 8 || sz > 128) {
|
||||
fprintf(stderr, "kick: bad --cursor-size '%s' "
|
||||
"(use 8..128, e.g. --cursor-size 32)\n", n);
|
||||
free(appv);
|
||||
return 2;
|
||||
}
|
||||
opt_cursor_size = (int)sz;
|
||||
continue;
|
||||
}
|
||||
if (val) {
|
||||
if (!parse_screen_mode(val)) {
|
||||
|
|
@ -14734,7 +14777,8 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
/* Standalone has no host compositor to draw a pointer, so give the
|
||||
output a real wlr_cursor. Theme/size follow the XDG cursor convention:
|
||||
XCURSOR_THEME (default "default") and XCURSOR_SIZE (default 24px).
|
||||
XCURSOR_THEME (default "default") and XCURSOR_SIZE (default 24px),
|
||||
with --cursor-size overriding the size when given.
|
||||
wlroots resolves the theme itself (search path, Inherits chains) and,
|
||||
when nothing is installed, substitutes a builtin arrow -- so the pointer
|
||||
is never invisible. We only report when the requested theme was
|
||||
|
|
@ -14758,6 +14802,9 @@ int main(int argc, char *argv[]) {
|
|||
if (end != size_env && v > 0)
|
||||
size = (uint32_t)v;
|
||||
}
|
||||
/* Explicit --cursor-size wins over the environment. */
|
||||
if (opt_cursor_size > 0)
|
||||
size = (uint32_t)opt_cursor_size;
|
||||
|
||||
server.xcursor_mgr = wlr_xcursor_manager_create(theme, size);
|
||||
if (server.xcursor_mgr)
|
||||
|
|
|
|||
|
|
@ -4229,6 +4229,36 @@ def test_sub_windows_flag_errors():
|
|||
f"error should mention --tab-groups:\n{out}"
|
||||
|
||||
|
||||
def test_cursor_size_flag_errors():
|
||||
"""A missing or bad --cursor-size value is a startup error (rc 2) naming
|
||||
the flag, before any window or backend work."""
|
||||
env = dict(os.environ)
|
||||
cases = (["--cursor-size"],
|
||||
["--cursor-size", "0"],
|
||||
["--cursor-size", "7"],
|
||||
["--cursor-size", "129"],
|
||||
["--cursor-size", "big"],
|
||||
["--cursor-size=foo"])
|
||||
for case in cases:
|
||||
proc = subprocess.Popen(
|
||||
["env", "-i",
|
||||
"PATH=" + env["PATH"],
|
||||
"HOME=" + env.get("HOME", "/"),
|
||||
"XDG_RUNTIME_DIR=" + env.get("XDG_RUNTIME_DIR", "/tmp"),
|
||||
"KICK_MODE=standalone",
|
||||
"WLR_BACKENDS=headless",
|
||||
"stdbuf", "-oL",
|
||||
BIN] + case,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
preexec_fn=_preexec_death(os.getpid()),
|
||||
)
|
||||
out, _ = proc.communicate(timeout=15)
|
||||
assert proc.returncode == 2, \
|
||||
f"--cursor-size {case} should exit rc 2; rc={proc.returncode}\n{out}"
|
||||
assert b"--cursor-size" in out, \
|
||||
f"error should mention --cursor-size:\n{out}"
|
||||
|
||||
|
||||
@pytest.mark.flaky
|
||||
def test_dead_command_explains_and_exits():
|
||||
"""A sole command that exits before opening a window is dropped with a
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue