drop tab onto container

This commit is contained in:
nakst 2021-09-10 18:50:12 +01:00
parent 9ce99cde84
commit d96b07e115
7 changed files with 91 additions and 38 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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));

View File

@ -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) {