import { Astal, Gdk, Gtk } from "ags/gtk4"; import { BackgroundWindow } from "./BackgroundWindow"; import { Accessor, CCProps, createComputed, createRoot, getScope } from "ags"; import { omitObjectKeys, WidgetNodeType } from "../modules/utils"; import GObject from "ags/gobject"; type PopupWindowSpecificProps = { $?: (self: Astal.Window) => void; children?: WidgetNodeType; /** Stylesheet for the background of the popup-window */ cssBackgroundWindow?: string; class?: string | Accessor; actionClosed?: (self: Astal.Window) => void|boolean; orientation?: Gtk.Orientation | Accessor; actionClickedOutside?: (self: Astal.Window) => void; actionKeyPressed?: (self: Astal.Window, keyval: number, keycode: number) => void; }; export type PopupWindowProps = Pick>, "monitor" | "layer" | "exclusivity" | "marginLeft" | "marginTop" | "marginRight" | "marginBottom" | "cursor" | "canFocus" | "hasFocus" | "tooltipMarkup" | "tooltipText" | "namespace" | "visible" | "widthRequest" | "heightRequest" | "halign" | "valign" | "anchor" | "vexpand" | "hexpand"> & PopupWindowSpecificProps; const { TOP, LEFT, RIGHT, BOTTOM } = Astal.WindowAnchor; export function PopupWindow(props: PopupWindowProps): GObject.Object { props.visible ??= true; props.layer ??= Astal.Layer.OVERLAY; props.actionClickedOutside ??= (self: Astal.Window) => self.close(); let clickedInside: boolean = false; return `popup-window ${clss} ${namespace}`) : props.class.as(clss => `popup-window ${clss} ${props.namespace ?? ""}`)) : `popup-window ${props.class ?? ""} ${props.namespace ?? ""}` } keymode={Astal.Keymode.EXCLUSIVE} exclusivity={props.exclusivity ?? Astal.Exclusivity.NORMAL} anchor={TOP | LEFT | BOTTOM | RIGHT} visible={false} onCloseRequest={(self) => props.actionClosed?.(self)} $={(self) => { const scope = getScope(); const conns: Map = new Map(); const gestureClick = Gtk.GestureClick.new(); const keyController = Gtk.EventControllerKey.new(); self.add_controller(gestureClick); self.add_controller(keyController); props.cssBackgroundWindow && createRoot((dispose) => dispose()} /> ); props.visible && self.show(); conns.set(gestureClick, gestureClick.connect("released", () => { if(clickedInside) { clickedInside = false; return; } props.actionClickedOutside!(self); })); conns.set(keyController, keyController.connect("key-pressed", (_, keyval, keycode) => { if(keyval === Gdk.KEY_Escape) { conns.forEach((id, obj) => { obj.disconnect(id); }); props.actionClickedOutside!(self); return; } props.actionKeyPressed?.(self, keyval, keycode); })); scope.onCleanup(() => conns.forEach((id, obj) => obj.disconnect(id))); props.$?.(self); }}> { const conns = new Map(), gestureClick = Gtk.GestureClick.new(); gestureClick.set_button(0); self.add_controller(gestureClick); conns.set(gestureClick, gestureClick.connect("released", () => clickedInside = true )); conns.set(self, self.connect("destroy", () => conns.forEach((id, obj) => obj.disconnect(id)))); }}> {props.children} as Astal.Window; } export function getPopupWindowContainer(popupWindow: Astal.Window): Gtk.Box { return popupWindow.get_child()!.get_first_child() as Gtk.Box; }