95 lines
3.6 KiB
C++
95 lines
3.6 KiB
C++
/*
|
|
* associations.cpp
|
|
* File type associations for the Files file manager
|
|
* Copyright (c) 2026 Daniel Hammer
|
|
*/
|
|
|
|
#include "filemanager_internal.hpp"
|
|
#include <montauk/config.h>
|
|
#include <gui/app_catalog.hpp>
|
|
|
|
namespace filemanager {
|
|
|
|
// Resolution is shared with the desktop (gui/app_catalog.hpp).
|
|
static bool assoc_item_launchable(const DesktopState* ds, const DesktopItem& item) {
|
|
return gui::app_catalog_launchable(ds, item);
|
|
}
|
|
|
|
static bool assoc_item_claims(const DesktopItem& item, const char* ext) {
|
|
return gui::app_catalog_claims(item, ext);
|
|
}
|
|
|
|
int filemanager_assoc_default(DesktopState* ds, const char* ext) {
|
|
return gui::app_catalog_default_for(ds, ext);
|
|
}
|
|
|
|
int filemanager_assoc_candidates(DesktopState* ds, const char* ext,
|
|
int* out, int max, int* recommended) {
|
|
if (recommended) *recommended = 0;
|
|
if (!ds || !out || max <= 0 || ds->desktop_item_count <= 0) return 0;
|
|
|
|
int* sorted = (int*)montauk::malloc((uint64_t)ds->desktop_item_count * sizeof(int));
|
|
if (!sorted) return 0;
|
|
int n = 0;
|
|
for (int i = 0; i < ds->desktop_item_count; i++) {
|
|
if (assoc_item_launchable(ds, ds->desktop_items[i])) sorted[n++] = i;
|
|
}
|
|
for (int i = 1; i < n; i++) {
|
|
int tmp = sorted[i];
|
|
int j = i - 1;
|
|
while (j >= 0 && str_compare_ci(ds->desktop_items[tmp].name,
|
|
ds->desktop_items[sorted[j]].name) < 0) {
|
|
sorted[j + 1] = sorted[j];
|
|
j--;
|
|
}
|
|
sorted[j + 1] = tmp;
|
|
}
|
|
|
|
// Apps that declare the type lead; any other regular app follows (an app
|
|
// that declares nothing may still open the file). Hidden and settings
|
|
// items only appear when they claim the type.
|
|
int count = 0;
|
|
for (int i = 0; i < n && count < max; i++) {
|
|
if (assoc_item_claims(ds->desktop_items[sorted[i]], ext)) out[count++] = sorted[i];
|
|
}
|
|
if (recommended) *recommended = count;
|
|
for (int i = 0; i < n && count < max; i++) {
|
|
const DesktopItem& item = ds->desktop_items[sorted[i]];
|
|
if (item.section == DESKTOP_ITEM_SECTION_APPS && !assoc_item_claims(item, ext))
|
|
out[count++] = sorted[i];
|
|
}
|
|
|
|
montauk::mfree(sorted);
|
|
return count;
|
|
}
|
|
|
|
bool filemanager_assoc_set_default(DesktopState* ds, const char* ext, int item_index) {
|
|
if (!ds || !ds->current_user[0] || !gui::app_catalog_ext_storable(ext)) return false;
|
|
if (item_index < 0 || item_index >= ds->desktop_item_count) return false;
|
|
|
|
auto doc = montauk::config::load_user(ds->current_user, gui::kAssociationsConfig);
|
|
char key[48];
|
|
gui::app_catalog_assoc_key(key, sizeof(key), ext);
|
|
montauk::config::set_string(&doc, key, ds->desktop_items[item_index].id);
|
|
int rc = montauk::config::save_user(ds->current_user, gui::kAssociationsConfig, &doc);
|
|
doc.destroy();
|
|
return rc == 0;
|
|
}
|
|
|
|
bool filemanager_file_looks_textual(const char* path) {
|
|
return gui::app_catalog_file_looks_textual(path);
|
|
}
|
|
|
|
bool filemanager_launch_with(DesktopState* ds, int item_index, const char* path) {
|
|
if (!ds || item_index < 0 || item_index >= ds->desktop_item_count) return false;
|
|
const DesktopItem& item = ds->desktop_items[item_index];
|
|
if (!assoc_item_launchable(ds, item)) return false;
|
|
// Apps that declare file types are started by the desktop, with the
|
|
// authority they get from the launcher. The desktop forwards a document
|
|
// path only to those, so anything else is started here.
|
|
if (item.file_types[0]) return files_host::launch_item(item.id, path);
|
|
return desktop_spawn_app(ds, item.binary_path, path) >= 0;
|
|
}
|
|
|
|
} // namespace filemanager
|