From a535b8b1c5149e3708858118aeef3fcad831d4e7 Mon Sep 17 00:00:00 2001 From: William Edwards Date: Fri, 10 Nov 2023 21:38:39 -0800 Subject: [PATCH] feat(RunningApp): add suspend/resume of running games --- core/systems/launcher/reaper.gd | 9 +++++++- core/systems/launcher/running_app.gd | 18 +++++++++++++++ .../card_ui/navigation/running_game_card.gd | 12 ++++++++-- .../card_ui/navigation/running_game_card.tscn | 22 ++++++++++++++++--- 4 files changed, 55 insertions(+), 6 deletions(-) diff --git a/core/systems/launcher/reaper.gd b/core/systems/launcher/reaper.gd index 9fe211fc..4a809967 100644 --- a/core/systems/launcher/reaper.gd +++ b/core/systems/launcher/reaper.gd @@ -4,6 +4,8 @@ class_name Reaper enum SIG { KILL = 9, TERM = 15, + CONT = 18, + STOP = 19, } @@ -35,7 +37,12 @@ static func reap(pid: int, sig: SIG = SIG.TERM) -> void: logger.info(cmd + " " + " ".join(args)) OS.execute(cmd, args) - logger.info("Reaped pids: " + ",".join(pids)) + var verb := "Reaped" + if sig == SIG.STOP: + verb = "Suspended" + if sig == SIG.CONT: + verb = "Resumed" + logger.info(verb + " pids: " + ",".join(pids)) # Returns an array of child PIDs that are in the given process group diff --git a/core/systems/launcher/running_app.gd b/core/systems/launcher/running_app.gd index 655a6008..8b20cb65 100644 --- a/core/systems/launcher/running_app.gd +++ b/core/systems/launcher/running_app.gd @@ -20,6 +20,8 @@ signal window_ids_changed(from: PackedInt32Array, to: PackedInt32Array) signal app_id_changed ## Emitted when the app's state has changed signal state_changed(from: STATE, to: STATE) +## Emitted when an app is suspended +signal suspended(enabled: bool) ## Emitted when the app is focused signal focus_entered ## Emitted when the app is unfocused @@ -51,6 +53,13 @@ var state: STATE = STATE.STARTED: state = v if old_state != state: state_changed.emit(old_state, state) +## Whether or not the running app is suspended +var is_suspended := false: + set(v): + var old_value := is_suspended + is_suspended = v + if old_value != is_suspended: + suspended.emit(is_suspended) ## Time in milliseconds when the app started var start_time := Time.get_ticks_msec() ## The currently detected window ID of the application @@ -164,6 +173,15 @@ func update() -> void: OS.execute("kill", ["-15", str(steam_pid)]) +## Pauses/Resumes the running app by running 'kill -STOP' or 'kill -CONT' +func suspend(enable: bool) -> void: + if enable: + Reaper.reap(pid, Reaper.SIG.STOP) + else: + Reaper.reap(pid, Reaper.SIG.CONT) + is_suspended = enable + + ## Returns the window title of the given window. If the window ID does not belong to this app, ## it will return an empty string. func get_window_title(win_id: int) -> String: diff --git a/core/ui/card_ui/navigation/running_game_card.gd b/core/ui/card_ui/navigation/running_game_card.gd index e6bb6ba6..27c01cd9 100644 --- a/core/ui/card_ui/navigation/running_game_card.gd +++ b/core/ui/card_ui/navigation/running_game_card.gd @@ -32,8 +32,9 @@ var button_scene := load("res://core/ui/components/card_button.tscn") as PackedS @onready var content_container := $%ContentContainer @onready var game_logo := $%GameLogo @onready var game_label := $%GameLabel -@onready var resume_button := $%ResumeButton -@onready var exit_button := $%ExitButton +@onready var resume_button := $%ResumeButton as CardButton +@onready var suspend_button := $%SuspendButton as CardButton +@onready var exit_button := $%ExitButton as CardButton @onready var highlight := $%HighlightTexture @onready var highlight_rect := $%HighlightTextureRect @onready var inside_panel := $%InsidePanel @@ -65,6 +66,13 @@ func _ready() -> void: launch_manager.stop(running_app) state_machine.pop_state() exit_button.pressed.connect(on_exit_game) + var on_suspend := func(): + running_app.suspend(not running_app.is_suspended) + if running_app.is_suspended: + suspend_button.text = "Continue" + else: + suspend_button.text = "Suspend" + suspend_button.pressed.connect(on_suspend) func _on_theme_changed() -> void: diff --git a/core/ui/card_ui/navigation/running_game_card.tscn b/core/ui/card_ui/navigation/running_game_card.tscn index 4c0fa843..844ebbbd 100644 --- a/core/ui/card_ui/navigation/running_game_card.tscn +++ b/core/ui/card_ui/navigation/running_game_card.tscn @@ -1,11 +1,10 @@ -[gd_scene load_steps=13 format=3 uid="uid://dlouq0b0bnm41"] +[gd_scene load_steps=14 format=3 uid="uid://dlouq0b0bnm41"] [ext_resource type="Texture2D" uid="uid://d2ipfga47yjju" path="res://assets/images/empty-grid-logo.png" id="1_4m4go"] [ext_resource type="Script" path="res://core/ui/card_ui/navigation/running_game_card.gd" id="1_vgpef"] [ext_resource type="PackedScene" uid="uid://uljtdvmuol3l" path="res://core/systems/input/focus_group_setter.tscn" id="2_ao14v"] [ext_resource type="PackedScene" uid="uid://d0u3rsa5qpj57" path="res://core/ui/components/subsection_label.tscn" id="2_w7u51"] [ext_resource type="PackedScene" uid="uid://dithv38oqgy58" path="res://core/ui/components/section_label.tscn" id="3_4x3oi"] -[ext_resource type="Texture2D" uid="uid://cj14g5onuca3o" path="res://assets/styles/dracula/highlight.tres" id="3_o7ylm"] [ext_resource type="PackedScene" uid="uid://8m20p2s0v5gb" path="res://core/systems/input/focus_group.tscn" id="5_smmwr"] [ext_resource type="PackedScene" uid="uid://b76dvfuouhlwd" path="res://core/systems/state/state_updater.tscn" id="6_s452c"] [ext_resource type="Resource" uid="uid://bytra6gw0dr4c" path="res://core/ui/card_ui/main-menu/main_menu_focus.tres" id="6_xmlue"] @@ -13,6 +12,18 @@ [ext_resource type="PackedScene" uid="uid://c71ayw7pcw6u6" path="res://core/ui/components/card_button.tscn" id="8_ixs6g"] [ext_resource type="Resource" uid="uid://cx8u1y5j7vyss" path="res://assets/state/states/gamepad_settings.tres" id="8_nyd1y"] +[sub_resource type="Image" id="Image_hqab3"] +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", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id="ImageTexture_ocbm3"] +image = SubResource("Image_hqab3") + [node name="RunningGameCard" type="PanelContainer"] anchors_preset = 10 anchor_right = 1.0 @@ -44,7 +55,7 @@ anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -texture = ExtResource("3_o7ylm") +texture = SubResource("ImageTexture_ocbm3") expand_mode = 1 stretch_mode = 6 @@ -115,6 +126,11 @@ unique_name_in_owner = true layout_mode = 2 text = "Resume" +[node name="SuspendButton" parent="MarginContainer/VBoxContainer/ContentContainer" instance=ExtResource("8_ixs6g")] +unique_name_in_owner = true +layout_mode = 2 +text = "Suspend" + [node name="GamepadButton" parent="MarginContainer/VBoxContainer/ContentContainer" instance=ExtResource("8_ixs6g")] layout_mode = 2 text = "Gamepad"