diff options
Diffstat (limited to 'lib/astal/gtk3/src/widget/window.vala')
-rw-r--r-- | lib/astal/gtk3/src/widget/window.vala | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/lib/astal/gtk3/src/widget/window.vala b/lib/astal/gtk3/src/widget/window.vala new file mode 100644 index 0000000..9287200 --- /dev/null +++ b/lib/astal/gtk3/src/widget/window.vala @@ -0,0 +1,293 @@ +using GtkLayerShell; + +[Flags] +public enum Astal.WindowAnchor { + NONE, + TOP, + RIGHT, + LEFT, + BOTTOM, +} + +public enum Astal.Exclusivity { + NORMAL, + /** + * Request the compositor to allocate space for this window. + */ + EXCLUSIVE, + /** + * Request the compositor to stack layers on top of each other. + */ + IGNORE, +} + +public enum Astal.Layer { + BACKGROUND = 0, // GtkLayerShell.Layer.BACKGROUND + BOTTOM = 1, // GtkLayerShell.Layer.BOTTOM + TOP = 2, // GtkLayerShell.Layer.TOP + OVERLAY = 3, // GtkLayerShell.Layer.OVERLAY +} + +public enum Astal.Keymode { + /** + * Window should not receive keyboard events. + */ + NONE = 0, // GtkLayerShell.KeyboardMode.NONE + /** + * Window should have exclusive focus if it is on the top or overlay layer. + */ + EXCLUSIVE = 1, // GtkLayerShell.KeyboardMode.EXCLUSIVE + /** + * Focus and Unfocues the window as needed. + */ + ON_DEMAND = 2, // GtkLayerShell.KeyboardMode.ON_DEMAND +} + +/** + * Subclass of [[email protected]] which integrates GtkLayerShell as class fields. + */ +public class Astal.Window : Gtk.Window { + private static bool check(string action) { + if (!is_supported()) { + critical(@"can not $action on window: layer shell not supported"); + print("tip: running from an xwayland terminal can cause this, for example VsCode"); + return true; + } + return false; + } + + private InhibitManager? inhibit_manager; + private Inhibitor? inhibitor; + + construct { + if (check("initialize layer shell")) + return; + + // If the window has no size allocatoted when it gets mapped. + // It won't show up later either when it size changes by adding children. + height_request = 1; + width_request = 1; + + init_for_window(this); + inhibit_manager = InhibitManager.get_default(); + } + + /** + * When `true` it will permit inhibiting the idle behavior such as screen blanking, locking, and screensaving. + */ + public bool inhibit { + set { + if (inhibit_manager == null) { + return; + } + if (value && inhibitor == null) { + inhibitor = inhibit_manager.inhibit(this); + } + else if (!value && inhibitor != null) { + inhibitor = null; + } + } + get { + return inhibitor != null; + } + } + + public override void show() { + base.show(); + if(inhibit) { + inhibitor = inhibit_manager.inhibit(this); + } + } + + /** + * Namespace of this window. This can be used to target the layer in compositor rules. + */ + public string namespace { + get { return get_namespace(this); } + set { set_namespace(this, value); } + } + + /** + * Edges to anchor the window to. + * + * If two perpendicular edges are anchored, the surface will be anchored to that corner. + * If two opposite edges are anchored, the window will be stretched across the screen in that direction. + */ + public WindowAnchor anchor { + set { + if (check("set anchor")) + return; + + set_anchor(this, Edge.TOP, WindowAnchor.TOP in value); + set_anchor(this, Edge.BOTTOM, WindowAnchor.BOTTOM in value); + set_anchor(this, Edge.LEFT, WindowAnchor.LEFT in value); + set_anchor(this, Edge.RIGHT, WindowAnchor.RIGHT in value); + } + get { + var a = WindowAnchor.NONE; + if (get_anchor(this, Edge.TOP)) + a = a | WindowAnchor.TOP; + + if (get_anchor(this, Edge.RIGHT)) + a = a | WindowAnchor.RIGHT; + + if (get_anchor(this, Edge.LEFT)) + a = a | WindowAnchor.LEFT; + + if (get_anchor(this, Edge.BOTTOM)) + a = a | WindowAnchor.BOTTOM; + + return a; + } + } + + /** + * Exclusivity of this window. + */ + public Exclusivity exclusivity { + set { + if (check("set exclusivity")) + return; + + switch (value) { + case Exclusivity.NORMAL: + set_exclusive_zone(this, 0); + break; + case Exclusivity.EXCLUSIVE: + auto_exclusive_zone_enable(this); + break; + case Exclusivity.IGNORE: + set_exclusive_zone(this, -1); + break; + } + } + get { + if (auto_exclusive_zone_is_enabled(this)) + return Exclusivity.EXCLUSIVE; + + if (get_exclusive_zone(this) == -1) + return Exclusivity.IGNORE; + + return Exclusivity.NORMAL; + } + } + + /** + * Which layer to appear this window on. + */ + public Layer layer { + get { return (Layer)get_layer(this); } + set { + if (check("set layer")) + return; + + set_layer(this, (GtkLayerShell.Layer)value); + } + } + + /** + * Keyboard mode of this window. + */ + public Keymode keymode { + get { return (Keymode)get_keyboard_mode(this); } + set { + if (check("set keymode")) + return; + + set_keyboard_mode(this, (GtkLayerShell.KeyboardMode)value); + } + } + + /** + * Which monitor to appear this window on. + */ + public Gdk.Monitor gdkmonitor { + get { return get_monitor(this); } + set { + if (check("set gdkmonitor")) + return; + + set_monitor (this, value); + } + } + + public new int margin_top { + get { return GtkLayerShell.get_margin(this, Edge.TOP); } + set { + if (check("set margin_top")) + return; + + GtkLayerShell.set_margin(this, Edge.TOP, value); + } + } + + public new int margin_bottom { + get { return GtkLayerShell.get_margin(this, Edge.BOTTOM); } + set { + if (check("set margin_bottom")) + return; + + GtkLayerShell.set_margin(this, Edge.BOTTOM, value); + } + } + + public new int margin_left { + get { return GtkLayerShell.get_margin(this, Edge.LEFT); } + set { + if (check("set margin_left")) + return; + + GtkLayerShell.set_margin(this, Edge.LEFT, value); + } + } + + public new int margin_right { + get { return GtkLayerShell.get_margin(this, Edge.RIGHT); } + set { + if (check("set margin_right")) + return; + + GtkLayerShell.set_margin(this, Edge.RIGHT, value); + } + } + + public new int margin { + set { + if (check("set margin")) + return; + + margin_top = value; + margin_right = value; + margin_bottom = value; + margin_left = value; + } + } + + /** + * Which monitor to appear this window on. + * + * CAUTION: the id might not be the same mapped by the compositor. + */ + public int monitor { + set { + if (check("set monitor")) + return; + + if (value < 0) + set_monitor(this, (Gdk.Monitor)null); + + var m = Gdk.Display.get_default().get_monitor(value); + set_monitor(this, m); + } + get { + var m = get_monitor(this); + var d = Gdk.Display.get_default(); + for (var i = 0; i < d.get_n_monitors(); ++i) { + if (m == d.get_monitor(i)) + return i; + } + + return -1; + } + } +} |