From 67968aef79e93629aeb9ef047294126a3bfea9bf Mon Sep 17 00:00:00 2001 From: bbedward Date: Wed, 26 Aug 2026 13:40:20 -0400 Subject: [PATCH] notifications: add option to execute default action on body click instead of expanding text fixes #2425 --- quickshell/Common/SettingsData.qml | 1 + quickshell/Common/settings/SettingsSpec.js | 1 + .../Notifications/Popup/NotificationPopup.qml | 22 +++++++++++++--- .../Modules/Settings/NotificationsTab.qml | 9 +++++++ .../translations/settings_search_index.json | 26 +++++++++++++++++++ 5 files changed, 56 insertions(+), 3 deletions(-) diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index f835ce9a2..81131bdb2 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -899,6 +899,7 @@ Singleton { property bool notificationOverlayEnabled: false property bool notificationPopupShadowEnabled: true property bool notificationPopupPrivacyMode: false + property bool notificationPopupBodyInvokesAction: false property bool notificationForegroundLayers: true property int overviewRows: 2 property int overviewColumns: 5 diff --git a/quickshell/Common/settings/SettingsSpec.js b/quickshell/Common/settings/SettingsSpec.js index fa4725819..f4af177b9 100644 --- a/quickshell/Common/settings/SettingsSpec.js +++ b/quickshell/Common/settings/SettingsSpec.js @@ -465,6 +465,7 @@ var SPEC = { notificationOverlayEnabled: { def: false }, notificationPopupShadowEnabled: { def: true }, notificationPopupPrivacyMode: { def: false }, + notificationPopupBodyInvokesAction: { def: false }, notificationForegroundLayers: { def: true }, overviewRows: { def: 2, persist: false }, overviewColumns: { def: 5, persist: false }, diff --git a/quickshell/Modules/Notifications/Popup/NotificationPopup.qml b/quickshell/Modules/Notifications/Popup/NotificationPopup.qml index 4fc4940c2..ddff9b756 100644 --- a/quickshell/Modules/Notifications/Popup/NotificationPopup.qml +++ b/quickshell/Modules/Notifications/Popup/NotificationPopup.qml @@ -109,6 +109,7 @@ PanelWindow { readonly property string clearText: I18n.tr("Dismiss") property bool descriptionExpanded: false readonly property bool hasExpandableBody: (notificationData?.htmlBody || "").replace(/<[^>]*>/g, "").trim().length > 0 + readonly property bool bodyClickInvokesAction: SettingsData.notificationPopupBodyInvokesAction && (notificationData?.actions?.length ?? 0) > 0 onDescriptionExpandedChanged: { if (connectedFrameMode) popupChromeGeometryChanged(); @@ -176,6 +177,11 @@ PanelWindow { popupContextMenuLoader.active = false; } + function invokeDefaultAction() { + notificationData.actions[0].invoke(); + NotificationService.dismissNotification(notificationData); + } + function dismissPopupReliably() { if (!notificationData || win.exiting || win._isDestroying) return; @@ -966,10 +972,16 @@ PanelWindow { MouseArea { anchors.fill: parent - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : (bodyText.hasMoreText || descriptionExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor + cursorShape: (parent.hoveredLink || win.bodyClickInvokesAction || bodyText.hasMoreText || descriptionExpanded) ? Qt.PointingHandCursor : Qt.ArrowCursor onClicked: mouse => { - if (!parent.hoveredLink && (bodyText.hasMoreText || descriptionExpanded)) + if (parent.hoveredLink || win.exiting) + return; + if (win.bodyClickInvokesAction) { + win.invokeDefaultAction(); + return; + } + if (bodyText.hasMoreText || descriptionExpanded) win.descriptionExpanded = !win.descriptionExpanded; } @@ -1023,7 +1035,7 @@ PanelWindow { iconSize: compactMode ? 14 : 16 buttonSize: compactMode ? 20 : 24 z: 15 - visible: SettingsData.notificationPopupPrivacyMode && win.hasExpandableBody + visible: (SettingsData.notificationPopupPrivacyMode || win.bodyClickInvokesAction) && win.hasExpandableBody onClicked: { if (win.hasExpandableBody) @@ -1155,6 +1167,10 @@ PanelWindow { menu.showAt(win.margins.left + p.x, win.margins.top + p.y, win.screen); } } else if (mouse.button === Qt.LeftButton) { + if (win.bodyClickInvokesAction) { + win.invokeDefaultAction(); + return; + } const canExpand = bodyText.hasMoreText || win.descriptionExpanded || (SettingsData.notificationPopupPrivacyMode && win.hasExpandableBody); if (canExpand) { win.descriptionExpanded = !win.descriptionExpanded; diff --git a/quickshell/Modules/Settings/NotificationsTab.qml b/quickshell/Modules/Settings/NotificationsTab.qml index 37a8c9c3f..f6322d9fb 100644 --- a/quickshell/Modules/Settings/NotificationsTab.qml +++ b/quickshell/Modules/Settings/NotificationsTab.qml @@ -342,6 +342,15 @@ Item { onToggled: checked => SettingsData.set("notificationPopupPrivacyMode", checked) } + SettingsToggleRow { + settingKey: "notificationPopupBodyInvokesAction" + tags: ["notification", "popup", "click", "body", "action", "invoke", "expand", "open"] + text: I18n.tr("Body Click Runs Default Action") + description: I18n.tr("Clicking a popup runs its first action instead of expanding the body") + checked: SettingsData.notificationPopupBodyInvokesAction + onToggled: checked => SettingsData.set("notificationPopupBodyInvokesAction", checked) + } + SettingsToggleRow { settingKey: "notificationFocusedMonitor" tags: ["notification", "popup", "focused", "monitor", "display", "screen", "active"] diff --git a/quickshell/translations/settings_search_index.json b/quickshell/translations/settings_search_index.json index ceaa35de4..5dee4a130 100644 --- a/quickshell/translations/settings_search_index.json +++ b/quickshell/translations/settings_search_index.json @@ -6915,6 +6915,32 @@ ], "description": "Control animation duration for notification popups and history" }, + { + "section": "notificationPopupBodyInvokesAction", + "label": "Body Click Runs Default Action", + "tabIndex": 17, + "category": "Notifications", + "keywords": [ + "action", + "alerts", + "body", + "click", + "clicking", + "default", + "expand", + "expanding", + "first", + "invoke", + "messages", + "notification", + "notifications", + "open", + "popup", + "runs", + "toast" + ], + "description": "Clicking a popup runs its first action instead of expanding the body" + }, { "section": "notificationBodyFontSize", "label": "Body Font Size",