Commit graph

1881 commits

Author SHA1 Message Date
8eda5c82b5 quickshell: give Archie a gallop for the ball, move his bed next to the bowl
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 13:34:20 +01:00
36360544ee quickshell: redraw Archie at 2px, fix his paws, add a throwable ball and a bed
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 13:21:13 +01:00
d53e491812 quickshell: redraw Archie smaller, with proper tan markings and a dachshund head
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 13:02:02 +01:00
e11d6d4e57 quickshell: Archie
A black and tan dachshund who lives along the bottom of the screen, with a
bowl he visits for a snack.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 12:42:40 +01:00
9b43f5f669 quickshell: panels launch the worm instead of turning him around
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 11:27:04 +01:00
bdb3ab0c75 quickshell: fling the worm when a panel pops out on top of him
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 11:14:09 +01:00
25819bd901 quickshell: flat head and tail past the hoop, solid panels, drop card knock-off
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 10:50:56 +01:00
75a31a7695 quickshell: inchworm gait, and the dropdown outline is what shoves him
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 10:21:43 +01:00
3eb1d242fa quickshell: worm rides the frame rail, falling cards knock him off it
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 10:01:49 +01:00
535fe56b76 quickshell: fix worm never appearing (var array reassign emits no notify)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 09:37:16 +01:00
4626e72219 quickshell: add a pixel worm and middle-click-to-knock-cards-off
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 08:30:09 +01:00
forgejo-actions[bot]
e39be67887 Update flake inputs 2026-08-04 04:00:46 +00:00
86640f5d7f quickshell: ramp nightlight across twilight instead of snapping at sunset
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 22:44:09 +01:00
6937279290 zen/vesktop: tint surfaces off base00 too, dropping the purple popups
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 20:36:32 +01:00
bc10b078c6 mediaserver-vm: offset forwarded host ports to avoid live services
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 14:08:54 +01:00
5da80e8f8f repo: drop stray HEAD worktree committed by mistake
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 14:07:54 +01:00
0235bc9875 flake: add mediaserver-vm host for testing services from scratch
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 14:07:34 +01:00
11f73e9e6a launcher: search ~/Documents and ~/Downloads, not all of $HOME
Searching $HOME buried real results under game assets and nixos config
files. A missing root is harmless: fd reports it on stderr, which nothing
reads, and still searches the rest at exit 0.
2026-08-03 12:24:16 +01:00
99525c98ed quickshell: drop the focus grab before activating a notification's window
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 10:39:53 +01:00
3d5ecb7b98 quickshell: notification click/action jumps to the app's window
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 10:34:15 +01:00
5aea7fab27 gtk: tint surfaces off base00 like the shell, not stylix's off-hue base01
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 10:18:09 +01:00
forgejo-actions[bot]
eca4f6deec Update flake inputs 2026-08-03 04:00:42 +00:00
17d8ba0b1a launcher: answer weather queries from open-meteo instead of the LLM
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 11:39:47 +01:00
748a345ea9 qs-ask: log outcomes to journal; launcher: spinner while Claude answers
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 11:27:08 +01:00
ba9558ba30 qs-ask: answer bare keyword queries instead of replying UNKNOWN
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 10:46:55 +01:00
9f63f2f55d desktop: tell GTK3 to prefer dark so nemo dialogs stop using light theme
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 09:58:50 +01:00
forgejo-actions[bot]
f002f4169b Update flake inputs 2026-08-02 04:00:47 +00:00
a026589ca2 stylix: match folder colour against papirus' real fills, not material hexes
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 22:47:26 +01:00
6649253aa7 desktop: drop adwaita icon themes, papirus is the active theme
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 22:34:19 +01:00
992cf8cb2e Add protonplus 2026-08-01 22:29:01 +01:00
946c631f2a hosts: drop duplicate adwaita-icon-theme (desktop.nix already installs it)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 22:25:01 +01:00
7d1f7b5db6 quickshell: launcher header with nix logo and user@host
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 22:05:09 +01:00
dcfc7f9573 Revert the launcher focus-grab fix attempts
None of them worked. quickshell.nix is back to a8eb767 apart from the
hidden-directory search change, which was a separate request and does
work. Removed: the toggle/grab/compositor-event logging, the grab re-arm,
and the full-screen input mask with its click catcher.

Kept the Battle.net window rule's class match (steam_app_0 was stale, and
the tray-icon rule below it needs the widened match), but its comment no
longer claims to fix the launcher.

Recorded the diagnosis at the focus grab so this doesn't get re-derived:
Hyprland's mouseMoveUnified() destroys the seat grab on any refocus()
while the cursor is over a surface the grab doesn't own, and every window
map/unmap calls refocus(). No user input involved, nothing to suppress.
2026-08-01 21:43:08 +01:00
59c1b10334 quickshell: own the pointer while a panel is open
Real cause of the launcher dying ~1ms after opening. Hyprland's
mouseMoveUnified() destroys the seat grab when it refocuses while the
cursor is over a surface the grab doesn't own, and `refocus` is true for
all 20 CInputManager::refocus() call sites — including every window map
and unmap. Battle.net churns windows continuously, so refocus() fired
over and over and killed the grab unless the cursor happened to be on the
bar. That is also why clicking a bar card "fixed" it.

Expand the input mask to the whole screen while a panel is open, so
accepts() is always true and nothing can tear the grab down. The grab no
longer sees outside clicks, so a MouseArea underneath the panels handles
dismissal. Drop the re-arm: it lost to the next refocus() every time.
2026-08-01 21:32:09 +01:00
a8d7d8ca64 quickshell: survive Hyprland dropping the focus grab
Hyprland 0.55.4 CXDGShellProtocol::onPopupDestroy() calls
setGrab(nullptr) unconditionally when the popup owning the xdg-popup grab
dies, without checking that grab is still the installed one. So opening
the launcher while some app holds a grabbing popup steals the seat grab,
that popup gets popup_done, the client destroys it, and its destructor
clears OUR grab — one client round trip later, measured at 1-2ms.

A clear that fast is not a click-outside, so re-arm instead of closing.
The offending popup is gone by then, so the second grab sticks. Capped at
3 tries so a hostile client can't spin it.
2026-08-01 21:16:37 +01:00
a040997551 quickshell: fix the trace hiding the event it was added to catch
The rawEvent gate keyed off launcherPanel.open, but the focus-grab clear
sets open=false before Hyprland's IPC event arrives, so the compositor
event around each clear was filtered out — the log came back empty. Key
off a timestamp instead, and report who holds focus when the grab clears.
2026-08-01 20:58:18 +01:00
b57c06da5e quickshell: trace compositor events while a panel is open
The Battle.net window rule didn't fix the launcher dying on open, so log
Hyprland's own event stream between `launcher toggle -> open` and
`focusgrab cleared` to see what actually takes focus. Gated on a panel
being open. Diagnostic — remove once the cause is known.
2026-08-01 20:40:39 +01:00
1e30a9017b hyprland: fix Battle.net activation rule matching a stale class
Battle.net now maps as steam_app_default, not steam_app_0, so the
suppress_event rule stopped applying — its activation spam clears
quickshell's focus grab, which kills the launcher in the same frame it
opens. Match either class; same for the tray-icon rule.
2026-08-01 20:32:23 +01:00
f436389ad7 quickshell: click a notification to jump to its app
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 20:29:19 +01:00
bcd685f3e3 quickshell: skip hidden dirs in file search, log launcher opens
fd drops --hidden, so ~/.cache, ~/.local/share/Steam, .git trees and
friends are out of the search entirely — most of the files under $HOME
and none of them worth matching by name. The .git/.cache/.steam excludes
go with it; node_modules is the one junk tree that isn't hidden.

Also log the three points that can swallow a Super+R: the IPC handler
when no bar is registered, the toggle itself, and the focus grab closing
a panel the user didn't close. journalctl --user -u quickshell.
2026-08-01 20:26:55 +01:00
a8eb76782c quickshell: stop launcher rows fading to random opacities
The results ListView had add/remove transitions animating opacity and
scale on the delegate root. The model is re-diffed on every keystroke, so
a row part-way through a fade frequently survived the next pass as a move
instead of a remove — and move animates x,y only, leaving the
half-finished opacity permanently unrestored. Rows accumulated stuck at
arbitrary opacities depending on typing speed, which read as the result
colours randomly fading.

Dropped both fades. x,y stay animated because the view re-asserts them on
every layout, so an interrupted slide self-corrects; opacity and scale
have no such backstop. Comment records that a future fade belongs on a
child item, not the root the view recycles.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 19:42:37 +01:00
4b4ae52c65 quickshell: fix pinned tiles never launching
launchPin passed a bare DesktopEntry to activate(), but activate()
started dispatching on a `kind` field when the results list became
heterogeneous (apps + files + web). A bare entry has no `kind`, so every
pin click fell through to the no-op branch: the tiles rendered, hovered
and dragged correctly and simply never launched. Regression from
"launcher searches files and the web".

Wrap via appItem() so the pin takes the same path as a search result, and
make activate()'s fallthrough console.warn instead of returning quietly —
the silence is the only reason this survived a release.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 19:32:31 +01:00
a927cf6ba9 qs-ask: name the session to drop a redundant API call
Profiled the second model call visible in modelUsage: it is
`source=generate_session_title`, inventing a title for a session that
--no-session-persistence immediately discards. It costs no wall time —
both requests dispatch ~1ms apart and run concurrently, which is why
duration_api_ms was roughly double duration_ms — but it spent 507 input
tokens against 153 for the actual question.

--name qs-ask removes it: one request instead of two, 660 input tokens
down to 153 per question. No latency change, 77% less input token spend,
which is what actually matters when the budget is a subscription rate
limit rather than a bill.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 17:56:36 +01:00
aee59ff0b2 qs-ask: disable thinking — 2.4x faster, same answers
Profiled where the ~6s actually went, and it was not where I assumed.
Haiku defaults to extended thinking, so it spent 225 output tokens and
1.9s deliberating before emitting an 80-character answer about the height
of a tower. MAX_THINKING_TOKENS=0: 43 output tokens, time-to-first-text
2657ms -> 1122ms, wall clock 5.7s -> ~2.4s, answer unchanged.

Two things measured NOT to be the bottleneck, recorded in the comment so
nobody optimises them later: process startup (0.12s boot plus 28ms to
fire the request, so a warm/persistent process saves nothing) and prompt
size (184 input tokens, no bloat to trim).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 17:49:44 +01:00
309c54d31b qs-ask: answer via Claude Code on the subscription, not an API key
No API key and no separate billing: qs-ask now shells out to `claude -p`,
which draws on the existing subscription already authenticated on this
host. The trade is latency — Claude Code boots a Node process per
question, ~6s measured against the raw API's ~1s — so the launcher now
races Wikipedia and Claude instead of chaining them. Wikipedia fills the
card in under a second and Claude supersedes it on arrival; chaining
would have left the card blank for six seconds on every question.

Isolation, verified: --safe-mode drops CLAUDE.md, skills, hooks, plugins
and MCP while leaving auth working, which matters for correctness and not
just speed — the global CLAUDE.md here asks for caveman-mode replies and
that would have leaked into answers. --no-session-persistence writes no
transcript, and a dedicated empty cwd keeps launcher questions out of any
project's history or auto-memory. Confirmed no project namespace, no
transcript and no memory write after a run.

Not --bare, which looks right and is a trap: its auth is strictly
ANTHROPIC_API_KEY, so it cannot use the subscription at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 17:34:50 +01:00
dbed82bab4 qs-ask: report why it went quiet on stderr
Silence on stdout is the launcher's fall-back-to-Wikipedia signal, so it
has to stay clean — but that made a misconfigured key indistinguishable
from a working fallback. Every reason now prints on stderr, which the
launcher discards and a human running qs-ask by hand can read.

Drops curl -f so a 4xx body's own error message ("API key is invalid.")
surfaces instead of just an exit code, and guards the specific mistake of
pasting the sk-ant-... placeholder literally.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 17:21:05 +01:00
958dc9b333 quickshell: Claude-backed launcher answers via the mediaserver
Adds qs-ask on the mediaserver — the Anthropic key lives there and nowhere
else, so neither desktop holds a credential and there's one place to
rotate it. The launcher pipes the question over the same SSH path the
server monitor already uses; the query goes over stdin because
`ssh host cmd arg` would re-parse arg through the remote shell.

Claude answers first, Wikipedia is the fallback. The script is the
feature gate: with no key it exits silently, which is the same signal as
a failed call or an UNKNOWN reply, so the Wikipedia path stays the
default with zero configuration. The card names whichever answered.

Haiku 4.5, no thinking and no effort (effort errors on Haiku) — a
one-sentence fact needs no reasoning tokens. ~$0.0005 per query.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 17:14:04 +01:00
5c3d84d0c9 quickshell: answer "where"/"when"/"who" questions, pick the right article
"where is K2" had no scoring signal at all — "where" is a stopword and
"k2" fell under the 3-char term floor, so every sentence tied at zero and
the card fell back to the opening line. Fixes:

- answer-type hints: a "where" question scores sentences carrying the
  vocabulary of place, "when" of dates, "who" of attribution. Stems, not
  whole words — the Telephone intro says "granted a United States
  patent", never "invented". "is a"/"was a" deliberately excluded, since
  they match the definitional opening of every article.
- term floor down to 2 chars so "K2" and "UK" count.
- fetch 3 candidates and choose: an exact title match wins, and a
  disambiguated title loses unless the query asked for that sense.
  Search rank alone put "Chernobyl (miniseries)" above the city.

Verified 11/11 on live responses by running the generated QML functions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 16:26:10 +01:00
95637d91c8 quickshell: instant answers in the launcher
Wikipedia search+extract in one request gives the article for a
natural-language query, then the intro's sentences are ranked so the card
leads with the one that actually answers: +3 per query term, +4 for a
digit when a number was asked for, ties to the earliest sentence. Title
words are dropped from the terms unless they're the attribute asked
about, which is what makes "mount everest height" return 8,848.86 m
instead of a sentence restating the subject.

Fires on a 600ms debounce, only for query shapes that aren't app
searches, cached per query — Wikipedia throttles bursts, so restraint is
correctness here. Every triggered query goes to Wikipedia.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 16:06:00 +01:00
03fda2a6bb quickshell: launcher searches files and the web
Results become one flat list — apps, then files, then a web fallback —
so a single set of arrow keys walks all of it and activate() dispatches
on the item kind.

Files come from one fd run per settled keystroke, scoped to $HOME and
capped with --max-results so fd exits as soon as it has enough; no index
and no daemon, so nothing is ever stale. Spaces in the query become
gaps ("report 2024" finds report-2024.pdf) and regex metacharacters are
escaped so a query can't make fd bail.

Web row is last and always there, with bangs (!yt !gh !no !np !w) to
retarget it. Suppressed for arithmetic so Enter keeps copying the sum.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 15:45:43 +01:00