feat(dock): implement context menu for launcher icon and improve screen handling

This commit is contained in:
tibssy
2026-02-19 04:28:36 +00:00
parent 6c555770cd
commit ff4da5d2b9
3 changed files with 153 additions and 8 deletions
+1
View File
@@ -17,6 +17,7 @@
"open-display-settings": "Display settings",
"open-launcher": "Open launcher",
"open-settings": "Open settings",
"dock-settings": "Dock settings",
"raise-to-top": "Raise to top",
"random-wallpaper": "Random wallpaper",
"run-custom-command": "Run custom command",
+90 -7
View File
@@ -154,6 +154,36 @@ Item {
}
return {};
}
readonly property string launcherWidgetSection: {
const widgetsBySection = screenName ? Settings.getBarWidgetsForScreen(screenName) : Settings.data.bar.widgets;
if (!widgetsBySection)
return "";
const sections = ["left", "center", "right"];
for (let i = 0; i < sections.length; i++) {
const sectionWidgets = widgetsBySection[sections[i]] || [];
for (let j = 0; j < sectionWidgets.length; j++) {
const widget = sectionWidgets[j];
if (widget && widget.id === "Launcher")
return sections[i];
}
}
return "";
}
readonly property int launcherWidgetIndex: {
const widgetsBySection = screenName ? Settings.getBarWidgetsForScreen(screenName) : Settings.data.bar.widgets;
if (!widgetsBySection)
return -1;
const sections = ["left", "center", "right"];
for (let i = 0; i < sections.length; i++) {
const sectionWidgets = widgetsBySection[sections[i]] || [];
for (let j = 0; j < sectionWidgets.length; j++) {
const widget = sectionWidgets[j];
if (widget && widget.id === "Launcher")
return j;
}
}
return -1;
}
readonly property var launcherMetadata: BarWidgetRegistry.widgetMetadata["Launcher"]
readonly property string launcherIcon: launcherWidgetSettings.icon || (launcherMetadata && launcherMetadata.icon ? launcherMetadata.icon : "search")
readonly property string launcherIconColorKey: launcherWidgetSettings.iconColor !== undefined
@@ -188,7 +218,7 @@ Item {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.MiddleButton
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
onEntered: {
dockRoot.anyAppHovered = true;
@@ -210,15 +240,67 @@ Item {
}
onClicked: mouse => {
if (mouse.button !== Qt.LeftButton && mouse.button !== Qt.MiddleButton) {
return;
}
const targetScreen = dockRoot.modelData || dockRoot.screen || null;
if (!targetScreen) {
return;
}
dockRoot.closeAllContextMenus();
PanelService.toggleLauncher(targetScreen);
if (mouse.button === Qt.RightButton) {
if (dockRoot.currentContextMenu === launcherContextMenu && launcherContextMenu.visible) {
dockRoot.closeAllContextMenus();
return;
}
dockRoot.closeAllContextMenus();
TooltipService.hideImmediately();
launcherContextMenu.show(launcherButton, null, targetScreen);
return;
}
if (mouse.button === Qt.LeftButton || mouse.button === Qt.MiddleButton) {
dockRoot.closeAllContextMenus();
PanelService.toggleLauncher(targetScreen);
}
}
}
DockMenu {
id: launcherContextMenu
dockPosition: dockRoot.dockPosition
menuMode: "launcher"
launcherWidgetSection: launcherButton.launcherWidgetSection
launcherWidgetIndex: launcherButton.launcherWidgetIndex
launcherWidgetSettings: launcherButton.launcherWidgetSettings
onHoveredChanged: {
if (dockRoot.currentContextMenu === launcherContextMenu && launcherContextMenu.visible) {
dockRoot.menuHovered = hovered;
} else {
dockRoot.menuHovered = false;
}
}
Connections {
target: launcherContextMenu
function onRequestClose() {
dockRoot.currentContextMenu = null;
dockRoot.hideTimer.stop();
launcherContextMenu.hide();
dockRoot.menuHovered = false;
dockRoot.anyAppHovered = false;
}
}
onVisibleChanged: {
if (visible) {
dockRoot.currentContextMenu = launcherContextMenu;
} else if (dockRoot.currentContextMenu === launcherContextMenu) {
dockRoot.currentContextMenu = null;
dockRoot.hideTimer.stop();
dockRoot.menuHovered = false;
if (dockRoot.autoHide && !dockRoot.dockHovered && !dockRoot.anyAppHovered && !dockRoot.peekHovered && !dockRoot.menuHovered) {
dockRoot.hideTimer.restart();
}
}
}
}
}
@@ -529,6 +611,7 @@ Item {
onClicked: mouse => {
if (mouse.button === Qt.RightButton) {
const targetScreen = dockRoot.modelData || dockRoot.screen || null;
// If right-clicking on the same app with an open context menu, close it
if (dockRoot.currentContextMenu === contextMenu && contextMenu.visible) {
dockRoot.closeAllContextMenus();
@@ -538,7 +621,7 @@ Item {
dockRoot.closeAllContextMenus();
// Hide tooltip when showing context menu
TooltipService.hideImmediately();
contextMenu.show(appButton, modelData.toplevel || modelData);
contextMenu.show(appButton, modelData.toplevel || modelData, targetScreen);
return;
}
+62 -1
View File
@@ -5,6 +5,7 @@ import Quickshell
import Quickshell.Wayland
import Quickshell.Widgets
import qs.Commons
import qs.Modules.Panels.Settings
import qs.Services.UI
import qs.Widgets
@@ -13,6 +14,12 @@ PopupWindow {
property var toplevel: null
property Item anchorItem: null
property ShellScreen targetScreen: null
property string menuMode: "app" // "app" or "launcher"
property string launcherWidgetSection: ""
property int launcherWidgetIndex: -1
property var launcherWidgetSettings: ({})
property bool hovered: menuMouseArea.containsMouse
property var onAppClosed: null // Callback function for when an app is closed
@@ -72,6 +79,34 @@ PopupWindow {
}
function initItems() {
if (menuMode === "launcher") {
root.items = [
{
"icon": "adjustments",
"text": I18n.tr("actions.dock-settings"),
"action": function () {
handleDockSettings();
}
},
{
"icon": "adjustments",
"text": I18n.tr("actions.launcher-settings"),
"action": function () {
handleLauncherSettings();
}
},
{
"icon": "settings",
"text": I18n.tr("actions.widget-settings"),
"action": function () {
handleLauncherWidgetSettings();
}
}
];
calculateMenuWidth();
return;
}
// Is this a running app?
const isRunning = root.toplevel && ToplevelManager && ToplevelManager.toplevels.values.includes(root.toplevel);
@@ -249,7 +284,7 @@ PopupWindow {
}
}
function show(item, toplevelData) {
function show(item, toplevelData, screen) {
if (!item) {
return;
}
@@ -260,6 +295,7 @@ PopupWindow {
// Then set up new data
anchorItem = item;
toplevel = toplevelData;
targetScreen = screen || null;
initItems();
visible = true;
@@ -315,6 +351,31 @@ PopupWindow {
root.requestClose();
}
function handleLauncherSettings() {
if (targetScreen) {
var panel = PanelService.getPanel("settingsPanel", targetScreen);
panel.requestedTab = SettingsPanel.Tab.Launcher;
panel.toggle();
}
root.requestClose();
}
function handleDockSettings() {
if (targetScreen) {
var panel = PanelService.getPanel("settingsPanel", targetScreen);
panel.requestedTab = SettingsPanel.Tab.Dock;
panel.toggle();
}
root.requestClose();
}
function handleLauncherWidgetSettings() {
if (targetScreen && launcherWidgetSection && launcherWidgetIndex >= 0) {
BarService.openWidgetSettings(targetScreen, launcherWidgetSection, launcherWidgetIndex, "Launcher", launcherWidgetSettings || {});
}
root.requestClose();
}
// Short delay to ignore spurious events
Timer {
id: gracePeriodTimer