156 lines
4.1 KiB
TypeScript
156 lines
4.1 KiB
TypeScript
const Hyprland = await Service.import('hyprland');
|
|
const { Box, EventBox, Revealer, Window } = Widget;
|
|
|
|
import Gdk from 'gi://Gdk?version=3.0';
|
|
|
|
import {
|
|
get_hyprland_monitor_desc,
|
|
get_monitor_desc_from_id,
|
|
} from '../lib.ts';
|
|
|
|
|
|
const FullscreenState = Variable({
|
|
monitors: [] as string[],
|
|
clientAddrs: new Map() as Map<string, string>,
|
|
});
|
|
|
|
Hyprland.connect('event', (hyprObj) => {
|
|
const arrayEquals = (a1: unknown[], a2: unknown[]) =>
|
|
a1.sort().toString() === a2.sort().toString();
|
|
|
|
const mapEquals = (m1: Map<string, string>, m2: Map<string, string>) =>
|
|
m1.size === m2.size &&
|
|
Array.from(m1.keys()).every((key) => m1.get(key) === m2.get(key));
|
|
|
|
const fs = FullscreenState.value;
|
|
const fsClients = hyprObj.clients.filter((c) => {
|
|
const mon = Hyprland.getMonitor(c.monitor);
|
|
|
|
return c.fullscreen &&
|
|
c.workspace.id === mon?.activeWorkspace.id;
|
|
});
|
|
|
|
const monitors = fsClients.map((c) =>
|
|
get_monitor_desc_from_id(c.monitor));
|
|
|
|
const clientAddrs = new Map(fsClients.map((c) => [
|
|
get_monitor_desc_from_id(c.monitor),
|
|
c.address,
|
|
]));
|
|
|
|
const hasChanged =
|
|
!arrayEquals(monitors, fs.monitors) ||
|
|
!mapEquals(clientAddrs, fs.clientAddrs);
|
|
|
|
if (hasChanged) {
|
|
FullscreenState.setValue({
|
|
monitors,
|
|
clientAddrs,
|
|
});
|
|
}
|
|
});
|
|
|
|
export default ({
|
|
anchor,
|
|
bar,
|
|
gdkmonitor = Gdk.Display.get_default()?.get_monitor(0) as Gdk.Monitor,
|
|
...rest
|
|
}) => {
|
|
const monitor = get_hyprland_monitor_desc(gdkmonitor);
|
|
const BarVisible = Variable(true);
|
|
|
|
FullscreenState.connect('changed', (v) => {
|
|
BarVisible.setValue(!v.value.monitors.includes(monitor));
|
|
});
|
|
|
|
const barCloser = Window({
|
|
name: `bar-${monitor}-closer`,
|
|
visible: false,
|
|
gdkmonitor,
|
|
anchor: ['top', 'bottom', 'left', 'right'],
|
|
layer: 'overlay',
|
|
|
|
child: EventBox({
|
|
on_hover: () => {
|
|
barCloser.set_visible(false);
|
|
BarVisible.setValue(false);
|
|
},
|
|
|
|
child: Box({
|
|
css: 'padding: 1px;',
|
|
}),
|
|
}),
|
|
});
|
|
|
|
// Hide bar instantly when out of focus
|
|
Hyprland.active.workspace.connect('changed', () => {
|
|
const addr = FullscreenState.value.clientAddrs.get(monitor);
|
|
|
|
if (addr) {
|
|
const client = Hyprland.getClient(addr);
|
|
|
|
if (client!.workspace.id !== Hyprland.active.workspace.id) {
|
|
BarVisible.setValue(false);
|
|
barCloser.visible = false;
|
|
}
|
|
}
|
|
});
|
|
|
|
const buffer = Box({
|
|
css: 'min-height: 10px',
|
|
visible: BarVisible.bind().as((v) => !v),
|
|
});
|
|
|
|
const vertical = anchor.includes('left') && anchor.includes('right');
|
|
const isBottomOrLeft = (
|
|
anchor.includes('left') && anchor.includes('right') && anchor.includes('bottom')
|
|
) || (
|
|
anchor.includes('top') && anchor.includes('bottom') && anchor.includes('left')
|
|
);
|
|
|
|
let transition: 'slide_up' | 'slide_down' | 'slide_left' | 'slide_right';
|
|
|
|
if (vertical) {
|
|
transition = isBottomOrLeft ? 'slide_up' : 'slide_down';
|
|
}
|
|
else {
|
|
transition = isBottomOrLeft ? 'slide_right' : 'slide_left';
|
|
}
|
|
|
|
const barWrap = Revealer({
|
|
reveal_child: BarVisible.bind(),
|
|
transition,
|
|
child: bar,
|
|
});
|
|
|
|
return Window({
|
|
name: `bar-${monitor}`,
|
|
layer: 'overlay',
|
|
gdkmonitor,
|
|
margins: [-1, -1, -1, -1],
|
|
anchor,
|
|
...rest,
|
|
|
|
attribute: {
|
|
barCloser,
|
|
},
|
|
|
|
child: EventBox({
|
|
child: Box({
|
|
css: 'min-height: 1px; padding: 1px;',
|
|
hexpand: true,
|
|
hpack: 'fill',
|
|
vertical,
|
|
|
|
children: isBottomOrLeft ?
|
|
[buffer, barWrap] :
|
|
[barWrap, buffer],
|
|
}),
|
|
}).on('enter-notify-event', () => {
|
|
if (!BarVisible.value) {
|
|
barCloser.visible = true;
|
|
BarVisible.setValue(true);
|
|
}
|
|
}),
|
|
});
|
|
};
|