Merge remote-tracking branch 'origin/main' into yolo
# Conflicts: # home/common/programs/default.nix
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
./zsh.nix
|
||||
./nix.nix
|
||||
./neovim
|
||||
./editors.nix
|
||||
./rust.nix
|
||||
./elixir.nix
|
||||
./nodejs.nix
|
||||
|
||||
@@ -57,6 +57,8 @@
|
||||
];
|
||||
|
||||
pointerCursor = {
|
||||
# setting the block alone no longer implies generation; must be explicit
|
||||
enable = true;
|
||||
package = pkgs.numix-cursor-theme;
|
||||
name = "Numix-Cursor-Light";
|
||||
};
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
# Trialling GUI editors alongside neovim, for reviewing agent-generated
|
||||
# diffs. Drop the ones that don't stick.
|
||||
home.packages = with pkgs; [
|
||||
zed-editor
|
||||
code-cursor
|
||||
# VSCodium and Cursor both default to Open VSX, which carries
|
||||
# GitHub.vscode-pull-request-github. Zed has no PR review at all.
|
||||
vscodium
|
||||
];
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
elixir_1_18
|
||||
# top-level elixir_* aliases are deprecated in favour of the beamPackages sets
|
||||
beamPackages.elixir_1_18
|
||||
];
|
||||
}
|
||||
|
||||
@@ -2,11 +2,49 @@
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
inputs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.custom.hyprland;
|
||||
|
||||
hyprPkgs = inputs.hyprland.packages.${pkgs.stdenv.hostPlatform.system};
|
||||
|
||||
# xdph runs this instead of hyprland-share-picker (screencopy:custom_picker_binary).
|
||||
# The contract is just "print [SELECTION] to stdout"; a leading "r" grants a
|
||||
# restore token. Printing it immediately means the dialog never renders.
|
||||
#
|
||||
# Why bypass the picker at all: Slack opens a burst of screencast sessions per
|
||||
# share and only asks for persist_mode=1, so the leading sessions race ahead of
|
||||
# their restore token and re-prompt. allow_token_by_default alone still left
|
||||
# ~3 dialogs per share.
|
||||
#
|
||||
# Escape hatch: `touch ~/.config/hypr/share-picker-manual` to get the real
|
||||
# picker back when you need a window or region instead of a whole screen.
|
||||
#
|
||||
# Deliberately NOT the focused monitor: at the moment you hit "share screen"
|
||||
# the focus is on the Slack/Chrome window, which is generally not the screen
|
||||
# you actually want to show. Auto-picking it would silently share the wrong
|
||||
# display. shareOutput is pinned per-host instead.
|
||||
sharePicker = pkgs.writeShellScriptBin "xdph-auto-picker" ''
|
||||
realPicker="${hyprPkgs.xdg-desktop-portal-hyprland}/bin/hyprland-share-picker"
|
||||
|
||||
if [ -e "$HOME/.config/hypr/share-picker-manual" ]; then
|
||||
exec "$realPicker" "$@"
|
||||
fi
|
||||
|
||||
want=${lib.escapeShellArg (toString cfg.shareOutput)}
|
||||
|
||||
# Only auto-select if that output is actually connected right now; otherwise
|
||||
# fall back to the picker rather than sharing something unexpected.
|
||||
if ${hyprPkgs.hyprland}/bin/hyprctl monitors -j 2>/dev/null \
|
||||
| ${pkgs.jq}/bin/jq -e --arg o "$want" 'any(.[]; .name == $o)' >/dev/null 2>&1; then
|
||||
printf '[SELECTION]r/screen:%s\n' "$want"
|
||||
else
|
||||
exec "$realPicker" "$@"
|
||||
fi
|
||||
'';
|
||||
|
||||
# Floating webcam preview for the "corner-cam" recording trick: run `webcam`,
|
||||
# then capture the whole screen with kooha/wf-recorder — the preview is in the
|
||||
# recording. v4l2 only (won't work with the laptop's IPU6 cam). Optional device
|
||||
@@ -32,10 +70,21 @@ in
|
||||
default = 24;
|
||||
description = "Cursor size for XCURSOR_SIZE and HYPRCURSOR_SIZE";
|
||||
};
|
||||
shareOutput = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
example = "HDMI-A-1";
|
||||
description = ''
|
||||
Output that screen-sharing auto-selects, bypassing the xdph picker
|
||||
entirely. null keeps the normal picker. Falls back to the picker if
|
||||
the named output isn't currently connected.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
imports = [
|
||||
./cursor.nix
|
||||
./kbptr.nix
|
||||
./noctalia
|
||||
./wallpapers.nix
|
||||
];
|
||||
@@ -62,6 +111,22 @@ in
|
||||
WEBKIT_DISABLE_DMABUF_RENDERER = "1";
|
||||
};
|
||||
|
||||
# xdph's share-picker is stateless: the "Allow a restore token" checkbox
|
||||
# starts unticked, so no app ever receives a token and every single share
|
||||
# re-prompts (journal showed 0 "Sent restore token" in 30 days, always
|
||||
# re-selecting the same output). This pre-ticks it, so OBS/Chrome/Slack get
|
||||
# a token on first share and skip the dialog thereafter.
|
||||
# Note: xdph.conf is still hyprlang — the 0.55 Lua switch only hit the
|
||||
# compositor config, not this separate binary.
|
||||
xdg.configFile."hypr/xdph.conf".text = ''
|
||||
screencopy {
|
||||
allow_token_by_default = true
|
||||
${lib.optionalString (
|
||||
cfg.shareOutput != null
|
||||
) " custom_picker_binary = ${sharePicker}/bin/xdph-auto-picker"}
|
||||
}
|
||||
'';
|
||||
|
||||
wayland.windowManager.hyprland = {
|
||||
enable = true;
|
||||
package = null;
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
# wl-kbptr's OpenCV target detection (the `detect` source used by SUPER+G) is
|
||||
# hardcoded for a ~1080p screen and finds almost nothing on a 4K one.
|
||||
#
|
||||
# src/target_detection.cpp:264 discards any candidate target with
|
||||
# `height >= 50 || width >= 500`. Every monitor here is 4K at scale = 1, so an
|
||||
# ordinary button or list row is ~50px tall and well over 500px wide — i.e.
|
||||
# basically every real control is thrown away for being "too big", and the
|
||||
# only survivors are emoji and avatars. Verified on-screen: stock, a full
|
||||
# Slack window got ~8 labels, all on images; patched, every channel, tab and
|
||||
# button gets one.
|
||||
#
|
||||
# Doubling the four thresholds (and the dilate kernel that merges glyph edges
|
||||
# into word blobs) is exactly the 1080p->4K ratio. None of these are exposed
|
||||
# as config options in 0.4.1, so patching is the only way in. Drop this
|
||||
# override if upstream makes detection DPI-aware.
|
||||
# Second bug, on the rotated monitor (DP-2, transform = 1): the pointer lands
|
||||
# in the wrong place because the rotation is applied twice.
|
||||
#
|
||||
# src/utils_wayland.c move_pointer() takes output->width/height — which come
|
||||
# from `xdg_output.logical_size`, i.e. already rotated — and then runs
|
||||
# _apply_transform() over them again before motion_absolute(). Hyprland's
|
||||
# virtual-pointer also works in logical space, so the second rotation is pure
|
||||
# error. Measured: asking for global (4000,1000) on DP-2 landed at
|
||||
# (4286,3726); the double-rotation arithmetic predicts (4301,3736).
|
||||
#
|
||||
# Passing TRANSFORM_NORMAL makes the call a no-op while keeping the (static)
|
||||
# function referenced, so no unused-function warning. Only correct for
|
||||
# compositors that expect logical coords; fine here, Hyprland-only config.
|
||||
wl-kbptr = pkgs.wl-kbptr.overrideAttrs (old: {
|
||||
postPatch = (old.postPatch or "") + ''
|
||||
substituteInPlace src/utils_wayland.c \
|
||||
--replace-fail \
|
||||
'&x, &y, &output_width, &output_height, state->current_output->transform' \
|
||||
'&x, &y, &output_width, &output_height, WL_OUTPUT_TRANSFORM_NORMAL'
|
||||
substituteInPlace src/target_detection.cpp \
|
||||
--replace-fail \
|
||||
'rect.height >= 50 || rect.width >= 500 || rect.height <= 3 ||' \
|
||||
'rect.height >= 100 || rect.width >= 1000 || rect.height <= 6 ||' \
|
||||
--replace-fail 'rect.width <= 7) {' 'rect.width <= 14) {' \
|
||||
--replace-fail 'if (rect.height <= 6) {' 'if (rect.height <= 12) {' \
|
||||
--replace-fail 'round(2.5 * scale), round(3.5 * scale)' \
|
||||
'round(5.0 * scale), round(7.0 * scale)'
|
||||
'';
|
||||
});
|
||||
in
|
||||
{
|
||||
home.packages = [ wl-kbptr ];
|
||||
|
||||
# wl-kbptr — move/click the pointer with the keyboard. We reorder the label
|
||||
# alphabet so the easiest tiles land on the home row, set a monospace label
|
||||
# font so labels stay legible over busy backgrounds, and roughly double every
|
||||
# size default. Run `wl-kbptr --help-config` for the full option list.
|
||||
#
|
||||
# The size bump is not taste, it's DPI: every monitor here is 4K at
|
||||
# `scale = 1` (see home/*/monitors.nix), and wl-kbptr paints raw cairo onto a
|
||||
# layer surface, so it never sees a scale factor — GDK_SCALE only fixes GTK
|
||||
# apps. Upstream's defaults are tuned for ~1080p and render half-size here.
|
||||
#
|
||||
# `label_font_size` is `min proportion max`, evaluated as
|
||||
# clamp(area_height * proportion, min, max). In floating/detect mode the
|
||||
# detected areas are buttons and icons, i.e. short, so it's the *minimum* that
|
||||
# is in force for nearly every label — raising max alone would change nothing.
|
||||
xdg.configFile."wl-kbptr/config".text = ''
|
||||
[general]
|
||||
modes=tile,bisect
|
||||
|
||||
[mode_tile]
|
||||
label_symbols=asdfghjklqwertyuiopzxcvbnm
|
||||
label_font_family=monospace
|
||||
label_font_size=20 50% 120
|
||||
|
||||
[mode_floating]
|
||||
label_symbols=asdfghjklqwertyuiopzxcvbnm
|
||||
label_font_family=monospace
|
||||
label_font_size=28 45% 80
|
||||
|
||||
[mode_bisect]
|
||||
label_font_family=monospace
|
||||
label_font_size=32
|
||||
label_padding=20
|
||||
pointer_size=32
|
||||
|
||||
[mode_split]
|
||||
pointer_size=32
|
||||
|
||||
[mode_click]
|
||||
button=left
|
||||
'';
|
||||
|
||||
wayland.windowManager.hyprland.extraConfig = ''
|
||||
-- wl-kbptr: keyboard pointer control.
|
||||
--
|
||||
-- SUPER+G "vimium for the desktop" — OpenCV detects clickable regions
|
||||
-- from a screencopy frame and labels them; type a label and it
|
||||
-- moves the pointer to that region's centre and left-clicks.
|
||||
-- Needs the HiDPI patch in kbptr.nix to find anything here.
|
||||
-- SUPER+SHIFT+G tile -> bisect, for anywhere detection misses. Type the tile
|
||||
-- label, then bisect with the home row; g/h/b left/right/middle
|
||||
-- click, Enter/Space just parks the cursor, Backspace steps back.
|
||||
--
|
||||
-- Both need wlr-layer-shell + wlr-virtual-pointer (+ wlr-screencopy for
|
||||
-- detect), all of which Hyprland implements.
|
||||
-- spelled out rather than reusing the `mod` local from default.nix: both
|
||||
-- chunks land in the same hyprland.lua but their relative order isn't pinned.
|
||||
-- Guarded with `pidof` the same way hypridle's lock_cmd is. wl-kbptr only
|
||||
-- exits on a keypress (main.c sets running=false solely from the keyboard
|
||||
-- handler), so an overlay that loses focus before you type a label just sits
|
||||
-- there holding an exclusive keyboard grab until it's killed from a shell —
|
||||
-- which happened here. The guard stops repeat presses stacking more of them.
|
||||
hl.bind("SUPER + G", hl.dsp.exec_cmd("pidof wl-kbptr || wl-kbptr -o modes=floating,click -o mode_floating.source=detect"))
|
||||
hl.bind("SUPER + SHIFT + G", hl.dsp.exec_cmd("pidof wl-kbptr || wl-kbptr"))
|
||||
'';
|
||||
}
|
||||
@@ -78,6 +78,10 @@
|
||||
fzf = {
|
||||
enable = true;
|
||||
enableZshIntegration = true;
|
||||
# Both fzf and atuin bind Ctrl-R, and home-manager warns about the clash.
|
||||
# Atuin is sourced last so it already won; this just makes that explicit
|
||||
# and silences the warning. fzf keeps Ctrl-T and Alt-C.
|
||||
historyWidget.zsh.command = "";
|
||||
};
|
||||
|
||||
zoxide = {
|
||||
|
||||
Reference in New Issue
Block a user