aboutsummaryrefslogtreecommitdiffstats
path: root/window-switcher
AgeCommit message (Collapse)AuthorFilesLines
8 daysdocs: the expose and its hot cornerDanilo M.1-37/+81
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8 daysfeat(window-switcher): the expose replaces the grid, with a hot cornerDanilo M.4-134/+202
Previews are placed at their Expose.js rects and sized to them, so each keeps its window's shape and relative size. Title and close show on hover only, so the scatter stays clean; icon and workspace marker always show. The keyboard selection is gone: this is a pointer feature, and Escape is the one key left. The top-right corner of DP-1 opens it after a 250ms glow that grows out of the corner, which is the warning and the way out. Input is only the corner's 2x2 pixels, since a larger input region would eat clicks on the windows below. It re-arms only when the pointer leaves while the expose is closed, or an Escape with the pointer still in the corner reopens it. It hides while status.gaming is set, read straight from the file: linking shared/Status.qml would start a second game poll and fire presentation side effects twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8 daysfeat(window-switcher): gravity pulls the scatter toward the centreDanilo M.1-21/+38
On screen the spiral alone read as loose: separation keeps the spiral's gaps, and the previews filled 24 to 30% of the screen. Thirty rounds now pull every window 15% closer to the centre and push them apart again, which fills 35 to 55% and makes each preview up to 1.5x larger. Twenty windows lay out in about 4ms. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8 daysfeat(window-switcher): the expose scatter layoutDanilo M.2-0/+138
layout() seeds windows on a golden-angle spiral, most recent at the centre, pushes overlapping pairs apart along the axis that costs less screen, and fits the result with one scale so sizes stay relative. The spec's first seed, the windows' real positions, was prototyped and dropped: every window on this desk fills its monitor, so they started in one pile, and pushing a pile apart made a line that still overlapped after 300 passes and filled 8 to 15% of the screen. The spiral converged in 1 to 55 passes. Comparing overlaps in raw pixels stacked wide windows into a column, which is why the axis choice divides by the screen's width and height. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07docs: the island, and waybar goneDanilo M.1-7/+7
AGENTS.md describes the hybrid model (desktop/ hosts drawer and island) and gains the gotchas found while building the island: UseQApplication for tray menus, WheelHandler vs MouseArea, accent colliding with green, xkb layout switching, and the tray popup un-hovering the island. The Blur waybar measurement becomes history. READMEs drop their present-tense waybar references. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07refactor: move the workspace icon map to a shared singletonDanilo M.2-21/+4
The island's clock pill shows the same desktop icon the window switcher does. One map, symlinked into both components like Theme.qml, rather than a second copy that would drift. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-19feat(desktop): press feedback on the shared buttonsDanilo M.1-1/+4
The hand-rolled buttons only reacted to hover, so a press gave no visual confirmation until the action's outcome appeared. kdeconnect made this obvious: its row buttons shell out to kdeconnect-cli, and nothing on screen acknowledged the click. Button.qml now fills solid accent while the mouse is held (red for danger), with the label flipped to base for contrast. TransportButton gets the same treatment, and the window-switcher close button lightens on press. Toggles, tiles and tabs are left alone: their own state change is already the feedback.
2026-09-16fix(window-switcher): use a messaging icon for desktop 7Danilo M.1-1/+1
The chat/internet-chat aliases in the icon theme all resolve to an empty outlined monitor; dialog-messages is the filled speech bubble.
2026-09-16fix(window-switcher): swap the desktop 2 and 3 iconsDanilo M.1-2/+2
Desktop 2 is the editor and desktop 3 the terminal; the map had them the other way round, matching waybar's stylesheet before it was corrected.
2026-09-16feat(window-switcher): mark desktops with waybar's iconsDanilo M.3-8/+62
The card's desktop line showed the workspace number. waybar draws the same eight desktops as CSS background images keyed by number, because its format-icons takes text rather than paths; those names now live in the Windows singleton and are resolved through the active icon theme, so a theme switch follows the drawer and the bar and the switcher agree. A named workspace, or one past eight, falls back to its number, and so does an icon the active theme cannot resolve.
2026-09-16refactor(theme): read the palette from ~/.cache/udtDanilo M.1-1/+1
unified-desktop-theme moved its generated files out of ~/.cache/wal, which pywal used to own and nothing writes any more. The palette udt-accent generates is now at ~/.cache/udt/udt-palette.qml. shared/Theme.qml is the only code change; every component reaches it through a symlink. The module READMEs cite the path, so they move with it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12docs(window-switcher): write down what the build cost to learnDanilo M.1-0/+151
The component is finished and on the user's ALT+TAB, so what is left is the part that would otherwise have to be rediscovered. Most of the time this build took went to three things that report success and then do nothing: Hyprland 0.56.2 evaluating dispatch arguments as Lua, so the documented-looking `focuswindow address:0x...` is a silent syntax error; a focus dispatched while the overlay still holds an exclusive keyboard grab being accepted and ignored; and a sort on a `focusHistoryID` property that does not exist, comparing NaN and leaving an arbitrary order that looks plausible. None of them logs anything. Those six, plus the missing `0x` prefix, the empty `toplevels` before `refreshToplevels()` and `ScreencopyView` reporting (-1, -1) rather than (0, 0), generalise past this component, so they go in AGENTS.md next to the other notes that exist because a commit message explained itself once. The card geometry and the blank icon square are specific to the grid and stay in the component README. Also corrects the counts that four components made true and five do not: the component lists, "the other three use ExclusionMode.Ignore", and the Theme symlink note. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SYg4wYHq5XNbiVmMeKRb1S
2026-09-12fix(window-switcher): namespace it like the other fourDanilo M.1-1/+1
The layer surface announced itself as window-switcher, while the other components all use a quickshell- prefix and the blur rules in decorations.lua match on it. A rule for the odd one out would have been the only one in that file matching a bare name, so the component matches the convention instead. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SYg4wYHq5XNbiVmMeKRb1S
2026-09-12fix(window-switcher): focus after the overlay is really goneDanilo M.1-4/+25
Picking a window focused nothing, and focus returned to whatever had it before. The overlay holds keyboard focus exclusively, and the compositor will not move window focus out from under that grab: the dispatch is accepted, reports ok, and is then ignored. Nothing in the log says so, which is why this looked like a dispatch that had worked. Closing first in the same turn is not enough either, because close() only clears a property and the layer surface survives until the frame after, so the dispatch still lands inside the grab. The target is now remembered and focused once the surface is actually gone. Tested in both directions, since the case that exposed it was cross-monitor: DP-1 to a window on DP-3, and back. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SYg4wYHq5XNbiVmMeKRb1S
2026-09-12fix(window-switcher): clamp the card size by height tooDanilo M.1-1/+12
Only the width was clamped, so rows were free to run off the top and bottom of the screen. A centred Grid has no way to scroll to a card that lands there, so the cards were unreachable rather than merely cramped: at 19 windows on a 1080-tall screen the fourth row was clipped, and it grew worse from there. Cards now shrink to fit the available height as well, which leaves every count up to 18 exactly as it was, since the width term still wins there. Thirty windows fit in 995px. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SYg4wYHq5XNbiVmMeKRb1S
2026-09-12feat(window-switcher): the grid, the selection, and an empty stateDanilo M.1-8/+100
Columns are the window count capped at six and the grid centres, so one card sits dead centre and two straddle the middle. Cards grow to fill their row up to 640px: without a ceiling a lone preview becomes a full-screen mirror of the window it stands for. The close button leaves the overlay open, because closing is a side errand and a dismissal would mean reopening to close a second window. That makes an empty overlay reachable by closing the last window, so there is an empty state rather than a full-screen dim with nothing in it, which reads as a hang. The selection needs no reset. The LazyLoader destroys the overlay on close and constructs a new one on the next opening, verified with a build counter: two openings, two constructions. selectedIndex is therefore 0 on every showing by initialisation, and an explicit assignment in Component.onCompleted would be a no-op. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SYg4wYHq5XNbiVmMeKRb1S
2026-09-12feat(window-switcher): one card, with the preview fittedDanilo M.1-0/+136
The card box is a fixed 16:10 and the preview is fitted inside it rather than the card taking its preview's shape. DP-1 windows are near 21:9 and DP-3 reports transform=1, so its windows are portrait 9:16: a 4.4x span of aspect ratio in one grid, and ragged rows would break the alignment of the three text lines that make it scannable. Both corner overlays carry a scrim. They are drawn over an arbitrary window, so a themed icon can otherwise land on a same-coloured region and disappear. An uncaptured ScreencopyView reports sourceSize (-1, -1) rather than (0, 0), so the aspect ratio guard tests for a positive height. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SYg4wYHq5XNbiVmMeKRb1S
2026-09-12feat(window-switcher): the window model, filtered and sortedDanilo M.1-0/+67
One place for everything that touches Hyprland, so the UI never issues a dispatch itself. That matters more than usual here because dispatch arguments are Lua on 0.56.2 and the documented-looking form is a syntax error that fails silently, and because HyprlandToplevel.address omits the 0x prefix that a dispatch needs. focusHistoryID is not a HyprlandToplevel property, only a field of the raw hyprctl object, so reading it directly returned undefined and left the sort a no-op. It is read through lastIpcObject, with a missing one sorting last rather than as most recent. Only special: workspaces are filtered, matching the rofi script this replaces. Windows elsewhere are kept whatever their visibility, since jumping to another desktop is the point of a switcher. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SYg4wYHq5XNbiVmMeKRb1S
2026-09-12fix(window-switcher): pick the screen the way the other components doDanilo M.1-1/+4
The screen was found by a name written inline, falling back to null. The other three panels all take a monitor property and fall back to screens[0], so this now does too: a machine without a DP-1 gets its first monitor rather than a null screen, and the name is in one place if it ever needs changing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SYg4wYHq5XNbiVmMeKRb1S
2026-09-12feat(window-switcher): the overlay skeleton, and a proven EscapeDanilo M.3-0/+109
A fifth component, so the same keepalive window as the other four: a config with no visible window exits without reporting anything, and this overlay is hidden almost always. Escape is handled on a focused Item inside the PanelWindow rather than on the window, because key events reach a focused item and Keys.onEscapePressed on a PanelWindow never fires. Proven before the grid is built on top of it, since keyboard navigation depends on the same grab. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SYg4wYHq5XNbiVmMeKRb1S