quickshell: move notification toast into bar surface
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
cb3716a1ec
commit
98560bbbef
1 changed files with 254 additions and 252 deletions
|
|
@ -239,7 +239,6 @@ in
|
|||
|
||||
-- Layer rules: blur behind bar and toasts
|
||||
hl.layer_rule({ match = { namespace = "quickshell-bar" }, blur = true, ignore_alpha = 0.3 })
|
||||
hl.layer_rule({ match = { namespace = "quickshell-toast" }, blur = true, ignore_alpha = 0.3 })
|
||||
|
||||
-- Startup
|
||||
hl.on("hyprland.start", function()
|
||||
|
|
@ -515,7 +514,6 @@ in
|
|||
singleton Theme 1.0 Theme.qml
|
||||
singleton Commands 1.0 Commands.qml
|
||||
Bar 1.0 Bar.qml
|
||||
NotificationToast 1.0 NotificationToast.qml
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
@ -590,13 +588,10 @@ in
|
|||
|
||||
Bar {
|
||||
notifServer: _notifServer
|
||||
}
|
||||
}
|
||||
|
||||
NotificationToast {
|
||||
shellRoot: root
|
||||
}
|
||||
}
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
@ -619,6 +614,7 @@ in
|
|||
id: bar
|
||||
required property var modelData
|
||||
required property NotificationServer notifServer
|
||||
required property var shellRoot
|
||||
screen: modelData
|
||||
WlrLayershell.namespace: "quickshell-bar"
|
||||
|
||||
|
|
@ -640,6 +636,12 @@ in
|
|||
width: activeDropdown && activeDropdown.visible ? activeDropdown.width : 0
|
||||
height: activeDropdown && activeDropdown.visible ? activeDropdown.height : 0
|
||||
}
|
||||
Region {
|
||||
x: toastItem.visible ? toastItem.x : 0
|
||||
y: toastItem.visible ? toastItem.y : 0
|
||||
width: toastItem.visible ? toastItem.width : 0
|
||||
height: toastItem.visible ? toastItem.height : 0
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
|
@ -651,23 +653,35 @@ in
|
|||
color: Theme.barBg
|
||||
}
|
||||
|
||||
// Bar bottom border — left segment (up to dropdown gap)
|
||||
// The "gap source" for the bar border — dropdown takes priority, then toast
|
||||
property bool hasGap: (activeDropdown && activeDropdown.dropdownHeight > 0)
|
||||
|| (toastItem.visible && _toastRect.height > 0)
|
||||
property real gapLeft: activeDropdown && activeDropdown.dropdownHeight > 0
|
||||
? activeDropdown.x
|
||||
: toastItem.visible && _toastRect.height > 0
|
||||
? toastItem.x : 0
|
||||
property real gapRight: activeDropdown && activeDropdown.dropdownHeight > 0
|
||||
? activeDropdown.x + activeDropdown.width
|
||||
: toastItem.visible && _toastRect.height > 0
|
||||
? toastItem.x + toastItem.width : 0
|
||||
property bool gapAlignRight: activeDropdown ? activeDropdown.alignRight : false
|
||||
|
||||
// Bar bottom border — left segment (up to gap)
|
||||
Rectangle {
|
||||
id: barBorderLeft
|
||||
x: 0; y: 30
|
||||
width: (!activeDropdown || activeDropdown.dropdownHeight <= 0)
|
||||
? bar.width : activeDropdown.x
|
||||
width: bar.hasGap ? bar.gapLeft : bar.width
|
||||
height: 1
|
||||
color: Theme.base03
|
||||
}
|
||||
|
||||
// Bar bottom border — right segment (after dropdown gap)
|
||||
// Bar bottom border — right segment (after gap)
|
||||
Rectangle {
|
||||
id: barBorderRight
|
||||
visible: activeDropdown && activeDropdown.dropdownHeight > 0 && !activeDropdown.alignRight
|
||||
x: activeDropdown ? activeDropdown.x + activeDropdown.width : 0
|
||||
visible: bar.hasGap && !bar.gapAlignRight
|
||||
x: bar.gapRight
|
||||
y: 30
|
||||
width: activeDropdown ? bar.width - x : 0
|
||||
width: bar.width - x
|
||||
height: 1
|
||||
color: Theme.base03
|
||||
}
|
||||
|
|
@ -2186,30 +2200,20 @@ in
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
"quickshell/NotificationToast.qml" = {
|
||||
onChange = qsRestart;
|
||||
text = ''
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Io
|
||||
import QtQuick
|
||||
|
||||
PanelWindow {
|
||||
id: notifToast
|
||||
required property var shellRoot
|
||||
screen: Quickshell.screens[0]
|
||||
// ── Notification Toast (only on primary screen) ──
|
||||
Item {
|
||||
id: toastItem
|
||||
visible: false
|
||||
property var currentNotif: null
|
||||
property bool open: false
|
||||
|
||||
property bool toastOpen: false
|
||||
readonly property var mutedApps: ["discord", "Discord", "Spotify", "spotify", "vlc", "mpv"]
|
||||
readonly property bool isPrimary: bar.screen === Quickshell.screens[0]
|
||||
|
||||
WlrLayershell.layer: WlrLayer.Overlay
|
||||
WlrLayershell.namespace: "quickshell-toast"
|
||||
exclusionMode: ExclusionMode.Ignore
|
||||
x: Math.round(bar.width / 2 - width / 2)
|
||||
y: 30
|
||||
width: _toastLeftEar.width + _toastRect.width + _toastRightEar.width
|
||||
height: _toastRect.height + 4
|
||||
|
||||
Process {
|
||||
id: notifSoundProc
|
||||
|
|
@ -2217,16 +2221,18 @@ in
|
|||
}
|
||||
|
||||
Connections {
|
||||
target: shellRoot
|
||||
target: bar.shellRoot
|
||||
function onNotificationReceived() {
|
||||
notifToast.show(shellRoot.latestNotification);
|
||||
if (toastItem.isPrimary) {
|
||||
toastItem.showToast(bar.shellRoot.latestNotification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function show(notification) {
|
||||
function showToast(notification) {
|
||||
currentNotif = notification;
|
||||
visible = true;
|
||||
open = true;
|
||||
toastOpen = true;
|
||||
_toastTimer.restart();
|
||||
if (!mutedApps.includes(notification.appName)) {
|
||||
notifSoundProc.running = true;
|
||||
|
|
@ -2234,27 +2240,20 @@ in
|
|||
}
|
||||
|
||||
function dismiss() {
|
||||
open = false;
|
||||
toastOpen = false;
|
||||
_toastCloseDelay.start();
|
||||
}
|
||||
|
||||
anchors.top: true
|
||||
margins.top: 30
|
||||
visible: false
|
||||
implicitWidth: 320 + 16
|
||||
implicitHeight: _toastRect.height + 4
|
||||
color: "transparent"
|
||||
|
||||
Timer {
|
||||
id: _toastTimer
|
||||
interval: 5000
|
||||
onTriggered: notifToast.dismiss()
|
||||
onTriggered: toastItem.dismiss()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: _toastCloseDelay
|
||||
interval: 230
|
||||
onTriggered: { notifToast.visible = false; notifToast.open = false; }
|
||||
onTriggered: { toastItem.visible = false; toastItem.toastOpen = false; }
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
|
|
@ -2266,6 +2265,7 @@ in
|
|||
|
||||
// Left inverse corner ear
|
||||
Item {
|
||||
id: _toastLeftEar
|
||||
anchors.right: _toastRect.left
|
||||
anchors.top: parent.top
|
||||
width: 8
|
||||
|
|
@ -2294,6 +2294,7 @@ in
|
|||
|
||||
// Right inverse corner ear
|
||||
Item {
|
||||
id: _toastRightEar
|
||||
anchors.left: _toastRect.right
|
||||
anchors.top: parent.top
|
||||
width: 8
|
||||
|
|
@ -2325,7 +2326,7 @@ in
|
|||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
width: 320
|
||||
height: notifToast.open ? toastCol.height + 16 : 0
|
||||
height: toastItem.toastOpen ? toastCol.height + 16 : 0
|
||||
color: Theme.barBg
|
||||
radius: 8
|
||||
topLeftRadius: 0
|
||||
|
|
@ -2369,7 +2370,7 @@ in
|
|||
|
||||
Text {
|
||||
width: parent.width
|
||||
text: notifToast.currentNotif ? (notifToast.currentNotif.summary || notifToast.currentNotif.appName) : ""
|
||||
text: toastItem.currentNotif ? (toastItem.currentNotif.summary || toastItem.currentNotif.appName) : ""
|
||||
color: Theme.base05
|
||||
font.family: "FiraMono Nerd Font"
|
||||
font.pixelSize: 12
|
||||
|
|
@ -2379,7 +2380,7 @@ in
|
|||
|
||||
Text {
|
||||
width: parent.width
|
||||
text: notifToast.currentNotif ? (notifToast.currentNotif.body || "") : ""
|
||||
text: toastItem.currentNotif ? (toastItem.currentNotif.body || "") : ""
|
||||
color: Theme.base04
|
||||
font.family: "FiraMono Nerd Font"
|
||||
font.pixelSize: 11
|
||||
|
|
@ -2391,9 +2392,9 @@ in
|
|||
|
||||
Row {
|
||||
spacing: 4
|
||||
visible: notifToast.currentNotif && notifToast.currentNotif.actions.length > 0
|
||||
visible: toastItem.currentNotif && toastItem.currentNotif.actions.length > 0
|
||||
Repeater {
|
||||
model: notifToast.currentNotif ? notifToast.currentNotif.actions : []
|
||||
model: toastItem.currentNotif ? toastItem.currentNotif.actions : []
|
||||
Rectangle {
|
||||
required property var modelData
|
||||
width: toastActionText.width + 12
|
||||
|
|
@ -2415,7 +2416,7 @@ in
|
|||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: { modelData.invoke(); notifToast.dismiss(); }
|
||||
onClicked: { modelData.invoke(); toastItem.dismiss(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2436,7 +2437,8 @@ in
|
|||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: { notifToast.currentNotif.dismiss(); notifToast.dismiss(); }
|
||||
onClicked: { toastItem.currentNotif.dismiss(); toastItem.dismiss(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue