Implement posix app loading (#643)

- Added POSIX desktop support for SDK builds, application packaging, and integration testing.
- Added POSIX filesystem partitions and improved application path handling.
- Added simulator support for loading and running applications dynamically.
- Improved simulator task stack handling and display startup reliability.
- Improved simulator display scaling, resizing, high-DPI support, and pointer accuracy.
- Fixed LVGL timers and input polling on POSIX. (fixes simulator with Linux on some Intel graphics platforms)
- Standardized data paths across platforms.
- Logging now works via separate task: this allows apps to write to log without it affecting their stdout (for apps that output text as relevant date for other apps, like the File Selection app)
- Fixes for app stdio
This commit is contained in:
Ken Van Hoeylandt
2026-08-31 22:09:04 +02:00
committed by GitHub
parent d3656bcd3d
commit 643cbc3806
66 changed files with 2139 additions and 336 deletions
+28 -6
View File
@@ -1,4 +1,7 @@
#include <Tactility/app/notes/Notes.h>
#include "Tactility/app/alertdialog/AlertDialog.h"
#include <Tactility/app/fileselection/FileSelection.h>
#include <Tactility/file/File.h>
@@ -6,6 +9,7 @@
#include <app/manager.h>
#include <app/manifest.h>
#include <app/scheduler.h>
#include <app/stream.h>
#include <lvgl_window_manager/window_manager.h>
@@ -25,6 +29,7 @@ namespace {
struct Context {
uint32_t appInstanceId;
TaskEventGroup* eventGroup = nullptr;
lv_obj_t* uiCurrentFileName = nullptr;
lv_obj_t* uiDropDownMenu = nullptr;
@@ -35,6 +40,10 @@ struct Context {
uint32_t loadFileLaunchId = 0;
uint32_t saveFileLaunchId = 0;
AppStream loadResultStream {};
uint8_t loadResultBuffer[256] {};
AppStream saveResultStream {};
uint8_t saveResultBuffer[256] {};
};
@@ -90,11 +99,11 @@ void appNotesEventCb(lv_event_t* e) {
lvgl_lock();
ctx->saveBuffer = lv_textarea_get_text(ctx->uiNoteText);
lvgl_unlock();
ctx->saveFileLaunchId = fileselection::startForExistingOrNewFile(ctx->appInstanceId);
ctx->saveFileLaunchId = fileselection::startForExistingOrNewFile(ctx->appInstanceId, ctx->saveResultStream, ctx->saveResultBuffer, sizeof(ctx->saveResultBuffer), ctx->eventGroup);
LOG_I(TAG, "launched with id %u", ctx->saveFileLaunchId);
break;
case 3: // Load
ctx->loadFileLaunchId = fileselection::startForExistingFile(ctx->appInstanceId);
ctx->loadFileLaunchId = fileselection::startForExistingFile(ctx->appInstanceId, ctx->loadResultStream, ctx->loadResultBuffer, sizeof(ctx->loadResultBuffer), ctx->eventGroup);
LOG_I(TAG, "launched with id %u", ctx->loadFileLaunchId);
break;
}
@@ -102,7 +111,7 @@ void appNotesEventCb(lv_event_t* e) {
auto* cont = lv_event_get_current_target_obj(e);
if (obj == cont) return;
if (lv_obj_get_child(cont, 1)) {
ctx->saveFileLaunchId = fileselection::startForExistingOrNewFile(ctx->appInstanceId);
ctx->saveFileLaunchId = fileselection::startForExistingOrNewFile(ctx->appInstanceId, ctx->saveResultStream, ctx->saveResultBuffer, sizeof(ctx->saveResultBuffer), ctx->eventGroup);
LOG_I(TAG, "launched with id %u", ctx->saveFileLaunchId);
} else { //Reset
resetFileContent(ctx);
@@ -189,6 +198,7 @@ int32_t appMain(int argc, char* argv[]) {
TaskEventGroup event_group {};
task_event_group_construct(&event_group);
ctx.eventGroup = &event_group;
AppEventSubscription sub {};
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
@@ -206,23 +216,35 @@ int32_t appMain(int argc, char* argv[]) {
shouldClose = true;
break;
case APP_EVENT_RESULT:
LOG_I(TAG, "Result for launch id %u", event.result.launch_id);
LOG_I(TAG, "Result for launch id %u = %u", event.result.launch_id, event.result.result);
if (event.result.launch_id == ctx.loadFileLaunchId) {
ctx.loadFileLaunchId = 0;
if (event.result.result == 0 /* Ok */) {
auto path = fileselection::getLastPath();
char destination[sizeof(ctx.loadResultBuffer)];
size_t length = app_stream_read(&ctx.loadResultStream, destination, sizeof(destination));
app_stream_unsubscribe(&ctx.loadResultStream);
auto path = std::string(destination, length);
LOG_I(TAG, "Path: '%s'", path.c_str());
if (!path.empty()) {
openFile(&ctx, path);
}
} else {
app_stream_unsubscribe(&ctx.loadResultStream);
}
} else if (event.result.launch_id == ctx.saveFileLaunchId) {
ctx.saveFileLaunchId = 0;
if (event.result.result == 0 /* Ok */) {
auto path = fileselection::getLastPath();
char destination[sizeof(ctx.saveResultBuffer)];
size_t length = app_stream_read(&ctx.saveResultStream, destination, sizeof(destination));
app_stream_unsubscribe(&ctx.saveResultStream);
auto path = std::string(destination, length);
// Must re-open file, because the UI was cleared after opening the dialog.
LOG_I(TAG, "Path: '%s'", path.c_str());
if (!path.empty() && saveFile(&ctx, path)) {
openFile(&ctx, path);
}
} else {
app_stream_unsubscribe(&ctx.saveResultStream);
}
}
app_manager_stop(event.result.launch_id);