summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
author2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-06-21 22:47:13 +1000
committer2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>2025-06-21 22:47:13 +1000
commit4a86b66d06dda958f8d136234225ed160604a61a (patch)
tree8dab0f695e035f26dccc2089ee4636c2b7b7ee2a /modules
parentpopouts: convert to layout (diff)
downloadcaelestia-shell-4a86b66d06dda958f8d136234225ed160604a61a.tar.gz
caelestia-shell-4a86b66d06dda958f8d136234225ed160604a61a.tar.bz2
caelestia-shell-4a86b66d06dda958f8d136234225ed160604a61a.zip
feat: window info panel
Also disable reload popup
Diffstat (limited to 'modules')
-rw-r--r--modules/bar/popouts/ActiveWindow.qml4
-rw-r--r--modules/bar/popouts/Background.qml18
-rw-r--r--modules/bar/popouts/Content.qml40
-rw-r--r--modules/bar/popouts/Wrapper.qml169
-rw-r--r--modules/drawers/Backgrounds.qml4
-rw-r--r--modules/drawers/Panels.qml12
-rw-r--r--modules/windowinfo/Details.qml158
-rw-r--r--modules/windowinfo/Preview.qml65
-rw-r--r--modules/windowinfo/WindowInfo.qml45
9 files changed, 464 insertions, 51 deletions
diff --git a/modules/bar/popouts/ActiveWindow.qml b/modules/bar/popouts/ActiveWindow.qml
index d92d436..fbad79e 100644
--- a/modules/bar/popouts/ActiveWindow.qml
+++ b/modules/bar/popouts/ActiveWindow.qml
@@ -10,6 +10,8 @@ import QtQuick.Layouts
Item {
id: root
+ required property Item wrapper
+
implicitWidth: Hyprland.activeClient ? child.implicitWidth : -Appearance.padding.large * 2
implicitHeight: child.implicitHeight
@@ -65,7 +67,7 @@ Item {
radius: Appearance.rounding.normal
function onClicked(): void {
- // TODO
+ root.wrapper.detach("winfo");
}
}
diff --git a/modules/bar/popouts/Background.qml b/modules/bar/popouts/Background.qml
index c099118..d626ec1 100644
--- a/modules/bar/popouts/Background.qml
+++ b/modules/bar/popouts/Background.qml
@@ -13,15 +13,17 @@ ShapePath {
readonly property real roundingX: flatten ? wrapper.width / 2 : rounding
property real ibr: invertBottomRounding ? -1 : 1
+ property real sideRounding: startX > 0 ? -1 : 1
+
strokeWidth: -1
fillColor: Config.border.colour
PathArc {
relativeX: root.roundingX
- relativeY: root.rounding
+ relativeY: root.rounding * root.sideRounding
radiusX: Math.min(root.rounding, root.wrapper.width)
radiusY: root.rounding
- direction: PathArc.Counterclockwise
+ direction: root.sideRounding < 0 ? PathArc.Clockwise : PathArc.Counterclockwise
}
PathLine {
relativeX: root.wrapper.width - root.roundingX * 2
@@ -50,10 +52,10 @@ ShapePath {
}
PathArc {
relativeX: -root.roundingX
- relativeY: root.rounding
+ relativeY: root.rounding * root.sideRounding
radiusX: Math.min(root.rounding, root.wrapper.width)
radiusY: root.rounding
- direction: PathArc.Counterclockwise
+ direction: root.sideRounding < 0 ? PathArc.Clockwise : PathArc.Counterclockwise
}
Behavior on fillColor {
@@ -71,4 +73,12 @@ ShapePath {
easing.bezierCurve: Appearance.anim.curves.standard
}
}
+
+ Behavior on sideRounding {
+ NumberAnimation {
+ duration: Appearance.anim.durations.normal
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: Appearance.anim.curves.standard
+ }
+ }
}
diff --git a/modules/bar/popouts/Content.qml b/modules/bar/popouts/Content.qml
index 43a0a09..2c10e5f 100644
--- a/modules/bar/popouts/Content.qml
+++ b/modules/bar/popouts/Content.qml
@@ -9,15 +9,15 @@ import QtQuick
Item {
id: root
+ required property Item wrapper
required property ShellScreen screen
-
- property string currentName
- property real currentCenter
- property bool hasCurrent
+ required property string currentName
+ required property real currentCenter
+ required property bool hasCurrent
anchors.centerIn: parent
- implicitWidth: hasCurrent ? (content.children.find(c => c.shouldBeActive)?.implicitWidth ?? 0) + Appearance.padding.large * 2 : 0
+ implicitWidth: (content.children.find(c => c.shouldBeActive)?.implicitWidth ?? 0) + Appearance.padding.large * 2
implicitHeight: (content.children.find(c => c.shouldBeActive)?.implicitHeight ?? 0) + Appearance.padding.large * 2
Item {
@@ -26,11 +26,11 @@ Item {
anchors.fill: parent
anchors.margins: Appearance.padding.large
- clip: true
-
Popout {
name: "activewindow"
- source: "ActiveWindow.qml"
+ sourceComponent: ActiveWindow {
+ wrapper: root.wrapper
+ }
}
Popout {
@@ -85,30 +85,6 @@ Item {
}
}
- Behavior on implicitWidth {
- Anim {
- easing.bezierCurve: Appearance.anim.curves.emphasized
- }
- }
-
- Behavior on implicitHeight {
- enabled: root.implicitWidth > 0
-
- Anim {
- easing.bezierCurve: Appearance.anim.curves.emphasized
- }
- }
-
- Behavior on currentCenter {
- enabled: root.implicitWidth > 0
-
- NumberAnimation {
- duration: Appearance.anim.durations.normal
- easing.type: Easing.BezierSpline
- easing.bezierCurve: Appearance.anim.curves.emphasized
- }
- }
-
component Popout: Loader {
id: popout
diff --git a/modules/bar/popouts/Wrapper.qml b/modules/bar/popouts/Wrapper.qml
index f304ea7..0ce17ce 100644
--- a/modules/bar/popouts/Wrapper.qml
+++ b/modules/bar/popouts/Wrapper.qml
@@ -1,6 +1,11 @@
+pragma ComponentBehavior: Bound
+
import "root:/services"
import "root:/config"
+import "root:/modules/windowinfo"
import Quickshell
+import Quickshell.Wayland
+import Quickshell.Hyprland
import QtQuick
Item {
@@ -8,18 +13,168 @@ Item {
required property ShellScreen screen
- property alias currentName: content.currentName
- property alias currentCenter: content.currentCenter
- property alias hasCurrent: content.hasCurrent
+ readonly property real nonAnimWidth: x > 0 || hasCurrent ? children.find(c => c.shouldBeActive)?.implicitWidth ?? content.implicitWidth : 0
+ readonly property real nonAnimHeight: children.find(c => c.shouldBeActive)?.implicitHeight ?? content.implicitHeight
+
+ property string currentName
+ property real currentCenter
+ property bool hasCurrent
+
+ property string detachedMode
+ readonly property bool isDetached: detachedMode.length > 0
+
+ property int animLength: Appearance.anim.durations.normal
+ property list<real> animCurve: Appearance.anim.curves.emphasized
+
+ function detach(mode: string): void {
+ animLength = Appearance.anim.durations.large;
+ detachedMode = mode;
+ focus = true;
+ }
+
+ function close(): void {
+ hasCurrent = false;
+ animCurve = Appearance.anim.curves.emphasizedAccel;
+ animLength = Appearance.anim.durations.normal;
+ detachedMode = "";
+ animCurve = Appearance.anim.curves.emphasized;
+ }
visible: width > 0 && height > 0
+ clip: true
+
+ implicitWidth: nonAnimWidth
+ implicitHeight: nonAnimHeight
+
+ Keys.onEscapePressed: close()
- implicitWidth: content.implicitWidth
- implicitHeight: content.implicitHeight
+ HyprlandFocusGrab {
+ active: root.isDetached
+ windows: [QsWindow.window]
+ onCleared: root.close()
+ }
+
+ Binding {
+ when: root.isDetached
- Content {
+ target: QsWindow.window
+ property: "WlrLayershell.keyboardFocus"
+ value: WlrKeyboardFocus.OnDemand
+ }
+
+ Comp {
id: content
- screen: root.screen
+ shouldBeActive: !root.detachedMode
+ asynchronous: true
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+
+ sourceComponent: Content {
+ wrapper: root
+ screen: root.screen
+ currentName: root.currentName
+ currentCenter: root.currentCenter
+ hasCurrent: root.hasCurrent
+ }
+ }
+
+ Comp {
+ shouldBeActive: root.detachedMode === "winfo"
+ asynchronous: true
+ anchors.centerIn: parent
+
+ sourceComponent: WindowInfo {
+ screen: root.screen
+ }
+ }
+
+ Behavior on x {
+ Anim {
+ duration: root.animLength
+ easing.bezierCurve: root.animCurve
+ }
+ }
+
+ Behavior on y {
+ enabled: root.implicitWidth > 0
+
+ Anim {
+ duration: root.animLength
+ easing.bezierCurve: root.animCurve
+ }
+ }
+
+ Behavior on implicitWidth {
+ Anim {
+ duration: root.animLength
+ easing.bezierCurve: root.animCurve
+ }
+ }
+
+ Behavior on implicitHeight {
+ enabled: root.implicitWidth > 0
+
+ Anim {
+ duration: root.animLength
+ easing.bezierCurve: root.animCurve
+ }
+ }
+
+ component Comp: Loader {
+ id: comp
+
+ property bool shouldBeActive
+
+ asynchronous: true
+ active: false
+ opacity: 0
+
+ states: State {
+ name: "active"
+ when: comp.shouldBeActive
+
+ PropertyChanges {
+ comp.opacity: 1
+ comp.active: true
+ }
+ }
+
+ transitions: [
+ Transition {
+ from: ""
+ to: "active"
+
+ SequentialAnimation {
+ PropertyAction {
+ property: "active"
+ }
+ Anim {
+ property: "opacity"
+ easing.bezierCurve: Appearance.anim.curves.standard
+ }
+ }
+ },
+ Transition {
+ from: "active"
+ to: ""
+
+ SequentialAnimation {
+ Anim {
+ property: "opacity"
+ easing.bezierCurve: Appearance.anim.curves.standard
+ }
+ PropertyAction {
+ property: "active"
+ }
+ }
+ }
+ ]
+ }
+
+ component Anim: NumberAnimation {
+ duration: Appearance.anim.durations.normal
+ easing.type: Easing.BezierSpline
+ easing.bezierCurve: Appearance.anim.curves.emphasized
}
}
diff --git a/modules/drawers/Backgrounds.qml b/modules/drawers/Backgrounds.qml
index 46ca477..b7e3d39 100644
--- a/modules/drawers/Backgrounds.qml
+++ b/modules/drawers/Backgrounds.qml
@@ -60,7 +60,7 @@ Shape {
wrapper: panels.popouts
invertBottomRounding: wrapper.y + wrapper.height + 1 >= root.height
- startX: 0
- startY: wrapper.y - rounding
+ startX: wrapper.x
+ startY: wrapper.y - rounding * sideRounding
}
}
diff --git a/modules/drawers/Panels.qml b/modules/drawers/Panels.qml
index a422fcc..5b2229c 100644
--- a/modules/drawers/Panels.qml
+++ b/modules/drawers/Panels.qml
@@ -80,11 +80,13 @@ Item {
screen: root.screen
- anchors.left: parent.left
- anchors.verticalCenter: parent.top
- anchors.verticalCenterOffset: {
- const off = root.popouts.currentCenter - Config.border.thickness;
- const diff = root.height - Math.floor(off + implicitHeight / 2);
+ x: isDetached ? (root.width - nonAnimWidth) / 2 : 0
+ y: {
+ if (isDetached)
+ return (root.height - nonAnimHeight) / 2;
+
+ const off = currentCenter - Config.border.thickness - nonAnimHeight / 2;
+ const diff = root.height - Math.floor(off + nonAnimHeight);
if (diff < 0)
return off + diff;
return off;
diff --git a/modules/windowinfo/Details.qml b/modules/windowinfo/Details.qml
new file mode 100644
index 0000000..1480f96
--- /dev/null
+++ b/modules/windowinfo/Details.qml
@@ -0,0 +1,158 @@
+import "root:/widgets"
+import "root:/services"
+import "root:/config"
+import Quickshell
+import QtQuick
+import QtQuick.Layouts
+
+ColumnLayout {
+ id: root
+
+ anchors.fill: parent
+ spacing: Appearance.spacing.small
+
+ Label {
+ Layout.topMargin: Appearance.padding.large * 2
+
+ text: Hyprland.activeClient.title
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+
+ font.pointSize: Appearance.font.size.large
+ font.weight: 500
+ }
+
+ Label {
+ text: Hyprland.activeClient.wmClass
+ color: Colours.palette.m3tertiary
+
+ font.pointSize: Appearance.font.size.larger
+ }
+
+ StyledRect {
+ Layout.fillWidth: true
+ Layout.preferredHeight: 1
+ Layout.leftMargin: Appearance.padding.large * 2
+ Layout.rightMargin: Appearance.padding.large * 2
+ Layout.topMargin: Appearance.spacing.normal
+ Layout.bottomMargin: Appearance.spacing.large
+
+ color: Colours.palette.m3secondary
+ }
+
+ Detail {
+ icon: "location_on"
+ text: qsTr("Address: %1").arg(Hyprland.activeClient.address)
+ color: Colours.palette.m3primary
+ }
+
+ Detail {
+ icon: "location_searching"
+ text: qsTr("Position: %1, %2").arg(Hyprland.activeClient.x).arg(Hyprland.activeClient.y)
+ }
+
+ Detail {
+ icon: "resize"
+ text: qsTr("Size: %1 x %2").arg(Hyprland.activeClient.width).arg(Hyprland.activeClient.height)
+ color: Colours.palette.m3tertiary
+ }
+
+ Detail {
+ icon: "workspaces"
+ text: qsTr("Workspace: %1 (%2)").arg(Hyprland.activeClient.workspace.name).arg(Hyprland.activeClient.workspace.id)
+ color: Colours.palette.m3secondary
+ }
+
+ Detail {
+ icon: "desktop_windows"
+ text: {
+ const mon = Hyprland.activeClient.monitor;
+ return qsTr("Monitor: %1 (%2) at %3, %4").arg(mon.name).arg(mon.id).arg(mon.x).arg(mon.y);
+ }
+ }
+
+ Detail {
+ icon: "page_header"
+ text: qsTr("Initial title: %1").arg(Hyprland.activeClient.initialTitle)
+ color: Colours.palette.m3tertiary
+ }
+
+ Detail {
+ icon: "category"
+ text: qsTr("Initial class: %1").arg(Hyprland.activeClient.initialClass)
+ }
+
+ Detail {
+ icon: "account_tree"
+ text: qsTr("Process id: %1").arg(Hyprland.activeClient.pid)
+ color: Colours.palette.m3primary
+ }
+
+ Detail {
+ icon: "picture_in_picture_center"
+ text: qsTr("Floating: %1").arg(Hyprland.activeClient.floating ? "yes" : "no")
+ color: Colours.palette.m3secondary
+ }
+
+ Detail {
+ icon: "gradient"
+ text: qsTr("Xwayland: %1").arg(Hyprland.activeClient.lastIpcObject.xwayland ? "yes" : "no")
+ }
+
+ Detail {
+ icon: "keep"
+ text: qsTr("Pinned: %1").arg(Hyprland.activeClient.pinned ? "yes" : "no")
+ color: Colours.palette.m3secondary
+ }
+
+ Detail {
+ icon: "fullscreen"
+ text: {
+ const fs = Hyprland.activeClient.fullscreen;
+ return qsTr("Fullscreen state: %1").arg(fs == 0 ? "off" : fs == 1 ? "maximised" : "on");
+ }
+ color: Colours.palette.m3tertiary
+ }
+
+ Item {
+ Layout.fillHeight: true
+ }
+
+ component Detail: RowLayout {
+ id: detail
+
+ required property string icon
+ required property string text
+ property alias color: icon.color
+
+ Layout.leftMargin: Appearance.padding.large
+ Layout.rightMargin: Appearance.padding.large
+ Layout.fillWidth: true
+
+ spacing: Appearance.spacing.normal
+
+ MaterialIcon {
+ id: icon
+
+ Layout.alignment: Qt.AlignVCenter
+ text: detail.icon
+ }
+
+ StyledText {
+ Layout.fillWidth: true
+ Layout.alignment: Qt.AlignVCenter
+
+ text: detail.text
+ elide: Text.ElideRight
+ font.pointSize: Appearance.font.size.normal
+ }
+ }
+
+ component Label: StyledText {
+ Layout.leftMargin: Appearance.padding.large
+ Layout.rightMargin: Appearance.padding.large
+ Layout.fillWidth: true
+ elide: Text.ElideRight
+ horizontalAlignment: Text.AlignHCenter
+ animate: true
+ }
+}
diff --git a/modules/windowinfo/Preview.qml b/modules/windowinfo/Preview.qml
new file mode 100644
index 0000000..26941db
--- /dev/null
+++ b/modules/windowinfo/Preview.qml
@@ -0,0 +1,65 @@
+pragma ComponentBehavior: Bound
+
+import "root:/widgets"
+import "root:/services"
+import "root:/config"
+import Quickshell
+import Quickshell.Io
+import Quickshell.Wayland
+import Quickshell.Widgets
+import QtQuick
+import QtQuick.Layouts
+
+Item {
+ id: root
+
+ required property ShellScreen screen
+
+ Layout.preferredWidth: preview.implicitWidth + Appearance.padding.large * 2
+ Layout.fillHeight: true
+
+ ClippingRectangle {
+ id: preview
+
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.top
+ anchors.bottom: label.top
+ anchors.topMargin: Appearance.padding.large
+ anchors.bottomMargin: Appearance.spacing.normal
+
+ implicitWidth: view.implicitWidth
+
+ color: "transparent"
+ radius: Appearance.rounding.small
+
+ ScreencopyView {
+ id: view
+
+ anchors.centerIn: parent
+
+ captureSource: Hyprland.activeClient ? ToplevelManager.activeToplevel : null
+ live: true
+
+ constraintSize.width: parent.height * Math.min(screen.width / screen.height, Hyprland.activeClient.width / Hyprland.activeClient.height)
+ constraintSize.height: parent.height
+ }
+ }
+
+ StyledText {
+ id: label
+
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: Appearance.padding.large
+
+ animate: true
+ text: {
+ const client = Hyprland.activeClient;
+ if (!client)
+ return qsTr("No active client");
+
+ const mon = Hyprland.monitors.values[Hyprland.activeClient.lastIpcObject.monitor];
+ return qsTr("%1 on monitor %2 at %3, %4").arg(client.title).arg(mon.name).arg(client.x).arg(client.y);
+ }
+ }
+}
diff --git a/modules/windowinfo/WindowInfo.qml b/modules/windowinfo/WindowInfo.qml
new file mode 100644
index 0000000..9a5376a
--- /dev/null
+++ b/modules/windowinfo/WindowInfo.qml
@@ -0,0 +1,45 @@
+import "root:/widgets"
+import "root:/services"
+import "root:/config"
+import Quickshell
+import QtQuick
+import QtQuick.Layouts
+
+Item {
+ id: root
+
+ required property ShellScreen screen
+
+ implicitWidth: child.implicitWidth
+ implicitHeight: screen.height * Config.winfo.sizes.heightMult
+
+ RowLayout {
+ id: child
+
+ anchors.fill: parent
+ anchors.margins: Appearance.padding.large
+
+ spacing: Appearance.spacing.normal
+
+ Preview {
+ screen: root.screen
+ }
+
+ ColumnLayout {
+ spacing: Appearance.spacing.normal
+
+ Layout.preferredWidth: Config.winfo.sizes.detailsWidth
+ Layout.fillHeight: true
+
+ StyledRect {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ color: Colours.palette.m3surfaceContainer
+ radius: Appearance.rounding.normal
+
+ Details {}
+ }
+ }
+ }
+}