initial commit
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import qs.config
|
||||
import qs.components
|
||||
import qs.services
|
||||
|
||||
// Left click focuses the window, or minimises it if it is already focused —
|
||||
// except under attwm, which has no minimised state. Middle click closes it.
|
||||
PanelButton {
|
||||
id: root
|
||||
|
||||
// The window this button stands for: either an attwm window object from its
|
||||
// IPC state, or a Toplevel handle from wlr-foreign-toplevel-management.
|
||||
// Both carry the same facts under different names, so `attwm` says which is
|
||||
// in hand rather than each read having to guess.
|
||||
required property var win
|
||||
required property bool attwm
|
||||
|
||||
readonly property string appId: (root.attwm ? root.win.app_id : root.win.appId) || ""
|
||||
readonly property bool activated: root.attwm ? root.win.focused : root.win.activated
|
||||
|
||||
// Not on screen right now: minimised elsewhere, and under attwm parked on a
|
||||
// tag nobody is viewing, which is that model's equivalent.
|
||||
readonly property bool hidden: root.attwm ? !root.win.visible : root.win.minimized
|
||||
|
||||
// Desktop entries carry a proper themed icon; appId alone often works as an
|
||||
// icon name too, which is the fallback AppIcon ends up using.
|
||||
readonly property var entry: DesktopEntries.heuristicLookup(root.appId)
|
||||
readonly property string title: root.win.title || root.appId || "Window"
|
||||
|
||||
active: root.activated
|
||||
minContentWidth: Config.windowButtonMinWidth
|
||||
acceptedButtons: Qt.LeftButton | Qt.MiddleButton
|
||||
|
||||
opacity: root.hidden ? 0.55 : 1
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.animDuration
|
||||
easing.type: Theme.animEasing
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: event => {
|
||||
if (event.button === Qt.MiddleButton) {
|
||||
if (root.attwm)
|
||||
Attwm.closeWindow(root.win.id);
|
||||
else
|
||||
root.win.close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (root.attwm) {
|
||||
// attwm has nothing to minimise into — a window is on a tag or it
|
||||
// is not — so a click always means focus, and attwm brings the
|
||||
// window's tags into view if they are not already.
|
||||
Attwm.focusWindow(root.win.id);
|
||||
return;
|
||||
}
|
||||
|
||||
if (root.win.activated) {
|
||||
root.win.minimized = true;
|
||||
} else {
|
||||
root.win.minimized = false;
|
||||
root.win.activate();
|
||||
}
|
||||
}
|
||||
|
||||
// Both children are given the same height so the Row needs no anchors,
|
||||
// which positioners disallow.
|
||||
Row {
|
||||
spacing: Theme.spacing + 2
|
||||
|
||||
AppIcon {
|
||||
icon: (root.entry && root.entry.icon) || root.appId
|
||||
fallbackLabel: root.appId || root.title
|
||||
size: Theme.iconSize
|
||||
}
|
||||
|
||||
Text {
|
||||
id: label
|
||||
|
||||
// Clamp to the natural width so the button never depends on its own
|
||||
// width, which would loop through PanelButton's implicit sizing.
|
||||
width: Math.min(implicitWidth, Config.windowButtonMaxWidth)
|
||||
height: Theme.iconSize
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideRight
|
||||
text: root.title
|
||||
color: root.activated ? Theme.text : Theme.textDim
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSize
|
||||
}
|
||||
}
|
||||
|
||||
// Active-window underline, the usual taskbar affordance.
|
||||
overlay: Rectangle {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
leftMargin: Theme.radius
|
||||
rightMargin: Theme.radius
|
||||
}
|
||||
height: 2
|
||||
radius: 1
|
||||
color: Theme.accent
|
||||
visible: root.activated
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user