Automatically shorten titles if they get too long

This commit is contained in:
Thomas Avé 2026-05-07 20:21:42 +07:00
parent be20e34b0e
commit 2776741c23
Signed by: thomasave
SSH Key Fingerprint: SHA256:bvIbWy6TO9+PdMTPzWy6dqkRlVQ3eSky+vQcc9aRIiE
1 changed files with 33 additions and 10 deletions

View File

@ -3,6 +3,7 @@ import app from "ags/gtk4/app";
import { createBinding, createState, For, With, Accessor } from "ags"; import { createBinding, createState, For, With, Accessor } from "ags";
import { createPoll } from "ags/time"; import { createPoll } from "ags/time";
import { subprocess, execAsync } from "ags/process"; import { subprocess, execAsync } from "ags/process";
import Pango from "gi://Pango";
import Tray from "gi://AstalTray"; import Tray from "gi://AstalTray";
import { getIconName } from "./utils"; import { getIconName } from "./utils";
import Wp from "gi://AstalWp"; import Wp from "gi://AstalWp";
@ -295,8 +296,24 @@ function Workspaces({ connector }: { connector: string }): JSX.Element {
); );
} }
function shorten(title: string) { const MAX_TOTAL_CHARS = 120;
return title.length > 40 ? title.slice(0, 20) + "..." : title; const MIN_TITLE_CHARS = 10;
const OVERHEAD_PER_WINDOW = 5; // icon + padding + margin in character-width equivalents
function computeTitleBudgets(wins: any[]): any[] {
const totalLength = wins.reduce((sum, w) => sum + (w.title || "").length, 0);
const count = wins.length;
const totalWithOverhead = totalLength + count * OVERHEAD_PER_WINDOW;
let maxChars: number;
if (count === 0 || totalWithOverhead <= MAX_TOTAL_CHARS) {
maxChars = -1;
} else {
const charsAvailable = MAX_TOTAL_CHARS - count * OVERHEAD_PER_WINDOW;
maxChars = Math.max(MIN_TITLE_CHARS, Math.floor(charsAvailable / count));
}
return wins.map(w => ({ ...w, maxChars }));
} }
function Clients({ connector }: { connector: string }): JSX.Element { function Clients({ connector }: { connector: string }): JSX.Element {
@ -311,6 +328,7 @@ function Clients({ connector }: { connector: string }): JSX.Element {
<box> <box>
{/* Generate a derived binding for windows, depending on the active workspace */} {/* Generate a derived binding for windows, depending on the active workspace */}
<For each={windows((wins: any[]) => <For each={windows((wins: any[]) =>
computeTitleBudgets(
wins.filter((w: any) => !w.title?.includes("rofi")) wins.filter((w: any) => !w.title?.includes("rofi"))
.filter((w: any) => w.workspace_id === active_ws_for_monitor) .filter((w: any) => w.workspace_id === active_ws_for_monitor)
.sort((a: any, b: any) => { .sort((a: any, b: any) => {
@ -318,11 +336,16 @@ function Clients({ connector }: { connector: string }): JSX.Element {
const posB = b.layout?.pos_in_scrolling_layout?.[0] ?? 0; const posB = b.layout?.pos_in_scrolling_layout?.[0] ?? 0;
return posA - posB; return posA - posB;
}) })
)
)}> )}>
{(win: any) => ( {(win: any) => (
<box class={win.is_focused ? "focused" : "unfocused"}> <box class={win.is_focused ? "focused" : "unfocused"}>
<image iconName={getIconName(win.app_id, win.title)} class="app-icon" /> <image iconName={getIconName(win.app_id, win.title)} class="app-icon" />
<label label={shorten(win.title || "")} /> <label
label={win.title || ""}
maxWidthChars={win.maxChars}
ellipsize={Pango.EllipsizeMode.END}
/>
</box> </box>
)} )}
</For> </For>