Skip to content

Commit

Permalink
Add SteamOS platform provider and session switching power menu buttons
Browse files Browse the repository at this point in the history
  • Loading branch information
ShadowApex committed Mar 27, 2023
1 parent 7014d84 commit e9bc4d8
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 14 deletions.
92 changes: 78 additions & 14 deletions core/global/platform.gd
Original file line number Diff line number Diff line change
Expand Up @@ -18,46 +18,68 @@ enum PLATFORM {
ONEXPLAYER_GEN1, ## Includes most OXP and AOKZOE devices
ONEXPLAYER_GEN2, ## GUNDAM edition.
STEAMDECK,

# OS Platforms
CHIMERAOS,
STEAMOS,
ARCH_LIKE,
}

## Data container for OS information
class OSInfo:
var name: String
var id: String
var id_like: String
var pretty_name: String
var version_codename: String
var variant_id: String

## Detected Operating System information
var os_info := _detect_os()
## The OS platform provider detected
var os: PlatformProvider
## The hardware platform provider detected
var platform: PlatformProvider
var logger := Log.get_logger("Platform", Log.LEVEL.DEBUG)

func _init() -> void:
var flags := get_platform_flags()

# Set hardware platform provider
if PLATFORM.ABERNIC_GEN1 in flags:
platform = load("res://core/platform/abernic_gen1.tres")
return
if PLATFORM.AYANEO_GEN1 in flags:
platform = load("res://core/platform/ayaneo_gen1.tres")
return
if PLATFORM.AYANEO_GEN2 in flags:
platform = load("res://core/platform/ayaneo_gen2.tres")
return
if PLATFORM.AYANEO_GEN3 in flags:
platform = load("res://core/platform/ayaneo_gen3.tres")
return
if PLATFORM.AYANEO_GEN4 in flags:
platform = load("res://core/platform/ayaneo_gen4.tres")
return
if PLATFORM.GENERIC in flags:
platform = load("res://core/platform/generic.tres")
return
if PLATFORM.GPD_GEN1 in flags:
platform = load("res://core/platform/gpd_gen1.tres")
return
if PLATFORM.ONEXPLAYER_GEN1 in flags:
platform = load("res://core/platform/onexplayer_gen1.tres")
return
if PLATFORM.ONEXPLAYER_GEN2 in flags:
platform = load("res://core/platform/onexplayer_gen2.tres")
return
if PLATFORM.STEAMDECK in flags:
platform = load("res://core/platform/steamdeck.tres")
return

# Set OS platform provider
if PLATFORM.STEAMOS in flags:
os = load("res://core/platform/steamos.tres")


## Loads the detected platforms. This should be called once when OpenGamepadUI
## first starts. It takes the root window to give platform providers the
## opportinity to modify the scene tree.
func load(root: Window) -> void:
if platform:
platform.ready(root)
if os:
os.ready(root)


## Returns the handheld gamepad for the detected platform
Expand All @@ -69,8 +91,11 @@ func get_handheld_gamepad() -> HandheldGamepad:

## Returns all detected platform flags
func get_platform_flags() -> Array[PLATFORM]:
var flags: Array[PLATFORM] = []
var dmi_flags := _read_dmi()
return [dmi_flags]
flags.append(dmi_flags)
flags.append_array(_read_os())
return flags


## Returns the hardware product name
Expand All @@ -92,7 +117,7 @@ func _read_sys(path: String) -> String:


## returns result of OS.Execute in a reliable data structure
func _do_exec(command: String, args: Array)-> Array:
func _do_exec(command: String, args: Array) -> Array:
var output = []
var exit_code := OS.execute(command, args, output)
return [output, exit_code]
Expand Down Expand Up @@ -145,5 +170,44 @@ func _read_dmi() -> PLATFORM:
return PLATFORM.GENERIC


func _detect_os() -> void:
pass
# Read OS information and return flags that match
func _read_os() -> Array[PLATFORM]:
var flags: Array[PLATFORM] = []
if not os_info:
return flags
if os_info.id == "steamos":
flags.append(PLATFORM.STEAMOS)
if os_info.id_like == "arch":
flags.append(PLATFORM.ARCH_LIKE)
return flags


## Detect the currently running OS
func _detect_os() -> OSInfo:
if not FileAccess.file_exists("/etc/os-release"):
return null
var os_file := FileAccess.open("/etc/os-release", FileAccess.READ)
var content := os_file.get_as_text()
var lines := content.split("\n")
var info := OSInfo.new()
for line in lines:
var key_value := line.split("=")
if key_value.size() != 2:
continue
var key := key_value[0]
var value := key_value[1].replace('"', "")

if key == "ID":
info.id = value
if key == "ID_LIKE":
info.id_like = value
if key == "NAME":
info.name = value
if key == "PRETTY_NAME":
info.pretty_name = value
if key == "VERSION_CODENAME":
info.version_codename = value
if key == "VARIANT_ID":
info.variant_id = value

return info
5 changes: 5 additions & 0 deletions core/main.gd
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ func _ready() -> void:
# Set bg to transparent
get_tree().get_root().transparent_bg = true
fade_texture.visible = true

# Load any platform-specific logic
Platform.load(get_tree().get_root())

# Initialize the state machine with its initial state
state_machine.push_state(home_state)
Expand All @@ -63,6 +66,8 @@ func _ready() -> void:

get_viewport().gui_focus_changed.connect(_on_focus_changed)
LibraryManager.reload_library()

get_tree()


func _on_focus_changed(control: Control) -> void:
Expand Down
9 changes: 9 additions & 0 deletions core/platform/platform_provider.gd
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ class_name PlatformProvider
var logger := Log.get_logger("PlatformProvider", Log.LEVEL.DEBUG)


## Ready will be called after the scene tree has initialized. This should be
## overridden in the child class if the platform wants to make changes to the
## scene tree.
func ready(root: Window) -> void:
pass


## If implemented, return a HandheldGamepad implementation for hardware platforms
## with embedded controllers.
func get_handheld_gamepad() -> HandheldGamepad:
logger.info("Platform not found. Using default configuration.")
return null
80 changes: 80 additions & 0 deletions core/platform/steamos.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
extends PlatformProvider
class_name PlatformSteamOS

const DESKTOP_FILE_PATH := "/home/deck/Desktop/return-opengamepadui.desktop"
const DESKTOP_FILE := "#!/usr/bin/env xdg-open
[Desktop Entry]
Version=1.0
Name=Return to OpenGamepadUI
GenericName=Game launcher and overlay
Type=Application
Comment=Game launcher and overlay
Icon=opengamepadui
Exec=opengamepadui-session-select opengamepadui
Terminal=false"


func _init() -> void:
logger.set_name("PlatformSteamOS")
_ensure_desktop_file()


func ready(root: Window) -> void:
if not _has_session_switcher():
logger.info("No session switcher script detected")
return
_add_session_switcher(root)


## Add a button to the power menu to allow session switching
func _add_session_switcher(root: Window) -> void:
# Get the power menu
var power_menu := root.get_tree().get_first_node_in_group("power_menu")
if not power_menu:
logger.warn("No power menu was found. Unable to add session switcher.")
return

# Create a button that will perform the session switching
var button_scene := load("res://core/ui/components/button.tscn") as PackedScene
var switch_to_steam := button_scene.instantiate() as Button
switch_to_steam.text = "Switch to Steam"
switch_to_steam.pressed.connect(_switch_session.bind("gamescope"))

var switch_to_desktop := button_scene.instantiate() as Button
switch_to_desktop.text = "Switch to Desktop"
switch_to_desktop.pressed.connect(_switch_session.bind("plasma"))

# Add the buttons just above the exit button
var exit_button := power_menu.exit_button as Button
var container := exit_button.get_parent()
container.add_child(switch_to_steam)
container.move_child(switch_to_steam, exit_button.get_index())
container.add_child(switch_to_desktop)
container.move_child(switch_to_desktop, exit_button.get_index())

# Coerce the focus manager to recalculate the focus neighbors
var focus_manager := power_menu.focus_manager as FocusManager
focus_manager._on_child_tree_changed(null)


## Returns true if we detect the session switching script
func _has_session_switcher() -> bool:
return OS.execute("which", ["opengamepadui-session-select"]) == 0


## Ensure there is a "Return to OpenGamepadUI" desktop shortcut
func _ensure_desktop_file() -> void:
if FileAccess.file_exists(DESKTOP_FILE_PATH):
return
var desktop_file := FileAccess.open(DESKTOP_FILE_PATH, FileAccess.WRITE)
desktop_file.store_string(DESKTOP_FILE)
desktop_file.close()
OS.execute("chmod", ["+x", DESKTOP_FILE_PATH])


## Switch to the given session
func _switch_session(name: String) -> void:
var out: Array = []
var code := OS.execute("opengamepadui-session-select", [name], out)
if code != OK:
logger.error("Unable to switch sessions: " + out[0])
7 changes: 7 additions & 0 deletions core/platform/steamos.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[gd_resource type="Resource" script_class="PlatformSteamOS" load_steps=2 format=3 uid="uid://dqn1kkcjpdi56"]

[ext_resource type="Script" path="res://core/platform/steamos.gd" id="1_6glao"]

[resource]
script = ExtResource("1_6glao")
name = "SteamOS"

0 comments on commit e9bc4d8

Please sign in to comment.