mirror of https://gitlab.com/nakst/essence
				
				
				
			use pipe for desktop requests
This commit is contained in:
		
							parent
							
								
									afed49f30b
								
							
						
					
					
						commit
						9e610bd928
					
				| 
						 | 
					@ -191,6 +191,8 @@ struct {
 | 
				
			||||||
	Array<EsSystemConfigurationGroup> systemConfigurationGroups;
 | 
						Array<EsSystemConfigurationGroup> systemConfigurationGroups;
 | 
				
			||||||
	EsMutex systemConfigurationMutex;
 | 
						EsMutex systemConfigurationMutex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EsHandle desktopRequestPipe, desktopResponsePipe;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Array<MountPoint> mountPoints;
 | 
						Array<MountPoint> mountPoints;
 | 
				
			||||||
	Array<EsMessageDevice> connectedDevices;
 | 
						Array<EsMessageDevice> connectedDevices;
 | 
				
			||||||
	bool foundBootFileSystem;
 | 
						bool foundBootFileSystem;
 | 
				
			||||||
| 
						 | 
					@ -1049,7 +1051,7 @@ EsMessage *EsMessageReceive() {
 | 
				
			||||||
		} else if (message.message.type == ES_MSG_APPLICATION_EXIT) {
 | 
							} else if (message.message.type == ES_MSG_APPLICATION_EXIT) {
 | 
				
			||||||
			if (api.startupInformation->isDesktop) {
 | 
								if (api.startupInformation->isDesktop) {
 | 
				
			||||||
				// Desktop tracks the number of instances it owns, so it needs to know when it exits.
 | 
									// Desktop tracks the number of instances it owns, so it needs to know when it exits.
 | 
				
			||||||
				ApplicationProcessTerminated(EsProcessGetID(ES_CURRENT_PROCESS));
 | 
									ApplicationProcessTerminated(DesktopGetApplicationProcessForDesktop());
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				api.workFinish = true;
 | 
									api.workFinish = true;
 | 
				
			||||||
				if (api.workAvailable) EsEventSet(api.workAvailable);
 | 
									if (api.workAvailable) EsEventSet(api.workAvailable);
 | 
				
			||||||
| 
						 | 
					@ -1573,6 +1575,8 @@ extern "C" void _start(EsProcessStartupInformation *_startupInformation) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const SystemStartupDataHeader *header = (const SystemStartupDataHeader *) EsBufferRead(&buffer, sizeof(SystemStartupDataHeader));
 | 
							const SystemStartupDataHeader *header = (const SystemStartupDataHeader *) EsBufferRead(&buffer, sizeof(SystemStartupDataHeader));
 | 
				
			||||||
		theming.cursorData = header->themeCursorData;
 | 
							theming.cursorData = header->themeCursorData;
 | 
				
			||||||
 | 
							api.desktopRequestPipe = header->desktopRequestPipe;
 | 
				
			||||||
 | 
							api.desktopResponsePipe = header->desktopResponsePipe;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (uintptr_t i = 0; i < header->initialMountPointCount; i++) {
 | 
							for (uintptr_t i = 0; i < header->initialMountPointCount; i++) {
 | 
				
			||||||
			const EsMountPoint *mountPoint = (const EsMountPoint *) EsBufferRead(&buffer, sizeof(EsMountPoint));
 | 
								const EsMountPoint *mountPoint = (const EsMountPoint *) EsBufferRead(&buffer, sizeof(EsMountPoint));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -138,6 +138,7 @@ struct BlankTabInstance : EsInstance {
 | 
				
			||||||
struct ApplicationProcess {
 | 
					struct ApplicationProcess {
 | 
				
			||||||
	EsObjectID id;
 | 
						EsObjectID id;
 | 
				
			||||||
	EsHandle handle;
 | 
						EsHandle handle;
 | 
				
			||||||
 | 
						EsHandle desktopRequestPipe, desktopResponsePipe;
 | 
				
			||||||
	InstalledApplication *application;
 | 
						InstalledApplication *application;
 | 
				
			||||||
	size_t instanceCount;
 | 
						size_t instanceCount;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -1664,6 +1665,127 @@ void ApplicationTemporaryDestroy(InstalledApplication *application) {
 | 
				
			||||||
	EsAssert(false);
 | 
						EsAssert(false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ApplicationProcessTerminated(ApplicationProcess *process) {
 | 
				
			||||||
 | 
						EsMessageMutexCheck();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						desktop.allApplicationProcesses.FindAndDeleteSwap(process, true /* assert found */);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) {
 | 
				
			||||||
 | 
							ApplicationInstance *instance = desktop.allApplicationInstances[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (instance->process == process) {
 | 
				
			||||||
 | 
								EmbeddedWindowDestroyed(instance->embeddedWindowID);
 | 
				
			||||||
 | 
								i--; // EmbeddedWindowDestroyed removes it from the array.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InstalledApplication *application = process->application;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (application) {
 | 
				
			||||||
 | 
							if (application->singleProcess == process) {
 | 
				
			||||||
 | 
								application->singleProcess = nullptr;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							application->singleInstance = nullptr;
 | 
				
			||||||
 | 
							ApplicationTemporaryDestroy(application);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (uintptr_t i = 0; i < desktop.openDocuments.Count(); i++) {
 | 
				
			||||||
 | 
							OpenDocument *document = &desktop.openDocuments[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (document->currentWriter == process->id) {
 | 
				
			||||||
 | 
								document->currentWriter = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!desktop.allApplicationProcesses.Length() && desktop.inShutdown) {
 | 
				
			||||||
 | 
							EsEventSet(desktop.shutdownReadyEvent);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EsAssert(!process->instanceCount);
 | 
				
			||||||
 | 
						EsHandleClose(process->handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (process->desktopRequestPipe) {
 | 
				
			||||||
 | 
							EsHandleClose(process->desktopRequestPipe);
 | 
				
			||||||
 | 
							EsHandleClose(process->desktopResponsePipe);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							// This must be a Desktop-owned instance.
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EsHeapFree(process);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DesktopRequestThread(EsGeneric argument) {
 | 
				
			||||||
 | 
						ApplicationProcess *process = (ApplicationProcess *) argument.p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t length;
 | 
				
			||||||
 | 
						size_t bytes;
 | 
				
			||||||
 | 
						EsObjectID embeddedWindowID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (true) {
 | 
				
			||||||
 | 
							bytes = EsPipeRead(process->desktopRequestPipe, &length, sizeof(length));
 | 
				
			||||||
 | 
							if (bytes != sizeof(length)) break; // Process has terminated or closed the pipe.
 | 
				
			||||||
 | 
							bytes = EsPipeRead(process->desktopRequestPipe, &embeddedWindowID, sizeof(embeddedWindowID));
 | 
				
			||||||
 | 
							if (bytes != sizeof(embeddedWindowID)) break; // Process has terminated or closed the pipe.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (length < 1 || length > DESKTOP_MESSAGE_SIZE_LIMIT) {
 | 
				
			||||||
 | 
								// Discard the message.
 | 
				
			||||||
 | 
								// TODO Crash the process.
 | 
				
			||||||
 | 
								EsPipeRead(process->desktopRequestPipe, nullptr, length); 
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void *buffer = EsHeapAllocate(length, false);
 | 
				
			||||||
 | 
							bytes = EsPipeRead(process->desktopRequestPipe, buffer, length);
 | 
				
			||||||
 | 
							if (bytes != length) break; // Process has terminated or closed the pipe.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!buffer) {
 | 
				
			||||||
 | 
								// The buffer could not be allocated, and the data read from the pipe was discarded.
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							EsBuffer response = { .canGrow = true };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							EsMessageMutexAcquire();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!DesktopSyscall(embeddedWindowID, process, (uint8_t *) buffer, length, &response)) {
 | 
				
			||||||
 | 
								// TODO Crash the process.
 | 
				
			||||||
 | 
								EsPrint("Process %d running application '%z' had a fatal error (this usually means a permission check failed) with desktop request #%d.\n", 
 | 
				
			||||||
 | 
										process->id, process->application->cName, *(uint8_t *) buffer);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							EsMessageMutexRelease();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!response.error) {
 | 
				
			||||||
 | 
								length = response.position;
 | 
				
			||||||
 | 
								EsPipeWrite(process->desktopResponsePipe, &length, sizeof(length));
 | 
				
			||||||
 | 
								EsPipeWrite(process->desktopResponsePipe, response.out, response.position);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								length = 0;
 | 
				
			||||||
 | 
								EsPipeWrite(process->desktopResponsePipe, &length, sizeof(length));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							EsHeapFree(response.out);
 | 
				
			||||||
 | 
							EsHeapFree(buffer);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EsMessageMutexAcquire();
 | 
				
			||||||
 | 
						ApplicationProcessTerminated(process);
 | 
				
			||||||
 | 
						EsMessageMutexRelease();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ApplicationProcess *DesktopGetApplicationProcessForDesktop() {
 | 
				
			||||||
 | 
						EsObjectID desktopProcessID = EsProcessGetID(ES_CURRENT_PROCESS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) {
 | 
				
			||||||
 | 
							if (desktop.allApplicationProcesses[i]->id == desktopProcessID) {
 | 
				
			||||||
 | 
								return desktop.allApplicationProcesses[i];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nullptr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool ApplicationInstanceStart(int64_t applicationID, _EsApplicationStartupInformation *startupInformation, ApplicationInstance *instance) {
 | 
					bool ApplicationInstanceStart(int64_t applicationID, _EsApplicationStartupInformation *startupInformation, ApplicationInstance *instance) {
 | 
				
			||||||
	if (desktop.inShutdown) {
 | 
						if (desktop.inShutdown) {
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
| 
						 | 
					@ -1708,19 +1830,12 @@ bool ApplicationInstanceStart(int64_t applicationID, _EsApplicationStartupInform
 | 
				
			||||||
	ApplicationProcess *process = application->singleProcess;
 | 
						ApplicationProcess *process = application->singleProcess;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (application->createInstance) {
 | 
						if (application->createInstance) {
 | 
				
			||||||
		EsObjectID desktopProcessID = EsProcessGetID(ES_CURRENT_PROCESS);
 | 
							process = DesktopGetApplicationProcessForDesktop();
 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) {
 | 
					 | 
				
			||||||
			if (desktop.allApplicationProcesses[i]->id == desktopProcessID) {
 | 
					 | 
				
			||||||
				process = desktop.allApplicationProcesses[i];
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!process) {
 | 
							if (!process) {
 | 
				
			||||||
			process = (ApplicationProcess *) EsHeapAllocate(sizeof(ApplicationProcess), true);
 | 
								process = (ApplicationProcess *) EsHeapAllocate(sizeof(ApplicationProcess), true);
 | 
				
			||||||
			process->handle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, ES_CURRENT_PROCESS, ES_CURRENT_PROCESS, 0, 0);
 | 
								process->handle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, ES_CURRENT_PROCESS, ES_CURRENT_PROCESS, 0, 0);
 | 
				
			||||||
			process->id = desktopProcessID;
 | 
								process->id = EsProcessGetID(ES_CURRENT_PROCESS);
 | 
				
			||||||
			desktop.allApplicationProcesses.Add(process);
 | 
								desktop.allApplicationProcesses.Add(process);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (!process) {
 | 
						} else if (!process) {
 | 
				
			||||||
| 
						 | 
					@ -1810,10 +1925,16 @@ bool ApplicationInstanceStart(int64_t applicationID, _EsApplicationStartupInform
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							EsHandle desktopRequestReadEnd, desktopRequestWriteEnd, desktopResponseReadEnd, desktopResponseWriteEnd;
 | 
				
			||||||
 | 
							EsPipeCreate(&desktopRequestReadEnd, &desktopRequestWriteEnd);
 | 
				
			||||||
 | 
							EsPipeCreate(&desktopResponseReadEnd, &desktopResponseWriteEnd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		EsBuffer buffer = { .canGrow = true };
 | 
							EsBuffer buffer = { .canGrow = true };
 | 
				
			||||||
		header.initialMountPointCount = initialMountPoints.Length();
 | 
							header.initialMountPointCount = initialMountPoints.Length();
 | 
				
			||||||
		header.initialDeviceCount = initialDevices.Length();
 | 
							header.initialDeviceCount = initialDevices.Length();
 | 
				
			||||||
		header.themeCursorData = theming.cursorData;
 | 
							header.themeCursorData = theming.cursorData;
 | 
				
			||||||
 | 
							header.desktopRequestPipe = desktopRequestWriteEnd;
 | 
				
			||||||
 | 
							header.desktopResponsePipe = desktopResponseReadEnd;
 | 
				
			||||||
		EsBufferWrite(&buffer, &header, sizeof(header));
 | 
							EsBufferWrite(&buffer, &header, sizeof(header));
 | 
				
			||||||
		EsBufferWrite(&buffer, initialMountPoints.array, sizeof(EsMountPoint) * header.initialMountPointCount);
 | 
							EsBufferWrite(&buffer, initialMountPoints.array, sizeof(EsMountPoint) * header.initialMountPointCount);
 | 
				
			||||||
		EsBufferWrite(&buffer, initialDevices.array, sizeof(EsMessageDevice) * header.initialDeviceCount);
 | 
							EsBufferWrite(&buffer, initialDevices.array, sizeof(EsMessageDevice) * header.initialDeviceCount);
 | 
				
			||||||
| 
						 | 
					@ -1822,6 +1943,10 @@ bool ApplicationInstanceStart(int64_t applicationID, _EsApplicationStartupInform
 | 
				
			||||||
		handleModeDuplicateList.Add(0);
 | 
							handleModeDuplicateList.Add(0);
 | 
				
			||||||
		handleDuplicateList.Add(header.themeCursorData);
 | 
							handleDuplicateList.Add(header.themeCursorData);
 | 
				
			||||||
		handleModeDuplicateList.Add(0);
 | 
							handleModeDuplicateList.Add(0);
 | 
				
			||||||
 | 
							handleDuplicateList.Add(header.desktopRequestPipe);
 | 
				
			||||||
 | 
							handleModeDuplicateList.Add(0);
 | 
				
			||||||
 | 
							handleDuplicateList.Add(header.desktopResponsePipe);
 | 
				
			||||||
 | 
							handleModeDuplicateList.Add(0);
 | 
				
			||||||
		EsHeapFree(buffer.out);
 | 
							EsHeapFree(buffer.out);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		arguments.handles = handleDuplicateList.array;
 | 
							arguments.handles = handleDuplicateList.array;
 | 
				
			||||||
| 
						 | 
					@ -1835,6 +1960,9 @@ bool ApplicationInstanceStart(int64_t applicationID, _EsApplicationStartupInform
 | 
				
			||||||
		if (settingsNode.handle)       EsHandleClose(settingsNode.handle);
 | 
							if (settingsNode.handle)       EsHandleClose(settingsNode.handle);
 | 
				
			||||||
		if (arguments.data.systemData) EsHandleClose(arguments.data.systemData);
 | 
							if (arguments.data.systemData) EsHandleClose(arguments.data.systemData);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							EsHandleClose(desktopResponseReadEnd);
 | 
				
			||||||
 | 
							EsHandleClose(desktopRequestWriteEnd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!ES_CHECK_ERROR(error)) {
 | 
							if (!ES_CHECK_ERROR(error)) {
 | 
				
			||||||
			EsHandleClose(information.mainThread.handle);
 | 
								EsHandleClose(information.mainThread.handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1842,8 +1970,17 @@ bool ApplicationInstanceStart(int64_t applicationID, _EsApplicationStartupInform
 | 
				
			||||||
			process->handle = information.handle;
 | 
								process->handle = information.handle;
 | 
				
			||||||
			process->id = information.pid;
 | 
								process->id = information.pid;
 | 
				
			||||||
			process->application = application;
 | 
								process->application = application;
 | 
				
			||||||
 | 
								process->desktopResponsePipe = desktopResponseWriteEnd;
 | 
				
			||||||
 | 
								process->desktopRequestPipe = desktopRequestReadEnd;
 | 
				
			||||||
			desktop.allApplicationProcesses.Add(process);
 | 
								desktop.allApplicationProcesses.Add(process);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								EsThreadInformation information;
 | 
				
			||||||
 | 
								EsThreadCreate(DesktopRequestThread, &information, process); 
 | 
				
			||||||
 | 
								EsHandleClose(information.handle);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
 | 
								EsHandleClose(desktopRequestReadEnd);
 | 
				
			||||||
 | 
								EsHandleClose(desktopResponseWriteEnd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			ApplicationTemporaryDestroy(application);
 | 
								ApplicationTemporaryDestroy(application);
 | 
				
			||||||
			_EsApplicationStartupInformation s = {};
 | 
								_EsApplicationStartupInformation s = {};
 | 
				
			||||||
			s.data = CRASHED_TAB_INVALID_EXECUTABLE;
 | 
								s.data = CRASHED_TAB_INVALID_EXECUTABLE;
 | 
				
			||||||
| 
						 | 
					@ -1931,15 +2068,11 @@ ApplicationInstance *ApplicationInstanceCreate(int64_t id, _EsApplicationStartup
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ApplicationProcess *ApplicationProcessFindByPID(EsObjectID pid, bool removeIfFound = false) {
 | 
					ApplicationProcess *ApplicationProcessFindByPID(EsObjectID pid) {
 | 
				
			||||||
	for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) {
 | 
						for (uintptr_t i = 0; i < desktop.allApplicationProcesses.Length(); i++) {
 | 
				
			||||||
		ApplicationProcess *process = desktop.allApplicationProcesses[i];
 | 
							ApplicationProcess *process = desktop.allApplicationProcesses[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (process->id == pid) {
 | 
							if (process->id == pid) {
 | 
				
			||||||
			if (removeIfFound) {
 | 
					 | 
				
			||||||
				desktop.allApplicationProcesses.DeleteSwap(i);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			return process;
 | 
								return process;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1994,48 +2127,6 @@ void ApplicationInstanceCrashed(EsMessage *message) {
 | 
				
			||||||
	EsHandleClose(processHandle);
 | 
						EsHandleClose(processHandle);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ApplicationProcessTerminated(EsObjectID pid) {
 | 
					 | 
				
			||||||
	for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) {
 | 
					 | 
				
			||||||
		ApplicationInstance *instance = desktop.allApplicationInstances[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (instance->process->id == pid) {
 | 
					 | 
				
			||||||
			EmbeddedWindowDestroyed(instance->embeddedWindowID);
 | 
					 | 
				
			||||||
			i--; // EmbeddedWindowDestroyed removes it from the array.
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	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++) {
 | 
					 | 
				
			||||||
		OpenDocument *document = &desktop.openDocuments[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (document->currentWriter == pid) {
 | 
					 | 
				
			||||||
			document->currentWriter = 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!desktop.allApplicationProcesses.Length() && desktop.inShutdown) {
 | 
					 | 
				
			||||||
		EsEventSet(desktop.shutdownReadyEvent);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//////////////////////////////////////////////////////
 | 
					//////////////////////////////////////////////////////
 | 
				
			||||||
// Document management:
 | 
					// Document management:
 | 
				
			||||||
//////////////////////////////////////////////////////
 | 
					//////////////////////////////////////////////////////
 | 
				
			||||||
| 
						 | 
					@ -2693,15 +2784,23 @@ void DesktopSetup() {
 | 
				
			||||||
	desktop.setupDesktopUIComplete = true;
 | 
						desktop.setupDesktopUIComplete = true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
 | 
					bool /* returns false on fatal error */ DesktopSyscall(EsObjectID windowID, ApplicationProcess *process, uint8_t *buffer, size_t bytes, EsBuffer *pipe) {
 | 
				
			||||||
	ApplicationInstance *instance = ApplicationInstanceFindByWindowID(message->desktop.windowID);
 | 
						EsMessageMutexCheck();
 | 
				
			||||||
 | 
						EsAssert(process);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ApplicationInstance *instance = ApplicationInstanceFindByWindowID(windowID);
 | 
				
			||||||
 | 
						InstalledApplication *application = process->application;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (instance && instance->process != process) {
 | 
				
			||||||
 | 
							EsPrint("DesktopSyscall - Process %d cannot operate on instance %d.\n", process->id, instance->embeddedWindowID);
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (buffer[0] == DESKTOP_MSG_START_APPLICATION) {
 | 
						if (buffer[0] == DESKTOP_MSG_START_APPLICATION) {
 | 
				
			||||||
		InstalledApplication *application = ApplicationFindByPID(message->desktop.processID);
 | 
							if (~application->permissions & APPLICATION_PERMISSION_START_APPLICATION) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (application && (application->permissions & APPLICATION_PERMISSION_START_APPLICATION)) {
 | 
					 | 
				
			||||||
		// TODO Restricting what flags can be requested?
 | 
							// TODO Restricting what flags can be requested?
 | 
				
			||||||
			EsBuffer b = { .in = buffer + 1, .bytes = message->desktop.bytes - 1 };
 | 
							EsBuffer b = { .in = buffer + 1, .bytes = bytes - 1 };
 | 
				
			||||||
		EsApplicationStartupRequest request = {};
 | 
							EsApplicationStartupRequest request = {};
 | 
				
			||||||
		EsBufferReadInto(&b, &request, sizeof(EsApplicationStartupRequest));
 | 
							EsBufferReadInto(&b, &request, sizeof(EsApplicationStartupRequest));
 | 
				
			||||||
		request.filePath = (const char *) EsBufferRead(&b, request.filePathBytes);
 | 
							request.filePath = (const char *) EsBufferRead(&b, request.filePathBytes);
 | 
				
			||||||
| 
						 | 
					@ -2715,11 +2814,7 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			OpenDocumentWithApplication(&request, container);
 | 
								OpenDocumentWithApplication(&request, container);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if (buffer[0] == DESKTOP_MSG_CREATE_CLIPBOARD_FILE && pipe) {
 | 
						} else if (buffer[0] == DESKTOP_MSG_CREATE_CLIPBOARD_FILE && pipe) {
 | 
				
			||||||
		EsHandle processHandle = EsProcessOpen(message->desktop.processID);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (processHandle) {
 | 
					 | 
				
			||||||
		EsHandle handle;
 | 
							EsHandle handle;
 | 
				
			||||||
		char *path;
 | 
							char *path;
 | 
				
			||||||
		size_t pathBytes;
 | 
							size_t pathBytes;
 | 
				
			||||||
| 
						 | 
					@ -2731,9 +2826,9 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			desktop.nextClipboardFile = handle;
 | 
								desktop.nextClipboardFile = handle;
 | 
				
			||||||
				desktop.nextClipboardProcessID = message->desktop.processID;
 | 
								desktop.nextClipboardProcessID = process->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				handle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, handle, processHandle, 0, 0);
 | 
								handle = EsSyscall(ES_SYSCALL_HANDLE_SHARE, handle, process->handle, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			EsHeapFree(path);
 | 
								EsHeapFree(path);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
| 
						 | 
					@ -2742,11 +2837,8 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		EsBufferWrite(pipe, &handle, sizeof(handle));
 | 
							EsBufferWrite(pipe, &handle, sizeof(handle));
 | 
				
			||||||
		EsBufferWrite(pipe, &error, sizeof(error));
 | 
							EsBufferWrite(pipe, &error, sizeof(error));
 | 
				
			||||||
 | 
						} else if (buffer[0] == DESKTOP_MSG_CLIPBOARD_PUT && bytes == sizeof(ClipboardInformation)
 | 
				
			||||||
			EsHandleClose(processHandle);
 | 
								&& desktop.nextClipboardFile && desktop.nextClipboardProcessID == process->id) {
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if (buffer[0] == DESKTOP_MSG_CLIPBOARD_PUT && message->desktop.bytes == sizeof(ClipboardInformation)
 | 
					 | 
				
			||||||
			&& desktop.nextClipboardFile && desktop.nextClipboardProcessID == message->desktop.processID) {
 | 
					 | 
				
			||||||
		ClipboardInformation *information = (ClipboardInformation *) buffer;
 | 
							ClipboardInformation *information = (ClipboardInformation *) buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (information->error == ES_SUCCESS) {
 | 
							if (information->error == ES_SUCCESS) {
 | 
				
			||||||
| 
						 | 
					@ -2772,83 +2864,62 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
 | 
				
			||||||
		desktop.nextClipboardFile = ES_INVALID_HANDLE;
 | 
							desktop.nextClipboardFile = ES_INVALID_HANDLE;
 | 
				
			||||||
		desktop.nextClipboardProcessID = 0;
 | 
							desktop.nextClipboardProcessID = 0;
 | 
				
			||||||
	} else if (buffer[0] == DESKTOP_MSG_CLIPBOARD_GET && pipe) {
 | 
						} else if (buffer[0] == DESKTOP_MSG_CLIPBOARD_GET && pipe) {
 | 
				
			||||||
		EsHandle processHandle = EsProcessOpen(message->desktop.processID);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (processHandle) {
 | 
					 | 
				
			||||||
		EsHandle fileHandle = desktop.clipboardFile 
 | 
							EsHandle fileHandle = desktop.clipboardFile 
 | 
				
			||||||
				? EsSyscall(ES_SYSCALL_HANDLE_SHARE, desktop.clipboardFile, processHandle, 1 /* ES_FILE_READ_SHARED */, 0) : ES_INVALID_HANDLE;
 | 
								? EsSyscall(ES_SYSCALL_HANDLE_SHARE, desktop.clipboardFile, process->handle, 1 /* ES_FILE_READ_SHARED */, 0) : ES_INVALID_HANDLE;
 | 
				
			||||||
		EsBufferWrite(pipe, &desktop.clipboardInformation, sizeof(desktop.clipboardInformation));
 | 
							EsBufferWrite(pipe, &desktop.clipboardInformation, sizeof(desktop.clipboardInformation));
 | 
				
			||||||
		EsBufferWrite(pipe, &fileHandle, sizeof(fileHandle));
 | 
							EsBufferWrite(pipe, &fileHandle, sizeof(fileHandle));
 | 
				
			||||||
			EsHandleClose(processHandle);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if (buffer[0] == DESKTOP_MSG_SYSTEM_CONFIGURATION_GET && pipe) {
 | 
						} else if (buffer[0] == DESKTOP_MSG_SYSTEM_CONFIGURATION_GET && pipe) {
 | 
				
			||||||
		InstalledApplication *application = ApplicationFindByPID(message->desktop.processID);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ConfigurationWriteSectionsToBuffer("font", nullptr, false, pipe);
 | 
							ConfigurationWriteSectionsToBuffer("font", nullptr, false, pipe);
 | 
				
			||||||
		ConfigurationWriteSectionsToBuffer(nullptr, "ui_fonts", false, pipe);
 | 
							ConfigurationWriteSectionsToBuffer(nullptr, "ui_fonts", false, pipe);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (application && (application->permissions & APPLICATION_PERMISSION_ALL_FILES)) {
 | 
							if (application->permissions & APPLICATION_PERMISSION_ALL_FILES) {
 | 
				
			||||||
			ConfigurationWriteSectionsToBuffer(nullptr, "paths", false, pipe);
 | 
								ConfigurationWriteSectionsToBuffer(nullptr, "paths", false, pipe);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (buffer[0] == DESKTOP_MSG_REQUEST_SHUTDOWN) {
 | 
						} else if (buffer[0] == DESKTOP_MSG_REQUEST_SHUTDOWN) {
 | 
				
			||||||
		InstalledApplication *application = ApplicationFindByPID(message->desktop.processID);
 | 
							if (~application->permissions & APPLICATION_PERMISSION_SHUTDOWN) return false;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (application && (application->permissions & APPLICATION_PERMISSION_SHUTDOWN)) {
 | 
					 | 
				
			||||||
		ShutdownModalCreate();
 | 
							ShutdownModalCreate();
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if (buffer[0] == DESKTOP_MSG_FILE_TYPES_GET && pipe) {
 | 
						} else if (buffer[0] == DESKTOP_MSG_FILE_TYPES_GET && pipe) {
 | 
				
			||||||
		InstalledApplication *application = ApplicationFindByPID(message->desktop.processID);
 | 
							if (~application->permissions & APPLICATION_PERMISSION_VIEW_FILE_TYPES) return false;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (application && (application->permissions & APPLICATION_PERMISSION_VIEW_FILE_TYPES)) {
 | 
					 | 
				
			||||||
		ConfigurationWriteSectionsToBuffer("file_type", nullptr, false, pipe);
 | 
							ConfigurationWriteSectionsToBuffer("file_type", nullptr, false, pipe);
 | 
				
			||||||
		}
 | 
						} else if (buffer[0] == DESKTOP_MSG_ANNOUNCE_PATH_MOVED && bytes > 1 + sizeof(uintptr_t) * 2) {
 | 
				
			||||||
	} else if (buffer[0] == DESKTOP_MSG_ANNOUNCE_PATH_MOVED && message->desktop.bytes > 1 + sizeof(uintptr_t) * 2) {
 | 
							if (~application->permissions & APPLICATION_PERMISSION_ALL_FILES) return false;
 | 
				
			||||||
		InstalledApplication *application = ApplicationFindByPID(message->desktop.processID);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (application && (application->permissions & APPLICATION_PERMISSION_ALL_FILES)) {
 | 
					 | 
				
			||||||
		uintptr_t oldPathBytes, newPathBytes;
 | 
							uintptr_t oldPathBytes, newPathBytes;
 | 
				
			||||||
		EsMemoryCopy(&oldPathBytes, buffer + 1, sizeof(uintptr_t));
 | 
							EsMemoryCopy(&oldPathBytes, buffer + 1, sizeof(uintptr_t));
 | 
				
			||||||
		EsMemoryCopy(&newPathBytes, buffer + 1 + sizeof(uintptr_t), sizeof(uintptr_t));
 | 
							EsMemoryCopy(&newPathBytes, buffer + 1 + sizeof(uintptr_t), sizeof(uintptr_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (oldPathBytes >= 0x4000 || newPathBytes >= 0x4000
 | 
							if (oldPathBytes >= 0x4000 || newPathBytes >= 0x4000
 | 
				
			||||||
					|| oldPathBytes + newPathBytes + sizeof(uintptr_t) * 2 + 1 != message->desktop.bytes) {
 | 
									|| oldPathBytes + newPathBytes + sizeof(uintptr_t) * 2 + 1 != bytes) {
 | 
				
			||||||
				return;
 | 
								return true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const char *oldPath = (const char *) buffer + 1 + sizeof(uintptr_t) * 2;
 | 
							const char *oldPath = (const char *) buffer + 1 + sizeof(uintptr_t) * 2;
 | 
				
			||||||
		const char *newPath = (const char *) buffer + 1 + sizeof(uintptr_t) * 2 + oldPathBytes;
 | 
							const char *newPath = (const char *) buffer + 1 + sizeof(uintptr_t) * 2 + oldPathBytes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		InstanceAnnouncePathMoved(application, oldPath, oldPathBytes, newPath, newPathBytes);
 | 
							InstanceAnnouncePathMoved(application, oldPath, oldPathBytes, newPath, newPathBytes);
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if (buffer[0] == DESKTOP_MSG_START_USER_TASK && pipe) {
 | 
						} else if (buffer[0] == DESKTOP_MSG_START_USER_TASK && pipe) {
 | 
				
			||||||
		ApplicationProcess *process = ApplicationProcessFindByPID(message->desktop.processID);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!process || !process->instanceCount) {
 | 
							if (!process || !process->instanceCount) {
 | 
				
			||||||
			return;
 | 
								return false;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		InstalledApplication *application = process->application;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// HACK User tasks use an embedded window object for IPC.
 | 
							// HACK User tasks use an embedded window object for IPC.
 | 
				
			||||||
		// 	This allows us to basically treat them like other instances.
 | 
							// 	This allows us to basically treat them like other instances.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		EsHandle processHandle = EsProcessOpen(message->desktop.processID);
 | 
					 | 
				
			||||||
		EsHandle windowHandle = EsSyscall(ES_SYSCALL_WINDOW_CREATE, ES_WINDOW_NORMAL, 0, 0, 0);
 | 
							EsHandle windowHandle = EsSyscall(ES_SYSCALL_WINDOW_CREATE, ES_WINDOW_NORMAL, 0, 0, 0);
 | 
				
			||||||
		ApplicationInstance *instance = (ApplicationInstance *) EsHeapAllocate(sizeof(ApplicationInstance), true);
 | 
							ApplicationInstance *instance = (ApplicationInstance *) EsHeapAllocate(sizeof(ApplicationInstance), true);
 | 
				
			||||||
		bool added = false;
 | 
							bool added = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (processHandle && windowHandle && instance) {
 | 
							if (windowHandle && instance) {
 | 
				
			||||||
			added = desktop.allApplicationInstances.Add(instance);
 | 
								added = desktop.allApplicationInstances.Add(instance);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!processHandle || !windowHandle || !instance || !added) {
 | 
							if (!windowHandle || !instance || !added) {
 | 
				
			||||||
			if (processHandle) EsHandleClose(processHandle);
 | 
					 | 
				
			||||||
			if (windowHandle) EsHandleClose(windowHandle);
 | 
								if (windowHandle) EsHandleClose(windowHandle);
 | 
				
			||||||
			if (instance) EsHeapFree(instance);
 | 
								if (instance) EsHeapFree(instance);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			EsHandle invalid = ES_INVALID_HANDLE;
 | 
								EsHandle invalid = ES_INVALID_HANDLE;
 | 
				
			||||||
			EsBufferWrite(pipe, &invalid, sizeof(invalid));
 | 
								EsBufferWrite(pipe, &invalid, sizeof(invalid));
 | 
				
			||||||
			return;
 | 
								return true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		instance->title[0] = ' ';
 | 
							instance->title[0] = ' ';
 | 
				
			||||||
| 
						 | 
					@ -2860,21 +2931,20 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
 | 
				
			||||||
		instance->process->instanceCount++;
 | 
							instance->process->instanceCount++;
 | 
				
			||||||
		instance->application = application;
 | 
							instance->application = application;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		EsHandle targetWindowHandle = EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, windowHandle, processHandle, 0, ES_WINDOW_PROPERTY_EMBED_OWNER);
 | 
							EsHandle targetWindowHandle = EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, windowHandle, process->handle, 0, ES_WINDOW_PROPERTY_EMBED_OWNER);
 | 
				
			||||||
		EsBufferWrite(pipe, &targetWindowHandle, sizeof(targetWindowHandle));
 | 
							EsBufferWrite(pipe, &targetWindowHandle, sizeof(targetWindowHandle));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		desktop.allOngoingUserTasks.Add(instance);
 | 
							desktop.allOngoingUserTasks.Add(instance);
 | 
				
			||||||
		TaskBarTasksButtonUpdate();
 | 
							TaskBarTasksButtonUpdate();
 | 
				
			||||||
	} else if (buffer[0] == DESKTOP_MSG_QUERY_OPEN_DOCUMENT) {
 | 
						} else if (buffer[0] == DESKTOP_MSG_QUERY_OPEN_DOCUMENT) {
 | 
				
			||||||
		InstalledApplication *application = ApplicationFindByPID(message->desktop.processID);
 | 
							if (~application->permissions & APPLICATION_PERMISSION_ALL_FILES) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (application && (application->permissions & APPLICATION_PERMISSION_ALL_FILES)) {
 | 
					 | 
				
			||||||
		EsObjectID id = 0;
 | 
							EsObjectID id = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		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];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if (0 == EsStringCompare(document->path, document->pathBytes, (char *) buffer + 1, message->desktop.bytes - 1)) {
 | 
								if (0 == EsStringCompare(document->path, document->pathBytes, (char *) buffer + 1, bytes - 1)) {
 | 
				
			||||||
				id = document->id;
 | 
									id = document->id;
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -2900,11 +2970,9 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		EsBufferWrite(pipe, &information, sizeof(information));
 | 
							EsBufferWrite(pipe, &information, sizeof(information));
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if (buffer[0] == DESKTOP_MSG_LIST_OPEN_DOCUMENTS) {
 | 
						} else if (buffer[0] == DESKTOP_MSG_LIST_OPEN_DOCUMENTS) {
 | 
				
			||||||
		InstalledApplication *application = ApplicationFindByPID(message->desktop.processID);
 | 
							if (~application->permissions & APPLICATION_PERMISSION_ALL_FILES) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (application && (application->permissions & APPLICATION_PERMISSION_ALL_FILES)) {
 | 
					 | 
				
			||||||
		size_t count = desktop.openDocuments.Count();
 | 
							size_t count = desktop.openDocuments.Count();
 | 
				
			||||||
		EsBufferWrite(pipe, &count, sizeof(size_t));
 | 
							EsBufferWrite(pipe, &count, sizeof(size_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2913,46 +2981,44 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
 | 
				
			||||||
			EsBufferWrite(pipe, &document->pathBytes, sizeof(size_t));
 | 
								EsBufferWrite(pipe, &document->pathBytes, sizeof(size_t));
 | 
				
			||||||
			EsBufferWrite(pipe, document->path, document->pathBytes);
 | 
								EsBufferWrite(pipe, document->path, document->pathBytes);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if (buffer[0] == DESKTOP_MSG_RUN_TEMPORARY_APPLICATION) {
 | 
						} else if (buffer[0] == DESKTOP_MSG_RUN_TEMPORARY_APPLICATION) {
 | 
				
			||||||
		InstalledApplication *requestingApplication = ApplicationFindByPID(message->desktop.processID);
 | 
							InstalledApplication *requestingApplication = application;
 | 
				
			||||||
 | 
							if (~requestingApplication->permissions & APPLICATION_PERMISSION_RUN_TEMPORARY_APPLICATION) return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (requestingApplication && (requestingApplication->permissions & APPLICATION_PERMISSION_RUN_TEMPORARY_APPLICATION)) {
 | 
					 | 
				
			||||||
		for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) {
 | 
							for (uintptr_t i = 0; i < desktop.installedApplications.Length(); i++) {
 | 
				
			||||||
				if (EsCStringLength(desktop.installedApplications[i]->cExecutable) == message->desktop.bytes - 1
 | 
								if (EsCStringLength(desktop.installedApplications[i]->cExecutable) == bytes - 1
 | 
				
			||||||
						&& 0 == EsMemoryCompare(desktop.installedApplications[i]->cExecutable, buffer + 1, message->desktop.bytes - 1)) {
 | 
										&& 0 == EsMemoryCompare(desktop.installedApplications[i]->cExecutable, buffer + 1, bytes - 1)) {
 | 
				
			||||||
				ApplicationInstanceCreate(desktop.installedApplications[i]->id, nullptr, nullptr);
 | 
									ApplicationInstanceCreate(desktop.installedApplications[i]->id, nullptr, nullptr);
 | 
				
			||||||
					return;
 | 
									return true;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			InstalledApplication *application = (InstalledApplication *) EsHeapAllocate(sizeof(InstalledApplication), true);
 | 
							InstalledApplication *temporaryApplication = (InstalledApplication *) EsHeapAllocate(sizeof(InstalledApplication), true);
 | 
				
			||||||
			if (!application) return;
 | 
							if (!temporaryApplication) return true;
 | 
				
			||||||
			application->temporary = true;
 | 
							temporaryApplication->temporary = true;
 | 
				
			||||||
			application->hidden = true;
 | 
							temporaryApplication->hidden = true;
 | 
				
			||||||
			application->useSingleProcess = true;
 | 
							temporaryApplication->useSingleProcess = true;
 | 
				
			||||||
			application->cExecutable = (char *) EsHeapAllocate(message->desktop.bytes, false);
 | 
							temporaryApplication->cExecutable = (char *) EsHeapAllocate(bytes, false);
 | 
				
			||||||
			if (!application->cExecutable) { EsHeapFree(application); return; }
 | 
							if (!temporaryApplication->cExecutable) { EsHeapFree(temporaryApplication); return true; }
 | 
				
			||||||
			EsMemoryCopy(application->cExecutable, buffer + 1, message->desktop.bytes - 1);
 | 
							EsMemoryCopy(temporaryApplication->cExecutable, buffer + 1, bytes - 1);
 | 
				
			||||||
			application->cExecutable[message->desktop.bytes - 1] = 0;
 | 
							temporaryApplication->cExecutable[bytes - 1] = 0;
 | 
				
			||||||
		static int64_t nextTemporaryID = -1;
 | 
							static int64_t nextTemporaryID = -1;
 | 
				
			||||||
			application->id = nextTemporaryID--;
 | 
							temporaryApplication->id = nextTemporaryID--;
 | 
				
			||||||
			application->cName = (char *) EsHeapAllocate(32, false);
 | 
							temporaryApplication->cName = (char *) EsHeapAllocate(32, false);
 | 
				
			||||||
			if (!application->cName) { EsHeapFree(application->cExecutable); EsHeapFree(application); return; }
 | 
							if (!temporaryApplication->cName) { EsHeapFree(temporaryApplication->cExecutable); EsHeapFree(temporaryApplication); return true; }
 | 
				
			||||||
			for (int i = 1; i < 31; i++) application->cName[i] = (EsRandomU8() % 26) + 'a';
 | 
							for (int i = 1; i < 31; i++) temporaryApplication->cName[i] = (EsRandomU8() % 26) + 'a';
 | 
				
			||||||
			application->cName[0] = '_', application->cName[31] = 0;
 | 
							temporaryApplication->cName[0] = '_', temporaryApplication->cName[31] = 0;
 | 
				
			||||||
		EsHandle handle;
 | 
							EsHandle handle;
 | 
				
			||||||
			EsError error = TemporaryFileCreate(&handle, &application->settingsPath, &application->settingsPathBytes, ES_NODE_DIRECTORY);
 | 
							EsError error = TemporaryFileCreate(&handle, &temporaryApplication->settingsPath, &temporaryApplication->settingsPathBytes, ES_NODE_DIRECTORY);
 | 
				
			||||||
		if (error == ES_SUCCESS) EsHandleClose(handle);
 | 
							if (error == ES_SUCCESS) EsHandleClose(handle);
 | 
				
			||||||
			desktop.installedApplications.Add(application);
 | 
							desktop.installedApplications.Add(temporaryApplication);
 | 
				
			||||||
			ApplicationInstanceCreate(application->id, nullptr, nullptr);
 | 
							ApplicationInstanceCreate(temporaryApplication->id, nullptr, nullptr);
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else if ((buffer[0] == DESKTOP_MSG_SET_TITLE || buffer[0] == DESKTOP_MSG_SET_ICON) && instance) {
 | 
						} else if ((buffer[0] == DESKTOP_MSG_SET_TITLE || buffer[0] == DESKTOP_MSG_SET_ICON) && instance) {
 | 
				
			||||||
		if (buffer[0] == DESKTOP_MSG_SET_TITLE) {
 | 
							if (buffer[0] == DESKTOP_MSG_SET_TITLE) {
 | 
				
			||||||
			instance->titleBytes = EsStringFormat(instance->title, sizeof(instance->title), "%s", 
 | 
								instance->titleBytes = EsStringFormat(instance->title, sizeof(instance->title), "%s", 
 | 
				
			||||||
					message->desktop.bytes - 1, buffer + 1);
 | 
										bytes - 1, buffer + 1);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			if (message->desktop.bytes == 5) {
 | 
								if (bytes == 5) {
 | 
				
			||||||
				EsMemoryCopy(&instance->iconID, buffer + 1, sizeof(uint32_t));
 | 
									EsMemoryCopy(&instance->iconID, buffer + 1, sizeof(uint32_t));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -2968,11 +3034,11 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
 | 
				
			||||||
				instance->tab->container->taskBarButton->Repaint(true);
 | 
									instance->tab->container->taskBarButton->Repaint(true);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (buffer[0] == DESKTOP_MSG_SET_MODIFIED && message->desktop.bytes == 2 && instance) {
 | 
						} else if (buffer[0] == DESKTOP_MSG_SET_MODIFIED && bytes == 2 && instance) {
 | 
				
			||||||
		if (instance->tab) {
 | 
							if (instance->tab) {
 | 
				
			||||||
			EsButtonSetCheck(instance->tab->closeButton, buffer[1] ? ES_CHECK_CHECKED : ES_CHECK_UNCHECKED, false);
 | 
								EsButtonSetCheck(instance->tab->closeButton, buffer[1] ? ES_CHECK_CHECKED : ES_CHECK_UNCHECKED, false);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (buffer[0] == DESKTOP_MSG_SET_PROGRESS && message->desktop.bytes == 1 + sizeof(double) && instance->isUserTask && instance) {
 | 
						} else if (buffer[0] == DESKTOP_MSG_SET_PROGRESS && bytes == 1 + sizeof(double) && instance->isUserTask && instance) {
 | 
				
			||||||
		double progress;
 | 
							double progress;
 | 
				
			||||||
		EsMemoryCopy(&progress, buffer + 1, sizeof(double));
 | 
							EsMemoryCopy(&progress, buffer + 1, sizeof(double));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2982,10 +3048,10 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
 | 
				
			||||||
			EsElementRepaint(desktop.tasksButton);
 | 
								EsElementRepaint(desktop.tasksButton);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (buffer[0] == DESKTOP_MSG_REQUEST_SAVE && instance) {
 | 
						} else if (buffer[0] == DESKTOP_MSG_REQUEST_SAVE && instance) {
 | 
				
			||||||
		ApplicationInstanceRequestSave(instance, (const char *) buffer + 1, message->desktop.bytes - 1, false);
 | 
							ApplicationInstanceRequestSave(instance, (const char *) buffer + 1, bytes - 1, false);
 | 
				
			||||||
	} else if (buffer[0] == DESKTOP_MSG_RENAME && instance) {
 | 
						} else if (buffer[0] == DESKTOP_MSG_RENAME && instance) {
 | 
				
			||||||
		const char *newName = (const char *) buffer + 1;
 | 
							const char *newName = (const char *) buffer + 1;
 | 
				
			||||||
		size_t newNameBytes = message->desktop.bytes - 1;
 | 
							size_t newNameBytes = bytes - 1;
 | 
				
			||||||
		OpenDocument *document = desktop.openDocuments.Get(&instance->documentID);
 | 
							OpenDocument *document = desktop.openDocuments.Get(&instance->documentID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!instance->documentID) {
 | 
							if (!instance->documentID) {
 | 
				
			||||||
| 
						 | 
					@ -3033,7 +3099,10 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		EsPrint("DesktopSyscall - Received unhandled message %d.\n", buffer[0]);
 | 
							EsPrint("DesktopSyscall - Received unhandled message %d.\n", buffer[0]);
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void EmbeddedWindowDestroyed(EsObjectID id) {
 | 
					void EmbeddedWindowDestroyed(EsObjectID id) {
 | 
				
			||||||
| 
						 | 
					@ -3063,25 +3132,9 @@ void DesktopSendMessage(EsMessage *message) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (message->type == ES_MSG_EMBEDDED_WINDOW_DESTROYED) {
 | 
						if (message->type == ES_MSG_EMBEDDED_WINDOW_DESTROYED) {
 | 
				
			||||||
		EmbeddedWindowDestroyed(message->desktop.windowID);
 | 
							EmbeddedWindowDestroyed(message->embeddedWindowDestroyedID);
 | 
				
			||||||
	} else if (message->type == ES_MSG_DESKTOP) {
 | 
					 | 
				
			||||||
		uint8_t *buffer = (uint8_t *) EsHeapAllocate(message->desktop.bytes, false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (buffer) {
 | 
					 | 
				
			||||||
			EsConstantBufferRead(message->desktop.buffer, buffer);
 | 
					 | 
				
			||||||
			EsBuffer pipe = { .canGrow = true };
 | 
					 | 
				
			||||||
			DesktopSyscall(message, buffer, &pipe);
 | 
					 | 
				
			||||||
			if (message->desktop.pipe) EsPipeWrite(message->desktop.pipe, pipe.out, pipe.position);
 | 
					 | 
				
			||||||
			EsHeapFree(pipe.out);
 | 
					 | 
				
			||||||
			EsHeapFree(buffer);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		EsHandleClose(message->desktop.buffer);
 | 
					 | 
				
			||||||
		if (message->desktop.pipe) EsHandleClose(message->desktop.pipe);
 | 
					 | 
				
			||||||
	} else if (message->type == ES_MSG_APPLICATION_CRASH) {
 | 
						} else if (message->type == ES_MSG_APPLICATION_CRASH) {
 | 
				
			||||||
		ApplicationInstanceCrashed(message);
 | 
							ApplicationInstanceCrashed(message);
 | 
				
			||||||
	} else if (message->type == ES_MSG_PROCESS_TERMINATED) {
 | 
					 | 
				
			||||||
		ApplicationProcessTerminated(message->crash.pid);
 | 
					 | 
				
			||||||
	} else if (message->type == ES_MSG_REGISTER_FILE_SYSTEM) {
 | 
						} else if (message->type == ES_MSG_REGISTER_FILE_SYSTEM) {
 | 
				
			||||||
		EsHandle rootDirectory = message->registerFileSystem.rootDirectory;
 | 
							EsHandle rootDirectory = message->registerFileSystem.rootDirectory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -856,8 +856,6 @@ private enum EsSyscallType {
 | 
				
			||||||
	ES_SYSCALL_WINDOW_SET_CURSOR
 | 
						ES_SYSCALL_WINDOW_SET_CURSOR
 | 
				
			||||||
	ES_SYSCALL_WINDOW_SET_PROPERTY
 | 
						ES_SYSCALL_WINDOW_SET_PROPERTY
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ES_SYSCALL_MESSAGE_DESKTOP
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// IO.
 | 
						// IO.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ES_SYSCALL_NODE_OPEN
 | 
						ES_SYSCALL_NODE_OPEN
 | 
				
			||||||
| 
						 | 
					@ -1782,12 +1780,6 @@ struct EsMessageProcessCrash {
 | 
				
			||||||
	uintptr_t pid;
 | 
						uintptr_t pid;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct EsMessageDesktop {
 | 
					 | 
				
			||||||
	EsObjectID windowID, processID;
 | 
					 | 
				
			||||||
	EsHandle buffer, pipe;
 | 
					 | 
				
			||||||
	size_t bytes;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct EsMessageEyedrop {
 | 
					struct EsMessageEyedrop {
 | 
				
			||||||
	uint32_t color;
 | 
						uint32_t color;
 | 
				
			||||||
	bool cancelled;
 | 
						bool cancelled;
 | 
				
			||||||
| 
						 | 
					@ -1892,13 +1884,13 @@ struct EsMessage {
 | 
				
			||||||
		// Internal messages:
 | 
							// Internal messages:
 | 
				
			||||||
		void *_argument;
 | 
							void *_argument;
 | 
				
			||||||
		EsMessageProcessCrash crash;
 | 
							EsMessageProcessCrash crash;
 | 
				
			||||||
		EsMessageDesktop desktop;
 | 
					 | 
				
			||||||
		EsMessageEyedrop eyedrop;
 | 
							EsMessageEyedrop eyedrop;
 | 
				
			||||||
		EsMessageCreateInstance createInstance;
 | 
							EsMessageCreateInstance createInstance;
 | 
				
			||||||
		EsMessageTabOperation tabOperation;
 | 
							EsMessageTabOperation tabOperation;
 | 
				
			||||||
		EsMessageRegisterFileSystem registerFileSystem;
 | 
							EsMessageRegisterFileSystem registerFileSystem;
 | 
				
			||||||
		EsMessageUnregisterFileSystem unregisterFileSystem;
 | 
							EsMessageUnregisterFileSystem unregisterFileSystem;
 | 
				
			||||||
		EsMessageDevice device;
 | 
							EsMessageDevice device;
 | 
				
			||||||
 | 
							EsObjectID embeddedWindowDestroyedID;
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2247,7 +2239,7 @@ function bool EsMouseIsMiddleHeld();
 | 
				
			||||||
// Pipes.
 | 
					// Pipes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function void EsPipeCreate(EsHandle *readEnd, EsHandle *writeEnd);
 | 
					function void EsPipeCreate(EsHandle *readEnd, EsHandle *writeEnd);
 | 
				
			||||||
function size_t EsPipeRead(EsHandle pipe, void *buffer, size_t bytes);
 | 
					function size_t EsPipeRead(EsHandle pipe, void *buffer, size_t bytes); // If buffer is null, then the data is discarded.
 | 
				
			||||||
function size_t EsPipeWrite(EsHandle pipe, const void *buffer, size_t bytes);
 | 
					function size_t EsPipeWrite(EsHandle pipe, const void *buffer, size_t bytes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Synchronisation and timing.
 | 
					// Synchronisation and timing.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -352,6 +352,7 @@ struct SystemStartupDataHeader {
 | 
				
			||||||
	size_t initialMountPointCount;
 | 
						size_t initialMountPointCount;
 | 
				
			||||||
	size_t initialDeviceCount;
 | 
						size_t initialDeviceCount;
 | 
				
			||||||
	uintptr_t themeCursorData;
 | 
						uintptr_t themeCursorData;
 | 
				
			||||||
 | 
						uintptr_t desktopRequestPipe, desktopResponsePipe;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef KERNEL
 | 
					#ifdef KERNEL
 | 
				
			||||||
| 
						 | 
					@ -397,9 +398,9 @@ extern "C" void *EsBufferWrite(EsBuffer *buffer, const void *source, size_t writ
 | 
				
			||||||
#define ES_THEME_CURSORS_WIDTH (264)
 | 
					#define ES_THEME_CURSORS_WIDTH (264)
 | 
				
			||||||
#define ES_THEME_CURSORS_HEIGHT (128)
 | 
					#define ES_THEME_CURSORS_HEIGHT (128)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Desktop messages: */
 | 
					/* Messages sent from Kernel to Desktop: */
 | 
				
			||||||
#define ES_MSG_EMBEDDED_WINDOW_DESTROYED 	((EsMessageType) (ES_MSG_SYSTEM_START + 0x001))
 | 
					#define ES_MSG_EMBEDDED_WINDOW_DESTROYED 	((EsMessageType) (ES_MSG_SYSTEM_START + 0x001))
 | 
				
			||||||
#define ES_MSG_DESKTOP	                        ((EsMessageType) (ES_MSG_SYSTEM_START + 0x005))
 | 
					#define ES_MSG_APPLICATION_CRASH		((EsMessageType) (ES_MSG_SYSTEM_START + 0x002))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Messages sent from Desktop to application instances: */
 | 
					/* Messages sent from Desktop to application instances: */
 | 
				
			||||||
#define ES_MSG_TAB_INSPECT_UI			((EsMessageType) (ES_MSG_SYSTEM_START + 0x101))
 | 
					#define ES_MSG_TAB_INSPECT_UI			((EsMessageType) (ES_MSG_SYSTEM_START + 0x101))
 | 
				
			||||||
| 
						 | 
					@ -409,16 +410,12 @@ extern "C" void *EsBufferWrite(EsBuffer *buffer, const void *source, size_t writ
 | 
				
			||||||
#define ES_MSG_INSTANCE_DOCUMENT_UPDATED	((EsMessageType) (ES_MSG_SYSTEM_START + 0x105))
 | 
					#define ES_MSG_INSTANCE_DOCUMENT_UPDATED	((EsMessageType) (ES_MSG_SYSTEM_START + 0x105))
 | 
				
			||||||
#define ES_MSG_INSTANCE_RENAME_RESPONSE		((EsMessageType) (ES_MSG_SYSTEM_START + 0x107))
 | 
					#define ES_MSG_INSTANCE_RENAME_RESPONSE		((EsMessageType) (ES_MSG_SYSTEM_START + 0x107))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Debugger messages: */
 | 
					 | 
				
			||||||
#define ES_MSG_APPLICATION_CRASH		((EsMessageType) (ES_MSG_SYSTEM_START + 0x201))
 | 
					 | 
				
			||||||
#define ES_MSG_PROCESS_TERMINATED		((EsMessageType) (ES_MSG_SYSTEM_START + 0x202))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Misc messages: */
 | 
					/* Misc messages: */
 | 
				
			||||||
#define ES_MSG_EYEDROP_REPORT			((EsMessageType) (ES_MSG_SYSTEM_START + 0x301))
 | 
					#define ES_MSG_EYEDROP_REPORT			((EsMessageType) (ES_MSG_SYSTEM_START + 0x201))
 | 
				
			||||||
#define ES_MSG_TIMER				((EsMessageType) (ES_MSG_SYSTEM_START + 0x302))
 | 
					#define ES_MSG_TIMER				((EsMessageType) (ES_MSG_SYSTEM_START + 0x202))
 | 
				
			||||||
#define ES_MSG_PING				((EsMessageType) (ES_MSG_SYSTEM_START + 0x303)) /* Sent by Desktop to check processes are processing messages. */
 | 
					#define ES_MSG_PING				((EsMessageType) (ES_MSG_SYSTEM_START + 0x203)) /* Sent by Desktop to check processes are processing messages. */
 | 
				
			||||||
#define ES_MSG_WAKEUP				((EsMessageType) (ES_MSG_SYSTEM_START + 0x304)) /* Sent to wakeup the message thread, so that it can process locally posted messages. */
 | 
					#define ES_MSG_WAKEUP				((EsMessageType) (ES_MSG_SYSTEM_START + 0x204)) /* Sent to wakeup the message thread, so that it can process locally posted messages. */
 | 
				
			||||||
#define ES_MSG_INSTANCE_OPEN_DELAYED		((EsMessageType) (ES_MSG_SYSTEM_START + 0x305))
 | 
					#define ES_MSG_INSTANCE_OPEN_DELAYED		((EsMessageType) (ES_MSG_SYSTEM_START + 0x205))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -749,36 +749,36 @@ size_t EsGameControllerStatePoll(EsGameControllerState *buffer) {
 | 
				
			||||||
	return EsSyscall(ES_SYSCALL_GAME_CONTROLLER_STATE_POLL, (uintptr_t) buffer, 0, 0, 0);
 | 
						return EsSyscall(ES_SYSCALL_GAME_CONTROLLER_STATE_POLL, (uintptr_t) buffer, 0, 0, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe);
 | 
					bool DesktopSyscall(EsObjectID windowID, struct ApplicationProcess *process, uint8_t *buffer, size_t bytes, EsBuffer *pipe);
 | 
				
			||||||
 | 
					struct ApplicationProcess *DesktopGetApplicationProcessForDesktop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void MessageDesktop(void *message, size_t messageBytes, EsHandle embeddedWindow = ES_INVALID_HANDLE, EsBuffer *responseBuffer = nullptr) {
 | 
					void MessageDesktop(void *message, size_t messageBytes, EsHandle embeddedWindow = ES_INVALID_HANDLE, EsBuffer *responseBuffer = nullptr) {
 | 
				
			||||||
 | 
						static EsMutex messageDesktopMutex = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EsObjectID embeddedWindowID = embeddedWindow ? EsSyscall(ES_SYSCALL_WINDOW_GET_ID, embeddedWindow, 0, 0, 0) : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EsMutexAcquire(&messageDesktopMutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (api.startupInformation->isDesktop) {
 | 
						if (api.startupInformation->isDesktop) {
 | 
				
			||||||
		EsMessage m = {};
 | 
							struct ApplicationProcess *process = DesktopGetApplicationProcessForDesktop();
 | 
				
			||||||
		m.type = ES_MSG_DESKTOP;
 | 
							bool noFatalErrors = DesktopSyscall(embeddedWindowID, process, (uint8_t *) message, messageBytes, responseBuffer);
 | 
				
			||||||
		m.desktop.windowID = embeddedWindow ? EsSyscall(ES_SYSCALL_WINDOW_GET_ID, embeddedWindow, 0, 0, 0) : 0;
 | 
							EsAssert(noFatalErrors);
 | 
				
			||||||
		m.desktop.processID = EsProcessGetID(ES_CURRENT_PROCESS);
 | 
					 | 
				
			||||||
		m.desktop.bytes = messageBytes;
 | 
					 | 
				
			||||||
		DesktopSyscall(&m, (uint8_t *) message, responseBuffer);
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		EsHandle pipeRead = ES_INVALID_HANDLE, pipeWrite = ES_INVALID_HANDLE;
 | 
							if (messageBytes <= DESKTOP_MESSAGE_SIZE_LIMIT) {
 | 
				
			||||||
 | 
								uint32_t length = messageBytes;
 | 
				
			||||||
 | 
								EsPipeWrite(api.desktopRequestPipe, &length, sizeof(length));
 | 
				
			||||||
 | 
								EsPipeWrite(api.desktopRequestPipe, &embeddedWindowID, sizeof(embeddedWindowID));
 | 
				
			||||||
 | 
								EsPipeWrite(api.desktopRequestPipe, message, messageBytes);
 | 
				
			||||||
 | 
								EsPipeRead(api.desktopResponsePipe, &length, sizeof(length));
 | 
				
			||||||
 | 
								EsAssert((length != 0) == (responseBuffer != 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (responseBuffer) {
 | 
								while (length) {
 | 
				
			||||||
			EsPipeCreate(&pipeRead, &pipeWrite);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		EsSyscall(ES_SYSCALL_MESSAGE_DESKTOP, (uintptr_t) message, messageBytes, embeddedWindow, pipeWrite);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (responseBuffer) {
 | 
					 | 
				
			||||||
				char buffer[4096];
 | 
									char buffer[4096];
 | 
				
			||||||
			EsHandleClose(pipeWrite);
 | 
									size_t bytesRead = EsPipeRead(api.desktopResponsePipe, buffer, sizeof(buffer) > length ? length : sizeof(buffer));
 | 
				
			||||||
 | 
					 | 
				
			||||||
			while (true) {
 | 
					 | 
				
			||||||
				size_t bytesRead = EsPipeRead(pipeRead, buffer, sizeof(buffer));
 | 
					 | 
				
			||||||
				if (!bytesRead) break;
 | 
									if (!bytesRead) break;
 | 
				
			||||||
				EsBufferWrite(responseBuffer, buffer, bytesRead);
 | 
									EsBufferWrite(responseBuffer, buffer, bytesRead);
 | 
				
			||||||
 | 
									length -= bytesRead;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					 | 
				
			||||||
			EsHandleClose(pipeRead);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -786,6 +786,8 @@ void MessageDesktop(void *message, size_t messageBytes, EsHandle embeddedWindow
 | 
				
			||||||
		responseBuffer->bytes = responseBuffer->position;
 | 
							responseBuffer->bytes = responseBuffer->position;
 | 
				
			||||||
		responseBuffer->position = 0;
 | 
							responseBuffer->position = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						EsMutexRelease(&messageDesktopMutex);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ClipboardInformation {
 | 
					struct ClipboardInformation {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -607,14 +607,14 @@ size_t Pipe::Access(void *_buffer, size_t bytes, bool write, bool user) {
 | 
				
			||||||
			// EsPrint("\tunread: %d; wp: %d\n", unreadData, writePosition);
 | 
								// EsPrint("\tunread: %d; wp: %d\n", unreadData, writePosition);
 | 
				
			||||||
			// EsPrint("\t%d, %d, %d, %d, %d\n", spaceAvailable, spaceAvailableRight, toWrite, toWriteRight, toWriteLeft);
 | 
								// EsPrint("\t%d, %d, %d, %d, %d\n", spaceAvailable, spaceAvailableRight, toWrite, toWriteRight, toWriteLeft);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			EsMemoryCopy((uint8_t *) buffer + writePosition, _buffer, toWriteRight);
 | 
								if (_buffer) EsMemoryCopy((uint8_t *) buffer + writePosition, _buffer, toWriteRight);
 | 
				
			||||||
			EsMemoryCopy((uint8_t *) buffer, (uint8_t *) _buffer + toWriteRight, toWriteLeft);
 | 
								if (_buffer) EsMemoryCopy((uint8_t *) buffer, (uint8_t *) _buffer + toWriteRight, toWriteLeft);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			writePosition += toWrite;
 | 
								writePosition += toWrite;
 | 
				
			||||||
			writePosition %= PIPE_BUFFER_SIZE;
 | 
								writePosition %= PIPE_BUFFER_SIZE;
 | 
				
			||||||
			unreadData += toWrite;
 | 
								unreadData += toWrite;
 | 
				
			||||||
			bytes -= toWrite;
 | 
								bytes -= toWrite;
 | 
				
			||||||
			_buffer = (uint8_t *) _buffer + toWrite;
 | 
								if (_buffer) _buffer = (uint8_t *) _buffer + toWrite;
 | 
				
			||||||
			amount += toWrite;
 | 
								amount += toWrite;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			KEventSet(&canRead, true);
 | 
								KEventSet(&canRead, true);
 | 
				
			||||||
| 
						 | 
					@ -640,14 +640,14 @@ size_t Pipe::Access(void *_buffer, size_t bytes, bool write, bool user) {
 | 
				
			||||||
			// EsPrint("\tunread: %d; rp: %d\n", unreadData, readPosition);
 | 
								// EsPrint("\tunread: %d; rp: %d\n", unreadData, readPosition);
 | 
				
			||||||
			// EsPrint("\t%d, %d, %d, %d, %d\n", dataAvailable, spaceAvailableRight, toRead, toReadRight, toReadLeft);
 | 
								// EsPrint("\t%d, %d, %d, %d, %d\n", dataAvailable, spaceAvailableRight, toRead, toReadRight, toReadLeft);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			EsMemoryCopy(_buffer, (uint8_t *) buffer + readPosition, toReadRight);
 | 
								if (_buffer) EsMemoryCopy(_buffer, (uint8_t *) buffer + readPosition, toReadRight);
 | 
				
			||||||
			EsMemoryCopy((uint8_t *) _buffer + toReadRight, (uint8_t *) buffer, toReadLeft);
 | 
								if (_buffer) EsMemoryCopy((uint8_t *) _buffer + toReadRight, (uint8_t *) buffer, toReadLeft);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			readPosition += toRead;
 | 
								readPosition += toRead;
 | 
				
			||||||
			readPosition %= PIPE_BUFFER_SIZE;
 | 
								readPosition %= PIPE_BUFFER_SIZE;
 | 
				
			||||||
			unreadData -= toRead;
 | 
								unreadData -= toRead;
 | 
				
			||||||
			bytes -= toRead;
 | 
								bytes -= toRead;
 | 
				
			||||||
			_buffer = (uint8_t *) _buffer + toRead;
 | 
								if (_buffer) _buffer = (uint8_t *) _buffer + toRead;
 | 
				
			||||||
			amount += toRead;
 | 
								amount += toRead;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			KEventSet(&canWrite, true);
 | 
								KEventSet(&canWrite, true);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -549,15 +549,6 @@ void ProcessKill(Process *process) {
 | 
				
			||||||
	// Don't actually deallocate it yet though; that is done on an async task queued by ProcessRemove.
 | 
						// Don't actually deallocate it yet though; that is done on an async task queued by ProcessRemove.
 | 
				
			||||||
	// This must be destroyed after the handle table!
 | 
						// This must be destroyed after the handle table!
 | 
				
			||||||
	MMSpaceDestroy(process->vmm); 
 | 
						MMSpaceDestroy(process->vmm); 
 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Tell Desktop the process has terminated.
 | 
					 | 
				
			||||||
	if (!scheduler.shutdown) {
 | 
					 | 
				
			||||||
		_EsMessageWithObject m;
 | 
					 | 
				
			||||||
		EsMemoryZero(&m, sizeof(m));
 | 
					 | 
				
			||||||
		m.message.type = ES_MSG_PROCESS_TERMINATED;
 | 
					 | 
				
			||||||
		m.message.crash.pid = process->id;
 | 
					 | 
				
			||||||
		DesktopSendMessage(&m);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ThreadKill(KAsyncTask *task) {
 | 
					void ThreadKill(KAsyncTask *task) {
 | 
				
			||||||
| 
						 | 
					@ -1089,6 +1080,8 @@ void ProcessPause(Process *process, bool resume) {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ProcessCrash(Process *process, EsCrashReason *crashReason) {
 | 
					void ProcessCrash(Process *process, EsCrashReason *crashReason) {
 | 
				
			||||||
 | 
						EsAssert(process == GetCurrentThread()->process); // TODO Test this function when crashing other processes!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (process == kernelProcess) {
 | 
						if (process == kernelProcess) {
 | 
				
			||||||
		KernelPanic("ProcessCrash - Kernel process has crashed (%d).\n", crashReason->errorCode);
 | 
							KernelPanic("ProcessCrash - Kernel process has crashed (%d).\n", crashReason->errorCode);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1097,18 +1090,13 @@ void ProcessCrash(Process *process, EsCrashReason *crashReason) {
 | 
				
			||||||
		KernelPanic("ProcessCrash - A critical process has crashed (%d).\n", crashReason->errorCode);
 | 
							KernelPanic("ProcessCrash - A critical process has crashed (%d).\n", crashReason->errorCode);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (GetCurrentThread()->process != process) {
 | 
						bool pauseProcess = false;
 | 
				
			||||||
		KernelPanic("ProcessCrash - Attempt to crash process from different process.\n");
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	KMutexAcquire(&process->crashMutex);
 | 
						KMutexAcquire(&process->crashMutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (process->crashed) {
 | 
						if (!process->crashed) {
 | 
				
			||||||
		KMutexRelease(&process->crashMutex);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		process->crashed = true;
 | 
							process->crashed = true;
 | 
				
			||||||
 | 
							pauseProcess = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		KernelLog(LOG_ERROR, "Scheduler", "process crashed", "Process %x has crashed! (%d)\n", process, crashReason->errorCode);
 | 
							KernelLog(LOG_ERROR, "Scheduler", "process crashed", "Process %x has crashed! (%d)\n", process, crashReason->errorCode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1122,11 +1110,14 @@ void ProcessCrash(Process *process, EsCrashReason *crashReason) {
 | 
				
			||||||
			EsMemoryCopy(&m.message.crash.reason, crashReason, sizeof(EsCrashReason));
 | 
								EsMemoryCopy(&m.message.crash.reason, crashReason, sizeof(EsCrashReason));
 | 
				
			||||||
			DesktopSendMessage(&m);
 | 
								DesktopSendMessage(&m);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	KMutexRelease(&process->crashMutex);
 | 
						KMutexRelease(&process->crashMutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pauseProcess) {
 | 
				
			||||||
		// TODO Shouldn't this be done before sending the desktop message?
 | 
							// TODO Shouldn't this be done before sending the desktop message?
 | 
				
			||||||
	ProcessPause(GetCurrentThread()->process, false);
 | 
							ProcessPause(process, false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Thread *Scheduler::PickThread(CPULocalStorage *local) {
 | 
					Thread *Scheduler::PickThread(CPULocalStorage *local) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1367,45 +1367,6 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_SCREEN_WORK_AREA_GET) {
 | 
				
			||||||
	SYSCALL_RETURN(ES_SUCCESS, false);
 | 
						SYSCALL_RETURN(ES_SUCCESS, false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SYSCALL_IMPLEMENT(ES_SYSCALL_MESSAGE_DESKTOP) {
 | 
					 | 
				
			||||||
	char *buffer;
 | 
					 | 
				
			||||||
	if (argument1 > DESKTOP_MESSAGE_SIZE_LIMIT) SYSCALL_RETURN(ES_ERROR_INSUFFICIENT_RESOURCES, false);
 | 
					 | 
				
			||||||
	SYSCALL_READ_HEAP(buffer, argument0, argument1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	SYSCALL_HANDLE_2(argument2, (KernelObjectType) (KERNEL_OBJECT_EMBEDDED_WINDOW | KERNEL_OBJECT_NONE), _window);
 | 
					 | 
				
			||||||
	SYSCALL_HANDLE_2(argument3, (KernelObjectType) (KERNEL_OBJECT_PIPE | KERNEL_OBJECT_NONE), _pipe);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	EmbeddedWindow *window = (EmbeddedWindow *) _window.object;
 | 
					 | 
				
			||||||
	Pipe *pipe = (Pipe *) _pipe.object;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (pipe && (~_pipe.flags & PIPE_WRITER)) {
 | 
					 | 
				
			||||||
		SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_FILE_ACCESS, true);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!scheduler.shutdown) {
 | 
					 | 
				
			||||||
		if (pipe) {
 | 
					 | 
				
			||||||
			OpenHandleToObject(pipe, KERNEL_OBJECT_PIPE, PIPE_WRITER);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		void *constantBuffer = ConstantBufferCreate(buffer, argument1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		_EsMessageWithObject m = {};
 | 
					 | 
				
			||||||
		m.message.type = ES_MSG_DESKTOP;
 | 
					 | 
				
			||||||
		m.message.desktop.buffer = constantBuffer ? DesktopOpenHandle(constantBuffer, ES_FLAGS_DEFAULT, KERNEL_OBJECT_CONSTANT_BUFFER) : ES_INVALID_HANDLE;
 | 
					 | 
				
			||||||
		m.message.desktop.bytes = argument1;
 | 
					 | 
				
			||||||
		m.message.desktop.windowID = window ? window->id : 0;
 | 
					 | 
				
			||||||
		m.message.desktop.processID = currentProcess->id;
 | 
					 | 
				
			||||||
		m.message.desktop.pipe = pipe ? DesktopOpenHandle(pipe, PIPE_WRITER, KERNEL_OBJECT_PIPE) : ES_INVALID_HANDLE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!m.message.desktop.buffer || !DesktopSendMessage(&m)) {
 | 
					 | 
				
			||||||
			DesktopCloseHandle(m.message.desktop.buffer); 
 | 
					 | 
				
			||||||
			DesktopCloseHandle(m.message.desktop.pipe); 
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	SYSCALL_RETURN(ES_SUCCESS, false);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef ENABLE_POSIX_SUBSYSTEM
 | 
					#ifdef ENABLE_POSIX_SUBSYSTEM
 | 
				
			||||||
SYSCALL_IMPLEMENT(ES_SYSCALL_POSIX) {
 | 
					SYSCALL_IMPLEMENT(ES_SYSCALL_POSIX) {
 | 
				
			||||||
	SYSCALL_PERMISSION(ES_PERMISSION_POSIX_SUBSYSTEM);
 | 
						SYSCALL_PERMISSION(ES_PERMISSION_POSIX_SUBSYSTEM);
 | 
				
			||||||
| 
						 | 
					@ -1457,8 +1418,14 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_PIPE_READ) {
 | 
				
			||||||
	SYSCALL_HANDLE_2(argument0, KERNEL_OBJECT_PIPE, _pipe);
 | 
						SYSCALL_HANDLE_2(argument0, KERNEL_OBJECT_PIPE, _pipe);
 | 
				
			||||||
	Pipe *pipe = (Pipe *) _pipe.object;
 | 
						Pipe *pipe = (Pipe *) _pipe.object;
 | 
				
			||||||
	if ((~_pipe.flags & PIPE_READER)) SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_FILE_ACCESS, true);
 | 
						if ((~_pipe.flags & PIPE_READER)) SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_FILE_ACCESS, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (argument1) {
 | 
				
			||||||
		SYSCALL_BUFFER(argument1, argument2, 2, false);
 | 
							SYSCALL_BUFFER(argument1, argument2, 2, false);
 | 
				
			||||||
		SYSCALL_RETURN(pipe->Access((void *) argument1, argument2, false, true), false);
 | 
							SYSCALL_RETURN(pipe->Access((void *) argument1, argument2, false, true), false);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							// Discard data.
 | 
				
			||||||
 | 
							SYSCALL_RETURN(pipe->Access(nullptr, argument2, false, true), false);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SYSCALL_IMPLEMENT(ES_SYSCALL_PIPE_WRITE) {
 | 
					SYSCALL_IMPLEMENT(ES_SYSCALL_PIPE_WRITE) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -936,7 +936,7 @@ void EmbeddedWindow::Close() {
 | 
				
			||||||
	SetEmbedOwner(nullptr);
 | 
						SetEmbedOwner(nullptr);
 | 
				
			||||||
	m.object = nullptr;
 | 
						m.object = nullptr;
 | 
				
			||||||
	m.message.type = ES_MSG_EMBEDDED_WINDOW_DESTROYED;
 | 
						m.message.type = ES_MSG_EMBEDDED_WINDOW_DESTROYED;
 | 
				
			||||||
	m.message.desktop.windowID = id;
 | 
						m.message.embeddedWindowDestroyedID = id;
 | 
				
			||||||
	DesktopSendMessage(&m);
 | 
						DesktopSendMessage(&m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (container && container->embed == this) {
 | 
						if (container && container->embed == this) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue