quickshell: seamless switching between dropdowns

Remove grabFocus from BarDropdown. Centralized toggleDropdown()
closes the active dropdown before opening a new one, so clicking
between network/battery/calendar/tray is instant — no double-click.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
rope 2026-05-26 17:13:58 +01:00
parent 2b9edcb589
commit 98d1e6249c

View file

@ -458,6 +458,25 @@ in
implicitHeight: 30
color: "#D1${c.base00}"
property var activeDropdown: null
function closeAllDropdowns() {
if (activeDropdown && activeDropdown.visible) {
activeDropdown.visible = false;
}
activeDropdown = null;
}
function toggleDropdown(dd, setupFn) {
if (dd.visible) {
dd.visible = false;
activeDropdown = null;
} else {
closeAllDropdowns();
if (setupFn) setupFn();
dd.visible = true;
activeDropdown = dd;
}
}
// Left workspaces
Row {
anchors.left: parent.left
@ -519,23 +538,11 @@ in
MouseArea {
anchors.fill: parent
onClicked: {
if (calPopup.justDismissed) return;
if (calPopup.visible) {
calPopup.open = false;
calCloseTimer.start();
} else {
calPopup.visible = true;
bar.toggleDropdown(calPopup);
}
}
}
Timer {
id: calCloseTimer
interval: 230
onTriggered: calPopup.visible = false
}
}
// Right network, battery, tray
Row {
anchors.right: parent.right
@ -653,16 +660,12 @@ in
MouseArea {
anchors.fill: parent
onClicked: {
if (netDropdown.justDismissed) return;
if (netDropdown.visible) {
netDropdown.visible = false;
} else {
bar.toggleDropdown(netDropdown, function() {
netWidget.wifiNetworks = [];
wifiScanProc.running = true;
let pos = netWidget.mapToItem(bar.contentItem, netWidget.width / 2, 0);
netDropdown.dropdownX = pos.x;
netDropdown.visible = true;
}
});
}
}
}
@ -765,16 +768,12 @@ in
MouseArea {
anchors.fill: parent
onClicked: {
if (batteryDropdown.justDismissed) return;
if (batteryDropdown.visible) {
batteryDropdown.visible = false;
} else {
bar.toggleDropdown(batteryDropdown, function() {
batteryProc.running = true;
profileProc.running = true;
let pos = batteryWidget.mapToItem(bar.contentItem, batteryWidget.width / 2, 0);
batteryDropdown.dropdownX = pos.x;
batteryDropdown.visible = true;
}
});
}
}
}
@ -815,13 +814,13 @@ in
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: (event) => {
if (contextMenu.justDismissed) return;
if (event.button === Qt.RightButton && modelData.hasMenu) {
bar.toggleDropdown(contextMenu, function() {
let pos = parent.mapToItem(bar.contentItem, parent.width / 2, 0);
contextMenu.dropdownX = pos.x;
contextMenu.trayItem = modelData;
menuOpener.menu = modelData.menu;
contextMenu.visible = true;
});
} else {
modelData.activate();
}
@ -836,7 +835,6 @@ in
component BarDropdown: PopupWindow {
id: dropdown
property bool open: false
property bool justDismissed: false
property real dropdownX: 0
property real fullWidth: 200
property real fullHeight: 200
@ -848,7 +846,6 @@ in
anchor.edges: Edges.Top | Edges.Left
anchor.gravity: Edges.Bottom | Edges.Right
anchor.adjustment: PopupAdjustment.Slide
grabFocus: true
visible: false
color: "transparent"
implicitWidth: fullWidth + 16
@ -859,17 +856,9 @@ in
open = true;
} else {
open = false;
justDismissed = true;
_dismissGuard.start();
}
}
Timer {
id: _dismissGuard
interval: 100
onTriggered: dropdown.justDismissed = false
}
Item {
anchors.right: _dropdownRect.left
anchors.top: parent.top
@ -1010,7 +999,7 @@ in
enabled: !modelData.isSeparator && modelData.enabled
onClicked: {
modelData.triggered();
contextMenu.visible = false;
bar.closeAllDropdowns();
}
}
}
@ -1071,7 +1060,7 @@ in
netWidget.netState = "disconnected";
netWidget.netConn = "";
netWidget.netIcon = "\u{f05aa}";
netDropdown.visible = false;
bar.closeAllDropdowns();
netRefreshDelay.start();
}
}
@ -1160,7 +1149,7 @@ in
wifiConnectProc.running = true;
netRefreshDelay.start();
}
netDropdown.visible = false;
bar.closeAllDropdowns();
}
}
}