From 4206aae3f6a8c4467c3172e8dd017748b30032aa Mon Sep 17 00:00:00 2001 From: nakst <> Date: Tue, 14 Sep 2021 10:01:38 +0100 Subject: [PATCH] close applications before shutdown; introduce ApplicationProcess --- apps/system_monitor.ini | 1 + desktop/api.cpp | 52 ++--- desktop/desktop.cpp | 474 ++++++++++++++++++++++++---------------- desktop/os.header | 1 - desktop/settings.cpp | 13 +- 5 files changed, 312 insertions(+), 229 deletions(-) diff --git a/apps/system_monitor.ini b/apps/system_monitor.ini index 78a0691..8071d1b 100644 --- a/apps/system_monitor.ini +++ b/apps/system_monitor.ini @@ -3,6 +3,7 @@ name=System Monitor icon=icon_utilities_system_monitor permission_manage_processes=1 permission_shutdown=1 +use_single_instance=1 [build] source=apps/system_monitor.cpp diff --git a/desktop/api.cpp b/desktop/api.cpp index 3e24bd5..5d74b32 100644 --- a/desktop/api.cpp +++ b/desktop/api.cpp @@ -139,8 +139,6 @@ struct { uintptr_t performanceTimerStackCount; ThreadLocalStorage firstThreadLocalStorage; - - size_t openInstanceCount; // Also counts user tasks. } api; ptrdiff_t tlsStorageOffset; @@ -159,6 +157,7 @@ EsFileStore *FileStoreCreateFromPath(const char *path, size_t pathBytes); EsFileStore *FileStoreCreateFromHandle(EsHandle handle); void FileStoreCloseHandle(EsFileStore *fileStore); EsError NodeOpen(const char *path, size_t pathBytes, uint32_t flags, _EsNodeInformation *node); +void ApplicationProcessTerminated(EsObjectID pid); #include "syscall.cpp" @@ -742,7 +741,6 @@ EsInstance *_EsInstanceCreate(size_t bytes, EsMessage *message, const char *appl APIInstance *apiInstance = InstanceSetup(instance); apiInstance->applicationName = applicationName; apiInstance->applicationNameBytes = applicationNameBytes; - api.openInstanceCount++; if (message && message->createInstance.data != ES_INVALID_HANDLE && message->createInstance.dataBytes > 1) { apiInstance->startupInformation = (EsApplicationStartupInformation *) EsHeapAllocate(message->createInstance.dataBytes, false); @@ -854,33 +852,30 @@ EsMessage *EsMessageReceive() { EsAssert(message.message.instanceSave.file->operationComplete); FileStoreCloseHandle(message.message.instanceSave.file); } else if (message.message.type == ES_MSG_APPLICATION_EXIT) { + if (api.startupInformation->isDesktop) { + // Desktop tracks the number of instances it owns, so it needs to know when it exits. + ApplicationProcessTerminated(EsProcessGetID(ES_CURRENT_PROCESS)); + } else { #ifdef DEBUG_BUILD - FontDatabaseFree(); - FreeUnusedStyles(true /* include permanent styles */); - theming.loadedStyles.Free(); - SystemConfigurationUnload(); - api.mountPoints.Free(); - api.postBox.Free(); - api.timers.Free(); - gui.animatingElements.Free(); - gui.accessKeys.entries.Free(); - gui.allWindows.Free(); - calculator.Free(); - HashTableFree(&gui.keyboardShortcutNames, false); - MemoryLeakDetectorCheckpoint(&heap); - EsPrint("ES_MSG_APPLICATION_EXIT - Heap allocation count: %d (%d from malloc).\n", heap.allocationsCount, mallocCount); + FontDatabaseFree(); + FreeUnusedStyles(true /* include permanent styles */); + theming.loadedStyles.Free(); + SystemConfigurationUnload(); + api.mountPoints.Free(); + api.postBox.Free(); + api.timers.Free(); + gui.animatingElements.Free(); + gui.accessKeys.entries.Free(); + gui.allWindows.Free(); + calculator.Free(); + HashTableFree(&gui.keyboardShortcutNames, false); + MemoryLeakDetectorCheckpoint(&heap); + EsPrint("ES_MSG_APPLICATION_EXIT - Heap allocation count: %d (%d from malloc).\n", heap.allocationsCount, mallocCount); #endif - EsProcessTerminateCurrent(); - } else if (message.message.type == ES_MSG_INSTANCE_DESTROY) { - api.openInstanceCount--; - - APIInstance *instance = (APIInstance *) message.message.instanceDestroy.instance->_private; - - if (instance->startupInformation && (instance->startupInformation->flags & ES_APPLICATION_STARTUP_SINGLE_INSTANCE_IN_PROCESS) - && !api.openInstanceCount) { - EsMessage m = { ES_MSG_APPLICATION_EXIT }; - EsMessagePost(nullptr, &m); + EsProcessTerminateCurrent(); } + } else if (message.message.type == ES_MSG_INSTANCE_DESTROY) { + APIInstance *instance = (APIInstance *) message.message.instanceDestroy.instance->_private; if (instance->startupInformation) { EsHeapFree((void *) instance->startupInformation->filePath); @@ -1723,8 +1718,6 @@ void UserTaskThread(EsGeneric _task) { EsUserTask *task = (EsUserTask *) _task.p; task->callback(task, task->data); EsMessageMutexAcquire(); - api.openInstanceCount--; - // TODO Send ES_MSG_APPLICATION_EXIT if needed. EsMessageMutexRelease(); EsSyscall(ES_SYSCALL_WINDOW_CLOSE, task->taskHandle, 0, 0, 0); EsHandleClose(task->taskHandle); @@ -1791,7 +1784,6 @@ EsError EsUserTaskStart(EsUserTaskCallback callback, EsGeneric data, const char if (error == ES_SUCCESS) { EsHandleClose(information.handle); - api.openInstanceCount++; } else { EsSyscall(ES_SYSCALL_WINDOW_CLOSE, task->taskHandle, 0, 0, 0); EsHandleClose(task->taskHandle); diff --git a/desktop/desktop.cpp b/desktop/desktop.cpp index 66032ff..0eed12c 100644 --- a/desktop/desktop.cpp +++ b/desktop/desktop.cpp @@ -1,7 +1,4 @@ // TODO Tabs: -// - Dragging out of the window. -// - Dragging onto other windows. -// - Keyboard shortcuts. // - New tab page - search; recent files. // - Right click menu. // - Duplicate tabs. @@ -119,9 +116,7 @@ struct InstalledApplication { bool useSingleInstance; struct ApplicationInstance *singleInstance; uint64_t permissions; - size_t openInstanceCount; // Only used if useSingleProcess is true. - EsHandle singleProcessHandle; - bool notified; // Temporary flag. + struct ApplicationProcess *singleProcess; EsFileOffset totalSize; // 0 if uncalculated. }; @@ -135,6 +130,13 @@ struct CrashedTabInstance : CommonDesktopInstance { struct BlankTabInstance : CommonDesktopInstance { }; +struct ApplicationProcess { + EsObjectID id; + EsHandle handle; + InstalledApplication *application; + size_t instanceCount; +}; + struct ApplicationInstance { // User interface. WindowTab *tab; // nullptr for notRespondingInstance and user tasks. @@ -143,8 +145,8 @@ struct ApplicationInstance { // Currently loaded application. InstalledApplication *application; - EsObjectID documentID, processID; - EsHandle processHandle; + EsObjectID documentID; + ApplicationProcess *process; bool isUserTask; // Metadata. @@ -154,6 +156,15 @@ struct ApplicationInstance { double progress; }; +const EsStyle styleSmallParagraph = { + .inherit = ES_STYLE_TEXT_PARAGRAPH, + + .metrics = { + .mask = ES_THEME_METRICS_TEXT_SIZE, + .textSize = 8, + }, +}; + const EsStyle styleNewTabContent = { .metrics = { .mask = ES_THEME_METRICS_INSETS | ES_THEME_METRICS_GAP_MAJOR, @@ -174,6 +185,7 @@ const EsStyle styleButtonGroupContainer = { struct { Array installedApplications; Array allApplicationInstances; + Array allApplicationProcesses; Array allContainerWindows; InstalledApplication *fileManager; @@ -199,6 +211,12 @@ struct { Array allOngoingUserTasks; double totalUserTaskProgress; + +#define SHUTDOWN_TIMEOUT (3000) // Maximum time to wait for applications to exit. + EsHandle shutdownReady; // Set when all applications have exited. + bool inShutdown; + + bool inspectorOpen; } desktop; int TaskBarButtonMessage(EsElement *element, EsMessage *message); @@ -420,6 +438,61 @@ int ReorderListMessage(EsElement *_list, EsMessage *message) { return 0; } +////////////////////////////////////////////////////// +// Desktop Inspector: +////////////////////////////////////////////////////// + +void DesktopInspectorThread(EsGeneric) { + EsMessageMutexAcquire(); + EsWindow *window = EsWindowCreate(nullptr, ES_WINDOW_PLAIN); + EsRectangle screen; + EsSyscall(ES_SYSCALL_SCREEN_WORK_AREA_GET, 0, (uintptr_t) &screen, 0, 0); + screen.l = screen.r - 400; + EsSyscall(ES_SYSCALL_WINDOW_MOVE, window->handle, (uintptr_t) &screen, 0, ES_WINDOW_MOVE_ALWAYS_ON_TOP); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, ES_FLAGS_DEFAULT, 0, ES_WINDOW_PROPERTY_SOLID); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, window->handle, 180, 0, ES_WINDOW_PROPERTY_ALPHA); + EsPanel *panel = EsPanelCreate(window, ES_CELL_FILL, ES_STYLE_PANEL_FILLED); + EsMessageMutexRelease(); + + while (true) { + EsMessageMutexAcquire(); + EsElementDestroyContents(panel); + char buffer[256]; + size_t bytes; + + EsTextDisplayCreate(panel, ES_CELL_H_FILL, ES_STYLE_TEXT_HEADING1, "Desktop Inspector"); + EsSpacerCreate(panel, ES_CELL_H_FILL, 0, 0, 5); + + for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { + ApplicationInstance *instance = desktop.allApplicationInstances[i]; + bytes = EsStringFormat(buffer, sizeof(buffer), "inst: eid %d, title '%s', pid %d, docid %d, app '%z'%z", + instance->embeddedWindowID, instance->titleBytes, instance->title, instance->process->id, + instance->documentID, instance->application->cName, instance->isUserTask ? ", utask" : ""); + EsTextDisplayCreate(panel, ES_CELL_H_FILL, &styleSmallParagraph, buffer, bytes); + } + + for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) { + ApplicationProcess *process = desktop.allApplicationProcesses[i]; + bytes = EsStringFormat(buffer, sizeof(buffer), "proc: pid %d, app '%z', instances %d", + process->id, process->application ? process->application->cName : "??", process->instanceCount); + EsTextDisplayCreate(panel, ES_CELL_H_FILL, &styleSmallParagraph, buffer, bytes); + } + + for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { + InstalledApplication *application = desktop.installedApplications[i]; + bytes = EsStringFormat(buffer, sizeof(buffer), "app: '%z'%z%z%z, spid %d, seid %d", + application->cName, application->temporary ? ", temp" : "", application->useSingleProcess ? ", 1proc" : "", + application->useSingleInstance ? ", 1inst" : "", + application->singleProcess ? application->singleProcess->id : 0, + application->singleInstance ? application->singleInstance->embeddedWindowID : 0); + EsTextDisplayCreate(panel, ES_CELL_H_FILL, &styleSmallParagraph, buffer, bytes); + } + + EsMessageMutexRelease(); + EsSleep(500); + } +} + ////////////////////////////////////////////////////// // Container windows: ////////////////////////////////////////////////////// @@ -427,7 +500,7 @@ int ReorderListMessage(EsElement *_list, EsMessage *message) { void WindowTabClose(WindowTab *tab) { if (tab->notRespondingInstance) { // The application is not responding, so force quit the process. - EsProcessTerminate(tab->applicationInstance->processHandle, 1); + EsProcessTerminate(tab->applicationInstance->process->handle, 1); } else { ApplicationInstanceClose(tab->applicationInstance); } @@ -497,6 +570,11 @@ int ProcessGlobalKeyboardShortcuts(EsElement *, EsMessage *message) { if (ctrlOnly && scancode == ES_SCANCODE_N) { ApplicationInstanceCreate(APPLICATION_ID_DESKTOP_BLANK_TAB, nullptr, nullptr); + } else if (message->keyboard.modifiers == (ES_MODIFIER_CTRL | ES_MODIFIER_FLAG) && scancode == ES_SCANCODE_D) { + if (!desktop.inspectorOpen) { + desktop.inspectorOpen = true; + EsThreadCreate(DesktopInspectorThread, nullptr, 0); + } } else { return 0; } @@ -713,7 +791,7 @@ int WindowTabMessage(EsElement *element, EsMessage *message) { ApplicationInstance *instance = tab->applicationInstance; EsMessage m = { ES_MSG_TAB_INSPECT_UI }; m.tabOperation.id = instance->embeddedWindowID; - EsMessagePostRemote(instance->processHandle, &m); + EsMessagePostRemote(instance->process->handle, &m); }, tab); } @@ -1008,6 +1086,33 @@ int TaskBarTasksButtonMessage(EsElement *element, EsMessage *message) { return ES_HANDLED; } +void Shutdown(uintptr_t action) { + // TODO This doesn't wait for Desktop instances. + + if (desktop.inShutdown) { + return; + } + + if (!desktop.allApplicationProcesses.Length()) { + // No applications are open, so we can shut down immediately. + EsSyscall(ES_SYSCALL_SHUTDOWN, action, 0, 0, 0); + } + + desktop.inShutdown = true; + desktop.shutdownReady = EsEventCreate(true); + + for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { + // Tell all applications to close. + ApplicationInstanceClose(desktop.allApplicationInstances[i]); + } + + EsThreadCreate([] (EsGeneric action) { + // Shut down either when all applications exit, or after the timeout. + EsWait(&desktop.shutdownReady, 1, SHUTDOWN_TIMEOUT); + EsSyscall(ES_SYSCALL_SHUTDOWN, action.u, 0, 0, 0); + }, nullptr, action); +} + void ShutdownModalCreate() { if (desktop.shutdownWindowOpen) { return; @@ -1048,11 +1153,11 @@ void ShutdownModalCreate() { // Setup command callbacks when the buttons are pressed. EsButtonOnCommand(shutdownButton, [] (EsInstance *, EsElement *, EsCommand *) { - EsSyscall(ES_SYSCALL_SHUTDOWN, SHUTDOWN_ACTION_POWER_OFF, 0, 0, 0); + Shutdown(SHUTDOWN_ACTION_POWER_OFF); }); EsButtonOnCommand(restartButton, [] (EsInstance *, EsElement *, EsCommand *) { - EsSyscall(ES_SYSCALL_SHUTDOWN, SHUTDOWN_ACTION_RESTART, 0, 0, 0); + Shutdown(SHUTDOWN_ACTION_RESTART); }); EsButtonOnCommand(cancelButton, [] (EsInstance *, EsElement *element, EsCommand *) { @@ -1070,7 +1175,7 @@ void InstanceForceQuit(EsInstance *, EsElement *element, EsCommand *) { ApplicationInstance *instance = desktop.allApplicationInstances[i]; if (instance->tab && instance->tab->notRespondingInstance && instance->tab->notRespondingInstance->embeddedWindowID == element->window->id) { - EsProcessTerminate(instance->processHandle, 1); + EsProcessTerminate(instance->process->handle, 1); break; } } @@ -1155,15 +1260,46 @@ void ApplicationInstanceClose(ApplicationInstance *instance) { // TODO Force closing not responding instances. EsMessage m = { ES_MSG_TAB_CLOSE_REQUEST }; m.tabOperation.id = instance->embeddedWindowID; - EsMessagePostRemote(instance->processHandle, &m); + EsMessagePostRemote(instance->process->handle, &m); +} + +void ApplicationInstanceCleanup(ApplicationInstance *instance) { + if (instance->documentID) { + OpenDocumentCloseReference(instance->documentID); + instance->documentID = 0; + } + + InstalledApplication *application = instance->application; + + if (application && application->singleInstance == instance) { + application->singleInstance = nullptr; + } + + if (instance->process) { + EsAssert(instance->process->instanceCount); + instance->process->instanceCount--; + + if (!instance->process->instanceCount) { + EsMessage m = { ES_MSG_APPLICATION_EXIT }; + EsMessagePostRemote(instance->process->handle, &m); + } + } + + instance->process = nullptr; + instance->application = nullptr; } bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInformation *startupInformation, ApplicationInstance *instance) { + if (desktop.inShutdown) { + return false; + } + InstalledApplication *application = nullptr; for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { if (desktop.installedApplications[i]->id == applicationID) { application = desktop.installedApplications[i]; + break; } } @@ -1190,34 +1326,29 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma instance->tab->notRespondingInstance = nullptr; } - if (instance->processHandle) { - EsHandleClose(instance->processHandle); - instance->processID = 0; - instance->processHandle = ES_INVALID_HANDLE; - } - - if (instance->documentID) { - OpenDocumentCloseReference(instance->documentID); - instance->documentID = 0; - } + ApplicationInstanceCleanup(instance); instance->application = application; - if (application->useSingleProcess && application->singleProcessHandle) { - EsProcessState state; - EsProcessGetState(application->singleProcessHandle, &state); - - if (state.flags & (ES_PROCESS_STATE_ALL_THREADS_TERMINATED | ES_PROCESS_STATE_TERMINATING | ES_PROCESS_STATE_CRASHED)) { - EsHandleClose(application->singleProcessHandle); - application->singleProcessHandle = ES_INVALID_HANDLE; - } - } - - EsHandle process = application->singleProcessHandle; + ApplicationProcess *process = application->singleProcess; if (application->createInstance) { - process = ES_CURRENT_PROCESS; - } else if (!application->useSingleProcess || process == ES_INVALID_HANDLE) { + EsObjectID desktopProcessID = EsProcessGetID(ES_CURRENT_PROCESS); + + for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) { + if (desktop.allApplicationProcesses[i]->id == desktopProcessID) { + process = desktop.allApplicationProcesses[i]; + break; + } + } + + if (!process) { + process = (ApplicationProcess *) EsHeapAllocate(sizeof(ApplicationProcess), true); + process->handle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, ES_CURRENT_PROCESS, ES_CURRENT_PROCESS, 0, 0); + process->id = desktopProcessID; + desktop.allApplicationProcesses.Add(process); + } + } else if (!process) { EsProcessInformation information; EsProcessCreationArguments arguments = {}; @@ -1336,8 +1467,13 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma } if (!ES_CHECK_ERROR(error)) { - process = information.handle; EsHandleClose(information.mainThread.handle); + + process = (ApplicationProcess *) EsHeapAllocate(sizeof(ApplicationProcess), true); + process->handle = information.handle; + process->id = information.pid; + process->application = application; + desktop.allApplicationProcesses.Add(process); } else { EsApplicationStartupInformation s = {}; s.data = CRASHED_TAB_INVALID_EXECUTABLE; @@ -1346,11 +1482,11 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma } if (application->useSingleProcess) { - application->singleProcessHandle = process; + application->singleProcess = process; } - instance->processID = EsProcessGetID(process); - instance->processHandle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, process, ES_CURRENT_PROCESS, 0, 0); + instance->process = process; + process->instanceCount++; if (startupInformation->documentID) { instance->documentID = startupInformation->documentID; @@ -1374,33 +1510,23 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma // Share handles to the file and the startup information buffer. if (startupInformation->readHandle) { - startupInformation->readHandle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, startupInformation->readHandle, process, 0, 0); - } - - if (!application->useSingleProcess && !application->createInstance) { - startupInformation->flags |= ES_APPLICATION_STARTUP_SINGLE_INSTANCE_IN_PROCESS; + startupInformation->readHandle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, startupInformation->readHandle, process->handle, 0, 0); } uint8_t *createInstanceDataBuffer = ApplicationStartupInformationToBuffer(startupInformation, &m.createInstance.dataBytes); - m.createInstance.data = EsConstantBufferCreate(createInstanceDataBuffer, m.createInstance.dataBytes, process); + m.createInstance.data = EsConstantBufferCreate(createInstanceDataBuffer, m.createInstance.dataBytes, process->handle); EsHeapFree(createInstanceDataBuffer); EsHandle handle = EsSyscall(ES_SYSCALL_WINDOW_CREATE, ES_WINDOW_NORMAL, 0, 0, 0); instance->embeddedWindowHandle = handle; EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, handle, 0xFF000000 | GetConstantNumber("windowFillColor"), 0, ES_WINDOW_PROPERTY_RESIZE_CLEAR_COLOR); instance->embeddedWindowID = EsSyscall(ES_SYSCALL_WINDOW_GET_ID, handle, 0, 0, 0); - m.createInstance.window = EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, handle, process, 0, ES_WINDOW_PROPERTY_EMBED_OWNER); + m.createInstance.window = EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, handle, process->handle, 0, ES_WINDOW_PROPERTY_EMBED_OWNER); if (application->createInstance) { application->createInstance(&m); } else { - EsMessagePostRemote(process, &m); - - if (!application->useSingleProcess) { - EsHandleClose(process); - } else { - application->openInstanceCount++; - } + EsMessagePostRemote(process->handle, &m); } if (application->useSingleInstance) { @@ -1432,7 +1558,6 @@ ApplicationInstance *ApplicationInstanceCreate(int64_t id, EsApplicationStartupI void ApplicationTemporaryDestroy(InstalledApplication *application) { if (!application->temporary) return; - EsAssert(!application->singleProcessHandle); for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { if (desktop.installedApplications[i] == application) { @@ -1449,6 +1574,27 @@ void ApplicationTemporaryDestroy(InstalledApplication *application) { EsAssert(false); } +ApplicationProcess *ApplicationProcessFindByPID(EsObjectID pid, bool removeIfFound = false) { + for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) { + ApplicationProcess *process = desktop.allApplicationProcesses[i]; + + if (process->id == pid) { + if (removeIfFound) { + desktop.allApplicationProcesses.DeleteSwap(i); + } + + return process; + } + } + + return nullptr; +} + +InstalledApplication *ApplicationFindByPID(EsObjectID pid) { + ApplicationProcess *process = ApplicationProcessFindByPID(pid); + return process ? process->application : nullptr; +} + void ApplicationInstanceCrashed(EsMessage *message) { EsHandle processHandle = EsProcessOpen(message->crash.pid); EsAssert(processHandle); // Since the process is paused, it cannot be removed. @@ -1461,10 +1607,21 @@ void ApplicationInstanceCrashed(EsMessage *message) { : EnumLookupNameFromValue(enumStrings_EsSyscallType, state.crashReason.duringSystemCall); EsPrint("Process %d has crashed with error %z, during system call %z.\n", state.id, fatalErrorString, systemCallString); + InstalledApplication *application = ApplicationFindByPID(message->crash.pid); + + if (application) { + if (application->singleProcess && application->singleProcess->id == message->crash.pid) { + application->singleProcess = nullptr; + } + + application->singleInstance = nullptr; + ApplicationTemporaryDestroy(application); + } + for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { ApplicationInstance *instance = desktop.allApplicationInstances[i]; - if (instance->processID == message->crash.pid) { + if (instance->process->id == message->crash.pid) { if (instance->tab) { ApplicationInstanceStart(APPLICATION_ID_DESKTOP_CRASHED, nullptr, instance); WindowTabActivate(instance->tab, true); @@ -1472,55 +1629,37 @@ void ApplicationInstanceCrashed(EsMessage *message) { } } - for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { - if (desktop.installedApplications[i]->useSingleProcess && desktop.installedApplications[i]->singleProcessHandle - && EsProcessGetID(desktop.installedApplications[i]->singleProcessHandle) == message->crash.pid) { - EsHandleClose(desktop.installedApplications[i]->singleProcessHandle); - desktop.installedApplications[i]->singleProcessHandle = ES_INVALID_HANDLE; - desktop.installedApplications[i]->singleInstance = nullptr; - desktop.installedApplications[i]->openInstanceCount = 0; - ApplicationTemporaryDestroy(desktop.installedApplications[i]); - break; - } - } - EsProcessTerminate(processHandle, 1); EsHandleClose(processHandle); } -InstalledApplication *ApplicationFindByPID(EsObjectID pid) { - for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { - ApplicationInstance *instance = desktop.allApplicationInstances[i]; - - if (instance->processID == pid) { - return instance->application; - } - } - - return nullptr; -} - void ApplicationProcessTerminated(EsObjectID pid) { for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { ApplicationInstance *instance = desktop.allApplicationInstances[i]; - if (instance->processID != pid) { - continue; + if (instance->process->id == pid) { + EmbeddedWindowDestroyed(instance->embeddedWindowID); + i--; // EmbeddedWindowDestroyed removes it from the array. } - - EmbeddedWindowDestroyed(instance->embeddedWindowID); } - for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { - if (desktop.installedApplications[i]->useSingleProcess && desktop.installedApplications[i]->singleProcessHandle - && EsProcessGetID(desktop.installedApplications[i]->singleProcessHandle) == pid) { - EsHandleClose(desktop.installedApplications[i]->singleProcessHandle); - desktop.installedApplications[i]->singleProcessHandle = ES_INVALID_HANDLE; - desktop.installedApplications[i]->singleInstance = nullptr; - desktop.installedApplications[i]->openInstanceCount = 0; - ApplicationTemporaryDestroy(desktop.installedApplications[i]); - break; + ApplicationProcess *process = ApplicationProcessFindByPID(pid, true /* remove from array */); + + if (process) { + InstalledApplication *application = process->application; + + if (application) { + if (application->singleProcess && application->singleProcess->id == pid) { + application->singleProcess = nullptr; + } + + application->singleInstance = nullptr; + ApplicationTemporaryDestroy(application); } + + EsAssert(!process->instanceCount); + EsHandleClose(process->handle); + EsHeapFree(process); } for (uintptr_t i = 0; i < desktop.openDocuments.Count(); i++) { @@ -1530,6 +1669,10 @@ void ApplicationProcessTerminated(EsObjectID pid) { document->currentWriter = 0; } } + + if (!desktop.allApplicationProcesses.Length() && desktop.inShutdown) { + EsEventSet(desktop.shutdownReady); + } } ////////////////////////////////////////////////////// @@ -1625,7 +1768,7 @@ EsError TemporaryFileCreate(EsHandle *handle, char **path, size_t *pathBytes, ui } void ApplicationInstanceRequestSave(ApplicationInstance *instance, const char *newName, size_t newNameBytes, bool failIfAlreadyExists) { - if (!instance->processHandle) return; + if (!instance->process) return; EsMessage m = {}; m.type = ES_MSG_INSTANCE_SAVE_RESPONSE; @@ -1643,7 +1786,7 @@ void ApplicationInstanceRequestSave(ApplicationInstance *instance, const char *n if (!nameBytes || (failIfAlreadyExists && nameBytes != folderBytes + newNameBytes)) { EsHeapFree(name); m.tabOperation.error = nameBytes ? ES_ERROR_FILE_ALREADY_EXISTS : ES_ERROR_TOO_MANY_FILES_WITH_NAME; - EsMessagePostRemote(instance->processHandle, &m); + EsMessagePostRemote(instance->process->handle, &m); return; } @@ -1652,7 +1795,7 @@ void ApplicationInstanceRequestSave(ApplicationInstance *instance, const char *n if (file.error != ES_SUCCESS) { EsHeapFree(name); m.tabOperation.error = file.error; - EsMessagePostRemote(instance->processHandle, &m); + EsMessagePostRemote(instance->process->handle, &m); return; } @@ -1679,9 +1822,9 @@ void ApplicationInstanceRequestSave(ApplicationInstance *instance, const char *n EsMessage m = { ES_MSG_INSTANCE_DOCUMENT_RENAMED }; m.tabOperation.id = instance->embeddedWindowID; - m.tabOperation.handle = EsConstantBufferCreate(name + nameOffset, nameBytes - nameOffset, instance->processHandle); + m.tabOperation.handle = EsConstantBufferCreate(name + nameOffset, nameBytes - nameOffset, instance->process->handle); m.tabOperation.bytes = nameBytes - nameOffset; - EsMessagePostRemote(instance->processHandle, &m); + EsMessagePostRemote(instance->process->handle, &m); } } @@ -1702,12 +1845,12 @@ void ApplicationInstanceRequestSave(ApplicationInstance *instance, const char *n if (m.tabOperation.error == ES_SUCCESS) { document->currentWriter = instance->embeddedWindowID; - m.tabOperation.handle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, fileHandle, instance->processHandle, 0, 0); + m.tabOperation.handle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, fileHandle, instance->process->handle, 0, 0); EsHandleClose(fileHandle); } } - EsMessagePostRemote(instance->processHandle, &m); + EsMessagePostRemote(instance->process->handle, &m); } void InstanceAnnouncePathMoved(InstalledApplication *fromApplication, const char *oldPath, size_t oldPathBytes, const char *newPath, size_t newPathBytes) { @@ -1749,16 +1892,16 @@ void InstanceAnnouncePathMoved(InstalledApplication *fromApplication, const char if (instance->documentID != documentID) continue; if (instance->application == fromApplication) continue; - if (!instance->processHandle) continue; + if (!instance->process) continue; EsMessage m = { ES_MSG_INSTANCE_DOCUMENT_RENAMED }; m.tabOperation.id = instance->embeddedWindowID; - m.tabOperation.handle = EsConstantBufferCreate(newPath + newNameOffset, newPathBytes - newNameOffset, instance->processHandle); + m.tabOperation.handle = EsConstantBufferCreate(newPath + newNameOffset, newPathBytes - newNameOffset, instance->process->handle); m.tabOperation.bytes = newPathBytes - newNameOffset; - EsMessagePostRemote(instance->processHandle, &m); + EsMessagePostRemote(instance->process->handle, &m); } - if (fromApplication != desktop.fileManager && desktop.fileManager && desktop.fileManager->singleProcessHandle) { + if (fromApplication != desktop.fileManager && desktop.fileManager && desktop.fileManager->singleProcess) { char *data = (char *) EsHeapAllocate(sizeof(size_t) * 2 + oldPathBytes + newPathBytes, false); EsMemoryCopy(data + 0, &oldPathBytes, sizeof(size_t)); EsMemoryCopy(data + sizeof(size_t), &newPathBytes, sizeof(size_t)); @@ -1767,8 +1910,8 @@ void InstanceAnnouncePathMoved(InstalledApplication *fromApplication, const char EsMessage m = {}; m.type = ES_MSG_FILE_MANAGER_PATH_MOVED; m.user.context2 = sizeof(size_t) * 2 + oldPathBytes + newPathBytes; - m.user.context1 = EsConstantBufferCreate(data, m.user.context2.u, desktop.fileManager->singleProcessHandle); - EsMessagePostRemote(desktop.fileManager->singleProcessHandle, &m); + m.user.context1 = EsConstantBufferCreate(data, m.user.context2.u, desktop.fileManager->singleProcess->handle); + EsMessagePostRemote(desktop.fileManager->singleProcess->handle, &m); EsHeapFree(data); } } @@ -1800,25 +1943,25 @@ void ApplicationInstanceCompleteSave(ApplicationInstance *fromInstance) { document->currentWriter = 0; - if (desktop.fileManager->singleProcessHandle) { + if (desktop.fileManager->singleProcess) { EsMessage m = {}; m.type = ES_MSG_FILE_MANAGER_FILE_MODIFIED; - m.user.context1 = EsConstantBufferCreate(document->path, document->pathBytes, desktop.fileManager->singleProcessHandle); + m.user.context1 = EsConstantBufferCreate(document->path, document->pathBytes, desktop.fileManager->singleProcess->handle); m.user.context2 = document->pathBytes; - EsMessagePostRemote(desktop.fileManager->singleProcessHandle, &m); + EsMessagePostRemote(desktop.fileManager->singleProcess->handle, &m); } for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { ApplicationInstance *instance = desktop.allApplicationInstances[i]; if (instance->documentID != document->id) continue; - if (!instance->processHandle) continue; + if (!instance->process) continue; EsMessage m = { ES_MSG_INSTANCE_DOCUMENT_UPDATED }; m.tabOperation.isSource = instance == fromInstance; m.tabOperation.id = instance->embeddedWindowID; - m.tabOperation.handle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, document->readHandle, instance->processHandle, 0, 0); - EsMessagePostRemote(instance->processHandle, &m); + m.tabOperation.handle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, document->readHandle, instance->process->handle, 0, 0); + EsMessagePostRemote(instance->process->handle, &m); } } @@ -1831,6 +1974,7 @@ void ConfigurationLoadApplications() { { InstalledApplication *application = (InstalledApplication *) EsHeapAllocate(sizeof(InstalledApplication), true); + application->cName = (char *) "(blank tab)"; application->id = APPLICATION_ID_DESKTOP_BLANK_TAB; application->hidden = true; application->createInstance = InstanceBlankTabCreate; @@ -1849,6 +1993,7 @@ void ConfigurationLoadApplications() { { InstalledApplication *application = (InstalledApplication *) EsHeapAllocate(sizeof(InstalledApplication), true); + application->cName = (char *) "(crashed tab)"; application->id = APPLICATION_ID_DESKTOP_CRASHED; application->hidden = true; application->createInstance = InstanceCrashedTabCreate; @@ -2014,12 +2159,12 @@ ApplicationInstance *ApplicationInstanceFindForeground() { void CheckForegroundWindowResponding(EsGeneric) { ApplicationInstance *instance = ApplicationInstanceFindForeground(); EsTimerSet(2500, CheckForegroundWindowResponding, 0); - if (!instance) return; + if (!instance || !instance->process) return; WindowTab *tab = instance->tab; EsProcessState state; - EsProcessGetState(instance->processHandle, &state); + EsProcessGetState(instance->process->handle, &state); if (state.flags & ES_PROCESS_STATE_PINGED) { if (tab->notRespondingInstance) { @@ -2042,7 +2187,7 @@ void CheckForegroundWindowResponding(EsGeneric) { EsMessage m; EsMemoryZero(&m, sizeof(EsMessage)); m.type = ES_MSG_PING; - EsMessagePostRemote(instance->processHandle, &m); + EsMessagePostRemote(instance->process->handle, &m); } } } @@ -2215,10 +2360,10 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) { ApplicationInstance *foreground = ApplicationInstanceFindForeground(); - if (foreground && foreground->processHandle) { + if (foreground && foreground->process) { EsMessage m = { ES_MSG_PRIMARY_CLIPBOARD_UPDATED }; m.tabOperation.id = foreground->embeddedWindowID; - EsMessagePostRemote(foreground->processHandle, &m); + EsMessagePostRemote(foreground->process->handle, &m); } } else { EsHandleClose(desktop.nextClipboardFile); @@ -2270,12 +2415,14 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) { InstanceAnnouncePathMoved(application, oldPath, oldPathBytes, newPath, newPathBytes); } } else if (buffer[0] == DESKTOP_MSG_START_USER_TASK && pipe) { - InstalledApplication *application = ApplicationFindByPID(message->desktop.processID); + ApplicationProcess *process = ApplicationProcessFindByPID(message->desktop.processID); - if (!application) { + if (!process || !process->instanceCount) { return; } + InstalledApplication *application = process->application; + // HACK User tasks use an embedded window object for IPC. // This allows us to basically treat them like other instances. @@ -2303,15 +2450,10 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) { instance->isUserTask = true; instance->embeddedWindowHandle = windowHandle; instance->embeddedWindowID = EsSyscall(ES_SYSCALL_WINDOW_GET_ID, windowHandle, 0, 0, 0); - instance->processHandle = processHandle; - instance->processID = message->desktop.processID; + instance->process = process; + instance->process->instanceCount++; instance->application = application; - if (application->singleProcessHandle) { - EsAssert(application->openInstanceCount); - application->openInstanceCount++; - } - EsHandle targetWindowHandle = EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, windowHandle, processHandle, 0, ES_WINDOW_PROPERTY_EMBED_OWNER); EsBufferWrite(pipe, &targetWindowHandle, sizeof(targetWindowHandle)); @@ -2373,7 +2515,7 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) { m.type = ES_MSG_INSTANCE_RENAME_RESPONSE; m.tabOperation.id = instance->embeddedWindowID; m.tabOperation.error = EsPathMove(oldPath, oldPathBytes, newPath, newPathBytes); - EsMessagePostRemote(instance->processHandle, &m); + EsMessagePostRemote(instance->process->handle, &m); if (m.tabOperation.error == ES_SUCCESS) { InstanceAnnouncePathMoved(nullptr, oldPath, oldPathBytes, newPath, newPathBytes); @@ -2433,31 +2575,8 @@ void EmbeddedWindowDestroyed(EsObjectID id) { if (!instance) return; EsHandleClose(instance->embeddedWindowHandle); - if (instance->processHandle) EsHandleClose(instance->processHandle); - if (instance->documentID) { - OpenDocumentCloseReference(instance->documentID); - } - - InstalledApplication *application = instance->application; - - if (application && application->singleInstance) { - application->singleInstance = nullptr; - } - - if (application && application->singleProcessHandle) { - EsAssert(application->openInstanceCount); - application->openInstanceCount--; - - if (!application->openInstanceCount && application->useSingleProcess) { - EsMessage m = { ES_MSG_APPLICATION_EXIT }; - EsMessagePostRemote(application->singleProcessHandle, &m); - EsHandleClose(application->singleProcessHandle); - application->singleProcessHandle = ES_INVALID_HANDLE; - ApplicationTemporaryDestroy(application); - application = nullptr; - } - } + ApplicationInstanceCleanup(instance); if (instance->tab) { WindowTabDestroy(instance->tab); @@ -2521,63 +2640,44 @@ void DesktopMessage(EsMessage *message) { } else if (message->type == ES_MSG_REGISTER_FILE_SYSTEM) { EsHandle rootDirectory = message->registerFileSystem.rootDirectory; - for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { - ApplicationInstance *instance = desktop.allApplicationInstances[i]; + for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) { + ApplicationProcess *process = desktop.allApplicationProcesses[i]; - if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_ALL_FILES) - && instance->processHandle && !instance->application->notified) { - message->registerFileSystem.rootDirectory = EsSyscall(ES_SYSCALL_HANDLE_SHARE, rootDirectory, instance->processHandle, 0, 0); - EsMessagePostRemote(instance->processHandle, message); - if (instance->application->useSingleProcess) instance->application->notified = true; + if (process->application && (process->application->permissions & APPLICATION_PERMISSION_ALL_FILES)) { + message->registerFileSystem.rootDirectory = EsSyscall(ES_SYSCALL_HANDLE_SHARE, rootDirectory, process->handle, 0, 0); + EsMessagePostRemote(process->handle, message); } } - - for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { - desktop.installedApplications[i]->notified = false; - } } else if (message->type == ES_MSG_DEVICE_CONNECTED) { EsHandle handle = message->device.handle; - for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { - ApplicationInstance *instance = desktop.allApplicationInstances[i]; + for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) { + ApplicationProcess *process = desktop.allApplicationProcesses[i]; - if (instance->application && (instance->application->permissions & APPLICATION_PERMISSION_ALL_DEVICES) - && instance->processHandle && !instance->application->notified) { - message->device.handle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, handle, instance->processHandle, 0, 0); - EsMessagePostRemote(instance->processHandle, message); - if (instance->application->useSingleProcess) instance->application->notified = true; + if (process->application && (process->application->permissions & APPLICATION_PERMISSION_ALL_DEVICES)) { + message->device.handle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, handle, process->handle, 0, 0); + EsMessagePostRemote(process->handle, message); } } - - for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { - desktop.installedApplications[i]->notified = false; - } } else if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM || message->type == ES_MSG_DEVICE_DISCONNECTED) { - for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { - ApplicationInstance *instance = desktop.allApplicationInstances[i]; + for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) { + ApplicationProcess *process = desktop.allApplicationProcesses[i]; - if (!instance->application) { + if (!process->application) { continue; } if (message->type == ES_MSG_UNREGISTER_FILE_SYSTEM) { - if (~instance->application->permissions & APPLICATION_PERMISSION_ALL_FILES) { + if (~process->application->permissions & APPLICATION_PERMISSION_ALL_FILES) { continue; } } else if (message->type == ES_MSG_DEVICE_DISCONNECTED) { - if (~instance->application->permissions & APPLICATION_PERMISSION_ALL_DEVICES) { + if (~process->application->permissions & APPLICATION_PERMISSION_ALL_DEVICES) { continue; } } - if (instance->processHandle && !instance->application->notified) { - 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; + EsMessagePostRemote(process->handle, message); } } else if (message->type == ES_MSG_SET_SCREEN_RESOLUTION) { if (desktop.setupDesktopUIComplete) { diff --git a/desktop/os.header b/desktop/os.header index cd02ecb..ec0134e 100644 --- a/desktop/os.header +++ b/desktop/os.header @@ -695,7 +695,6 @@ define ES_ELEMENT_FOCUS_ENSURE_VISIBLE (1 << 0) define ES_ELEMENT_FOCUS_FROM_KEYBOARD (1 << 1) define ES_APPLICATION_STARTUP_MANUAL_PATH (1 << 0) -define ES_APPLICATION_STARTUP_SINGLE_INSTANCE_IN_PROCESS (1 << 1) define ES_LIST_VIEW_INLINE_TEXTBOX_COPY_EXISTING_TEXT (1 << 0) define ES_LIST_VIEW_INLINE_TEXTBOX_REJECT_EDIT_IF_FOCUS_LOST (1 << 1) diff --git a/desktop/settings.cpp b/desktop/settings.cpp index 836271c..6697c62 100644 --- a/desktop/settings.cpp +++ b/desktop/settings.cpp @@ -146,17 +146,8 @@ void SettingsUpdateGlobalAndWindowManager() { EsMemoryZero(&m, sizeof(EsMessage)); m.type = ES_MSG_UI_SCALE_CHANGED; - for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { - ApplicationInstance *instance = desktop.allApplicationInstances[i]; - - if (instance->processHandle && !instance->application->notified) { - EsMessagePostRemote(instance->processHandle, &m); - if (instance->application->useSingleProcess) instance->application->notified = true; - } - } - - for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) { - desktop.installedApplications[i]->notified = false; + for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) { + EsMessagePostRemote(desktop.allApplicationProcesses[i]->handle, &m); } } }