Fix ags battery icon + always select main monitor
This commit is contained in:
parent
dbec898d65
commit
c4ae794622
|
|
@ -183,6 +183,32 @@ function Right() {
|
|||
);
|
||||
}
|
||||
|
||||
// Icon names to try for the current battery state, most specific first.
|
||||
// Papirus does not ship every combination, so each entry needs a fallback:
|
||||
// "-charged-symbolic" only exists at level 100, and "-charging-symbolic" only
|
||||
// up to level 90 (above that the panel icon has to be named directly).
|
||||
function batteryIconNames(): string[] {
|
||||
const percentage = battery.percentage;
|
||||
const thresholds = [...Array(11).keys()].map((i) => i * 10);
|
||||
const level = thresholds.find((threshold) => threshold >= percentage * 100);
|
||||
const plain = `battery-level-${level}-symbolic`;
|
||||
|
||||
// Being full is a state, not a 100% reading: with a charge limit set the
|
||||
// battery stops well below 100 and sits there reporting FULLY_CHARGED.
|
||||
if (battery.state === Battery.State.FULLY_CHARGED) {
|
||||
return [`battery-level-${level}-charged-symbolic`, plain];
|
||||
}
|
||||
if (battery.charging) {
|
||||
const padded = String(level).padStart(3, "0");
|
||||
return [
|
||||
`battery-level-${level}-charging-symbolic`,
|
||||
`battery-${padded}-charging`,
|
||||
plain,
|
||||
];
|
||||
}
|
||||
return [plain];
|
||||
}
|
||||
|
||||
// Papirus encodes the battery level as a 35%-opacity overlay inside its
|
||||
// *-symbolic icons. GTK4's symbolic recoloring flattens that opacity, so every
|
||||
// level renders as a solid, full battery. The Papirus *-symbolic icons are just
|
||||
|
|
@ -190,13 +216,12 @@ function Right() {
|
|||
// normally — so we resolve each name to that underlying file and load it
|
||||
// directly (as a non-symbolic file icon), which renders the correct level.
|
||||
function batteryGicon(): Gio.Icon {
|
||||
const percentage = battery.percentage;
|
||||
const thresholds = [...Array(11).keys()].map((i) => i * 10);
|
||||
const icon = thresholds.find((threshold) => threshold >= percentage * 100);
|
||||
const name = battery.charging
|
||||
? `battery-level-${icon}-${percentage >= 0.99 ? "charged" : "charging"}-symbolic`
|
||||
: `battery-level-${icon}-symbolic`;
|
||||
const symbolic = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()!)
|
||||
const theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default()!);
|
||||
// lookup_icon() never fails: for an unknown name it hands back the
|
||||
// "image-missing" paintable, so check availability before resolving.
|
||||
const names = batteryIconNames();
|
||||
const name = names.find((n) => theme.has_icon(n)) ?? names[names.length - 1];
|
||||
const symbolic = theme
|
||||
.lookup_icon(name, null, 16, 1, Gtk.TextDirection.NONE, 0)
|
||||
.get_file();
|
||||
if (!symbolic) return Gio.ThemedIcon.new(name);
|
||||
|
|
@ -217,15 +242,21 @@ function batteryGicon(): Gio.Icon {
|
|||
return new Gio.FileIcon({ file: symbolic });
|
||||
}
|
||||
|
||||
function batteryTooltip(): string {
|
||||
return `${Math.round(battery.percentage * 100)}%`;
|
||||
}
|
||||
|
||||
function BatteryIcon(): JSX.Element {
|
||||
if (battery.get_state() == 0) return <box />;
|
||||
// AstalBattery does not emit notify::percentage/charging/state on this
|
||||
// system, so a signal binding stays frozen at its initial value (e.g.
|
||||
// showing "charged" forever). Poll the live values instead.
|
||||
const gicon = createPoll<Gio.Icon>(batteryGicon(), 10000, batteryGicon);
|
||||
const tooltip = createPoll<string>(batteryTooltip(), 10000, batteryTooltip);
|
||||
return (
|
||||
<button
|
||||
class="battery-item"
|
||||
tooltipText={tooltip}
|
||||
onClicked={() => execAsync(["gnome-power-statistics"])}
|
||||
>
|
||||
<box>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,16 @@ import style from "./style.scss";
|
|||
import Bar from "./Bar";
|
||||
import NotificationPopups from "./notifications/NotificationPopups";
|
||||
|
||||
const PREFERRED_MONITOR = "eDP-1";
|
||||
|
||||
function pick_monitor(): Gdk.Monitor | undefined {
|
||||
const monitors = app.get_monitors();
|
||||
return (
|
||||
monitors.find((m: Gdk.Monitor) => m.get_connector() === PREFERRED_MONITOR) ??
|
||||
monitors[0]
|
||||
);
|
||||
}
|
||||
|
||||
function register_windows(monitor: Gdk.Monitor) {
|
||||
let scale = (monitor.get_geometry().width >= 3000) ? 1.2 : 1;
|
||||
Bar(monitor, scale);
|
||||
|
|
@ -14,6 +24,11 @@ app.start({
|
|||
css: style,
|
||||
iconTheme: "Papirus",
|
||||
main() {
|
||||
register_windows(app.get_monitors()[0]);
|
||||
const monitor = pick_monitor();
|
||||
if (!monitor) {
|
||||
console.error("No monitors available, not creating the bar.");
|
||||
return;
|
||||
}
|
||||
register_windows(monitor);
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -18,9 +18,15 @@ const app_icons = new Apps.Apps().list.reduce(
|
|||
export function getIconName(app_id: string | null | undefined, title: string | null | undefined) {
|
||||
if (!app_id && !title) return "";
|
||||
|
||||
// Our foot terminals carry a unique per-window app-id ("footclient-<pid>") so the
|
||||
// "duplicate window" keybind can tell them apart; strip that suffix back to the
|
||||
// base app-id ("footclient") so the icon still resolves.
|
||||
const norm = app_id ? app_id.replace(/-\d+$/, "") : app_id;
|
||||
|
||||
// try fields matching Niri outputs
|
||||
const possibleKeys = [
|
||||
app_id,
|
||||
norm,
|
||||
title
|
||||
].filter(Boolean) as string[];
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue