open document reference counting

This commit is contained in:
nakst 2021-08-25 09:54:14 +01:00
parent 56bd531f66
commit b8731dc27e
5 changed files with 129 additions and 30 deletions

View File

@ -987,8 +987,7 @@ void EsInstanceSaveComplete(EsMessage *message, bool success) {
}
if (success) {
message->instanceSave.file->error = EsFileControl(message->instanceSave.file->handle,
ES_FILE_CONTROL_NOTIFY_MONITORS | ES_FILE_CONTROL_FLUSH);
message->instanceSave.file->error = EsFileControl(message->instanceSave.file->handle, ES_FILE_CONTROL_FLUSH);
if (message->instanceSave.file->error != ES_SUCCESS) {
success = false;

View File

@ -5,8 +5,6 @@
// - New tab page - search; recent files.
// - Right click menu.
// - Duplicate tabs.
// - If a process exits, its tabs won't close because Desktop has a handle.
// - Also clear any OpenDocument currentWriter fields it owns.
// TODO Graphical issues:
// - New tab button isn't flush with right border when tab band full.
@ -31,6 +29,7 @@
// TODO Only let File Manager read the file_type sections of the system configuration.
// TODO Restarting Desktop if it crashes.
// TODO Make sure applications can't delete |Fonts: and |Themes:.
// TODO Handle open document deletion.
#define MSG_SETUP_DESKTOP_UI ((EsMessageType) (ES_MSG_USER_START + 1))
@ -105,6 +104,7 @@ struct OpenDocument {
EsHandle readHandle;
EsObjectID id;
EsObjectID currentWriter;
uintptr_t referenceCount;
};
struct InstalledApplication {
@ -122,10 +122,14 @@ struct InstalledApplication {
bool notified; // Temporary flag.
};
struct CrashedTabInstance : EsInstance {
struct CommonDesktopInstance : EsInstance {
void (*destroy)(EsInstance *);
};
struct BlankTabInstance : EsInstance {
struct CrashedTabInstance : CommonDesktopInstance {
};
struct BlankTabInstance : CommonDesktopInstance {
};
struct ApplicationInstance {
@ -184,6 +188,8 @@ struct {
EsObjectID nextClipboardProcessID;
EsHandle clipboardFile;
ClipboardInformation clipboardInformation;
bool configurationModified;
} desktop;
int TaskBarButtonMessage(EsElement *element, EsMessage *message);
@ -192,6 +198,9 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma
void ApplicationInstanceClose(ApplicationInstance *instance);
ApplicationInstance *ApplicationInstanceFindByWindowID(EsObjectID windowID, bool remove = false);
void EmbeddedWindowDestroyed(EsObjectID id);
void ConfigurationWriteToFile();
void OpenDocumentOpenReference(EsObjectID id);
void OpenDocumentCloseReference(EsObjectID id);
#include "settings.cpp"
@ -908,6 +917,11 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma
instance->processHandle = ES_INVALID_HANDLE;
}
if (instance->documentID) {
OpenDocumentCloseReference(instance->documentID);
instance->documentID = 0;
}
instance->application = application;
if (application->useSingleProcess && application->singleProcessHandle) {
@ -1017,6 +1031,11 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma
instance->processID = EsProcessGetID(process);
instance->processHandle = EsSyscall(ES_SYSCALL_PROCESS_SHARE, process, ES_CURRENT_PROCESS, 0, 0);
if (startupInformation->documentID) {
instance->documentID = startupInformation->documentID;
OpenDocumentOpenReference(instance->documentID);
}
EsMessage m = { ES_MSG_INSTANCE_CREATE };
if (~startupInformation->flags & ES_APPLICATION_STARTUP_MANUAL_PATH) {
@ -1077,9 +1096,16 @@ ApplicationInstance *ApplicationInstanceCreate(int64_t id, EsApplicationStartupI
instance->titleBytes = 1;
instance->tab = tab;
desktop.allApplicationInstances.Add(instance);
ApplicationInstanceStart(id, startupInformation, instance);
if (!hidden) WindowTabActivate(tab);
return instance;
if (ApplicationInstanceStart(id, startupInformation, instance)) {
if (!hidden) WindowTabActivate(tab);
return instance;
} else {
// TODO Destroy the tab/container window.
// Or, we probably didn't want to create them in the first place.
EsHeapFree(instance);
return nullptr;
}
}
void ApplicationTemporaryDestroy(InstalledApplication *application) {
@ -1171,15 +1197,39 @@ void ApplicationProcessTerminated(EsObjectID pid) {
break;
}
}
for (uintptr_t i = 0; i < desktop.openDocuments.Count(); i++) {
OpenDocument *document = &desktop.openDocuments[i];
if (document->currentWriter == pid) {
document->currentWriter = 0;
}
}
}
//////////////////////////////////////////////////////
// Document management:
//////////////////////////////////////////////////////
void OpenDocumentCloseReference(EsObjectID id) {
OpenDocument *document = desktop.openDocuments.Get(&id);
EsAssert(document->referenceCount && document->referenceCount < 0x10000000 /* sanity check */);
document->referenceCount--;
if (document->referenceCount) return;
EsHeapFree(document->path);
EsHeapFree(document->temporarySavePath);
EsHandleClose(document->readHandle);
desktop.openDocuments.Delete(&id);
}
void OpenDocumentOpenReference(EsObjectID id) {
OpenDocument *document = desktop.openDocuments.Get(&id);
EsAssert(document->referenceCount && document->referenceCount < 0x10000000 /* sanity check */);
document->referenceCount++;
}
void OpenDocumentWithApplication(EsApplicationStartupInformation *startupInformation) {
bool foundDocument = false;
EsObjectID documentID;
for (uintptr_t i = 0; i < desktop.openDocuments.Count(); i++) {
OpenDocument *document = &desktop.openDocuments[i];
@ -1188,7 +1238,8 @@ void OpenDocumentWithApplication(EsApplicationStartupInformation *startupInforma
&& 0 == EsMemoryCompare(document->path, startupInformation->filePath, document->pathBytes)) {
foundDocument = true;
startupInformation->readHandle = document->readHandle;
documentID = document->id;
startupInformation->documentID = document->id;
document->referenceCount++;
break;
}
}
@ -1207,18 +1258,16 @@ void OpenDocumentWithApplication(EsApplicationStartupInformation *startupInforma
document.pathBytes = startupInformation->filePathBytes;
document.readHandle = file.handle;
document.id = ++desktop.currentDocumentID;
documentID = document.id;
document.referenceCount = 1;
EsMemoryCopy(document.path, startupInformation->filePath, startupInformation->filePathBytes);
*desktop.openDocuments.Put(&document.id) = document;
startupInformation->readHandle = document.readHandle;
startupInformation->documentID = document.id;
}
ApplicationInstance *instance = ApplicationInstanceCreate(startupInformation->id, startupInformation, nullptr);
if (instance) {
instance->documentID = documentID;
}
ApplicationInstanceCreate(startupInformation->id, startupInformation, nullptr);
OpenDocumentCloseReference(startupInformation->documentID);
}
EsError TemporaryFileCreate(EsHandle *handle, char **path, size_t *pathBytes) {
@ -1319,6 +1368,9 @@ void ApplicationInstanceRequestSave(ApplicationInstance *instance, const char *n
if (document->currentWriter) {
m.tabOperation.error = ES_ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE;
} else {
EsHeapFree(document->temporarySavePath);
document->temporarySavePath = nullptr;
EsHandle fileHandle;
m.tabOperation.error = TemporaryFileCreate(&fileHandle, &document->temporarySavePath, &document->temporarySavePathBytes);
@ -1526,7 +1578,7 @@ void ConfigurationLoadApplications() {
}, 0);
}
void ConfigurationWriteSectionsToBuffer(const char *sectionClass, const char *section, EsBuffer *pipe) {
void ConfigurationWriteSectionsToBuffer(const char *sectionClass, const char *section, bool includeComments, EsBuffer *pipe) {
char buffer[4096];
EsMutexAcquire(&api.systemConfigurationMutex);
@ -1547,7 +1599,7 @@ void ConfigurationWriteSectionsToBuffer(const char *sectionClass, const char *se
for (uintptr_t i = 0; i < group->itemCount; i++) {
EsSystemConfigurationItem *item = group->items + i;
if (!item->keyBytes || item->key[0] == ';') {
if ((!item->keyBytes || item->key[0] == ';') && !includeComments) {
continue;
}
@ -1561,6 +1613,37 @@ void ConfigurationWriteSectionsToBuffer(const char *sectionClass, const char *se
EsMutexRelease(&api.systemConfigurationMutex);
}
void ConfigurationWriteToFile() {
if (!desktop.configurationModified) {
return;
}
EsBuffer buffer = { .canGrow = true };
ConfigurationWriteSectionsToBuffer(nullptr, nullptr, true /* include comments */, &buffer);
if (!buffer.error) {
if (ES_SUCCESS == EsFileWriteAll(EsLiteral(K_SYSTEM_CONFIGURATION "_"), buffer.out, buffer.position)) {
// TODO Atomic delete and move.
if (ES_SUCCESS == EsPathDelete(EsLiteral(K_SYSTEM_CONFIGURATION))) {
if (ES_SUCCESS == EsPathMove(EsLiteral(K_SYSTEM_CONFIGURATION "_"), EsLiteral(K_SYSTEM_CONFIGURATION))) {
EsPrint("ConfigurationWriteToFile - New configuration successfully written.\n");
desktop.configurationModified = true;
} else {
EsPrint("ConfigurationWriteToFile - Error while moving to final path.\n");
}
} else {
EsPrint("ConfigurationWriteToFile - Error while deleting old file.\n");
}
} else {
EsPrint("ConfigurationWriteToFile - Error while writing to file.\n");
}
} else {
EsPrint("ConfigurationWriteToFile - Error while writing to buffer.\n");
}
EsHeapFree(buffer.out);
}
//////////////////////////////////////////////////////
// Image utilities:
//////////////////////////////////////////////////////
@ -1885,8 +1968,8 @@ void DesktopMessage2(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
EsHandleClose(processHandle);
}
} else if (buffer[0] == DESKTOP_MSG_SYSTEM_CONFIGURATION_GET && pipe) {
ConfigurationWriteSectionsToBuffer("font", nullptr, pipe);
ConfigurationWriteSectionsToBuffer(nullptr, "ui", pipe);
ConfigurationWriteSectionsToBuffer("font", nullptr, false, pipe);
ConfigurationWriteSectionsToBuffer(nullptr, "ui", false, pipe);
} else if (buffer[0] == DESKTOP_MSG_REQUEST_SHUTDOWN) {
InstalledApplication *application = ApplicationFindByPID(message->desktop.processID);
@ -1897,7 +1980,7 @@ void DesktopMessage2(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
InstalledApplication *application = ApplicationFindByPID(message->desktop.processID);
if (application && (application->permissions & APPLICATION_PERMISSION_VIEW_FILE_TYPES)) {
ConfigurationWriteSectionsToBuffer("file_type", nullptr, pipe);
ConfigurationWriteSectionsToBuffer("file_type", nullptr, false, pipe);
}
} else if (!instance) {
// -------------------------------------------------
@ -1965,8 +2048,6 @@ void DesktopMessage2(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
}
void EmbeddedWindowDestroyed(EsObjectID id) {
// TODO Close open documents.
EsMenuCloseAll();
ApplicationInstance *instance = ApplicationInstanceFindByWindowID(id, true /* remove if found */);
if (!instance) return;
@ -1974,6 +2055,10 @@ void EmbeddedWindowDestroyed(EsObjectID id) {
EsHandleClose(instance->embeddedWindowHandle);
if (instance->processHandle) EsHandleClose(instance->processHandle);
if (instance->documentID) {
OpenDocumentCloseReference(instance->documentID);
}
InstalledApplication *application = instance->application;
if (application && application->singleInstance) {
@ -2126,6 +2211,12 @@ void DesktopMessage(EsMessage *message) {
EsSyscall(ES_SYSCALL_WINDOW_MOVE, window->handle, (uintptr_t) &bounds, 0, ES_WINDOW_MOVE_ALWAYS_ON_TOP);
wrapper->StartAnimating();
}
} else if (message->type == ES_MSG_INSTANCE_DESTROY) {
CommonDesktopInstance *instance = (CommonDesktopInstance *) message->instanceDestroy.instance;
if (instance->destroy) {
instance->destroy(instance);
}
} else if (message->type == MSG_SETUP_DESKTOP_UI) {
DesktopSetup();
}

View File

@ -654,8 +654,7 @@ define ES_ECHO_REQUEST_MAX_LENGTH (48)
define ES_CONNECTION_OPEN_WAIT (1 << 0)
define ES_FILE_CONTROL_NOTIFY_MONITORS (1 << 0)
define ES_FILE_CONTROL_FLUSH (1 << 1)
define ES_FILE_CONTROL_FLUSH (1 << 0)
define ES_ELEMENT_UPDATE_CONTENT_WIDTH (1 << 0)
define ES_ELEMENT_UPDATE_CONTENT_HEIGHT (1 << 1)
@ -1392,7 +1391,10 @@ struct EsApplicationStartupInformation {
EsWindow *targetWindow;
uint32_t flags;
int32_t data;
EsHandle readHandle; // Internal use.
// Internal use only.
EsHandle readHandle;
EsObjectID documentID;
};
struct EsINIState {

View File

@ -1,7 +1,6 @@
// TODO Save system configuration file on closing the instance or going back to all settings.
// TODO Undo button overlapped slightly when scrollbar shown.
struct SettingsInstance : EsInstance {
struct SettingsInstance : CommonDesktopInstance {
EsPanel *switcher;
EsPanel *mainPage;
EsButton *undoButton;
@ -131,6 +130,7 @@ void SettingsBackButton(EsInstance *_instance, EsElement *, EsCommand *) {
instance->undoButton = nullptr;
instance->controls.Free();
EsPanelSwitchTo(instance->switcher, instance->mainPage, ES_TRANSITION_ZOOM_OUT, ES_PANEL_SWITCHER_DESTROY_PREVIOUS_AFTER_TRANSITION, 1.0f);
ConfigurationWriteToFile();
}
void SettingsNumberBoxSetValue(EsElement *element, int32_t newValue) {
@ -156,6 +156,7 @@ void SettingsNumberBoxSetValue(EsElement *element, int32_t newValue) {
if (oldValue != newValue) {
SettingsUpdateGlobalAndWindowManager();
EsElementSetDisabled(instance->undoButton, false);
desktop.configurationModified = true;
}
}
@ -221,6 +222,7 @@ void SettingsCheckboxCommand(EsInstance *_instance, EsElement *element, EsComman
if (oldValue == newValue) return;
SettingsUpdateGlobalAndWindowManager();
EsElementSetDisabled(instance->undoButton, false);
desktop.configurationModified = true;
}
void SettingsAddCheckbox(EsElement *table, const char *string, ptrdiff_t stringBytes, char accessKey,
@ -328,6 +330,7 @@ int SettingsSliderMessage(EsElement *element, EsMessage *message) {
if (oldValue != newValue) {
SettingsUpdateGlobalAndWindowManager();
EsElementSetDisabled(instance->undoButton, false);
desktop.configurationModified = true;
}
}
@ -536,4 +539,8 @@ void InstanceSettingsCreate(EsMessage *message) {
EsButtonOnCommand(button, SettingsButtonPressed);
}
}
instance->destroy = [] (EsInstance *) {
ConfigurationWriteToFile();
};
}

View File

@ -171,7 +171,7 @@ EsError EsFileWriteAllGatherFromHandle(EsHandle handle, const void **data, size_
offset += sizes[i];
}
error = EsFileControl(handle, ES_FILE_CONTROL_NOTIFY_MONITORS | ES_FILE_CONTROL_FLUSH);
error = EsFileControl(handle, ES_FILE_CONTROL_FLUSH);
return error;
}