diff --git a/src/IPC.js b/src/IPC.js index 7f771699..de771e44 100644 --- a/src/IPC.js +++ b/src/IPC.js @@ -92,6 +92,19 @@ window.addEventListener('message', async (event) => { //------------------------------------------------- if(event.data.msg === 'READY'){ $(target_iframe).attr('data-appUsesSDK', 'true'); + + // If we were waiting to launch this as a child app, report to the parent that it succeeded. + const child_launch_callback = window.child_launch_callbacks[event.data.appInstanceID]; + if (child_launch_callback) { + const parent_iframe = iframe_for_app_instance(child_launch_callback.parent_instance_id); + // send confirmation to requester window + parent_iframe.contentWindow.postMessage({ + msg: 'childAppLaunched', + original_msg_id: child_launch_callback.launch_msg_id, + child_instance_id: event.data.appInstanceID, + }, '*'); + delete window.child_launch_callbacks[event.data.appInstanceID]; + } } //------------------------------------------------- // windowFocused @@ -500,16 +513,20 @@ window.addEventListener('message', async (event) => { // launchApp //-------------------------------------------------------- else if(event.data.msg === 'launchApp'){ - // launch app + // TODO: Determine if the app is allowed to launch child apps? We may want to limit this to prevent abuse. + // remember app for launch callback later + const child_instance_id = uuidv4(); + window.child_launch_callbacks[child_instance_id] = { + parent_instance_id: event.data.appInstanceID, + launch_msg_id: msg_id, + }; + // launch child app launch_app({ name: event.data.app_name ?? app_name, args: event.data.args ?? {}, + parent_instance_id: event.data.appInstanceID, + uuid: child_instance_id, }); - - // send confirmation to requester window - target_iframe.contentWindow.postMessage({ - original_msg_id: msg_id, - }, '*'); } //-------------------------------------------------------- // readAppDataFile diff --git a/src/globals.js b/src/globals.js index 5d91c0af..ea429a28 100644 --- a/src/globals.js +++ b/src/globals.js @@ -130,6 +130,9 @@ window.launch_apps = []; window.launch_apps.recent = [] window.launch_apps.recommended = [] +// Map of { child_instance_id -> { parent_instance_id, launch_msg_id } } +window.child_launch_callbacks = {}; + // Is puter being loaded inside an iframe? if (window.location !== window.parent.location) { window.is_embedded = true; diff --git a/src/helpers.js b/src/helpers.js index 47bf3741..a8486d11 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -1849,7 +1849,7 @@ window.trigger_download = (paths)=>{ * @param {*} options */ window.launch_app = async (options)=>{ - const uuid = uuidv4(); + const uuid = options.uuid ?? uuidv4(); let icon, title, file_signature; const window_options = options.window_options ?? {}; @@ -1945,6 +1945,11 @@ window.launch_app = async (options)=>{ // add app_id to URL iframe_url.searchParams.append('puter.app.id', app_info.uuid); + // add parent_app_instance_id to URL + if (options.parent_instance_id) { + iframe_url.searchParams.append('puter.parent_instance_id', options.parent_instance_id); + } + if(file_signature){ iframe_url.searchParams.append('puter.item.uid', file_signature.uid); iframe_url.searchParams.append('puter.item.path', options.file_path ? `~/` + options.file_path.split('/').slice(1).join('/') : file_signature.path);