@@ -33,10 +33,13 @@ signal all_apps_stopped()
3333signal app_launched (app : RunningApp )
3434signal app_stopped (app : RunningApp )
3535signal app_switched (from : RunningApp , to : RunningApp )
36+ signal app_lifecycle_progressed (progress : float , type : AppLifecycleHook .TYPE )
37+ signal app_lifecycle_notified (text : String , type : AppLifecycleHook .TYPE )
3638signal recent_apps_changed ()
3739
3840const settings_manager := preload ("res://core/global/settings_manager.tres" )
3941const notification_manager := preload ("res://core/global/notification_manager.tres" )
42+ const library_manager := preload ("res://core/global/library_manager.tres" )
4043
4144var gamescope := preload ("res://core/systems/gamescope/gamescope.tres" ) as GamescopeInstance
4245var input_plumber := load ("res://core/systems/input/input_plumber.tres" ) as InputPlumberInstance
@@ -196,20 +199,34 @@ func _save_persist_data():
196199## Launches the given application and switches to the in-game state. Returns a
197200## [RunningApp] instance of the application.
198201func launch (app : LibraryLaunchItem ) -> RunningApp :
202+ # Create a running app from the launch item
199203 var running_app := _launch (app )
200204
201205 # Add the running app to our list and change to the IN_GAME state
202206 _add_running (running_app )
203207 state_machine .set_state ([in_game_state ])
204208 _update_recent_apps (app )
205209
210+ # Execute any pre-launch hooks and start the app
211+ await _execute_hooks (app , AppLifecycleHook .TYPE .PRE_LAUNCH )
212+ running_app .start ()
213+
214+ # Call any hooks at different points in the app's lifecycle
215+ var on_app_state_changed := func (_from : RunningApp .STATE , to : RunningApp .STATE ):
216+ if to == RunningApp .STATE .RUNNING :
217+ _execute_hooks (app , AppLifecycleHook .TYPE .LAUNCH )
218+ elif to == RunningApp .STATE .STOPPED :
219+ _execute_hooks (app , AppLifecycleHook .TYPE .EXIT )
220+ running_app .state_changed .connect (on_app_state_changed )
221+
206222 return running_app
207223
208224
209225## Launches the given app in the background. Returns the [RunningApp] instance.
210226func launch_in_background (app : LibraryLaunchItem ) -> RunningApp :
211227 # Start the application
212228 var running_app := _launch (app )
229+ running_app .start ()
213230
214231 # Listen for app state changes
215232 var on_app_state_changed := func (from : RunningApp .STATE , to : RunningApp .STATE ):
@@ -224,6 +241,37 @@ func launch_in_background(app: LibraryLaunchItem) -> RunningApp:
224241 return running_app
225242
226243
244+ ## Executes application lifecycle hooks for the given app
245+ func _execute_hooks (app : LibraryLaunchItem , type : AppLifecycleHook .TYPE ) -> void :
246+ var library := library_manager .get_library_by_id (app ._provider_id )
247+ if not library :
248+ logger .warn ("Unable to find library for app:" , app )
249+ return
250+ var hooks := library .get_app_lifecycle_hooks ()
251+
252+ # Filter based on hook type
253+ var hooks_to_run : Array [AppLifecycleHook ] = []
254+ for item in hooks :
255+ if item .get_type () != type :
256+ continue
257+ hooks_to_run .push_back (item )
258+
259+ # Emit signals if the hook has progress
260+ var on_hook_progress := func (progress : float ):
261+ self .app_lifecycle_progressed .emit (progress , type )
262+ var on_hook_notify := func (text : String ):
263+ self .app_lifecycle_notified .emit (text , type )
264+
265+ # Run each hook and emit signals on hook progress
266+ for hook in hooks_to_run :
267+ logger .info ("Executing lifecycle hook:" , hook )
268+ hook .progressed .connect (on_hook_progress )
269+ hook .notified .connect (on_hook_notify )
270+ await hook .execute (app )
271+ hook .notified .disconnect (on_hook_notify )
272+ hook .progressed .disconnect (on_hook_progress )
273+
274+
227275## Launches the given app
228276func _launch (app : LibraryLaunchItem ) -> RunningApp :
229277 var cmd : String = app .command
@@ -283,9 +331,8 @@ func _launch(app: LibraryLaunchItem) -> RunningApp:
283331 command .append_array (args )
284332 logger .info ("Launching game with command: {0} {1} " .format ([exec , str (command )]))
285333
286- # Launch the application process
287- var running_app := RunningApp .spawn (app , env , exec , command )
288- logger .info ("Launched with PID: {0} " .format ([running_app .pid ]))
334+ # Create the running app instance, but do not start it yet.
335+ var running_app := RunningApp .create (app , env , exec , command )
289336
290337 return running_app
291338
@@ -489,9 +536,10 @@ func check_running() -> void:
489536 var root_id := _xwayland_game .root_window_id
490537 if root_id < 0 :
491538 return
539+ var all_windows := _xwayland_game .get_all_windows (root_id )
492540
493541 # Update our view of running processes and what windows they have
494- _update_pids (root_id )
542+ _update_pids (all_windows )
495543
496544 # Update the state of all running apps
497545 for app in _running :
@@ -502,11 +550,10 @@ func check_running() -> void:
502550
503551# Updates our mapping of PIDs to Windows. This gives us a good view of what
504552# processes are running, and what windows they have.
505- func _update_pids (root_id : int ):
553+ func _update_pids (all_windows : PackedInt64Array ):
506554 if not _xwayland_game :
507555 return
508556 var pids := {}
509- var all_windows := _xwayland_game .get_all_windows (root_id )
510557 for window in all_windows :
511558 var window_pids := _xwayland_game .get_pids_for_window (window )
512559 for window_pid in window_pids :
@@ -661,7 +708,7 @@ func _make_running_app_from_process(name: String, pid: int, window_id: int, app_
661708# Creates a new RunningApp instance from a given LibraryLaunchItem, PID, and
662709# xwayland instance.
663710func _make_running_app (launch_item : LibraryLaunchItem , pid : int , display : String ) -> RunningApp :
664- var running_app : RunningApp = RunningApp .new (launch_item , pid , display )
711+ var running_app : RunningApp = RunningApp .new (launch_item , display )
665712 running_app .launch_item = launch_item
666713 running_app .pid = pid
667714 running_app .display = display
0 commit comments