diff --git a/Bar/Bar.qml b/Bar/Bar.qml index 83c3ae7..037d76c 100644 --- a/Bar/Bar.qml +++ b/Bar/Bar.qml @@ -63,6 +63,10 @@ Scope { Media { anchors.verticalCenter: parent.verticalCenter } + + Taskbar { + anchors.verticalCenter: parent.verticalCenter + } } ActiveWindow { diff --git a/Bar/Modules/Taskbar.qml b/Bar/Modules/Taskbar.qml new file mode 100644 index 0000000..afdb653 --- /dev/null +++ b/Bar/Modules/Taskbar.qml @@ -0,0 +1,186 @@ +import QtQuick +import QtQuick.Controls +import Quickshell +import Quickshell.Wayland +import Quickshell.Widgets +import qs.Settings +import qs.Components + +Item { + id: taskbar + width: runningAppsRow.width + height: Settings.settings.taskbarIconSize + + function getAppIcon(toplevel) { + if (!toplevel) + return ""; + + // Try different icon resolution strategies + var icon = Quickshell.iconPath(toplevel.appId?.toLowerCase(), true); + if (!icon) { + icon = Quickshell.iconPath(toplevel.appId, true); + } + if (!icon) { + icon = Quickshell.iconPath(toplevel.title?.toLowerCase(), true); + } + if (!icon) { + icon = Quickshell.iconPath(toplevel.title, true); + } + if (!icon) { + icon = Quickshell.iconPath("application-x-executable", true); + } + console.log(icon) + + return icon || ""; + } + + Row { + id: runningAppsRow + spacing: 8 + height: parent.height + + Repeater { + model: ToplevelManager ? ToplevelManager.toplevels : null + + delegate: Rectangle { + + id: appButton + width: Settings.settings.taskbarIconSize + height: Settings.settings.taskbarIconSize + radius: Math.max(4, Settings.settings.taskbarIconSize * 0.25) + color: isActive ? Theme.accentPrimary : (hovered ? Theme.surfaceVariant : "transparent") + border.color: isActive ? Qt.darker(Theme.accentPrimary, 1.2) : "transparent" + border.width: 1 + + + + property bool isActive: ToplevelManager.activeToplevel && ToplevelManager.activeToplevel === modelData + property bool hovered: mouseArea.containsMouse + property string appId: modelData ? modelData.appId : "" + property string appTitle: modelData ? modelData.title : "" + + Behavior on color { + ColorAnimation { + duration: 150 + } + } + + Behavior on border.color { + ColorAnimation { + duration: 150 + } + } + + // App icon + IconImage { + id: appIcon + width: Math.max(12, Settings.settings.taskbarIconSize * 0.625) // 62.5% of button size (20/32 = 0.625) + height: Math.max(12, Settings.settings.taskbarIconSize * 0.625) + anchors.centerIn: parent + source: getAppIcon(modelData) + smooth: true + + // Fallback to first letter if no icon + visible: source.toString() !== "" + } + + // Fallback text if no icon available + Text { + anchors.centerIn: parent + visible: !appIcon.visible + text: appButton.appId ? appButton.appId.charAt(0).toUpperCase() : "?" + font.family: Theme.fontFamily + font.pixelSize: Math.max(10, Settings.settings.taskbarIconSize * 0.4375) // 43.75% of button size (14/32 = 0.4375) + font.bold: true + color: appButton.isActive ? Theme.onAccent : Theme.textPrimary + } + + // Tooltip + ToolTip { + id: tooltip + visible: mouseArea.containsMouse && !mouseArea.pressed + delay: 800 + text: appTitle || appId + + background: Rectangle { + color: Theme.backgroundPrimary + border.color: Theme.outline + border.width: 1 + radius: 8 + } + + contentItem: Text { + text: tooltip.text + font.family: Theme.fontFamily + font.pixelSize: Theme.fontSizeCaption + color: Theme.textPrimary + } + } + + MouseArea { + id: mouseArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + + onClicked: function(mouse) { + console.log("[Taskbar] Clicked on", appButton.appId, "- Active:", appButton.isActive); + + if (mouse.button === Qt.MiddleButton) { + console.log("[Taskbar] Middle-clicked on", appButton.appId); + + // Example: Close the window with middle click + if (modelData && modelData.close) { + modelData.close(); + } else { + console.log("[Taskbar] No close method available for:", modelData); + } + } + + if (mouse.button === Qt.LeftButton) { + // Left click: Focus/activate the window + if (modelData && modelData.activate) { + modelData.activate(); + } else { + console.log("[Taskbar] No activate method available for:", modelData); + } + } + } + + // Right-click for additional actions + onPressed: mouse => { + if (mouse.button === Qt.RightButton) { + console.log("[Taskbar] Right-clicked on", appButton.appId); + + // Example actions you can add: + // 1. Close window + // if (modelData && modelData.close) { + // modelData.close(); + // } + + // 2. Minimize window + // if (modelData && modelData.minimize) { + // modelData.minimize(); + // } + + // 3. Show context menu (needs Menu component) + // contextMenu.popup(); + } + } + } + + // Active indicator dot + Rectangle { + visible: isActive + width: 4 + height: 4 + radius: 2 + color: Theme.onAccent + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottomMargin: -6 + } + } + } + } +} diff --git a/Settings/Settings.qml b/Settings/Settings.qml index 9626986..17941bc 100644 --- a/Settings/Settings.qml +++ b/Settings/Settings.qml @@ -59,6 +59,7 @@ Singleton { property bool use12HourClock: false property bool dimPanels: true property real fontSizeMultiplier: 1.0 // Font size multiplier (1.0 = normal, 1.2 = 20% larger, 0.8 = 20% smaller) + property int taskbarIconSize: 24 // Taskbar icon button size in pixels (default: 32, smaller: 24, larger: 40) property var pinnedExecs: [] // Added for AppLauncher pinned apps } }