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) { if (success) {
message->instanceSave.file->error = EsFileControl(message->instanceSave.file->handle, message->instanceSave.file->error = EsFileControl(message->instanceSave.file->handle, ES_FILE_CONTROL_FLUSH);
ES_FILE_CONTROL_NOTIFY_MONITORS | ES_FILE_CONTROL_FLUSH);
if (message->instanceSave.file->error != ES_SUCCESS) { if (message->instanceSave.file->error != ES_SUCCESS) {
success = false; success = false;

View File

@ -5,8 +5,6 @@
// - New tab page - search; recent files. // - New tab page - search; recent files.
// - Right click menu. // - Right click menu.
// - Duplicate tabs. // - 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: // TODO Graphical issues:
// - New tab button isn't flush with right border when tab band full. // - 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 Only let File Manager read the file_type sections of the system configuration.
// TODO Restarting Desktop if it crashes. // TODO Restarting Desktop if it crashes.
// TODO Make sure applications can't delete |Fonts: and |Themes:. // 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)) #define MSG_SETUP_DESKTOP_UI ((EsMessageType) (ES_MSG_USER_START + 1))
@ -105,6 +104,7 @@ struct OpenDocument {
EsHandle readHandle; EsHandle readHandle;
EsObjectID id; EsObjectID id;
EsObjectID currentWriter; EsObjectID currentWriter;
uintptr_t referenceCount;
}; };
struct InstalledApplication { struct InstalledApplication {
@ -122,10 +122,14 @@ struct InstalledApplication {
bool notified; // Temporary flag. bool notified; // Temporary flag.
}; };
struct CrashedTabInstance : EsInstance { struct CommonDesktopInstance : EsInstance {
void (*destroy)(EsInstance *);
}; };
struct BlankTabInstance : EsInstance { struct CrashedTabInstance : CommonDesktopInstance {
};
struct BlankTabInstance : CommonDesktopInstance {
}; };
struct ApplicationInstance { struct ApplicationInstance {
@ -184,6 +188,8 @@ struct {
EsObjectID nextClipboardProcessID; EsObjectID nextClipboardProcessID;
EsHandle clipboardFile; EsHandle clipboardFile;
ClipboardInformation clipboardInformation; ClipboardInformation clipboardInformation;
bool configurationModified;
} desktop; } desktop;
int TaskBarButtonMessage(EsElement *element, EsMessage *message); int TaskBarButtonMessage(EsElement *element, EsMessage *message);
@ -192,6 +198,9 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma
void ApplicationInstanceClose(ApplicationInstance *instance); void ApplicationInstanceClose(ApplicationInstance *instance);
ApplicationInstance *ApplicationInstanceFindByWindowID(EsObjectID windowID, bool remove = false); ApplicationInstance *ApplicationInstanceFindByWindowID(EsObjectID windowID, bool remove = false);
void EmbeddedWindowDestroyed(EsObjectID id); void EmbeddedWindowDestroyed(EsObjectID id);
void ConfigurationWriteToFile();
void OpenDocumentOpenReference(EsObjectID id);
void OpenDocumentCloseReference(EsObjectID id);
#include "settings.cpp" #include "settings.cpp"
@ -908,6 +917,11 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma
instance->processHandle = ES_INVALID_HANDLE; instance->processHandle = ES_INVALID_HANDLE;
} }
if (instance->documentID) {
OpenDocumentCloseReference(instance->documentID);
instance->documentID = 0;
}
instance->application = application; instance->application = application;
if (application->useSingleProcess && application->singleProcessHandle) { if (application->useSingleProcess && application->singleProcessHandle) {
@ -1017,6 +1031,11 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma
instance->processID = EsProcessGetID(process); instance->processID = EsProcessGetID(process);
instance->processHandle = EsSyscall(ES_SYSCALL_PROCESS_SHARE, process, ES_CURRENT_PROCESS, 0, 0); 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 }; EsMessage m = { ES_MSG_INSTANCE_CREATE };
if (~startupInformation->flags & ES_APPLICATION_STARTUP_MANUAL_PATH) { if (~startupInformation->flags & ES_APPLICATION_STARTUP_MANUAL_PATH) {
@ -1077,9 +1096,16 @@ ApplicationInstance *ApplicationInstanceCreate(int64_t id, EsApplicationStartupI
instance->titleBytes = 1; instance->titleBytes = 1;
instance->tab = tab; instance->tab = tab;
desktop.allApplicationInstances.Add(instance); desktop.allApplicationInstances.Add(instance);
ApplicationInstanceStart(id, startupInformation, instance);
if (!hidden) WindowTabActivate(tab); if (ApplicationInstanceStart(id, startupInformation, instance)) {
return 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) { void ApplicationTemporaryDestroy(InstalledApplication *application) {
@ -1171,15 +1197,39 @@ void ApplicationProcessTerminated(EsObjectID pid) {
break; 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: // 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) { void OpenDocumentWithApplication(EsApplicationStartupInformation *startupInformation) {
bool foundDocument = false; bool foundDocument = false;
EsObjectID documentID;
for (uintptr_t i = 0; i < desktop.openDocuments.Count(); i++) { for (uintptr_t i = 0; i < desktop.openDocuments.Count(); i++) {
OpenDocument *document = &desktop.openDocuments[i]; OpenDocument *document = &desktop.openDocuments[i];
@ -1188,7 +1238,8 @@ void OpenDocumentWithApplication(EsApplicationStartupInformation *startupInforma
&& 0 == EsMemoryCompare(document->path, startupInformation->filePath, document->pathBytes)) { && 0 == EsMemoryCompare(document->path, startupInformation->filePath, document->pathBytes)) {
foundDocument = true; foundDocument = true;
startupInformation->readHandle = document->readHandle; startupInformation->readHandle = document->readHandle;
documentID = document->id; startupInformation->documentID = document->id;
document->referenceCount++;
break; break;
} }
} }
@ -1207,18 +1258,16 @@ void OpenDocumentWithApplication(EsApplicationStartupInformation *startupInforma
document.pathBytes = startupInformation->filePathBytes; document.pathBytes = startupInformation->filePathBytes;
document.readHandle = file.handle; document.readHandle = file.handle;
document.id = ++desktop.currentDocumentID; document.id = ++desktop.currentDocumentID;
documentID = document.id; document.referenceCount = 1;
EsMemoryCopy(document.path, startupInformation->filePath, startupInformation->filePathBytes); EsMemoryCopy(document.path, startupInformation->filePath, startupInformation->filePathBytes);
*desktop.openDocuments.Put(&document.id) = document; *desktop.openDocuments.Put(&document.id) = document;
startupInformation->readHandle = document.readHandle; startupInformation->readHandle = document.readHandle;
startupInformation->documentID = document.id;
} }
ApplicationInstance *instance = ApplicationInstanceCreate(startupInformation->id, startupInformation, nullptr); ApplicationInstanceCreate(startupInformation->id, startupInformation, nullptr);
OpenDocumentCloseReference(startupInformation->documentID);
if (instance) {
instance->documentID = documentID;
}
} }
EsError TemporaryFileCreate(EsHandle *handle, char **path, size_t *pathBytes) { EsError TemporaryFileCreate(EsHandle *handle, char **path, size_t *pathBytes) {
@ -1319,6 +1368,9 @@ void ApplicationInstanceRequestSave(ApplicationInstance *instance, const char *n
if (document->currentWriter) { if (document->currentWriter) {
m.tabOperation.error = ES_ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE; m.tabOperation.error = ES_ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE;
} else { } else {
EsHeapFree(document->temporarySavePath);
document->temporarySavePath = nullptr;
EsHandle fileHandle; EsHandle fileHandle;
m.tabOperation.error = TemporaryFileCreate(&fileHandle, &document->temporarySavePath, &document->temporarySavePathBytes); m.tabOperation.error = TemporaryFileCreate(&fileHandle, &document->temporarySavePath, &document->temporarySavePathBytes);
@ -1526,7 +1578,7 @@ void ConfigurationLoadApplications() {
}, 0); }, 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]; char buffer[4096];
EsMutexAcquire(&api.systemConfigurationMutex); EsMutexAcquire(&api.systemConfigurationMutex);
@ -1547,7 +1599,7 @@ void ConfigurationWriteSectionsToBuffer(const char *sectionClass, const char *se
for (uintptr_t i = 0; i < group->itemCount; i++) { for (uintptr_t i = 0; i < group->itemCount; i++) {
EsSystemConfigurationItem *item = group->items + i; EsSystemConfigurationItem *item = group->items + i;
if (!item->keyBytes || item->key[0] == ';') { if ((!item->keyBytes || item->key[0] == ';') && !includeComments) {
continue; continue;
} }
@ -1561,6 +1613,37 @@ void ConfigurationWriteSectionsToBuffer(const char *sectionClass, const char *se
EsMutexRelease(&api.systemConfigurationMutex); 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: // Image utilities:
////////////////////////////////////////////////////// //////////////////////////////////////////////////////
@ -1885,8 +1968,8 @@ void DesktopMessage2(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
EsHandleClose(processHandle); EsHandleClose(processHandle);
} }
} else if (buffer[0] == DESKTOP_MSG_SYSTEM_CONFIGURATION_GET && pipe) { } else if (buffer[0] == DESKTOP_MSG_SYSTEM_CONFIGURATION_GET && pipe) {
ConfigurationWriteSectionsToBuffer("font", nullptr, pipe); ConfigurationWriteSectionsToBuffer("font", nullptr, false, pipe);
ConfigurationWriteSectionsToBuffer(nullptr, "ui", pipe); ConfigurationWriteSectionsToBuffer(nullptr, "ui", false, pipe);
} else if (buffer[0] == DESKTOP_MSG_REQUEST_SHUTDOWN) { } else if (buffer[0] == DESKTOP_MSG_REQUEST_SHUTDOWN) {
InstalledApplication *application = ApplicationFindByPID(message->desktop.processID); 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); InstalledApplication *application = ApplicationFindByPID(message->desktop.processID);
if (application && (application->permissions & APPLICATION_PERMISSION_VIEW_FILE_TYPES)) { if (application && (application->permissions & APPLICATION_PERMISSION_VIEW_FILE_TYPES)) {
ConfigurationWriteSectionsToBuffer("file_type", nullptr, pipe); ConfigurationWriteSectionsToBuffer("file_type", nullptr, false, pipe);
} }
} else if (!instance) { } else if (!instance) {
// ------------------------------------------------- // -------------------------------------------------
@ -1965,8 +2048,6 @@ void DesktopMessage2(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
} }
void EmbeddedWindowDestroyed(EsObjectID id) { void EmbeddedWindowDestroyed(EsObjectID id) {
// TODO Close open documents.
EsMenuCloseAll(); EsMenuCloseAll();
ApplicationInstance *instance = ApplicationInstanceFindByWindowID(id, true /* remove if found */); ApplicationInstance *instance = ApplicationInstanceFindByWindowID(id, true /* remove if found */);
if (!instance) return; if (!instance) return;
@ -1974,6 +2055,10 @@ void EmbeddedWindowDestroyed(EsObjectID id) {
EsHandleClose(instance->embeddedWindowHandle); EsHandleClose(instance->embeddedWindowHandle);
if (instance->processHandle) EsHandleClose(instance->processHandle); if (instance->processHandle) EsHandleClose(instance->processHandle);
if (instance->documentID) {
OpenDocumentCloseReference(instance->documentID);
}
InstalledApplication *application = instance->application; InstalledApplication *application = instance->application;
if (application && application->singleInstance) { 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); EsSyscall(ES_SYSCALL_WINDOW_MOVE, window->handle, (uintptr_t) &bounds, 0, ES_WINDOW_MOVE_ALWAYS_ON_TOP);
wrapper->StartAnimating(); 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) { } else if (message->type == MSG_SETUP_DESKTOP_UI) {
DesktopSetup(); DesktopSetup();
} }

View File

@ -654,8 +654,7 @@ define ES_ECHO_REQUEST_MAX_LENGTH (48)
define ES_CONNECTION_OPEN_WAIT (1 << 0) define ES_CONNECTION_OPEN_WAIT (1 << 0)
define ES_FILE_CONTROL_NOTIFY_MONITORS (1 << 0) define ES_FILE_CONTROL_FLUSH (1 << 0)
define ES_FILE_CONTROL_FLUSH (1 << 1)
define ES_ELEMENT_UPDATE_CONTENT_WIDTH (1 << 0) define ES_ELEMENT_UPDATE_CONTENT_WIDTH (1 << 0)
define ES_ELEMENT_UPDATE_CONTENT_HEIGHT (1 << 1) define ES_ELEMENT_UPDATE_CONTENT_HEIGHT (1 << 1)
@ -1392,7 +1391,10 @@ struct EsApplicationStartupInformation {
EsWindow *targetWindow; EsWindow *targetWindow;
uint32_t flags; uint32_t flags;
int32_t data; int32_t data;
EsHandle readHandle; // Internal use.
// Internal use only.
EsHandle readHandle;
EsObjectID documentID;
}; };
struct EsINIState { 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. // TODO Undo button overlapped slightly when scrollbar shown.
struct SettingsInstance : EsInstance { struct SettingsInstance : CommonDesktopInstance {
EsPanel *switcher; EsPanel *switcher;
EsPanel *mainPage; EsPanel *mainPage;
EsButton *undoButton; EsButton *undoButton;
@ -131,6 +130,7 @@ void SettingsBackButton(EsInstance *_instance, EsElement *, EsCommand *) {
instance->undoButton = nullptr; instance->undoButton = nullptr;
instance->controls.Free(); instance->controls.Free();
EsPanelSwitchTo(instance->switcher, instance->mainPage, ES_TRANSITION_ZOOM_OUT, ES_PANEL_SWITCHER_DESTROY_PREVIOUS_AFTER_TRANSITION, 1.0f); 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) { void SettingsNumberBoxSetValue(EsElement *element, int32_t newValue) {
@ -156,6 +156,7 @@ void SettingsNumberBoxSetValue(EsElement *element, int32_t newValue) {
if (oldValue != newValue) { if (oldValue != newValue) {
SettingsUpdateGlobalAndWindowManager(); SettingsUpdateGlobalAndWindowManager();
EsElementSetDisabled(instance->undoButton, false); EsElementSetDisabled(instance->undoButton, false);
desktop.configurationModified = true;
} }
} }
@ -221,6 +222,7 @@ void SettingsCheckboxCommand(EsInstance *_instance, EsElement *element, EsComman
if (oldValue == newValue) return; if (oldValue == newValue) return;
SettingsUpdateGlobalAndWindowManager(); SettingsUpdateGlobalAndWindowManager();
EsElementSetDisabled(instance->undoButton, false); EsElementSetDisabled(instance->undoButton, false);
desktop.configurationModified = true;
} }
void SettingsAddCheckbox(EsElement *table, const char *string, ptrdiff_t stringBytes, char accessKey, 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) { if (oldValue != newValue) {
SettingsUpdateGlobalAndWindowManager(); SettingsUpdateGlobalAndWindowManager();
EsElementSetDisabled(instance->undoButton, false); EsElementSetDisabled(instance->undoButton, false);
desktop.configurationModified = true;
} }
} }
@ -536,4 +539,8 @@ void InstanceSettingsCreate(EsMessage *message) {
EsButtonOnCommand(button, SettingsButtonPressed); EsButtonOnCommand(button, SettingsButtonPressed);
} }
} }
instance->destroy = [] (EsInstance *) {
ConfigurationWriteToFile();
};
} }

View File

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