diff --git a/desktop/api.cpp b/desktop/api.cpp index 8c46ac8..abe261b 100644 --- a/desktop/api.cpp +++ b/desktop/api.cpp @@ -780,16 +780,21 @@ void EsInstanceDestroy(EsInstance *instance) { EsElementDestroy(instance->window); } -EsInstance *InstanceFromWindowID(uint64_t id) { +EsWindow *WindowFromWindowID(EsObjectID id) { for (uintptr_t i = 0; i < gui.allWindows.Length(); i++) { - if (EsSyscall(ES_SYSCALL_WINDOW_GET_ID, gui.allWindows[i]->handle, 0, 0, 0) == id) { - return gui.allWindows[i]->instance; + if (gui.allWindows[i]->id == id) { + return gui.allWindows[i]; } } return nullptr; } +EsInstance *InstanceFromWindowID(EsObjectID id) { + EsWindow *window = WindowFromWindowID(id); + return window ? window->instance : nullptr; +} + EsError GetMessage(_EsMessageWithObject *message) { // Process posted messages first, // so that messages like ES_MSG_WINDOW_DESTROYED are received last. diff --git a/desktop/desktop.cpp b/desktop/desktop.cpp index 8059377..b274d15 100644 --- a/desktop/desktop.cpp +++ b/desktop/desktop.cpp @@ -464,9 +464,9 @@ void WindowTabDestroy(WindowTab *tab) { } } -WindowTab *WindowTabMoveToNewContainer(WindowTab *tab) { +WindowTab *WindowTabMoveToNewContainer(WindowTab *tab, ContainerWindow *container = nullptr) { // Create the new tab and container window. - WindowTab *newTab = WindowTabCreate(ContainerWindowCreate()); + WindowTab *newTab = WindowTabCreate(container ?: ContainerWindowCreate()); if (!newTab) return nullptr; // Move ownership of the instance to the new tab. @@ -480,6 +480,10 @@ WindowTab *WindowTabMoveToNewContainer(WindowTab *tab) { // Destroy the old tab, and activate the new one. WindowTabDestroy(tab); // Deplaces the embedded window from the old container. WindowTabActivate(newTab); + + // If this is an existing container window, make sure it's activated. + if (container) EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, newTab->window->handle, 0, 0, ES_WINDOW_PROPERTY_FOCUSED); + return newTab; } @@ -587,9 +591,39 @@ int WindowTabMessage(EsElement *element, EsMessage *message) { EsElementSetDisabled(band->GetChild(0), true); if (band->items.Length() == 1) { - // TODO Dragging into other containers. - EsPoint screenPosition = EsMouseGetPosition(); - WindowChangeBounds(RESIZE_MOVE, screenPosition.x, screenPosition.y, &gui.lastClickX, &gui.lastClickY, band->window); + // Get the window we're hovering the tab over. + EsObjectID hoverWindowID; + EsPoint mousePositionOnScreen = EsMouseGetPosition(); + EsSyscall(ES_SYSCALL_WINDOW_FIND_BY_POINT, (uintptr_t) &hoverWindowID, mousePositionOnScreen.x, mousePositionOnScreen.y, tab->window->id); + EsWindow *hoverWindow = WindowFromWindowID(hoverWindowID); + bool dragInto = false; + + if (hoverWindow && hoverWindow->windowStyle == ES_WINDOW_CONTAINER) { + // Are we hovering over the tab band? + ContainerWindow *hoverContainer = (ContainerWindow *) hoverWindow->userData.p; + EsRectangle hoverTabBandBounds = hoverContainer->tabBand->GetScreenBounds(); + dragInto = EsRectangleContains(hoverTabBandBounds, mousePositionOnScreen.x, mousePositionOnScreen.y); + } + + if (!dragInto) { + // Move the current window. + WindowChangeBounds(RESIZE_MOVE, mousePositionOnScreen.x, mousePositionOnScreen.y, &gui.lastClickX, &gui.lastClickY, band->window); + } else { + ContainerWindow *hoverContainer = (ContainerWindow *) hoverWindow->userData.p; + int32_t dragOffset = mousePositionOnScreen.x - tab->GetScreenBounds().l; + + // Move the tab into the new container. + EsSyscall(ES_SYSCALL_WINDOW_TRANSFER_PRESS, tab->window->handle, hoverWindow->handle, 0, 0); + EsSyscall(ES_SYSCALL_WINDOW_SET_PROPERTY, tab->window->handle, 0, 0, ES_WINDOW_PROPERTY_EMBED); + WindowTab *newTab = WindowTabMoveToNewContainer(tab, hoverContainer); + + // Setup the drag in the new container. + // TODO Sometimes the tab ends up a few pixels off? + newTab->window->pressed = newTab; + newTab->window->dragged = newTab; + newTab->dragOffset = dragOffset + hoverContainer->tabBand->currentStyle->insets.l; + newTab->dragging = true; + } } else { EsPoint mousePosition = EsMouseGetPosition(tab->window); int32_t dragOffThreshold = GetConstantNumber("tabDragOffThreshold"); @@ -598,6 +632,8 @@ int WindowTabMessage(EsElement *element, EsMessage *message) { if (EsRectangleContains(EsRectangleAdd(band->GetWindowBounds(), ES_RECT_1I(-dragOffThreshold)), mousePosition.x, mousePosition.y)) { ReorderItemDragged(tab, message->mouseDragged.newPositionX); } else { + // TODO Moving a tab directly from one container to another. + // If we dragged the tab off the left or right side of the band, put it at the start of the new tab band. bool putAtStart = tab->dragPosition < band->currentStyle->insets.l || tab->dragPosition + tab->width > band->width - band->currentStyle->insets.r; @@ -620,7 +656,10 @@ int WindowTabMessage(EsElement *element, EsMessage *message) { gui.lastClickX = putAtStart ? putAtStartClickX : mousePosition.x; gui.mouseButtonDown = true; gui.draggingStarted = true; - WindowTabMessage(newTab, message); + + // Update the bounds of the new container. + EsPoint mousePositionOnScreen = EsMouseGetPosition(); + WindowChangeBounds(RESIZE_MOVE, mousePositionOnScreen.x, mousePositionOnScreen.y, &gui.lastClickX, &gui.lastClickY, newTab->window); } } } @@ -975,12 +1014,10 @@ void ShutdownModalCreate() { ////////////////////////////////////////////////////// void InstanceForceQuit(EsInstance *, EsElement *element, EsCommand *) { - EsObjectID windowID = EsSyscall(ES_SYSCALL_WINDOW_GET_ID, element->window->handle, 0, 0, 0); - for (uintptr_t i = 0; i < desktop.allApplicationInstances.Length(); i++) { ApplicationInstance *instance = desktop.allApplicationInstances[i]; - if (instance->tab && instance->tab->notRespondingInstance && instance->tab->notRespondingInstance->embeddedWindowID == windowID) { + if (instance->tab && instance->tab->notRespondingInstance && instance->tab->notRespondingInstance->embeddedWindowID == element->window->id) { EsProcessTerminate(instance->processHandle, 1); break; } @@ -1032,8 +1069,7 @@ void InstanceBlankTabCreate(EsMessage *message) { button->userData = application; EsButtonOnCommand(button, [] (EsInstance *, EsElement *element, EsCommand *) { - EsObjectID tabID = EsSyscall(ES_SYSCALL_WINDOW_GET_ID, element->window->handle, 0, 0, 0); - ApplicationInstance *instance = ApplicationInstanceFindByWindowID(tabID); + ApplicationInstance *instance = ApplicationInstanceFindByWindowID(element->window->id); if (ApplicationInstanceStart(((InstalledApplication *) element->userData.p)->id, nullptr, instance)) { WindowTabActivate(instance->tab, true); diff --git a/desktop/gui.cpp b/desktop/gui.cpp index 2544684..43a44b8 100644 --- a/desktop/gui.cpp +++ b/desktop/gui.cpp @@ -420,6 +420,7 @@ void HeapDuplicate(void **pointer, size_t *outBytes, const void *data, size_t by struct EsWindow : EsElement { EsHandle handle; + EsObjectID id; EsWindowStyle windowStyle; uint32_t windowWidth, windowHeight; @@ -879,6 +880,7 @@ EsWindow *EsWindowCreate(EsInstance *instance, EsWindowStyle style) { window->handle = EsSyscall(ES_SYSCALL_WINDOW_CREATE, style, 0, (uintptr_t) window, 0); } + window->id = EsSyscall(ES_SYSCALL_WINDOW_GET_ID, window->handle, 0, 0, 0); window->Initialise(nullptr, ES_CELL_FILL, ProcessRootMessage, nullptr); window->cName = "window"; window->window = window; diff --git a/desktop/os.header b/desktop/os.header index 8076297..2a4da00 100644 --- a/desktop/os.header +++ b/desktop/os.header @@ -286,7 +286,7 @@ define ES_ERROR_FILE_ALREADY_EXISTS (-19) define ES_ERROR_FILE_DOES_NOT_EXIST (-20) define ES_ERROR_DRIVE_ERROR_FILE_DAMAGED (-21) define ES_ERROR_ACCESS_NOT_WITHIN_FILE_BOUNDS (-22) -define ES_ERROR_PERMISSION_NOT_GRANTED (-23) +define ES_ERROR_PERMISSION_NOT_GRANTED (-23) define ES_ERROR_FILE_IN_EXCLUSIVE_USE (-24) define ES_ERROR_FILE_CANNOT_GET_EXCLUSIVE_USE (-25) define ES_ERROR_INCORRECT_NODE_TYPE (-26) @@ -808,6 +808,7 @@ enum EsSyscallType { ES_SYSCALL_WINDOW_REDRAW ES_SYSCALL_WINDOW_MOVE ES_SYSCALL_WINDOW_TRANSFER_PRESS + ES_SYSCALL_WINDOW_FIND_BY_POINT ES_SYSCALL_WINDOW_GET_ID ES_SYSCALL_WINDOW_GET_BOUNDS ES_SYSCALL_WINDOW_GET_EMBED_KEYBOARD diff --git a/kernel/memory.cpp b/kernel/memory.cpp index 0267723..7c60239 100644 --- a/kernel/memory.cpp +++ b/kernel/memory.cpp @@ -775,6 +775,8 @@ bool MMHandlePageFault(MMSpace *space, uintptr_t address, unsigned faultFlags) { } MMRegion *MMReserve(MMSpace *space, size_t bytes, unsigned flags, uintptr_t forcedAddress, bool generateGuardPages) { + // TODO Handling EsHeapAllocate failures. + MMRegion *outputRegion = nullptr; size_t pagesNeeded = ((bytes + K_PAGE_SIZE - 1) & ~(K_PAGE_SIZE - 1)) / K_PAGE_SIZE; diff --git a/kernel/syscall.cpp b/kernel/syscall.cpp index e2f0d5f..db25265 100644 --- a/kernel/syscall.cpp +++ b/kernel/syscall.cpp @@ -1144,6 +1144,7 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_TRANSFER_PRESS) { if (windowManager.pressedWindow == oldWindow) { windowManager.pressedWindow = newWindow; + newWindow->hoveringOverEmbed = false; } KMutexRelease(&windowManager.mutex); @@ -1151,6 +1152,16 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_TRANSFER_PRESS) { SYSCALL_RETURN(ES_SUCCESS, false); } +SYSCALL_IMPLEMENT(ES_SYSCALL_WINDOW_FIND_BY_POINT) { + SYSCALL_PERMISSION(ES_PERMISSION_SCREEN_MODIFY); + KMutexAcquire(&windowManager.mutex); + Window *window = windowManager.FindWindowAtPosition(argument1 /* x */, argument2 /* y */, argument3 /* exclude */); + EsObjectID id = window ? window->id : 0; + KMutexRelease(&windowManager.mutex); + SYSCALL_WRITE(argument0, &id, sizeof(id)); + SYSCALL_RETURN(ES_SUCCESS, false); +} + SYSCALL_IMPLEMENT(ES_SYSCALL_CURSOR_POSITION_GET) { EsPoint point = ES_POINT(windowManager.cursorX, windowManager.cursorY); SYSCALL_WRITE(argument0, &point, sizeof(EsPoint)); diff --git a/kernel/windows.cpp b/kernel/windows.cpp index 809aedf..40fe23a 100644 --- a/kernel/windows.cpp +++ b/kernel/windows.cpp @@ -61,13 +61,12 @@ struct Window { struct WindowManager { void *CreateWindow(Process *process, void *apiWindow, EsWindowStyle style); void *CreateEmbeddedWindow(Process *process, void *apiWindow); - Window *FindWindowAtPosition(int cursorX, int cursorY); + Window *FindWindowAtPosition(int cursorX, int cursorY, EsObjectID exclude = 0); void Initialise(); void MoveCursor(int64_t xMovement, int64_t yMovement); void ClickCursor(unsigned buttons); - void UpdateCursor(int xMovement, int yMovement, unsigned buttons); void PressKey(unsigned scancode); void Redraw(EsPoint position, int width, int height, Window *except = nullptr, int startingAt = 0, bool addToModifiedRegion = true); @@ -239,14 +238,15 @@ void SendMessageToWindow(Window *window, EsMessage *message) { } } -Window *WindowManager::FindWindowAtPosition(int cursorX, int cursorY) { +Window *WindowManager::FindWindowAtPosition(int cursorX, int cursorY, EsObjectID exclude) { KMutexAssertLocked(&mutex); for (intptr_t i = windows.Length() - 1; i >= 0; i--) { Window *window = windows[i]; EsRectangle bounds = ES_RECT_4PD(window->position.x, window->position.y, window->width, window->height); - if (window->solid && !window->hidden && EsRectangleContains(EsRectangleAdd(bounds, window->solidInsets), cursorX, cursorY) + if (window->solid && !window->hidden && exclude != window->id + && EsRectangleContains(EsRectangleAdd(bounds, window->solidInsets), cursorX, cursorY) && (!window->isMaximised || EsRectangleContains(workArea, cursorX, cursorY))) { return window; } @@ -255,24 +255,6 @@ Window *WindowManager::FindWindowAtPosition(int cursorX, int cursorY) { return nullptr; } -void WindowManager::UpdateCursor(int xMovement, int yMovement, unsigned buttons) { - if (!initialised) { - return; - } - - if (xMovement || yMovement) { - if (xMovement * xMovement + yMovement * yMovement < 10 && buttons != lastButtons) { - // This seems to be movement noise generated when the buttons were pressed/released. - } else { - KMutexAcquire(&mutex); - MoveCursor(xMovement, yMovement); - KMutexRelease(&mutex); - } - } - - ClickCursor(buttons); -} - void WindowManager::EndEyedrop(bool cancelled) { KMutexAssertLocked(&mutex); @@ -1222,7 +1204,21 @@ void WindowManager::StartEyedrop(uintptr_t object, Window *avoid, uint32_t cance } void KCursorUpdate(int xMovement, int yMovement, unsigned buttons) { - windowManager.UpdateCursor(xMovement, yMovement, buttons); + if (!windowManager.initialised) { + return; + } + + if (xMovement || yMovement) { + if (xMovement * xMovement + yMovement * yMovement < 10 && buttons != windowManager.lastButtons) { + // This seems to be movement noise generated when the buttons were pressed/released. + } else { + KMutexAcquire(&windowManager.mutex); + windowManager.MoveCursor(xMovement, yMovement); + KMutexRelease(&windowManager.mutex); + } + } + + windowManager.ClickCursor(buttons); } void KKeyPress(unsigned scancode) {