diff --git a/src/components/bar/utils/monitors/index.ts b/src/components/bar/utils/monitors/index.ts index 3c2092d..62b937b 100644 --- a/src/components/bar/utils/monitors/index.ts +++ b/src/components/bar/utils/monitors/index.ts @@ -3,6 +3,13 @@ import { BarLayout, BarLayouts } from 'src/lib/options/types'; import { GdkMonitorService } from 'src/services/display/monitor'; import { MonitorMapping } from './types'; import { JSXElement } from 'src/core/types'; +import AstalHyprland from 'gi://AstalHyprland?version=0.1'; + +const emptyBar = { + left: [], + middle: [], + right: [], +}; /** * Returns the bar layout configuration for a specific monitor @@ -12,24 +19,80 @@ import { JSXElement } from 'src/core/types'; * @returns BarLayout configuration for the specified monitor, falling back to default if not found */ export const getLayoutForMonitor = (monitor: number, layouts: BarLayouts): BarLayout => { - const matchingKey = Object.keys(layouts).find((key) => key === monitor.toString()); - const wildcard = Object.keys(layouts).find((key) => key === '*'); + const [rootKey, rootLayout] = _getResolveLayoutForMonitor(monitor, layouts); - if (matchingKey !== undefined) { - return layouts[matchingKey]; - } + let left = rootLayout.left; + let middle = rootLayout.middle; + let right = rootLayout.right; - if (wildcard) { - return layouts[wildcard]; + let layout = rootLayout; + const visited = [rootKey]; + while ( + layout.extends !== undefined && + (left === undefined || middle === undefined || right === undefined) + ) { + if (visited.includes(layout.extends)) { + console.error(`found circular reference in layout extensions: ${visited.join(' -> ')}`); + return emptyBar; + } + visited.push(layout.extends); + + if (!(layout.extends in layouts)) { + console.error( + `failed to find layout with name '${layout.extends}' (resolved path: ${visited.join(' -> ')})`, + ); + return emptyBar; + } + + layout = layouts[layout.extends]; + + if (left === undefined) { + left = layout.left; + } + if (middle === undefined) { + middle = layout.middle; + } + if (right === undefined) { + right = layout.right; + } } return { - left: ['dashboard', 'workspaces', 'windowtitle'], - middle: ['media'], - right: ['volume', 'network', 'bluetooth', 'battery', 'systray', 'clock', 'notifications'], + left: left ?? [], + middle: middle ?? [], + right: right ?? [], }; }; +const _getResolveLayoutForMonitor = (monitor: number, layouts: BarLayouts): [string, BarLayout] => { + const hyprlandService = AstalHyprland.get_default(); + const monitorConn = hyprlandService.get_monitor(monitor).get_name(); + + const matchingConn = Object.keys(layouts).find((key) => key === monitorConn); + if (matchingConn !== undefined) { + return [matchingConn, layouts[matchingConn]]; + } + + const matchingNum = Object.keys(layouts).find((key) => key === monitor.toString()); + if (matchingNum !== undefined) { + return [matchingNum, layouts[matchingNum]]; + } + + const wildcard = Object.keys(layouts).find((key) => key === '*'); + if (wildcard) { + return [wildcard, layouts[wildcard]]; + } + + return [ + 'default', + { + left: ['dashboard', 'workspaces', 'windowtitle'], + middle: ['media'], + right: ['volume', 'network', 'bluetooth', 'battery', 'systray', 'clock', 'notifications'], + }, + ]; +}; + /** * Checks if a bar layout configuration is empty * diff --git a/src/lib/bar/helpers.ts b/src/lib/bar/helpers.ts index 57b3bf9..72c6f31 100644 --- a/src/lib/bar/helpers.ts +++ b/src/lib/bar/helpers.ts @@ -16,9 +16,9 @@ export function getLayoutItems(): BarModule[] { const itemsInLayout: BarModule[] = []; Object.keys(layouts.get()).forEach((monitor) => { - const leftItems = layouts.get()[monitor].left; - const rightItems = layouts.get()[monitor].right; - const middleItems = layouts.get()[monitor].middle; + const leftItems = layouts.get()[monitor].left ?? []; + const rightItems = layouts.get()[monitor].right ?? []; + const middleItems = layouts.get()[monitor].middle ?? []; itemsInLayout.push(...leftItems); itemsInLayout.push(...middleItems); diff --git a/src/lib/options/types.ts b/src/lib/options/types.ts index bafb6c1..67b9d0e 100644 --- a/src/lib/options/types.ts +++ b/src/lib/options/types.ts @@ -46,6 +46,7 @@ export type BarLayout = { left: BarModule[]; middle: BarModule[]; right: BarModule[]; + extends?: string; }; export type BarLayouts = { [key: string]: BarLayout; diff --git a/src/services/display/monitor/index.ts b/src/services/display/monitor/index.ts index 156d13c..d176e9c 100644 --- a/src/services/display/monitor/index.ts +++ b/src/services/display/monitor/index.ts @@ -60,7 +60,7 @@ export class GdkMonitorService { const tempUsedIds = new Set(); const monitorsToUse = validMonitors.length > 0 ? validMonitors : hyprlandMonitors; - const result = this._matchMonitor( + return this._matchMonitor( monitorsToUse, gdkMonitor, monitor, @@ -68,8 +68,6 @@ export class GdkMonitorService { (mon, gdkMon) => this._matchMonitorKey(mon, gdkMon), tempUsedIds, ); - - return result; } /**