feat: filesystem and Files app support for >64 file entries, 64-bit sizes, async ops, GUI toolkit improvements to devexplorer app

This commit is contained in:
2026-06-07 09:33:46 +02:00
parent 6554ef7e15
commit 3d620673c0
27 changed files with 1110 additions and 293 deletions
@@ -41,8 +41,9 @@ struct FileDeleteConfirmDialogState {
char path[512]; // primary path (used for single-item subtitle)
SvgIcon icon;
// Multi-item targets. count == 1 keeps the original single-folder UX.
char paths[64][512];
// Multi-item targets (dynamically allocated). count == 1 keeps the original
// single-folder UX.
char (*paths)[512];
int count;
};
@@ -87,12 +88,12 @@ static void props_close_self(DesktopState* ds, void* app_data) {
}
}
static void props_center_dialog(DesktopState* ds,
const void* owner_app_data,
int w,
int h,
int* out_x,
int* out_y) {
void props_center_dialog(DesktopState* ds,
const void* owner_app_data,
int w,
int h,
int* out_x,
int* out_y) {
if (!out_x || !out_y) return;
int wx = 180;
@@ -441,22 +442,38 @@ static void delete_confirm_apply(FileDeleteConfirmDialogState* st) {
if (!st) return;
FileManagerState* owner = delete_confirm_live_owner(st);
bool any = false;
int n = st->count > 0 ? st->count : (st->path[0] ? 1 : 0);
for (int i = 0; i < n; i++) {
const char* p = (st->count > 0) ? st->paths[i] : st->path;
if (!p || !p[0]) continue;
if (filemanager_delete_recursive(p)) any = true;
// Delete on a worker thread with a progress dialog. The job copies the path
// list, so it stays valid after this confirm dialog is freed.
bool started = false;
if (owner && n > 0) {
const char** arr = (const char**)montauk::malloc((uint64_t)n * sizeof(const char*));
if (arr) {
for (int i = 0; i < n; i++)
arr[i] = (st->count > 0) ? st->paths[i] : st->path;
started = filemanager_start_delete_job(owner, arr, n);
montauk::mfree(arr);
}
}
if (owner) {
if (owner->delete_confirm_dialog == st)
owner->delete_confirm_dialog = nullptr;
if (any) {
if (!started) {
// Fallback: delete synchronously (e.g. another operation is running).
bool any = false;
for (int i = 0; i < n; i++) {
const char* p = (st->count > 0) ? st->paths[i] : st->path;
if (!p || !p[0]) continue;
if (filemanager_delete_recursive(p)) any = true;
}
if (owner && any) {
filemanager_clear_multi_selection(owner);
filemanager_read_dir(owner);
}
}
if (owner && owner->delete_confirm_dialog == st)
owner->delete_confirm_dialog = nullptr;
delete_confirm_close(st);
}
@@ -560,6 +577,7 @@ static void delete_confirm_on_close(Window* win) {
if (owner && owner->delete_confirm_dialog == st)
owner->delete_confirm_dialog = nullptr;
if (st->paths) montauk::mfree(st->paths);
montauk::mfree(st);
win->app_data = nullptr;
}
@@ -650,8 +668,14 @@ void filemanager_show_bulk_delete_confirmation(FileManagerState* fm,
st->owner = fm;
st->accent = ds->settings.accent_color;
st->paths = (char(*)[512])montauk::malloc((uint64_t)count * 512);
if (!st->paths) {
montauk::mfree(st);
return;
}
int out = 0;
for (int i = 0; i < count && out < 64; i++) {
for (int i = 0; i < count; i++) {
int idx = indices[i];
if (idx < 0 || idx >= fm->entry_count) continue;
if (fm->entry_types[idx] == FM_ENTRY_DRIVE) continue;
@@ -660,6 +684,7 @@ void filemanager_show_bulk_delete_confirmation(FileManagerState* fm,
out++;
}
if (out == 0) {
montauk::mfree(st->paths);
montauk::mfree(st);
return;
}
@@ -803,7 +828,7 @@ void filemanager_show_multi_properties(FileManagerState* fm,
st->desktop = ds;
st->accent = ds->settings.accent_color;
int total_size = 0;
uint64_t total_size = 0;
bool any_file = false;
for (int i = 0; i < count; i++) {
int idx = indices[i];