Taskbar/TaskbarGrouped: fix hyprland context menu (sort of)

This commit is contained in:
Ly-sec
2025-11-24 15:41:28 +01:00
parent c7116827a4
commit 0e899d5559
2 changed files with 271 additions and 33 deletions
+91 -10
View File
@@ -43,22 +43,26 @@ Rectangle {
// Context menu state
property var selectedWindow: null
property string selectedAppName: ""
property int modelUpdateTrigger: 0 // Dummy property to force model re-evaluation
NPopupContextMenu {
id: contextMenu
model: {
// Reference modelUpdateTrigger to make binding reactive
const _ = root.modelUpdateTrigger;
var items = [];
if (selectedWindow) {
if (root.selectedWindow) {
items.push({
"label": I18n.tr("context-menu.activate-app", {
"app": selectedAppName
"app": root.selectedAppName
}),
"action": "activate",
"icon": "focus"
});
items.push({
"label": I18n.tr("context-menu.close-app", {
"app": selectedAppName
"app": root.selectedAppName
}),
"action": "close",
"icon": "x"
@@ -203,6 +207,7 @@ Rectangle {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
preventStealing: true
onPressed: function (mouse) {
if (!taskbarItem.modelData)
@@ -213,16 +218,25 @@ Rectangle {
} catch (error) {
Logger.e("Taskbar", "Failed to activate toplevel: " + error);
}
} else if (mouse.button === Qt.RightButton) {
}
}
onReleased: function (mouse) {
if (!taskbarItem.modelData)
return;
if (mouse.button === Qt.RightButton) {
mouse.accepted = true;
TooltipService.hide();
root.selectedWindow = taskbarItem.modelData;
root.selectedAppName = CompositorService.getCleanAppName(taskbarItem.modelData.appId, taskbarItem.modelData.title);
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
const pos = BarService.getContextMenuPosition(taskbarItem, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(taskbarItem, pos.x, pos.y);
popupMenuWindow.showContextMenu(contextMenu);
}
// Store position and size for timer callback
const globalPos = taskbarItem.mapToItem(root, 0, 0);
contextMenuOpenTimer.globalX = globalPos.x;
contextMenuOpenTimer.globalY = globalPos.y;
contextMenuOpenTimer.itemWidth = taskbarItem.width;
contextMenuOpenTimer.itemHeight = taskbarItem.height;
contextMenuOpenTimer.restart();
}
}
onEntered: TooltipService.show(taskbarItem, taskbarItem.modelData.title || taskbarItem.modelData.appId || "Unknown app.", BarService.getTooltipDirection())
@@ -231,4 +245,71 @@ Rectangle {
}
}
}
Timer {
id: contextMenuOpenTimer
interval: 10
repeat: false
property real globalX: 0
property real globalY: 0
property real itemWidth: 0
property real itemHeight: 0
onTriggered: {
// Directly build and set model as a new array (bypass binding issues)
var items = [];
if (root.selectedWindow) {
items.push({
"label": I18n.tr("context-menu.activate-app", {
"app": root.selectedAppName
}),
"action": "activate",
"icon": "focus"
});
items.push({
"label": I18n.tr("context-menu.close-app", {
"app": root.selectedAppName
}),
"action": "close",
"icon": "x"
});
}
items.push({
"label": I18n.tr("context-menu.widget-settings"),
"action": "widget-settings",
"icon": "settings"
});
// Set the model directly
contextMenu.model = items;
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.open();
// Calculate menu position relative to the clicked item with consistent spacing
const barPosition = Settings.data.bar.position;
const spacing = Style.barHeight * 0.5;
let menuX, menuY;
if (barPosition === "top") {
menuX = globalX + (itemWidth / 2) - (contextMenu.implicitWidth / 2);
menuY = globalY + itemHeight + spacing;
} else if (barPosition === "bottom") {
menuX = globalX + (itemWidth / 2) - (contextMenu.implicitWidth / 2);
menuY = globalY - contextMenu.implicitHeight - (Style.barHeight * 2);
} else if (barPosition === "left") {
menuX = globalX + itemWidth + spacing;
menuY = globalY + (itemHeight / 2) - (contextMenu.implicitHeight / 2);
} else {
// right
menuX = globalX - contextMenu.implicitWidth - spacing;
menuY = globalY + (itemHeight / 2) - (contextMenu.implicitHeight / 2);
}
contextMenu.openAtItem(root, menuX, menuY);
popupMenuWindow.contentItem = contextMenu;
}
}
}
}
+180 -23
View File
@@ -53,6 +53,7 @@ Item {
// Context menu state
property var selectedWindow: null
property string selectedAppName: ""
property int modelUpdateTrigger: 0 // Dummy property to force model re-evaluation
function refreshWorkspaces() {
localWorkspaces.clear();
@@ -167,18 +168,21 @@ Item {
id: contextMenu
model: {
// Reference modelUpdateTrigger to make binding reactive
const _ = root.modelUpdateTrigger;
var items = [];
if (selectedWindow) {
if (root.selectedWindow) {
items.push({
"label": I18n.tr("context-menu.activate-app", {
"app": selectedAppName
"app": root.selectedAppName
}),
"action": "activate",
"icon": "focus"
});
items.push({
"label": I18n.tr("context-menu.close-app", {
"app": selectedAppName
"app": root.selectedAppName
}),
"action": "close",
"icon": "x"
@@ -273,21 +277,28 @@ Item {
enabled: !hasWindows
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
preventStealing: true
onPressed: mouse => {
if (mouse.button === Qt.LeftButton) {
CompositorService.switchToWorkspace(workspaceModel);
} else if (mouse.button === Qt.RightButton) {
TooltipService.hide();
root.selectedWindow = "";
root.selectedAppName = "";
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
const pos = BarService.getContextMenuPosition(container, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(container, pos.x, pos.y);
popupMenuWindow.showContextMenu(contextMenu);
}
}
}
onReleased: mouse => {
if (mouse.button === Qt.RightButton) {
mouse.accepted = true;
TooltipService.hide();
root.selectedWindow = "";
root.selectedAppName = "";
// Store position and size for timer callback
const globalPos = container.mapToItem(root, 0, 0);
contextMenuOpenTimer1.globalX = globalPos.x;
contextMenuOpenTimer1.globalY = globalPos.y;
contextMenuOpenTimer1.itemWidth = container.width;
contextMenuOpenTimer1.itemHeight = container.height;
contextMenuOpenTimer1.restart();
}
}
}
Flow {
@@ -359,6 +370,7 @@ Item {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
preventStealing: true
onPressed: mouse => {
if (!model) {
@@ -367,18 +379,29 @@ Item {
if (mouse.button === Qt.LeftButton) {
CompositorService.focusWindow(model);
} else if (mouse.button === Qt.RightButton) {
TooltipService.hide();
root.selectedWindow = model;
root.selectedAppName = CompositorService.getCleanAppName(model.appId, model.title);
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
const pos = BarService.getContextMenuPosition(taskbarItem, contextMenu.implicitWidth, contextMenu.implicitHeight);
contextMenu.openAtItem(taskbarItem, pos.x, pos.y);
popupMenuWindow.showContextMenu(contextMenu);
}
}
}
onReleased: mouse => {
if (!model) {
return;
}
if (mouse.button === Qt.RightButton) {
mouse.accepted = true;
TooltipService.hide();
root.selectedWindow = model;
root.selectedAppName = CompositorService.getCleanAppName(model.appId, model.title);
// Store position and size for timer callback
const globalPos = taskbarItem.mapToItem(root, 0, 0);
contextMenuOpenTimer2.globalX = globalPos.x;
contextMenuOpenTimer2.globalY = globalPos.y;
contextMenuOpenTimer2.itemWidth = taskbarItem.width;
contextMenuOpenTimer2.itemHeight = taskbarItem.height;
contextMenuOpenTimer2.restart();
}
}
onEntered: {
taskbarItem.itemHovered = true;
TooltipService.show(taskbarItem, model.title || model.appId || "Unknown app.", BarService.getTooltipDirection());
@@ -533,4 +556,138 @@ Item {
delegate: workspaceRepeaterDelegate
}
}
Timer {
id: contextMenuOpenTimer1
interval: 10
repeat: false
property real globalX: 0
property real globalY: 0
property real itemWidth: 0
property real itemHeight: 0
onTriggered: {
// Directly build and set model as a new array (bypass binding issues)
var items = [];
if (root.selectedWindow) {
items.push({
"label": I18n.tr("context-menu.activate-app", {
"app": root.selectedAppName
}),
"action": "activate",
"icon": "focus"
});
items.push({
"label": I18n.tr("context-menu.close-app", {
"app": root.selectedAppName
}),
"action": "close",
"icon": "x"
});
}
items.push({
"label": I18n.tr("context-menu.widget-settings"),
"action": "widget-settings",
"icon": "settings"
});
// Set the model directly
contextMenu.model = items;
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.open();
// Calculate menu position relative to the clicked item with consistent spacing
const barPosition = Settings.data.bar.position;
const spacing = Style.barHeight * 0.5;
let menuX, menuY;
if (barPosition === "top") {
menuX = globalX + (itemWidth / 2) - (contextMenu.implicitWidth / 2);
menuY = globalY + itemHeight + spacing;
} else if (barPosition === "bottom") {
menuX = globalX + (itemWidth / 2) - (contextMenu.implicitWidth / 2);
menuY = globalY - contextMenu.implicitHeight - (Style.barHeight * 2);
} else if (barPosition === "left") {
menuX = globalX + itemWidth + spacing;
menuY = globalY + (itemHeight / 2) - (contextMenu.implicitHeight / 2);
} else {
// right
menuX = globalX - contextMenu.implicitWidth - spacing;
menuY = globalY + (itemHeight / 2) - (contextMenu.implicitHeight / 2);
}
contextMenu.openAtItem(root, menuX, menuY);
popupMenuWindow.contentItem = contextMenu;
}
}
}
Timer {
id: contextMenuOpenTimer2
interval: 10
repeat: false
property real globalX: 0
property real globalY: 0
property real itemWidth: 0
property real itemHeight: 0
onTriggered: {
// Directly build and set model as a new array (bypass binding issues)
var items = [];
if (root.selectedWindow) {
items.push({
"label": I18n.tr("context-menu.activate-app", {
"app": root.selectedAppName
}),
"action": "activate",
"icon": "focus"
});
items.push({
"label": I18n.tr("context-menu.close-app", {
"app": root.selectedAppName
}),
"action": "close",
"icon": "x"
});
}
items.push({
"label": I18n.tr("context-menu.widget-settings"),
"action": "widget-settings",
"icon": "settings"
});
// Set the model directly
contextMenu.model = items;
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
if (popupMenuWindow) {
popupMenuWindow.open();
// Calculate menu position relative to the clicked item with consistent spacing
const barPosition = Settings.data.bar.position;
const spacing = Style.barHeight * 0.5;
let menuX, menuY;
if (barPosition === "top") {
menuX = globalX + (itemWidth / 2) - (contextMenu.implicitWidth / 2);
menuY = globalY + itemHeight + spacing;
} else if (barPosition === "bottom") {
menuX = globalX + (itemWidth / 2) - (contextMenu.implicitWidth / 2);
menuY = globalY - contextMenu.implicitHeight - (Style.barHeight * 2);
} else if (barPosition === "left") {
menuX = globalX + itemWidth + spacing;
menuY = globalY + (itemHeight / 2) - (contextMenu.implicitHeight / 2);
} else {
// right
menuX = globalX - contextMenu.implicitWidth - spacing;
menuY = globalY + (itemHeight / 2) - (contextMenu.implicitHeight / 2);
}
contextMenu.openAtItem(root, menuX, menuY);
popupMenuWindow.contentItem = contextMenu;
}
}
}
}