quickshell: DIAGNOSTIC hide chrome SDF to measure its GPU cost
This commit is contained in:
parent
389d7a5d65
commit
9d4b1f8c93
1 changed files with 208 additions and 8 deletions
|
|
@ -1,10 +1,56 @@
|
|||
# settings/quickshell.nix — Quickshell desktop shell (bar, notifications, QML),
|
||||
# split out of settings/hyprland.nix. The hyprland-side blur layer rule for
|
||||
# the "quickshell-bar" namespace still lives there.
|
||||
{ config, pkgs, lib, ... }:
|
||||
{ config, pkgs, lib, inputs, ... }:
|
||||
let
|
||||
isMacbook = config.networking.hostName == "FredOS-Macbook";
|
||||
ui = import ./ui.nix; # shared corner-rounding knob
|
||||
|
||||
# ── Wallpaper set ──────────────────────────────────────────────────────
|
||||
# Every image in walls/ gets its own dark base16 palette, generated at
|
||||
# build time by stylix's own palette-generator. The shell picks one at
|
||||
# RUNTIME (state file + FileView in Theme.qml), so switching wallpaper
|
||||
# re-tints the whole shell without a rebuild.
|
||||
#
|
||||
# One derivation per image, not one for the set: palette generation is a
|
||||
# genetic search that takes seconds, and per-image derivations mean adding
|
||||
# a wallpaper only regenerates the new one. builtins.path hashes the image
|
||||
# content alone, so unrelated repo edits don't invalidate any of them.
|
||||
paletteGenerator =
|
||||
inputs.stylix.packages.${pkgs.stdenv.hostPlatform.system}.palette-generator;
|
||||
|
||||
wallFiles = builtins.attrNames (lib.filterAttrs
|
||||
(n: t: t == "regular"
|
||||
&& lib.any (e: lib.hasSuffix e (lib.toLower n)) [ ".png" ".jpg" ".jpeg" ])
|
||||
(builtins.readDir (inputs.self + "/walls")));
|
||||
|
||||
# Store names allow a narrow charset, filenames don't. Keep wallpaper
|
||||
# names plain — a space survives, anything more exotic may not.
|
||||
wallStem = f: lib.head (lib.splitString "." f);
|
||||
wallSlug = f: lib.replaceStrings [ " " ] [ "-" ] (wallStem f);
|
||||
wallImage = f: builtins.path {
|
||||
name = "wall-" + lib.replaceStrings [ " " ] [ "-" ] f;
|
||||
path = inputs.self + "/walls/${f}";
|
||||
};
|
||||
wallPalette = f: pkgs.runCommand "palette-${wallSlug f}" { } ''
|
||||
mkdir -p $out
|
||||
${paletteGenerator}/bin/palette-generator dark ${wallImage f} $out/palette.json
|
||||
'';
|
||||
|
||||
# The list Theme.qml carries verbatim. Naming the store paths inside a
|
||||
# home-manager file keeps both image and palette alive as generation
|
||||
# references — no extra gcroot needed.
|
||||
wallsJson = builtins.toJSON (map (f: {
|
||||
name = wallStem f;
|
||||
image = "${wallImage f}";
|
||||
palette = "${wallPalette f}/palette.json";
|
||||
}) wallFiles);
|
||||
|
||||
# Falls back to walls/wallpaper.png — the one stylix themes everything
|
||||
# else from — so a missing state file lands on the build-time scheme.
|
||||
defaultWall = if lib.elem "wallpaper" (map wallStem wallFiles)
|
||||
then "wallpaper"
|
||||
else wallStem (lib.head wallFiles);
|
||||
in
|
||||
{
|
||||
config = lib.mkIf (lib.elem config.networking.hostName [ "FredOS-Gaming" "FredOS-Macbook" ]) {
|
||||
|
|
@ -383,25 +429,74 @@ in
|
|||
onChange = qsRestart;
|
||||
text = ''
|
||||
pragma Singleton
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
id: theme
|
||||
|
||||
// ── Wallpapers ─────────────────────────────────────────
|
||||
// Built in settings/quickshell.nix: one entry per image in
|
||||
// walls/, each with a dark base16 palette generated from it.
|
||||
readonly property var walls: ${wallsJson}
|
||||
|
||||
// Which one is live. Persisted so the choice survives a
|
||||
// reboot; every colour below is a binding on `pal`, so
|
||||
// writing this file re-tints the entire shell in place.
|
||||
property FileView wallFile: FileView {
|
||||
path: Quickshell.env("HOME") + "/.local/state/quickshell-wallpaper.json"
|
||||
printErrors: false
|
||||
// Synchronous: the palette load chains off this, and an
|
||||
// async hop here means one frame painted in the wrong
|
||||
// scheme on every startup.
|
||||
blockLoading: true
|
||||
adapter: JsonAdapter {
|
||||
id: wallState
|
||||
property string name: "${defaultWall}"
|
||||
}
|
||||
onLoadFailed: writeAdapter()
|
||||
}
|
||||
|
||||
// Unknown name (wallpaper deleted from the repo since it was
|
||||
// picked) falls back to the first entry rather than blanking.
|
||||
readonly property var currentWall:
|
||||
walls.find(w => w.name === wallState.name) || walls[0] || null
|
||||
readonly property string wallImage: currentWall ? currentWall.image : ""
|
||||
|
||||
function setWall(name) {
|
||||
wallState.name = name;
|
||||
wallFile.writeAdapter();
|
||||
}
|
||||
|
||||
property var pal: ({})
|
||||
property FileView palFile: FileView {
|
||||
path: theme.currentWall ? theme.currentWall.palette : ""
|
||||
printErrors: false
|
||||
blockLoading: true
|
||||
onLoaded: theme.pal = JSON.parse(text())
|
||||
}
|
||||
|
||||
// ── Surfaces: one hue, three steps. base01/base02 are tints of
|
||||
// base00 rather than stylix's own base01/base02, which come
|
||||
// straight off the wallpaper and routinely land off-hue — a
|
||||
// purple card floating over a slate bar. Tinting keeps
|
||||
// bar → card → hover reading as one stack. Two numbers, and
|
||||
// they are the whole surface ladder.
|
||||
readonly property color base00: "#${c.base00}"
|
||||
//
|
||||
// The "#${c.base00}" fallbacks are stylix's build-time scheme
|
||||
// (walls/wallpaper.png): what shows for the frame or two
|
||||
// before palFile lands, and if a palette file ever goes bad.
|
||||
readonly property color base00: "#" + (pal.base00 || "${c.base00}")
|
||||
readonly property color base01: Qt.lighter(base00, 1.7) // card
|
||||
readonly property color base02: Qt.lighter(base00, 2.4) // hover / chip / track
|
||||
// ── Ink, wallpaper-derived: base05 primary, base04 muted,
|
||||
// base03 disabled (also the border colour).
|
||||
readonly property color base03: "#${c.base03}"
|
||||
readonly property color base04: "#${c.base04}"
|
||||
readonly property color base05: "#${c.base05}"
|
||||
readonly property color base03: "#" + (pal.base03 || "${c.base03}")
|
||||
readonly property color base04: "#" + (pal.base04 || "${c.base04}")
|
||||
readonly property color base05: "#" + (pal.base05 || "${c.base05}")
|
||||
// The one themed accent: active, focused, selected, filled.
|
||||
readonly property color base0D: "#${c.base0D}"
|
||||
readonly property color base0D: "#" + (pal.base0D || "${c.base0D}")
|
||||
|
||||
// ── Status colours: fixed hues, pulled toward the theme.
|
||||
// Sourcing these from stylix doesn't work — base08-base0F all
|
||||
|
|
@ -538,7 +633,7 @@ in
|
|||
Image {
|
||||
id: wall
|
||||
anchors.fill: parent
|
||||
source: "file://" + Quickshell.env("HOME") + "/.local/share/backgrounds/wallpaper.png"
|
||||
source: "file://" + Theme.wallImage
|
||||
// cache:false — soft reload (qs ipc reload) keeps the process
|
||||
// alive, and the QML pixmap cache is keyed by URL, so a new
|
||||
// wallpaper behind the same path never shows without this.
|
||||
|
|
@ -1485,7 +1580,7 @@ in
|
|||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: "file://" + Quickshell.env("HOME") + "/.local/share/backgrounds/wallpaper.png"
|
||||
source: "file://" + Theme.wallImage
|
||||
cache: false // same-URL pixmap cache survives soft reload
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
}
|
||||
|
|
@ -1947,6 +2042,9 @@ in
|
|||
// ears / border-gaps / melt geometry lives in the math now.
|
||||
ShaderEffect {
|
||||
id: chromeSdf
|
||||
// DIAGNOSTIC ONLY — revert. Measuring how much of the
|
||||
// shell's idle GPU cost is this full-screen SDF pass.
|
||||
visible: false
|
||||
anchors.fill: parent
|
||||
// Panels grow rightward out of the bar column, so the
|
||||
// cross-axis is now vertical: the 8px inset that used to
|
||||
|
|
@ -3833,6 +3931,36 @@ in
|
|||
}
|
||||
}
|
||||
|
||||
BarSep {}
|
||||
|
||||
// Wallpaper picker. Sits under the workspaces because it
|
||||
// grows downward with them — the mid/bottom clusters
|
||||
// anchor from the other end and never move.
|
||||
Item {
|
||||
id: wallBtn
|
||||
width: Theme.barWidth
|
||||
height: 24
|
||||
|
||||
SIcon {
|
||||
anchors.centerIn: parent
|
||||
text: "image"
|
||||
font.pixelSize: 18
|
||||
color: bar.activeDropdown === wallDropdown ? Theme.base0D
|
||||
: wallMa.containsMouse ? Theme.base05 : Theme.base04
|
||||
Behavior on color { ColorAnimation { duration: Theme.animFade } }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: wallMa
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: bar.toggleDropdown(wallDropdown, function() {
|
||||
let pos = wallBtn.mapToItem(bar.contentItem, 0, wallBtn.height / 2);
|
||||
wallDropdown.dropdownY = pos.y;
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── Mid cluster: the server glance, pinned just above the
|
||||
|
|
@ -4992,6 +5120,78 @@ in
|
|||
}
|
||||
}
|
||||
|
||||
// Wallpaper picker — thumbnail grid. Clicking a tile writes
|
||||
// the state file, which re-binds Theme's whole palette: the
|
||||
// wallpaper, the bar and every open panel re-tint together,
|
||||
// no rebuild and no restart.
|
||||
BarDropdown {
|
||||
id: wallDropdown
|
||||
fullWidth: wallCard.width + 2 * Theme.panelGap
|
||||
fullHeight: wallCard.height + 2 * Theme.panelGap
|
||||
|
||||
Rectangle {
|
||||
id: wallCard
|
||||
anchors.centerIn: parent
|
||||
width: wallGrid.width + 2 * Theme.cardPad
|
||||
height: wallGrid.height + 2 * Theme.cardPad
|
||||
radius: Theme.radiusCard
|
||||
color: Theme.cardBg
|
||||
|
||||
Grid {
|
||||
id: wallGrid
|
||||
anchors.centerIn: parent
|
||||
// Two up: a 16:9 thumb wide enough to recognise
|
||||
// still leaves the panel narrower than the
|
||||
// launcher, and the column stays short.
|
||||
columns: 2
|
||||
spacing: 6
|
||||
|
||||
Repeater {
|
||||
model: Theme.walls
|
||||
|
||||
ClippingRectangle {
|
||||
id: wallTile
|
||||
required property var modelData
|
||||
readonly property bool active:
|
||||
Theme.currentWall && Theme.currentWall.name === modelData.name
|
||||
|
||||
width: 124
|
||||
height: 70
|
||||
radius: Theme.radiusTiny
|
||||
color: Theme.base01
|
||||
// Accent ring on the live one, base04 on
|
||||
// hover — same selection language as the
|
||||
// workspace pill above it.
|
||||
border.width: Theme.borderWidth
|
||||
border.color: active ? Theme.base0D
|
||||
: wallTileMa.containsMouse ? Theme.base04
|
||||
: "transparent"
|
||||
Behavior on border.color { ColorAnimation { duration: Theme.animFade } }
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: "file://" + wallTile.modelData.image
|
||||
// Decode at thumbnail size: the full
|
||||
// 4K texture per tile is what makes a
|
||||
// picker like this cost real VRAM.
|
||||
sourceSize.width: 248
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: wallTileMa
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: Theme.setWall(wallTile.modelData.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Volume dropdown
|
||||
// Server monitor dropdown — the btop-at-a-distance view.
|
||||
BarDropdown {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue