This commit is contained in:
2025-01-28 01:17:16 +02:00
parent 72828a9e58
commit 55de3f8fd3
6 changed files with 236 additions and 251 deletions

View File

@@ -74,7 +74,6 @@ namespace FlaxEditor.GUI.Docking
} }
// Ensure the dragged window stays on top of every other window // Ensure the dragged window stays on top of every other window
//window.Show();
window.IsAlwaysOnTop = true; window.IsAlwaysOnTop = true;
} }

View File

@@ -405,19 +405,24 @@ public:
auto windowHandle = static_cast<SDLWindow*>(window)->_window; auto windowHandle = static_cast<SDLWindow*>(window)->_window;
if (relativeMode) if (relativeMode)
{ {
oldScreenRect = SDL_GetWindowMouseRect(windowHandle);
relativeModeWindow = window; relativeModeWindow = window;
SDL_GetMouseState(&oldPosition.X, &oldPosition.Y); SDL_GetMouseState(&oldPosition.X, &oldPosition.Y);
if (!SDL_CursorVisible()) if (!SDL_CursorVisible())
{ {
// Trap the cursor in current location // Trap the cursor in current location
SDL_Rect clipRect = { (int)oldPosition.X, (int)oldPosition.Y, 1, 1 }; SDL_Rect clipRect = { (int)oldPosition.X, (int)oldPosition.Y, 1, 1 };
oldScreenRect = SDL_GetWindowMouseRect(windowHandle);
SDL_SetWindowMouseRect(windowHandle, &clipRect); SDL_SetWindowMouseRect(windowHandle, &clipRect);
} }
} }
else 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); SDL_WarpMouseInWindow(windowHandle, oldPosition.X, oldPosition.Y);
oldScreenRect = nullptr; oldScreenRect = nullptr;
relativeModeWindow = nullptr; relativeModeWindow = nullptr;

View File

@@ -63,8 +63,6 @@ class LinuxDropTextData : public IGuiData
{ {
public: public:
StringView Text; StringView Text;
SDLWindow* Window;
int64* dragOver;
Type GetType() const override Type GetType() const override
{ {
@@ -234,17 +232,16 @@ namespace WaylandImpl
{ {
public: public:
int64 StartFlag = 0; int64 StartFlag = 0;
int64 WaitFlag = 0;
int64 ExitFlag = 0; int64 ExitFlag = 0;
StringView data = nullptr; SDLWindow* Window = nullptr;
SDLWindow* window = nullptr; SDLWindow* DragSourceWindow = nullptr;
SDLWindow* dragSourceWindow = nullptr; Float2 DragOffset = Float2::Zero;
Float2 dragOffset = Float2::Zero;
int64 waitFlag = 0;
// [ThreadPoolTask] // [ThreadPoolTask]
bool Run() override bool Run() override
{ {
bool dragWindow = data == String("notawindow"); bool dragWindow = DraggingWindow;
uint32 grabSerial = GrabSerial; uint32 grabSerial = GrabSerial;
if (EventQueue == nullptr) if (EventQueue == nullptr)
@@ -261,21 +258,22 @@ namespace WaylandImpl
wl_event_queue_destroy(EventQueue); wl_event_queue_destroy(EventQueue);
EventQueue = wl_display_create_queue(WaylandDisplay); EventQueue = wl_display_create_queue(WaylandDisplay);
WrappedDataDeviceManager = (wl_data_device_manager*)wl_proxy_create_wrapper(DataDeviceManager); WrappedDataDeviceManager = static_cast<wl_data_device_manager*>(wl_proxy_create_wrapper(DataDeviceManager));
wl_proxy_set_queue((wl_proxy*)WrappedDataDeviceManager, EventQueue); wl_proxy_set_queue(reinterpret_cast<wl_proxy*>(WrappedDataDeviceManager), EventQueue);
DataDevice = wl_data_device_manager_get_data_device(WrappedDataDeviceManager, Seat); DataDevice = wl_data_device_manager_get_data_device(WrappedDataDeviceManager, Seat);
wl_data_device_add_listener(DataDevice, &DataDeviceListener, nullptr); wl_data_device_add_listener(DataDevice, &DataDeviceListener, nullptr);
wl_display_roundtrip(WaylandDisplay); wl_display_roundtrip(WaylandDisplay);
wl_data_device_set_user_data(DataDevice, dragWindow ? dragSourceWindow : window); 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); WrappedDataDevice = static_cast<wl_data_device*>(wl_proxy_create_wrapper(DataDevice));
wl_proxy_set_queue(reinterpret_cast<wl_proxy*>(WrappedDataDevice), EventQueue);
} }
// Offer data for consumption, the data source is destroyed elsewhere // 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* dataSource = wl_data_device_manager_create_data_source(WrappedDataDeviceManager);
wl_data_source* wrappedDataSource = (wl_data_source*)wl_proxy_create_wrapper(dataSource); 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<wl_proxy*>(wrappedDataSource), EventQueue);
if (dragWindow) if (dragWindow)
{ {
wl_data_source_offer(dataSource, "flaxengine/window"); 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_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); wl_data_source_set_actions(dataSource, WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
} }
LinuxDropTextData textData; LinuxDropTextData textData;
textData.Text = *data; textData.Text = *DraggingData;
textData.Window = window;
textData.dragOver = &DragOverFlag;
wl_data_source_add_listener(dataSource, &DataSourceListener, &textData); wl_data_source_add_listener(dataSource, &DataSourceListener, &textData);
auto _window = window->GetSDLWindow(); // Begin dragging operation
auto _mainwindow = dragSourceWindow != nullptr ? dragSourceWindow->GetSDLWindow() : _window; auto draggedWindow = Window->GetSDLWindow();
wl_surface* originSurface = (wl_surface*)SDL_GetPointerProperty(SDL_GetWindowProperties(_mainwindow), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr); auto dragStartWindow = DragSourceWindow != nullptr ? DragSourceWindow->GetSDLWindow() : draggedWindow;
wl_surface* originSurface = static_cast<wl_surface*>(SDL_GetPointerProperty(SDL_GetWindowProperties(dragStartWindow), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr));
wl_surface* iconSurface = nullptr; wl_surface* iconSurface = nullptr;
wl_data_device_start_drag(WrappedDataDevice, dataSource, originSurface, iconSurface, grabSerial); wl_data_device_start_drag(WrappedDataDevice, dataSource, originSurface, iconSurface, grabSerial);
@@ -308,25 +304,25 @@ namespace WaylandImpl
while (Platform::AtomicRead(&ExitFlag) == 0) while (Platform::AtomicRead(&ExitFlag) == 0)
{ {
// Start dispatching events to keep data offers alive
if (wl_display_dispatch_queue(WaylandDisplay, EventQueue) == -1) if (wl_display_dispatch_queue(WaylandDisplay, EventQueue) == -1)
LOG(Warning, "wl_display_dispatch_queue failed, errno: {}", errno); LOG(Warning, "wl_display_dispatch_queue failed, errno: {}", errno);
if (wl_display_roundtrip_queue(WaylandDisplay, EventQueue) == -1) if (wl_display_roundtrip_queue(WaylandDisplay, EventQueue) == -1)
LOG(Warning, "wl_display_roundtrip_queue failed, errno: {}", errno); 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<xdg_toplevel*>(SDL_GetPointerProperty(SDL_GetWindowProperties(draggedWindow), SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, nullptr));
{
auto toplevel = (xdg_toplevel*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, nullptr);
if (toplevel != nullptr) if (toplevel != nullptr)
{ {
wrappedToplevel = (xdg_toplevel*)wl_proxy_create_wrapper(toplevel); // Attach the window to the ongoing drag operation
wl_proxy_set_queue((wl_proxy*)wrappedToplevel, EventQueue); wrappedToplevel = static_cast<xdg_toplevel*>(wl_proxy_create_wrapper(toplevel));
wl_proxy_set_queue(reinterpret_cast<wl_proxy*>(wrappedToplevel), EventQueue);
toplevelDrag = xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag(DragManager, dataSource); toplevelDrag = xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag(DragManager, dataSource);
Float2 scaledOffset = dragOffset / window->GetDpiScale(); Float2 scaledOffset = DragOffset / Window->GetDpiScale();
xdg_toplevel_drag_v1_attach(toplevelDrag, wrappedToplevel, (int32)scaledOffset.X, (int32)scaledOffset.Y); xdg_toplevel_drag_v1_attach(toplevelDrag, wrappedToplevel, static_cast<int32>(scaledOffset.X), static_cast<int32>(scaledOffset.Y));
}
} }
} }
} }
@@ -362,17 +358,13 @@ namespace WaylandImpl
}; };
} }
namespace Impl
{
Window* draggedWindow = nullptr;
}
using namespace Impl;
// X11 // X11
Delegate<void*> LinuxPlatform::xEventReceived; Delegate<void*> LinuxPlatform::xEventReceived;
namespace X11Impl namespace X11Impl
{ {
Window* DraggedWindow = nullptr;
struct Property struct Property
{ {
unsigned char* data; unsigned char* data;
@@ -542,7 +534,6 @@ namespace X11Impl
return Float2((float)x, (float)y); return Float2((float)x, (float)y);
} }
} }
//using namespace X11Impl;
DragDropEffect Window::DoDragDrop(const StringView& data) DragDropEffect Window::DoDragDrop(const StringView& data)
{ {
@@ -560,8 +551,9 @@ 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 // 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. // while SDL is dispatching the main Wayland event queue when receiving the data offer from us.
// Show()? // Show the window without changing the focus
{ //Show();
if (!_visible) if (!_visible)
{ {
if (_showAfterFirstPaint) if (_showAfterFirstPaint)
@@ -573,10 +565,8 @@ DragDropEffect Window::DoDragDropWayland(const StringView& data, Window* dragSou
SDL_ShowWindow(_window); SDL_ShowWindow(_window);
} }
WindowBase::Show(); WindowBase::Show();
}
//while (true) /*{
{
const double time = Platform::GetTimeSeconds(); const double time = Platform::GetTimeSeconds();
// Update game logic // Update game logic
@@ -591,40 +581,37 @@ DragDropEffect Window::DoDragDropWayland(const StringView& data, Window* dragSou
Engine::OnDraw(); Engine::OnDraw();
Platform::Sleep(1); Platform::Sleep(1);
} }*/
WaylandImpl::DraggingActive = true; WaylandImpl::DraggingActive = true;
WaylandImpl::DraggingWindow = data == String("notawindow");
WaylandImpl::DraggingData = StringView(data.Get(), data.Length()); WaylandImpl::DraggingData = StringView(data.Get(), data.Length());
WaylandImpl::DragOverFlag = 0; WaylandImpl::DragOverFlag = 0;
auto task = New<WaylandImpl::DragDropJob>(); auto task = New<WaylandImpl::DragDropJob>();
task->data = data; task->Window = this;
task->window = this; task->DragSourceWindow = dragSourceWindow; // Needs to be the parent window when dragging a tab to window
task->dragSourceWindow = dragSourceWindow; // Needs to be the parent window when dragging a tab to window task->DragOffset = dragOffset;
task->dragOffset = dragOffset;
task->grabSerial = WaylandImpl::GrabSerial;
Task::StartNew(task); Task::StartNew(task);
while (task->GetState() == TaskState::Queued) while (task->GetState() == TaskState::Queued)
Platform::Sleep(1); Platform::Sleep(1);
while (Platform::AtomicRead(&task->StartFlag) == 0) while (Platform::AtomicRead(&task->StartFlag) == 0)
{
Platform::Sleep(1); Platform::Sleep(1);
}
while (Platform::AtomicRead(&WaylandImpl::DragOverFlag) == 0) while (Platform::AtomicRead(&WaylandImpl::DragOverFlag) == 0)
{ {
SDLPlatform::Tick(); SDLPlatform::Tick();
Engine::OnUpdate();//Scripting::Update(); // For docking updates Engine::OnUpdate();//Scripting::Update(); // For docking updates
//if (Platform::AtomicRead(&task->WaitFlag) == 1)
Engine::OnDraw(); Engine::OnDraw();
Platform::Sleep(1); // The window needs to be finished showing up before we can start dragging it
if (IsVisible() && Platform::AtomicRead(&task->WaitFlag) == 0)
if (IsVisible() && Platform::AtomicRead(&task->waitFlag) == 0)
{ {
Platform::AtomicStore(&task->waitFlag, 1); Platform::AtomicStore(&task->WaitFlag, 1);
} }
Platform::Sleep(1);
} }
// The mouse up event was ignored earlier, release the button now // The mouse up event was ignored earlier, release the button now
@@ -634,7 +621,6 @@ DragDropEffect Window::DoDragDropWayland(const StringView& data, Window* dragSou
task->Wait(); task->Wait();
WaylandImpl::DraggingActive = false; WaylandImpl::DraggingActive = false;
WaylandImpl::DraggingWindow = false;
WaylandImpl::DraggingData = nullptr; WaylandImpl::DraggingData = nullptr;
return DragDropEffect::None; return DragDropEffect::None;
@@ -964,7 +950,7 @@ void SDLPlatform::PreHandleEvents()
void SDLPlatform::PostHandleEvents() void SDLPlatform::PostHandleEvents()
{ {
// Handle window dragging release here // Handle window dragging release here
if (draggedWindow != nullptr) if (X11Impl::DraggedWindow != nullptr)
{ {
Float2 mousePosition; Float2 mousePosition;
auto buttons = SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y); auto buttons = SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y);
@@ -975,14 +961,14 @@ void SDLPlatform::PostHandleEvents()
SDL_Event buttonUpEvent { 0 }; SDL_Event buttonUpEvent { 0 };
buttonUpEvent.motion.type = SDL_EVENT_MOUSE_BUTTON_UP; buttonUpEvent.motion.type = SDL_EVENT_MOUSE_BUTTON_UP;
buttonUpEvent.button.down = false; 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.timestamp = SDL_GetTicksNS();
buttonUpEvent.motion.state = SDL_BUTTON_LEFT; buttonUpEvent.motion.state = SDL_BUTTON_LEFT;
buttonUpEvent.button.clicks = 1; buttonUpEvent.button.clicks = 1;
buttonUpEvent.motion.x = mousePosition.X; buttonUpEvent.motion.x = mousePosition.X;
buttonUpEvent.motion.y = mousePosition.Y; buttonUpEvent.motion.y = mousePosition.Y;
draggedWindow->HandleEvent(buttonUpEvent); X11Impl::DraggedWindow->HandleEvent(buttonUpEvent);
draggedWindow = nullptr; 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... // X11 doesn't report any mouse events when mouse is over the caption area, send a simulated event instead...
Float2 mousePosition; Float2 mousePosition;
auto buttons = SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y); 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 // TODO: verify mouse position, window focus
bool result = false; bool result = false;
OnLeftButtonHit(WindowHitCodes::Caption, result); OnLeftButtonHit(WindowHitCodes::Caption, result);
if (result) if (result)
draggedWindow = this; X11Impl::DraggedWindow = this;
} }
} }
break; break;
@@ -1474,6 +1460,29 @@ bool SDLPlatform::UsesX11()
return X11Impl::xDisplay != nullptr; 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) DialogResult MessageBox::Show(Window* parent, const StringView& text, const StringView& caption, MessageBoxButtons buttons, MessageBoxIcon icon)
{ {
StringAnsi textAnsi(text); StringAnsi textAnsi(text);

View File

@@ -2,6 +2,8 @@
#if PLATFORM_SDL && PLATFORM_WINDOWS #if PLATFORM_SDL && PLATFORM_WINDOWS
#define BORDERLESS_MAXIMIZE_WORKAROUND 2
#include "SDLPlatform.h" #include "SDLPlatform.h"
#include "SDLInput.h" #include "SDLInput.h"
@@ -16,9 +18,15 @@
#include <SDL3/SDL_system.h> #include <SDL3/SDL_system.h>
#include <SDL3/SDL_timer.h> #include <SDL3/SDL_timer.h>
extern Window* draggedWindow; namespace WinImpl
Float2 draggedWindowStartPosition = Float2::Zero; {
Float2 draggedWindowMousePosition = Float2::Zero; 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 // 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) bool SDLCALL SDLPlatform::EventMessageHook(void* userdata, MSG* msg)
@@ -39,7 +47,7 @@ bool SDLCALL SDLPlatform::EventMessageHook(void* userdata, MSG* msg)
ASSERT((window) != nullptr); \ ASSERT((window) != nullptr); \
} while (false) } while (false)
if (draggedWindow != nullptr) if (WinImpl::DraggedWindow != nullptr)
{ {
LOG(Info, "event hook message: {}", msg->message); LOG(Info, "event hook message: {}", msg->message);
} }
@@ -48,12 +56,12 @@ bool SDLCALL SDLPlatform::EventMessageHook(void* userdata, MSG* msg)
{ {
Window* window; Window* window;
GET_WINDOW_WITH_HWND(window, msg->hwnd); GET_WINDOW_WITH_HWND(window, msg->hwnd);
draggedWindow = window; WinImpl::DraggedWindow = window;
draggedWindowStartPosition = draggedWindow->GetClientPosition(); WinImpl::DraggedWindowStartPosition = WinImpl::DraggedWindow->GetClientPosition();
Float2 mousePos(static_cast<float>(static_cast<LONG>(WINDOWS_GET_X_LPARAM(msg->lParam))), static_cast<float>(static_cast<LONG>(WINDOWS_GET_Y_LPARAM(msg->lParam)))); Float2 mousePos(static_cast<float>(static_cast<LONG>(WINDOWS_GET_X_LPARAM(msg->lParam))), static_cast<float>(static_cast<LONG>(WINDOWS_GET_Y_LPARAM(msg->lParam))));
draggedWindowMousePosition = mousePos; WinImpl::DraggedWindowMousePosition = mousePos;
draggedWindowMousePosition -= draggedWindowStartPosition; WinImpl::DraggedWindowMousePosition -= WinImpl::DraggedWindowStartPosition;
bool result = false; bool result = false;
WindowHitCodes hit = static_cast<WindowHitCodes>(msg->wParam); WindowHitCodes hit = static_cast<WindowHitCodes>(msg->wParam);
@@ -70,8 +78,8 @@ bool SDLCALL SDLPlatform::EventMessageHook(void* userdata, MSG* msg)
event.button.windowID = SDL_GetWindowID(window->GetSDLWindow()); event.button.windowID = SDL_GetWindowID(window->GetSDLWindow());
event.button.button = SDL_BUTTON_LEFT; event.button.button = SDL_BUTTON_LEFT;
event.button.clicks = 1; event.button.clicks = 1;
event.button.x = draggedWindowMousePosition.X; event.button.x = WinImpl::DraggedWindowMousePosition.X;
event.button.y = draggedWindowMousePosition.Y; event.button.y = WinImpl::DraggedWindowMousePosition.Y;
SDL_PushEvent(&event); SDL_PushEvent(&event);
} }
@@ -144,14 +152,14 @@ bool EventFilterCallback(void* userdata, SDL_Event* event)
} }
else if (event->type == SDL_EVENT_WINDOW_MOVED) else if (event->type == SDL_EVENT_WINDOW_MOVED)
{ {
Float2 start = draggedWindowStartPosition; Float2 start = WinImpl::DraggedWindowStartPosition;
Float2 newPos = Float2(static_cast<float>(event->window.data1), static_cast<float>(event->window.data2)); Float2 newPos = Float2(static_cast<float>(event->window.data1), static_cast<float>(event->window.data2));
Float2 offset = newPos - start; Float2 offset = newPos - start;
Float2 mousePos = draggedWindowMousePosition; Float2 mousePos = WinImpl::DraggedWindowMousePosition;
SDL_Event mouseMovedEvent { 0 }; SDL_Event mouseMovedEvent { 0 };
mouseMovedEvent.motion.type = SDL_EVENT_MOUSE_MOTION; 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.timestamp = SDL_GetTicksNS();
mouseMovedEvent.motion.state = SDL_BUTTON_LEFT; mouseMovedEvent.motion.state = SDL_BUTTON_LEFT;
mouseMovedEvent.motion.x = mousePos.X; mouseMovedEvent.motion.x = mousePos.X;
@@ -171,15 +179,15 @@ bool EventFilterCallback(void* userdata, SDL_Event* event)
void SDLPlatform::PreHandleEvents() void SDLPlatform::PreHandleEvents()
{ {
SDL_AddEventWatch(EventFilterCallback, &draggedWindow); SDL_AddEventWatch(EventFilterCallback, &WinImpl::DraggedWindow);
} }
void SDLPlatform::PostHandleEvents() void SDLPlatform::PostHandleEvents()
{ {
SDL_RemoveEventWatch(watch, &draggedWindow); SDL_RemoveEventWatch(watch, &WinImpl::DraggedWindow);
// Handle window dragging release here // Handle window dragging release here
if (draggedWindow != nullptr) if (WinImpl::DraggedWindow != nullptr)
{ {
Float2 mousePosition; Float2 mousePosition;
auto buttons = SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y); auto buttons = SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y);
@@ -188,14 +196,14 @@ void SDLPlatform::PostHandleEvents()
SDL_Event buttonUpEvent { 0 }; SDL_Event buttonUpEvent { 0 };
buttonUpEvent.motion.type = SDL_EVENT_MOUSE_BUTTON_UP; buttonUpEvent.motion.type = SDL_EVENT_MOUSE_BUTTON_UP;
buttonUpEvent.button.down = false; 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.timestamp = SDL_GetTicksNS();
buttonUpEvent.motion.state = SDL_BUTTON_LEFT; buttonUpEvent.motion.state = SDL_BUTTON_LEFT;
buttonUpEvent.button.clicks = 1; buttonUpEvent.button.clicks = 1;
buttonUpEvent.motion.x = mousePosition.X; buttonUpEvent.motion.x = mousePosition.X;
buttonUpEvent.motion.y = mousePosition.Y; buttonUpEvent.motion.y = mousePosition.Y;
draggedWindow->HandleEvent(buttonUpEvent); WinImpl::DraggedWindow->HandleEvent(buttonUpEvent);
draggedWindow = nullptr; WinImpl::DraggedWindow = nullptr;
} }
} }
@@ -260,18 +268,18 @@ bool SDLWindow::HandleEventInternal(SDL_Event& event)
} }
case SDL_EVENT_MOUSE_BUTTON_UP: 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 // Send the button event to dragged window as well
Float2 mousePos = ClientToScreen({ event.button.x, event.button.y }); Float2 mousePos = ClientToScreen({ event.button.x, event.button.y });
Float2 clientPos = draggedWindow->ScreenToClient(mousePos); Float2 clientPos = WinImpl::DraggedWindow->ScreenToClient(mousePos);
SDL_Event event2 = event; SDL_Event event2 = event;
event2.button.windowID = draggedWindow->_windowId; event2.button.windowID = WinImpl::DraggedWindow->_windowId;
event2.button.x = clientPos.X; event2.button.x = clientPos.X;
event2.button.y = clientPos.Y; event2.button.y = clientPos.Y;
SDLInput::HandleEvent(draggedWindow, event2); SDLInput::HandleEvent(WinImpl::DraggedWindow, event2);
} }
break; break;
} }
@@ -297,10 +305,68 @@ bool SDLPlatform::UsesX11()
return false; 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) void SDLPlatform::SetHighDpiAwarenessEnabled(bool enable)
{ {
// Other supported values: "permonitor", "permonitorv2" // Other supported values: "permonitor", "permonitorv2"
SDL_SetHint("SDL_WINDOWS_DPI_AWARENESS", enable ? "system" : "unaware"); 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 #endif

View File

@@ -213,6 +213,8 @@ Float2 SDLPlatform::GetMousePosition()
// Wayland doesn't support reporting global mouse position, // Wayland doesn't support reporting global mouse position,
// use the last known reported position we got from received window events. // use the last known reported position we got from received window events.
pos = Input::GetMouseScreenPosition(); pos = Input::GetMouseScreenPosition();
//if (!SDL_GetGlobalMouseState(&pos.X, &pos.Y))
// LOG(Error, "SDL_GetGlobalMouseState() failed");
} }
else if (UsesX11()) else if (UsesX11())
SDL_GetGlobalMouseState(&pos.X, &pos.Y); SDL_GetGlobalMouseState(&pos.X, &pos.Y);

View File

@@ -14,7 +14,6 @@
#include "Engine/Input/Input.h" #include "Engine/Input/Input.h"
#include "Engine/Input/Keyboard.h" #include "Engine/Input/Keyboard.h"
#include "Engine/Input/Mouse.h" #include "Engine/Input/Mouse.h"
#include "Engine/Platform/IGuiData.h"
#include "Engine/Platform/WindowsManager.h" #include "Engine/Platform/WindowsManager.h"
#define NOGDI #define NOGDI
@@ -33,45 +32,49 @@
#endif #endif
#elif PLATFORM_LINUX #elif PLATFORM_LINUX
#include "Engine/Platform/Linux/IncludeX11.h" #include "Engine/Platform/Linux/IncludeX11.h"
#include "Engine/Core/Collections/Dictionary.h"
#include <wayland/xdg-toplevel-drag-v1.h>
#include <wayland/xdg-shell.h>
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 #endif
extern Window* draggedWindow;
#define DefaultDPI 96 #define DefaultDPI 96
namespace namespace WindowImpl
{ {
SDLWindow* LastEventWindow = nullptr; SDLWindow* LastEventWindow = nullptr;
static SDL_Cursor* Cursors[SDL_SYSTEM_CURSOR_COUNT] = { 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); SDL_HitTestResult OnWindowHitTest(SDL_Window* win, const SDL_Point* area, void* data);
void GetRelativeWindowOffset(WindowType type, SDLWindow* parentWindow, Int2& positionOffset); void GetRelativeWindowOffset(WindowType type, SDLWindow* parentWindow, Int2& positionOffset);
Int2 GetSDLWindowScreenPosition(const SDLWindow* window); 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) bool IsPopupWindow(WindowType type)
{ {
return type == WindowType::Popup || type == WindowType::Tooltip; 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) SDLWindow::SDLWindow(const CreateWindowSettings& settings)
: WindowBase(settings) : WindowBase(settings)
, _handle(nullptr) , _handle(nullptr)
@@ -186,28 +189,6 @@ SDLWindow::SDLWindow(const CreateWindowSettings& settings)
#endif #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 SDL_Window* SDLWindow::GetSDLWindow() const
{ {
return _window; return _window;
@@ -528,11 +509,6 @@ void SDLWindow::Hide()
SDL_HideWindow(_window); SDL_HideWindow(_window);
#if PLATFORM_LINUX
//if (SDLPlatform::UsesWayland() && _dragOver)
// StopDragging();
#endif
WindowBase::Hide(); WindowBase::Hide();
} }
@@ -544,26 +520,18 @@ void SDLWindow::Minimize()
SDL_MinimizeWindow(_window); SDL_MinimizeWindow(_window);
} }
#if !PLATFORM_WINDOWS
void SDLWindow::Maximize() void SDLWindow::Maximize()
{ {
if (!_settings.AllowMaximize) if (!_settings.AllowMaximize)
return; 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); 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) void SDLWindow::SetBorderless(bool isBorderless, bool maximized)
{ {
if (IsFullscreen()) if (IsFullscreen())
@@ -577,47 +545,24 @@ void SDLWindow::SetBorderless(bool isBorderless, bool maximized)
BringToFront(); BringToFront();
if (isBorderless)
{
SDL_SetWindowBordered(_window, !isBorderless ? true : false); SDL_SetWindowBordered(_window, !isBorderless ? true : false);
if (maximized) if (maximized)
{
Maximize(); Maximize();
}
else else
Focus(); Focus();
}
else
{
SDL_SetWindowBordered(_window, !isBorderless ? true : false);
if (maximized)
{
Maximize();
}
else
Focus();
}
CheckForWindowResize(); CheckForWindowResize();
} }
#if !PLATFORM_WINDOWS
void SDLWindow::Restore() 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); 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 bool SDLWindow::IsClosed() const
{ {
return _handle == nullptr; return _handle == nullptr;
@@ -637,7 +582,7 @@ void SDLWindow::BringToFront(bool force)
SDL_RaiseWindow(_window); SDL_RaiseWindow(_window);
SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, activateWhenRaised); SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, activateWhenRaised);
#endif #endif
if (SDLPlatform::UsesX11()) //if (SDLPlatform::UsesX11())
{ {
auto activateWhenRaised = SDL_GetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED); auto activateWhenRaised = SDL_GetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED);
SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, "0"); SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, "0");
@@ -649,12 +594,11 @@ void SDLWindow::BringToFront(bool force)
void SDLWindow::SetClientBounds(const Rectangle& clientArea) void SDLWindow::SetClientBounds(const Rectangle& clientArea)
{ {
int newX = static_cast<int>(clientArea.GetLeft()); Int2 newPos = Int2(clientArea.GetTopLeft());
int newY = static_cast<int>(clientArea.GetTop());
int newW = static_cast<int>(clientArea.GetWidth()); int newW = static_cast<int>(clientArea.GetWidth());
int newH = static_cast<int>(clientArea.GetHeight()); int newH = static_cast<int>(clientArea.GetHeight());
SetSDLWindowScreenPosition(this, newX, newY); SetSDLWindowScreenPosition(this, newPos);
SDL_SetWindowSize(_window, newW, newH); SDL_SetWindowSize(_window, newW, newH);
} }
@@ -688,9 +632,9 @@ Int2 GetSDLWindowScreenPosition(const SDLWindow* window)
return position - relativeOffset; 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); GetRelativeWindowOffset(window->GetSettings().Type, window->GetSettings().Parent, relativePosition);
SDL_SetWindowPosition(window->GetSDLWindow(), relativePosition.X, relativePosition.Y); SDL_SetWindowPosition(window->GetSDLWindow(), relativePosition.X, relativePosition.Y);
} }
@@ -710,12 +654,12 @@ void SDLWindow::SetPosition(const Float2& position)
screenPosition += Int2(monitorBounds.GetTopLeft()); screenPosition += Int2(monitorBounds.GetTopLeft());
} }
SetSDLWindowScreenPosition(this, screenPosition.X, screenPosition.Y); SetSDLWindowScreenPosition(this, screenPosition);
} }
void SDLWindow::SetClientPosition(const Float2& position) void SDLWindow::SetClientPosition(const Float2& position)
{ {
SetSDLWindowScreenPosition(this, static_cast<int>(position.X), static_cast<int>(position.Y)); SetSDLWindowScreenPosition(this, Int2(position));
} }
void SDLWindow::SetIsFullscreen(bool isFullscreen) void SDLWindow::SetIsFullscreen(bool isFullscreen)
@@ -806,25 +750,15 @@ void SDLWindow::SetOpacity(const float opacity)
LOG(Warning, "SDL_SetWindowOpacity failed: {0}", String(SDL_GetError())); LOG(Warning, "SDL_SetWindowOpacity failed: {0}", String(SDL_GetError()));
} }
#if !PLATFORM_WINDOWS
void SDLWindow::Focus() 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_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 String SDLWindow::GetTitle() const
{ {
return String(SDL_GetWindowTitle(_window)); return String(SDL_GetWindowTitle(_window));
@@ -992,35 +926,5 @@ void SDLWindow::UpdateCursor()
SDL_SetCursor(Cursors[index]); 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 #endif