Open screenshot notifications in Loupe

This commit is contained in:
rope 2026-09-19 09:38:53 +01:00
parent 6ee092433c
commit 7f18d154cd

View file

@ -1636,16 +1636,14 @@ in
} }
SText { SText {
width: parent.width width: parent.width
text: _nc.notif ? (_nc.notif.body || "") : "" text: bar.isHyprshotNotification(_nc.notif)
? "Click to annotate in Loupe."
: (_nc.notif ? (_nc.notif.body || "") : "")
color: Theme.base04 color: Theme.base04
font.pixelSize: _nc.bodySize font.pixelSize: _nc.bodySize
elide: Text.ElideRight elide: Text.ElideRight
maximumLineCount: _nc.bodyLines maximumLineCount: _nc.bodyLines
wrapMode: Text.Wrap wrapMode: Text.Wrap
// hyprshot's body used to be a noisy save path and was
// hidden. Under --clipboard-only it reads "Image copied
// to the clipboard", which is the only thing correcting
// its own "Screenshot saved" summary — nothing is saved.
visible: text !== "" visible: text !== ""
} }
Row { Row {
@ -3415,11 +3413,39 @@ in
} }
} }
function isHyprshotNotification(notif) {
return notif && (notif.appName || "").toLowerCase() === "hyprshot";
}
// Hyprshot supplies the saved PNG as an icon and repeats it in
// the body. Quickshell may expose that icon as a themed image
// URL rather than the original path, so keep the body fallback.
function screenshotPath(notif) {
if (!isHyprshotNotification(notif)) return "";
const marker = "/loupe-screenshots/";
const candidates = [notif.appIcon || "", notif.image || ""];
for (let path of candidates) {
if (path.startsWith("file://"))
path = decodeURIComponent(path.substring(7));
if (path.startsWith("/") && path.includes(marker) && path.endsWith(".png"))
return path;
}
const body = notif.body || "";
const markerAt = body.indexOf(marker);
const endAt = body.indexOf(".png", markerAt);
if (markerAt < 0 || endAt < 0) return "";
const tagAt = body.lastIndexOf("<i>", markerAt);
const startAt = tagAt >= 0 ? tagAt + 3 : body.lastIndexOf(" ", markerAt) + 1;
const path = body.substring(startAt, endAt + 4);
return path.startsWith("/") ? path : "";
}
// Preview image for a notification: its image hint, else a // Preview image for a notification: its image hint, else a
// file-path appIcon (e.g. album art on disk). "" = none. // file-path appIcon (e.g. album art on disk). "" = none.
function notifPreviewSource(notif) { function notifPreviewSource(notif) {
if (!notif) return ""; if (!notif) return "";
if (notif.appName === "Hyprshot") return ""; if (isHyprshotNotification(notif)) return "";
if (notif.image && notif.image !== "") return notif.image; if (notif.image && notif.image !== "") return notif.image;
let a = notif.appIcon || ""; let a = notif.appIcon || "";
if (a.startsWith("file://")) return a; if (a.startsWith("file://")) return a;
@ -3432,7 +3458,7 @@ in
// avoid holding full-screen preview textures in the bar. // avoid holding full-screen preview textures in the bar.
function notifPreviewIcon(notif) { function notifPreviewIcon(notif) {
if (!notif) return ""; if (!notif) return "";
return notif.appName === "Hyprshot" ? "camera" : ""; return isHyprshotNotification(notif) ? "camera" : "";
} }
// Jump to the window that sent a notification. Toplevel.activate() // Jump to the window that sent a notification. Toplevel.activate()
// goes over wlr-foreign-toplevel — the same path a taskbar uses — // goes over wlr-foreign-toplevel — the same path a taskbar uses —
@ -3460,10 +3486,9 @@ in
// behind the default action, so fire that too when they send one. // behind the default action, so fire that too when they send one.
function activateNotif(notif) { function activateNotif(notif) {
if (!notif) return; if (!notif) return;
if (notif.appName === "Hyprshot" && Commands.loupe !== "") { if (isHyprshotNotification(notif) && Commands.loupe !== "") {
let path = notif.appIcon || ""; const path = screenshotPath(notif);
if (path.startsWith("file://")) path = decodeURIComponent(path.substring(7)); if (path !== "") {
if (path.startsWith("/") && path.includes("/loupe-screenshots/") && path.endsWith(".png")) {
Quickshell.execDetached([Commands.loupe, path]); Quickshell.execDetached([Commands.loupe, path]);
return; return;
} }