From d8f24608c58c324deb81a9193c7f2765b9f06052 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Tue, 16 Jul 2024 21:17:22 -0700 Subject: [PATCH 01/23] umu_run: monitor baselayer and windows in separate threads --- umu/umu_run.py | 109 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 88 insertions(+), 21 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index f690c6a02..a4209e354 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -581,21 +581,57 @@ def window_setup(gamescope_baselayer_sequence: list[int]) -> None: # noqa set_gamescope_baselayer_order(rearranged_sequence) -def monitor_layers( # noqa - gamescope_baselayer_sequence: list[int], window_client_list: list[str] +def monitor_baselayer( + d_secondary: display.Display, gamescope_baselayer_sequence: list[int] ) -> None: + """Monitor for broken gamescope baselayer sequences.""" + root: Window = d_secondary.screen().root + atom = d_secondary.get_atom("GAMESCOPECTRL_BASELAYER_APPID") + root.change_attributes(event_mask=X.PropertyChangeMask) + + log.debug("Monitoring base layers") + while True: - # Check if the window sequence has changed: - current_window_list = get_window_client_ids() - if current_window_list != window_client_list: - window_setup(gamescope_baselayer_sequence) + event: AnyEvent = d_secondary.next_event() + + # Check if the layer sequence has changed to the broken one + if event.type == X.PropertyNotify and event.atom == atom: + prop = root.get_full_property(atom, Xatom.CARDINAL) + + log.debug("Property value for atom '%s': %s", atom, prop.value) + if prop.value == gamescope_baselayer_sequence: + log.debug("Broken base layer sequence detected") + log.debug("Rearranging base layer sequence") + rearranged = [ + prop.value[0], + prop.value[3], + prop.value[1], + prop.value[2], + ] + log.debug("'%s' -> '%s'", prop.value, rearranged) + set_gamescope_baselayer_order(d_secondary, rearranged) + + time.sleep(0.1) + + +def monitor_windows( + d_primary: display.Display, + gamescope_baselayer_sequence: list[int], + window_client_list: list[str], +) -> None: + """Monitor for new windows and assign them Steam's layer ID.""" + steam_assigned_layer_id: int = gamescope_baselayer_sequence[-1] - # Check if the layer sequence has changed - current_sequence = get_gamescope_baselayer_order() - if current_sequence == gamescope_baselayer_sequence: - window_setup(gamescope_baselayer_sequence) + log.debug("Monitoring windows") - time.sleep(5) # Check every 5 seconds + while True: + # Check if the window sequence has changed + current_window_list = get_window_client_ids(d_primary) + if current_window_list != window_client_list: + log.debug("New window sequence detected") + set_steam_game_property( + d_primary, current_window_list, steam_assigned_layer_id + ) def run_command(command: list[AnyPath]) -> int: @@ -605,6 +641,8 @@ def run_command(command: list[AnyPath]) -> int: proc: Popen ret: int = 0 libc: str = get_libc() + d_primary: display.Display | None = None + d_secondary: display.Display | None = None gamescope_baselayer_sequence: list[int] | None = None if not command: @@ -641,23 +679,52 @@ def run_command(command: list[AnyPath]) -> int: ) if os.environ.get("XDG_CURRENT_DESKTOP") == "gamescope": - gamescope_baselayer_sequence = get_gamescope_baselayer_order() + d_secondary = display.Display(":0") + gamescope_baselayer_sequence = get_gamescope_baselayer_order( + d_secondary + ) # Dont do window fuckery if we're not inside gamescope if gamescope_baselayer_sequence and not os.environ.get("EXE", "").endswith( "winetricks" ): - window_client_list = get_window_client_ids() - window_setup(gamescope_baselayer_sequence) - monitor_thread = threading.Thread( - target=monitor_layers, - args=(gamescope_baselayer_sequence, window_client_list), + d_primary = display.Display(":1") + window_client_list: list[str] = [] + + while not window_client_list: + window_client_list = get_window_client_ids(d_primary) + + window_setup(d_primary, d_secondary, gamescope_baselayer_sequence) + + # Monitor the windows + window_thread = threading.Thread( + target=monitor_windows, + args=(d_primary, gamescope_baselayer_sequence, window_client_list), ) - monitor_thread.daemon = True - monitor_thread.start() + window_thread.daemon = True + window_thread.start() + + # Monitor the baselayer + baselayer_thread = threading.Thread( + target=monitor_baselayer, + args=( + d_secondary, + gamescope_baselayer_sequence, + ), + ) + baselayer_thread.daemon = True + baselayer_thread.start() - ret = proc.wait() - log.debug("Child %s exited with wait status: %s", proc.pid, ret) + try: + ret = proc.wait() + log.debug("Child %s exited with wait status: %s", proc.pid, ret) + except KeyboardInterrupt as e: + raise e + finally: + if d_primary: + d_primary.close() + if d_secondary: + d_secondary.close() return ret From c5169eba6c0b6eaeffc67a13edcda25ba1e54459 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Tue, 16 Jul 2024 21:17:44 -0700 Subject: [PATCH 02/23] umu_run: refactor get_client_window_ids --- umu/umu_run.py | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index a4209e354..c21128d09 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -27,7 +27,9 @@ ): sys.path.append(os.environ["UMU_CLIENT_RTPATH"]) -from Xlib import Xatom, display +from Xlib import X, Xatom, display +from Xlib.protocol.event import AnyEvent +from Xlib.xobject.drawable import Window from umu.umu_consts import ( DEBUG_FORMAT, @@ -439,34 +441,22 @@ def build_command( return command -def get_window_client_ids() -> list[str]: +def get_window_client_ids(d: display.Display) -> list[str]: """Get the list of client windows.""" - d = display.Display(":1") try: - root = d.screen().root + root: Window = d.screen().root + root.change_attributes(event_mask=X.SubstructureNotifyMask) - max_wait_time = 30 # Maximum wait time in seconds - wait_interval = 1 # Interval between checks in seconds - elapsed_time = 0 - window_ids: list[str] = [] - - while elapsed_time < max_wait_time: - children = root.query_tree().children - if children and len(children) > 1: - for child in children: - log.debug("Window ID: %s", child.id) - log.debug("Window Name: %s", child.get_wm_name()) - log.debug("Window Class: %s", child.get_wm_class()) - log.debug("Window Geometry: %s", child.get_geometry()) - log.debug("Window Attributes: %s", child.get_attributes()) - # if "steam_app" in str(child.get_wm_class()): - window_ids.append(child.id) - return window_ids - time.sleep(wait_interval) - elapsed_time += wait_interval - return [] - finally: - d.close() + log.debug("Waiting for new child windows") + event: AnyEvent = d.next_event() + + if event.type == X.CreateNotify: + log.debug("Found new child windows") + return [child.id for child in root.query_tree().children] + except Exception as e: + log.exception(e) + + return [] def set_steam_game_property( # noqa: D103 From 0926ceab818b28013cfde89e673fbb2bea23fa15 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Tue, 16 Jul 2024 21:18:06 -0700 Subject: [PATCH 03/23] umu_run: refactor set_steam_game_property --- umu/umu_run.py | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index c21128d09..4e5182e3f 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -460,26 +460,21 @@ def get_window_client_ids(d: display.Display) -> list[str]: def set_steam_game_property( # noqa: D103 - window_ids: list[str], steam_assigned_layer_id: int + d: display.Display, window_ids: list[str], steam_assigned_layer_id: int ) -> None: - d = display.Display(":1") try: - root = d.screen().root - log.debug("Root: %s", root) - + log.debug("steam_layer: %s", steam_assigned_layer_id) for window_id in window_ids: log.debug("window_id: %s", window_id) - log.debug("steam_layer: %s", steam_assigned_layer_id) try: - window = d.create_resource_object("window", int(window_id)) - window.get_full_property( - d.intern_atom("STEAM_GAME"), Xatom.CARDINAL + window: Window = d.create_resource_object( + "window", int(window_id) ) window.change_property( - d.intern_atom("STEAM_GAME"), + d.get_atom("STEAM_GAME"), Xatom.CARDINAL, 32, - [int(steam_assigned_layer_id)], + [steam_assigned_layer_id], ) log.debug( "Successfully set STEAM_GAME property for window ID: %s", @@ -493,8 +488,6 @@ def set_steam_game_property( # noqa: D103 log.exception(e) except Exception as e: log.exception(e) - finally: - d.close() def get_gamescope_baselayer_order() -> list[int] | None: # noqa: D103 From 03955a39067efa4206fe6e442e866e1b19dad6e2 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Tue, 16 Jul 2024 21:18:23 -0700 Subject: [PATCH 04/23] umu_run: refactor get_gamescope_baselayer_order --- umu/umu_run.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index 4e5182e3f..d1fdbff8c 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -490,13 +490,12 @@ def set_steam_game_property( # noqa: D103 log.exception(e) -def get_gamescope_baselayer_order() -> list[int] | None: # noqa: D103 - d = display.Display(":0") +def get_gamescope_baselayer_order(d: display.Display) -> list[int] | None: # noqa: D103 try: - root = d.screen().root + root: Window = d.screen().root # Intern the atom for GAMESCOPECTRL_BASELAYER_APPID - atom = d.intern_atom("GAMESCOPECTRL_BASELAYER_APPID") + atom = d.get_atom("GAMESCOPECTRL_BASELAYER_APPID") # Get the property value prop = root.get_full_property(atom, Xatom.CARDINAL) @@ -508,8 +507,6 @@ def get_gamescope_baselayer_order() -> list[int] | None: # noqa: D103 except Exception as e: log.error("Error getting GAMESCOPECTRL_BASELAYER_APPID property") log.exception(e) - finally: - d.close() return None @@ -524,6 +521,8 @@ def rearrange_gamescope_baselayer_order( # noqa # Rearrange the sequence rearranged = [sequence[0], sequence[3], sequence[1], sequence[2]] + log.debug("Rearranging base layer sequence") + log.debug("'%s' -> '%s'", sequence, rearranged) # Return the rearranged sequence and the second element return rearranged, rearranged[1] From ca82a43a56534f929c82034b981a1cc252b59558 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Tue, 16 Jul 2024 21:18:41 -0700 Subject: [PATCH 05/23] umu_run: refactor set_gamescope_baselayer_order --- umu/umu_run.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index d1fdbff8c..3440abec2 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -528,13 +528,14 @@ def rearrange_gamescope_baselayer_order( # noqa return rearranged, rearranged[1] -def set_gamescope_baselayer_order(rearranged: list[int]) -> None: # noqa +def set_gamescope_baselayer_order( # noqa + d: display.Display, rearranged: list[int] +) -> None: try: - d = display.Display(":0") - root = d.screen().root + root: Window = d.screen().root # Intern the atom for GAMESCOPECTRL_BASELAYER_APPID - atom = d.intern_atom("GAMESCOPECTRL_BASELAYER_APPID") + atom = d.get_atom("GAMESCOPECTRL_BASELAYER_APPID") # Set the property value root.change_property(atom, Xatom.CARDINAL, 32, rearranged) @@ -545,8 +546,6 @@ def set_gamescope_baselayer_order(rearranged: list[int]) -> None: # noqa except Exception as e: log.error("Error setting GAMESCOPECTRL_BASELAYER_APPID property") log.exception(e) - finally: - d.close() def window_setup(gamescope_baselayer_sequence: list[int]) -> None: # noqa From b10222c6c62d344581458df0c41320dbc1b3d81f Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Tue, 16 Jul 2024 21:19:12 -0700 Subject: [PATCH 06/23] umu_run: refactor window_setup --- umu/umu_run.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index 3440abec2..9f0791c3b 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -548,18 +548,27 @@ def set_gamescope_baselayer_order( # noqa log.exception(e) -def window_setup(gamescope_baselayer_sequence: list[int]) -> None: # noqa +def window_setup( # noqa + d_primary: display.Display, + d_secondary: display.Display, + gamescope_baselayer_sequence: list[int], +) -> None: + game_window_ids: list[str] = [] + if gamescope_baselayer_sequence: # Rearrange the sequence rearranged_sequence, steam_assigned_layer_id = ( rearrange_gamescope_baselayer_order(gamescope_baselayer_sequence) ) + # Assign our window a STEAM_GAME id - game_window_ids = get_window_client_ids() - if game_window_ids: - set_steam_game_property(game_window_ids, steam_assigned_layer_id) + while not game_window_ids: + game_window_ids = get_window_client_ids(d_primary) - set_gamescope_baselayer_order(rearranged_sequence) + set_steam_game_property( + d_primary, game_window_ids, steam_assigned_layer_id + ) + set_gamescope_baselayer_order(d_secondary, rearranged_sequence) def monitor_baselayer( From c696f73d9854511413fc617acea1f9f53b12ca29 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 08:43:21 -0700 Subject: [PATCH 07/23] umu_run: change identifiers for displays - In the Steam Deck, DISPLAY=:0 is where the primary xwayland server is and not DISPLAY=:1 --- umu/umu_run.py | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index 9f0791c3b..33207049f 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -563,26 +563,26 @@ def window_setup( # noqa # Assign our window a STEAM_GAME id while not game_window_ids: - game_window_ids = get_window_client_ids(d_primary) + game_window_ids = get_window_client_ids(d_secondary) set_steam_game_property( - d_primary, game_window_ids, steam_assigned_layer_id + d_secondary, game_window_ids, steam_assigned_layer_id ) - set_gamescope_baselayer_order(d_secondary, rearranged_sequence) + set_gamescope_baselayer_order(d_primary, rearranged_sequence) def monitor_baselayer( - d_secondary: display.Display, gamescope_baselayer_sequence: list[int] + d_primary: display.Display, gamescope_baselayer_sequence: list[int] ) -> None: """Monitor for broken gamescope baselayer sequences.""" - root: Window = d_secondary.screen().root - atom = d_secondary.get_atom("GAMESCOPECTRL_BASELAYER_APPID") + root: Window = d_primary.screen().root + atom = d_primary.get_atom("GAMESCOPECTRL_BASELAYER_APPID") root.change_attributes(event_mask=X.PropertyChangeMask) log.debug("Monitoring base layers") while True: - event: AnyEvent = d_secondary.next_event() + event: AnyEvent = d_primary.next_event() # Check if the layer sequence has changed to the broken one if event.type == X.PropertyNotify and event.atom == atom: @@ -599,13 +599,13 @@ def monitor_baselayer( prop.value[2], ] log.debug("'%s' -> '%s'", prop.value, rearranged) - set_gamescope_baselayer_order(d_secondary, rearranged) + set_gamescope_baselayer_order(d_primary, rearranged) time.sleep(0.1) def monitor_windows( - d_primary: display.Display, + d_secondary: display.Display, gamescope_baselayer_sequence: list[int], window_client_list: list[str], ) -> None: @@ -616,11 +616,11 @@ def monitor_windows( while True: # Check if the window sequence has changed - current_window_list = get_window_client_ids(d_primary) + current_window_list = get_window_client_ids(d_secondary) if current_window_list != window_client_list: log.debug("New window sequence detected") set_steam_game_property( - d_primary, current_window_list, steam_assigned_layer_id + d_secondary, current_window_list, steam_assigned_layer_id ) @@ -669,27 +669,30 @@ def run_command(command: list[AnyPath]) -> int: ) if os.environ.get("XDG_CURRENT_DESKTOP") == "gamescope": - d_secondary = display.Display(":0") - gamescope_baselayer_sequence = get_gamescope_baselayer_order( - d_secondary - ) + # Primary xwayland server on the Steam Deck + d_primary = display.Display(":0") + gamescope_baselayer_sequence = get_gamescope_baselayer_order(d_primary) # Dont do window fuckery if we're not inside gamescope if gamescope_baselayer_sequence and not os.environ.get("EXE", "").endswith( "winetricks" ): - d_primary = display.Display(":1") + d_secondary = display.Display(":1") window_client_list: list[str] = [] while not window_client_list: - window_client_list = get_window_client_ids(d_primary) + window_client_list = get_window_client_ids(d_secondary) window_setup(d_primary, d_secondary, gamescope_baselayer_sequence) # Monitor the windows window_thread = threading.Thread( target=monitor_windows, - args=(d_primary, gamescope_baselayer_sequence, window_client_list), + args=( + d_secondary, + gamescope_baselayer_sequence, + window_client_list, + ), ) window_thread.daemon = True window_thread.start() @@ -698,7 +701,7 @@ def run_command(command: list[AnyPath]) -> int: baselayer_thread = threading.Thread( target=monitor_baselayer, args=( - d_secondary, + d_primary, gamescope_baselayer_sequence, ), ) From fd1266e9e255b9f4d50ab2bcc96b8c9707652c17 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 09:06:23 -0700 Subject: [PATCH 08/23] umu_run: add debug statement --- umu/umu_run.py | 1 + 1 file changed, 1 insertion(+) diff --git a/umu/umu_run.py b/umu/umu_run.py index 33207049f..3f0b16bc1 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -617,6 +617,7 @@ def monitor_windows( while True: # Check if the window sequence has changed current_window_list = get_window_client_ids(d_secondary) + log.debug("Current windows: %s", current_window_list) if current_window_list != window_client_list: log.debug("New window sequence detected") set_steam_game_property( From 193579f2eced11923a88d25016d45e9623c9ca62 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 09:34:46 -0700 Subject: [PATCH 09/23] umu_run: pass reference to each display's root window --- umu/umu_run.py | 58 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index 3f0b16bc1..ad3796c3f 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -441,12 +441,9 @@ def build_command( return command -def get_window_client_ids(d: display.Display) -> list[str]: +def get_window_client_ids(d: display.Display, root: Window) -> list[str]: """Get the list of client windows.""" try: - root: Window = d.screen().root - root.change_attributes(event_mask=X.SubstructureNotifyMask) - log.debug("Waiting for new child windows") event: AnyEvent = d.next_event() @@ -529,16 +526,14 @@ def rearrange_gamescope_baselayer_order( # noqa def set_gamescope_baselayer_order( # noqa - d: display.Display, rearranged: list[int] + d: display.Display, root_primary: Window, rearranged: list[int] ) -> None: try: - root: Window = d.screen().root - # Intern the atom for GAMESCOPECTRL_BASELAYER_APPID atom = d.get_atom("GAMESCOPECTRL_BASELAYER_APPID") # Set the property value - root.change_property(atom, Xatom.CARDINAL, 32, rearranged) + root_primary.change_property(atom, Xatom.CARDINAL, 32, rearranged) log.debug( "Successfully set GAMESCOPECTRL_BASELAYER_APPID property: %s", ", ".join(map(str, rearranged)), @@ -551,6 +546,8 @@ def set_gamescope_baselayer_order( # noqa def window_setup( # noqa d_primary: display.Display, d_secondary: display.Display, + root_primary: Window, + root_secondary: Window, gamescope_baselayer_sequence: list[int], ) -> None: game_window_ids: list[str] = [] @@ -563,21 +560,26 @@ def window_setup( # noqa # Assign our window a STEAM_GAME id while not game_window_ids: - game_window_ids = get_window_client_ids(d_secondary) + game_window_ids = get_window_client_ids( + d_secondary, root_secondary + ) set_steam_game_property( d_secondary, game_window_ids, steam_assigned_layer_id ) - set_gamescope_baselayer_order(d_primary, rearranged_sequence) + set_gamescope_baselayer_order( + d_primary, root_primary, rearranged_sequence + ) def monitor_baselayer( - d_primary: display.Display, gamescope_baselayer_sequence: list[int] + d_primary: display.Display, + root_primary: Window, + gamescope_baselayer_sequence: list[int], ) -> None: """Monitor for broken gamescope baselayer sequences.""" - root: Window = d_primary.screen().root atom = d_primary.get_atom("GAMESCOPECTRL_BASELAYER_APPID") - root.change_attributes(event_mask=X.PropertyChangeMask) + root_primary.change_attributes(event_mask=X.PropertyChangeMask) log.debug("Monitoring base layers") @@ -586,7 +588,7 @@ def monitor_baselayer( # Check if the layer sequence has changed to the broken one if event.type == X.PropertyNotify and event.atom == atom: - prop = root.get_full_property(atom, Xatom.CARDINAL) + prop = root_primary.get_full_property(atom, Xatom.CARDINAL) log.debug("Property value for atom '%s': %s", atom, prop.value) if prop.value == gamescope_baselayer_sequence: @@ -599,13 +601,16 @@ def monitor_baselayer( prop.value[2], ] log.debug("'%s' -> '%s'", prop.value, rearranged) - set_gamescope_baselayer_order(d_primary, rearranged) + set_gamescope_baselayer_order( + d_primary, root_primary, rearranged + ) time.sleep(0.1) def monitor_windows( d_secondary: display.Display, + root_secondary: Window, gamescope_baselayer_sequence: list[int], window_client_list: list[str], ) -> None: @@ -616,7 +621,9 @@ def monitor_windows( while True: # Check if the window sequence has changed - current_window_list = get_window_client_ids(d_secondary) + current_window_list = get_window_client_ids( + d_secondary, root_secondary + ) log.debug("Current windows: %s", current_window_list) if current_window_list != window_client_list: log.debug("New window sequence detected") @@ -672,6 +679,8 @@ def run_command(command: list[AnyPath]) -> int: if os.environ.get("XDG_CURRENT_DESKTOP") == "gamescope": # Primary xwayland server on the Steam Deck d_primary = display.Display(":0") + # Root window of the primary xwayland server + root_primary: Window = d_primary.screen().root gamescope_baselayer_sequence = get_gamescope_baselayer_order(d_primary) # Dont do window fuckery if we're not inside gamescope @@ -680,17 +689,29 @@ def run_command(command: list[AnyPath]) -> int: ): d_secondary = display.Display(":1") window_client_list: list[str] = [] + root_secondary: Window = d_secondary.screen().root + root_secondary.change_attributes(event_mask=X.SubstructureNotifyMask) while not window_client_list: - window_client_list = get_window_client_ids(d_secondary) + window_client_list = get_window_client_ids( + d_secondary, root_secondary + ) - window_setup(d_primary, d_secondary, gamescope_baselayer_sequence) + # Setup the windows and pass the displays with their root windows + window_setup( + d_primary, + d_secondary, + root_primary, + root_secondary, + gamescope_baselayer_sequence, + ) # Monitor the windows window_thread = threading.Thread( target=monitor_windows, args=( d_secondary, + root_secondary, gamescope_baselayer_sequence, window_client_list, ), @@ -703,6 +724,7 @@ def run_command(command: list[AnyPath]) -> int: target=monitor_baselayer, args=( d_primary, + root_primary, gamescope_baselayer_sequence, ), ) From aa64ae1d29919cfb0cfde212ccf7c57a9066d157 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 09:52:49 -0700 Subject: [PATCH 10/23] umu_run: ignore empty windows --- umu/umu_run.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index ad3796c3f..23b8f0400 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -624,6 +624,10 @@ def monitor_windows( current_window_list = get_window_client_ids( d_secondary, root_secondary ) + + if not current_window_list: + continue + log.debug("Current windows: %s", current_window_list) if current_window_list != window_client_list: log.debug("New window sequence detected") @@ -688,8 +692,9 @@ def run_command(command: list[AnyPath]) -> int: "winetricks" ): d_secondary = display.Display(":1") - window_client_list: list[str] = [] root_secondary: Window = d_secondary.screen().root + window_client_list: list[str] = [] + root_secondary.change_attributes(event_mask=X.SubstructureNotifyMask) while not window_client_list: From f12d4bb0607bae27d8979229746730bc84cb4198 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 10:28:42 -0700 Subject: [PATCH 11/23] umu_run: update format --- umu/umu_run.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index 23b8f0400..3d23a1654 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -646,6 +646,10 @@ def run_command(command: list[AnyPath]) -> int: d_primary: display.Display | None = None d_secondary: display.Display | None = None gamescope_baselayer_sequence: list[int] | None = None + # Root window of the primary xwayland server + root_primary: Window + # Root window of the client application + root_secondary: Window if not command: err: str = f"Command list is empty or None: {command}" @@ -683,8 +687,7 @@ def run_command(command: list[AnyPath]) -> int: if os.environ.get("XDG_CURRENT_DESKTOP") == "gamescope": # Primary xwayland server on the Steam Deck d_primary = display.Display(":0") - # Root window of the primary xwayland server - root_primary: Window = d_primary.screen().root + root_primary = d_primary.screen().root gamescope_baselayer_sequence = get_gamescope_baselayer_order(d_primary) # Dont do window fuckery if we're not inside gamescope @@ -692,7 +695,7 @@ def run_command(command: list[AnyPath]) -> int: "winetricks" ): d_secondary = display.Display(":1") - root_secondary: Window = d_secondary.screen().root + root_secondary = d_secondary.screen().root window_client_list: list[str] = [] root_secondary.change_attributes(event_mask=X.SubstructureNotifyMask) From 4326cd688dc5cbcb017853a7ae39c7e07967f44e Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 10:28:55 -0700 Subject: [PATCH 12/23] umu_run: update comments --- umu/umu_run.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index 3d23a1654..3c67d476a 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -442,7 +442,7 @@ def build_command( def get_window_client_ids(d: display.Display, root: Window) -> list[str]: - """Get the list of client windows.""" + """Get the list of new client windows under the root window.""" try: log.debug("Waiting for new child windows") event: AnyEvent = d.next_event() @@ -643,8 +643,11 @@ def run_command(command: list[AnyPath]) -> int: proc: Popen ret: int = 0 libc: str = get_libc() + # Primary display of the focusable app under the gamescope session d_primary: display.Display | None = None + # Display of the client application under the gamescope session d_secondary: display.Display | None = None + # GAMESCOPECTRL_BASELAYER_APPID value on the primary's window gamescope_baselayer_sequence: list[int] | None = None # Root window of the primary xwayland server root_primary: Window @@ -685,7 +688,7 @@ def run_command(command: list[AnyPath]) -> int: ) if os.environ.get("XDG_CURRENT_DESKTOP") == "gamescope": - # Primary xwayland server on the Steam Deck + # :0 is where the primary xwayland server is on the Steam Deck d_primary = display.Display(":0") root_primary = d_primary.screen().root gamescope_baselayer_sequence = get_gamescope_baselayer_order(d_primary) @@ -700,12 +703,13 @@ def run_command(command: list[AnyPath]) -> int: root_secondary.change_attributes(event_mask=X.SubstructureNotifyMask) + # Get new windows under the client display's window while not window_client_list: window_client_list = get_window_client_ids( d_secondary, root_secondary ) - # Setup the windows and pass the displays with their root windows + # Setup the windows window_setup( d_primary, d_secondary, From f5d5f96c84d59a3fc5c2f2ddc71b11e48d75d9c3 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 10:36:43 -0700 Subject: [PATCH 13/23] umu_run: remove debug statement --- umu/umu_run.py | 1 - 1 file changed, 1 deletion(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index 3c67d476a..6a281f6b4 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -628,7 +628,6 @@ def monitor_windows( if not current_window_list: continue - log.debug("Current windows: %s", current_window_list) if current_window_list != window_client_list: log.debug("New window sequence detected") set_steam_game_property( From e3bf34bf8f8a6f5d80581fefb4f8d8dc4a31483b Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 10:38:15 -0700 Subject: [PATCH 14/23] umu_run: don't raise with the exception --- umu/umu_run.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index 6a281f6b4..0eaa1d3aa 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -745,8 +745,8 @@ def run_command(command: list[AnyPath]) -> int: try: ret = proc.wait() log.debug("Child %s exited with wait status: %s", proc.pid, ret) - except KeyboardInterrupt as e: - raise e + except KeyboardInterrupt: + raise finally: if d_primary: d_primary.close() From 4833dce9ca056edb216ac56b263d9b55fe7e42fd Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:26:43 -0700 Subject: [PATCH 15/23] umu_run: pass the game window ids --- umu/umu_run.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index 0eaa1d3aa..b1baf9268 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -547,11 +547,9 @@ def window_setup( # noqa d_primary: display.Display, d_secondary: display.Display, root_primary: Window, - root_secondary: Window, gamescope_baselayer_sequence: list[int], + game_window_ids: list[str], ) -> None: - game_window_ids: list[str] = [] - if gamescope_baselayer_sequence: # Rearrange the sequence rearranged_sequence, steam_assigned_layer_id = ( @@ -559,14 +557,10 @@ def window_setup( # noqa ) # Assign our window a STEAM_GAME id - while not game_window_ids: - game_window_ids = get_window_client_ids( - d_secondary, root_secondary - ) - set_steam_game_property( d_secondary, game_window_ids, steam_assigned_layer_id ) + set_gamescope_baselayer_order( d_primary, root_primary, rearranged_sequence ) @@ -713,8 +707,8 @@ def run_command(command: list[AnyPath]) -> int: d_primary, d_secondary, root_primary, - root_secondary, gamescope_baselayer_sequence, + window_client_list, ) # Monitor the windows From 9fc87ea68a24ae9b190866acc58b0f7750d18a18 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 22:06:29 -0700 Subject: [PATCH 16/23] umu_run: update comments --- umu/umu_run.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index b1baf9268..177e37a74 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -642,9 +642,9 @@ def run_command(command: list[AnyPath]) -> int: d_secondary: display.Display | None = None # GAMESCOPECTRL_BASELAYER_APPID value on the primary's window gamescope_baselayer_sequence: list[int] | None = None - # Root window of the primary xwayland server + # Root window of the primary display root_primary: Window - # Root window of the client application + # Root window of the client application's display root_secondary: Window if not command: @@ -711,7 +711,7 @@ def run_command(command: list[AnyPath]) -> int: window_client_list, ) - # Monitor the windows + # Monitor for new windows window_thread = threading.Thread( target=monitor_windows, args=( @@ -724,7 +724,7 @@ def run_command(command: list[AnyPath]) -> int: window_thread.daemon = True window_thread.start() - # Monitor the baselayer + # Monitor for broken baselayers baselayer_thread = threading.Thread( target=monitor_baselayer, args=( From b8b226e2550011f4da9d586fc3474d90bdbfadec Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 22:06:46 -0700 Subject: [PATCH 17/23] umu_run: update debug statements --- umu/umu_run.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index 177e37a74..e1ca19013 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -623,7 +623,7 @@ def monitor_windows( continue if current_window_list != window_client_list: - log.debug("New window sequence detected") + log.debug("New windows detected") set_steam_game_property( d_secondary, current_window_list, steam_assigned_layer_id ) From a7080565a7644df641f782535976e982ee01ffd9 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 22:07:21 -0700 Subject: [PATCH 18/23] umu_run: continue when empty windows are returned --- umu/umu_run.py | 1 + 1 file changed, 1 insertion(+) diff --git a/umu/umu_run.py b/umu/umu_run.py index e1ca19013..57d293b07 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -598,6 +598,7 @@ def monitor_baselayer( set_gamescope_baselayer_order( d_primary, root_primary, rearranged ) + continue time.sleep(0.1) From 365146dcb2f1fc96f771e4ac95a85bbd29b26148 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 22:46:48 -0700 Subject: [PATCH 19/23] umu_run: don't pass root windows --- umu/umu_run.py | 43 +++++++++++-------------------------------- 1 file changed, 11 insertions(+), 32 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index 57d293b07..1bcc15d3f 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -441,7 +441,7 @@ def build_command( return command -def get_window_client_ids(d: display.Display, root: Window) -> list[str]: +def get_window_client_ids(d: display.Display) -> list[str]: """Get the list of new client windows under the root window.""" try: log.debug("Waiting for new child windows") @@ -526,7 +526,7 @@ def rearrange_gamescope_baselayer_order( # noqa def set_gamescope_baselayer_order( # noqa - d: display.Display, root_primary: Window, rearranged: list[int] + d: display.Display, rearranged: list[int] ) -> None: try: # Intern the atom for GAMESCOPECTRL_BASELAYER_APPID @@ -546,7 +546,6 @@ def set_gamescope_baselayer_order( # noqa def window_setup( # noqa d_primary: display.Display, d_secondary: display.Display, - root_primary: Window, gamescope_baselayer_sequence: list[int], game_window_ids: list[str], ) -> None: @@ -561,17 +560,15 @@ def window_setup( # noqa d_secondary, game_window_ids, steam_assigned_layer_id ) - set_gamescope_baselayer_order( - d_primary, root_primary, rearranged_sequence - ) + set_gamescope_baselayer_order(d_primary, rearranged_sequence) def monitor_baselayer( d_primary: display.Display, - root_primary: Window, gamescope_baselayer_sequence: list[int], ) -> None: """Monitor for broken gamescope baselayer sequences.""" + root_primary: Window = d_primary.screen().root atom = d_primary.get_atom("GAMESCOPECTRL_BASELAYER_APPID") root_primary.change_attributes(event_mask=X.PropertyChangeMask) @@ -595,9 +592,7 @@ def monitor_baselayer( prop.value[2], ] log.debug("'%s' -> '%s'", prop.value, rearranged) - set_gamescope_baselayer_order( - d_primary, root_primary, rearranged - ) + set_gamescope_baselayer_order(d_primary, rearranged) continue time.sleep(0.1) @@ -605,7 +600,6 @@ def monitor_baselayer( def monitor_windows( d_secondary: display.Display, - root_secondary: Window, gamescope_baselayer_sequence: list[int], window_client_list: list[str], ) -> None: @@ -616,9 +610,7 @@ def monitor_windows( while True: # Check if the window sequence has changed - current_window_list = get_window_client_ids( - d_secondary, root_secondary - ) + current_window_list = get_window_client_ids(d_secondary) if not current_window_list: continue @@ -643,10 +635,6 @@ def run_command(command: list[AnyPath]) -> int: d_secondary: display.Display | None = None # GAMESCOPECTRL_BASELAYER_APPID value on the primary's window gamescope_baselayer_sequence: list[int] | None = None - # Root window of the primary display - root_primary: Window - # Root window of the client application's display - root_secondary: Window if not command: err: str = f"Command list is empty or None: {command}" @@ -684,7 +672,6 @@ def run_command(command: list[AnyPath]) -> int: if os.environ.get("XDG_CURRENT_DESKTOP") == "gamescope": # :0 is where the primary xwayland server is on the Steam Deck d_primary = display.Display(":0") - root_primary = d_primary.screen().root gamescope_baselayer_sequence = get_gamescope_baselayer_order(d_primary) # Dont do window fuckery if we're not inside gamescope @@ -692,22 +679,19 @@ def run_command(command: list[AnyPath]) -> int: "winetricks" ): d_secondary = display.Display(":1") - root_secondary = d_secondary.screen().root + d_secondary.screen().root.change_attributes( + event_mask=X.SubstructureNotifyMask + ) window_client_list: list[str] = [] - root_secondary.change_attributes(event_mask=X.SubstructureNotifyMask) - # Get new windows under the client display's window while not window_client_list: - window_client_list = get_window_client_ids( - d_secondary, root_secondary - ) + window_client_list = get_window_client_ids(d_secondary) # Setup the windows window_setup( d_primary, d_secondary, - root_primary, gamescope_baselayer_sequence, window_client_list, ) @@ -717,7 +701,6 @@ def run_command(command: list[AnyPath]) -> int: target=monitor_windows, args=( d_secondary, - root_secondary, gamescope_baselayer_sequence, window_client_list, ), @@ -728,11 +711,7 @@ def run_command(command: list[AnyPath]) -> int: # Monitor for broken baselayers baselayer_thread = threading.Thread( target=monitor_baselayer, - args=( - d_primary, - root_primary, - gamescope_baselayer_sequence, - ), + args=(d_primary, gamescope_baselayer_sequence), ) baselayer_thread.daemon = True baselayer_thread.start() From 06e0468231f38972e2d78e0bc9e710b979e2a26e Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 22:47:42 -0700 Subject: [PATCH 20/23] umu_run: access the root window from the display --- umu/umu_run.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index 1bcc15d3f..dc250b14d 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -449,7 +449,9 @@ def get_window_client_ids(d: display.Display) -> list[str]: if event.type == X.CreateNotify: log.debug("Found new child windows") - return [child.id for child in root.query_tree().children] + return [ + child.id for child in d.screen().root.query_tree().children + ] except Exception as e: log.exception(e) @@ -489,13 +491,11 @@ def set_steam_game_property( # noqa: D103 def get_gamescope_baselayer_order(d: display.Display) -> list[int] | None: # noqa: D103 try: - root: Window = d.screen().root - # Intern the atom for GAMESCOPECTRL_BASELAYER_APPID atom = d.get_atom("GAMESCOPECTRL_BASELAYER_APPID") # Get the property value - prop = root.get_full_property(atom, Xatom.CARDINAL) + prop = d.screen().root.get_full_property(atom, Xatom.CARDINAL) if prop: # Extract and return the value @@ -533,7 +533,7 @@ def set_gamescope_baselayer_order( # noqa atom = d.get_atom("GAMESCOPECTRL_BASELAYER_APPID") # Set the property value - root_primary.change_property(atom, Xatom.CARDINAL, 32, rearranged) + d.screen().root.change_property(atom, Xatom.CARDINAL, 32, rearranged) log.debug( "Successfully set GAMESCOPECTRL_BASELAYER_APPID property: %s", ", ".join(map(str, rearranged)), From 0b730c880096042d67bf06d40adb8b7323471942 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 22:48:00 -0700 Subject: [PATCH 21/23] umu_run: remove debug statement --- umu/umu_run.py | 1 - 1 file changed, 1 deletion(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index dc250b14d..a663676ce 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -444,7 +444,6 @@ def build_command( def get_window_client_ids(d: display.Display) -> list[str]: """Get the list of new client windows under the root window.""" try: - log.debug("Waiting for new child windows") event: AnyEvent = d.next_event() if event.type == X.CreateNotify: From 157451abaeb1d4f0fe81683209579283ea91e2d3 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 23:19:33 -0700 Subject: [PATCH 22/23] umu_run: update docstrings --- umu/umu_run.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index a663676ce..aa40252c4 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -457,9 +457,10 @@ def get_window_client_ids(d: display.Display) -> list[str]: return [] -def set_steam_game_property( # noqa: D103 +def set_steam_game_property( d: display.Display, window_ids: list[str], steam_assigned_layer_id: int ) -> None: + """Set Steam's assigned layer ID on a list of windows.""" try: log.debug("steam_layer: %s", steam_assigned_layer_id) for window_id in window_ids: @@ -488,7 +489,8 @@ def set_steam_game_property( # noqa: D103 log.exception(e) -def get_gamescope_baselayer_order(d: display.Display) -> list[int] | None: # noqa: D103 +def get_gamescope_baselayer_order(d: display.Display) -> list[int] | None: + """Get the gamescope base layer seq on the primary root window.""" try: # Intern the atom for GAMESCOPECTRL_BASELAYER_APPID atom = d.get_atom("GAMESCOPECTRL_BASELAYER_APPID") @@ -507,9 +509,10 @@ def get_gamescope_baselayer_order(d: display.Display) -> list[int] | None: # no return None -def rearrange_gamescope_baselayer_order( # noqa +def rearrange_gamescope_baselayer_order( sequence: list[int], ) -> tuple[list[int], int]: + """Rearrange a gamescope base layer sequence retrieved from a window.""" # Ensure there are exactly 4 numbers if len(sequence) != 4: err = "Unexpected number of elements in sequence" @@ -524,9 +527,10 @@ def rearrange_gamescope_baselayer_order( # noqa return rearranged, rearranged[1] -def set_gamescope_baselayer_order( # noqa +def set_gamescope_baselayer_order( d: display.Display, rearranged: list[int] ) -> None: + """Set a new gamescope base layer seq on the primary root window.""" try: # Intern the atom for GAMESCOPECTRL_BASELAYER_APPID atom = d.get_atom("GAMESCOPECTRL_BASELAYER_APPID") From 6c99de8e96a1d2e06533f8e4daeadb7306c12780 Mon Sep 17 00:00:00 2001 From: R1kaB3rN <100738684+R1kaB3rN@users.noreply.github.com> Date: Wed, 17 Jul 2024 23:54:48 -0700 Subject: [PATCH 23/23] umu_run: use the function to get the sequence --- umu/umu_run.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/umu/umu_run.py b/umu/umu_run.py index aa40252c4..b7e7dca96 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -587,13 +587,7 @@ def monitor_baselayer( log.debug("Property value for atom '%s': %s", atom, prop.value) if prop.value == gamescope_baselayer_sequence: log.debug("Broken base layer sequence detected") - log.debug("Rearranging base layer sequence") - rearranged = [ - prop.value[0], - prop.value[3], - prop.value[1], - prop.value[2], - ] + rearranged, _ = rearrange_gamescope_baselayer_order(prop.value) log.debug("'%s' -> '%s'", prop.value, rearranged) set_gamescope_baselayer_order(d_primary, rearranged) continue