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),
|
# settings/quickshell.nix — Quickshell desktop shell (bar, notifications, QML),
|
||||||
# split out of settings/hyprland.nix. The hyprland-side blur layer rule for
|
# split out of settings/hyprland.nix. The hyprland-side blur layer rule for
|
||||||
# the "quickshell-bar" namespace still lives there.
|
# the "quickshell-bar" namespace still lives there.
|
||||||
{ config, pkgs, lib, ... }:
|
{ config, pkgs, lib, inputs, ... }:
|
||||||
let
|
let
|
||||||
isMacbook = config.networking.hostName == "FredOS-Macbook";
|
isMacbook = config.networking.hostName == "FredOS-Macbook";
|
||||||
ui = import ./ui.nix; # shared corner-rounding knob
|
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
|
in
|
||||||
{
|
{
|
||||||
config = lib.mkIf (lib.elem config.networking.hostName [ "FredOS-Gaming" "FredOS-Macbook" ]) {
|
config = lib.mkIf (lib.elem config.networking.hostName [ "FredOS-Gaming" "FredOS-Macbook" ]) {
|
||||||
|
|
@ -383,25 +429,74 @@ in
|
||||||
onChange = qsRestart;
|
onChange = qsRestart;
|
||||||
text = ''
|
text = ''
|
||||||
pragma Singleton
|
pragma Singleton
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
|
||||||
QtObject {
|
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
|
// ── Surfaces: one hue, three steps. base01/base02 are tints of
|
||||||
// base00 rather than stylix's own base01/base02, which come
|
// base00 rather than stylix's own base01/base02, which come
|
||||||
// straight off the wallpaper and routinely land off-hue — a
|
// straight off the wallpaper and routinely land off-hue — a
|
||||||
// purple card floating over a slate bar. Tinting keeps
|
// purple card floating over a slate bar. Tinting keeps
|
||||||
// bar → card → hover reading as one stack. Two numbers, and
|
// bar → card → hover reading as one stack. Two numbers, and
|
||||||
// they are the whole surface ladder.
|
// 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 base01: Qt.lighter(base00, 1.7) // card
|
||||||
readonly property color base02: Qt.lighter(base00, 2.4) // hover / chip / track
|
readonly property color base02: Qt.lighter(base00, 2.4) // hover / chip / track
|
||||||
// ── Ink, wallpaper-derived: base05 primary, base04 muted,
|
// ── Ink, wallpaper-derived: base05 primary, base04 muted,
|
||||||
// base03 disabled (also the border colour).
|
// base03 disabled (also the border colour).
|
||||||
readonly property color base03: "#${c.base03}"
|
readonly property color base03: "#" + (pal.base03 || "${c.base03}")
|
||||||
readonly property color base04: "#${c.base04}"
|
readonly property color base04: "#" + (pal.base04 || "${c.base04}")
|
||||||
readonly property color base05: "#${c.base05}"
|
readonly property color base05: "#" + (pal.base05 || "${c.base05}")
|
||||||
// The one themed accent: active, focused, selected, filled.
|
// 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.
|
// ── Status colours: fixed hues, pulled toward the theme.
|
||||||
// Sourcing these from stylix doesn't work — base08-base0F all
|
// Sourcing these from stylix doesn't work — base08-base0F all
|
||||||
|
|
@ -538,7 +633,7 @@ in
|
||||||
Image {
|
Image {
|
||||||
id: wall
|
id: wall
|
||||||
anchors.fill: parent
|
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
|
// cache:false — soft reload (qs ipc reload) keeps the process
|
||||||
// alive, and the QML pixmap cache is keyed by URL, so a new
|
// alive, and the QML pixmap cache is keyed by URL, so a new
|
||||||
// wallpaper behind the same path never shows without this.
|
// wallpaper behind the same path never shows without this.
|
||||||
|
|
@ -1485,7 +1580,7 @@ in
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
anchors.fill: parent
|
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
|
cache: false // same-URL pixmap cache survives soft reload
|
||||||
fillMode: Image.PreserveAspectCrop
|
fillMode: Image.PreserveAspectCrop
|
||||||
}
|
}
|
||||||
|
|
@ -1947,6 +2042,9 @@ in
|
||||||
// ears / border-gaps / melt geometry lives in the math now.
|
// ears / border-gaps / melt geometry lives in the math now.
|
||||||
ShaderEffect {
|
ShaderEffect {
|
||||||
id: chromeSdf
|
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
|
anchors.fill: parent
|
||||||
// Panels grow rightward out of the bar column, so the
|
// Panels grow rightward out of the bar column, so the
|
||||||
// cross-axis is now vertical: the 8px inset that used to
|
// 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
|
// ── 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
|
// Volume dropdown
|
||||||
// Server monitor dropdown — the btop-at-a-distance view.
|
// Server monitor dropdown — the btop-at-a-distance view.
|
||||||
BarDropdown {
|
BarDropdown {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue