import { Astal, bind, Gdk, Gtk, Variable, Widget } from 'astal'; import AstalHyprland from 'gi://AstalHyprland?version=0.1'; const Hyprland = AstalHyprland.get_default(); import { get_hyprland_monitor_desc, get_monitor_desc } from '../../lib'; const FullscreenState = Variable({ monitors: [] as string[], clientAddrs: new Map() as Map, }); Hyprland.connect('event', () => { const arrayEquals = (a1: unknown[], a2: unknown[]) => a1.sort().toString() === a2.sort().toString(); const mapEquals = (m1: Map, m2: Map) => m1.size === m2.size && Array.from(m1.keys()).every((key) => m1.get(key) === m2.get(key)); const fs = FullscreenState.get(); const fsClients = Hyprland.get_clients().filter((c) => { const mon = c.get_monitor(); return c.fullscreen && c.workspace.id === mon?.activeWorkspace.id; }); const monitors = fsClients.map((c) => get_monitor_desc(c.monitor)); const clientAddrs = new Map(fsClients.map((c) => [ get_monitor_desc(c.monitor), c.address ?? '', ])); const hasChanged = !arrayEquals(monitors, fs.monitors) || !mapEquals(clientAddrs, fs.clientAddrs); if (hasChanged) { FullscreenState.set({ monitors, clientAddrs, }); } }); export default ({ anchor, gdkmonitor = Gdk.Display.get_default()?.get_monitor(0) as Gdk.Monitor, child, ...rest }: Widget.WindowProps) => { const monitor = get_hyprland_monitor_desc(gdkmonitor); const BarVisible = Variable(true); FullscreenState.subscribe((v) => { BarVisible.set(!v.monitors.includes(monitor)); }); const barCloser = ( { barCloser.visible = false; BarVisible.set(false); }} > ); // Hide bar instantly when out of focus Hyprland.connect('notify::focused-workspace', () => { const addr = FullscreenState.get().clientAddrs.get(monitor); if (addr) { const client = Hyprland.get_client(addr); if (client?.workspace.id !== Hyprland.get_focused_workspace().get_id()) { BarVisible.set(true); barCloser.visible = false; } else { BarVisible.set(false); barCloser.visible = true; } } }); const buffer = ( !v)} /> ); const vertical = anchor >= (Astal.WindowAnchor.LEFT | Astal.WindowAnchor.RIGHT); const isBottomOrLeft = ( anchor === (Astal.WindowAnchor.LEFT | Astal.WindowAnchor.RIGHT | Astal.WindowAnchor.BOTTOM) ) || ( anchor === (Astal.WindowAnchor.LEFT | Astal.WindowAnchor.TOP | Astal.WindowAnchor.BOTTOM) ); let transition: Gtk.RevealerTransitionType; if (vertical) { transition = isBottomOrLeft ? Gtk.RevealerTransitionType.SLIDE_UP : Gtk.RevealerTransitionType.SLIDE_DOWN; } else { transition = isBottomOrLeft ? Gtk.RevealerTransitionType.SLIDE_RIGHT : Gtk.RevealerTransitionType.SLIDE_LEFT; } const barWrap = ( {child} ); return ( { if (!BarVisible.get()) { barCloser.visible = true; BarVisible.set(true); } }} > {isBottomOrLeft ? [buffer, barWrap] : [barWrap, buffer]} ); };