quickshell: notification click/action jumps to the app's window
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
5aea7fab27
commit
3d5ecb7b98
1 changed files with 59 additions and 1 deletions
|
|
@ -1480,7 +1480,10 @@ in
|
|||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: { modelData.invoke(); _nc.actionInvoked(); }
|
||||
// Invoking an action ("View", "Reply"…)
|
||||
// makes the app want focus, but it can't
|
||||
// take it itself — see focusNotifApp.
|
||||
onClicked: { modelData.invoke(); bar.focusNotifApp(_nc.notif); _nc.actionInvoked(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3217,6 +3220,37 @@ in
|
|||
if (a.startsWith("/")) return "file://" + a;
|
||||
return "";
|
||||
}
|
||||
// Jump to the window that sent a notification. Toplevel.activate()
|
||||
// goes over wlr-foreign-toplevel — the same path a taskbar uses —
|
||||
// so Hyprland follows it across workspaces. The app raising
|
||||
// itself does not work here: misc:focus_on_activate is off, so
|
||||
// its own activation request is dropped on purpose.
|
||||
function focusNotifApp(notif) {
|
||||
if (!notif) return;
|
||||
const want = [(notif.desktopEntry || "").replace(/\.desktop$/, ""), notif.appName]
|
||||
.filter(s => s !== "").map(s => s.toLowerCase());
|
||||
if (want.length === 0) return;
|
||||
const tls = ToplevelManager.toplevels.values;
|
||||
// Exact appId first: appName is a display name ("Vesktop"),
|
||||
// appId the wayland id ("vesktop"), and they often differ by
|
||||
// more than case, hence the substring pass.
|
||||
for (const t of tls)
|
||||
if (want.includes((t.appId || "").toLowerCase())) { t.activate(); return; }
|
||||
for (const t of tls) {
|
||||
const id = (t.appId || "").toLowerCase();
|
||||
if (id !== "" && want.some(w => id.includes(w) || w.includes(id))) { t.activate(); return; }
|
||||
}
|
||||
}
|
||||
|
||||
// Clicking a notification body. Apps hide "open the right chat"
|
||||
// behind the default action, so fire that too when they send one.
|
||||
function activateNotif(notif) {
|
||||
if (!notif) return;
|
||||
for (const a of notif.actions)
|
||||
if (a.identifier === "default") { a.invoke(); break; }
|
||||
focusNotifApp(notif);
|
||||
}
|
||||
|
||||
function toggleDropdown(dd, setupFn) {
|
||||
if (dd.visible && !dd.closing) {
|
||||
dd.animateClose();
|
||||
|
|
@ -6045,6 +6079,18 @@ in
|
|||
width: parent.width
|
||||
height: Math.max(notifPreview.visible ? 48 : 0, ncBody.height)
|
||||
|
||||
// First child, so the action chips and the
|
||||
// dismiss button still take their own clicks.
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
bar.activateNotif(notifItem.modelData);
|
||||
notifItem.modelData.dismiss();
|
||||
bar.closeAllDropdowns();
|
||||
}
|
||||
}
|
||||
|
||||
// Image preview (album art, screenshot thumb…)
|
||||
ClippingRectangle {
|
||||
id: notifPreview
|
||||
|
|
@ -6325,6 +6371,18 @@ in
|
|||
|
||||
property string previewSource: bar.notifPreviewSource(toastItem.currentNotif)
|
||||
|
||||
// First child, so the action chips and the dismiss
|
||||
// button still take their own clicks.
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
bar.activateNotif(toastItem.currentNotif);
|
||||
if (toastItem.currentNotif) toastItem.currentNotif.dismiss();
|
||||
toastItem.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
// Image preview (screenshot thumb, album art…)
|
||||
ClippingRectangle {
|
||||
id: toastPreview
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue