2024-10-16 22:33:15 -04:00
|
|
|
import { App, Astal, Gtk, Widget } from 'astal/gtk3';
|
2024-10-18 00:44:45 -04:00
|
|
|
import { register } from 'astal/gobject';
|
2024-10-15 20:01:20 -04:00
|
|
|
import { Binding, idle } from 'astal';
|
2024-10-12 15:21:28 -04:00
|
|
|
|
2024-10-16 22:33:15 -04:00
|
|
|
import { get_hyprland_monitor, hyprMessage } from '../../lib';
|
2024-10-12 15:21:28 -04:00
|
|
|
|
|
|
|
/* Types */
|
|
|
|
type CloseType = 'none' | 'stay' | 'released' | 'clicked';
|
|
|
|
type HyprTransition = 'slide' | 'slide top' | 'slide bottom' | 'slide left' |
|
|
|
|
'slide right' | 'popin' | 'fade';
|
|
|
|
type PopupCallback = (self: PopupWindow) => void;
|
|
|
|
|
|
|
|
type PopupWindowProps = Widget.WindowProps & {
|
|
|
|
transition?: HyprTransition | Binding<HyprTransition>
|
|
|
|
close_on_unfocus?: CloseType | Binding<CloseType>
|
|
|
|
on_open?: PopupCallback
|
|
|
|
on_close?: PopupCallback
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
@register()
|
2024-10-16 21:44:45 -04:00
|
|
|
export class PopupWindow extends Widget.Window {
|
2024-10-18 00:44:45 -04:00
|
|
|
transition: HyprTransition | Binding<HyprTransition>;
|
|
|
|
close_on_unfocus: CloseType | Binding<CloseType>;
|
|
|
|
on_open: PopupCallback;
|
|
|
|
on_close: PopupCallback;
|
2024-10-12 15:21:28 -04:00
|
|
|
|
|
|
|
constructor({
|
2024-10-16 21:44:45 -04:00
|
|
|
transition = 'slide top',
|
|
|
|
close_on_unfocus = 'released',
|
2024-10-12 15:21:28 -04:00
|
|
|
on_open = () => { /**/ },
|
|
|
|
on_close = () => { /**/ },
|
|
|
|
|
|
|
|
name,
|
|
|
|
visible = false,
|
|
|
|
layer = Astal.Layer.OVERLAY,
|
|
|
|
...rest
|
|
|
|
}: PopupWindowProps) {
|
|
|
|
super({
|
|
|
|
...rest,
|
2024-10-16 21:44:45 -04:00
|
|
|
name: `win-${name}`,
|
2024-10-12 15:21:28 -04:00
|
|
|
namespace: `win-${name}`,
|
|
|
|
visible: false,
|
|
|
|
layer,
|
|
|
|
setup: () => idle(() => {
|
|
|
|
// Add way to make window open on startup
|
|
|
|
if (visible) {
|
|
|
|
this.visible = true;
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
});
|
|
|
|
|
2024-10-16 21:44:45 -04:00
|
|
|
App.add_window(this);
|
|
|
|
|
2024-10-12 15:21:28 -04:00
|
|
|
const setTransition = (_: PopupWindow, t: HyprTransition | Binding<HyprTransition>) => {
|
2024-10-16 22:33:15 -04:00
|
|
|
hyprMessage(`keyword layerrule animation ${t}, ${this.name}`).catch(console.log);
|
2024-10-12 15:21:28 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
this.connect('notify::transition', setTransition);
|
|
|
|
|
|
|
|
this.close_on_unfocus = close_on_unfocus;
|
|
|
|
this.transition = transition;
|
|
|
|
this.on_open = on_open;
|
|
|
|
this.on_close = on_close;
|
|
|
|
|
|
|
|
this.connect('notify::visible', () => {
|
|
|
|
// Make sure we have the right animation
|
|
|
|
setTransition(this, this.transition);
|
|
|
|
|
|
|
|
if (this.visible) {
|
|
|
|
this.on_open(this);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.on_close(this);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
2024-10-16 22:33:15 -04:00
|
|
|
|
|
|
|
set_x_pos(
|
|
|
|
alloc: Gtk.Allocation,
|
|
|
|
side = 'right' as 'left' | 'right',
|
|
|
|
) {
|
|
|
|
const monitor = this.gdkmonitor ??
|
2024-10-17 11:04:24 -04:00
|
|
|
this.get_display().get_monitor_at_point(alloc.x, alloc.y);
|
2024-10-16 22:33:15 -04:00
|
|
|
|
|
|
|
// @ts-expect-error this should exist
|
|
|
|
const transform = get_hyprland_monitor(monitor)?.transform;
|
|
|
|
|
|
|
|
let width: number;
|
|
|
|
|
|
|
|
if (transform && (transform === 1 || transform === 3)) {
|
|
|
|
width = monitor.get_geometry().height;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
width = monitor.get_geometry().width;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.margin_right = side === 'right' ?
|
2024-10-17 11:04:24 -04:00
|
|
|
(width - alloc.x - alloc.width) :
|
|
|
|
this.margin_right;
|
2024-10-16 22:33:15 -04:00
|
|
|
|
|
|
|
this.margin_left = side === 'right' ?
|
2024-10-17 11:04:24 -04:00
|
|
|
this.margin_left :
|
|
|
|
(alloc.x - alloc.width);
|
2024-10-16 22:33:15 -04:00
|
|
|
}
|
2024-10-12 15:21:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
export default (props: PopupWindowProps) => new PopupWindow(props);
|