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

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