1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-08-01 19:18:28 -04:00

launcher: add option to choose spotlight style on niri overview

This commit is contained in:
bbedward
2026-07-13 16:01:08 -04:00
parent 2cb48aaf6b
commit 3da19e5c15
9 changed files with 145 additions and 69 deletions
+1
View File
@@ -520,6 +520,7 @@ Singleton {
property var appDrawerSectionViewModes: ({}) property var appDrawerSectionViewModes: ({})
onAppDrawerSectionViewModesChanged: saveSettings() onAppDrawerSectionViewModesChanged: saveSettings()
property bool niriOverviewOverlayEnabled: true property bool niriOverviewOverlayEnabled: true
property string niriOverviewLauncherStyle: "full"
property string dankLauncherV2Size: "compact" property string dankLauncherV2Size: "compact"
property bool dankLauncherV2ShowSourceBadges: true property bool dankLauncherV2ShowSourceBadges: true
property bool dankLauncherV2BorderEnabled: false property bool dankLauncherV2BorderEnabled: false
@@ -251,6 +251,7 @@ var SPEC = {
spotlightSectionViewModes: { def: {} }, spotlightSectionViewModes: { def: {} },
appDrawerSectionViewModes: { def: {} }, appDrawerSectionViewModes: { def: {} },
niriOverviewOverlayEnabled: { def: true }, niriOverviewOverlayEnabled: { def: true },
niriOverviewLauncherStyle: { def: "full" },
dankLauncherV2Size: { def: "compact" }, dankLauncherV2Size: { def: "compact" },
dankLauncherV2ShowSourceBadges: { def: true }, dankLauncherV2ShowSourceBadges: { def: true },
dankLauncherV2BorderEnabled: { def: false }, dankLauncherV2BorderEnabled: { def: false },
@@ -120,18 +120,6 @@ Item {
readonly property int borderWidth: SettingsData.dankLauncherV2BorderEnabled ? SettingsData.dankLauncherV2BorderThickness : 0 readonly property int borderWidth: SettingsData.dankLauncherV2BorderEnabled ? SettingsData.dankLauncherV2BorderThickness : 0
readonly property bool useSingleWindow: CompositorService.isHyprland || useBackgroundDarken readonly property bool useSingleWindow: CompositorService.isHyprland || useBackgroundDarken
// Blur region isn't auto-committed on geometry changes; kick twice to catch resize settling.
function _kickBlurCommit() {
launcherBlur.kick();
Qt.callLater(launcherBlur.kick);
}
onAlignedXChanged: _kickBlurCommit()
onAlignedYChanged: _kickBlurCommit()
onAlignedWidthChanged: _kickBlurCommit()
on_ContentImplicitHChanged: _kickBlurCommit()
onContentVisibleChanged: _kickBlurCommit()
signal dialogClosed signal dialogClosed
function _ensureContentLoadedAndInitialize(query, mode) { function _ensureContentLoadedAndInitialize(query, mode) {
@@ -354,9 +342,6 @@ Item {
blurRadius: root.cornerRadius blurRadius: root.cornerRadius
} }
onWidthChanged: root._kickBlurCommit()
onHeightChanged: root._kickBlurCommit()
WlrLayershell.namespace: "dms:spotlight" WlrLayershell.namespace: "dms:spotlight"
WlrLayershell.layer: root.effectiveLauncherLayer WlrLayershell.layer: root.effectiveLauncherLayer
WlrLayershell.exclusiveZone: -1 WlrLayershell.exclusiveZone: -1
@@ -441,9 +426,6 @@ Item {
opacity: contentVisible ? 1 : 0 opacity: contentVisible ? 1 : 0
onOpacityChanged: root._kickBlurCommit()
onSlideOffsetChanged: root._kickBlurCommit()
Behavior on opacity { Behavior on opacity {
NumberAnimation { NumberAnimation {
duration: contentVisible ? root._openDuration : root._closeDuration duration: contentVisible ? root._openDuration : root._closeDuration
@@ -322,9 +322,13 @@ DankPopout {
DankTabBar { DankTabBar {
id: tabBar id: tabBar
// Effective visibility is false while the popout window is unmapped, so gating
// height on `visible` collapses the bar between opens and resizes the surface
// mid-animation. Gate on the model instead.
readonly property bool hasTabs: (model?.length ?? 0) > 0
width: parent.width width: parent.width
height: visible ? 48 : 0 height: hasTabs ? 48 : 0
visible: model.length > 0 visible: hasTabs
currentIndex: root.currentTabIndex currentIndex: root.currentTabIndex
spacing: Theme.spacingS spacing: Theme.spacingS
equalWidthTabs: true equalWidthTabs: true
@@ -356,8 +360,8 @@ DankPopout {
Item { Item {
width: parent.width width: parent.width
height: visible ? Theme.spacingXS : 0 height: tabBar.hasTabs ? Theme.spacingXS : 0
visible: tabBar.visible visible: tabBar.hasTabs
} }
Item { Item {
@@ -223,8 +223,9 @@ Rectangle {
Rectangle { Rectangle {
id: dankWarning id: dankWarning
width: parent.width width: parent.width
visible: CalendarService && CalendarService.dankNeedsLaunch readonly property bool showWarning: CalendarService?.dankNeedsLaunch ?? false
height: visible ? Math.max(28, warningRow.implicitHeight) + Theme.spacingS : 0 visible: showWarning
height: showWarning ? Math.max(28, warningRow.implicitHeight) + Theme.spacingS : 0
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: Theme.warningHover color: Theme.warningHover
border.color: Theme.withAlpha(Theme.warning, 0.35) border.color: Theme.withAlpha(Theme.warning, 0.35)
@@ -770,6 +770,20 @@ Item {
checked: SettingsData.niriOverviewOverlayEnabled checked: SettingsData.niriOverviewOverlayEnabled
onToggled: checked => SettingsData.set("niriOverviewOverlayEnabled", checked) onToggled: checked => SettingsData.set("niriOverviewOverlayEnabled", checked)
} }
SettingsButtonGroupRow {
visible: SettingsData.niriOverviewOverlayEnabled
settingKey: "niriOverviewLauncherStyle"
tags: ["launcher", "niri", "overview", "overlay", "style", "spotlight", "full"]
text: I18n.tr("Default Opens")
model: [I18n.tr("Full"), I18n.tr("Spotlight")]
currentIndex: SettingsData.niriOverviewLauncherStyle === "spotlight" ? 1 : 0
onSelectionChanged: (index, selected) => {
if (!selected)
return;
SettingsData.set("niriOverviewLauncherStyle", index === 1 ? "spotlight" : "full");
}
}
} }
SettingsCard { SettingsCard {
@@ -101,6 +101,23 @@ Scope {
readonly property bool overlayVisible: NiriService.inOverview || niriOverviewScope.isClosing readonly property bool overlayVisible: NiriService.inOverview || niriOverviewScope.isClosing
property bool hasActivePopout: !!PopoutManager.currentPopoutsByScreen[screen.name] property bool hasActivePopout: !!PopoutManager.currentPopoutsByScreen[screen.name]
property bool hasActiveModal: !!ModalManager.currentModalsByScreen[screen.name] property bool hasActiveModal: !!ModalManager.currentModalsByScreen[screen.name]
readonly property bool useSpotlightStyle: SettingsData.niriOverviewLauncherStyle === "spotlight"
readonly property var launcherContent: useSpotlightStyle ? spotlightLauncherLoader.item : fullLauncherLoader.item
readonly property QtObject fakeParentModal: QtObject {
readonly property bool spotlightOpen: spotlightContainer.visible
readonly property bool isClosing: niriOverviewScope.isClosing
readonly property real alignedX: spotlightContainer.x
readonly property real alignedY: spotlightContainer.y
readonly property real screenHeight: overlayWindow.screen?.height ?? 1080
function hide() {
if (niriOverviewScope.searchActive) {
niriOverviewScope.hideSpotlight();
return;
}
NiriService.toggleOverview();
}
}
Connections { Connections {
target: PopoutManager target: PopoutManager
@@ -219,13 +236,13 @@ Scope {
if (event.isAutoRepeat || !event.text) if (event.isAutoRepeat || !event.text)
return; return;
if (!launcherContent?.searchField) if (!overlayWindow.launcherContent?.searchField)
return; return;
const trimmedText = event.text.trim(); const trimmedText = event.text.trim();
launcherContent.searchField.text = trimmedText; overlayWindow.launcherContent.searchField.text = trimmedText;
launcherContent.controller.setSearchQuery(trimmedText); overlayWindow.launcherContent.controller.setSearchQuery(trimmedText);
niriOverviewScope.showSpotlight(overlayWindow.screen.name); niriOverviewScope.showSpotlight(overlayWindow.screen.name);
Qt.callLater(() => launcherContent.searchField.forceActiveFocus()); Qt.callLater(() => overlayWindow.launcherContent.searchField.forceActiveFocus());
event.accepted = true; event.accepted = true;
} }
} }
@@ -237,7 +254,7 @@ Scope {
// edge and slide in from beyond that edge. In any other mode the // edge and slide in from beyond that edge. In any other mode the
// spotlight stays centered — identical to master. // spotlight stays centered — identical to master.
readonly property string connectedEmergeSide: SettingsData.frameLauncherEmergeSide || "bottom" readonly property string connectedEmergeSide: SettingsData.frameLauncherEmergeSide || "bottom"
readonly property real _centerY: (parent.height - height) / 2 readonly property real _centerY: overlayWindow.useSpotlightStyle ? Math.max(0, parent.height * 0.33 - 28) : (parent.height - height) / 2
readonly property real _connectedRestY: { readonly property real _connectedRestY: {
if (!Theme.isConnectedEffect || !overlayWindow.screen) if (!Theme.isConnectedEffect || !overlayWindow.screen)
return _centerY; return _centerY;
@@ -277,8 +294,8 @@ Scope {
return 600; return 600;
} }
} }
width: Math.min(baseWidth, overlayWindow.screen.width - 100) width: overlayWindow.useSpotlightStyle ? Math.min(680, overlayWindow.screen.width - 80) : Math.min(baseWidth, overlayWindow.screen.width - 100)
height: Math.min(baseHeight, overlayWindow.screen.height - 100) height: overlayWindow.useSpotlightStyle ? Math.ceil(overlayWindow.launcherContent?.implicitHeight ?? 56) : Math.min(baseHeight, overlayWindow.screen.height - 100)
readonly property bool animatingOut: niriOverviewScope.isClosing && overlayWindow.isSpotlightScreen readonly property bool animatingOut: niriOverviewScope.isClosing && overlayWindow.isSpotlightScreen
@@ -344,57 +361,51 @@ Scope {
anchors.fill: parent anchors.fill: parent
focus: true focus: true
Keys.onPressed: event => launcherContent.activeContextMenu?.handleKey(event) Keys.onPressed: event => overlayWindow.launcherContent?.activeContextMenu?.handleKey(event)
Keys.onEscapePressed: event => { Keys.onEscapePressed: event => {
launcherContent.activeContextMenu?.handleKey(event); overlayWindow.launcherContent?.activeContextMenu?.handleKey(event);
if (!event.accepted) if (!event.accepted)
launcherContent.parentModal?.hide(); overlayWindow.launcherContent?.parentModal?.hide();
event.accepted = true; event.accepted = true;
} }
LauncherContent { Loader {
id: launcherContent id: fullLauncherLoader
anchors.fill: parent anchors.fill: parent
anchors.margins: 0 active: !overlayWindow.useSpotlightStyle
sourceComponent: LauncherContent {
property var fakeParentModal: QtObject { parentModal: overlayWindow.fakeParentModal
property bool spotlightOpen: spotlightContainer.visible
property bool isClosing: niriOverviewScope.isClosing
property real alignedX: spotlightContainer.x
property real alignedY: spotlightContainer.y
function hide() {
if (niriOverviewScope.searchActive) {
niriOverviewScope.hideSpotlight();
return;
}
NiriService.toggleOverview();
}
} }
}
Connections { Loader {
target: launcherContent.searchField id: spotlightLauncherLoader
function onTextChanged() { anchors.fill: parent
if (launcherContent.searchField.text.length > 0 || !niriOverviewScope.searchActive) active: overlayWindow.useSpotlightStyle
return; sourceComponent: SpotlightLauncherContent {
niriOverviewScope.hideSpotlight(); parentModal: overlayWindow.fakeParentModal
}
} }
}
Component.onCompleted: { Connections {
parentModal = fakeParentModal; target: overlayWindow.launcherContent?.searchField ?? null
function onTextChanged() {
if (overlayWindow.launcherContent.searchField.text.length > 0 || !niriOverviewScope.searchActive)
return;
niriOverviewScope.hideSpotlight();
} }
}
Connections { Connections {
target: launcherContent.controller target: overlayWindow.launcherContent?.controller ?? null
function onItemExecuted() { function onItemExecuted() {
niriOverviewScope.releaseKeyboard = true; niriOverviewScope.releaseKeyboard = true;
} }
function onModeChanged(mode) { function onModeChanged(mode) {
if (launcherContent.controller.autoSwitchedToFiles) if (overlayWindow.launcherContent.controller.autoSwitchedToFiles)
return; return;
SessionData.setNiriOverviewLastMode(mode); SessionData.setNiriOverviewLastMode(mode);
}
} }
} }
} }
+42
View File
@@ -60,6 +60,42 @@ Item {
targetWindow.BackgroundEffect.blurRegion = _active ? blurRegion : null; targetWindow.BackgroundEffect.blurRegion = _active ? blurRegion : null;
} }
// Republish after geometry settles, plus one trailing pass.
onBlurXChanged: settleKickAction.restart()
onBlurYChanged: settleKickAction.restart()
onBlurWidthChanged: settleKickAction.restart()
onBlurHeightChanged: settleKickAction.restart()
onBlurRadiusChanged: settleKickAction.restart()
onClipEnabledChanged: settleKickAction.restart()
onClipXChanged: settleKickAction.restart()
onClipYChanged: settleKickAction.restart()
onClipWidthChanged: settleKickAction.restart()
onClipHeightChanged: settleKickAction.restart()
function _runSettleKick() {
if (!targetWindow?.visible)
return;
kick();
settleRepeatTimer.restart();
}
DeferredAction {
id: settleKickAction
interval: 16
onTriggered: root._runSettleKick()
}
Timer {
id: settleRepeatTimer
interval: 96
repeat: false
onTriggered: {
if (!root.targetWindow?.visible)
return;
root.kick();
}
}
function _scheduleLifecycleKick() { function _scheduleLifecycleKick() {
lifecycleKickAction.restart(); lifecycleKickAction.restart();
} }
@@ -98,6 +134,12 @@ Item {
else else
root._clear(); root._clear();
} }
function onWidthChanged() {
settleKickAction.restart();
}
function onHeightChanged() {
settleKickAction.restart();
}
function onResourcesLost() { function onResourcesLost() {
root._clear(); root._clear();
// Re-arm so blur self-heals since instances are no longer recreated per open // Re-arm so blur self-heals since instances are no longer recreated per open
@@ -2398,6 +2398,26 @@
"style" "style"
] ]
}, },
{
"section": "niriOverviewLauncherStyle",
"label": "Default Opens",
"tabIndex": 9,
"category": "Launcher",
"keywords": [
"default",
"drawer",
"full",
"launcher",
"menu",
"niri",
"opens",
"overlay",
"overview",
"spotlight",
"start",
"style"
]
},
{ {
"section": "niriOverviewOverlayEnabled", "section": "niriOverviewOverlayEnabled",
"label": "Enable Overview Overlay", "label": "Enable Overview Overlay",