Run executables directly (#645)

- Apps can be launched directly from file paths (including Files app support)
- Added executable detection to identify unsupported or invalid binaries before launch.
- App startup is now streamlined through separate registered-app and direct-execution interfaces.
- Existing app launch points were migrated to the updated startup APIs.
This commit is contained in:
Ken Van Hoeylandt
2026-09-04 21:23:08 +02:00
committed by GitHub
parent 643cbc3806
commit a0b2ee7ebc
63 changed files with 1276 additions and 347 deletions
@@ -10,7 +10,7 @@ namespace tt::app::fileselection {
/**
* Show a file selection dialog that allows the user to select an existing file, as a modal
* child of @a callerAppInstanceId (see app_manager_start_for_result_with_streams()). Result
* child of @a callerAppInstanceId (see app_start_for_result_with_streams()). Result
* (0 = Ok, 1 = Cancelled) is delivered back via APP_EVENT_RESULT once this app's thread exits.
* On result == 0, read the picked path with app_stream_read(&stream, ...) then
* app_stream_unsubscribe(&stream); on any other result, just app_stream_unsubscribe(&stream).
@@ -1,8 +1,12 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <string>
#include <app/stream.h>
#include <tactility/concurrent/task_event_group.h>
/**
* Show a dialog with a title, a message and a text field.
*/
@@ -10,19 +14,21 @@ namespace tt::app::inputdialog {
/**
* Show a dialog with the provided title, message and prefilled text, as a modal child of
* @a callerAppInstanceId (a new-model app - see app/manager.h). The caller receives the result
* as an APP_EVENT_RESULT in its own event loop: 0 = OK (call getLastText() for the entered
* text), 1 = Cancelled or dismissed without a press. The caller is responsible for calling
* app_manager_stop() on the returned instance id once it has handled the result.
* @a callerAppInstanceId (see app_start_for_result_with_streams()). Result (0 = OK, 1 =
* Cancelled or dismissed without a press) is delivered back via APP_EVENT_RESULT once this app's
* thread exits. On result == 0, read the entered text with app_stream_read(&stream, ...) then
* app_stream_unsubscribe(&stream); on any other result, just app_stream_unsubscribe(&stream).
* The caller must call app_manager_stop() on the returned instance id once that event arrives,
* to fully reap this instance.
* @param[in,out] stream caller-owned storage bound to the started app's stdout; must stay valid
* until app_stream_unsubscribe() is called on it (see above).
* @param[in] buffer caller-owned backing storage for @a stream's ring buffer; must stay valid
* for the same duration as @a stream.
* @param[in] bufferCapacity size of @a buffer in bytes.
* @param[in] eventGroup the caller's own event group, reused for the stream's readiness bits
* (see app_stream_subscribe()). The caller isn't required to actually wait on them itself.
* @return the new dialog's app instance id
*/
uint32_t start(uint32_t callerAppInstanceId, const std::string& title, const std::string& message, const std::string& prefilled = "");
/**
* @return the text entered the last time any InputDialog instance was closed with OK. Only one
* dialog is expected to be open at a time - call this right after receiving its
* APP_EVENT_RESULT with result == 0.
*/
std::string getLastText();
uint32_t start(uint32_t callerAppInstanceId, const std::string& title, const std::string& message, const std::string& prefilled, AppStream& stream, void* buffer, size_t bufferCapacity, TaskEventGroup* eventGroup);
}
@@ -5,7 +5,7 @@
namespace tt::app::wifimanage {
/**
* Starts as a modal child of @a callerAppInstanceId (see app_manager_start_for_result()) - an
* Starts as a modal child of @a callerAppInstanceId (see app_start_for_result()) - an
* APP_EVENT_RESULT is delivered back once the user closes this screen (default Cancelled/no
* bundle if never explicitly set - callers that just want a "the wifi step is done" signal, like
* Setup, can ignore the actual result value).