quickshell: segment bar groups, pin server glance
This commit is contained in:
parent
4df4062806
commit
7bfd1e25c3
1 changed files with 214 additions and 179 deletions
|
|
@ -775,6 +775,20 @@ in
|
||||||
font.pixelSize: 16
|
font.pixelSize: 16
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── BarSep: hairline between widget groups in the bar column.
|
||||||
|
// Wrapped in a plain Item because a Column refuses to position
|
||||||
|
// children that set their own horizontalCenter anchor.
|
||||||
|
component BarSep: Item {
|
||||||
|
width: Theme.barWidth
|
||||||
|
height: 1
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: 16
|
||||||
|
height: 1
|
||||||
|
color: Theme.base02
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── GlanceStat: a bar-column stat — clock-sized value over a
|
// ── GlanceStat: a bar-column stat — clock-sized value over a
|
||||||
// faded 9px caption (the server glance rows).
|
// faded 9px caption (the server glance rows).
|
||||||
component GlanceStat: Column {
|
component GlanceStat: Column {
|
||||||
|
|
@ -1621,9 +1635,11 @@ in
|
||||||
precision: SystemClock.Minutes
|
precision: SystemClock.Minutes
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Top cluster: logo, clock, workspaces. The bar is a column
|
// ── Top cluster: logo, clock, workspaces — the three groups
|
||||||
// now, so the two clusters anchor to opposite ends and the gap
|
// that belong to "this machine, right now", split by hairlines.
|
||||||
// between them is the OSD slot.
|
// The server glance is NOT here: it anchors above the bottom
|
||||||
|
// cluster instead, so adding a workspace grows this column
|
||||||
|
// downward into empty space rather than shoving the stats.
|
||||||
Column {
|
Column {
|
||||||
id: barTop
|
id: barTop
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
|
|
@ -1663,6 +1679,8 @@ in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BarSep {}
|
||||||
|
|
||||||
// Clock — HH over mm; "HH:mm" does not fit a 46px column.
|
// Clock — HH over mm; "HH:mm" does not fit a 46px column.
|
||||||
Item {
|
Item {
|
||||||
id: clockText
|
id: clockText
|
||||||
|
|
@ -1713,6 +1731,8 @@ in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BarSep {}
|
||||||
|
|
||||||
// Workspace dots: accent pill for the focused workspace,
|
// Workspace dots: accent pill for the focused workspace,
|
||||||
// dim dots otherwise. Stacked vertically now, so the
|
// dim dots otherwise. Stacked vertically now, so the
|
||||||
// focused pill grows along HEIGHT rather than width.
|
// focused pill grows along HEIGHT rather than width.
|
||||||
|
|
@ -1753,197 +1773,210 @@ in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server monitor: one persistent SSH streaming `top -b`
|
}
|
||||||
// from the mediaserver (2s ticks, parsed line by line —
|
|
||||||
// no per-poll reconnects) plus a streaming ping to the
|
|
||||||
// router. Glance = CPU/RAM numbers + ping ms; click
|
|
||||||
// opens the btop-style dropdown.
|
|
||||||
Item {
|
|
||||||
id: srvWidget
|
|
||||||
width: Theme.barWidth
|
|
||||||
height: srvGlanceCol.height
|
|
||||||
|
|
||||||
property bool connected: false
|
// ── Mid cluster: the server glance, pinned just above the
|
||||||
property real cpu: 0
|
// bottom cluster. Its own anchor (not a barTop child) is the
|
||||||
property real memUsed: 0 // GiB
|
// whole point: workspace count then changes nothing here.
|
||||||
property real memTotal: 0
|
//
|
||||||
property real pingMs: -1
|
// Server monitor: one persistent SSH streaming `top -b`
|
||||||
property string uptime: ""
|
// from the mediaserver (2s ticks, parsed line by line —
|
||||||
property string load: ""
|
// no per-poll reconnects) plus a streaming ping to the
|
||||||
property var procs: []
|
// router. Glance = CPU/RAM numbers + ping ms; click
|
||||||
property int tempC: -1
|
// opens the btop-style dropdown.
|
||||||
property real rxBps: 0
|
Item {
|
||||||
property real txBps: 0
|
id: srvWidget
|
||||||
|
width: Theme.barWidth
|
||||||
|
height: srvGlanceCol.height
|
||||||
|
anchors.horizontalCenter: barBgRect.horizontalCenter
|
||||||
|
anchors.bottom: barBottom.top
|
||||||
|
anchors.bottomMargin: 20
|
||||||
|
// Fades out while the OSD takes this slot.
|
||||||
|
opacity: osdItem.shown ? 0 : 1
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation { duration: Theme.animContent }
|
||||||
|
}
|
||||||
|
|
||||||
function fmtRate(bps) {
|
property bool connected: false
|
||||||
const b = bps * 8;
|
property real cpu: 0
|
||||||
if (b >= 1e9) return (b / 1e9).toFixed(2) + " Gb/s";
|
property real memUsed: 0 // GiB
|
||||||
if (b >= 1e6) return (b / 1e6).toFixed(1) + " Mb/s";
|
property real memTotal: 0
|
||||||
if (b >= 1e3) return Math.round(b / 1e3) + " Kb/s";
|
property real pingMs: -1
|
||||||
return Math.round(b) + " b/s";
|
property string uptime: ""
|
||||||
|
property string load: ""
|
||||||
|
property var procs: []
|
||||||
|
property int tempC: -1
|
||||||
|
property real rxBps: 0
|
||||||
|
property real txBps: 0
|
||||||
|
|
||||||
|
function fmtRate(bps) {
|
||||||
|
const b = bps * 8;
|
||||||
|
if (b >= 1e9) return (b / 1e9).toFixed(2) + " Gb/s";
|
||||||
|
if (b >= 1e6) return (b / 1e6).toFixed(1) + " Mb/s";
|
||||||
|
if (b >= 1e3) return Math.round(b / 1e3) + " Kb/s";
|
||||||
|
return Math.round(b) + " b/s";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split variants for the bar glance: number and unit
|
||||||
|
// live on separate lines, so both stay narrow.
|
||||||
|
function rateVal(bps) {
|
||||||
|
const b = bps * 8;
|
||||||
|
if (b >= 1e9) return (b / 1e9).toFixed(1);
|
||||||
|
if (b >= 1e7) return Math.round(b / 1e6).toString();
|
||||||
|
if (b >= 1e6) return (b / 1e6).toFixed(1);
|
||||||
|
return Math.round(b / 1e3).toString();
|
||||||
|
}
|
||||||
|
function rateUnit(bps) {
|
||||||
|
const b = bps * 8;
|
||||||
|
if (b >= 1e9) return "gb/s";
|
||||||
|
if (b >= 1e6) return "mb/s";
|
||||||
|
return "kb/s";
|
||||||
|
}
|
||||||
|
|
||||||
|
property var _procsPending: []
|
||||||
|
property bool _collecting: false
|
||||||
|
|
||||||
|
function _parseLine(line) {
|
||||||
|
if (line.indexOf("@STAT ") === 0) {
|
||||||
|
const t = line.match(/temp=(\d+)/);
|
||||||
|
if (t) tempC = parseInt(t[1]);
|
||||||
|
const rx = line.match(/rxbps=(-?\d+)/);
|
||||||
|
if (rx) rxBps = Math.max(0, parseInt(rx[1]));
|
||||||
|
const tx = line.match(/txbps=(-?\d+)/);
|
||||||
|
if (tx) txBps = Math.max(0, parseInt(tx[1]));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (line.indexOf("top - ") === 0) {
|
||||||
// Split variants for the bar glance: number and unit
|
if (_collecting) procs = _procsPending;
|
||||||
// live on separate lines, so both stay narrow.
|
_collecting = false;
|
||||||
function rateVal(bps) {
|
const up = line.match(/up\s+(.*?),\s*\d+\s+users?,/);
|
||||||
const b = bps * 8;
|
if (up) uptime = up[1].replace(/\s+/g, " ");
|
||||||
if (b >= 1e9) return (b / 1e9).toFixed(1);
|
const la = line.match(/load average:\s*(.*)$/);
|
||||||
if (b >= 1e7) return Math.round(b / 1e6).toString();
|
if (la) load = la[1];
|
||||||
if (b >= 1e6) return (b / 1e6).toFixed(1);
|
return;
|
||||||
return Math.round(b / 1e3).toString();
|
|
||||||
}
|
}
|
||||||
function rateUnit(bps) {
|
if (line.indexOf("%Cpu(s)") === 0) {
|
||||||
const b = bps * 8;
|
const m = line.match(/([\d.]+)\s+id/);
|
||||||
if (b >= 1e9) return "gb/s";
|
if (m) { cpu = Math.max(0, 100 - parseFloat(m[1])); connected = true; }
|
||||||
if (b >= 1e6) return "mb/s";
|
return;
|
||||||
return "kb/s";
|
|
||||||
}
|
}
|
||||||
|
const mem = line.match(/^(\S+) Mem\s*:\s*([\d.]+)\s+total,\s*[\d.]+\s+free,\s*([\d.]+)\s+used/);
|
||||||
property var _procsPending: []
|
if (mem) {
|
||||||
property bool _collecting: false
|
const div = mem[1] === "KiB" ? 1048576 : mem[1] === "MiB" ? 1024 : 1;
|
||||||
|
memTotal = parseFloat(mem[2]) / div;
|
||||||
function _parseLine(line) {
|
memUsed = parseFloat(mem[3]) / div;
|
||||||
if (line.indexOf("@STAT ") === 0) {
|
return;
|
||||||
const t = line.match(/temp=(\d+)/);
|
}
|
||||||
if (t) tempC = parseInt(t[1]);
|
if (/^\s*PID\s/.test(line)) { _collecting = true; _procsPending = []; return; }
|
||||||
const rx = line.match(/rxbps=(-?\d+)/);
|
if (_collecting) {
|
||||||
if (rx) rxBps = Math.max(0, parseInt(rx[1]));
|
const f = line.trim().split(/\s+/);
|
||||||
const tx = line.match(/txbps=(-?\d+)/);
|
if (f.length >= 12) {
|
||||||
if (tx) txBps = Math.max(0, parseInt(tx[1]));
|
_procsPending.push({ pid: f[0], cpu: parseFloat(f[8]), mem: parseFloat(f[9]), name: f.slice(11).join(" ") });
|
||||||
return;
|
// top sorts by %CPU; first 10 rows are the story
|
||||||
}
|
if (_procsPending.length >= 10) { procs = _procsPending; _collecting = false; }
|
||||||
if (line.indexOf("top - ") === 0) {
|
} else {
|
||||||
if (_collecting) procs = _procsPending;
|
procs = _procsPending; _collecting = false;
|
||||||
_collecting = false;
|
|
||||||
const up = line.match(/up\s+(.*?),\s*\d+\s+users?,/);
|
|
||||||
if (up) uptime = up[1].replace(/\s+/g, " ");
|
|
||||||
const la = line.match(/load average:\s*(.*)$/);
|
|
||||||
if (la) load = la[1];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (line.indexOf("%Cpu(s)") === 0) {
|
|
||||||
const m = line.match(/([\d.]+)\s+id/);
|
|
||||||
if (m) { cpu = Math.max(0, 100 - parseFloat(m[1])); connected = true; }
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const mem = line.match(/^(\S+) Mem\s*:\s*([\d.]+)\s+total,\s*[\d.]+\s+free,\s*([\d.]+)\s+used/);
|
|
||||||
if (mem) {
|
|
||||||
const div = mem[1] === "KiB" ? 1048576 : mem[1] === "MiB" ? 1024 : 1;
|
|
||||||
memTotal = parseFloat(mem[2]) / div;
|
|
||||||
memUsed = parseFloat(mem[3]) / div;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (/^\s*PID\s/.test(line)) { _collecting = true; _procsPending = []; return; }
|
|
||||||
if (_collecting) {
|
|
||||||
const f = line.trim().split(/\s+/);
|
|
||||||
if (f.length >= 12) {
|
|
||||||
_procsPending.push({ pid: f[0], cpu: parseFloat(f[8]), mem: parseFloat(f[9]), name: f.slice(11).join(" ") });
|
|
||||||
// top sorts by %CPU; first 10 rows are the story
|
|
||||||
if (_procsPending.length >= 10) { procs = _procsPending; _collecting = false; }
|
|
||||||
} else {
|
|
||||||
procs = _procsPending; _collecting = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: srvTop
|
id: srvTop
|
||||||
command: [Commands.ssh, "-o", "BatchMode=yes", "-o", "ConnectTimeout=3",
|
command: [Commands.ssh, "-o", "BatchMode=yes", "-o", "ConnectTimeout=3",
|
||||||
"-o", "StrictHostKeyChecking=accept-new",
|
"-o", "StrictHostKeyChecking=accept-new",
|
||||||
"-o", "ServerAliveInterval=5", "-o", "ServerAliveCountMax=2",
|
"-o", "ServerAliveInterval=5", "-o", "ServerAliveCountMax=2",
|
||||||
"fred@10.0.0.1", "qs-stats"]
|
"fred@10.0.0.1", "qs-stats"]
|
||||||
running: true
|
running: true
|
||||||
stdout: SplitParser {
|
stdout: SplitParser {
|
||||||
onRead: data => srvWidget._parseLine(data)
|
onRead: data => srvWidget._parseLine(data)
|
||||||
}
|
|
||||||
onRunningChanged: if (!running) { srvWidget.connected = false; srvRestart.start(); }
|
|
||||||
}
|
}
|
||||||
Timer { id: srvRestart; interval: 10000; onTriggered: srvTop.running = true }
|
onRunningChanged: if (!running) { srvWidget.connected = false; srvRestart.start(); }
|
||||||
|
}
|
||||||
|
Timer { id: srvRestart; interval: 10000; onTriggered: srvTop.running = true }
|
||||||
|
|
||||||
// Ping is deliberately separate from the SSH stream:
|
// Ping is deliberately separate from the SSH stream:
|
||||||
// ping up + ssh down = box alive but wedged (seen it).
|
// ping up + ssh down = box alive but wedged (seen it).
|
||||||
Process {
|
Process {
|
||||||
id: srvPing
|
id: srvPing
|
||||||
command: [Commands.ping, "-n", "-i", "2", "10.0.0.1"]
|
command: [Commands.ping, "-n", "-i", "2", "10.0.0.1"]
|
||||||
running: true
|
running: true
|
||||||
stdout: SplitParser {
|
stdout: SplitParser {
|
||||||
onRead: data => {
|
onRead: data => {
|
||||||
const m = data.match(/time=([\d.]+)\s*ms/);
|
const m = data.match(/time=([\d.]+)\s*ms/);
|
||||||
if (m) { srvWidget.pingMs = parseFloat(m[1]); pingStale.restart(); }
|
if (m) { srvWidget.pingMs = parseFloat(m[1]); pingStale.restart(); }
|
||||||
}
|
|
||||||
}
|
|
||||||
onRunningChanged: if (!running) pingRestart.start()
|
|
||||||
}
|
|
||||||
Timer { id: pingRestart; interval: 10000; onTriggered: srvPing.running = true }
|
|
||||||
// No echo reply for 3 intervals -> show dashes, not a stale number.
|
|
||||||
Timer { id: pingStale; interval: 6000; onTriggered: srvWidget.pingMs = -1 }
|
|
||||||
|
|
||||||
function openSrvDropdown() {
|
|
||||||
bar.toggleDropdown(srvDropdown, function() {
|
|
||||||
let pos = srvWidget.mapToItem(bar.contentItem, 0, srvWidget.height / 2);
|
|
||||||
srvDropdown.dropdownY = pos.y;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stat stack, clock-sized values over faded captions.
|
|
||||||
Column {
|
|
||||||
id: srvGlanceCol
|
|
||||||
anchors.centerIn: parent
|
|
||||||
spacing: 5
|
|
||||||
|
|
||||||
GlanceStat {
|
|
||||||
value: srvWidget.connected ? Math.round(srvWidget.cpu) + "%" : "--"
|
|
||||||
caption: "cpu"
|
|
||||||
valueColor: srvWidget.connected ? Theme.base0D : Theme.base03
|
|
||||||
}
|
|
||||||
GlanceStat {
|
|
||||||
value: srvWidget.connected && srvWidget.memTotal > 0
|
|
||||||
? Math.round(100 * srvWidget.memUsed / srvWidget.memTotal) + "%" : "--"
|
|
||||||
caption: "ram"
|
|
||||||
valueColor: srvWidget.connected ? Theme.base0C : Theme.base03
|
|
||||||
}
|
|
||||||
GlanceStat {
|
|
||||||
value: srvWidget.connected && srvWidget.tempC >= 0 ? srvWidget.tempC + "°" : "--"
|
|
||||||
caption: "temp"
|
|
||||||
valueColor: !srvWidget.connected || srvWidget.tempC < 0 ? Theme.base03
|
|
||||||
: srvWidget.tempC >= 85 ? Theme.base08
|
|
||||||
: srvWidget.tempC >= 70 ? Theme.base0A : Theme.base05
|
|
||||||
}
|
|
||||||
GlanceStat {
|
|
||||||
value: srvWidget.connected ? srvWidget.rateVal(srvWidget.rxBps) : "--"
|
|
||||||
caption: "↓ " + srvWidget.rateUnit(srvWidget.rxBps)
|
|
||||||
valueColor: srvWidget.connected ? Theme.base0B : Theme.base03
|
|
||||||
}
|
|
||||||
GlanceStat {
|
|
||||||
value: srvWidget.connected ? srvWidget.rateVal(srvWidget.txBps) : "--"
|
|
||||||
caption: "↑ " + srvWidget.rateUnit(srvWidget.txBps)
|
|
||||||
valueColor: srvWidget.connected ? Theme.base09 : Theme.base03
|
|
||||||
}
|
|
||||||
GlanceStat {
|
|
||||||
value: srvWidget.pingMs < 0 ? "--"
|
|
||||||
: srvWidget.pingMs < 10 ? srvWidget.pingMs.toFixed(1)
|
|
||||||
: Math.round(srvWidget.pingMs).toString()
|
|
||||||
caption: "ms"
|
|
||||||
valueColor: srvWidget.pingMs < 0 ? Theme.base03 : Theme.base04
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onRunningChanged: if (!running) pingRestart.start()
|
||||||
|
}
|
||||||
|
Timer { id: pingRestart; interval: 10000; onTriggered: srvPing.running = true }
|
||||||
|
// No echo reply for 3 intervals -> show dashes, not a stale number.
|
||||||
|
Timer { id: pingStale; interval: 6000; onTriggered: srvWidget.pingMs = -1 }
|
||||||
|
|
||||||
MouseArea {
|
function openSrvDropdown() {
|
||||||
anchors.fill: parent
|
bar.toggleDropdown(srvDropdown, function() {
|
||||||
hoverEnabled: true
|
let pos = srvWidget.mapToItem(bar.contentItem, 0, srvWidget.height / 2);
|
||||||
onClicked: srvWidget.openSrvDropdown()
|
srvDropdown.dropdownY = pos.y;
|
||||||
onEntered: {
|
});
|
||||||
if (bar.activeDropdown) {
|
}
|
||||||
if (bar.activeDropdown !== srvDropdown) srvWidget.openSrvDropdown();
|
|
||||||
}
|
// Stat stack, clock-sized values over faded captions.
|
||||||
|
Column {
|
||||||
|
id: srvGlanceCol
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: 5
|
||||||
|
|
||||||
|
GlanceStat {
|
||||||
|
value: srvWidget.connected ? Math.round(srvWidget.cpu) + "%" : "--"
|
||||||
|
caption: "cpu"
|
||||||
|
valueColor: srvWidget.connected ? Theme.base0D : Theme.base03
|
||||||
|
}
|
||||||
|
GlanceStat {
|
||||||
|
value: srvWidget.connected && srvWidget.memTotal > 0
|
||||||
|
? Math.round(100 * srvWidget.memUsed / srvWidget.memTotal) + "%" : "--"
|
||||||
|
caption: "ram"
|
||||||
|
valueColor: srvWidget.connected ? Theme.base0C : Theme.base03
|
||||||
|
}
|
||||||
|
GlanceStat {
|
||||||
|
value: srvWidget.connected && srvWidget.tempC >= 0 ? srvWidget.tempC + "°" : "--"
|
||||||
|
caption: "temp"
|
||||||
|
valueColor: !srvWidget.connected || srvWidget.tempC < 0 ? Theme.base03
|
||||||
|
: srvWidget.tempC >= 85 ? Theme.base08
|
||||||
|
: srvWidget.tempC >= 70 ? Theme.base0A : Theme.base05
|
||||||
|
}
|
||||||
|
GlanceStat {
|
||||||
|
value: srvWidget.connected ? srvWidget.rateVal(srvWidget.rxBps) : "--"
|
||||||
|
caption: "↓ " + srvWidget.rateUnit(srvWidget.rxBps)
|
||||||
|
valueColor: srvWidget.connected ? Theme.base0B : Theme.base03
|
||||||
|
}
|
||||||
|
GlanceStat {
|
||||||
|
value: srvWidget.connected ? srvWidget.rateVal(srvWidget.txBps) : "--"
|
||||||
|
caption: "↑ " + srvWidget.rateUnit(srvWidget.txBps)
|
||||||
|
valueColor: srvWidget.connected ? Theme.base09 : Theme.base03
|
||||||
|
}
|
||||||
|
GlanceStat {
|
||||||
|
value: srvWidget.pingMs < 0 ? "--"
|
||||||
|
: srvWidget.pingMs < 10 ? srvWidget.pingMs.toFixed(1)
|
||||||
|
: Math.round(srvWidget.pingMs).toString()
|
||||||
|
caption: "ms"
|
||||||
|
valueColor: srvWidget.pingMs < 0 ? Theme.base03 : Theme.base04
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
onClicked: srvWidget.openSrvDropdown()
|
||||||
|
onEntered: {
|
||||||
|
if (bar.activeDropdown) {
|
||||||
|
if (bar.activeDropdown !== srvDropdown) srvWidget.openSrvDropdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Bottom cluster: status icons, tray, power button. Anchored
|
// ── Bottom cluster: status icons, tray, power button. Anchored
|
||||||
// to the bottom edge so the gap above it — between here and the
|
// to the bottom edge; the server glance sits just above it and
|
||||||
// workspace dots — stays free as the OSD slot.
|
// the OSD borrows that same slot while it is on screen.
|
||||||
Column {
|
Column {
|
||||||
id: barBottom
|
id: barBottom
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
@ -2294,7 +2327,7 @@ in
|
||||||
|
|
||||||
// Group separator: status icons / tray / power read
|
// Group separator: status icons / tray / power read
|
||||||
// as three clusters instead of one clump.
|
// as three clusters instead of one clump.
|
||||||
Item { width: Theme.barWidth; height: 10 }
|
BarSep {}
|
||||||
|
|
||||||
// Tray icons — stacked, like everything else in the column
|
// Tray icons — stacked, like everything else in the column
|
||||||
Column {
|
Column {
|
||||||
|
|
@ -2382,7 +2415,7 @@ in
|
||||||
|
|
||||||
// Group separator: status icons / tray / power read
|
// Group separator: status icons / tray / power read
|
||||||
// as three clusters instead of one clump.
|
// as three clusters instead of one clump.
|
||||||
Item { width: Theme.barWidth; height: 10 }
|
BarSep {}
|
||||||
|
|
||||||
// Power menu opener — bottom-left corner. Opens the same
|
// Power menu opener — bottom-left corner. Opens the same
|
||||||
// session menu as Super+L, which now unfolds from here.
|
// session menu as Super+L, which now unfolds from here.
|
||||||
|
|
@ -4168,10 +4201,12 @@ in
|
||||||
property real value: 0
|
property real value: 0
|
||||||
property color fill: Theme.base0D
|
property color fill: Theme.base0D
|
||||||
|
|
||||||
|
// Takes over the server glance's slot: fixed position, no
|
||||||
|
// dependence on how tall the workspace column has grown.
|
||||||
width: Theme.barWidth
|
width: Theme.barWidth
|
||||||
|
height: 170
|
||||||
anchors.horizontalCenter: barBgRect.horizontalCenter
|
anchors.horizontalCenter: barBgRect.horizontalCenter
|
||||||
anchors.top: barTop.bottom
|
anchors.verticalCenter: srvWidget.verticalCenter
|
||||||
anchors.bottom: barBottom.top
|
|
||||||
opacity: shown ? 1 : 0
|
opacity: shown ? 1 : 0
|
||||||
visible: opacity > 0.01
|
visible: opacity > 0.01
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue