diff --git a/apps/test.cpp b/apps/test.cpp index 100d9a8..9ac477b 100644 --- a/apps/test.cpp +++ b/apps/test.cpp @@ -154,6 +154,7 @@ void InitialiseInstance(EsInstance *instance) { EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Hang"), [] (EsInstance *, EsElement *, EsCommand *) { while (true); }); EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Wait"), [] (EsInstance *, EsElement *, EsCommand *) { EsSleep(8000); }); EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Wait, then crash"), [] (EsInstance *, EsElement *, EsCommand *) { EsSleep(8000); EsAssert(false); }); + EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Wait, then exit"), [] (EsInstance *, EsElement *, EsCommand *) { EsSleep(1000); EsProcessTerminateCurrent(); }); EsButtonOnCommand(EsButtonCreate(panel, ES_FLAGS_DEFAULT, 0, "Crash 2"), [] (EsInstance *, EsElement *, EsCommand *) { EsSyscall(ES_SYSCALL_WAIT, 0x8000000000000000, 1, 0, 0); diff --git a/desktop/desktop.cpp b/desktop/desktop.cpp index 03ebdcc..2b05875 100644 --- a/desktop/desktop.cpp +++ b/desktop/desktop.cpp @@ -63,6 +63,7 @@ struct ReorderList : EsElement { }; struct WindowTab : ReorderItem { + // NOTE Don't forget to update WindowTabMoveToNewContainer when modifying this. struct ContainerWindow *container; struct ApplicationInstance *applicationInstance; struct ApplicationInstance *notRespondingInstance; @@ -209,6 +210,8 @@ void ConfigurationWriteToFile(); void OpenDocumentOpenReference(EsObjectID id); void OpenDocumentCloseReference(EsObjectID id); void WallpaperLoad(EsGeneric); +WindowTab *WindowTabCreate(ContainerWindow *container); +ContainerWindow *ContainerWindowCreate(); #include "settings.cpp" @@ -439,6 +442,45 @@ void WindowTabActivate(WindowTab *tab, bool force = false) { } } +void WindowTabDestroy(WindowTab *tab) { + ContainerWindow *container = tab->container; + + if (container->tabBand->items.Length() == 1) { + EsElementDestroy(container->window); + EsElementDestroy(container->taskBarButton); + desktop.allContainerWindows.FindAndDeleteSwap(container, true); + } else { + if (container->active == tab) { + container->active = nullptr; + + for (uintptr_t i = 0; i < container->tabBand->items.Length(); i++) { + if (container->tabBand->items[i] != tab) continue; + WindowTabActivate((WindowTab *) container->tabBand->items[i ? (i - 1) : 1]); + break; + } + } + + EsElementDestroy(tab); + } +} + +void WindowTabMoveToNewContainer(WindowTab *tab) { + // Create the new tab and container window. + WindowTab *newTab = WindowTabCreate(ContainerWindowCreate()); + + // Move ownership of the instance to the new tab. + newTab->applicationInstance = tab->applicationInstance; + newTab->notRespondingInstance = tab->notRespondingInstance; + EsAssert(tab->applicationInstance->tab == tab); + tab->applicationInstance->tab = newTab; + tab->applicationInstance = nullptr; + tab->notRespondingInstance = nullptr; + + // Destroy the old tab, and activate the new one. + WindowTabDestroy(tab); // Deplaces the embedded window from the old container. + WindowTabActivate(newTab); +} + int ContainerWindowMessage(EsElement *element, EsMessage *message) { ContainerWindow *container = (ContainerWindow *) element->userData.p; @@ -558,6 +600,12 @@ int WindowTabMessage(EsElement *element, EsMessage *message) { WindowTabClose((WindowTab *) context.p); }, tab); + if (tab->container->tabBand->items.Length() > 1) { + EsMenuAddItem(menu, ES_FLAGS_DEFAULT, INTERFACE_STRING(DesktopMoveTabToNewWindow), [] (EsMenu *, EsGeneric context) { + WindowTabMoveToNewContainer((WindowTab *) context.p); + }, tab); + } + if (EsKeyboardIsShiftHeld()) { EsMenuAddSeparator(menu); @@ -581,10 +629,9 @@ int WindowTabMessage(EsElement *element, EsMessage *message) { return ES_HANDLED; } -WindowTab *WindowTabCreate(ContainerWindow *container, ApplicationInstance *instance) { +WindowTab *WindowTabCreate(ContainerWindow *container) { WindowTab *tab = (WindowTab *) EsHeapAllocate(sizeof(WindowTab), true); tab->container = container; - tab->applicationInstance = instance; tab->Initialise(container->tabBand, ES_CELL_H_SHRINK | ES_CELL_V_BOTTOM, WindowTabMessage, nullptr); tab->cName = "window tab"; @@ -1196,7 +1243,8 @@ bool ApplicationInstanceStart(int64_t applicationID, EsApplicationStartupInforma ApplicationInstance *ApplicationInstanceCreate(int64_t id, EsApplicationStartupInformation *startupInformation, ContainerWindow *container, bool hidden) { ApplicationInstance *instance = (ApplicationInstance *) EsHeapAllocate(sizeof(ApplicationInstance), true); - WindowTab *tab = !hidden ? WindowTabCreate(container ?: ContainerWindowCreate(), instance) : nullptr; + WindowTab *tab = !hidden ? WindowTabCreate(container ?: ContainerWindowCreate()) : nullptr; + if (tab) tab->applicationInstance = instance; instance->title[0] = ' '; instance->titleBytes = 1; instance->tab = tab; @@ -2227,7 +2275,7 @@ void DesktopSyscall(EsMessage *message, uint8_t *buffer, EsBuffer *pipe) { } void EmbeddedWindowDestroyed(EsObjectID id) { - EsMenuCloseAll(); + EsMenuCloseAll(); // The tab will be destroyed, but menus might be keeping pointers to it. ApplicationInstance *instance = ApplicationInstanceFindByWindowID(id, true /* remove if found */); if (!instance) return; @@ -2259,25 +2307,7 @@ void EmbeddedWindowDestroyed(EsObjectID id) { } if (instance->tab) { - ContainerWindow *container = instance->tab->container; - - if (container->tabBand->items.Length() == 1) { - EsElementDestroy(container->window); - EsElementDestroy(container->taskBarButton); - desktop.allContainerWindows.FindAndDeleteSwap(container, true); - } else { - if (container->active == instance->tab) { - container->active = nullptr; - - for (uintptr_t i = 0; i < container->tabBand->items.Length(); i++) { - if (container->tabBand->items[i] != instance->tab) continue; - WindowTabActivate((WindowTab *) container->tabBand->items[i ? (i - 1) : 1]); - break; - } - } - - EsElementDestroy(instance->tab); - } + WindowTabDestroy(instance->tab); } else if (instance->isUserTask) { desktop.totalUserTaskProgress -= instance->progress; EsElementRepaint(desktop.tasksButton); diff --git a/desktop/gui.cpp b/desktop/gui.cpp index 4dd0d68..40a6b6f 100644 --- a/desktop/gui.cpp +++ b/desktop/gui.cpp @@ -5289,6 +5289,16 @@ void EsElement::Destroy(bool manual) { } } + if (state & UI_STATE_MENU_SOURCE) { + for (uintptr_t i = 0; i < gui.allWindows.Length(); i++) { + if (gui.allWindows[i]->source == this) { + // Close the menu attached to this element. + EsElementDestroy(gui.allWindows[i]); + break; + } + } + } + state |= UI_STATE_DESTROYING | UI_STATE_DESTROYING_CHILD | UI_STATE_BLOCK_INTERACTION; if (parent) { @@ -6935,42 +6945,46 @@ void UIProcessWindowManagerMessage(EsWindow *window, EsMessage *message, Process window->mousePosition.x -= windowBounds.l, window->mousePosition.y -= windowBounds.t; window->hovering = true; } else if (message->type == ES_MSG_WINDOW_DEACTIVATED) { - AccessKeyModeExit(); + if (window->activated) { + AccessKeyModeExit(); - if (window->windowStyle == ES_WINDOW_MENU) { - window->Destroy(); + if (window->windowStyle == ES_WINDOW_MENU) { + window->Destroy(); + } + + window->activated = false; + window->hovering = false; + + if (window->focused) { + window->inactiveFocus = window->focused; + window->inactiveFocus->Repaint(true); + UIRemoveFocusFromElement(window->focused); + window->focused = nullptr; + } + + EsMessageSend(window, message); + UIMaybeRefreshStyleAll(window); } - - window->activated = false; - window->hovering = false; - - if (window->focused) { - window->inactiveFocus = window->focused; - window->inactiveFocus->Repaint(true); - UIRemoveFocusFromElement(window->focused); - window->focused = nullptr; - } - - EsMessageSend(window, message); - UIMaybeRefreshStyleAll(window); } else if (message->type == ES_MSG_WINDOW_ACTIVATED) { - AccessKeyModeExit(); + if (!window->activated) { + AccessKeyModeExit(); - gui.leftModifiers = gui.rightModifiers = 0; - gui.clickChainStartMs = 0; + gui.leftModifiers = gui.rightModifiers = 0; + gui.clickChainStartMs = 0; - window->activated = true; - EsMessage m = { ES_MSG_WINDOW_ACTIVATED }; - EsMessageSend(window, &m); + window->activated = true; + EsMessage m = { ES_MSG_WINDOW_ACTIVATED }; + EsMessageSend(window, &m); - if (!window->focused && window->inactiveFocus) { - EsElementFocus(window->inactiveFocus, false); - window->inactiveFocus->Repaint(true); - window->inactiveFocus = nullptr; + if (!window->focused && window->inactiveFocus) { + EsElementFocus(window->inactiveFocus, false); + window->inactiveFocus->Repaint(true); + window->inactiveFocus = nullptr; + } + + UIRefreshPrimaryClipboard(window); + UIMaybeRefreshStyleAll(window); } - - UIRefreshPrimaryClipboard(window); - UIMaybeRefreshStyleAll(window); } skipInputMessage:; diff --git a/kernel/windows.cpp b/kernel/windows.cpp index 92f0511..809aedf 100644 --- a/kernel/windows.cpp +++ b/kernel/windows.cpp @@ -1186,6 +1186,11 @@ void Window::SetEmbed(EmbeddedWindow *newEmbed) { if (embed) { embed->container = this; ResizeEmbed(); + + EsMessage message; + EsMemoryZero(&message, sizeof(message)); + message.type = windowManager.activeWindow == this ? ES_MSG_WINDOW_ACTIVATED : ES_MSG_WINDOW_DEACTIVATED; + embed->owner->messageQueue.SendMessage(embed->apiWindow, &message); } } diff --git a/res/Theme Source.dat b/res/Theme Source.dat index 012db0b..55aca07 100644 Binary files a/res/Theme Source.dat and b/res/Theme Source.dat differ diff --git a/res/Themes/Theme.dat b/res/Themes/Theme.dat index bdd578a..def7e34 100644 Binary files a/res/Themes/Theme.dat and b/res/Themes/Theme.dat differ diff --git a/shared/strings.cpp b/shared/strings.cpp index c3a1d45..96ce7c7 100644 --- a/shared/strings.cpp +++ b/shared/strings.cpp @@ -77,9 +77,6 @@ DEFINE_INTERFACE_STRING(CommonUnitMilliseconds, " ms"); // Desktop. -DEFINE_INTERFACE_STRING(DesktopCloseTab, "Close tab"); -DEFINE_INTERFACE_STRING(DesktopInspectUI, "Inspect UI"); -DEFINE_INTERFACE_STRING(DesktopCenterWindow, "Center in screen"); DEFINE_INTERFACE_STRING(DesktopNewTabTitle, "New Tab"); DEFINE_INTERFACE_STRING(DesktopShutdownTitle, "Shutdown"); DEFINE_INTERFACE_STRING(DesktopShutdownAction, "Shutdown"); @@ -91,6 +88,11 @@ DEFINE_INTERFACE_STRING(DesktopApplicationStartupError, "The requested applicati DEFINE_INTERFACE_STRING(DesktopNotResponding, "The application is not responding.\nIf you choose to force quit, any unsaved data may be lost."); DEFINE_INTERFACE_STRING(DesktopConfirmShutdown, "Are you sure you want to turn off your computer? All applications will be closed."); +DEFINE_INTERFACE_STRING(DesktopCloseTab, "Close tab"); +DEFINE_INTERFACE_STRING(DesktopMoveTabToNewWindow, "Move to new window"); +DEFINE_INTERFACE_STRING(DesktopInspectUI, "Inspect UI"); +DEFINE_INTERFACE_STRING(DesktopCenterWindow, "Center in screen"); + DEFINE_INTERFACE_STRING(DesktopSettingsApplication, "Settings"); DEFINE_INTERFACE_STRING(DesktopSettingsTitle, "Settings"); DEFINE_INTERFACE_STRING(DesktopSettingsBackButton, "All settings");