diff --git a/Source/Editor/GUI/Docking/WindowDragHelper.cs b/Source/Editor/GUI/Docking/WindowDragHelper.cs index 9072dfea2..22903e95e 100644 --- a/Source/Editor/GUI/Docking/WindowDragHelper.cs +++ b/Source/Editor/GUI/Docking/WindowDragHelper.cs @@ -74,7 +74,6 @@ namespace FlaxEditor.GUI.Docking } // Ensure the dragged window stays on top of every other window - //window.Show(); window.IsAlwaysOnTop = true; } diff --git a/Source/Engine/Platform/SDL/SDLInput.cpp b/Source/Engine/Platform/SDL/SDLInput.cpp index c166f6ae5..06bb8a6e9 100644 --- a/Source/Engine/Platform/SDL/SDLInput.cpp +++ b/Source/Engine/Platform/SDL/SDLInput.cpp @@ -405,19 +405,24 @@ public: auto windowHandle = static_cast(window)->_window; if (relativeMode) { - oldScreenRect = SDL_GetWindowMouseRect(windowHandle); relativeModeWindow = window; SDL_GetMouseState(&oldPosition.X, &oldPosition.Y); if (!SDL_CursorVisible()) { // Trap the cursor in current location SDL_Rect clipRect = { (int)oldPosition.X, (int)oldPosition.Y, 1, 1 }; + oldScreenRect = SDL_GetWindowMouseRect(windowHandle); SDL_SetWindowMouseRect(windowHandle, &clipRect); } } else { - SDL_SetWindowMouseRect(windowHandle, oldScreenRect); + if (relativeModeWindow != window) + { + // FIXME: When floating game window is focused and editor viewport activated, the relative mode gets stuck + return; + } + SDL_SetWindowMouseRect(windowHandle, nullptr);//oldScreenRect); SDL_WarpMouseInWindow(windowHandle, oldPosition.X, oldPosition.Y); oldScreenRect = nullptr; relativeModeWindow = nullptr; diff --git a/Source/Engine/Platform/SDL/SDLPlatform.Linux.cpp b/Source/Engine/Platform/SDL/SDLPlatform.Linux.cpp index 5ee152988..e272aafc2 100644 --- a/Source/Engine/Platform/SDL/SDLPlatform.Linux.cpp +++ b/Source/Engine/Platform/SDL/SDLPlatform.Linux.cpp @@ -63,8 +63,6 @@ class LinuxDropTextData : public IGuiData { public: StringView Text; - SDLWindow* Window; - int64* dragOver; Type GetType() const override { @@ -234,17 +232,16 @@ namespace WaylandImpl { public: int64 StartFlag = 0; + int64 WaitFlag = 0; int64 ExitFlag = 0; - StringView data = nullptr; - SDLWindow* window = nullptr; - SDLWindow* dragSourceWindow = nullptr; - Float2 dragOffset = Float2::Zero; - int64 waitFlag = 0; + SDLWindow* Window = nullptr; + SDLWindow* DragSourceWindow = nullptr; + Float2 DragOffset = Float2::Zero; // [ThreadPoolTask] bool Run() override { - bool dragWindow = data == String("notawindow"); + bool dragWindow = DraggingWindow; uint32 grabSerial = GrabSerial; if (EventQueue == nullptr) @@ -261,21 +258,22 @@ namespace WaylandImpl wl_event_queue_destroy(EventQueue); EventQueue = wl_display_create_queue(WaylandDisplay); - WrappedDataDeviceManager = (wl_data_device_manager*)wl_proxy_create_wrapper(DataDeviceManager); - wl_proxy_set_queue((wl_proxy*)WrappedDataDeviceManager, EventQueue); + WrappedDataDeviceManager = static_cast(wl_proxy_create_wrapper(DataDeviceManager)); + wl_proxy_set_queue(reinterpret_cast(WrappedDataDeviceManager), EventQueue); DataDevice = wl_data_device_manager_get_data_device(WrappedDataDeviceManager, Seat); wl_data_device_add_listener(DataDevice, &DataDeviceListener, nullptr); wl_display_roundtrip(WaylandDisplay); - wl_data_device_set_user_data(DataDevice, dragWindow ? dragSourceWindow : window); - WrappedDataDevice = (wl_data_device*)wl_proxy_create_wrapper(DataDevice); - wl_proxy_set_queue((wl_proxy*)WrappedDataDevice, EventQueue); + wl_data_device_set_user_data(DataDevice, dragWindow ? DragSourceWindow : Window); + + WrappedDataDevice = static_cast(wl_proxy_create_wrapper(DataDevice)); + wl_proxy_set_queue(reinterpret_cast(WrappedDataDevice), EventQueue); } // Offer data for consumption, the data source is destroyed elsewhere wl_data_source* dataSource = wl_data_device_manager_create_data_source(WrappedDataDeviceManager); wl_data_source* wrappedDataSource = (wl_data_source*)wl_proxy_create_wrapper(dataSource); - wl_proxy_set_queue((wl_proxy*)wrappedDataSource, EventQueue); + wl_proxy_set_queue(reinterpret_cast(wrappedDataSource), EventQueue); if (dragWindow) { wl_data_source_offer(dataSource, "flaxengine/window"); @@ -288,16 +286,14 @@ namespace WaylandImpl wl_data_source_offer(dataSource, "text/plain;charset=utf-8"); wl_data_source_set_actions(dataSource, WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); } - LinuxDropTextData textData; - textData.Text = *data; - textData.Window = window; - textData.dragOver = &DragOverFlag; + textData.Text = *DraggingData; wl_data_source_add_listener(dataSource, &DataSourceListener, &textData); - auto _window = window->GetSDLWindow(); - auto _mainwindow = dragSourceWindow != nullptr ? dragSourceWindow->GetSDLWindow() : _window; - wl_surface* originSurface = (wl_surface*)SDL_GetPointerProperty(SDL_GetWindowProperties(_mainwindow), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr); + // Begin dragging operation + auto draggedWindow = Window->GetSDLWindow(); + auto dragStartWindow = DragSourceWindow != nullptr ? DragSourceWindow->GetSDLWindow() : draggedWindow; + wl_surface* originSurface = static_cast(SDL_GetPointerProperty(SDL_GetWindowProperties(dragStartWindow), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr)); wl_surface* iconSurface = nullptr; wl_data_device_start_drag(WrappedDataDevice, dataSource, originSurface, iconSurface, grabSerial); @@ -305,35 +301,35 @@ namespace WaylandImpl xdg_toplevel_drag_v1* toplevelDrag = nullptr; xdg_toplevel* wrappedToplevel = nullptr; - + while (Platform::AtomicRead(&ExitFlag) == 0) { + // Start dispatching events to keep data offers alive if (wl_display_dispatch_queue(WaylandDisplay, EventQueue) == -1) LOG(Warning, "wl_display_dispatch_queue failed, errno: {}", errno); if (wl_display_roundtrip_queue(WaylandDisplay, EventQueue) == -1) LOG(Warning, "wl_display_roundtrip_queue failed, errno: {}", errno); - if (wrappedToplevel == nullptr && dragWindow) + // Wait until window has showed up + if (wrappedToplevel == nullptr && dragWindow && Platform::AtomicRead(&WaitFlag) != 0) { - if (Platform::AtomicRead(&waitFlag) != 0) + auto toplevel = static_cast(SDL_GetPointerProperty(SDL_GetWindowProperties(draggedWindow), SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, nullptr)); + if (toplevel != nullptr) { - auto toplevel = (xdg_toplevel*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, nullptr); - if (toplevel != nullptr) - { - wrappedToplevel = (xdg_toplevel*)wl_proxy_create_wrapper(toplevel); - wl_proxy_set_queue((wl_proxy*)wrappedToplevel, EventQueue); - toplevelDrag = xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag(DragManager, dataSource); + // Attach the window to the ongoing drag operation + wrappedToplevel = static_cast(wl_proxy_create_wrapper(toplevel)); + wl_proxy_set_queue(reinterpret_cast(wrappedToplevel), EventQueue); + toplevelDrag = xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag(DragManager, dataSource); - Float2 scaledOffset = dragOffset / window->GetDpiScale(); - xdg_toplevel_drag_v1_attach(toplevelDrag, wrappedToplevel, (int32)scaledOffset.X, (int32)scaledOffset.Y); - } + Float2 scaledOffset = DragOffset / Window->GetDpiScale(); + xdg_toplevel_drag_v1_attach(toplevelDrag, wrappedToplevel, static_cast(scaledOffset.X), static_cast(scaledOffset.Y)); } } } if (wl_display_roundtrip_queue(WaylandDisplay, EventQueue) == -1) LOG(Warning, "wl_display_roundtrip_queue failed, errno: {}", errno); - + if (toplevelDrag != nullptr) { wl_proxy_wrapper_destroy(wrappedToplevel); @@ -362,17 +358,13 @@ namespace WaylandImpl }; } -namespace Impl -{ - Window* draggedWindow = nullptr; -} -using namespace Impl; - // X11 Delegate LinuxPlatform::xEventReceived; namespace X11Impl { + Window* DraggedWindow = nullptr; + struct Property { unsigned char* data; @@ -542,7 +534,6 @@ namespace X11Impl return Float2((float)x, (float)y); } } -//using namespace X11Impl; DragDropEffect Window::DoDragDrop(const StringView& data) { @@ -560,23 +551,22 @@ DragDropEffect Window::DoDragDropWayland(const StringView& data, Window* dragSou // For drag-and-drop, we need to run another event queue in a separate thread to avoid racing issues // while SDL is dispatching the main Wayland event queue when receiving the data offer from us. - // Show()? - { - if (!_visible) - { - if (_showAfterFirstPaint) - { - if (RenderTask) - RenderTask->Enabled = true; - } - else - SDL_ShowWindow(_window); - } - WindowBase::Show(); - } + // Show the window without changing the focus + //Show(); - //while (true) + if (!_visible) { + if (_showAfterFirstPaint) + { + if (RenderTask) + RenderTask->Enabled = true; + } + else + SDL_ShowWindow(_window); + } + WindowBase::Show(); + + /*{ const double time = Platform::GetTimeSeconds(); // Update game logic @@ -591,40 +581,37 @@ DragDropEffect Window::DoDragDropWayland(const StringView& data, Window* dragSou Engine::OnDraw(); Platform::Sleep(1); - } + }*/ WaylandImpl::DraggingActive = true; - WaylandImpl::DraggingWindow = data == String("notawindow"); WaylandImpl::DraggingData = StringView(data.Get(), data.Length()); WaylandImpl::DragOverFlag = 0; auto task = New(); - task->data = data; - task->window = this; - task->dragSourceWindow = dragSourceWindow; // Needs to be the parent window when dragging a tab to window - task->dragOffset = dragOffset; - task->grabSerial = WaylandImpl::GrabSerial; + task->Window = this; + task->DragSourceWindow = dragSourceWindow; // Needs to be the parent window when dragging a tab to window + task->DragOffset = dragOffset; Task::StartNew(task); while (task->GetState() == TaskState::Queued) Platform::Sleep(1); while (Platform::AtomicRead(&task->StartFlag) == 0) - { Platform::Sleep(1); - } while (Platform::AtomicRead(&WaylandImpl::DragOverFlag) == 0) { SDLPlatform::Tick(); Engine::OnUpdate();//Scripting::Update(); // For docking updates - Engine::OnDraw(); + //if (Platform::AtomicRead(&task->WaitFlag) == 1) + Engine::OnDraw(); + + // The window needs to be finished showing up before we can start dragging it + if (IsVisible() && Platform::AtomicRead(&task->WaitFlag) == 0) + { + Platform::AtomicStore(&task->WaitFlag, 1); + } Platform::Sleep(1); - - if (IsVisible() && Platform::AtomicRead(&task->waitFlag) == 0) - { - Platform::AtomicStore(&task->waitFlag, 1); - } } // The mouse up event was ignored earlier, release the button now @@ -632,9 +619,8 @@ DragDropEffect Window::DoDragDropWayland(const StringView& data, Window* dragSou Platform::AtomicStore(&task->ExitFlag, 1); task->Wait(); - + WaylandImpl::DraggingActive = false; - WaylandImpl::DraggingWindow = false; WaylandImpl::DraggingData = nullptr; return DragDropEffect::None; @@ -964,7 +950,7 @@ void SDLPlatform::PreHandleEvents() void SDLPlatform::PostHandleEvents() { // Handle window dragging release here - if (draggedWindow != nullptr) + if (X11Impl::DraggedWindow != nullptr) { Float2 mousePosition; auto buttons = SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y); @@ -975,14 +961,14 @@ void SDLPlatform::PostHandleEvents() SDL_Event buttonUpEvent { 0 }; buttonUpEvent.motion.type = SDL_EVENT_MOUSE_BUTTON_UP; buttonUpEvent.button.down = false; - buttonUpEvent.motion.windowID = SDL_GetWindowID(draggedWindow->GetSDLWindow()); + buttonUpEvent.motion.windowID = SDL_GetWindowID(X11Impl::DraggedWindow->GetSDLWindow()); buttonUpEvent.motion.timestamp = SDL_GetTicksNS(); buttonUpEvent.motion.state = SDL_BUTTON_LEFT; buttonUpEvent.button.clicks = 1; buttonUpEvent.motion.x = mousePosition.X; buttonUpEvent.motion.y = mousePosition.Y; - draggedWindow->HandleEvent(buttonUpEvent); - draggedWindow = nullptr; + X11Impl::DraggedWindow->HandleEvent(buttonUpEvent); + X11Impl::DraggedWindow = nullptr; } } } @@ -998,13 +984,13 @@ bool SDLWindow::HandleEventInternal(SDL_Event& event) // X11 doesn't report any mouse events when mouse is over the caption area, send a simulated event instead... Float2 mousePosition; auto buttons = SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y); - if ((buttons & SDL_BUTTON_MASK(SDL_BUTTON_LEFT)) != 0 && draggedWindow == nullptr) + if ((buttons & SDL_BUTTON_MASK(SDL_BUTTON_LEFT)) != 0 && X11Impl::DraggedWindow == nullptr) { // TODO: verify mouse position, window focus bool result = false; OnLeftButtonHit(WindowHitCodes::Caption, result); if (result) - draggedWindow = this; + X11Impl::DraggedWindow = this; } } break; @@ -1474,6 +1460,29 @@ bool SDLPlatform::UsesX11() return X11Impl::xDisplay != nullptr; } +DragDropEffect SDLWindow::DoDragDrop(const StringView& data, const Float2& offset, Window* dragSourceWindow) +{ + if (SDLPlatform::UsesWayland()) + { + Float2 dragOffset = offset; + if (_settings.HasBorder && dragSourceWindow == this) + { + // Wayland includes the decorations in the client-space coordinates, adjust the offset for it. + // Assume the title decoration is 25px thick... + float topOffset = 25.0f; + dragOffset += Float2(0.0f, topOffset); + } + + WaylandImpl::DraggingWindow = true; + DoDragDropWayland(String(""), dragSourceWindow, dragOffset); + WaylandImpl::DraggingWindow = false; + //Show(); + } + else + Show(); + return DragDropEffect::None; +} + DialogResult MessageBox::Show(Window* parent, const StringView& text, const StringView& caption, MessageBoxButtons buttons, MessageBoxIcon icon) { StringAnsi textAnsi(text); diff --git a/Source/Engine/Platform/SDL/SDLPlatform.Windows.cpp b/Source/Engine/Platform/SDL/SDLPlatform.Windows.cpp index 10bdea912..e11d5d93c 100644 --- a/Source/Engine/Platform/SDL/SDLPlatform.Windows.cpp +++ b/Source/Engine/Platform/SDL/SDLPlatform.Windows.cpp @@ -2,6 +2,8 @@ #if PLATFORM_SDL && PLATFORM_WINDOWS +#define BORDERLESS_MAXIMIZE_WORKAROUND 2 + #include "SDLPlatform.h" #include "SDLInput.h" @@ -16,9 +18,15 @@ #include #include -extern Window* draggedWindow; -Float2 draggedWindowStartPosition = Float2::Zero; -Float2 draggedWindowMousePosition = Float2::Zero; +namespace WinImpl +{ + Window* DraggedWindow; + Float2 DraggedWindowStartPosition = Float2::Zero; + Float2 DraggedWindowMousePosition = Float2::Zero; +#if BORDERLESS_MAXIMIZE_WORKAROUND == 2 + int SkipMaximizeEventsCount = 0; +#endif +} // The events for releasing the mouse during window dragging are missing, handle the mouse release event here bool SDLCALL SDLPlatform::EventMessageHook(void* userdata, MSG* msg) @@ -39,7 +47,7 @@ bool SDLCALL SDLPlatform::EventMessageHook(void* userdata, MSG* msg) ASSERT((window) != nullptr); \ } while (false) - if (draggedWindow != nullptr) + if (WinImpl::DraggedWindow != nullptr) { LOG(Info, "event hook message: {}", msg->message); } @@ -48,12 +56,12 @@ bool SDLCALL SDLPlatform::EventMessageHook(void* userdata, MSG* msg) { Window* window; GET_WINDOW_WITH_HWND(window, msg->hwnd); - draggedWindow = window; + WinImpl::DraggedWindow = window; - draggedWindowStartPosition = draggedWindow->GetClientPosition(); + WinImpl::DraggedWindowStartPosition = WinImpl::DraggedWindow->GetClientPosition(); Float2 mousePos(static_cast(static_cast(WINDOWS_GET_X_LPARAM(msg->lParam))), static_cast(static_cast(WINDOWS_GET_Y_LPARAM(msg->lParam)))); - draggedWindowMousePosition = mousePos; - draggedWindowMousePosition -= draggedWindowStartPosition; + WinImpl::DraggedWindowMousePosition = mousePos; + WinImpl::DraggedWindowMousePosition -= WinImpl::DraggedWindowStartPosition; bool result = false; WindowHitCodes hit = static_cast(msg->wParam); @@ -70,8 +78,8 @@ bool SDLCALL SDLPlatform::EventMessageHook(void* userdata, MSG* msg) event.button.windowID = SDL_GetWindowID(window->GetSDLWindow()); event.button.button = SDL_BUTTON_LEFT; event.button.clicks = 1; - event.button.x = draggedWindowMousePosition.X; - event.button.y = draggedWindowMousePosition.Y; + event.button.x = WinImpl::DraggedWindowMousePosition.X; + event.button.y = WinImpl::DraggedWindowMousePosition.Y; SDL_PushEvent(&event); } @@ -144,14 +152,14 @@ bool EventFilterCallback(void* userdata, SDL_Event* event) } else if (event->type == SDL_EVENT_WINDOW_MOVED) { - Float2 start = draggedWindowStartPosition; + Float2 start = WinImpl::DraggedWindowStartPosition; Float2 newPos = Float2(static_cast(event->window.data1), static_cast(event->window.data2)); Float2 offset = newPos - start; - Float2 mousePos = draggedWindowMousePosition; + Float2 mousePos = WinImpl::DraggedWindowMousePosition; SDL_Event mouseMovedEvent { 0 }; mouseMovedEvent.motion.type = SDL_EVENT_MOUSE_MOTION; - mouseMovedEvent.motion.windowID = SDL_GetWindowID(draggedWindow->GetSDLWindow()); + mouseMovedEvent.motion.windowID = SDL_GetWindowID(WinImpl::DraggedWindow->GetSDLWindow()); mouseMovedEvent.motion.timestamp = SDL_GetTicksNS(); mouseMovedEvent.motion.state = SDL_BUTTON_LEFT; mouseMovedEvent.motion.x = mousePos.X; @@ -171,15 +179,15 @@ bool EventFilterCallback(void* userdata, SDL_Event* event) void SDLPlatform::PreHandleEvents() { - SDL_AddEventWatch(EventFilterCallback, &draggedWindow); + SDL_AddEventWatch(EventFilterCallback, &WinImpl::DraggedWindow); } void SDLPlatform::PostHandleEvents() { - SDL_RemoveEventWatch(watch, &draggedWindow); + SDL_RemoveEventWatch(watch, &WinImpl::DraggedWindow); // Handle window dragging release here - if (draggedWindow != nullptr) + if (WinImpl::DraggedWindow != nullptr) { Float2 mousePosition; auto buttons = SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y); @@ -188,14 +196,14 @@ void SDLPlatform::PostHandleEvents() SDL_Event buttonUpEvent { 0 }; buttonUpEvent.motion.type = SDL_EVENT_MOUSE_BUTTON_UP; buttonUpEvent.button.down = false; - buttonUpEvent.motion.windowID = SDL_GetWindowID(draggedWindow->GetSDLWindow()); + buttonUpEvent.motion.windowID = SDL_GetWindowID(WinImpl::DraggedWindow->GetSDLWindow()); buttonUpEvent.motion.timestamp = SDL_GetTicksNS(); buttonUpEvent.motion.state = SDL_BUTTON_LEFT; buttonUpEvent.button.clicks = 1; buttonUpEvent.motion.x = mousePosition.X; buttonUpEvent.motion.y = mousePosition.Y; - draggedWindow->HandleEvent(buttonUpEvent); - draggedWindow = nullptr; + WinImpl::DraggedWindow->HandleEvent(buttonUpEvent); + WinImpl::DraggedWindow = nullptr; } } @@ -260,18 +268,18 @@ bool SDLWindow::HandleEventInternal(SDL_Event& event) } case SDL_EVENT_MOUSE_BUTTON_UP: { - if (draggedWindow != nullptr && draggedWindow->_windowId != event.button.windowID) + if (WinImpl::DraggedWindow != nullptr && WinImpl::DraggedWindow->_windowId != event.button.windowID) { // Send the button event to dragged window as well Float2 mousePos = ClientToScreen({ event.button.x, event.button.y }); - Float2 clientPos = draggedWindow->ScreenToClient(mousePos); + Float2 clientPos = WinImpl::DraggedWindow->ScreenToClient(mousePos); SDL_Event event2 = event; - event2.button.windowID = draggedWindow->_windowId; + event2.button.windowID = WinImpl::DraggedWindow->_windowId; event2.button.x = clientPos.X; event2.button.y = clientPos.Y; - SDLInput::HandleEvent(draggedWindow, event2); + SDLInput::HandleEvent(WinImpl::DraggedWindow, event2); } break; } @@ -297,10 +305,68 @@ bool SDLPlatform::UsesX11() return false; } +void SDLWindow::Maximize() +{ + if (!_settings.AllowMaximize) + return; + +#if BORDERLESS_MAXIMIZE_WORKAROUND == 1 + // Workaround for "SDL_BORDERLESS_RESIZABLE_STYLE" hint not working as expected when maximizing windows + auto style = ::GetWindowLong((HWND)_handle, GWL_STYLE); + style &= ~STYLE_RESIZABLE; + ::SetWindowLong((HWND)_handle, GWL_STYLE, style); + + SDL_MaximizeWindow(_window); + + style = ::GetWindowLong((HWND)_handle, GWL_STYLE) | STYLE_RESIZABLE; + ::SetWindowLong((HWND)_handle, GWL_STYLE, style); +#else + SDL_MaximizeWindow(_window); +#endif +} + +void SDLWindow::Restore() +{ +#if BORDERLESS_MAXIMIZE_WORKAROUND == 1 + // Workaround for "SDL_BORDERLESS_RESIZABLE_STYLE" hint not working as expected when maximizing windows + auto style = ::GetWindowLong((HWND)_handle, GWL_STYLE); + style &= ~STYLE_RESIZABLE; + ::SetWindowLong((HWND)_handle, GWL_STYLE, style); + + SDL_RestoreWindow(_window); + + style = ::GetWindowLong((HWND)_handle, GWL_STYLE) | STYLE_RESIZABLE; + ::SetWindowLong((HWND)_handle, GWL_STYLE, style); +#else + SDL_RestoreWindow(_window); +#endif +} + +void SDLWindow::Focus() +{ + auto activateWhenRaised = SDL_GetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED); + SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, "1"); + + // Forcing the window to focus causes issues with opening context menus while window is maximized + //auto forceRaiseWindow = SDL_GetHint(SDL_HINT_FORCE_RAISEWINDOW); + //SDL_SetHint(SDL_HINT_FORCE_RAISEWINDOW, "1"); + + SDL_RaiseWindow(_window); + + SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, activateWhenRaised); + //SDL_SetHint(SDL_HINT_FORCE_RAISEWINDOW, forceRaiseWindow); +} + void SDLPlatform::SetHighDpiAwarenessEnabled(bool enable) { // Other supported values: "permonitor", "permonitorv2" SDL_SetHint("SDL_WINDOWS_DPI_AWARENESS", enable ? "system" : "unaware"); } +DragDropEffect SDLWindow::DoDragDrop(const StringView& data, const Float2& offset, Window* dragSourceWindow) +{ + Show(); + return DragDropEffect::None; +} + #endif diff --git a/Source/Engine/Platform/SDL/SDLPlatform.cpp b/Source/Engine/Platform/SDL/SDLPlatform.cpp index f23b10fcd..e3efb55f5 100644 --- a/Source/Engine/Platform/SDL/SDLPlatform.cpp +++ b/Source/Engine/Platform/SDL/SDLPlatform.cpp @@ -138,7 +138,7 @@ void SDLPlatform::Tick() SDLInput::Update(); PreHandleEvents(); - + SDL_PumpEvents(); SDL_Event events[32]; int count = SDL_PeepEvents(events, SDL_arraysize(events), SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST); @@ -213,6 +213,8 @@ Float2 SDLPlatform::GetMousePosition() // Wayland doesn't support reporting global mouse position, // use the last known reported position we got from received window events. pos = Input::GetMouseScreenPosition(); + //if (!SDL_GetGlobalMouseState(&pos.X, &pos.Y)) + // LOG(Error, "SDL_GetGlobalMouseState() failed"); } else if (UsesX11()) SDL_GetGlobalMouseState(&pos.X, &pos.Y); diff --git a/Source/Engine/Platform/SDL/SDLWindow.cpp b/Source/Engine/Platform/SDL/SDLWindow.cpp index 1fc5a939e..9a13ddec8 100644 --- a/Source/Engine/Platform/SDL/SDLWindow.cpp +++ b/Source/Engine/Platform/SDL/SDLWindow.cpp @@ -14,7 +14,6 @@ #include "Engine/Input/Input.h" #include "Engine/Input/Keyboard.h" #include "Engine/Input/Mouse.h" -#include "Engine/Platform/IGuiData.h" #include "Engine/Platform/WindowsManager.h" #define NOGDI @@ -33,45 +32,49 @@ #endif #elif PLATFORM_LINUX #include "Engine/Platform/Linux/IncludeX11.h" -#include "Engine/Core/Collections/Dictionary.h" -#include -#include - -extern SDLWindow* LastPointerWindow; -extern Int2 LastPointerPosition; -extern uint32 ImplicitGrabSerial; -extern xdg_toplevel_drag_manager_v1* DragManager; -extern wl_seat* WaylandSeat; -extern wl_data_device_manager* WaylandDataDeviceManager; -extern bool waylandDraggingActive; -extern bool waylandDraggingWindow; -extern StringView waylandDraggingData; #endif -extern Window* draggedWindow; - #define DefaultDPI 96 -namespace +namespace WindowImpl { SDLWindow* LastEventWindow = nullptr; static SDL_Cursor* Cursors[SDL_SYSTEM_CURSOR_COUNT] = { nullptr }; -#if BORDERLESS_MAXIMIZE_WORKAROUND == 2 - int SkipMaximizeEventsCount = 0; -#endif } +using namespace WindowImpl; -void* GetNativeWindowPointer(SDL_Window* window); SDL_HitTestResult OnWindowHitTest(SDL_Window* win, const SDL_Point* area, void* data); void GetRelativeWindowOffset(WindowType type, SDLWindow* parentWindow, Int2& positionOffset); Int2 GetSDLWindowScreenPosition(const SDLWindow* window); -void SetSDLWindowScreenPosition(const SDLWindow* window, const int x, const int y); +void SetSDLWindowScreenPosition(const SDLWindow* window, const Int2 position); bool IsPopupWindow(WindowType type) { return type == WindowType::Popup || type == WindowType::Tooltip; } +void* GetNativeWindowPointer(SDL_Window* window) +{ + void* windowPtr; + auto props = SDL_GetWindowProperties(window); +#if PLATFORM_WINDOWS + windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr); +#elif PLATFORM_LINUX + windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr); + if (windowPtr == nullptr) + windowPtr = (void*)SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0); +#elif PLATFORM_MAC + windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, nullptr); +#elif PLATFORM_ANDROID + windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_ANDROID_WINDOW_POINTER, nullptr); +#elif PLATFORM_IOS + windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_UIKIT_WINDOW_POINTER, nullptr); +#else + static_assert(false, "unsupported platform"); +#endif + return windowPtr; +} + SDLWindow::SDLWindow(const CreateWindowSettings& settings) : WindowBase(settings) , _handle(nullptr) @@ -186,28 +189,6 @@ SDLWindow::SDLWindow(const CreateWindowSettings& settings) #endif } -void* GetNativeWindowPointer(SDL_Window* window) -{ - void* windowPtr; - auto props = SDL_GetWindowProperties(window); -#if PLATFORM_WINDOWS - windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr); -#elif PLATFORM_LINUX - windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr); - if (windowPtr == nullptr) - windowPtr = (void*)SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0); -#elif PLATFORM_MAC - windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, nullptr); -#elif PLATFORM_ANDROID - windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_ANDROID_WINDOW_POINTER, nullptr); -#elif PLATFORM_IOS - windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_UIKIT_WINDOW_POINTER, nullptr); -#else - static_assert(false, "unsupported platform"); -#endif - return windowPtr; -} - SDL_Window* SDLWindow::GetSDLWindow() const { return _window; @@ -528,11 +509,6 @@ void SDLWindow::Hide() SDL_HideWindow(_window); -#if PLATFORM_LINUX - //if (SDLPlatform::UsesWayland() && _dragOver) - // StopDragging(); -#endif - WindowBase::Hide(); } @@ -544,26 +520,18 @@ void SDLWindow::Minimize() SDL_MinimizeWindow(_window); } +#if !PLATFORM_WINDOWS + void SDLWindow::Maximize() { if (!_settings.AllowMaximize) return; -#if PLATFORM_WINDOWS && BORDERLESS_MAXIMIZE_WORKAROUND == 1 - // Workaround for "SDL_BORDERLESS_RESIZABLE_STYLE" hint not working as expected when maximizing windows - auto style = ::GetWindowLong((HWND)_handle, GWL_STYLE); - style &= ~STYLE_RESIZABLE; - ::SetWindowLong((HWND)_handle, GWL_STYLE, style); - SDL_MaximizeWindow(_window); - - style = ::GetWindowLong((HWND)_handle, GWL_STYLE) | STYLE_RESIZABLE; - ::SetWindowLong((HWND)_handle, GWL_STYLE, style); -#else - SDL_MaximizeWindow(_window); -#endif } +#endif + void SDLWindow::SetBorderless(bool isBorderless, bool maximized) { if (IsFullscreen()) @@ -577,47 +545,24 @@ void SDLWindow::SetBorderless(bool isBorderless, bool maximized) BringToFront(); - if (isBorderless) - { - SDL_SetWindowBordered(_window, !isBorderless ? true : false); - if (maximized) - { - Maximize(); - } - else - Focus(); - } + SDL_SetWindowBordered(_window, !isBorderless ? true : false); + if (maximized) + Maximize(); else - { - SDL_SetWindowBordered(_window, !isBorderless ? true : false); - if (maximized) - { - Maximize(); - } - else - Focus(); - } - + Focus(); + CheckForWindowResize(); } +#if !PLATFORM_WINDOWS + void SDLWindow::Restore() { -#if PLATFORM_WINDOWS && BORDERLESS_MAXIMIZE_WORKAROUND == 1 - // Workaround for "SDL_BORDERLESS_RESIZABLE_STYLE" hint not working as expected when maximizing windows - auto style = ::GetWindowLong((HWND)_handle, GWL_STYLE); - style &= ~STYLE_RESIZABLE; - ::SetWindowLong((HWND)_handle, GWL_STYLE, style); - SDL_RestoreWindow(_window); - - style = ::GetWindowLong((HWND)_handle, GWL_STYLE) | STYLE_RESIZABLE; - ::SetWindowLong((HWND)_handle, GWL_STYLE, style); -#else - SDL_RestoreWindow(_window); -#endif } +#endif + bool SDLWindow::IsClosed() const { return _handle == nullptr; @@ -637,7 +582,7 @@ void SDLWindow::BringToFront(bool force) SDL_RaiseWindow(_window); SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, activateWhenRaised); #endif - if (SDLPlatform::UsesX11()) + //if (SDLPlatform::UsesX11()) { auto activateWhenRaised = SDL_GetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED); SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, "0"); @@ -649,12 +594,11 @@ void SDLWindow::BringToFront(bool force) void SDLWindow::SetClientBounds(const Rectangle& clientArea) { - int newX = static_cast(clientArea.GetLeft()); - int newY = static_cast(clientArea.GetTop()); + Int2 newPos = Int2(clientArea.GetTopLeft()); int newW = static_cast(clientArea.GetWidth()); int newH = static_cast(clientArea.GetHeight()); - SetSDLWindowScreenPosition(this, newX, newY); + SetSDLWindowScreenPosition(this, newPos); SDL_SetWindowSize(_window, newW, newH); } @@ -688,9 +632,9 @@ Int2 GetSDLWindowScreenPosition(const SDLWindow* window) return position - relativeOffset; } -void SetSDLWindowScreenPosition(const SDLWindow* window, const int x, const int y) +void SetSDLWindowScreenPosition(const SDLWindow* window, const Int2 position) { - Int2 relativePosition(x, y); + Int2 relativePosition = position; GetRelativeWindowOffset(window->GetSettings().Type, window->GetSettings().Parent, relativePosition); SDL_SetWindowPosition(window->GetSDLWindow(), relativePosition.X, relativePosition.Y); } @@ -710,12 +654,12 @@ void SDLWindow::SetPosition(const Float2& position) screenPosition += Int2(monitorBounds.GetTopLeft()); } - SetSDLWindowScreenPosition(this, screenPosition.X, screenPosition.Y); + SetSDLWindowScreenPosition(this, screenPosition); } void SDLWindow::SetClientPosition(const Float2& position) { - SetSDLWindowScreenPosition(this, static_cast(position.X), static_cast(position.Y)); + SetSDLWindowScreenPosition(this, Int2(position)); } void SDLWindow::SetIsFullscreen(bool isFullscreen) @@ -806,25 +750,15 @@ void SDLWindow::SetOpacity(const float opacity) LOG(Warning, "SDL_SetWindowOpacity failed: {0}", String(SDL_GetError())); } +#if !PLATFORM_WINDOWS + void SDLWindow::Focus() { -#if PLATFORM_WINDOWS - auto activateWhenRaised = SDL_GetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED); - SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, "1"); - - // Forcing the window to focus causes issues with opening context menus while window is maximized - //auto forceRaiseWindow = SDL_GetHint(SDL_HINT_FORCE_RAISEWINDOW); - //SDL_SetHint(SDL_HINT_FORCE_RAISEWINDOW, "1"); - SDL_RaiseWindow(_window); - - SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, activateWhenRaised); - //SDL_SetHint(SDL_HINT_FORCE_RAISEWINDOW, forceRaiseWindow); -#else - SDL_RaiseWindow(_window); -#endif } +#endif + String SDLWindow::GetTitle() const { return String(SDL_GetWindowTitle(_window)); @@ -992,35 +926,5 @@ void SDLWindow::UpdateCursor() SDL_SetCursor(Cursors[index]); } -//bool draggingActive = false; -DragDropEffect SDLWindow::DoDragDrop(const StringView& data, const Float2& offset, Window* dragSourceWindow) -{ - // TODO: this needs to be non-blocking in all platforms - - Float2 dragOffset = offset; - if (_settings.HasBorder) - { -#if PLATFORM_LINUX - if (SDLPlatform::UsesWayland() && dragSourceWindow == this) - { - // Wayland includes the decorations in the client-space coordinates, adjust the offset for it. - // Assume the title decoration is 25px thick... - float topOffset = 25.0f; - dragOffset += Float2(0.0f, topOffset); - } -#endif - } - -#if PLATFORM_LINUX - if (SDLPlatform::UsesWayland()) - DoDragDropWayland(String("notawindow"), dragSourceWindow, dragOffset); - else -#endif - { - Show(); - } - return DragDropEffect::None; -} - #endif