From 649c0b74333b39fec6341d4d57279eb87d2110ae Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Mon, 7 Sep 2026 22:56:48 -0400 Subject: [PATCH 1/4] Install broadcom-wl-dkms now that Arch dropped the prebuilt module Arch removed the prebuilt broadcom-wl package on 2026-09-02 and rebuilt broadcom-wl-dkms with replaces=(broadcom-wl). A replaces entry only helps upgrades of an already-installed package, so the name is now unresolvable as an explicit pacman target and the ISO offline mirror download fails with "target not found: broadcom-wl". broadcom-wl-dkms depends on dkms, so the explicit dkms in the hardware fix is redundant; linux-headers stays because the module has to build against the running kernel. --- install/hardware/fix-bcm43xx.sh | 2 +- install/omarchy-other.packages | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/install/hardware/fix-bcm43xx.sh b/install/hardware/fix-bcm43xx.sh index a788d6f9..6b7e5648 100644 --- a/install/hardware/fix-bcm43xx.sh +++ b/install/hardware/fix-bcm43xx.sh @@ -6,5 +6,5 @@ pci_info=$(lspci -nn) if (echo "$pci_info" | grep -q "14e4:43a0" || echo "$pci_info" | grep -q "14e4:4331"); then echo "BCM4360 / BCM4331 detected" - omarchy-pkg-add broadcom-wl dkms linux-headers + omarchy-pkg-add broadcom-wl-dkms linux-headers fi diff --git a/install/omarchy-other.packages b/install/omarchy-other.packages index e5d56d56..3214657a 100644 --- a/install/omarchy-other.packages +++ b/install/omarchy-other.packages @@ -5,7 +5,7 @@ autoconf-archive asusctl base base-devel -broadcom-wl +broadcom-wl-dkms btrfs-progs dkms egl-wayland From 138d839b37033aca3ccd93803417f2470f839441 Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Tue, 8 Sep 2026 02:22:55 -0400 Subject: [PATCH 2/4] Keep Cursor bundled Node off the mise PATH --- etc/mise/conf.d/omarchy.toml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 etc/mise/conf.d/omarchy.toml diff --git a/etc/mise/conf.d/omarchy.toml b/etc/mise/conf.d/omarchy.toml new file mode 100644 index 00000000..c9354a2e --- /dev/null +++ b/etc/mise/conf.d/omarchy.toml @@ -0,0 +1,4 @@ +# Keep Cursor optional while applying these options whenever mise installs it. +# Expose only its launcher so the bundled Node cannot shadow the user's Node. +[tool_alias] +cursor-agent = 'http:cursor-agent[bin_path=bin,postinstall=mkdir -p "$MISE_TOOL_INSTALL_PATH/bin" && ln -sfn ../dist-package/cursor-agent "$MISE_TOOL_INSTALL_PATH/bin/cursor-agent"]' From f5cd244ed07892e94998a6da81f1cfff19e0677e Mon Sep 17 00:00:00 2001 From: Ryan Hughes Date: Tue, 8 Sep 2026 02:36:58 -0400 Subject: [PATCH 3/4] Retire the stock user icon font missed by Quattro upgrades --- agents/skills/icon-font.md | 10 +- bin/omarchy-upgrade-to-quattro | 4 +- migrations/1788848726.sh | 21 ++++ .../fixtures/legacy-icon-font/README.md | 3 + .../fixtures/legacy-icon-font/omarchy.ttf | Bin 0 -> 1824 bytes .../legacy-icon-font-migration-test.sh | 106 ++++++++++++++++++ 6 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 migrations/1788848726.sh create mode 100644 test/shell.d/fixtures/legacy-icon-font/README.md create mode 100644 test/shell.d/fixtures/legacy-icon-font/omarchy.ttf create mode 100644 test/shell.d/legacy-icon-font-migration-test.sh diff --git a/agents/skills/icon-font.md b/agents/skills/icon-font.md index 333f8752..15585006 100644 --- a/agents/skills/icon-font.md +++ b/agents/skills/icon-font.md @@ -70,10 +70,6 @@ magick -background white -fill black -font default/fonts/omarchy/omarchy.ttf \ -pointsize 110 label:@/tmp/row.txt /tmp/font-row.png ``` -Then confirm it in the running menu per -[`visual-verification.md`](visual-verification.md). Fontconfig prefers the -packaged font over a copy in `~/.local/share/fonts` for the same family, so a -preview needs either the real file replaced or a `` rule in -`~/.config/fontconfig/conf.d/` pointing fontconfig away from the packaged one. -Restart the shell afterwards — Qt reads the font database at startup, so -`omarchy menu refresh` alone will not pick up a changed font. +Then confirm it in the running menu per [`visual-verification.md`](visual-verification.md). Avoid leaving two fonts with the `omarchy` family registered: Qt can use an old copy in `~/.local/share/fonts` even when `fc-match omarchy` reports the packaged font. For a preview, either replace the packaged file in the disposable VM or temporarily exclude it with a `` rule in `~/.config/fontconfig/conf.d/` before loading the candidate. + +Refresh the font cache and restart the shell afterwards — Qt reads the font database at startup, so `omarchy menu refresh` alone will not pick up a changed font. Remove temporary fonts and rules after verification. diff --git a/bin/omarchy-upgrade-to-quattro b/bin/omarchy-upgrade-to-quattro index 21691914..e6a27ee6 100755 --- a/bin/omarchy-upgrade-to-quattro +++ b/bin/omarchy-upgrade-to-quattro @@ -1569,7 +1569,6 @@ refresh xournalpp/settings.xml 1c1a9efbf1b6dc7813bf3440fd5bf8409fc283e8d0192ca29 # fastfetch/config.jsonc -> /etc/fastfetch/config.jsonc # fontconfig/fonts.conf -> /usr/share/fontconfig/conf.avail/50-omarchy.conf # mimeapps.list -> /usr/share/applications/mimeapps.list -# omarchy.ttf -> /usr/share/fonts/omarchy/omarchy.ttf # systemd/user/bt-agent.service -> /usr/lib/systemd/user/bt-agent.service # systemd/user/omarchy-recover-internal-monitor.service -> /usr/lib/systemd/user/omarchy-recover-internal-monitor.service # systemd/user/omarchy-sleep-lock.service -> /usr/lib/systemd/user/omarchy-sleep-lock.service @@ -1602,7 +1601,6 @@ retire fontconfig/fonts.conf 6dec98b539388b95ecfdb3c7ab951001c712820eb0581002832 retire fontconfig/fonts.conf 3545f6c5a8c1465df7a4e251b3c2047d4ba03654c86636794f64cb0d8ea8ef63 retire fontconfig/fonts.conf 0f085b449f1cbe8eda3b59a6235bf2a3ddb6e982ab5d22fa642248916e63bafc retire mimeapps.list 3b574cef135b5deb7a8a0c7e17139037cf1fe155300e3809f60bed0e04120975 -retire omarchy.ttf e55e67119e82f56f92d90cbf54b7ccc1b2946b32c535a29370439d7ef5215966 retire systemd/user/bt-agent.service 0406b577a1225dc2a9f86638d3c346eb3635168576f04050be50ebcc0be6be12 retire systemd/user/omarchy-recover-internal-monitor.service b9b92cedc44cf3cb6216948629be55b53d16746e31896dc6469fd49ba55e82f4 retire systemd/user/omarchy-recover-internal-monitor.service e1483079b9f2aefcd43b4722c75a31643e5f3bb5a2eada5f52f1d7d201e8c289 @@ -2381,6 +2379,8 @@ cleanup_retired_services ensure_sleep_lock_service remove_retired_default_packages run_final_system_package_upgrade +# This also retires the stock ~/.local/share/fonts/omarchy.ttf missed by the +# former ~/.config retirement entry, through migration 1788848726. run_post_upgrade_migrations run_post_upgrade_update_steps refresh_current_theme_after_upgrade diff --git a/migrations/1788848726.sh b/migrations/1788848726.sh new file mode 100644 index 00000000..ab33ffcc --- /dev/null +++ b/migrations/1788848726.sh @@ -0,0 +1,21 @@ +echo "Retire the stock user icon font missed by the Quattro upgrade" + +legacy_font="$HOME/.local/share/fonts/omarchy.ttf" + +# The upgrader treated this as ~/.config/omarchy.ttf and left the old family +# registered alongside the packaged font. Preserve custom fonts and symlinks. +if [[ -f $legacy_font && ! -L $legacy_font ]]; then + legacy_hash=$(sha256sum "$legacy_font") + if [[ ${legacy_hash%% *} == "e55e67119e82f56f92d90cbf54b7ccc1b2946b32c535a29370439d7ef5215966" ]]; then + if [[ ! -f /usr/share/fonts/omarchy/omarchy.ttf ]]; then + echo "Packaged Omarchy icon font is missing; keeping the legacy font." >&2 + exit 1 + fi + + rm "$legacy_font" + fi +fi + +# Also refresh on retries after removal succeeded but the cache refresh failed. +# The normal update restarts the shell, which reloads Qt's font database. +fc-cache -f diff --git a/test/shell.d/fixtures/legacy-icon-font/README.md b/test/shell.d/fixtures/legacy-icon-font/README.md new file mode 100644 index 00000000..c773098d --- /dev/null +++ b/test/shell.d/fixtures/legacy-icon-font/README.md @@ -0,0 +1,3 @@ +Stock Omarchy icon font from `config/omarchy.ttf` at `babfafa5^`, before fonts moved into the settings package. SHA-256: `e55e67119e82f56f92d90cbf54b7ccc1b2946b32c535a29370439d7ef5215966`. + +The migration test uses the real font so it exercises the exact-content guard without mocking `sha256sum`. diff --git a/test/shell.d/fixtures/legacy-icon-font/omarchy.ttf b/test/shell.d/fixtures/legacy-icon-font/omarchy.ttf new file mode 100644 index 0000000000000000000000000000000000000000..273256d07549caa5de9121fc13110e9b704b63d5 GIT binary patch literal 1824 zcmcIkPiz!b82^204Gd`!6Ps-*6bvyQ2u?A9)qpfHY1CmlyIV4|vzbl_ zYdnx}(a;1BgacfA(~~3~3`7rxKw^US;=zL+G}?H^cxV@X-|VZj&&o_tfb4)X(osQeLF|u^)NuuP<#`0Ib)@TcFkpZX|&So&t+ zqvzkek4n$?k9&9L)p2dMdn=V-nQ)Ek!!Wozl4{EwzylRYYA>_aw_qK0kH3%p&`Vo* z$rRMH_fqw+gtH9~B@-$1Q>#!Tc*V>%=OS;yX4V3c+Jw1nB=Ut;VtsD?$f(P`S^mMe za77FG9JQO!d-bC8!Me?&!vYo$I?KY{clG|vc`?sAQ_DP5sf(FkXr z5cM{ilwZUaYAks0DMyHrptFnzdV-tjs9s0H_>Due>Z$0O`Rr^Ug>@0n3TjqTc1)Vv zv_y87&noBBtovN%+%_TFVV+^VRNt`fL2pG_w-OoF8;uQXmnVkxwmXKo<}#tOxpT1Z zH;(L`WKCVc4!n$A7y=IM9@zZ?#{^l(nKU%9U-l0SZ6)jM%5ST`+UO>7Y-J%=T^*F` z-7l@_+Lf+ft68;Lckj}Y>)Kd>n@d-gtiRpWMQhq!9i-@XZ`8CXcG_)InZBU4DlOuo z(dUTz4Yr8~49@fKr|(ZmyKAq(WxS56!4+)92ioPf{!jW58f+1NVsMW5GlOm7s|M$> z9g7ARsQ=dBGNy3H;0j)qopIzPezS8jXv~LRVk9$71FH~Oj{>syT2B}w)&J2;5|4a{?2 zs@rJWC{58b!5n7k)q;b4JfpG4A|~n6%KSW}oM-5FhP~u4?i}-sQ=6hrxo)yKaI^K) zJLHIIYiG8z)cEwSvTrr2jl&q_s6XakrI%LP`%~*(>c4t3>Jv+HVoP2MQk0VPNf||R Qs1i#go+RQ+Q?&Vkha6VlMF0Q* literal 0 HcmV?d00001 diff --git a/test/shell.d/legacy-icon-font-migration-test.sh b/test/shell.d/legacy-icon-font-migration-test.sh new file mode 100644 index 00000000..c042f76c --- /dev/null +++ b/test/shell.d/legacy-icon-font-migration-test.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +set -euo pipefail + +source "$(dirname "$0")/base-test.sh" + +migration="$ROOT/migrations/1788848726.sh" +fixture="$ROOT/test/shell.d/fixtures/legacy-icon-font/omarchy.ttf" +test_dir=$(mktemp -d) +trap 'rm -rf "$test_dir"' EXIT + +export FONT_TEST_HOME="$test_dir/home with spaces" +export FONT_TEST_PACKAGE="$test_dir/packaged-font.ttf" +export FONT_TEST_CACHE_LOG="$test_dir/cache.log" +legacy_font="$FONT_TEST_HOME/.local/share/fonts/omarchy.ttf" + +# Redirect only the filesystem roots; run the real hash check and removal. +# Never change the developer's HOME or refresh their real font cache. +python3 - "$migration" "$test_dir/migration.sh" <<'PY' +import pathlib +import sys + +source = pathlib.Path(sys.argv[1]).read_text() +source = source.replace('$HOME', '$FONT_TEST_HOME') +source = source.replace('/usr/share/fonts/omarchy/omarchy.ttf', '$FONT_TEST_PACKAGE') +pathlib.Path(sys.argv[2]).write_text(source) +PY + +mkdir -p "$test_dir/bin" +cat > "$test_dir/bin/fc-cache" <<'SH' +#!/bin/bash +printf '%s\n' "$*" >> "$FONT_TEST_CACHE_LOG" +exit "${FONT_TEST_CACHE_STATUS:-0}" +SH +chmod +x "$test_dir/bin/fc-cache" + +reset_fonts() { + rm -rf "$FONT_TEST_HOME" + mkdir -p "$FONT_TEST_HOME/.local/share/fonts" "$FONT_TEST_HOME/.config" + cp "$ROOT/default/fonts/omarchy/omarchy.ttf" "$FONT_TEST_PACKAGE" + : > "$FONT_TEST_CACHE_LOG" +} + +run_migration() { + PATH="$test_dir/bin:$PATH" bash -euo pipefail "$test_dir/migration.sh" > "$test_dir/output" 2>&1 +} + +reset_fonts +cp "$fixture" "$legacy_font" +cp "$fixture" "$FONT_TEST_HOME/.config/omarchy.ttf" +run_migration +[[ ! -e $legacy_font ]] || fail "stock font is removed from the actual user font directory" +cmp "$fixture" "$FONT_TEST_HOME/.config/omarchy.ttf" || fail "unrelated config path is untouched" +cmp "$ROOT/default/fonts/omarchy/omarchy.ttf" "$FONT_TEST_PACKAGE" || fail "packaged font is untouched" +[[ $(cat "$FONT_TEST_CACHE_LOG") == "-f" ]] || fail "font cache is refreshed after retirement" +pass "retire the known stock font at its real path and refresh the cache" + +run_migration +[[ ! -e $legacy_font ]] || fail "a second run leaves the stock font retired" +pass "font retirement is idempotent" + +reset_fonts +cp "$fixture" "$legacy_font" +printf 'custom modification\n' >> "$legacy_font" +cp "$legacy_font" "$test_dir/custom-font.ttf" +run_migration +cmp "$test_dir/custom-font.ttf" "$legacy_font" || fail "custom font is preserved" +pass "preserve a modified font with the legacy filename" + +reset_fonts +cp "$fixture" "$test_dir/symlink-target.ttf" +ln -s "$test_dir/symlink-target.ttf" "$legacy_font" +run_migration +[[ -L $legacy_font ]] || fail "user font symlink is preserved" +cmp "$fixture" "$test_dir/symlink-target.ttf" || fail "symlink target is untouched" +pass "preserve user font symlinks even when they point to the stock font" + +reset_fonts +run_migration +[[ ! -e $legacy_font ]] || fail "an absent user font is left absent" +pass "handle installs without a legacy user font" + +reset_fonts +cp "$fixture" "$legacy_font" +rm "$FONT_TEST_PACKAGE" +if run_migration; then + fail "missing packaged font keeps the repair pending" +fi +cmp "$fixture" "$legacy_font" || fail "keep the stock font until its replacement is present" +[[ ! -s $FONT_TEST_CACHE_LOG ]] || fail "missing replacement stops before cache refresh" +pass "preserve the stock font and fail when the packaged replacement is missing" + +reset_fonts +cp "$fixture" "$legacy_font" +if FONT_TEST_CACHE_STATUS=17 run_migration; then + fail "font cache failure keeps the repair pending" +fi +[[ ! -e $legacy_font ]] || fail "cache failure follows successful retirement" +run_migration +(( $(wc -l < "$FONT_TEST_CACHE_LOG") == 2 )) || fail "retry refreshes the cache after the file was removed" +pass "retry a failed cache refresh after successful font retirement" + +if grep -q $'^retire\tomarchy.ttf\t' "$ROOT/bin/omarchy-upgrade-to-quattro"; then + fail "upgrader no longer treats the user font as a config file" +fi +pass "upgrader leaves font retirement to its post-upgrade migrations" From 7e8feb047d8e1989ba1ae1fe5d8faa38f3f5fe60 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 8 Sep 2026 14:09:51 +0200 Subject: [PATCH 4/4] Relay the Elgato Cam Link 4K as a 16:9 virtual camera (#10809) * Relay the Elgato Cam Link 4K as a 16:9 virtual camera Browser meeting apps such as Zoom's web client ask the Cam Link for a standard-definition stream, and Chromium settles on the smallest mode it offers, 640x480. The Cam Link fills that 4:3 frame by cropping its 16:9 input, and the app then paints the frame into a 16:9 tile, so everyone comes out stretched wide. The web client has no HD switch to avoid it. Hide the raw capture node from users and re-expose it through v4l2-relayd as a 1280x720 virtual camera with the same name, so there is still just one "Cam Link 4K" to pick and no way to negotiate 4:3 from it. udev starts the relay whenever the Cam Link enumerates and stops it on unplug, and the relay only pulls frames while something is watching. The sink runs unsynced because v4l2src stamps each frame with its capture time, which a synced sink treats as already late and drops. Co-Authored-By: Claude Fable 5.1 * Take the review fixes for the Cam Link 4K relay Tie only the device's stop into the relay instance. A start dependency on it left a job waiting on a device that never comes whenever the base v4l2-relayd.service is started without a Cam Link attached, since the package generator wants every configured instance. Let the loopback unit rerun on each relay start, so a deleted or unloaded device is recreated on replug instead of the oneshot staying satisfied. Start the relay outright at the end of the migration. The udev trigger only starts it when the rule is new to the device, and a failed module build would otherwise pass silently with the raw camera already hidden. Run the hardware fix after the Panther Lake kernel swap, as it pulls in a DKMS module that would otherwise build twice. Co-Authored-By: Claude Fable 5.1 --------- Co-authored-by: Claude Fable 5.1 --- bin/omarchy-hw-elgato-camlink-4k | 5 +++++ .../system/camlink-4k-loopback.service | 9 +++++++++ .../camlink.conf | 16 +++++++++++++++ default/udev/elgato-camlink-4k.rules | 6 ++++++ default/v4l2-relayd/camlink.conf | 9 +++++++++ install/hardware/all.sh | 3 +++ install/hardware/fix-elgato-camlink-4k.sh | 18 +++++++++++++++++ migrations/1788862626.sh | 20 +++++++++++++++++++ 8 files changed, 86 insertions(+) create mode 100755 bin/omarchy-hw-elgato-camlink-4k create mode 100644 default/systemd/system/camlink-4k-loopback.service create mode 100644 default/systemd/system/v4l2-relayd@camlink.service.d/camlink.conf create mode 100644 default/udev/elgato-camlink-4k.rules create mode 100644 default/v4l2-relayd/camlink.conf create mode 100644 install/hardware/fix-elgato-camlink-4k.sh create mode 100644 migrations/1788862626.sh diff --git a/bin/omarchy-hw-elgato-camlink-4k b/bin/omarchy-hw-elgato-camlink-4k new file mode 100755 index 00000000..e94a54b2 --- /dev/null +++ b/bin/omarchy-hw-elgato-camlink-4k @@ -0,0 +1,5 @@ +#!/bin/bash + +# omarchy:summary=Detect whether an Elgato Cam Link 4K is plugged in. + +grep -qsx "Cam Link 4K" /sys/bus/usb/devices/*/product diff --git a/default/systemd/system/camlink-4k-loopback.service b/default/systemd/system/camlink-4k-loopback.service new file mode 100644 index 00000000..3b7d7b07 --- /dev/null +++ b/default/systemd/system/camlink-4k-loopback.service @@ -0,0 +1,9 @@ +[Unit] +Description=Create the Cam Link 4K virtual camera +After=systemd-modules-load.service + +[Service] +# Reruns on every relay start, so a deleted or unloaded device comes back. +Type=oneshot +ExecStart=/usr/bin/modprobe v4l2loopback +ExecStart=/bin/sh -c 'grep -qsx "Cam Link 4K" /sys/devices/virtual/video4linux/*/name || exec v4l2loopback-ctl add -n "Cam Link 4K" -x 1' diff --git a/default/systemd/system/v4l2-relayd@camlink.service.d/camlink.conf b/default/systemd/system/v4l2-relayd@camlink.service.d/camlink.conf new file mode 100644 index 00000000..956b2a41 --- /dev/null +++ b/default/systemd/system/v4l2-relayd@camlink.service.d/camlink.conf @@ -0,0 +1,16 @@ +[Unit] +# udev starts this when the Cam Link 4K appears. Only the device's stop is +# tied in: a start dependency on it would leave a job waiting whenever the +# base v4l2-relayd.service is started with no Cam Link attached. +ConditionPathExists=/dev/camlink4k +StopPropagatedFrom=dev-camlink4k.device +Requires=camlink-4k-loopback.service +After=camlink-4k-loopback.service + +[Service] +RestartSec=2 +# The packaged command line, plus sync=false on the sink. v4l2src stamps each +# frame with its capture time, so by the time it reaches the sink it is already +# past due and a synced sink drops every one of them. +ExecStart= +ExecStart=/bin/sh -c 'DEVICE=$(grep -l -m1 -E "^${CARD_LABEL}$" /sys/devices/virtual/video4linux/*/name | cut -d/ -f6); exec /usr/bin/v4l2-relayd -i "${VIDEOSRC}" $${SPLASHSRC:+-s "$${SPLASHSRC}"} -o "appsrc name=appsrc caps=video/x-raw,format=${FORMAT},width=${WIDTH},height=${HEIGHT},framerate=${FRAMERATE} ! videoconvert ! v4l2sink name=v4l2sink sync=false device=/dev/$${DEVICE}" $EXTRA_OPTS' diff --git a/default/udev/elgato-camlink-4k.rules b/default/udev/elgato-camlink-4k.rules new file mode 100644 index 00000000..27740681 --- /dev/null +++ b/default/udev/elgato-camlink-4k.rules @@ -0,0 +1,6 @@ +# Keep the Elgato Cam Link 4K's raw capture node away from users and hand it to +# the v4l2-relayd instance that re-exposes it as a 16:9 virtual camera. +# Sorted after 70-uaccess adds the tag and before 73-seat-late applies its ACL. +SUBSYSTEM=="video4linux", ENV{ID_VENDOR_ID}=="0fd9", ENV{ID_MODEL}=="Cam_Link_4K", ENV{ID_V4L_CAPABILITIES}==":capture:", \ + TAG-="uaccess", OWNER="root", GROUP="root", MODE="0600", SYMLINK+="camlink4k", \ + TAG+="systemd", ENV{SYSTEMD_ALIAS}="/dev/camlink4k", ENV{SYSTEMD_WANTS}="v4l2-relayd@camlink.service" diff --git a/default/v4l2-relayd/camlink.conf b/default/v4l2-relayd/camlink.conf new file mode 100644 index 00000000..7f4ce67e --- /dev/null +++ b/default/v4l2-relayd/camlink.conf @@ -0,0 +1,9 @@ +# Elgato Cam Link 4K relayed as a fixed 16:9 virtual camera. Browser meeting +# apps send 720p at most; raise WIDTH/HEIGHT (up to 3840x2160) for apps that +# can use more. +VIDEOSRC="v4l2src device=/dev/camlink4k" +FORMAT=NV12 +WIDTH=1280 +HEIGHT=720 +FRAMERATE=30/1 +CARD_LABEL="Cam Link 4K" diff --git a/install/hardware/all.sh b/install/hardware/all.sh index 7b806ce8..defeef1c 100644 --- a/install/hardware/all.sh +++ b/install/hardware/all.sh @@ -24,6 +24,9 @@ run_logged "$OMARCHY_INSTALL/hardware/intel/fred.sh" run_logged "$OMARCHY_INSTALL/hardware/intel/fix-wifi7-eht.sh" run_logged "$OMARCHY_INSTALL/hardware/intel/sof-firmware.sh" +# Pulls in v4l2loopback-dkms, so it sits after the Panther Lake kernel swap. +run_logged "$OMARCHY_INSTALL/hardware/fix-elgato-camlink-4k.sh" + # Rebuilds the boot image, so it has to follow the Panther Lake kernel swap # above rather than sit with the other Dell leaf at the top of this file. run_logged "$OMARCHY_INSTALL/hardware/dell-xps13-sidecar-amps.sh" diff --git a/install/hardware/fix-elgato-camlink-4k.sh b/install/hardware/fix-elgato-camlink-4k.sh new file mode 100644 index 00000000..f726fd9a --- /dev/null +++ b/install/hardware/fix-elgato-camlink-4k.sh @@ -0,0 +1,18 @@ +# Expose the Elgato Cam Link 4K as a 16:9-only virtual camera. +# Browsers ask it for 640x480, which it fills by cropping, and the 4:3 frame +# then gets stretched into a 16:9 tile. The raw node is hidden from users and +# v4l2-relayd re-exposes it at 1280x720 under the same name. + +if omarchy-hw-elgato-camlink-4k; then + mapfile -t kernel_headers < <(pacman -Qqs '^linux(-zen|-lts|-hardened|-t2|-ptl|-omarchy-bore)?$' | sed 's/$/-headers/') + omarchy-pkg-add "${kernel_headers[@]}" v4l2loopback-dkms v4l2loopback-utils v4l2-relayd + + sudo install -Dm644 "$OMARCHY_PATH/default/udev/elgato-camlink-4k.rules" /etc/udev/rules.d/71-elgato-camlink-4k.rules + sudo install -Dm644 "$OMARCHY_PATH/default/v4l2-relayd/camlink.conf" /etc/v4l2-relayd.d/camlink.conf + sudo install -Dm644 "$OMARCHY_PATH/default/systemd/system/camlink-4k-loopback.service" /etc/systemd/system/camlink-4k-loopback.service + sudo install -Dm644 "$OMARCHY_PATH/default/systemd/system/v4l2-relayd@camlink.service.d/camlink.conf" "/etc/systemd/system/v4l2-relayd@camlink.service.d/camlink.conf" + + # The module's own default device would otherwise show up in browsers as + # "Dummy video device" on machines without another relay. + echo "options v4l2loopback exclusive_caps=1" | sudo tee /etc/modprobe.d/v4l2loopback-exclusive-caps.conf >/dev/null +fi diff --git a/migrations/1788862626.sh b/migrations/1788862626.sh new file mode 100644 index 00000000..822d8513 --- /dev/null +++ b/migrations/1788862626.sh @@ -0,0 +1,20 @@ +echo "Expose the Elgato Cam Link 4K as a 16:9 virtual camera" + +if omarchy-hw-elgato-camlink-4k; then + source "$OMARCHY_PATH/install/hardware/fix-elgato-camlink-4k.sh" + + sudo systemctl daemon-reload + sudo udevadm control --reload + + # Re-run the rules for the Cam Link that is plugged in now so it gets hidden + # and relayed right away. The user ACL from its first plug survives a + # re-trigger, so drop it here; a replug or reboot does the same on its own. + sudo udevadm trigger --action=add --subsystem-match=video4linux + sudo udevadm settle + [[ -e /dev/camlink4k ]] && sudo setfacl -b /dev/camlink4k + + # The trigger only starts the relay when the rule is new to the device. + # Start it outright so a failed module build or loopback surfaces here, + # with the raw camera hidden, rather than passing silently. + sudo systemctl start v4l2-relayd@camlink.service +fi