mirror of https://gitlab.com/nakst/essence
fix race on desktopProcess in shut down
This commit is contained in:
parent
2436959c84
commit
c2dc5adbe7
|
@ -1483,7 +1483,7 @@ extern "C" void _start(EsProcessStartupInformation *_startupInformation) {
|
|||
|
||||
while (!api.foundBootFileSystem) {
|
||||
EsMessage *message = EsMessageReceive();
|
||||
DesktopMessage(message);
|
||||
DesktopSendMessage(message);
|
||||
}
|
||||
|
||||
size_t fileSize;
|
||||
|
|
|
@ -238,6 +238,7 @@ void WallpaperLoad(EsGeneric);
|
|||
WindowTab *WindowTabCreate(ContainerWindow *container);
|
||||
ContainerWindow *ContainerWindowCreate();
|
||||
void ContainerWindowShow(ContainerWindow *, int32_t width, int32_t height);
|
||||
void ShutdownModalCreate();
|
||||
|
||||
#include "settings.cpp"
|
||||
|
||||
|
@ -626,6 +627,8 @@ int ProcessGlobalKeyboardShortcuts(EsElement *, EsMessage *message) {
|
|||
ApplicationInstanceCreate(desktop.installedApplications[i]->id, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
} else if (scancode == ES_SCANCODE_ACPI_POWER) {
|
||||
ShutdownModalCreate();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
@ -2964,14 +2967,12 @@ void EmbeddedWindowDestroyed(EsObjectID id) {
|
|||
EsHeapFree(instance);
|
||||
}
|
||||
|
||||
void DesktopMessage(EsMessage *message) {
|
||||
void DesktopSendMessage(EsMessage *message) {
|
||||
if (!desktop.clockReady) {
|
||||
desktop.clockReady = EsEventCreate(false);
|
||||
}
|
||||
|
||||
if (message->type == ES_MSG_POWER_BUTTON_PRESSED) {
|
||||
ShutdownModalCreate();
|
||||
} else if (message->type == ES_MSG_EMBEDDED_WINDOW_DESTROYED) {
|
||||
if (message->type == ES_MSG_EMBEDDED_WINDOW_DESTROYED) {
|
||||
EmbeddedWindowDestroyed(message->desktop.windowID);
|
||||
} else if (message->type == ES_MSG_DESKTOP) {
|
||||
uint8_t *buffer = (uint8_t *) EsHeapAllocate(message->desktop.bytes, false);
|
||||
|
@ -3073,6 +3074,6 @@ void DesktopEntry() {
|
|||
|
||||
while (true) {
|
||||
EsMessage *message = EsMessageReceive();
|
||||
DesktopMessage(message);
|
||||
DesktopSendMessage(message);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -966,7 +966,6 @@ enum EsMessageType {
|
|||
ES_MSG_SLIDER_MOVED = 0x3006 // The slider has been moved.
|
||||
|
||||
// Desktop messages:
|
||||
ES_MSG_POWER_BUTTON_PRESSED = 0x4801
|
||||
ES_MSG_EMBEDDED_WINDOW_DESTROYED = 0x4802
|
||||
ES_MSG_SET_SCREEN_RESOLUTION = 0x4803
|
||||
ES_MSG_REGISTER_FILE_SYSTEM = 0x4804
|
||||
|
|
|
@ -425,9 +425,8 @@ ES_EXTERN_C ACPI_STATUS AcpiOsEnterSleep(UINT8 sleepState, UINT32 registerAValue
|
|||
|
||||
UINT32 ACPIPowerButtonPressed(void *) {
|
||||
KRegisterAsyncTask(&powerButtonAsyncTask, [] (KAsyncTask *) {
|
||||
_EsMessageWithObject m = { nullptr, ES_MSG_POWER_BUTTON_PRESSED };
|
||||
if (scheduler.shutdown) return;
|
||||
if (desktopProcess) desktopProcess->messageQueue.SendMessage(&m);
|
||||
KKeyPress(ES_SCANCODE_ACPI_POWER | K_SCANCODE_KEY_PRESSED);
|
||||
KKeyPress(ES_SCANCODE_ACPI_POWER | K_SCANCODE_KEY_RELEASED);
|
||||
});
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -79,6 +79,8 @@ void CCSpaceUncover(CCSpace *cache, EsFileOffset removeStart, EsFileOffset remov
|
|||
EsError CCSpaceAccess(CCSpace *cache, K_USER_BUFFER void *buffer, EsFileOffset offset, EsFileOffset count, uint32_t flags,
|
||||
MMSpace *mapSpace = nullptr, unsigned mapFlags = ES_FLAGS_DEFAULT);
|
||||
|
||||
MMActiveSectionManager activeSectionManager;
|
||||
|
||||
#else
|
||||
|
||||
CCCachedSection *CCFindCachedSectionContaining(CCSpace *cache, EsFileOffset sectionOffset) {
|
||||
|
|
|
@ -119,11 +119,11 @@ void DeviceRemovedRecurse(KDevice *device) {
|
|||
}
|
||||
|
||||
if (device->flags & K_DEVICE_VISIBLE_TO_USER) {
|
||||
EsMessage m;
|
||||
_EsMessageWithObject m;
|
||||
EsMemoryZero(&m, sizeof(m));
|
||||
m.type = ES_MSG_DEVICE_DISCONNECTED;
|
||||
m.device.id = device->objectID;
|
||||
desktopProcess->messageQueue.SendMessage(nullptr, &m);
|
||||
m.message.type = ES_MSG_DEVICE_DISCONNECTED;
|
||||
m.message.device.id = device->objectID;
|
||||
DesktopSendMessage(&m);
|
||||
}
|
||||
|
||||
if (device->removed) {
|
||||
|
@ -145,16 +145,16 @@ void KDeviceSendConnectedMessage(KDevice *device, EsDeviceType type) {
|
|||
|
||||
KDeviceOpenHandle(device);
|
||||
|
||||
EsMessage m;
|
||||
_EsMessageWithObject m;
|
||||
EsMemoryZero(&m, sizeof(m));
|
||||
m.type = ES_MSG_DEVICE_CONNECTED;
|
||||
m.device.id = device->objectID;
|
||||
m.device.type = type;
|
||||
m.device.handle = desktopProcess->handleTable.OpenHandle(device, 0, KERNEL_OBJECT_DEVICE);
|
||||
m.message.type = ES_MSG_DEVICE_CONNECTED;
|
||||
m.message.device.id = device->objectID;
|
||||
m.message.device.type = type;
|
||||
m.message.device.handle = DesktopOpenHandle(device, 0, KERNEL_OBJECT_DEVICE);
|
||||
|
||||
if (m.device.handle) {
|
||||
if (!desktopProcess->messageQueue.SendMessage(nullptr, &m)) {
|
||||
desktopProcess->handleTable.CloseHandle(m.device.handle); // This will check that the handle is still valid.
|
||||
if (m.message.device.handle) {
|
||||
if (!DesktopSendMessage(&m)) {
|
||||
DesktopCloseHandle(m.message.device.handle); // This will check that the handle is still valid.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1876,11 +1876,11 @@ void FSRegisterBootFileSystem(KFileSystem *fileSystem, EsUniqueIdentifier identi
|
|||
|
||||
void FSFileSystemDeviceRemoved(KDevice *device) {
|
||||
KFileSystem *fileSystem = (KFileSystem *) device;
|
||||
EsMessage m;
|
||||
EsMemoryZero(&m, sizeof(EsMessage));
|
||||
m.type = ES_MSG_UNREGISTER_FILE_SYSTEM;
|
||||
m.unregisterFileSystem.id = fileSystem->objectID;
|
||||
desktopProcess->messageQueue.SendMessage(nullptr, &m);
|
||||
_EsMessageWithObject m;
|
||||
EsMemoryZero(&m, sizeof(m));
|
||||
m.message.type = ES_MSG_UNREGISTER_FILE_SYSTEM;
|
||||
m.message.unregisterFileSystem.id = fileSystem->objectID;
|
||||
DesktopSendMessage(&m);
|
||||
}
|
||||
|
||||
void FSRegisterFileSystem(KFileSystem *fileSystem) {
|
||||
|
@ -1893,16 +1893,15 @@ void FSRegisterFileSystem(KFileSystem *fileSystem) {
|
|||
fileSystem->rootDirectory->directoryEntry->directoryChildren = fileSystem->rootDirectoryInitialChildren;
|
||||
FSNodeOpenHandle(fileSystem->rootDirectory, ES_FLAGS_DEFAULT, fileSystem->isBootFileSystem ? FS_NODE_OPEN_HANDLE_STANDARD : FS_NODE_OPEN_HANDLE_FIRST);
|
||||
|
||||
EsMessage m;
|
||||
EsMemoryZero(&m, sizeof(EsMessage));
|
||||
m.type = ES_MSG_REGISTER_FILE_SYSTEM;
|
||||
m.registerFileSystem.isBootFileSystem = fileSystem->isBootFileSystem;
|
||||
_EsMessageWithObject m;
|
||||
EsMemoryZero(&m, sizeof(m));
|
||||
m.message.type = ES_MSG_REGISTER_FILE_SYSTEM;
|
||||
m.message.registerFileSystem.isBootFileSystem = fileSystem->isBootFileSystem;
|
||||
m.message.registerFileSystem.rootDirectory = DesktopOpenHandle(fileSystem->rootDirectory, _ES_NODE_DIRECTORY_WRITE, KERNEL_OBJECT_NODE);
|
||||
|
||||
m.registerFileSystem.rootDirectory = desktopProcess->handleTable.OpenHandle(fileSystem->rootDirectory, _ES_NODE_DIRECTORY_WRITE, KERNEL_OBJECT_NODE);
|
||||
|
||||
if (m.registerFileSystem.rootDirectory) {
|
||||
if (!desktopProcess->messageQueue.SendMessage(nullptr, &m)) {
|
||||
desktopProcess->handleTable.CloseHandle(m.registerFileSystem.rootDirectory); // This will check that the handle is still valid.
|
||||
if (m.message.registerFileSystem.rootDirectory) {
|
||||
if (!DesktopSendMessage(&m)) {
|
||||
DesktopCloseHandle(m.message.registerFileSystem.rootDirectory); // This will check that the handle is still valid.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -113,10 +113,10 @@ void KRegisterGraphicsTarget(KGraphicsTarget *target) {
|
|||
#else
|
||||
windowManager.Initialise();
|
||||
|
||||
EsMessage m;
|
||||
EsMemoryZero(&m, sizeof(EsMessage));
|
||||
m.type = ES_MSG_SET_SCREEN_RESOLUTION;
|
||||
desktopProcess->messageQueue.SendMessage(nullptr, &m);
|
||||
_EsMessageWithObject m;
|
||||
EsMemoryZero(&m, sizeof(m));
|
||||
m.message.type = ES_MSG_SET_SCREEN_RESOLUTION;
|
||||
DesktopSendMessage(&m);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -302,7 +302,6 @@ void PMCopy(uintptr_t page, void *source, size_t pageCount);
|
|||
|
||||
MMSpace _kernelMMSpace, _coreMMSpace;
|
||||
PMM pmm;
|
||||
MMActiveSectionManager activeSectionManager;
|
||||
|
||||
MMRegion *mmCoreRegions = (MMRegion *) MM_CORE_REGIONS_START;
|
||||
size_t mmCoreRegionCount, mmCoreRegionArrayCommit;
|
||||
|
|
|
@ -574,10 +574,6 @@ EsHandle MakeConstantBuffer(K_USER_BUFFER const void *data, size_t bytes, Proces
|
|||
return object ? process->handleTable.OpenHandle(object, 0, KERNEL_OBJECT_CONSTANT_BUFFER) : ES_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
EsHandle MakeConstantBufferForDesktop(K_USER_BUFFER const void *data, size_t bytes) {
|
||||
return MakeConstantBuffer(data, bytes, desktopProcess);
|
||||
}
|
||||
|
||||
size_t Pipe::Access(void *_buffer, size_t bytes, bool write, bool user) {
|
||||
size_t amount = 0;
|
||||
Thread *currentThread = GetCurrentThread();
|
||||
|
@ -730,6 +726,12 @@ bool MessageQueue::SendMessage(_EsMessageWithObject *_message) {
|
|||
|
||||
KEventSet(¬Empty, true);
|
||||
|
||||
// TODO Temporary.
|
||||
static int largest = 0;
|
||||
int size = messages.Length();
|
||||
if (size > largest) largest = size;
|
||||
if (size > 40) KernelPanic("what\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -188,8 +188,6 @@ struct Process {
|
|||
};
|
||||
|
||||
struct Scheduler {
|
||||
// External API:
|
||||
|
||||
void Yield(InterruptContext *context);
|
||||
void CreateProcessorThreads(CPULocalStorage *local);
|
||||
void AddActiveThread(Thread *thread, bool start /* put it at the start of the active list */); // Add an active thread into the queue.
|
||||
|
@ -199,8 +197,6 @@ struct Scheduler {
|
|||
Thread *PickThread(CPULocalStorage *local); // Pick the next thread to execute.
|
||||
int8_t GetThreadEffectivePriority(Thread *thread);
|
||||
|
||||
// Variables:
|
||||
|
||||
KSpinlock dispatchSpinlock; // For accessing synchronisation objects, thread states, scheduling lists, etc. TODO Break this up!
|
||||
KSpinlock activeTimersSpinlock; // For accessing the activeTimers lists.
|
||||
LinkedList<Thread> activeThreads[THREAD_PRIORITY_COUNT];
|
||||
|
@ -244,9 +240,14 @@ void ThreadSetTemporaryAddressSpace(MMSpace *space);
|
|||
Thread *ThreadSpawn(const char *cName, uintptr_t startAddress, uintptr_t argument1 = 0,
|
||||
uint32_t flags = ES_FLAGS_DEFAULT, Process *process = nullptr, uintptr_t argument2 = 0);
|
||||
|
||||
bool DesktopSendMessage(_EsMessageWithObject *message);
|
||||
EsHandle DesktopOpenHandle(void *object, uint32_t flags, KernelObjectType type);
|
||||
void DesktopCloseHandle(EsHandle handle);
|
||||
|
||||
Process _kernelProcess;
|
||||
Process *kernelProcess = &_kernelProcess;
|
||||
Process *desktopProcess;
|
||||
KMutex desktopMutex;
|
||||
Scheduler scheduler;
|
||||
|
||||
#endif
|
||||
|
@ -544,7 +545,7 @@ void ProcessKill(Process *process) {
|
|||
EsMemoryZero(&m, sizeof(m));
|
||||
m.message.type = ES_MSG_PROCESS_TERMINATED;
|
||||
m.message.crash.pid = process->id;
|
||||
desktopProcess->messageQueue.SendMessage(&m);
|
||||
DesktopSendMessage(&m);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -728,7 +729,7 @@ void ProcessLoadExecutable() {
|
|||
|
||||
KLoadedExecutable application = {};
|
||||
|
||||
if (thisProcess != desktopProcess && loadError == ES_SUCCESS) {
|
||||
if (thisProcess->type != PROCESS_DESKTOP && loadError == ES_SUCCESS) {
|
||||
loadError = KLoadELF(thisProcess->executableNode, &application);
|
||||
}
|
||||
|
||||
|
@ -754,7 +755,7 @@ void ProcessLoadExecutable() {
|
|||
if (!startupInformation) {
|
||||
success = false;
|
||||
} else {
|
||||
startupInformation->isDesktop = thisProcess == desktopProcess;
|
||||
startupInformation->isDesktop = thisProcess->type == PROCESS_DESKTOP;
|
||||
startupInformation->isBundle = application.isBundle;
|
||||
startupInformation->applicationStartAddress = application.startAddress;
|
||||
startupInformation->tlsImageStart = application.tlsImageStart;
|
||||
|
@ -1086,7 +1087,7 @@ void ProcessCrash(Process *process, EsCrashReason *crashReason) {
|
|||
m.message.type = ES_MSG_APPLICATION_CRASH;
|
||||
m.message.crash.pid = process->id;
|
||||
EsMemoryCopy(&m.message.crash.reason, crashReason, sizeof(EsCrashReason));
|
||||
desktopProcess->messageQueue.SendMessage(&m);
|
||||
DesktopSendMessage(&m);
|
||||
}
|
||||
|
||||
KMutexRelease(&process->crashMutex);
|
||||
|
@ -1272,11 +1273,16 @@ void Scheduler::Yield(InterruptContext *context) {
|
|||
}
|
||||
|
||||
void ProcessTerminateAll() {
|
||||
KMutexAcquire(&desktopMutex);
|
||||
|
||||
scheduler.shutdown = true;
|
||||
|
||||
// Close our handle to the desktop process.
|
||||
CloseHandleToObject(desktopProcess->executableMainThread, KERNEL_OBJECT_THREAD);
|
||||
CloseHandleToObject(desktopProcess, KERNEL_OBJECT_PROCESS);
|
||||
desktopProcess = nullptr;
|
||||
|
||||
KMutexRelease(&desktopMutex);
|
||||
|
||||
KernelLog(LOG_INFO, "Scheduler", "terminating all processes", "ProcessTerminateAll - Terminating all processes....\n");
|
||||
|
||||
|
@ -1331,6 +1337,31 @@ void KYield() {
|
|||
ProcessorFakeTimerInterrupt();
|
||||
}
|
||||
|
||||
bool DesktopSendMessage(_EsMessageWithObject *message) {
|
||||
bool result = false;
|
||||
KMutexAcquire(&desktopMutex);
|
||||
if (desktopProcess) result = desktopProcess->messageQueue.SendMessage(message);
|
||||
KMutexRelease(&desktopMutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
EsHandle DesktopOpenHandle(void *object, uint32_t flags, KernelObjectType type) {
|
||||
EsHandle result = ES_INVALID_HANDLE;
|
||||
bool close = false;
|
||||
KMutexAcquire(&desktopMutex);
|
||||
if (desktopProcess) result = desktopProcess->handleTable.OpenHandle(object, flags, type);
|
||||
else close = true;
|
||||
KMutexRelease(&desktopMutex);
|
||||
if (close) CloseHandleToObject(object, type, flags);
|
||||
return result;
|
||||
}
|
||||
|
||||
void DesktopCloseHandle(EsHandle handle) {
|
||||
KMutexAcquire(&desktopMutex);
|
||||
if (desktopProcess) desktopProcess->handleTable.CloseHandle(handle); // This will check that the handle is still valid.
|
||||
KMutexRelease(&desktopMutex);
|
||||
}
|
||||
|
||||
uint64_t KCPUCurrentID() { return GetLocalStorage() ->processorID; }
|
||||
uint64_t KProcessCurrentID() { return GetCurrentThread()->process->id; }
|
||||
uint64_t KThreadCurrentID() { return GetCurrentThread() ->id; }
|
||||
|
|
|
@ -4,10 +4,6 @@
|
|||
|
||||
#ifdef IMPLEMENTATION
|
||||
|
||||
#ifdef DEBUG_BUILD
|
||||
uintptr_t nextMutexID;
|
||||
#endif
|
||||
|
||||
void KSpinlockAcquire(KSpinlock *spinlock) {
|
||||
if (scheduler.panic) return;
|
||||
|
||||
|
@ -187,6 +183,7 @@ bool KMutexAcquire(KMutex *mutex) {
|
|||
KMutexAssertLocked(mutex);
|
||||
|
||||
if (!mutex->id) {
|
||||
static uintptr_t nextMutexID;
|
||||
mutex->id = __sync_fetch_and_add(&nextMutexID, 1);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
#ifdef IMPLEMENTATION
|
||||
|
||||
KMutex eventForwardMutex;
|
||||
|
||||
#define SYSCALL_BUFFER_LIMIT (64 * 1024 * 1024) // To prevent overflow and DOS attacks.
|
||||
#define SYSCALL_BUFFER(address, length, index, write) \
|
||||
MMRegion *_region ## index = MMFindAndPinRegion(currentVMM, (address), (length)); \
|
||||
|
@ -1368,17 +1366,19 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_MESSAGE_DESKTOP) {
|
|||
OpenHandleToObject(pipe, KERNEL_OBJECT_PIPE, PIPE_WRITER);
|
||||
}
|
||||
|
||||
void *constantBuffer = MakeConstantBuffer(buffer, argument1);
|
||||
|
||||
_EsMessageWithObject m = {};
|
||||
m.message.type = ES_MSG_DESKTOP;
|
||||
m.message.desktop.buffer = MakeConstantBufferForDesktop(buffer, argument1);
|
||||
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 ? desktopProcess->handleTable.OpenHandle(pipe, PIPE_WRITER, KERNEL_OBJECT_PIPE) : ES_INVALID_HANDLE;
|
||||
m.message.desktop.pipe = pipe ? DesktopOpenHandle(pipe, PIPE_WRITER, KERNEL_OBJECT_PIPE) : ES_INVALID_HANDLE;
|
||||
|
||||
if (!m.message.desktop.buffer || !desktopProcess->messageQueue.SendMessage(&m)) {
|
||||
desktopProcess->handleTable.CloseHandle(m.message.desktop.buffer);
|
||||
desktopProcess->handleTable.CloseHandle(m.message.desktop.pipe);
|
||||
if (!m.message.desktop.buffer || !DesktopSendMessage(&m)) {
|
||||
DesktopCloseHandle(m.message.desktop.buffer);
|
||||
DesktopCloseHandle(m.message.desktop.pipe);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -399,12 +399,11 @@ void WindowManager::PressKey(uint32_t scancode) {
|
|||
KernelLog(LOG_VERBOSE, "WM", "press key", "WindowManager::PressKey - Received key press %x. Modifiers are %X. Keys held: %d/%d%z.\n",
|
||||
scancode, modifiers, keysHeld, maximumKeysHeld, message.keyboard.single ? " (single)" : "");
|
||||
|
||||
if ((modifiers & ES_MODIFIER_CTRL) && (modifiers & ES_MODIFIER_FLAG)) {
|
||||
desktopProcess->messageQueue.SendMessage(nullptr, &message);
|
||||
} else if (activeWindow) {
|
||||
SendMessageToWindow(activeWindow, &message);
|
||||
if (((modifiers & ES_MODIFIER_CTRL) && (modifiers & ES_MODIFIER_FLAG)) || !activeWindow) {
|
||||
_EsMessageWithObject messageWithObject = { nullptr, message };
|
||||
DesktopSendMessage(&messageWithObject);
|
||||
} else {
|
||||
desktopProcess->messageQueue.SendMessage(nullptr, &message);
|
||||
SendMessageToWindow(activeWindow, &message);
|
||||
}
|
||||
|
||||
KMutexRelease(&mutex);
|
||||
|
@ -928,17 +927,16 @@ void EmbeddedWindow::Destroy() {
|
|||
void EmbeddedWindow::Close() {
|
||||
KMutexAssertLocked(&windowManager.mutex);
|
||||
|
||||
EsMessage message;
|
||||
EsMemoryZero(&message, sizeof(EsMessage));
|
||||
message.type = ES_MSG_WINDOW_DESTROYED;
|
||||
owner->messageQueue.SendMessage(apiWindow, &message);
|
||||
_EsMessageWithObject m;
|
||||
EsMemoryZero(&m, sizeof(m));
|
||||
m.object = apiWindow;
|
||||
m.message.type = ES_MSG_WINDOW_DESTROYED;
|
||||
owner->messageQueue.SendMessage(&m);
|
||||
SetEmbedOwner(nullptr);
|
||||
|
||||
if (!scheduler.shutdown) {
|
||||
message.type = ES_MSG_EMBEDDED_WINDOW_DESTROYED;
|
||||
message.desktop.windowID = id;
|
||||
desktopProcess->messageQueue.SendMessage(nullptr, &message);
|
||||
}
|
||||
m.object = nullptr;
|
||||
m.message.type = ES_MSG_EMBEDDED_WINDOW_DESTROYED;
|
||||
m.message.desktop.windowID = id;
|
||||
DesktopSendMessage(&m);
|
||||
|
||||
if (container && container->embed == this) {
|
||||
container->SetEmbed(nullptr);
|
||||
|
|
Loading…
Reference in New Issue