quickshell: replace macOS-style shell with standalone overview module

Swap the illogical-impulse-derived components for the upstream
quickshell-overview standalone module, update Hyprland keybinds
(Super+Tab overview, rofi launcher), refresh foot colors and
starship theme, and adjust related host/module wiring.
This commit is contained in:
2026-09-18 23:25:42 -07:00
parent 47c0c9c719
commit 367e21ef95
75 changed files with 3634 additions and 5773 deletions

View File

@@ -0,0 +1,209 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Hyprland
import "../common"
/**
* Provides access to some Hyprland data not available in Quickshell.Hyprland.
*/
Singleton {
id: root
property var windowList: []
property var addresses: []
property var windowByAddress: ({})
property var workspaces: []
property var allWorkspaces: []
property var workspaceIds: []
property var workspaceById: ({})
property var activeWorkspace: null
property var monitors: []
property var layers: ({})
property bool pendingWindowsUpdate: false
property bool pendingMonitorsUpdate: false
property bool pendingLayersUpdate: false
property bool pendingWorkspacesUpdate: false
property bool pendingActiveWorkspaceUpdate: false
function updateWindowList() {
getClients.running = true;
}
function updateLayers() {
getLayers.running = true;
}
function updateMonitors() {
getMonitors.running = true;
}
function updateWorkspaces() {
getWorkspaces.running = true;
getActiveWorkspace.running = true;
}
function updateAll() {
scheduleUpdates(true, true, true, true, true);
}
function scheduleUpdates(windows, monitors, layers, workspaces, activeWorkspace) {
pendingWindowsUpdate = pendingWindowsUpdate || !!windows;
pendingMonitorsUpdate = pendingMonitorsUpdate || !!monitors;
pendingLayersUpdate = pendingLayersUpdate || !!layers;
pendingWorkspacesUpdate = pendingWorkspacesUpdate || !!workspaces;
pendingActiveWorkspaceUpdate = pendingActiveWorkspaceUpdate || !!activeWorkspace;
const debounceMs = Math.max(0, Config.options.hacks.hyprlandEventDebounceMs);
if (debounceMs === 0) {
flushPendingUpdates();
} else {
eventDebounceTimer.interval = debounceMs;
eventDebounceTimer.restart();
}
}
function flushPendingUpdates() {
if (pendingWindowsUpdate) {
pendingWindowsUpdate = false;
updateWindowList();
}
if (pendingMonitorsUpdate) {
pendingMonitorsUpdate = false;
updateMonitors();
}
if (pendingLayersUpdate) {
pendingLayersUpdate = false;
updateLayers();
}
if (pendingWorkspacesUpdate) {
pendingWorkspacesUpdate = false;
getWorkspaces.running = true;
}
if (pendingActiveWorkspaceUpdate) {
pendingActiveWorkspaceUpdate = false;
getActiveWorkspace.running = true;
}
}
function biggestWindowForWorkspace(workspaceId) {
const windowsInThisWorkspace = HyprlandData.windowList.filter(w => w.workspace.id == workspaceId);
return windowsInThisWorkspace.reduce((maxWin, win) => {
const maxArea = (maxWin?.size?.[0] ?? 0) * (maxWin?.size?.[1] ?? 0);
const winArea = (win?.size?.[0] ?? 0) * (win?.size?.[1] ?? 0);
return winArea > maxArea ? win : maxWin;
}, null);
}
Component.onCompleted: {
scheduleUpdates(true, true, true, true, true);
flushPendingUpdates();
}
Connections {
target: Hyprland
function onRawEvent(event) {
const eventName = `${event?.name ?? event?.event ?? event?.type ?? ""}`;
if (["openlayer", "closelayer", "screencast"].includes(eventName))
return;
if (eventName === "openwindow" || eventName === "closewindow" || eventName === "movewindow" || eventName === "movewindowv2" || eventName === "windowtitle") {
scheduleUpdates(true, false, false, true, false);
return;
}
if (eventName === "workspace" || eventName === "workspacev2" || eventName === "focusedmon" || eventName === "focusedmonv2" || eventName === "activewindow" || eventName === "activewindowv2") {
scheduleUpdates(false, false, false, true, true);
return;
}
if (eventName.startsWith("monitor") || eventName === "configreloaded") {
scheduleUpdates(true, true, false, true, true);
return;
}
scheduleUpdates(true, true, true, true, true);
}
}
Timer {
id: eventDebounceTimer
interval: Math.max(0, Config.options.hacks.hyprlandEventDebounceMs)
repeat: false
onTriggered: root.flushPendingUpdates()
}
Process {
id: getClients
command: ["hyprctl", "clients", "-j"]
stdout: StdioCollector {
id: clientsCollector
onStreamFinished: {
root.windowList = JSON.parse(clientsCollector.text);
let tempWinByAddress = {};
for (var i = 0; i < root.windowList.length; ++i) {
var win = root.windowList[i];
tempWinByAddress[win.address] = win;
}
root.windowByAddress = tempWinByAddress;
root.addresses = root.windowList.map(win => win.address);
}
}
}
Process {
id: getMonitors
command: ["hyprctl", "monitors", "-j"]
stdout: StdioCollector {
id: monitorsCollector
onStreamFinished: {
root.monitors = JSON.parse(monitorsCollector.text);
}
}
}
Process {
id: getLayers
command: ["hyprctl", "layers", "-j"]
stdout: StdioCollector {
id: layersCollector
onStreamFinished: {
root.layers = JSON.parse(layersCollector.text);
}
}
}
Process {
id: getWorkspaces
command: ["hyprctl", "workspaces", "-j"]
stdout: StdioCollector {
id: workspacesCollector
onStreamFinished: {
const rawWorkspaces = JSON.parse(workspacesCollector.text);
root.allWorkspaces = rawWorkspaces;
root.workspaces = rawWorkspaces.filter(ws => ws.id >= 1 && ws.id <= 100);
let tempWorkspaceById = {};
for (var i = 0; i < root.workspaces.length; ++i) {
var ws = root.workspaces[i];
tempWorkspaceById[ws.id] = ws;
}
root.workspaceById = tempWorkspaceById;
root.workspaceIds = root.workspaces.map(ws => ws.id);
}
}
}
Process {
id: getActiveWorkspace
command: ["hyprctl", "activeworkspace", "-j"]
stdout: StdioCollector {
id: activeWorkspaceCollector
onStreamFinished: {
root.activeWorkspace = JSON.parse(activeWorkspaceCollector.text);
}
}
}
}