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
//window.Show();
window.IsAlwaysOnTop = true;
}

View File

@@ -405,19 +405,24 @@ public:
auto windowHandle = static_cast<SDLWindow*>(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;

View File

@@ -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_data_device_manager*>(wl_proxy_create_wrapper(DataDeviceManager));
wl_proxy_set_queue(reinterpret_cast<wl_proxy*>(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_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
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<wl_proxy*>(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<wl_surface*>(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<xdg_toplevel*>(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<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);
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<int32>(scaledOffset.X), static_cast<int32>(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<void*> 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<WaylandImpl::DragDropJob>();
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);

View File

@@ -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 <SDL3/SDL_system.h>
#include <SDL3/SDL_timer.h>
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<float>(static_cast<LONG>(WINDOWS_GET_X_LPARAM(msg->lParam))), static_cast<float>(static_cast<LONG>(WINDOWS_GET_Y_LPARAM(msg->lParam))));
draggedWindowMousePosition = mousePos;
draggedWindowMousePosition -= draggedWindowStartPosition;
WinImpl::DraggedWindowMousePosition = mousePos;
WinImpl::DraggedWindowMousePosition -= WinImpl::DraggedWindowStartPosition;
bool result = false;
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.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<float>(event->window.data1), static_cast<float>(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

View File

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

View File

@@ -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 <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
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<int>(clientArea.GetLeft());
int newY = static_cast<int>(clientArea.GetTop());
Int2 newPos = Int2(clientArea.GetTopLeft());
int newW = static_cast<int>(clientArea.GetWidth());
int newH = static_cast<int>(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<int>(position.X), static_cast<int>(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