Add notice if app is taking a while to launch
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import QtQuick
|
import QtQuick
|
||||||
@@ -18,6 +19,12 @@ Item {
|
|||||||
property bool cursorActive: true
|
property bool cursorActive: true
|
||||||
property bool hoverArmed: false
|
property bool hoverArmed: false
|
||||||
property var filteredEntries: []
|
property var filteredEntries: []
|
||||||
|
property int launchSerial: 0
|
||||||
|
property int launchToplevelCount: 0
|
||||||
|
property var launchActiveToplevel: null
|
||||||
|
property bool launchOsdOpen: false
|
||||||
|
property string launchOsdMessage: ""
|
||||||
|
property var hiddenEntryIds: ({})
|
||||||
|
|
||||||
// Bound to the central [app-launcher] section in shell.toml via Color.qml.
|
// Bound to the central [app-launcher] section in shell.toml via Color.qml.
|
||||||
// Each color already includes its alpha companion (composed in the
|
// Each color already includes its alpha companion (composed in the
|
||||||
@@ -95,7 +102,15 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function entrySortKey(entry) {
|
function entrySortKey(entry) {
|
||||||
return String((entry && entry.id) || root.entryName(entry)).toLowerCase()
|
return root.entryName(entry).toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
function toplevelCount() {
|
||||||
|
try { return ToplevelManager.toplevels.values.length } catch (e) { return 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
function shellQuote(value) {
|
||||||
|
return "'" + String(value).replace(/'/g, "'\\''") + "'"
|
||||||
}
|
}
|
||||||
|
|
||||||
function entrySearchText(entry) {
|
function entrySearchText(entry) {
|
||||||
@@ -107,7 +122,24 @@ Item {
|
|||||||
|
|
||||||
function isHiddenEntry(entry) {
|
function isHiddenEntry(entry) {
|
||||||
var id = String((entry && entry.id) || "")
|
var id = String((entry && entry.id) || "")
|
||||||
return id === "avahi-discover" || id === "bssh" || id === "bvnc"
|
return root.hiddenEntryIds[id] === true
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadHiddenEntries(rawText) {
|
||||||
|
var next = ({})
|
||||||
|
var lines = String(rawText || "").split(/\n/)
|
||||||
|
for (var i = 0; i < lines.length; i++) {
|
||||||
|
var id = lines[i].trim()
|
||||||
|
if (id.length > 0) next[id] = true
|
||||||
|
}
|
||||||
|
root.hiddenEntryIds = next
|
||||||
|
if (root.opened) root.rebuildDisplay()
|
||||||
|
}
|
||||||
|
|
||||||
|
function hiddenEntryScanCommand() {
|
||||||
|
var desktop = [Quickshell.env("XDG_CURRENT_DESKTOP"), Quickshell.env("XDG_SESSION_DESKTOP"), Quickshell.env("DESKTOP_SESSION")].filter(function(v) { return String(v || "").length > 0 }).join(":")
|
||||||
|
var script = root.omarchyPath + "/shell/scripts/app-launcher-hidden-entries.sh"
|
||||||
|
return root.shellQuote(script) + " " + root.shellQuote(desktop)
|
||||||
}
|
}
|
||||||
|
|
||||||
function fuzzyScore(entry, query) {
|
function fuzzyScore(entry, query) {
|
||||||
@@ -210,19 +242,88 @@ Item {
|
|||||||
if (index < 0 || index >= root.filteredEntries.length) return
|
if (index < 0 || index >= root.filteredEntries.length) return
|
||||||
var entry = root.filteredEntries[index]
|
var entry = root.filteredEntries[index]
|
||||||
if (!entry) return
|
if (!entry) return
|
||||||
|
root.beginLaunchFeedback(entry)
|
||||||
root.dismiss()
|
root.dismiss()
|
||||||
entry.execute()
|
entry.execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function beginLaunchFeedback(entry) {
|
||||||
|
root.launchSerial++
|
||||||
|
root.launchToplevelCount = root.toplevelCount()
|
||||||
|
root.launchActiveToplevel = ToplevelManager.activeToplevel
|
||||||
|
root.launchOsdOpen = false
|
||||||
|
root.launchOsdMessage = "Launching " + root.entryName(entry) + "…"
|
||||||
|
launchDelay.restart()
|
||||||
|
launchTimeout.restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeLaunchFeedback(serial) {
|
||||||
|
if (serial !== root.launchSerial) return
|
||||||
|
launchDelay.stop()
|
||||||
|
launchTimeout.stop()
|
||||||
|
if (root.launchOsdOpen) {
|
||||||
|
Quickshell.execDetached(["omarchy-shell", "osd", "close"])
|
||||||
|
root.launchOsdOpen = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function maybeFinishLaunchFeedback() {
|
||||||
|
if (!launchDelay.running && !launchTimeout.running && !root.launchOsdOpen) return
|
||||||
|
if (root.toplevelCount() <= root.launchToplevelCount && ToplevelManager.activeToplevel === root.launchActiveToplevel) return
|
||||||
|
root.closeLaunchFeedback(root.launchSerial)
|
||||||
|
}
|
||||||
|
|
||||||
ListModel { id: displayModel }
|
ListModel { id: displayModel }
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: hiddenEntryScan
|
||||||
|
command: ["bash", "-lc", root.hiddenEntryScanCommand()]
|
||||||
|
stdout: SplitParser { onRead: function(line) { hiddenEntryOutput.text += line + "\n" } }
|
||||||
|
onStarted: hiddenEntryOutput.text = ""
|
||||||
|
onExited: root.loadHiddenEntries(hiddenEntryOutput.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: hiddenEntryOutput
|
||||||
|
property string text: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: ToplevelManager.toplevels
|
||||||
|
function onValuesChanged() { root.maybeFinishLaunchFeedback() }
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: ToplevelManager
|
||||||
|
function onActiveToplevelChanged() { root.maybeFinishLaunchFeedback() }
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: launchDelay
|
||||||
|
interval: 2000
|
||||||
|
onTriggered: {
|
||||||
|
if (root.toplevelCount() > root.launchToplevelCount || ToplevelManager.activeToplevel !== root.launchActiveToplevel) return
|
||||||
|
root.launchOsdOpen = true
|
||||||
|
Quickshell.execDetached(["omarchy-shell", "osd", "show", JSON.stringify({ icon: "", message: root.launchOsdMessage, duration: 0 })])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: launchTimeout
|
||||||
|
interval: 15000
|
||||||
|
onTriggered: root.closeLaunchFeedback(root.launchSerial)
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: DesktopEntries.applications
|
target: DesktopEntries.applications
|
||||||
function onValuesChanged() {
|
function onValuesChanged() {
|
||||||
|
hiddenEntryScan.running = true
|
||||||
if (root.opened) root.rebuildDisplay()
|
if (root.opened) root.rebuildDisplay()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: hiddenEntryScan.running = true
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: panel
|
id: panel
|
||||||
visible: root.opened
|
visible: root.opened
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ Item {
|
|||||||
property int value: 0
|
property int value: 0
|
||||||
property int maxValue: 100
|
property int maxValue: 100
|
||||||
property bool hasProgress: true
|
property bool hasProgress: true
|
||||||
|
property int duration: 1200
|
||||||
|
|
||||||
function clamp(v, min, max) { return Math.max(min, Math.min(max, v)) }
|
function clamp(v, min, max) { return Math.max(min, Math.min(max, v)) }
|
||||||
|
|
||||||
@@ -29,27 +30,31 @@ Item {
|
|||||||
if (n === "touchpad") return ""
|
if (n === "touchpad") return ""
|
||||||
if (n === "touch" || n === "touchscreen") return ""
|
if (n === "touch" || n === "touchscreen") return ""
|
||||||
if (n === "media" || n === "player") return ""
|
if (n === "media" || n === "player") return ""
|
||||||
|
if (n.length > 0) return name
|
||||||
if (percent <= 0) return ""
|
if (percent <= 0) return ""
|
||||||
if (percent <= 33) return ""
|
if (percent <= 33) return ""
|
||||||
if (percent <= 66) return ""
|
if (percent <= 66) return ""
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
function show(iconName, rawMessage, rawValue, rawMax, rawProgressText) {
|
function show(iconName, rawMessage, rawValue, rawMax, rawProgressText, rawDuration) {
|
||||||
maxValue = Math.max(1, parseInt(rawMax || "100", 10))
|
maxValue = Math.max(1, parseInt(rawMax || "100", 10))
|
||||||
var parsed = parseInt(rawValue || "0", 10)
|
var parsed = parseInt(rawValue || "0", 10)
|
||||||
hasProgress = rawValue !== "" && !isNaN(parsed) && rawMessage === ""
|
hasProgress = rawValue !== "" && !isNaN(parsed) && rawMessage === ""
|
||||||
value = hasProgress ? clamp(parsed, 0, maxValue) : 0
|
value = hasProgress ? clamp(parsed, 0, maxValue) : 0
|
||||||
message = String(rawMessage || (hasProgress ? (rawProgressText || Math.round(value * 100 / maxValue) + "%") : ""))
|
message = String(rawMessage || (hasProgress ? (rawProgressText || Math.round(value * 100 / maxValue) + "%") : ""))
|
||||||
icon = iconFor(iconName, hasProgress ? Math.round(value * 100 / maxValue) : -1)
|
icon = iconFor(iconName, hasProgress ? Math.round(value * 100 / maxValue) : -1)
|
||||||
|
var parsedDuration = parseInt(rawDuration || "1200", 10)
|
||||||
|
duration = isNaN(parsedDuration) ? 1200 : Math.max(0, parsedDuration)
|
||||||
opened = true
|
opened = true
|
||||||
hideTimer.restart()
|
if (duration > 0) hideTimer.restart()
|
||||||
|
else hideTimer.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
function open(payloadJson) {
|
function open(payloadJson) {
|
||||||
try {
|
try {
|
||||||
var p = JSON.parse(payloadJson || "{}")
|
var p = JSON.parse(payloadJson || "{}")
|
||||||
show(p.icon || "", p.message || "", p.value === undefined ? "" : String(p.value), p.max === undefined ? "100" : String(p.max), p.progressText || "")
|
show(p.icon || "", p.message || "", p.value === undefined ? "" : String(p.value), p.max === undefined ? "100" : String(p.max), p.progressText || "", p.duration === undefined ? "1200" : String(p.duration))
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +62,7 @@ Item {
|
|||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: hideTimer
|
id: hideTimer
|
||||||
interval: 1200
|
interval: root.duration
|
||||||
onTriggered: root.opened = false
|
onTriggered: root.opened = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user