Skip to content

Commit

Permalink
fix(LaunchManager): better window detection
Browse files Browse the repository at this point in the history
  • Loading branch information
ShadowApex committed Dec 10, 2024
1 parent 21adfd3 commit f169780
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 19 deletions.
2 changes: 1 addition & 1 deletion core/systems/launcher/interactive_process.gd
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func start() -> int:


func _on_line_written(line: String):
logger.info("PTY:", line)
logger.trace("PTY:", line)
self.lines_mutex.lock()
self.lines_buffer.append(line)
self.lines_mutex.unlock()
Expand Down
37 changes: 36 additions & 1 deletion core/systems/launcher/running_app.gd
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ func update() -> void:
update_wayland_app()


## Tries to discover if the launched app is an X11 or Wayland application
func discover_app_type() -> APP_TYPE:
# Update all the windows
self.window_ids = get_all_window_ids()
Expand Down Expand Up @@ -231,6 +232,7 @@ func update_xwayland_app() -> void:
if id > 0 and window_id != id:
logger.trace("Setting window ID " + str(id) + " for " + launch_item.name)
window_id = id
has_valid_window = true
else:
has_valid_window = true

Expand Down Expand Up @@ -294,7 +296,8 @@ func get_window_title(win_id: int) -> String:
var xwayland := gamescope.get_xwayland_by_name(display)
if not xwayland:
return ""
return xwayland.get_window_name(win_id)
var title := xwayland.get_window_name(win_id)
return title


## Attempt to discover the window ID from the PID of the given application
Expand Down Expand Up @@ -322,6 +325,9 @@ func get_all_window_ids() -> PackedInt32Array:
# processes
var all_windows := xwayland.get_all_windows(xwayland.root_window_id)
for window_id in all_windows:
if xwayland.has_app_id(window_id) and xwayland.get_app_id(window_id) == self.app_id:
window_ids.append(window_id)
continue
var window_pids := xwayland.get_pids_for_window(window_id)
for window_pid in window_pids:
if window_pid in pids:
Expand Down Expand Up @@ -466,6 +472,11 @@ func needs_window_id() -> bool:
if window_id <= 0:
logger.trace(launch_item.name + " has a bad window ID: " + str(window_id))
return true
# If this is a Steam app and the current window id is a Steam window, don't
# consider this a valid window id. TODO: We might not need this since we also
# check this in _discover_window_id()
if is_steam_app() and is_steam_window(window_id):
return true
var focusable_windows := xwayland_primary.focusable_windows
if not window_id in focusable_windows:
logger.trace(str(window_id) + " is not in the list of focusable windows")
Expand Down Expand Up @@ -521,6 +532,11 @@ func _discover_window_id() -> int:
var focusable := xwayland_primary.focusable_windows
for window in possible_windows:
if window in focusable:
# If this is a steam app, don't consider any Steam windows as valid
# discovered window ids for this app.
if is_steam_app() and is_steam_window(window):
logger.debug("Window", window, "is a Steam window")
continue
return window

return -1
Expand All @@ -542,6 +558,25 @@ func is_steam_app() -> bool:
return false


## Returns true if the given window id is detected as a Steam window
func is_steam_window(window_id: int) -> bool:
var xwayland := gamescope.get_xwayland_by_name(display)
if not xwayland:
return false

var window_pids := xwayland.get_pids_for_window(window_id)
for window_pid in window_pids:
var pid_info := Reaper.get_pid_status(window_pid)
if not "Name" in pid_info:
continue
var process_name := pid_info["Name"] as String
if process_name in ["steam", "steamwebhelper"]:
return true
print(process_name)

return false


## Finds the steam process so it can be killed when a game closes
func find_steam() -> int:
var child_pids := get_child_pids()
Expand Down
3 changes: 2 additions & 1 deletion core/systems/library/library_desktop.gd
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ func _apply_quirks(launch_item: LibraryLaunchItem) -> void:

# If the desktop shortcut is for Steam, add the '-silent' argument so it
# doesn't launch into the Steam interface
var args := PackedStringArray(["-gamepadui", "-steamos3", "-steampal", "-steamdeck", "-silent"])
#var args := PackedStringArray(["-gamepadui", "-steamos3", "-steampal", "-steamdeck", "-silent"])
var args := PackedStringArray(["-silent"])
args.append_array(launch_item.args)
launch_item.args = args

Expand Down
1 change: 0 additions & 1 deletion core/systems/library/library_refresher.gd
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ func _on_ready() -> void:

## Fires when the given signal is emitted.
func _on_signal():
print("LOADING LIBRARY!")
library_manager.reload_library()


Expand Down
23 changes: 12 additions & 11 deletions core/systems/sandbox/sandbox_bubblewrap.gd
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,16 @@ func is_available() -> bool:
# Applies additional blacklists depending on if we're launching a steam app
func _apply_quirks(app: LibraryLaunchItem) -> PackedStringArray:
var args := PackedStringArray()
# Only block device access if this is a Steam app
if app.command != "steam":
return args

# Block any hidraw devices
var devices := DirAccess.get_files_at("/dev")
for dev in devices:
if not dev.begins_with("hidraw"):
continue
var path := "/".join(["/dev", dev])
args.append_array(["--bind", "/dev/null", path])
return args
# # Only block device access if this is a Steam app
# if app.command != "steam":
# return args
#
# # Block any hidraw devices
# var devices := DirAccess.get_files_at("/dev")
# for dev in devices:
# if not dev.begins_with("hidraw"):
# continue
# var path := "/".join(["/dev", dev])
# args.append_array(["--bind", "/dev/null", path])
# return args
24 changes: 24 additions & 0 deletions core/ui/card_ui/card_ui.gd
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var gamescope := load("res://core/systems/gamescope/gamescope.tres") as Gamescop
var library_manager := load("res://core/global/library_manager.tres") as LibraryManager
var settings_manager := load("res://core/global/settings_manager.tres") as SettingsManager
var input_plumber := load("res://core/systems/input/input_plumber.tres") as InputPlumberInstance
var launch_manager := load("res://core/global/launch_manager.tres") as LaunchManager

var state_machine := (
preload("res://assets/state/state_machines/global_state_machine.tres") as StateMachine
Expand All @@ -22,6 +23,7 @@ var power_state := preload("res://assets/state/states/power_menu.tres") as State
var PID: int = OS.get_process_id()
var _xwayland_primary := gamescope.get_xwayland(gamescope.XWAYLAND_TYPE_PRIMARY)
var _xwayland_ogui := gamescope.get_xwayland(gamescope.XWAYLAND_TYPE_OGUI)
var _xwayland_game := gamescope.get_xwayland(gamescope.XWAYLAND_TYPE_GAME)
var overlay_window_id := 0

@onready var panel := $%Panel as Panel
Expand Down Expand Up @@ -61,6 +63,28 @@ func _setup(window_id: int) -> void:
if _xwayland_primary.set_input_focus(window_id, 1) != OK:
logger.error("Unable to set STEAM_INPUT_FOCUS atom!")

# Override reserved app ids for any newly created windows
# Listen for window created/destroyed events
var on_window_created := func(window_id: int):
logger.debug("Window created:", window_id)
var try := 0
while try < 10:
if _xwayland_game.has_app_id(window_id):
break
try += 1
await get_tree().create_timer(0.2).timeout # wait a beat
var app_id := _xwayland_game.get_app_id(window_id)
if app_id == GamescopeInstance.OVERLAY_GAME_ID:
# Find the current running app and use that app id
var running := launch_manager.get_running()
running.reverse()
for app in running:
_xwayland_game.set_app_id(window_id, app.app_id)
return
logger.warn("Unable to find a running app to tie Steam to")
_xwayland_game.set_app_id(window_id, 7769)
_xwayland_game.window_created.connect(on_window_created)


# Called when the node enters the scene tree for the first time.
# gamescope --xwayland-count 2 -- build/opengamepad-ui.x86_64
Expand Down
5 changes: 3 additions & 2 deletions core/ui/card_ui/navigation/running_game_card.gd
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ func set_running_app(app: RunningApp):
# Connect to app signals to allow switching between app windows
var on_windows_changed := func(_from: PackedInt32Array, to: PackedInt32Array):
var xwayland := gamescope.get_xwayland(gamescope.XWAYLAND_TYPE_PRIMARY)
var xwayland_game := gamescope.get_xwayland(gamescope.XWAYLAND_TYPE_GAME)
var focusable_windows := xwayland.get_focusable_windows()
# Add a button to switch to a given window
for window_id in to:
Expand All @@ -123,9 +124,9 @@ func set_running_app(app: RunningApp):
continue
if not window_id in focusable_windows:
continue
var window_name := app.get_window_title(window_id)
var window_name := xwayland_game.get_window_name(window_id)
if window_name == "":
continue
window_name = "Window (" + str(window_id) + ")"
var button := button_scene.instantiate() as CardButton
button.text = window_name
button.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
Expand Down
4 changes: 2 additions & 2 deletions core/ui/card_ui/navigation/running_game_card.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
[ext_resource type="Resource" uid="uid://cr544el0cqjlm" path="res://assets/state/state_machines/global_state_machine.tres" id="15_p4kr0"]
[ext_resource type="Resource" uid="uid://cv3vduo0ojk1u" path="res://assets/state/states/menu.tres" id="16_vmedb"]

[sub_resource type="Image" id="Image_geul6"]
[sub_resource type="Image" id="Image_8fib7"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
Expand All @@ -27,7 +27,7 @@ data = {
}

[sub_resource type="ImageTexture" id="ImageTexture_osglk"]
image = SubResource("Image_geul6")
image = SubResource("Image_8fib7")

[node name="RunningGameCard" type="PanelContainer"]
anchors_preset = 10
Expand Down

0 comments on commit f169780

Please sign in to comment.