mirror of https://gitlab.com/nakst/essence
remove loadedFoldersMutex; bugfixes
This commit is contained in:
parent
9ad6930ac7
commit
db3f454bba
|
@ -64,8 +64,11 @@ void CommandRename(Instance *instance, EsElement *, EsCommand *) {
|
||||||
|
|
||||||
EsDirectoryChild information = {};
|
EsDirectoryChild information = {};
|
||||||
EsPathQueryInformation(newPath, newPathBytes, &information);
|
EsPathQueryInformation(newPath, newPathBytes, &information);
|
||||||
|
EsMutexAcquire(&folder->modifyEntriesMutex);
|
||||||
|
EsAssert(folder->doneInitialEnumeration);
|
||||||
uint64_t id = FolderRemoveEntryAndUpdateInstances(folder, STRING(task->string2));
|
uint64_t id = FolderRemoveEntryAndUpdateInstances(folder, STRING(task->string2));
|
||||||
FolderAddEntryAndUpdateInstances(folder, STRING(task->string), &information, instance, false, id);
|
FolderAddEntryAndUpdateInstances(folder, STRING(task->string), &information, instance, id);
|
||||||
|
EsMutexRelease(&folder->modifyEntriesMutex);
|
||||||
|
|
||||||
EsHeapFree(oldPath);
|
EsHeapFree(oldPath);
|
||||||
EsHeapFree(newPath);
|
EsHeapFree(newPath);
|
||||||
|
@ -102,7 +105,10 @@ void CommandNewFolder(Instance *instance, EsElement *, EsCommand *) {
|
||||||
Folder *folder = instance->folder;
|
Folder *folder = instance->folder;
|
||||||
EsDirectoryChild information = {};
|
EsDirectoryChild information = {};
|
||||||
information.type = ES_NODE_DIRECTORY;
|
information.type = ES_NODE_DIRECTORY;
|
||||||
FolderAddEntryAndUpdateInstances(folder, STRING(task->string), &information, instance, false);
|
EsMutexAcquire(&folder->modifyEntriesMutex);
|
||||||
|
EsAssert(folder->doneInitialEnumeration);
|
||||||
|
FolderAddEntryAndUpdateInstances(folder, STRING(task->string), &information, instance);
|
||||||
|
EsMutexRelease(&folder->modifyEntriesMutex);
|
||||||
CommandRename(instance, nullptr, nullptr);
|
CommandRename(instance, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,9 +142,7 @@ void InstanceRegisterCommands(Instance *instance) {
|
||||||
}, stableCommandID++, "Alt+Up");
|
}, stableCommandID++, "Alt+Up");
|
||||||
|
|
||||||
EsCommandRegister(&instance->commandRefresh, instance, [] (Instance *instance, EsElement *, EsCommand *) {
|
EsCommandRegister(&instance->commandRefresh, instance, [] (Instance *instance, EsElement *, EsCommand *) {
|
||||||
EsMutexAcquire(&loadedFoldersMutex);
|
|
||||||
FolderRefresh(instance->folder);
|
FolderRefresh(instance->folder);
|
||||||
EsMutexRelease(&loadedFoldersMutex);
|
|
||||||
}, stableCommandID++, "F5");
|
}, stableCommandID++, "F5");
|
||||||
|
|
||||||
EsCommandRegister(&instance->commandNewFolder, instance, CommandNewFolder, stableCommandID++, "Ctrl+Shift+N");
|
EsCommandRegister(&instance->commandNewFolder, instance, CommandNewFolder, stableCommandID++, "Ctrl+Shift+N");
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
#define NAMESPACE_HANDLER_ROOT (3) // Acts as a container handler where needed.
|
#define NAMESPACE_HANDLER_ROOT (3) // Acts as a container handler where needed.
|
||||||
#define NAMESPACE_HANDLER_INVALID (4) // For when a folder does not exist.
|
#define NAMESPACE_HANDLER_INVALID (4) // For when a folder does not exist.
|
||||||
|
|
||||||
EsMutex loadedFoldersMutex;
|
|
||||||
Array<Folder *> loadedFolders;
|
Array<Folder *> loadedFolders;
|
||||||
|
|
||||||
#define MAXIMUM_FOLDERS_WITH_NO_ATTACHED_INSTANCES (20)
|
// #define MAXIMUM_FOLDERS_WITH_NO_ATTACHED_INSTANCES (20)
|
||||||
|
// TODO Temporary.
|
||||||
|
#define MAXIMUM_FOLDERS_WITH_NO_ATTACHED_INSTANCES (0)
|
||||||
Array<Folder *> foldersWithNoAttachedInstances;
|
Array<Folder *> foldersWithNoAttachedInstances;
|
||||||
|
|
||||||
/////////////////////////////////
|
/////////////////////////////////
|
||||||
|
@ -68,15 +69,16 @@ EsError FSDirEnumerate(Folder *folder) {
|
||||||
EsDirectoryChild *buffer = nullptr;
|
EsDirectoryChild *buffer = nullptr;
|
||||||
ptrdiff_t _entryCount = EsDirectoryEnumerateChildren(STRING(folder->path), &buffer);
|
ptrdiff_t _entryCount = EsDirectoryEnumerateChildren(STRING(folder->path), &buffer);
|
||||||
|
|
||||||
if (ES_CHECK_ERROR(_entryCount)) {
|
if (!ES_CHECK_ERROR(_entryCount)) {
|
||||||
EsHeapFree(buffer);
|
for (intptr_t i = 0; i < _entryCount; i++) {
|
||||||
return (EsError) _entryCount;
|
FolderAddEntry(folder, buffer[i].name, buffer[i].nameBytes, &buffer[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_entryCount = ES_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderAddEntries(folder, buffer, _entryCount);
|
|
||||||
EsHeapFree(buffer);
|
EsHeapFree(buffer);
|
||||||
|
return (EsError) _entryCount;
|
||||||
return ES_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSDirGetTotalSize(Folder *folder) {
|
void FSDirGetTotalSize(Folder *folder) {
|
||||||
|
@ -252,6 +254,8 @@ void NamespaceFindHandlersForPath(NamespaceHandler **itemHandler, NamespaceHandl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EsAssert(*itemHandler && *containerHandler); // NAMESPACE_HANDLER_INVALID should handle failure cases.
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t NamespaceGetIcon(String path) {
|
uint32_t NamespaceGetIcon(String path) {
|
||||||
|
@ -327,6 +331,10 @@ void FolderDestroy(Folder *folder) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringDestroy(&folder->path);
|
||||||
|
folder->attachedInstances.Free();
|
||||||
|
HashTableFree(&folder->entries, false);
|
||||||
|
EsMutexDestroy(&folder->modifyEntriesMutex);
|
||||||
EsHeapFree(folder);
|
EsHeapFree(folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,8 +343,10 @@ void FolderDetachInstance(Instance *instance) {
|
||||||
if (!folder) return;
|
if (!folder) return;
|
||||||
instance->folder = nullptr;
|
instance->folder = nullptr;
|
||||||
folder->attachedInstances.FindAndDeleteSwap(instance, true);
|
folder->attachedInstances.FindAndDeleteSwap(instance, true);
|
||||||
|
folder->referenceCount--;
|
||||||
|
|
||||||
if (!folder->attachedInstances.Length() && !folder->attachingInstances.Length()) {
|
if (!folder->referenceCount) {
|
||||||
|
EsAssert(!folder->attachedInstances.Length());
|
||||||
foldersWithNoAttachedInstances.Add(folder);
|
foldersWithNoAttachedInstances.Add(folder);
|
||||||
|
|
||||||
if (foldersWithNoAttachedInstances.Length() > MAXIMUM_FOLDERS_WITH_NO_ATTACHED_INSTANCES) {
|
if (foldersWithNoAttachedInstances.Length() > MAXIMUM_FOLDERS_WITH_NO_ATTACHED_INSTANCES) {
|
||||||
|
@ -391,16 +401,8 @@ FolderEntry *FolderAddEntry(Folder *folder, const char *_name, size_t nameBytes,
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderAddEntries(Folder *folder, EsDirectoryChild *buffer, size_t entryCount) {
|
|
||||||
for (uintptr_t i = 0; i < entryCount; i++) {
|
|
||||||
FolderAddEntry(folder, buffer[i].name, buffer[i].nameBytes, &buffer[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FolderAddEntryAndUpdateInstances(Folder *folder, const char *name, size_t nameBytes,
|
void FolderAddEntryAndUpdateInstances(Folder *folder, const char *name, size_t nameBytes,
|
||||||
EsDirectoryChild *information, Instance *selectItem, bool mutexAlreadyAcquired, uint64_t id = 0) {
|
EsDirectoryChild *information, Instance *selectItem, uint64_t id = 0) {
|
||||||
if (!mutexAlreadyAcquired) EsMutexAcquire(&loadedFoldersMutex);
|
|
||||||
|
|
||||||
if (folder->containerHandler->getTotalSize) {
|
if (folder->containerHandler->getTotalSize) {
|
||||||
folder->containerHandler->getTotalSize(folder);
|
folder->containerHandler->getTotalSize(folder);
|
||||||
}
|
}
|
||||||
|
@ -414,13 +416,9 @@ void FolderAddEntryAndUpdateInstances(Folder *folder, const char *name, size_t n
|
||||||
InstanceAddSingle(instance, listEntry);
|
InstanceAddSingle(instance, listEntry);
|
||||||
InstanceUpdateStatusString(instance);
|
InstanceUpdateStatusString(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mutexAlreadyAcquired) EsMutexRelease(&loadedFoldersMutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t FolderRemoveEntryAndUpdateInstances(Folder *folder, const char *name, size_t nameBytes) {
|
uint64_t FolderRemoveEntryAndUpdateInstances(Folder *folder, const char *name, size_t nameBytes) {
|
||||||
EsMutexAcquire(&loadedFoldersMutex);
|
|
||||||
|
|
||||||
FolderEntry *entry = (FolderEntry *) HashTableGetLong(&folder->entries, name, nameBytes);
|
FolderEntry *entry = (FolderEntry *) HashTableGetLong(&folder->entries, name, nameBytes);
|
||||||
uint64_t id = 0;
|
uint64_t id = 0;
|
||||||
|
|
||||||
|
@ -434,15 +432,12 @@ uint64_t FolderRemoveEntryAndUpdateInstances(Folder *folder, const char *name, s
|
||||||
FolderEntryCloseHandle(folder, entry);
|
FolderEntryCloseHandle(folder, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
EsMutexRelease(&loadedFoldersMutex);
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderPathMoved(Instance *instance, String oldPath, String newPath) {
|
void FolderPathMoved(Instance *instance, String oldPath, String newPath) {
|
||||||
_EsPathAnnouncePathMoved(instance, STRING(oldPath), STRING(newPath));
|
_EsPathAnnouncePathMoved(instance, STRING(oldPath), STRING(newPath));
|
||||||
|
|
||||||
EsMutexAcquire(&loadedFoldersMutex);
|
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
|
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
|
||||||
Folder *folder = loadedFolders[i];
|
Folder *folder = loadedFolders[i];
|
||||||
|
|
||||||
|
@ -453,8 +448,6 @@ void FolderPathMoved(Instance *instance, String oldPath, String newPath) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EsMutexRelease(&loadedFoldersMutex);
|
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < bookmarks.Length(); i++) {
|
for (uintptr_t i = 0; i < bookmarks.Length(); i++) {
|
||||||
PathReplacePrefix(&bookmarks[i], oldPath, newPath);
|
PathReplacePrefix(&bookmarks[i], oldPath, newPath);
|
||||||
}
|
}
|
||||||
|
@ -502,21 +495,12 @@ void FolderPathMoved(Instance *instance, String oldPath, String newPath) {
|
||||||
ConfigurationSave();
|
ConfigurationSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
EsError FolderAttachInstance(Instance *instance, String path, bool recurse, Folder **newFolder) {
|
void FolderAttachInstance(Instance *instance, String path, bool recurse) {
|
||||||
// TODO Don't modify attachedInstances/attachingInstances/loadedFolders without the message mutex!
|
|
||||||
// And then we can remove loadedFoldersMutex.
|
|
||||||
|
|
||||||
// (Called on the blocking task thread.)
|
|
||||||
|
|
||||||
Folder *folder = nullptr;
|
Folder *folder = nullptr;
|
||||||
NamespaceHandler *itemHandler = nullptr, *containerHandler = nullptr;
|
|
||||||
EsError error;
|
|
||||||
bool driveRemoved = false;
|
bool driveRemoved = false;
|
||||||
|
|
||||||
// Check if we've already loaded the folder.
|
// Check if we've already loaded the folder.
|
||||||
|
|
||||||
EsMutexAcquire(&loadedFoldersMutex);
|
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
|
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
|
||||||
if (StringEquals(loadedFolders[i]->path, path) && loadedFolders[i]->recurse == recurse) {
|
if (StringEquals(loadedFolders[i]->path, path) && loadedFolders[i]->recurse == recurse) {
|
||||||
if (!loadedFolders[i]->refreshing) {
|
if (!loadedFolders[i]->refreshing) {
|
||||||
|
@ -528,70 +512,39 @@ EsError FolderAttachInstance(Instance *instance, String path, bool recurse, Fold
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EsMutexRelease(&loadedFoldersMutex);
|
|
||||||
|
|
||||||
// Find the handler for the path.
|
|
||||||
|
|
||||||
NamespaceFindHandlersForPath(&itemHandler, &containerHandler, path);
|
|
||||||
|
|
||||||
if (!itemHandler || !containerHandler) {
|
|
||||||
return ES_ERROR_FILE_DOES_NOT_EXIST;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load a new folder.
|
|
||||||
|
|
||||||
folder = (Folder *) EsHeapAllocate(sizeof(Folder), true);
|
folder = (Folder *) EsHeapAllocate(sizeof(Folder), true);
|
||||||
|
|
||||||
folder->path = StringDuplicate(path);
|
folder->path = StringDuplicate(path);
|
||||||
folder->recurse = recurse;
|
folder->recurse = recurse;
|
||||||
folder->itemHandler = itemHandler;
|
NamespaceFindHandlersForPath(&folder->itemHandler, &folder->containerHandler, path);
|
||||||
folder->containerHandler = containerHandler;
|
|
||||||
folder->cEmptyMessage = interfaceString_FileManagerEmptyFolderView;
|
folder->cEmptyMessage = interfaceString_FileManagerEmptyFolderView;
|
||||||
folder->driveRemoved = driveRemoved;
|
folder->driveRemoved = driveRemoved;
|
||||||
|
|
||||||
EsArenaInitialise(&folder->entryArena, 1048576, sizeof(FolderEntry));
|
EsArenaInitialise(&folder->entryArena, 1048576, sizeof(FolderEntry));
|
||||||
|
|
||||||
// TODO Make this asynchronous for some folder providers, or recursive requests
|
|
||||||
// (that is, immediately present to the user while streaming data in).
|
|
||||||
error = itemHandler->enumerate(folder);
|
|
||||||
|
|
||||||
folder->driveRemoved = false;
|
|
||||||
folder->refreshing = false;
|
|
||||||
|
|
||||||
if (error != ES_SUCCESS) {
|
|
||||||
StringDestroy(&folder->path);
|
|
||||||
EsHeapFree(folder);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (containerHandler->getTotalSize) {
|
|
||||||
containerHandler->getTotalSize(folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
EsMutexAcquire(&loadedFoldersMutex);
|
|
||||||
loadedFolders.Add(folder);
|
loadedFolders.Add(folder);
|
||||||
|
|
||||||
success:;
|
success:;
|
||||||
|
|
||||||
foldersWithNoAttachedInstances.FindAndDeleteSwap(folder, false);
|
foldersWithNoAttachedInstances.FindAndDeleteSwap(folder, false);
|
||||||
folder->attachingInstances.Add(instance);
|
folder->referenceCount++;
|
||||||
|
FolderDetachInstance(instance);
|
||||||
EsMutexRelease(&loadedFoldersMutex);
|
instance->folder = folder;
|
||||||
|
|
||||||
*newFolder = folder;
|
|
||||||
return ES_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderRefresh(Folder *folder) {
|
void FolderRefresh(Folder *folder) {
|
||||||
// EsMutexAssertLocked(&loadedFoldersMutex);
|
|
||||||
|
|
||||||
if (folder->refreshing) {
|
if (folder->refreshing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
folder->refreshing = true;
|
folder->refreshing = true;
|
||||||
|
|
||||||
|
Array<Instance *> instancesToRefresh = {};
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < folder->attachedInstances.Length(); i++) {
|
for (uintptr_t i = 0; i < folder->attachedInstances.Length(); i++) {
|
||||||
InstanceLoadFolder(folder->attachedInstances[i], StringDuplicate(folder->path), LOAD_FOLDER_REFRESH);
|
instancesToRefresh.Add(folder->attachedInstances[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < instancesToRefresh.Length(); i++) {
|
||||||
|
InstanceLoadFolder(instancesToRefresh[i], StringDuplicate(folder->path), LOAD_FOLDER_REFRESH);
|
||||||
|
}
|
||||||
|
|
||||||
|
instancesToRefresh.Free();
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,7 +101,7 @@ struct HistoryEntry {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Drive {
|
struct Drive {
|
||||||
const char *prefix;
|
char *prefix;
|
||||||
size_t prefixBytes;
|
size_t prefixBytes;
|
||||||
EsVolumeInformation information;
|
EsVolumeInformation information;
|
||||||
};
|
};
|
||||||
|
@ -201,18 +201,20 @@ struct Folder {
|
||||||
EsArena entryArena;
|
EsArena entryArena;
|
||||||
|
|
||||||
Array<Instance *> attachedInstances;
|
Array<Instance *> attachedInstances;
|
||||||
Array<Instance *> attachingInstances;
|
uintptr_t referenceCount;
|
||||||
|
|
||||||
String path;
|
String path;
|
||||||
bool recurse;
|
bool recurse;
|
||||||
bool refreshing;
|
bool refreshing;
|
||||||
bool driveRemoved;
|
bool driveRemoved;
|
||||||
|
|
||||||
|
bool doneInitialEnumeration;
|
||||||
|
EsMutex modifyEntriesMutex;
|
||||||
|
|
||||||
EsFileOffset spaceTotal;
|
EsFileOffset spaceTotal;
|
||||||
EsFileOffset spaceUsed;
|
EsFileOffset spaceUsed;
|
||||||
|
|
||||||
NamespaceHandler *itemHandler, *containerHandler;
|
NamespaceHandler *itemHandler, *containerHandler;
|
||||||
|
|
||||||
const char *cEmptyMessage;
|
const char *cEmptyMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -409,6 +411,25 @@ void ConfigurationSave() {
|
||||||
#include "commands.cpp"
|
#include "commands.cpp"
|
||||||
#include "ui.cpp"
|
#include "ui.cpp"
|
||||||
|
|
||||||
|
void DriveRefreshFolders(bool removed, const char *prefix, size_t prefixBytes) {
|
||||||
|
Array<Folder *> foldersToRefresh = {};
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
|
||||||
|
Folder *folder = loadedFolders[i];
|
||||||
|
|
||||||
|
if (folder->itemHandler->type == NAMESPACE_HANDLER_DRIVES_PAGE || StringStartsWith(folder->path, StringFromLiteralWithSize(prefix, prefixBytes))) {
|
||||||
|
foldersToRefresh.Add(folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < foldersToRefresh.Length(); i++) {
|
||||||
|
foldersToRefresh[i]->driveRemoved = removed;
|
||||||
|
FolderRefresh(foldersToRefresh[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
foldersToRefresh.Free();
|
||||||
|
}
|
||||||
|
|
||||||
void DriveRemove(const char *prefix, size_t prefixBytes) {
|
void DriveRemove(const char *prefix, size_t prefixBytes) {
|
||||||
if (!prefixBytes || prefix[0] == '|') return;
|
if (!prefixBytes || prefix[0] == '|') return;
|
||||||
EsMutexAcquire(&drivesMutex);
|
EsMutexAcquire(&drivesMutex);
|
||||||
|
@ -416,6 +437,7 @@ void DriveRemove(const char *prefix, size_t prefixBytes) {
|
||||||
|
|
||||||
for (uintptr_t index = 0; index < drives.Length(); index++) {
|
for (uintptr_t index = 0; index < drives.Length(); index++) {
|
||||||
if (0 == EsStringCompareRaw(prefix, prefixBytes, drives[index].prefix, drives[index].prefixBytes)) {
|
if (0 == EsStringCompareRaw(prefix, prefixBytes, drives[index].prefix, drives[index].prefixBytes)) {
|
||||||
|
EsHeapFree(drives[index].prefix);
|
||||||
drives.Delete(index);
|
drives.Delete(index);
|
||||||
found = true;
|
found = true;
|
||||||
|
|
||||||
|
@ -429,20 +451,7 @@ void DriveRemove(const char *prefix, size_t prefixBytes) {
|
||||||
|
|
||||||
EsAssert(found);
|
EsAssert(found);
|
||||||
EsMutexRelease(&drivesMutex);
|
EsMutexRelease(&drivesMutex);
|
||||||
|
DriveRefreshFolders(true, prefix, prefixBytes);
|
||||||
EsMutexAcquire(&loadedFoldersMutex);
|
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
|
|
||||||
Folder *folder = loadedFolders[i];
|
|
||||||
|
|
||||||
if (folder->itemHandler->type == NAMESPACE_HANDLER_DRIVES_PAGE
|
|
||||||
|| StringStartsWith(folder->path, StringFromLiteralWithSize(prefix, prefixBytes))) {
|
|
||||||
folder->driveRemoved = true;
|
|
||||||
FolderRefresh(folder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EsMutexRelease(&loadedFoldersMutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DriveAdd(const char *prefix, size_t prefixBytes) {
|
void DriveAdd(const char *prefix, size_t prefixBytes) {
|
||||||
|
@ -451,7 +460,8 @@ void DriveAdd(const char *prefix, size_t prefixBytes) {
|
||||||
EsMutexAcquire(&drivesMutex);
|
EsMutexAcquire(&drivesMutex);
|
||||||
|
|
||||||
Drive drive = {};
|
Drive drive = {};
|
||||||
drive.prefix = prefix;
|
drive.prefix = (char *) EsHeapAllocate(prefixBytes, false);
|
||||||
|
EsMemoryCopy(drive.prefix, prefix, prefixBytes);
|
||||||
drive.prefixBytes = prefixBytes;
|
drive.prefixBytes = prefixBytes;
|
||||||
EsMountPointGetVolumeInformation(prefix, prefixBytes, &drive.information);
|
EsMountPointGetVolumeInformation(prefix, prefixBytes, &drive.information);
|
||||||
drives.Add(drive);
|
drives.Add(drive);
|
||||||
|
@ -461,13 +471,7 @@ void DriveAdd(const char *prefix, size_t prefixBytes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
EsMutexRelease(&drivesMutex);
|
EsMutexRelease(&drivesMutex);
|
||||||
|
DriveRefreshFolders(false, prefix, prefixBytes);
|
||||||
for (uintptr_t i = 0; i < instances.Length(); i++) {
|
|
||||||
if (instances[i]->folder->itemHandler->type == NAMESPACE_HANDLER_DRIVES_PAGE
|
|
||||||
|| StringStartsWith(instances[i]->folder->path, StringFromLiteralWithSize(prefix, prefixBytes))) {
|
|
||||||
FolderRefresh(instances[i]->folder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadSettings() {
|
void LoadSettings() {
|
||||||
|
@ -528,7 +532,6 @@ void _start() {
|
||||||
InstanceCreateUI(instance);
|
InstanceCreateUI(instance);
|
||||||
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
|
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
|
||||||
// TODO Cleanup/cancel any unfinished non-blocking tasks before we get here!
|
// TODO Cleanup/cancel any unfinished non-blocking tasks before we get here!
|
||||||
|
|
||||||
Instance *instance = message->instanceDestroy.instance;
|
Instance *instance = message->instanceDestroy.instance;
|
||||||
InstanceDestroy(instance);
|
InstanceDestroy(instance);
|
||||||
instances.FindAndDeleteSwap(instance, true);
|
instances.FindAndDeleteSwap(instance, true);
|
||||||
|
@ -549,15 +552,18 @@ void _start() {
|
||||||
EsDirectoryChild information = {};
|
EsDirectoryChild information = {};
|
||||||
|
|
||||||
if (EsPathQueryInformation(STRING(path), &information)) {
|
if (EsPathQueryInformation(STRING(path), &information)) {
|
||||||
EsMutexAcquire(&loadedFoldersMutex);
|
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
|
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
|
||||||
if (loadedFolders[i]->itemHandler->type != NAMESPACE_HANDLER_FILE_SYSTEM) continue;
|
if (loadedFolders[i]->itemHandler->type != NAMESPACE_HANDLER_FILE_SYSTEM) continue;
|
||||||
if (EsStringCompareRaw(STRING(loadedFolders[i]->path), STRING(folder))) continue;
|
if (EsStringCompareRaw(STRING(loadedFolders[i]->path), STRING(folder))) continue;
|
||||||
FolderAddEntryAndUpdateInstances(loadedFolders[i], file.text, file.bytes, &information, nullptr, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
EsMutexRelease(&loadedFoldersMutex);
|
EsMutexAcquire(&loadedFolders[i]->modifyEntriesMutex);
|
||||||
|
|
||||||
|
if (loadedFolders[i]->doneInitialEnumeration) {
|
||||||
|
FolderAddEntryAndUpdateInstances(loadedFolders[i], file.text, file.bytes, &information, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
EsMutexRelease(&loadedFolders[i]->modifyEntriesMutex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,37 +23,46 @@ void InstanceFolderPathChanged(Instance *instance, bool fromLoadFolder) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstanceLoadFolder(Instance *instance, String path /* takes ownership */, int historyMode) {
|
bool InstanceLoadFolder(Instance *instance, String path /* takes ownership */, int historyMode) {
|
||||||
// Check if the path hasn't changed.
|
|
||||||
|
|
||||||
if (instance->folder && !instance->folder->refreshing && StringEquals(path, instance->folder->path)) {
|
if (instance->folder && !instance->folder->refreshing && StringEquals(path, instance->folder->path)) {
|
||||||
|
// The path hasn't changed; ignore.
|
||||||
StringDestroy(&path);
|
StringDestroy(&path);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InstanceRemoveContents(instance);
|
||||||
|
FolderAttachInstance(instance, path, false);
|
||||||
|
StringDestroy(&path);
|
||||||
|
|
||||||
Task task = {};
|
Task task = {};
|
||||||
|
|
||||||
task.context = historyMode;
|
task.context = historyMode;
|
||||||
task.string = path;
|
|
||||||
task.cDescription = interfaceString_FileManagerOpenFolderTask;
|
task.cDescription = interfaceString_FileManagerOpenFolderTask;
|
||||||
|
|
||||||
task.callback = [] (Instance *instance, Task *task) {
|
task.callback = [] (Instance *instance, Task *) {
|
||||||
Folder *newFolder = nullptr;
|
Folder *folder = instance->folder;
|
||||||
task->result = FolderAttachInstance(instance, task->string, false, &newFolder);
|
EsMutexAcquire(&folder->modifyEntriesMutex);
|
||||||
task->context2 = newFolder;
|
|
||||||
StringDestroy(&task->string);
|
if (!folder->doneInitialEnumeration) {
|
||||||
|
folder->itemHandler->enumerate(folder);
|
||||||
|
|
||||||
|
if (folder->containerHandler->getTotalSize) {
|
||||||
|
folder->containerHandler->getTotalSize(folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
folder->driveRemoved = false;
|
||||||
|
folder->refreshing = false;
|
||||||
|
folder->doneInitialEnumeration = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
EsMutexRelease(&folder->modifyEntriesMutex);
|
||||||
};
|
};
|
||||||
|
|
||||||
task.then = [] (Instance *instance, Task *task) {
|
task.then = [] (Instance *instance, Task *task) {
|
||||||
if (ES_CHECK_ERROR(task->result)) {
|
// TODO Check if folder was marked for refresh.
|
||||||
EsTextboxSelectAll(instance->breadcrumbBar);
|
|
||||||
EsTextboxInsert(instance->breadcrumbBar, STRING(instance->path));
|
|
||||||
InstanceReportError(instance, ERROR_LOAD_FOLDER, task->result);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int historyMode = task->context.i & 0xFF;
|
int historyMode = task->context.i & 0xFF;
|
||||||
int flags = task->context.i;
|
int flags = task->context.i;
|
||||||
Folder *folder = (Folder *) task->context2.p;
|
Folder *folder = instance->folder;
|
||||||
|
folder->attachedInstances.Add(instance);
|
||||||
|
|
||||||
// Add the path to the history array.
|
// Add the path to the history array.
|
||||||
|
|
||||||
|
@ -92,13 +101,6 @@ bool InstanceLoadFolder(Instance *instance, String path /* takes ownership */, i
|
||||||
EsCommandSetDisabled(&instance->commandRename, true);
|
EsCommandSetDisabled(&instance->commandRename, true);
|
||||||
EsCommandSetDisabled(&instance->commandRefresh, false);
|
EsCommandSetDisabled(&instance->commandRefresh, false);
|
||||||
|
|
||||||
// Detach from the old folder.
|
|
||||||
|
|
||||||
EsMutexAcquire(&loadedFoldersMutex);
|
|
||||||
|
|
||||||
InstanceRemoveContents(instance);
|
|
||||||
FolderDetachInstance(instance);
|
|
||||||
|
|
||||||
// Load the view settings for the folder.
|
// Load the view settings for the folder.
|
||||||
|
|
||||||
bool foundViewSettings = false;
|
bool foundViewSettings = false;
|
||||||
|
@ -129,24 +131,13 @@ bool InstanceLoadFolder(Instance *instance, String path /* takes ownership */, i
|
||||||
|
|
||||||
InstanceRefreshViewType(instance);
|
InstanceRefreshViewType(instance);
|
||||||
|
|
||||||
// Attach to the new folder.
|
// Update the user interface.
|
||||||
|
|
||||||
folder->attachingInstances.FindAndDeleteSwap(instance, true);
|
|
||||||
instance->folder = folder;
|
|
||||||
folder->attachedInstances.Add(instance);
|
|
||||||
|
|
||||||
EsListViewSetEmptyMessage(instance->list, folder->cEmptyMessage);
|
EsListViewSetEmptyMessage(instance->list, folder->cEmptyMessage);
|
||||||
InstanceAddContents(instance, &folder->entries);
|
InstanceAddContents(instance, &folder->entries);
|
||||||
|
|
||||||
EsMutexRelease(&loadedFoldersMutex);
|
|
||||||
|
|
||||||
InstanceFolderPathChanged(instance, true);
|
InstanceFolderPathChanged(instance, true);
|
||||||
|
|
||||||
if (~flags & LOAD_FOLDER_NO_FOCUS) {
|
|
||||||
EsElementFocus(instance->list);
|
|
||||||
}
|
|
||||||
|
|
||||||
EsListViewInvalidateAll(instance->placesView);
|
EsListViewInvalidateAll(instance->placesView);
|
||||||
|
if (~flags & LOAD_FOLDER_NO_FOCUS) EsElementFocus(instance->list);
|
||||||
};
|
};
|
||||||
|
|
||||||
BlockingTaskQueue(instance, task);
|
BlockingTaskQueue(instance, task);
|
||||||
|
@ -277,7 +268,7 @@ void InstanceUpdateStatusString(Instance *instance) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceAddSingle(Instance *instance, ListEntry entry) {
|
void InstanceAddSingle(Instance *instance, ListEntry entry) {
|
||||||
// Call with loadedFoldersMutex and message mutex.
|
// Call with the message mutex acquired.
|
||||||
|
|
||||||
if (!InstanceAddInternal(instance, &entry)) {
|
if (!InstanceAddInternal(instance, &entry)) {
|
||||||
return; // Filtered out.
|
return; // Filtered out.
|
||||||
|
@ -326,7 +317,7 @@ ES_MACRO_SORT(InstanceSortListContents, ListEntry, {
|
||||||
}, uint16_t);
|
}, uint16_t);
|
||||||
|
|
||||||
void InstanceAddContents(Instance *instance, HashTable *newEntries) {
|
void InstanceAddContents(Instance *instance, HashTable *newEntries) {
|
||||||
// Call with loadedFoldersMutex and message mutex.
|
// Call with the message mutex acquired.
|
||||||
|
|
||||||
size_t oldListEntryCount = instance->listContents.Length();
|
size_t oldListEntryCount = instance->listContents.Length();
|
||||||
|
|
||||||
|
|
|
@ -742,7 +742,7 @@ EsMessage *EsMessageReceive() {
|
||||||
elements.Free();
|
elements.Free();
|
||||||
}
|
}
|
||||||
|
|
||||||
instance->commands.Free(false);
|
instance->commands.Free();
|
||||||
if (instance->fileStore) FileStoreCloseHandle(instance->fileStore);
|
if (instance->fileStore) FileStoreCloseHandle(instance->fileStore);
|
||||||
EsHeapFree(instance);
|
EsHeapFree(instance);
|
||||||
EsHeapFree(message.message.instanceDestroy.instance);
|
EsHeapFree(message.message.instanceDestroy.instance);
|
||||||
|
|
|
@ -116,6 +116,7 @@ struct InstalledApplication {
|
||||||
uint64_t permissions;
|
uint64_t permissions;
|
||||||
size_t openInstanceCount; // Only used if useSingleProcess is true.
|
size_t openInstanceCount; // Only used if useSingleProcess is true.
|
||||||
EsHandle singleProcessHandle;
|
EsHandle singleProcessHandle;
|
||||||
|
bool notified; // Temporary flag.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CrashedTabInstance : EsInstance {
|
struct CrashedTabInstance : EsInstance {
|
||||||
|
@ -2010,19 +2011,31 @@ void DesktopMessage(EsMessage *message) {
|
||||||
for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) {
|
for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) {
|
||||||
ApplicationInstance *instance = desktop.allApplicationInstances[i];
|
ApplicationInstance *instance = desktop.allApplicationInstances[i];
|
||||||
|
|
||||||
if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_ALL_FILES) && instance->processHandle) {
|
if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_ALL_FILES)
|
||||||
|
&& instance->processHandle && !instance->application->notified) {
|
||||||
message->registerFileSystem.rootDirectory = EsSyscall(ES_SYSCALL_NODE_SHARE, rootDirectory, instance->processHandle, 0, 0);
|
message->registerFileSystem.rootDirectory = EsSyscall(ES_SYSCALL_NODE_SHARE, rootDirectory, instance->processHandle, 0, 0);
|
||||||
EsMessagePostRemote(instance->processHandle, message);
|
EsMessagePostRemote(instance->processHandle, message);
|
||||||
|
if (instance->application->useSingleProcess) instance->application->notified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) {
|
||||||
|
desktop.installedApplications[i]->notified = false;
|
||||||
|
}
|
||||||
} else if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM) {
|
} else if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM) {
|
||||||
for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) {
|
for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) {
|
||||||
ApplicationInstance *instance = desktop.allApplicationInstances[i];
|
ApplicationInstance *instance = desktop.allApplicationInstances[i];
|
||||||
|
|
||||||
if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_ALL_FILES) && instance->processHandle) {
|
if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_ALL_FILES)
|
||||||
|
&& instance->processHandle && !instance->application->notified) {
|
||||||
EsMessagePostRemote(instance->processHandle, message);
|
EsMessagePostRemote(instance->processHandle, message);
|
||||||
|
if (instance->application->useSingleProcess) instance->application->notified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) {
|
||||||
|
desktop.installedApplications[i]->notified = false;
|
||||||
|
}
|
||||||
} else if (message->type == ES_MSG_DEVICE_CONNECTED) {
|
} else if (message->type == ES_MSG_DEVICE_CONNECTED) {
|
||||||
desktop.connectedDevices.Add(message->device);
|
desktop.connectedDevices.Add(message->device);
|
||||||
} else if (message->type == ES_MSG_DEVICE_DISCONNECTED) {
|
} else if (message->type == ES_MSG_DEVICE_DISCONNECTED) {
|
||||||
|
|
|
@ -349,7 +349,7 @@ bool HashStoreDelete(HashTable *table, HashStoreOptions *options, const void *ke
|
||||||
|
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
|
|
||||||
template <class K /* set to char * for long keys */, class V>
|
template <class K /* set to char for long keys */, class V>
|
||||||
struct HashStore {
|
struct HashStore {
|
||||||
HashTable table;
|
HashTable table;
|
||||||
|
|
||||||
|
@ -393,8 +393,8 @@ struct HashStore {
|
||||||
return HashStoreDelete(&table, &options, k, bytes);
|
return HashStoreDelete(&table, &options, k, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Free(bool variableLengthKeys) {
|
inline void Free() {
|
||||||
HashTableFree(&table, variableLengthKeys);
|
HashTableFree(&table, sizeof(K) == 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue