updated quickshell
This commit is contained in:
@@ -25,7 +25,7 @@ Rectangle {
|
||||
model: root.menuName === "File" ? [
|
||||
{ text: "New Window", shortcut: "⌘N", cmd: "foot &" },
|
||||
{ text: "New Incognito Window", shortcut: "⇧⌘N", cmd: "brave --incognito &" },
|
||||
{ text: "Close Window", shortcut: "⌘W", cmd: "hyprctl dispatch killactive" },
|
||||
{ text: "Close Window", shortcut: "⌘W", cmd: "hyprctl dispatch \"hl.dsp.window.close()\"" },
|
||||
{ text: "---", shortcut: "", cmd: "" },
|
||||
{ text: "Take Screenshot", shortcut: "⇧⌘5", cmd: "grim -g \"$(slurp)\" ~/screenshot.png" }
|
||||
] : []
|
||||
@@ -49,9 +49,9 @@ Rectangle {
|
||||
// VIEW MENU
|
||||
Repeater {
|
||||
model: root.menuName === "View" ? [
|
||||
{ text: "Toggle Fullscreen", shortcut: "⌃⌘F", cmd: "hyprctl dispatch fullscreen 0" },
|
||||
{ text: "Toggle Floating", shortcut: "⌘V", cmd: "hyprctl dispatch togglefloating" },
|
||||
{ text: "Toggle Group", shortcut: "⌘G", cmd: "hyprctl dispatch togglegroup" },
|
||||
{ text: "Toggle Fullscreen", shortcut: "⌃⌘F", cmd: "hyprctl dispatch \"hl.dsp.window.fullscreen({fullscreen = 0})\"" },
|
||||
{ text: "Toggle Floating", shortcut: "⌘V", cmd: "hyprctl dispatch \"hl.dsp.window.float({action = \"toggle\"})\"" },
|
||||
{ text: "Toggle Group", shortcut: "⌘G", cmd: "hyprctl dispatch \"hl.dsp.group.toggle()\"" },
|
||||
{ text: "---", shortcut: "", cmd: "" },
|
||||
{ text: "Zoom In", shortcut: "⌘+", cmd: "" },
|
||||
{ text: "Zoom Out", shortcut: "⌘-", cmd: "" }
|
||||
@@ -62,12 +62,12 @@ Rectangle {
|
||||
// WINDOW MENU
|
||||
Repeater {
|
||||
model: root.menuName === "Window" ? [
|
||||
{ text: "Minimize Window", shortcut: "⌘M", cmd: "hyprctl dispatch movetoworkspacesilent special:scratch" },
|
||||
{ text: "Tile Left", shortcut: "⌃⌥←", cmd: "hyprctl dispatch movewindow l" },
|
||||
{ text: "Tile Right", shortcut: "⌃⌥→", cmd: "hyprctl dispatch movewindow r" },
|
||||
{ text: "Minimize Window", shortcut: "⌘M", cmd: "hyprctl dispatch \"hl.dsp.window.move({workspace = \"special:scratch\"})\"" },
|
||||
{ text: "Tile Left", shortcut: "⌃⌥←", cmd: "hyprctl dispatch \"hl.dsp.window.move({direction = \"left\"})\"" },
|
||||
{ text: "Tile Right", shortcut: "⌃⌥→", cmd: "hyprctl dispatch \"hl.dsp.window.move({direction = \"right\"})\"" },
|
||||
{ text: "---", shortcut: "", cmd: "" },
|
||||
{ text: "Show Scratchpad", shortcut: "⌘↩", cmd: "hyprctl dispatch togglespecialworkspace scratch" },
|
||||
{ text: "Show Messaging", shortcut: "⌘M", cmd: "hyprctl dispatch togglespecialworkspace messaging" }
|
||||
{ text: "Show Scratchpad", shortcut: "⌘↩", cmd: "hyprctl dispatch \"hl.dsp.workspace.toggle_special(\"scratch\")\"" },
|
||||
{ text: "Show Messaging", shortcut: "⌘M", cmd: "hyprctl dispatch \"hl.dsp.workspace.toggle_special(\"messaging\")\"" }
|
||||
] : []
|
||||
delegate: MenuEntryDelegate {}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ Rectangle {
|
||||
shortcut: "⇧⌘Q"
|
||||
onTriggered: {
|
||||
GlobalState.appleMenuVisible = false;
|
||||
GlobalState.launchApp("hyprctl dispatch exit");
|
||||
GlobalState.launchApp("loginctl terminate-session");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ PanelWindow {
|
||||
isPinned: false
|
||||
onCustomClicked: {
|
||||
if (modelData.address) {
|
||||
Hyprland.dispatch(`focuswindow address:${modelData.address}`);
|
||||
Hyprland.dispatch(`hl.dsp.focus({window = "address:${modelData.address}"})`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,8 +308,9 @@ PanelWindow {
|
||||
var seen = {}
|
||||
if (GlobalState.runningApps) {
|
||||
for (var i = 0; i < GlobalState.runningApps.length; i++) {
|
||||
var cls = GlobalState.runningApps[i]
|
||||
if (cls && pinned.indexOf(cls) === -1 && !seen[cls]) {
|
||||
// hyprctl clients entries are objects; extract the class string
|
||||
var cls = GlobalState.runningApps[i] && GlobalState.runningApps[i].class
|
||||
if (cls && cls.length > 0 && pinned.indexOf(cls) === -1 && !seen[cls]) {
|
||||
seen[cls] = true
|
||||
running.push(cls)
|
||||
}
|
||||
@@ -331,7 +332,7 @@ PanelWindow {
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: modelData.charAt(0).toUpperCase()
|
||||
text: modelData && modelData.length > 0 ? modelData.charAt(0).toUpperCase() : "?"
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 12
|
||||
|
||||
@@ -31,7 +31,9 @@ PanelWindow {
|
||||
|
||||
// App Database Loader Process
|
||||
readonly property Process appScanProc: Process {
|
||||
command: ["bash", "-c", "dirs=(\"/run/current-system/sw/share/applications\" \"$HOME/.nix-profile/share/applications\" \"$HOME/.local/share/applications\"); echo '['; first=1; for d in \"${dirs[@]}\"; do [ -d \"$d\" ] && for f in \"$d\"/*.desktop; do [ -e \"$f\" ] || continue; grep -q \"^NoDisplay=true\" \"$f\" 2>/dev/null && continue; n=$(grep -m 1 \"^Name=\" \"$f\" 2>/dev/null | cut -d= -f2-); e=$(grep -m 1 \"^Exec=\" \"$f\" 2>/dev/null | cut -d= -f2- | sed -E 's/%[fFuUdDnNickvm]//g'); if [ -n \"$n\" ] && [ -n \"$e\" ]; then [ $first -eq 0 ] && echo ','; first=0; echo \"{\\\"name\\\":\\\"$n\\\",\\\"exec\\\":\\\"$e\\\"}\"; fi; done; done; echo ']'"]
|
||||
// Indexes .desktop applications AND executable user scripts so the
|
||||
// launcher finds "everything" without depending on an external service.
|
||||
command: ["bash", "-c", "dirs=(\"/run/current-system/sw/share/applications\" \"$HOME/.nix-profile/share/applications\" \"$HOME/.local/share/applications\"); bdirs=(\"$HOME/.local/bin\" \"$HOME/bin\" \"$HOME/.cargo/bin\"); echo '['; first=1; for d in \"${dirs[@]}\"; do [ -d \"$d\" ] && for f in \"$d\"/*.desktop; do [ -e \"$f\" ] || continue; grep -q \"^NoDisplay=true\" \"$f\" 2>/dev/null && continue; n=$(grep -m 1 \"^Name=\" \"$f\" 2>/dev/null | cut -d= -f2-); e=$(grep -m 1 \"^Exec=\" \"$f\" 2>/dev/null | cut -d= -f2- | sed -E 's/%[fFuUdDnNickvm]//g'); if [ -n \"$n\" ] && [ -n \"$e\" ]; then [ $first -eq 0 ] && echo ','; first=0; echo \"{\\\"name\\\":\\\"$n\\\",\\\"exec\\\":\\\"$e\\\"}\"; fi; done; done; for d in \"${bdirs[@]}\"; do [ -d \"$d\" ] || continue; for f in \"$d\"/*; do [ -f \"$f\" ] && [ -x \"$f\" ] || continue; n=$(basename \"$f\"); [ $first -eq 0 ] && echo ','; first=0; printf '{\\\"name\\\":\\\"%s\\\",\\\"exec\\\":\\\"%s\\\",\\\"comment\\\":\\\"script\\\"}\\n' \"$n\" \"$f\"; done; done; echo ']'"]
|
||||
stdout: StdioCollector {
|
||||
onDataChanged: {
|
||||
try {
|
||||
|
||||
@@ -73,6 +73,7 @@ PanelWindow {
|
||||
component ToggleCard: Rectangle {
|
||||
property string title: ""
|
||||
property string icon: ""
|
||||
property string glyph: "" // Nerd Font glyph alternative to icon file
|
||||
property bool active: false
|
||||
signal clicked()
|
||||
|
||||
@@ -97,15 +98,22 @@ PanelWindow {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
spacing: 12
|
||||
Text {
|
||||
visible: parent.parent.glyph !== ""
|
||||
text: parent.parent.glyph
|
||||
font.family: "JetBrainsMono Nerd Font"
|
||||
font.pixelSize: 20
|
||||
color: parent.parent.active ? Theme.accentVolt : Theme.textMuted
|
||||
}
|
||||
Image {
|
||||
source: icon ? Qt.resolvedUrl("../" + icon) : ""
|
||||
source: parent.parent.icon && parent.parent.glyph === "" ? Qt.resolvedUrl("../" + parent.parent.icon) : ""
|
||||
Layout.preferredWidth: 24
|
||||
Layout.preferredHeight: 24
|
||||
sourceSize: Qt.size(24, 24)
|
||||
visible: parent.icon !== ""
|
||||
visible: parent.parent.icon !== "" && parent.parent.glyph === ""
|
||||
}
|
||||
Text {
|
||||
text: title
|
||||
text: parent.parent.title
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 13
|
||||
@@ -312,8 +320,7 @@ PanelWindow {
|
||||
icon: "assets/wifi.svg"
|
||||
active: GlobalState.wifiConnected
|
||||
onClicked: {
|
||||
let proc = Quickshell.createProcess("sh", ["-c", "nm-connection-editor || foot -e nmtui"])
|
||||
proc.start()
|
||||
Quickshell.execDetached(["sh", "-c", "nm-connection-editor || foot -e nmtui"])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -330,14 +337,14 @@ PanelWindow {
|
||||
ToggleCard {
|
||||
property bool dndActive: false
|
||||
title: "Do Not Disturb"
|
||||
icon: "" // Optional DND icon
|
||||
glyph: "\uF186"
|
||||
active: dndActive
|
||||
onClicked: dndActive = !dndActive
|
||||
}
|
||||
|
||||
ToggleCard {
|
||||
title: GlobalState.volumeMuted ? "Muted" : "Sound"
|
||||
icon: "" // Optional sound icon
|
||||
glyph: GlobalState.volumeMuted ? "\uF026" : "\uF028"
|
||||
active: !GlobalState.volumeMuted
|
||||
onClicked: GlobalState.toggleVolumeMute()
|
||||
}
|
||||
@@ -423,6 +430,13 @@ PanelWindow {
|
||||
valueText: GlobalState.memUsedGb + " / " + GlobalState.memTotalGb + " GB"
|
||||
}
|
||||
|
||||
ProgressBarItem {
|
||||
label: "DISK"
|
||||
percent: GlobalState.diskPercent
|
||||
valueText: GlobalState.diskUsedGb + " / " + GlobalState.diskTotalGb + " GB"
|
||||
barColor: GlobalState.diskPercent > 90 ? Theme.accentCoral : Theme.accentVolt
|
||||
}
|
||||
|
||||
ProgressBarItem {
|
||||
label: "VRAM"
|
||||
percent: (GlobalState.gpuVramUsed / Math.max(1, GlobalState.gpuVramTotal)) * 100
|
||||
@@ -446,7 +460,12 @@ PanelWindow {
|
||||
color: GlobalState.wifiConnected ? Theme.accentVolt : Theme.accentCoral
|
||||
}
|
||||
Text {
|
||||
text: GlobalState.wifiConnected ? "Connected" : "Disconnected"
|
||||
text: {
|
||||
if (!GlobalState.wifiConnected) return "Disconnected";
|
||||
if (GlobalState.connectionType === "wifi") return "Wi-Fi — " + (GlobalState.wifiSsid !== "" ? GlobalState.wifiSsid : "unknown");
|
||||
if (GlobalState.connectionType === "eth") return "Ethernet";
|
||||
return "Connected";
|
||||
}
|
||||
color: Theme.textPrimary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 14
|
||||
@@ -454,14 +473,8 @@ PanelWindow {
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "SSID: " + (GlobalState.wifiSsid !== "" ? GlobalState.wifiSsid : "None")
|
||||
color: Theme.textSecondary
|
||||
font.family: Theme.fontSans
|
||||
font.pixelSize: 13
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "IP: " + GlobalState.ipAddress
|
||||
visible: GlobalState.wifiConnected
|
||||
text: "IP: " + (GlobalState.ipAddress !== "" ? GlobalState.ipAddress : "—")
|
||||
color: Theme.textSecondary
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 13
|
||||
@@ -478,8 +491,7 @@ PanelWindow {
|
||||
onEntered: parent.color = Theme.textPrimary
|
||||
onExited: parent.color = Theme.textMuted
|
||||
onClicked: {
|
||||
let proc = Quickshell.createProcess("sh", ["-c", "nm-connection-editor || foot -e nmtui"])
|
||||
proc.start()
|
||||
Quickshell.execDetached(["sh", "-c", "nm-connection-editor || foot -e nmtui"])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -558,7 +570,7 @@ PanelWindow {
|
||||
}
|
||||
}
|
||||
Text {
|
||||
text: GlobalState.mediaStatus === "Playing" ? "⏸" : "▶"
|
||||
text: GlobalState.mediaPlaying ? "⏸" : "▶"
|
||||
font.pixelSize: 24
|
||||
color: Theme.textSecondary
|
||||
MouseArea {
|
||||
|
||||
@@ -5,6 +5,11 @@ import Quickshell.Wayland
|
||||
import "../theme"
|
||||
import ".."
|
||||
|
||||
// Nerd Font glyphs (JetBrainsMono Nerd Font, installed system-wide)
|
||||
// \uF1EB wifi \uF796 ethernet \uF538 memory \uF1C0 disk
|
||||
// \uF028 volume \uF185 brightness \uF240 battery \uF0E7 charging
|
||||
// \uF017 clock \uF2DB cpu
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
|
||||
@@ -38,33 +43,87 @@ PanelWindow {
|
||||
color: Theme.glassBorder
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// Helpers to compose rich-text status segments
|
||||
// --------------------------------------------------------------------
|
||||
function pad(num) {
|
||||
if (num === undefined || num === null) return "00";
|
||||
return num < 10 ? "0" + num : num.toString();
|
||||
}
|
||||
|
||||
function seg(icon, value, iconColor, valueColor) {
|
||||
return "<font color=\"" + iconColor + "\">" + icon + "</font><font color=\"" + valueColor + "\"> " + value + "</font>";
|
||||
}
|
||||
|
||||
function buildStats() {
|
||||
const c = "#e5e2e1";
|
||||
const dim = "#adaaaa";
|
||||
const volt = "#CFFC00";
|
||||
const coral = "#FF7A59";
|
||||
const sep = "<font color=\"#2a2929\"> // </font>";
|
||||
const parts = [];
|
||||
|
||||
// Network: type icon + SSID (wifi) + IP
|
||||
if (GlobalState.wifiConnected) {
|
||||
const icon = GlobalState.connectionType === "wifi" ? "\uF1EB" : "\uF796";
|
||||
const label = (GlobalState.connectionType === "wifi" && GlobalState.wifiSsid !== "") ? GlobalState.wifiSsid : "eth";
|
||||
parts.push(seg(icon, label + " " + (GlobalState.ipAddress !== "" ? GlobalState.ipAddress : "\u2014"), volt, c));
|
||||
} else {
|
||||
parts.push(seg("\uF1EB", "offline", coral, dim));
|
||||
}
|
||||
|
||||
// Memory (used GB / total GB)
|
||||
parts.push(seg("\uF538", GlobalState.memUsedGb + "G / " + GlobalState.memTotalGb + "G",
|
||||
GlobalState.memPercent > 85 ? coral : dim, c));
|
||||
|
||||
// Disk (root filesystem percent)
|
||||
parts.push(seg("\uF1C0", GlobalState.diskPercent + "%",
|
||||
GlobalState.diskPercent > 90 ? coral : dim, c));
|
||||
|
||||
// Audio (mute state flips icon + color)
|
||||
if (GlobalState.volumeMuted) {
|
||||
parts.push(seg("\uF026", "mute", coral, dim));
|
||||
} else {
|
||||
parts.push(seg("\uF028", GlobalState.volume + "%", dim, c));
|
||||
}
|
||||
|
||||
// Display brightness
|
||||
parts.push(seg("\uF185", GlobalState.brightness + "%", dim, c));
|
||||
|
||||
// Battery (only when present, e.g. laptops)
|
||||
if (GlobalState.batteryPresent) {
|
||||
const icon = GlobalState.batteryCharging ? "\uF0E7" : "\uF240";
|
||||
parts.push(seg(icon, GlobalState.batteryPercent + "%",
|
||||
GlobalState.batteryPercent < 20 ? coral : dim, c));
|
||||
}
|
||||
|
||||
return parts.join(sep);
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
spacing: 16
|
||||
|
||||
// Left Section
|
||||
// Left Section: workspace indicator
|
||||
Text {
|
||||
id: workspaceIndicator
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
font.family: Theme.fontMono
|
||||
textFormat: Text.RichText
|
||||
font.family: "JetBrainsMono Nerd Font"
|
||||
font.pixelSize: 12
|
||||
color: Theme.textMuted
|
||||
|
||||
function pad(num) {
|
||||
if (num === undefined || num === null) return "00";
|
||||
return num < 10 ? "0" + num : num.toString();
|
||||
}
|
||||
|
||||
text: pad(GlobalState.activeWorkspace) + " // " + (GlobalState.workspaceNames[GlobalState.activeWorkspace] !== undefined ? GlobalState.workspaceNames[GlobalState.activeWorkspace] : "main")
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: 150 }
|
||||
text: {
|
||||
const name = GlobalState.workspaceNames[GlobalState.activeWorkspace] !== undefined
|
||||
? GlobalState.workspaceNames[GlobalState.activeWorkspace] : "main";
|
||||
return "<font color=\"#CFFC00\">" + pad(GlobalState.activeWorkspace) + "</font>"
|
||||
+ "<font color=\"#2a2929\"> // </font>"
|
||||
+ "<font color=\"#adaaaa\">" + name + "</font>";
|
||||
}
|
||||
}
|
||||
|
||||
// Center Section
|
||||
// Center Section: focused window title
|
||||
Text {
|
||||
id: windowTitle
|
||||
Layout.fillWidth: true
|
||||
@@ -84,18 +143,35 @@ PanelWindow {
|
||||
}
|
||||
}
|
||||
|
||||
// Right Section
|
||||
// Right Section: live system stats (click to open the System HUD)
|
||||
Text {
|
||||
id: stats
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
textFormat: Text.RichText
|
||||
font.family: "JetBrainsMono Nerd Font"
|
||||
font.pixelSize: 11
|
||||
|
||||
text: buildStats()
|
||||
|
||||
MouseArea {
|
||||
id: statsMouse
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: GlobalState.toggleSystemHud()
|
||||
}
|
||||
}
|
||||
|
||||
// Clock
|
||||
Text {
|
||||
id: clock
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
font.family: Theme.fontMono
|
||||
textFormat: Text.RichText
|
||||
font.family: "JetBrainsMono Nerd Font"
|
||||
font.pixelSize: 12
|
||||
color: Theme.textPrimary
|
||||
text: GlobalState.timeString
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: 150 }
|
||||
}
|
||||
text: "<font color=\"#adaaaa\">\uF017</font>"
|
||||
+ "<font color=\"#ffffff\"> " + GlobalState.timeString + "</font>"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user