diff --git a/Drawers/Backgrounds.qml b/Drawers/Backgrounds.qml index dfa1185..5220174 100644 --- a/Drawers/Backgrounds.qml +++ b/Drawers/Backgrounds.qml @@ -9,14 +9,14 @@ Shape { required property Item bar anchors.fill: parent - anchors.margins: 8 + // anchors.margins: 8 anchors.topMargin: bar.implicitHeight preferredRendererType: Shape.CurveRenderer Modules.Background { wrapper: root.panels.popouts - startX: wrapper.x - rounding + startX: wrapper.x - 8 startY: wrapper.y } } diff --git a/Drawers/Panels.qml b/Drawers/Panels.qml index adfb7b5..b845540 100644 --- a/Drawers/Panels.qml +++ b/Drawers/Panels.qml @@ -13,7 +13,7 @@ Item { readonly property alias popouts: popouts anchors.fill: parent - anchors.margins: 8 + // anchors.margins: 8 anchors.topMargin: bar.implicitHeight Modules.Wrapper { @@ -21,13 +21,12 @@ Item { screen: root.screen - anchors.top: parent.top x: { - const off = currentCenter - 8 - nonAnimWidth / 2; + const off = currentCenter - nonAnimWidth / 2; const diff = root.width - Math.floor(off + nonAnimWidth); - if (diff < 0) + if ( diff < 0 ) return off + diff; - return Math.floor(Math.max(off, 0)); + return Math.floor( Math.max( off, 0 )); } } } diff --git a/Helpers/Hypr.qml b/Helpers/Hypr.qml index 1c2b6bc..8d733fe 100644 --- a/Helpers/Hypr.qml +++ b/Helpers/Hypr.qml @@ -14,11 +14,15 @@ Singleton { readonly property var workspaces: Hyprland.workspaces readonly property var monitors: Hyprland.monitors - readonly property HyprlandToplevel activeToplevel: Hyprland.activeToplevel?.wayland?.activated ? Hyprland.activeToplevel : null + readonly property HyprlandToplevel activeToplevel: Hyprland.activeToplevel readonly property HyprlandWorkspace focusedWorkspace: Hyprland.focusedWorkspace readonly property HyprlandMonitor focusedMonitor: Hyprland.focusedMonitor readonly property int activeWsId: focusedWorkspace?.id ?? 1 + property string activeName + property string applicationDir: "/usr/share/applications/" + property string desktopName: "" + readonly property HyprKeyboard keyboard: extras.devices.keyboards.find(kb => kb.main) ?? null readonly property bool capsLock: keyboard?.capsLock ?? false readonly property bool numLock: keyboard?.numLock ?? false @@ -49,6 +53,19 @@ Singleton { Component.onCompleted: reloadDynamicConfs() + function updateActiveWindow(): void { + root.desktopName = root.applicationDir + root.activeToplevel?.lastIpcObject.class + ".desktop"; + } + + Connections { + target: Hyprland + + function onRawEvent( event: HyprlandEvent ): void { + if ( event.name === "activewindow" ) { + } + } + } + Connections { target: Hyprland @@ -63,15 +80,38 @@ Singleton { } else if (["workspace", "moveworkspace", "activespecial", "focusedmon"].includes(n)) { Hyprland.refreshWorkspaces(); Hyprland.refreshMonitors(); + Qt.callLater( root.updateActiveWindow ); } else if (["openwindow", "closewindow", "movewindow"].includes(n)) { Hyprland.refreshToplevels(); Hyprland.refreshWorkspaces(); + Qt.callLater( root.updateActiveWindow ); } else if (n.includes("mon")) { Hyprland.refreshMonitors(); + Qt.callLater( root.updateActiveWindow ); } else if (n.includes("workspace")) { Hyprland.refreshWorkspaces(); + Qt.callLater( root.updateActiveWindow ); } else if (n.includes("window") || n.includes("group") || ["pin", "fullscreen", "changefloatingmode", "minimize"].includes(n)) { Hyprland.refreshToplevels(); + Qt.callLater( root.updateActiveWindow ); + } + } + } + + FileView { + id: desktopEntryName + + path: root.desktopName + + onLoaded: { + const lines = text().split( "\n" ); + for ( const line of lines ) { + if ( line.startsWith( "Name=" )) { + let name = line.replace( "Name=", "" ); + let caseFix = name[ 0 ].toUpperCase() + name.slice( 1 ); + root.activeName = caseFix; + break; + } } } } diff --git a/Helpers/InitialTitle.qml b/Helpers/InitialTitle.qml index d587a63..e169991 100644 --- a/Helpers/InitialTitle.qml +++ b/Helpers/InitialTitle.qml @@ -1,22 +1,18 @@ pragma Singleton -import Quickshell.Io + import Quickshell +import Quickshell.Hyprland +import qs.Helpers Singleton { - function getInitialTitle(callback) { - initialTitleProc.running = true - initialTitleProc.stdout.streamFinished.connect( function() { - let cleaned = initialTitleProc.stdout.text.trim().replace(/\"/g, "") - callback(cleaned === "null" ? "" : cleaned) - }) - } + let activeWindow = Hypr.activeToplevel.title + let activeClass = Hypr.activeToplevel.lastIpcObject.class.toString() + let regex = new RegExp(activeClass, "i") - Process { - id: initialTitleProc - command: ["./scripts/initialTitle.sh"] - running: false - stdout: StdioCollector { - } + console.log("ActiveWindow", activeWindow, "ActiveClass", activeClass, "Regex", regex) + + const evalTitle = activeWindow.match(regex) + callback(evalTitle) } } diff --git a/Modules/AudioWidget.qml b/Modules/AudioWidget.qml index 358d67a..1dc5625 100644 --- a/Modules/AudioWidget.qml +++ b/Modules/AudioWidget.qml @@ -9,7 +9,8 @@ import qs.Components Item { id: root implicitWidth: expanded ? 300 : 150 - implicitHeight: 34 + anchors.top: parent.top + anchors.bottom: parent.bottom property bool expanded: false property color textColor: Config.useDynamicColors ? DynamicColors.palette.m3tertiaryFixed : "#ffffff" diff --git a/Modules/Background.qml b/Modules/Background.qml index c4597c7..a1554ef 100644 --- a/Modules/Background.qml +++ b/Modules/Background.qml @@ -48,7 +48,7 @@ ShapePath { PathLine { relativeX: 0 - relativeY: -(root.wrapper.height - root.roundingY * 2) + relativeY: -( root.wrapper.height - root.roundingY * 2 ) } PathArc { diff --git a/Modules/Bar/BarLoader.qml b/Modules/Bar/BarLoader.qml index 878e69e..f893a3a 100644 --- a/Modules/Bar/BarLoader.qml +++ b/Modules/Bar/BarLoader.qml @@ -11,8 +11,6 @@ import qs.Daemons RowLayout { id: root anchors.fill: parent - anchors.leftMargin: 5 - anchors.rightMargin: 5 readonly property int vPadding: 6 required property Wrapper popouts @@ -34,26 +32,22 @@ RowLayout { if (id === "audio" && Config.barConfig.popouts.audio) { popouts.currentName = "audio"; - popouts.currentCenter = Qt.binding(() => item.mapToItem(root, itemWidth / 2, 0).x); + popouts.currentCenter = Qt.binding( () => item.mapToItem(root, itemWidth / 2, 0 ).x ); popouts.hasCurrent = true; } else if ( id === "resources" && Config.barConfig.popouts.resources ) { popouts.currentName = "resources"; - popouts.currentCenter = Qt.binding(() => item.mapToItem(root, itemWidth / 2 + 5, 0).x); + popouts.currentCenter = Qt.binding( () => item.mapToItem( root, itemWidth / 2, 0 ).x ); popouts.hasCurrent = true; - } else if (id === "tray" && Config.barConfig.popouts.tray) { - const index = Math.floor(((x - top - 6) / item.implicitWidth) * item.items.count); - const trayItem = item.items.itemAt(index); - if (trayItem) { - popouts.currentName = `traymenu${index}`; - popouts.currentCenter = Qt.binding(() => trayItem.mapToItem(root, trayItem.implicitWidth / 2 + 4, 0).x); + } else if ( id === "tray" && Config.barConfig.popouts.tray ) { + const index = Math.floor((( x - top ) / item.implicitWidth ) * item.items.count ); + const trayItem = item.items.itemAt( index ); + if ( trayItem ) { + popouts.currentName = `traymenu${ index }`; + popouts.currentCenter = Qt.binding( () => trayItem.mapToItem( root, trayItem.implicitWidth / 2, 0 ).x ); popouts.hasCurrent = true; } else { popouts.hasCurrent = false; } - } else if (id === "activeWindow" && Config.barConfig.popouts.activeWindow) { - popouts.currentName = id.toLowerCase(); - popouts.currentCenter = item.mapToItem(root, 0, itemHeight / 2).y; - popouts.hasCurrent = true; } } @@ -107,17 +101,13 @@ RowLayout { DelegateChoice { roleValue: "notifBell" delegate: WrappedLoader { - sourceComponent: NotifBell { - Layout.alignment: Qt.AlignHCenter - } + sourceComponent: NotifBell {} } } DelegateChoice { roleValue: "clock" delegate: WrappedLoader { - sourceComponent: Clock { - Layout.alignment: Qt.AlignHCenter - } + sourceComponent: Clock {} } } DelegateChoice { @@ -134,6 +124,9 @@ RowLayout { required property string id required property int index + Layout.alignment: Qt.AlignVCenter + Layout.fillHeight: true + function findFirstEnabled(): Item { const count = repeater.count; for (let i = 0; i < count; i++) { @@ -153,11 +146,8 @@ RowLayout { return null; } - Layout.alignment: Qt.AlignHCenter - - // Cursed ahh thing to add padding to first and last enabled components - Layout.topMargin: findFirstEnabled() === this ? root.vPadding : 0 - Layout.bottomMargin: findLastEnabled() === this ? root.vPadding : 0 + Layout.leftMargin: findFirstEnabled() === this ? root.vPadding : 0 + Layout.rightMargin: findLastEnabled() === this ? root.vPadding : 0 visible: enabled active: enabled diff --git a/Modules/Clock.qml b/Modules/Clock.qml index d6dc607..819de30 100644 --- a/Modules/Clock.qml +++ b/Modules/Clock.qml @@ -4,9 +4,16 @@ import qs.Modules Item { implicitWidth: timeText.contentWidth - implicitHeight: timeText.contentHeight + anchors.top: parent.top + anchors.bottom: parent.bottom + Text { id: timeText + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + text: Time.time color: Config.useDynamicColors ? DynamicColors.palette.m3tertiary : "white" diff --git a/Modules/Content.qml b/Modules/Content.qml index 3b590e3..c570410 100644 --- a/Modules/Content.qml +++ b/Modules/Content.qml @@ -12,16 +12,13 @@ Item { readonly property Popout currentPopout: content.children.find(c => c.shouldBeActive) ?? null readonly property Item current: currentPopout?.item ?? null - anchors.centerIn: parent - - implicitWidth: (currentPopout?.implicitWidth ?? 0) + 10 * 2 - implicitHeight: (currentPopout?.implicitHeight ?? 0) + 10 * 2 + implicitWidth: (currentPopout?.implicitWidth ?? 0) + 5 * 2 + implicitHeight: (currentPopout?.implicitHeight ?? 0) + 5 * 2 Item { id: content anchors.fill: parent - anchors.margins: 10 Popout { name: "audio" @@ -80,8 +77,7 @@ Item { required property string name readonly property bool shouldBeActive: root.wrapper.currentName === name - anchors.top: parent.top - anchors.horizontalCenter: parent.horizontalCenter + anchors.centerIn: parent opacity: 0 scale: 0.8 diff --git a/Modules/NotifBell.qml b/Modules/NotifBell.qml index 786e6fa..2003e2a 100644 --- a/Modules/NotifBell.qml +++ b/Modules/NotifBell.qml @@ -4,11 +4,21 @@ import qs.Helpers import qs.Components Item { + id: root + implicitWidth: 20 - implicitHeight: 18 + anchors.top: parent.top + anchors.bottom: parent.bottom + MaterialIcon { id: notificationCenterIcon + + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + property color iconColor: Config.useDynamicColors ? DynamicColors.palette.m3tertiaryFixed : "white" + text: HasNotifications.hasNotifications ? "\uf4fe" : "\ue7f4" font.family: "Material Symbols Rounded" font.pixelSize: 20 diff --git a/Modules/Resources.qml b/Modules/Resources.qml index 7604ada..2855ad9 100644 --- a/Modules/Resources.qml +++ b/Modules/Resources.qml @@ -14,8 +14,10 @@ Item { implicitWidth: rowLayout.implicitWidth + rowLayout.anchors.leftMargin + rowLayout.anchors.rightMargin implicitHeight: 34 property color textColor: Config.useDynamicColors ? DynamicColors.palette.m3tertiaryFixed : "#ffffff" + clip: true Rectangle { + id: backgroundRect anchors { left: parent.left right: parent.right diff --git a/Modules/TrayWidget.qml b/Modules/TrayWidget.qml index 8572960..ef5ab72 100644 --- a/Modules/TrayWidget.qml +++ b/Modules/TrayWidget.qml @@ -7,9 +7,15 @@ import Quickshell.Services.SystemTray Row { id: root + + anchors.top: parent.top + anchors.bottom: parent.bottom + required property PanelWindow bar readonly property alias items: repeater + spacing: 0 + Repeater { id: repeater model: SystemTray.items diff --git a/Modules/UpdatesWidget.qml b/Modules/UpdatesWidget.qml index 6220ac1..a849f0b 100644 --- a/Modules/UpdatesWidget.qml +++ b/Modules/UpdatesWidget.qml @@ -6,12 +6,16 @@ import qs.Config Item { id: root property int countUpdates: Updates.availableUpdates - implicitWidth: contentRow.childrenRect.width + 10 - implicitHeight: 22 + implicitWidth: textMetrics.width + contentRow.spacing + 30 + anchors.top: parent.top + anchors.bottom: parent.bottom property color textColor: Config.useDynamicColors ? DynamicColors.palette.m3tertiaryFixed : "#ffffff" Rectangle { - anchors.fill: parent + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + implicitHeight: 22 radius: height / 2 color: Config.useDynamicColors ? DynamicColors.tPalette.m3surfaceContainer : "#40000000" Behavior on color { diff --git a/Modules/WindowTitle.qml b/Modules/WindowTitle.qml index 76b7c7a..4554fe1 100644 --- a/Modules/WindowTitle.qml +++ b/Modules/WindowTitle.qml @@ -3,10 +3,11 @@ import QtQuick.Layouts import Quickshell.Hyprland import qs.Helpers import qs.Config +import qs.Components Item { id: root - property string currentTitle + property string currentTitle: Hypr.activeName Layout.fillHeight: true Layout.preferredWidth: Math.max( titleText1.implicitWidth, titleText2.implicitWidth ) + 10 clip: true @@ -14,15 +15,15 @@ Item { property bool showFirst: true property color textColor: Config.useDynamicColors ? DynamicColors.palette.m3primary : "white" - Component.onCompleted: { - Hyprland.rawEvent.connect(( event ) => { - if (event.name === "activewindow") { - InitialTitle.getInitialTitle( function( initialTitle ) { - root.currentTitle = initialTitle - }) - } - }) - } + // Component.onCompleted: { + // Hyprland.rawEvent.connect(( event ) => { + // if (event.name === "activewindow") { + // InitialTitle.getInitialTitle( function( initialTitle ) { + // root.currentTitle = initialTitle + // }) + // } + // }) + // } onCurrentTitleChanged: { if (showFirst) { @@ -34,14 +35,13 @@ Item { } } - Text { + CustomText { id: titleText1 anchors.fill: parent anchors.margins: 5 text: root.currentTitle color: root.textColor elide: Text.ElideRight - font.family: "Rubik" font.pixelSize: 16 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter @@ -49,13 +49,9 @@ Item { Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } } - - Behavior on color { - CAnim {} - } } - Text { + CustomText { id: titleText2 anchors.fill: parent anchors.margins: 5 @@ -68,9 +64,5 @@ Item { Behavior on opacity { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad } } - - Behavior on color { - CAnim {} - } } } diff --git a/Modules/Workspaces.qml b/Modules/Workspaces.qml index 6d183eb..82c9597 100644 --- a/Modules/Workspaces.qml +++ b/Modules/Workspaces.qml @@ -12,14 +12,17 @@ import qs.Components Item { id: itemRoot required property PanelWindow bar - implicitHeight: 28 - implicitWidth: root.implicitWidth + anchors.top: parent.top + anchors.bottom: parent.bottom + implicitWidth: workspacesRow.implicitWidth + 10 Rectangle { id: root property HyprlandMonitor monitor: Hyprland.monitorFor( itemRoot.bar?.screen ) - implicitWidth: workspacesRow.implicitWidth + 10 + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter implicitHeight: 22 function shouldShow(monitor) { diff --git a/Modules/Wrapper.qml b/Modules/Wrapper.qml index 032e5fe..733bfbd 100644 --- a/Modules/Wrapper.qml +++ b/Modules/Wrapper.qml @@ -71,8 +71,6 @@ Item { shouldBeActive: root.hasCurrent asynchronous: true - anchors.top: parent.top - anchors.horizontalCenter: parent.horizontalCenter sourceComponent: Content { wrapper: root diff --git a/testwindow/shell.qml b/testwindow/shell.qml index b7bd507..0295dd7 100644 --- a/testwindow/shell.qml +++ b/testwindow/shell.qml @@ -1,14 +1,78 @@ import Quickshell import QtQuick -import Quickshell.Hyprland FloatingWindow { - id: root title: "terminal" - minimumSize: Qt.size(400, 300) - Component.onCompleted: { - Hyprland.refreshToplevels() - console.log(Hyprland.toplevels.values) + + Rectangle { + id: root + width: 480 + height: 320 + + property int callsToUpdateMinimumWidth: 0 + property bool optimize: true + + property int currentTextModel: 0 + property var columnTexts: [ + ["Click on either", "rectangle above", "and note how the counter", "below updates", "significantly faster using the", "regular (non-optimized)", "implementation"], + ["The width", "of this column", "is", "no wider than the", "widest item"], + ["Note how using Qt.callLater()", "the minimum width is", "calculated a bare-minimum", "number", "of times"] + ] + + Text { + x: 20; y: 280 + text: "Times minimum width has been calculated: " + root.callsToUpdateMinimumWidth + } + + Row { + y: 25; spacing: 30; anchors.horizontalCenter: parent.horizontalCenter + Rectangle { + width: 200; height: 50; color: "lightgreen" + Text { text: "Optimized behavior\nusing Qt.callLater()"; anchors.centerIn: parent } + MouseArea { anchors.fill: parent; onClicked: { root.optimize = true; root.currentTextModel++ } } + } + Rectangle { + width: 200; height: 50; color: "lightblue" + Text { text: "Regular behavior"; anchors.centerIn: parent} + MouseArea { anchors.fill: parent; onClicked: { root.optimize = false; root.currentTextModel++ } } + } + } + + Column { + id: column + anchors.centerIn: parent + + onChildrenChanged: root.optimize ? Qt.callLater(updateMinimumWidth) : updateMinimumWidth() + + property int widestChild + function updateMinimumWidth() { + root.callsToUpdateMinimumWidth++ + var w = 0; + for (var i in children) { + var child = children[i]; + if (child.implicitWidth > w) { + w = child.implicitWidth; + } + } + + widestChild = w; + } + + Repeater { + id: repeater + model: root.columnTexts[root.currentTextModel%3] + delegate: Text { + id: text + required property string modelData + required property int index + color: "white" + text: modelData + width: column.widestChild + horizontalAlignment: Text.Center + Rectangle { anchors.fill: parent; z: -1; color: text.index%2 ? "gray" : "darkgray" } + } + } + } } }