quickshell: click-outside dropdown dismissal, drop auto-close timers
Extend the launcher/session HyprlandFocusGrab to the bar dropdowns and remove the per-dropdown inactivity timers. Shift+Super+S brackets hyprshot with a screenshot pin so open menus survive slurp's input grab. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
215239e7aa
commit
83b4c5ef09
2 changed files with 36 additions and 40 deletions
|
|
@ -281,7 +281,9 @@ in
|
|||
end
|
||||
|
||||
-- Screenshots — Shift+Super+S matches GNOME binding
|
||||
hl.bind(mod .. " + SHIFT + S", hl.dsp.exec_cmd("hyprshot -m region --clipboard-only"))
|
||||
-- Pin/unpin quickshell's focus grab around the region select so an
|
||||
-- open menu survives slurp's input grab (no-ops if qs isn't up).
|
||||
hl.bind(mod .. " + SHIFT + S", hl.dsp.exec_cmd("sh -c 'qs ipc call screenshot pin; hyprshot -m region --clipboard-only; qs ipc call screenshot unpin'"))
|
||||
hl.bind("Print", hl.dsp.exec_cmd("hyprshot -m output --clipboard-only"))
|
||||
|
||||
-- Settings shortcut — Super+I matches GNOME binding
|
||||
|
|
|
|||
|
|
@ -238,6 +238,16 @@ in
|
|||
function reload(): void { Quickshell.reload(false); }
|
||||
}
|
||||
|
||||
// Screenshot pin: the Shift+Super+S keybind brackets hyprshot
|
||||
// with pin/unpin so the focus grab is suspended while slurp
|
||||
// grabs input — otherwise the open menu would close like any
|
||||
// click-outside. Self-heals via a watchdog if unpin is missed.
|
||||
IpcHandler {
|
||||
target: "screenshot"
|
||||
function pin(): void { if (root.mainBar) root.mainBar.setScreenshotPin(true); }
|
||||
function unpin(): void { if (root.mainBar) root.mainBar.setScreenshotPin(false); }
|
||||
}
|
||||
|
||||
NotificationServer {
|
||||
id: _notifServer
|
||||
bodySupported: true
|
||||
|
|
@ -291,7 +301,7 @@ in
|
|||
// (caelestia's): the grab redirects focus to this window and
|
||||
// OnDemand lets the layer surface accept it. Exclusive fights
|
||||
// the grab — it self-clears and instantly closes the panel.
|
||||
WlrLayershell.keyboardFocus: sessionMenu.open || launcherPanel.open ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
|
||||
WlrLayershell.keyboardFocus: (sessionMenu.open || launcherPanel.open || bar.activeDropdown !== null) && !bar.screenshotPinned ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
|
|
@ -910,18 +920,38 @@ in
|
|||
}
|
||||
}
|
||||
|
||||
// Click-outside dismissal for the keyboard-grabbing panels
|
||||
// Click-outside dismissal for every panel — the launcher,
|
||||
// session menu AND the bar dropdowns. Clicking into another
|
||||
// window (or anywhere outside the bar) clears the grab and
|
||||
// closes whatever is open. Suspended while screenshotPinned so
|
||||
// slurp can grab input without dismissing the menu.
|
||||
HyprlandFocusGrab {
|
||||
active: sessionMenu.open || launcherPanel.open
|
||||
active: (sessionMenu.open || launcherPanel.open || bar.activeDropdown !== null) && !bar.screenshotPinned
|
||||
windows: [bar]
|
||||
onCleared: {
|
||||
if (bar.screenshotPinned) return;
|
||||
sessionMenu.open = false;
|
||||
launcherPanel.open = false;
|
||||
bar.closeAllDropdowns();
|
||||
}
|
||||
}
|
||||
|
||||
property var activeDropdown: null
|
||||
|
||||
// Set by the screenshot keybind (via IPC) to hold menus open
|
||||
// while a region screenshot runs. Watchdog unpins if the
|
||||
// bracketing unpin call is ever missed.
|
||||
property bool screenshotPinned: false
|
||||
Timer {
|
||||
id: _pinWatchdog
|
||||
interval: 30000
|
||||
onTriggered: bar.screenshotPinned = false
|
||||
}
|
||||
function setScreenshotPin(v) {
|
||||
screenshotPinned = v;
|
||||
if (v) _pinWatchdog.restart(); else _pinWatchdog.stop();
|
||||
}
|
||||
|
||||
function closeAllDropdowns() {
|
||||
if (activeDropdown && activeDropdown.visible) {
|
||||
activeDropdown.animateClose();
|
||||
|
|
@ -1024,7 +1054,6 @@ in
|
|||
onEntered: {
|
||||
if (bar.activeDropdown) {
|
||||
if (bar.activeDropdown !== calPopup) bar.toggleDropdown(calPopup, function() { calPopup.resetView(); });
|
||||
else bar.activeDropdown.resetAutoClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1104,7 +1133,6 @@ in
|
|||
onEntered: {
|
||||
if (bar.activeDropdown) {
|
||||
if (bar.activeDropdown !== volDropdown) volWidget.openVolDropdown();
|
||||
else bar.activeDropdown.resetAutoClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1271,7 +1299,6 @@ in
|
|||
onEntered: {
|
||||
if (bar.activeDropdown) {
|
||||
if (bar.activeDropdown !== netDropdown) netWidget.openNetDropdown();
|
||||
else bar.activeDropdown.resetAutoClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1352,7 +1379,6 @@ in
|
|||
onEntered: {
|
||||
if (bar.activeDropdown) {
|
||||
if (bar.activeDropdown !== batteryDropdown) batteryWidget.openBatteryDropdown();
|
||||
else bar.activeDropdown.resetAutoClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1366,12 +1392,6 @@ in
|
|||
height: Theme.barHeight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
HoverHandler {
|
||||
onHoveredChanged: {
|
||||
if (hovered && bar.activeDropdown) bar.activeDropdown.resetAutoClose();
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: SystemTray.items
|
||||
|
||||
|
|
@ -1405,7 +1425,6 @@ in
|
|||
acceptedButtons: Qt.NoButton
|
||||
onEntered: {
|
||||
if (bar.activeDropdown) {
|
||||
bar.activeDropdown.resetAutoClose();
|
||||
if (modelData.hasMenu && !(bar.activeDropdown === contextMenu && contextMenu.trayItem === modelData)) {
|
||||
if (bar.activeDropdown === contextMenu) {
|
||||
// Same dropdown, just switch content
|
||||
|
|
@ -1413,7 +1432,6 @@ in
|
|||
contextMenu.dropdownX = pos.x;
|
||||
contextMenu.trayItem = modelData;
|
||||
menuOpener.menu = modelData.menu;
|
||||
contextMenu.resetAutoClose();
|
||||
} else {
|
||||
bar.toggleDropdown(contextMenu, function() {
|
||||
let pos = parent.mapToItem(bar.contentItem, parent.width / 2, 0);
|
||||
|
|
@ -1457,7 +1475,6 @@ in
|
|||
property real dropdownX: 0
|
||||
property real fullWidth: 200
|
||||
property real fullHeight: 200
|
||||
property int autoCloseMs: 1500
|
||||
// Flush-right dropdowns merge into the screen frame's
|
||||
// right column instead of centering on their widget.
|
||||
property bool alignRight: false
|
||||
|
|
@ -1477,14 +1494,9 @@ in
|
|||
bar.activeDropdown = null;
|
||||
chrome.shrinkToButton(dropdown);
|
||||
}
|
||||
_autoClose.stop();
|
||||
_closeDelay.start();
|
||||
}
|
||||
|
||||
function resetAutoClose() {
|
||||
if (visible && !closing) _autoClose.restart();
|
||||
}
|
||||
|
||||
// Reopen a dropdown that's mid-close: the pending hide
|
||||
// timer must be cancelled, otherwise it fires later and
|
||||
// closes the revived dropdown (and the whole chrome).
|
||||
|
|
@ -1492,7 +1504,6 @@ in
|
|||
_closeDelay.stop();
|
||||
closing = false;
|
||||
open = true;
|
||||
_autoClose.restart();
|
||||
}
|
||||
|
||||
x: alignRight
|
||||
|
|
@ -1507,33 +1518,18 @@ in
|
|||
if (visible) {
|
||||
closing = false;
|
||||
open = true;
|
||||
_autoClose.restart();
|
||||
} else {
|
||||
open = false;
|
||||
closing = false;
|
||||
_autoClose.stop();
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: _autoClose
|
||||
interval: dropdown.autoCloseMs
|
||||
onTriggered: bar.closeAllDropdowns()
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: _closeDelay
|
||||
interval: 300
|
||||
onTriggered: { dropdown.visible = false; dropdown.closing = false; if (bar.activeDropdown === dropdown) bar.activeDropdown = null; }
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
onHoveredChanged: {
|
||||
if (hovered) _autoClose.stop();
|
||||
else _autoClose.restart();
|
||||
}
|
||||
}
|
||||
|
||||
// Content is clipped to the chrome's ANIMATED geometry —
|
||||
// revealed as the panel slides/grows over it and wiped as
|
||||
// the panel leaves, instead of popping in place. The inner
|
||||
|
|
@ -1731,7 +1727,6 @@ in
|
|||
alignRight: true
|
||||
fullWidth: volDropdownCol.width + 28
|
||||
fullHeight: volDropdownCol.height + 20
|
||||
autoCloseMs: 3000
|
||||
|
||||
Column {
|
||||
id: volDropdownCol
|
||||
|
|
@ -2165,7 +2160,6 @@ in
|
|||
// edges render as soft 2px lines
|
||||
fullWidth: Math.ceil(calRow.width) + 24
|
||||
fullHeight: Math.ceil(calRow.height) + 24
|
||||
autoCloseMs: 3000
|
||||
|
||||
// Month being viewed; reset to today when the popup opens
|
||||
// (via the setup function passed to bar.toggleDropdown).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue