From 4850f1b0f6fef25175aaf8f44ce7770c874c191e Mon Sep 17 00:00:00 2001 From: Leonhard <106322251+leolost2605@users.noreply.github.com> Date: Fri, 6 Dec 2024 15:54:55 +0100 Subject: [PATCH] X11: Use window shape to fix input for invisible windows (#2142) --- lib/Utils.vala | 45 +++++++++++++++++++++++++++++ src/ShellClients/DelegateActor.vala | 42 --------------------------- src/ShellClients/PanelClone.vala | 14 ++++----- src/ShellClients/PanelWindow.vala | 4 --- src/meson.build | 1 - vapi/xfixes-4.0.vapi | 4 +++ 6 files changed, 56 insertions(+), 54 deletions(-) delete mode 100644 src/ShellClients/DelegateActor.vala diff --git a/lib/Utils.vala b/lib/Utils.vala index d48eb754..f651d622 100644 --- a/lib/Utils.vala +++ b/lib/Utils.vala @@ -400,5 +400,50 @@ namespace Gala { return texture; } + + private static HashTable regions = new HashTable (null, null); + + public static void x11_set_window_pass_through (Meta.Window window) { + unowned var x11_display = window.display.get_x11_display (); + +#if HAS_MUTTER46 + var x_window = x11_display.lookup_xwindow (window); +#else + var x_window = window.get_xwindow (); +#endif + unowned var xdisplay = x11_display.get_xdisplay (); + + regions[window] = X.Fixes.create_region_from_window (xdisplay, x_window, 0); + + X.Xrectangle rect = {}; + + var region = X.Fixes.create_region (xdisplay, {rect}); + + X.Fixes.set_window_shape_region (xdisplay, x_window, 2, 0, 0, region); + + X.Fixes.destroy_region (xdisplay, region); + } + + public static void x11_unset_window_pass_through (Meta.Window window) { + unowned var x11_display = window.display.get_x11_display (); + +#if HAS_MUTTER46 + var x_window = x11_display.lookup_xwindow (window); +#else + var x_window = window.get_xwindow (); +#endif + unowned var xdisplay = x11_display.get_xdisplay (); + + var region = regions[window]; + + if (region == null) { + return; + } + + X.Fixes.set_window_shape_region (xdisplay, x_window, 2, 0, 0, region); + + regions.remove (window); + X.Fixes.destroy_region (xdisplay, region); + } } } diff --git a/src/ShellClients/DelegateActor.vala b/src/ShellClients/DelegateActor.vala deleted file mode 100644 index bd93f912..00000000 --- a/src/ShellClients/DelegateActor.vala +++ /dev/null @@ -1,42 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-3.0-or-later - * SPDX-FileCopyrightText: 2024 elementary, Inc. (https://elementary.io) - */ - -/* This class is used to workaround https://github.com/elementary/gala/issues/2101 */ -public class Gala.DelegateActor : GLib.Object { - public const int OUT_OF_BOUNDS = 1000000; - - public Meta.WindowActor actor { get; construct; } - - /* Current window actor position or position before the window was moved out of bounds */ - public float x { get; private set; default = 0.0f; } - public float y { get; private set; default = 0.0f; } - - /* Current window position or position before it was moved out of bounds */ - public int actual_x { get; private set; default = 0; } - public int actual_y { get; private set; default = 0; } - - public DelegateActor (Meta.WindowActor actor) { - Object (actor: actor); - } - - construct { - actor.meta_window.position_changed.connect ((_window) => { - var rect = _window.get_frame_rect (); - - if (rect.x != OUT_OF_BOUNDS) { - actual_x = rect.x; - Idle.add_once (() => { - x = actor.x; - }); - } - if (rect.y != OUT_OF_BOUNDS) { - actual_y = rect.y; - Idle.add_once (() => { - y = actor.y; - }); - } - }); - } -} diff --git a/src/ShellClients/PanelClone.vala b/src/ShellClients/PanelClone.vala index 15fc8d23..6a32b101 100644 --- a/src/ShellClients/PanelClone.vala +++ b/src/ShellClients/PanelClone.vala @@ -48,8 +48,8 @@ public class Gala.PanelClone : Object { actor = (Meta.WindowActor) panel.window.get_compositor_private (); // WindowActor position and Window position aren't necessarily the same. // The clone needs the actor position - panel.delegate_actor.notify["x"].connect (update_clone_position); - panel.delegate_actor.notify["y"].connect (update_clone_position); + actor.notify["x"].connect (update_clone_position); + actor.notify["y"].connect (update_clone_position); // Actor visibility might be changed by something else e.g. workspace switch // but we want to keep it in sync with us actor.notify["visible"].connect (update_visible); @@ -97,7 +97,7 @@ public class Gala.PanelClone : Object { switch (panel.anchor) { case TOP: case BOTTOM: - return panel.delegate_actor.x; + return actor.x; default: return 0; } @@ -106,9 +106,9 @@ public class Gala.PanelClone : Object { private float calculate_clone_y (bool hidden) { switch (panel.anchor) { case TOP: - return hidden ? panel.delegate_actor.y - actor.height : panel.delegate_actor.y; + return hidden ? actor.y - actor.height : actor.y; case BOTTOM: - return hidden ? panel.delegate_actor.y + actor.height : panel.delegate_actor.y; + return hidden ? actor.y + actor.height : actor.y; default: return 0; } @@ -128,7 +128,7 @@ public class Gala.PanelClone : Object { panel_hidden = true; if (!Meta.Util.is_wayland_compositor ()) { - panel.window.move_frame (false, DelegateActor.OUT_OF_BOUNDS, DelegateActor.OUT_OF_BOUNDS); + Utils.x11_set_window_pass_through (panel.window); } if (panel.anchor != TOP && panel.anchor != BOTTOM) { @@ -151,7 +151,7 @@ public class Gala.PanelClone : Object { } if (!Meta.Util.is_wayland_compositor ()) { - panel.window.move_frame (false, panel.delegate_actor.actual_x, panel.delegate_actor.actual_y); + Utils.x11_unset_window_pass_through (panel.window); } clone.save_easing_state (); diff --git a/src/ShellClients/PanelWindow.vala b/src/ShellClients/PanelWindow.vala index 107218e1..5351cbe5 100644 --- a/src/ShellClients/PanelWindow.vala +++ b/src/ShellClients/PanelWindow.vala @@ -15,7 +15,6 @@ public class Gala.PanelWindow : Object { public Meta.Side anchor; - public DelegateActor delegate_actor; private PanelClone clone; private uint idle_move_id = 0; @@ -46,7 +45,6 @@ public class Gala.PanelWindow : Object { window.stick (); - delegate_actor = new DelegateActor ((Meta.WindowActor) window.get_compositor_private ()); clone = new PanelClone (wm, this); var monitor_manager = wm.get_display ().get_context ().get_backend ().get_monitor_manager (); @@ -64,8 +62,6 @@ public class Gala.PanelWindow : Object { public Meta.Rectangle get_custom_window_rect () { #endif var window_rect = window.get_frame_rect (); - window_rect.x = delegate_actor.actual_x; - window_rect.y = delegate_actor.actual_y; if (width > 0) { window_rect.width = width; diff --git a/src/meson.build b/src/meson.build index d8fa147a..7e6488fd 100644 --- a/src/meson.build +++ b/src/meson.build @@ -41,7 +41,6 @@ gala_bin_sources = files( 'HotCorners/Barrier.vala', 'HotCorners/HotCorner.vala', 'HotCorners/HotCornerManager.vala', - 'ShellClients/DelegateActor.vala', 'ShellClients/HideTracker.vala', 'ShellClients/ManagedClient.vala', 'ShellClients/NotificationsClient.vala', diff --git a/vapi/xfixes-4.0.vapi b/vapi/xfixes-4.0.vapi index 3cbcfc76..acd84e05 100644 --- a/vapi/xfixes-4.0.vapi +++ b/vapi/xfixes-4.0.vapi @@ -6,8 +6,12 @@ namespace X { namespace Fixes { [CCode (cheader_filename = "X11/extensions/Xfixes.h", cname = "XFixesCreateRegion")] public static X.XserverRegion create_region (X.Display display, [CCode (array_length = true)] X.Xrectangle[] rectangles); + [CCode (cheader_filename = "X11/extensions/Xfixes.h", cname = "XFixesCreateRegionFromWindow")] + public static X.XserverRegion create_region_from_window (X.Display display, X.Window window, int shape_kind); [CCode (cheader_filename = "X11/extensions/Xfixes.h", cname = "XFixesDestroyRegion")] public static void destroy_region (X.Display display, X.XserverRegion region); + [CCode (cheader_filename = "X11/extensions/Xfixes.h", cname = "XFixesSetWindowShapeRegion")] + public static void set_window_shape_region (X.Display display, X.Window win, int shape_kind, int x_off, int y_off, XserverRegion region); } [SimpleType] [CCode (cheader_filename = "X11/extensions/Xfixes.h", cname = "XserverRegion", has_type_id = false)]