swadhinbiswas Initial de-omarchy: Omarchy UI layer for Arch-based distros · 8/22/2026
9f393b2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
import QtQuick
import Quickshell
import Quickshell.Hyprland
import qs.Commons
PopupWindow {
id: root
required property Item anchorItem
required property QtObject bar
property var owner: null
property int margin: Style.gapsOut
property int padding: Style.spacing.popupPadding
property int contentWidth: Style.space(280)
property int contentHeight: Style.space(200)
property color borderColor: Color.popups.border
property var borderSpec: Border.localOrSurfaceSpec("popups", "border", borderColor, Color.popups.border, Math.max(1, Style.space(2)))
property bool open: false
property bool centerOnBar: false
// "click" — uses HyprlandFocusGrab so clicking outside dismisses the popup.
// "hover" — passive overlay; the owning widget controls open via hover.
property string triggerMode: "click"
readonly property var coordinatorKey: owner || root
readonly property var anchorWindow: anchorItem ? anchorItem.QsWindow.window : null
readonly property var popupScreen: anchorWindow ? anchorWindow.screen : null
readonly property bool containsMouse: cardHover.hovered
readonly property real screenW: popupScreen ? popupScreen.width : 0
readonly property real screenH: popupScreen ? popupScreen.height : 0
readonly property real barW: anchorWindow ? anchorWindow.width : 0
readonly property real barH: anchorWindow ? anchorWindow.height : 0
readonly property real availableCardWidth: screenW > 0
? Math.max(120, screenW - ((bar && (bar.position === "left" || bar.position === "right")) ? barW : 0) - root.margin * 2)
: 0
readonly property real availableCardHeight: screenH > 0
? Math.max(120, screenH - ((bar && (bar.position === "top" || bar.position === "bottom")) ? barH : 0) - root.margin * 2)
: 0
readonly property real verticalContentInset: padding * 2 + Border.top(borderSpec) + Border.bottom(borderSpec)
function fittedContentWidth(width, cap) {
var desired = Math.max(1, Number(width) || 1)
var maxWidth = root.availableCardWidth > 0 ? root.availableCardWidth : desired
if (cap !== undefined && Number(cap) > 0) maxWidth = Math.min(maxWidth, Number(cap))
return Math.round(Math.min(desired, maxWidth))
}
function fittedContentHeight(implicitHeight, cap) {
var desired = Math.max(root.verticalContentInset, (Number(implicitHeight) || 0) + root.verticalContentInset)
var maxHeight = root.availableCardHeight > 0 ? root.availableCardHeight : desired
if (cap !== undefined && Number(cap) > 0) maxHeight = Math.min(maxHeight, Number(cap))
return Math.round(Math.min(desired, maxHeight))
}
function cappedContentHeight(height) {
var desired = Math.max(root.padding * 2, Number(height) || root.padding * 2)
var maxHeight = root.availableCardHeight > 0 ? root.availableCardHeight : desired
return Math.round(Math.min(desired, maxHeight))
}
function close() {
if (owner && "close" in owner) owner.close()
else root.open = false
}
default property alias contentItem: contentHolder.children
visible: open || card.opacity > 0
color: "transparent"
implicitWidth: contentWidth
implicitHeight: contentHeight
onOpenChanged: {
if (!bar) return
if (open) bar.requestPopout(coordinatorKey)
else if (bar.activePopout === coordinatorKey) bar.releasePopout(coordinatorKey)
}
// Outside-click dismissal via Hyprland's focus grab. While `active`, input
// is routed only to the listed windows; clicking anywhere else clears the
// grab and we close the popup. Skipped for hover-mode popups so the cursor
// can move freely between the trigger and the popup.
HyprlandFocusGrab {
active: root.open && root.triggerMode === "click"
windows: root.anchorWindow ? [root, root.anchorWindow] : [root]
onCleared: root.close()
}
anchor {
id: popupAnchor
window: anchorItem ? anchorItem.QsWindow.window : null
adjustment: PopupAdjustment.Slide
edges: Edges.Top | Edges.Left
gravity: Edges.Bottom | Edges.Right
rect.width: 1
rect.height: 1
onAnchoring: {
if (!root.anchorItem || !root.bar) return
var target = root.anchorItem
var popupWidth = root.implicitWidth
var popupHeight = root.implicitHeight
var localX = target.width / 2 - popupWidth / 2
var localY = target.height + root.margin
if (root.bar.position === "bottom") {
localY = -popupHeight - root.margin
} else if (root.bar.position === "left") {
localX = target.width + root.margin
localY = target.height / 2 - popupHeight / 2
} else if (root.bar.position === "right") {
localX = -popupWidth - root.margin
localY = target.height / 2 - popupHeight / 2
}
var window = target.QsWindow.window
if (!window) return
if (root.centerOnBar) {
var cx = 0;
var cy = 0;
if (root.bar.position === "top" || root.bar.position === "bottom") {
cx = window.width / 2 - popupWidth / 2
cy = root.bar.position === "bottom" ? -popupHeight - root.margin : window.height + root.margin
cx = Math.max(root.margin, Math.min(cx, window.width - popupWidth - root.margin))
} else {
cx = root.bar.position === "left" ? window.width + root.margin : -popupWidth - root.margin
cy = window.height / 2 - popupHeight / 2
cy = Math.max(root.margin, Math.min(cy, window.height - popupHeight - root.margin))
}
popupAnchor.rect.x = Math.round(cx)
popupAnchor.rect.y = Math.round(cy)
return
}
var point = window.contentItem.mapFromItem(target, localX, localY)
if (root.bar.position === "top" || root.bar.position === "bottom") {
point.x = Math.max(root.margin, Math.min(point.x, window.width - popupWidth - root.margin))
} else {
point.y = Math.max(root.margin, Math.min(point.y, window.height - popupHeight - root.margin))
}
popupAnchor.rect.x = Math.round(point.x)
popupAnchor.rect.y = Math.round(point.y)
}
}
BorderSurface {
id: card
anchors.fill: parent
color: Color.popups.background
borderSpec: root.borderSpec
padding: root.padding
radius: Style.cornerRadius
opacity: root.open ? 1.0 : 0
Behavior on opacity {
NumberAnimation { duration: 140; easing.type: Easing.OutCubic }
}
Item {
id: contentHolder
anchors.fill: parent
anchors.topMargin: card.contentTopInset
anchors.rightMargin: card.contentRightInset
anchors.bottomMargin: card.contentBottomInset
anchors.leftMargin: card.contentLeftInset
}
HoverHandler {
id: cardHover
}
}
}