_wayland drag wip
Some checks are pending
Build Android / Game (Android, Release ARM64) (push) Waiting to run
Build iOS / Game (iOS, Release ARM64) (push) Waiting to run
Build Linux / Editor (Linux, Development x64) (push) Waiting to run
Build Linux / Game (Linux, Release x64) (push) Waiting to run
Build macOS / Editor (Mac, Development ARM64) (push) Waiting to run
Build macOS / Game (Mac, Release ARM64) (push) Waiting to run
Build Windows / Editor (Windows, Development x64) (push) Waiting to run
Build Windows / Game (Windows, Release x64) (push) Waiting to run
Cooker / Cook (Mac) (push) Waiting to run
Tests / Tests (Linux) (push) Waiting to run
Tests / Tests (Windows) (push) Waiting to run

This commit is contained in:
2025-01-10 01:00:38 +02:00
parent d41f5bd3e6
commit 2fc6e95ec3
9 changed files with 757 additions and 320 deletions

View File

@@ -103,6 +103,15 @@ namespace FlaxEditor.GUI.Docking
else
window.StartDragging(_dragOffset);
//window.Show();
//window.BringToFront();
//window.Focus();
//toMove.OnShow();
// Perform layout again
//windowGUI.PerformLayout();
// Start tracking mouse
//Proxy.Window.StartTrackingMouse(false);
}
@@ -509,6 +518,7 @@ namespace FlaxEditor.GUI.Docking
private void OnUpdate()
{
//Editor.Log("OnUpdate");
if (_lateDragStartTimer > 0)
{
_lateDragStartTimer -= Time.UnscaledDeltaTime;
@@ -524,6 +534,7 @@ namespace FlaxEditor.GUI.Docking
private void OnMouseMove(Float2 mousePos)
{
//Editor.Log("OnMouseMove");
// Recalculate the drag offset because the current mouse screen position was invalid when we initialized the window
if (_lateDragOffsetUpdate)
{

View File

@@ -200,7 +200,7 @@ namespace FlaxEditor.GUI.Docking
windowGUI.PerformLayout();
// Show
FlaxEngine.Scripting.InvokeOnUpdate(() =>
/*FlaxEngine.Scripting.InvokeOnUpdate(() =>
{
window.Show();
window.BringToFront();
@@ -209,7 +209,7 @@ namespace FlaxEditor.GUI.Docking
// Perform layout again
windowGUI.PerformLayout();
});
});*/
}
/// <summary>

View File

@@ -420,6 +420,11 @@ void StringAnsi::Append(const char* chars, int32 count)
_length = oldLength + count;
_data = (char*)Platform::Allocate((_length + 1) * sizeof(char), 16);
for (int i = 0; i < _length + 1; i++)
{
_data[i] = '0' + i % 10;
}
Platform::MemoryCopy(_data, oldData, oldLength * sizeof(char));
Platform::MemoryCopy(_data + oldLength, chars, count * sizeof(char));
_data[_length] = 0;

View File

@@ -496,6 +496,14 @@ bool SDLInput::HandleEvent(SDLWindow* window, SDL_Event& event)
}
return true;
}
case SDL_EVENT_DROP_POSITION:
{
// We are not receiving mouse motion events during drag-and-drop
auto dpiScale = window->GetDpiScale();
const Float2 mousePos = window->ClientToScreen({ event.drop.x * dpiScale, event.drop.y * dpiScale});
Input::Mouse->OnMouseMove(mousePos, window);
return true;
}
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
{
Input::Mouse->OnMouseLeave(window);

View File

@@ -1,5 +1,11 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
#include <errno.h>
#include "Engine/Platform/Base/DragDropHelper.h"
#include "Engine/Platform/Unix/UnixFile.h"
#include "wayland/xdg-toplevel-drag-v1.h"
#include <wayland/xdg-shell.h>
#include <wayland/xdg-shell.h>
#if PLATFORM_SDL && PLATFORM_LINUX
@@ -16,6 +22,8 @@
#include "Engine/Engine/CommandLine.h"
#include "Engine/Platform/WindowsManager.h"
#include "Engine/Platform/Linux/IncludeX11.h"
#include "Engine/Input/Input.h"
#include "Engine/Input/Mouse.h"
#include <SDL3/SDL_video.h>
#include <SDL3/SDL_system.h>
@@ -28,13 +36,15 @@ void WaylandRegistryGlobal(void* data, wl_registry *registry, uint32 id, const c
void WaylandRegistryGlobalRemove(void* data, wl_registry *registry, uint32 id);
Dictionary<wl_surface*, SDLWindow*> SurfaceToWindowMap;
uint32 LastPointerSerial = 0;
uint32 ImplicitGrabSerial = 0;
wl_display* WaylandDisplay = nullptr;
wl_registry_listener WaylandRegistryListener = { WaylandRegistryGlobal, WaylandRegistryGlobalRemove };
xdg_toplevel_drag_manager_v1* DragManager = nullptr;
wl_seat* WaylandSeat = nullptr;
wl_data_device_manager* WaylandDataDeviceManager = nullptr;
xdg_wm_base* WaylandXdgWmBase = nullptr;
wl_data_device* dataDevice;
bool waylandDraggingActive = false;
// X11
Delegate<void*> LinuxPlatform::xEventReceived;
@@ -86,6 +96,7 @@ class LinuxDropFilesData : public IGuiData
{
public:
Array<String> Files;
SDLWindow* Window;
Type GetType() const override
{
@@ -105,6 +116,8 @@ class LinuxDropTextData : public IGuiData
{
public:
StringView Text;
SDLWindow* Window;
int64* dragOver;
Type GetType() const override
{
@@ -267,10 +280,578 @@ DragDropEffect Window::DoDragDrop(const StringView& data)
return DoDragDropX11(data);
}
wl_data_source* dataSource;
xdg_toplevel_drag_v1* toplevelDrag = nullptr;
wl_data_offer* WaylandDataOffer = nullptr; // The last accepted offer
uint32 WaylandDataOfferSerial = 0; // The last accepted serial for offer
StringAnsi WaylandDataOfferMimeType;
SDLWindow* DragTargetWindow = nullptr;
Float2 DragTargetPosition;
wl_data_offer* WaylandDataSelectionOffer = nullptr;
void WaylandDataOffer_Offer(void* data, wl_data_offer* offer, const char *mime_type)
{
// We are being offered these types of data
//LOG(Info, "WaylandDataOffer_Offer: {}", String(mime_type));
//if (WaylandDataOffer == nullptr)
// return;
//if (StringAnsi(mime_type) == "x.flaxengine.window.snap")
// WaylandDataOfferMimeType = StringAnsi(mime_type);
// wl_data_offer_accept(WaylandDataOffer, WaylandDataOfferSerial, mime_type);
}
void WaylandDataOffer_SourceActions(void *data,
struct wl_data_offer *wl_data_offer,
uint32_t source_actions)
{
//
//LOG(Info, "WaylandDataOffer_SourceActions: {}", source_actions);
}
void WaylandDataOffer_Action(void *data,
struct wl_data_offer *wl_data_offer,
uint32_t dnd_action)
{
// DnD: This action will be performed if dropped
//LOG(Info, "WaylandDataOffer_Action: {}", dnd_action);
}
wl_data_offer_listener WaylandDataOfferListener = { WaylandDataOffer_Offer, WaylandDataOffer_SourceActions, WaylandDataOffer_Action};
void WaylandDataDevice_DataOffer(void *data, wl_data_device *wl_data_device, wl_data_offer *id)
{
LOG(Info, "WaylandDataDevice_DataOffer: {}", (uint64)id);
/*int ret = wl_data_offer_add_listener(id, &WaylandDataOfferListener, nullptr);
if (ret != 0)
LOG(Error, "wl_data_offer_add_listener failed");*/
}
void WaylandDataDevice_Enter(void *data, wl_data_device *wl_data_device, uint32 serial, wl_surface *surface, wl_fixed_t x, wl_fixed_t y, wl_data_offer *id)
{
// DnD: The cursor entered a target surface
LOG(Info, "WaylandDataDevice_Enter serial: {}, surface: {}, pos: {}x{}, id: {}", serial, (uint64)surface, wl_fixed_to_double(x), wl_fixed_to_double(y), (uint64)id);
WaylandDataOffer = id;
WaylandDataOfferSerial = serial;
DragTargetPosition = Float2(MAX_float, MAX_float);
SDLWindow* sourceWindow = (SDLWindow*)data;
if (!SurfaceToWindowMap.TryGet(surface, DragTargetWindow))
DragTargetWindow = nullptr;
if (DragTargetWindow != nullptr)
DragTargetWindow = DragTargetWindow;
if (/*SurfaceToWindowMap.TryGet(surface, DragTargetWindow) && */DragTargetWindow != sourceWindow)
{
// Inform that we support the following action at this given point
wl_data_offer_set_actions(id, WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE, WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE);
if (WaylandDataOfferMimeType == "x.flaxengine.window.snap")
wl_data_offer_accept(WaylandDataOffer, WaylandDataOfferSerial, "x.flaxengine.window.snap");
}
else
{
wl_data_offer_set_actions(id, WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE, WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE);
}
}
void WaylandDataDevice_Leave(void *data, wl_data_device *wl_data_device)
{
// DnD: The cursor left the surface area
// id from enter must be destroyed here
LOG(Info, "WaylandDataDevice_Leave");
if (WaylandDataOffer != nullptr)
wl_data_offer_destroy(WaylandDataOffer);
WaylandDataOffer = nullptr;
WaylandDataOfferSerial = 0;
WaylandDataOfferMimeType = StringAnsi::Empty;
}
void WaylandDataDevice_Motion(void *data, wl_data_device *wl_data_device, uint32_t time, wl_fixed_t x, wl_fixed_t y)
{
// DnD: The cursor moves along the surface
Float2 dragPosition(wl_fixed_to_double(x), wl_fixed_to_double(y));
LOG(Info, "WaylandDataDevice_Motion {},{}", (int)dragPosition.X, (int)dragPosition.Y);
if (DragTargetWindow != nullptr)
{
Float2 mousePos = dragPosition * DragTargetWindow->GetDpiScale();
mousePos = Float2::Floor(mousePos);
if (DragTargetPosition != mousePos)
{
//LOG(Info, "{}: {}", time, mousePos);
Input::Mouse->OnMouseMove(mousePos, DragTargetWindow);
DragTargetPosition = mousePos;
}
}
//SDLWindow* targetWindow;
//if (SurfaceToWindowMap.TryGet(surface, targetWindow) && targetWindow == surfaceWindow)
}
void WaylandDataDevice_Drop(void *data, wl_data_device *wl_data_device)
{
// DnD: The drop is accepted
LOG(Info, "WaylandDataDevice_Drop");
/*int fds[2];
pipe(fds);
wl_data_offer_receive(offer, "text/plain", fds[1]);
close(fds[1]);
// TODO: do something with fds[0]
close(fds[0]);*/
if (WaylandDataOffer != nullptr)
{
wl_data_offer_finish(WaylandDataOffer);
wl_data_offer_destroy(WaylandDataOffer);
WaylandDataOffer = nullptr;
}
}
void WaylandDataDevice_Selection(void *data, wl_data_device *wl_data_device, wl_data_offer *id)
{
// Clipboard: We can read the clipboard content
/*
int fds[2];
pipe(fds);
wl_data_offer_receive(offer, "text/plain", fds[1]);
close(fds[1]);
wl_display_roundtrip(display);
while (true)
{
char buf[1024];
ssize_t n = read(fds[0], buf, sizeof(buf));
if (n <= 0)
break;
//fwrite(buf, 1, n, stdout);
}
close(fds[0]);
wl_data_offer_destroy(offer);
*/
LOG(Info, "WaylandDataDevice_Selection: {}", (uint64)id);
if (WaylandDataSelectionOffer != nullptr)
wl_data_offer_destroy(WaylandDataSelectionOffer);
WaylandDataSelectionOffer = id;
}
wl_data_device_listener WaylandDataDeviceListener =
{
WaylandDataDevice_DataOffer,
WaylandDataDevice_Enter,
WaylandDataDevice_Leave,
WaylandDataDevice_Motion,
WaylandDataDevice_Drop,
WaylandDataDevice_Selection
};
void WaylandDataSource_Target(void *data,
struct wl_data_source *wl_data_source,
const char *mime_type)
{
// The destination accepts the following types, or null if nothing
//SDLWindow* window = static_cast<SDLWindow*>(data);
LOG(Info, "WaylandDataSource_Target mime: {}", String(mime_type));
}
void WaylandDataSource_Send(void *data,
struct wl_data_source *wl_data_source,
const char *mime_type,
int32_t fd)
{
// Clipboard: The other end has accepted the data?
IGuiData* inputData = static_cast<IGuiData*>(data);
//LOG(Info, "WaylandDataSource_Send mime: {}", String(mime_type));
if (inputData->GetType() == IGuiData::Type::Text)
{
UnixFile file(fd);
StringAnsi text = StringAnsi(inputData->GetAsText());
file.Write(text.Get(), text.Length() * sizeof(StringAnsi::CharType));
file.Close();
//Platform::AtomicStore(((LinuxDropTextData*)inputData)->dragOver, 1);
}
}
void WaylandDataSource_Cancelled(void* data, wl_data_source *source)
{
// Clipboard: other application has replaced the content in clipboard
//SDLWindow* window = static_cast<SDLWindow*>(data);
//LOG(Info, "WaylandDataSource_Cancelled");
IGuiData* inputData = static_cast<IGuiData*>(data);
Platform::AtomicStore(((LinuxDropTextData*)inputData)->dragOver, 1);
wl_data_source_destroy(source);
// The mouse up event was ignored earlier, release the button now
SDLWindow* window = ((LinuxDropTextData*)inputData)->Window;
Input::Mouse->OnMouseUp(Platform::GetMousePosition(), MouseButton::Left, window);
/*if (DragTargetWindow != nullptr)
{
Input::Mouse->OnMouseUp(DragTargetPosition, MouseButton::Left, DragTargetWindow);
}
else*/ /*if (window != nullptr)
{
Input::Mouse->OnMouseUp(DragTargetPosition, MouseButton::Left, window);
}*/
}
void WaylandDataSource_DnDDropPerformed(void *data,
struct wl_data_source *wl_data_source)
{
// The destination is being asked to begin DnD, asking confirmation with ASK actionh
//SDLWindow* window = static_cast<SDLWindow*>(data);
//LOG(Info, "WaylandDataSource_DnDDropPerformed");
}
void WaylandDataSource_DnDFinished(void *data,
struct wl_data_source *wl_data_source)
{
// The destination has finally accepted the last given dnd_action
//SDLWindow* window = static_cast<SDLWindow*>(data);
//LOG(Info, "WaylandDataSource_DnDFinished");
IGuiData* inputData = static_cast<IGuiData*>(data);
Platform::AtomicStore(((LinuxDropTextData*)inputData)->dragOver, 1);
wl_data_source_destroy(wl_data_source);
// The mouse up event was ignored earlier, release the button now
SDLWindow* window = ((LinuxDropTextData*)inputData)->Window;
Input::Mouse->OnMouseUp(Platform::GetMousePosition(), MouseButton::Left, window);
/*if (DragTargetWindow != nullptr)
{
Input::Mouse->OnMouseUp(DragTargetPosition, MouseButton::Left, DragTargetWindow);
}
else*/ /*if (window != nullptr)
{
Input::Mouse->OnMouseUp(DragTargetPosition, MouseButton::Left, window);
}*/
}
void WaylandDataSource_Action(void *data,
struct wl_data_source *wl_data_source,
uint32_t dnd_action)
{
// DnD: The destination may accept the given action if confirmed
//SDLWindow* window = static_cast<SDLWindow*>(data);
LOG(Info, "WaylandDataSource_Action: {}", String(dnd_action == 0 ? "NONE" : dnd_action == 1 ? "COPY" : dnd_action == 2 ? "MOVE" : dnd_action == 4 ? "ASK" : ""));
}
wl_data_source_listener WaylandDataSourceListener =
{
WaylandDataSource_Target,
WaylandDataSource_Send,
WaylandDataSource_Cancelled,
WaylandDataSource_DnDDropPerformed,
WaylandDataSource_DnDFinished,
WaylandDataSource_Action
};
wl_event_queue* WaylandQueue = nullptr;
wl_data_device_manager* wrappedManager = nullptr;
wl_data_source* wrappedDataSource = nullptr;
wl_data_device* wrappedDataDevice = nullptr;
class WaylandDragDropJob : public ThreadPoolTask
{
public:
int64 StartFlag = 0;
int64 ExitFlag = 0;
StringView data;
SDLWindow* window;
int64 dragOver = 0;
int64 waitFlag = 0;
// [ThreadPoolTask]
bool Run() override
{
Scripting::GetScriptsDomain()->Dispatch();
wl_display* wrappedDisplay = WaylandDisplay;//(wl_display*)wl_proxy_create_wrapper(WaylandDisplay);
//wl_proxy_set_queue((wl_proxy*)wrappedDisplay, queue);
if (WaylandQueue == nullptr)
{
if (wrappedDataDevice != nullptr)
wl_proxy_wrapper_destroy(wrappedDataDevice);
if (wrappedDataSource != nullptr)
wl_proxy_wrapper_destroy(wrappedDataSource);
if (wrappedManager != nullptr)
wl_proxy_wrapper_destroy(wrappedManager);
if (dataDevice != nullptr)
wl_data_device_destroy(dataDevice);
// This seems to throw bogus warnings about wl_data_source still being attached to the queue
if (WaylandQueue != nullptr)
wl_event_queue_destroy(WaylandQueue);
WaylandQueue = wl_display_create_queue(WaylandDisplay);
wrappedManager = (wl_data_device_manager*)wl_proxy_create_wrapper(WaylandDataDeviceManager);
wl_proxy_set_queue((wl_proxy*)wrappedManager, WaylandQueue);
//
//dataDevice = wl_data_device_manager_get_data_device(WaylandDataDeviceManager, WaylandSeat);
//wl_data_device_add_listener(dataDevice, &WaylandDataDeviceListener, nullptr);
//wl_display_roundtrip(WaylandDisplay);
/*auto */dataDevice = wl_data_device_manager_get_data_device(wrappedManager, WaylandSeat);
wl_data_device_add_listener(dataDevice, &WaylandDataDeviceListener, nullptr);
wl_display_roundtrip(wrappedDisplay);
wl_data_device_set_user_data(dataDevice, window);
wrappedDataDevice = (wl_data_device*)wl_proxy_create_wrapper(dataDevice);
wl_proxy_set_queue((wl_proxy*)wrappedDataDevice, WaylandQueue);
}
// We offer the following types of things for consumption:
dataSource = wl_data_device_manager_create_data_source(wrappedManager);
wrappedDataSource = (wl_data_source*)wl_proxy_create_wrapper(dataSource);
wl_proxy_set_queue((wl_proxy*)wrappedDataSource, WaylandQueue);
if (data == String("awindow"))
{
wl_data_source_offer(dataSource, "flaxengine/window");
wl_data_source_offer(dataSource, "text/plain;charset=utf-8"); // TODO: needs support for custom mime-types in SDL
wl_data_source_set_actions(dataSource, wl_data_device_manager_dnd_action::WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE);
}
else
{
wl_data_source_offer(dataSource, "text/plain");
wl_data_source_offer(dataSource, "text/plain;charset=utf-8");
wl_data_source_set_actions(dataSource, wl_data_device_manager_dnd_action::WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | wl_data_device_manager_dnd_action::WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
}
LinuxDropTextData textData;
textData.Text = *data;
textData.Window = window;
textData.dragOver = &dragOver;
auto _window = window->GetSDLWindow();
//wl_data_source_set_user_data(wrappedDataSource, &textData);
wl_data_source_add_listener(dataSource, &WaylandDataSourceListener, &textData);
xdg_toplevel* toplevel = nullptr;//(xdg_toplevel*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, nullptr);
if (toplevel == nullptr)
{
//Platform::AtomicStore(&StartFlag, 1);
/*while (Platform::AtomicRead(&waitFlag) == 0)
{
}*/
//toplevel = (xdg_toplevel*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, nullptr);
}
xdg_toplevel* wrappedToplevel = nullptr;
{
wl_surface* origin = (wl_surface*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr);
wl_surface* icon = nullptr;
uint32 id = ImplicitGrabSerial;
//id = (uint32)SDL_GetNumberProperty(SDL_GetGlobalProperties(), "wayland.serial", 0);
wl_data_device_start_drag((wl_data_device*)SDL_GetPointerProperty(SDL_GetGlobalProperties(), "wayland.data_device", wrappedDataDevice), dataSource, origin, icon, id);
if (data == String("awindow"))
{
if (toplevel != nullptr)
{
wrappedToplevel = (xdg_toplevel*)wl_proxy_create_wrapper(toplevel);
wl_proxy_set_queue((wl_proxy*)wrappedToplevel, WaylandQueue);
toplevelDrag = xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag(DragManager, dataSource);
Float2 offset(100, 240);
Float2 scaledOffset = offset / window->GetDpiScale();
//xdg_toplevel_drag_v1_attach(toplevelDrag, toplevel, (int32)scaledOffset.X, (int32)scaledOffset.Y);
xdg_toplevel_drag_v1_attach(toplevelDrag, wrappedToplevel, (int32)scaledOffset.X, (int32)scaledOffset.Y);
}
}
}
/*wl_display_dispatch_queue(wrappedDisplay, queue);
wl_display_roundtrip_queue(wrappedDisplay, queue);
wl_display_flush(wrappedDisplay);
wl_display_dispatch_queue(wrappedDisplay, queue);
wl_display_dispatch(wrappedDisplay);*/
//wl_display_dispatch_queue_pending(wrappedDisplay, queue);
/*int ret;
while (ret = wl_display_prepare_read_queue(wrappedDisplay, queue), ret != 0)
{
if (ret == -1)
LOG(Info, "err wl_display_prepare_read_queue: {}", errno);
if (wl_display_dispatch_queue_pending(wrappedDisplay, queue) == -1)
LOG(Warning, "err wl_display_dispatch_queue_pending: {}", errno);
//else
// LOG(Info, "OK wl_display_dispatch_queue_pending");
}*/
//if (wl_display_flush(wrappedDisplay) == -1)
// LOG(Warning, "err wl_display_flush: {}", errno);
Platform::AtomicStore(&StartFlag, 1);
while (Platform::AtomicRead(&ExitFlag) == 0)
{
//SDLPlatform::Tick();
//Engine::OnDraw();
//wl_display_dispatch_queue(displayWrapped, queue);
//wl_display_roundtrip_queue(displayWrapped, queue);
//wl_display_flush(displayWrapped);
//wl_display_dispatch_queue(displayWrapped, queue);
//wl_display_dispatch(displayWrapped);
//wl_display_dispatch_queue(wrappedDisplay, queue);
//if (wl_display_flush(wrappedDisplay) == -1)
// LOG(Warning, "err wl_display_flush: {}", errno);
//if (wl_display_dispatch_pending(wrappedDisplay) == -1)
// LOG(Warning, "err wl_display_dispatch_pending: {}", errno);
if (wl_display_dispatch_queue(wrappedDisplay, WaylandQueue) == -1)
LOG(Warning, "err wl_display_dispatch_queue: {}", errno);
if (wl_display_roundtrip_queue(wrappedDisplay, WaylandQueue) == -1)
LOG(Warning, "err wl_display_roundtrip_queue: {}", errno);
if (toplevel == nullptr && data == String("awindow"))
{
if (Platform::AtomicRead(&waitFlag) != 0)
{
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, WaylandQueue);
toplevelDrag = xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag(DragManager, dataSource);
Float2 offset(100, 240);
Float2 scaledOffset = offset / window->GetDpiScale();
//xdg_toplevel_drag_v1_attach(toplevelDrag, toplevel, (int32)scaledOffset.X, (int32)scaledOffset.Y);
xdg_toplevel_drag_v1_attach(toplevelDrag, wrappedToplevel, (int32)scaledOffset.X, (int32)scaledOffset.Y);
}
}
}
//if (wl_display_dispatch_queue(wrappedDisplay, queue) == -1)
// LOG(Warning, "err wl_display_dispatch_queue: {}", errno);
//else
// LOG(Info, "OK wl_display_dispatch_queue");
//if (wl_display_dispatch_queue_pending(wrappedDisplay, queue) == -1)
// LOG(Warning, "err wl_display_dispatch_queue_pending: {}", errno);
//else
// LOG(Info, "OK wl_display_dispatch_queue_pending");
//wl_display_dispatch_pending(WaylandDisplay
//Platform::Sleep(1);
}
if (wl_display_roundtrip_queue(wrappedDisplay, WaylandQueue) == -1)
LOG(Warning, "err wl_display_roundtrip_queue: {}", errno);
//if (wl_display_dispatch_queue(wrappedDisplay, queue) == -1)
// LOG(Warning, "err wl_display_dispatch_queue: {}", errno);
if (toplevelDrag != nullptr)
{
wl_proxy_wrapper_destroy(wrappedToplevel);
xdg_toplevel_drag_v1_destroy(toplevelDrag);
toplevelDrag = nullptr;
}
/*
wl_proxy_wrapper_destroy(wrappedDataDevice);
wl_proxy_wrapper_destroy(wrappedDataSource);
wl_proxy_wrapper_destroy(wrappedManager);
wl_data_device_destroy(dataDevice);*/
if (wrappedDataSource != nullptr)
wl_proxy_wrapper_destroy(wrappedDataSource);
//if (dataSource != nullptr)
// wl_proxy_wrapper_destroy(dataSource);
if (WaylandDataSelectionOffer != nullptr)
{
wl_data_offer_destroy(WaylandDataSelectionOffer);
WaylandDataSelectionOffer = nullptr;
}
// This seems to throw bogus warnings about wl_data_source still being attached to the queue
/*wl_event_queue_destroy(WaylandQueue);
*/
//dataDevice = nullptr;
return false;
}
};
DragDropEffect Window::DoDragDropWayland(const StringView& data)
{
// TODO: Wayland
LOG(Warning, "Wayland Drag and drop is not implemented yet.");
// For drag-and-drop, we need to setup the event queue in separate thread to avoid racing issues
// while SDL is dispatching the main Wayland event queue when receiving the data offer from us.
waylandDraggingActive = true;
auto task = New<WaylandDragDropJob>();
task->data = data;
task->window = this;
task->dragOver = 0;
Task::StartNew(task);
while (task->GetState() == TaskState::Queued)
Platform::Sleep(1);
while (Platform::AtomicRead(&task->StartFlag) == 0)
{
Platform::Sleep(1);
}
Show();
//Focus();
int counter = 100;
while (Platform::AtomicRead(&task->dragOver) == 0)
{
SDLPlatform::Tick();
Engine::OnUpdate(); // For docking updates
Engine::OnDraw();
Platform::Sleep(1);
if (IsVisible() && Platform::AtomicRead(&task->waitFlag) == 0)
{
/*if (counter > 0)
counter--;
else*/
Platform::AtomicStore(&task->waitFlag, 1);
}
}
Platform::AtomicStore(&task->ExitFlag, 1);
task->Wait();
waylandDraggingActive = false;
return DragDropEffect::None;
}
@@ -857,13 +1438,10 @@ int X11ErrorHandler(X11::Display* display, X11::XErrorEvent* event)
return 0;
}
extern wl_data_device_listener WaylandDataDeviceListener;
wl_data_device* dataDevice;
bool SDLPlatform::InitPlatform()
{
if (LinuxPlatform::Init())
return true;
//if (LinuxPlatform::Init())
// return true;
#if false
if (!CommandLine::Options.Headless && strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0)
@@ -874,32 +1452,42 @@ bool SDLPlatform::InitPlatform()
wl_registry_add_listener(registry, &WaylandRegistryListener, nullptr);
wl_display_roundtrip(WaylandDisplay);
dataDevice = wl_data_device_manager_get_data_device(WaylandDataDeviceManager, WaylandSeat);
wl_data_device_add_listener(dataDevice, &WaylandDataDeviceListener, nullptr);
wl_display_roundtrip(WaylandDisplay);
}
#else
bool waylandRequested = !CommandLine::Options.X11 || CommandLine::Options.Wayland;
bool waylandRequested = (!CommandLine::Options.X11 || CommandLine::Options.Wayland) && StringAnsi(SDL_GetHint(SDL_HINT_VIDEO_DRIVER)) == "wayland";
if (!CommandLine::Options.Headless && waylandRequested)
{
// Ignore in X11 session
String waylandDisplayEnv;
if (!GetEnvironmentVariable(String("WAYLAND_DISPLAY"), waylandDisplayEnv))
{
WaylandDisplay = wl_display_connect(nullptr);
WaylandDisplay = (wl_display*)SDL_GetPointerProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER, nullptr);
if (WaylandDisplay == nullptr)
{
WaylandDisplay = wl_display_connect(nullptr);
SDL_SetPointerProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER, WaylandDisplay);
}
if (WaylandDisplay != nullptr)
{
// We need to manage the wl_display and create the wl_data_device
// before SDL so we can receive drag-and-drop related events from compositor.
SDL_SetPointerProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER, WaylandDisplay);
//SDL_SetPointerProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER, WaylandDisplay);
wl_registry* registry = wl_display_get_registry(WaylandDisplay);
wl_registry_add_listener(registry, &WaylandRegistryListener, nullptr);
wl_display_roundtrip(WaylandDisplay);
dataDevice = wl_data_device_manager_get_data_device(WaylandDataDeviceManager, WaylandSeat);
/*dataDevice = wl_data_device_manager_get_data_device(WaylandDataDeviceManager, WaylandSeat);
wl_data_device_add_listener(dataDevice, &WaylandDataDeviceListener, nullptr);
wl_display_roundtrip(WaylandDisplay);
wl_display_roundtrip(WaylandDisplay);*/
}
}
}
@@ -1007,7 +1595,7 @@ void WaylandPointer_Enter(void *data,
LastPointerWindow = window;
LastPointerPosition = Int2(surface_x, surface_y);*/
//LOG(Info, "WaylandPointerEnter serial:{}", serial);
LastPointerSerial = serial;
//ImplicitGrabSerial = serial;
}
void WaylandPointer_Leave(void *data,
@@ -1017,7 +1605,6 @@ void WaylandPointer_Leave(void *data,
{
//LastPointerWindow = nullptr;
//LOG(Info, "WaylandPointerLeave serial:{}", serial);
LastPointerSerial = serial;
}
void WaylandPointer_Motion(void *data,
@@ -1032,12 +1619,13 @@ void WaylandPointer_Motion(void *data,
void WaylandPointer_Button(void* data, wl_pointer* wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
{
//LOG(Info, "WaylandPointerButton serial:{}", serial);
LOG(Info, "WaylandPointerButton serial:{}, button:{}, state:{}", serial, button, state);
// HACK: We store the serial for upcoming drag-and-drop action even though we are
// not really performing the action during this specific button press event.
// SDL receives the same event which actually starts the DnD process.
LastPointerSerial = serial;
// SDL receives the same event which actually starts the drag process.
if (state == 1)
ImplicitGrabSerial = serial;
}
void WaylandPointer_Axis(void *data,
@@ -1130,7 +1718,7 @@ wl_seat_listener SeatListener = { SeatCapabilities, SeatName };
void WaylandRegistryGlobal(void* data, wl_registry *registry, uint32 id, const char* interface, uint32 version)
{
StringAnsi interfaceStr(interface);
LOG(Info, "WaylandRegistryGlobal id: {}, interface: {}", id, String(interface));
//LOG(Info, "WaylandRegistryGlobal id: {}, interface: {}", id, String(interface));
if (interfaceStr == "xdg_toplevel_drag_manager_v1")
DragManager = (xdg_toplevel_drag_manager_v1*)wl_registry_bind(registry, id, &xdg_toplevel_drag_manager_v1_interface, 1U);
else if (interfaceStr == "wl_seat")

View File

@@ -45,6 +45,7 @@ bool SDLPlatform::Init()
SDL_SetHintWithPriority(SDL_HINT_VIDEO_DRIVER, "wayland", SDL_HINT_OVERRIDE);
else
SDL_SetHintWithPriority(SDL_HINT_VIDEO_DRIVER, "wayland", SDL_HINT_OVERRIDE);
//SDL_SetHintWithPriority(SDL_HINT_VIDEO_DRIVER, "x11", SDL_HINT_OVERRIDE);
#endif
#if PLATFORM_LINUX
@@ -76,17 +77,17 @@ bool SDLPlatform::Init()
SDL_SetHint(SDL_HINT_VIDEO_WAYLAND_SCALE_TO_DISPLAY, "1");
// Disable SDL clipboard support
SDL_SetEventEnabled(SDL_EVENT_CLIPBOARD_UPDATE, false);
/*SDL_SetEventEnabled(SDL_EVENT_CLIPBOARD_UPDATE, false);
// Disable SDL drag and drop support
SDL_SetEventEnabled(SDL_EVENT_DROP_FILE, false);
SDL_SetEventEnabled(SDL_EVENT_DROP_TEXT, false);
SDL_SetEventEnabled(SDL_EVENT_DROP_BEGIN, false);
SDL_SetEventEnabled(SDL_EVENT_DROP_COMPLETE, false);
SDL_SetEventEnabled(SDL_EVENT_DROP_POSITION, false);
SDL_SetEventEnabled(SDL_EVENT_DROP_POSITION, false);*/
if (InitPlatform())
return true;
//if (InitPlatform())
// return true;
if (!SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD))
Platform::Fatal(String::Format(TEXT("Failed to initialize SDL: {0}."), String(SDL_GetError())));
@@ -107,7 +108,9 @@ bool SDLPlatform::Init()
}
}
SDL_free(locales);
if (InitPlatform())
return true;
SDLInput::Init();

View File

@@ -40,11 +40,12 @@
extern Dictionary<wl_surface*, SDLWindow*> SurfaceToWindowMap;
extern SDLWindow* LastPointerWindow;
extern Int2 LastPointerPosition;
extern uint32 LastPointerSerial;
extern uint32 ImplicitGrabSerial;
extern xdg_toplevel_drag_manager_v1* DragManager;
extern wl_seat* WaylandSeat;
extern wl_data_device_manager* WaylandDataDeviceManager;
extern xdg_wm_base* WaylandXdgWmBase;
extern bool waylandDraggingActive;
#endif
#define DefaultDPI 96
@@ -452,6 +453,7 @@ void SDLWindow::HandleEvent(SDL_Event& event)
}
case SDL_EVENT_MOUSE_MOTION:
{
//LOG(Info, "SDL_EVENT_MOUSE_MOTION");
if (_isTrackingMouse && _isUsingMouseOffset)
{
Float2 delta(event.motion.xrel, event.motion.yrel);
@@ -588,6 +590,7 @@ void SDLWindow::HandleEvent(SDL_Event& event)
}
case SDL_EVENT_WINDOW_FOCUS_GAINED:
{
LOG(Info, "focus {}", GetTitle());
#if PLATFORM_LINUX
_forcedFocus = false;
#endif
@@ -603,6 +606,7 @@ void SDLWindow::HandleEvent(SDL_Event& event)
}
case SDL_EVENT_WINDOW_FOCUS_LOST:
{
LOG(Info, "focus lost {}", GetTitle());
#if PLATFORM_LINUX
_forcedFocus = false;
#endif
@@ -629,10 +633,24 @@ void SDLWindow::HandleEvent(SDL_Event& event)
}
return;
}
#if false
#if true
case SDL_EVENT_CLIPBOARD_UPDATE:
{
LOG(Info, "SDL_EVENT_CLIPBOARD_UPDATE");
return;
}
case SDL_EVENT_DROP_BEGIN:
{
Focus();
LOG(Info, "SDL_EVENT_DROP_BEGIN");
auto dpiScale = GetDpiScale();
const Float2 mousePos = ClientToScreen({ event.drop.x * dpiScale, event.drop.y * dpiScale});
DragDropEffect effect = DragDropEffect::None;
auto daata = event.drop.data;
SDLDropTextData dropData;
OnDragEnter(&dropData, mousePos, effect);
/*Focus();
Float2 mousePosition;
SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y);
mousePosition = ScreenToClient(mousePosition);
@@ -640,20 +658,37 @@ void SDLWindow::HandleEvent(SDL_Event& event)
DragDropEffect effect;
SDLDropTextData dropData;
OnDragEnter(&dropData, mousePosition, effect);
OnDragOver(&dropData, mousePosition, effect);
OnDragOver(&dropData, mousePosition, effect);*/
return;
}
case SDL_EVENT_DROP_POSITION:
{
auto dpiScale = GetDpiScale();
const Float2 mousePos = ClientToScreen({ event.drop.x * dpiScale, event.drop.y * dpiScale});
DragDropEffect effect = DragDropEffect::None;
auto daata = event.drop.data;
SDLDropTextData dropData;
OnDragOver(&dropData, Float2(static_cast<float>(event.drop.x), static_cast<float>(event.drop.y)), effect);
return;
OnDragOver(&dropData, mousePos, effect);
/*DragDropEffect effect = DragDropEffect::None;
SDLDropTextData dropData;
OnDragOver(&dropData, Float2(static_cast<float>(event.drop.x), static_cast<float>(event.drop.y)), effect);*/
break;
}
case SDL_EVENT_DROP_FILE:
{
SDLDropFilesData dropData;
LOG(Info, "SDL_EVENT_DROP_FILE");
auto dpiScale = GetDpiScale();
const Float2 mousePos = ClientToScreen({ event.drop.x * dpiScale, event.drop.y * dpiScale});
DragDropEffect effect = DragDropEffect::None;
auto daata = event.drop.data;
SDLDropTextData dropData;
OnDragDrop(&dropData, mousePos, effect);
/*SDLDropFilesData dropData;
dropData.Files.Add(StringAnsi(event.drop.data).ToString()); // TODO: collect multiple files at once?
Focus();
@@ -662,12 +697,23 @@ void SDLWindow::HandleEvent(SDL_Event& event)
SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y);
mousePosition = ScreenToClient(mousePosition);
DragDropEffect effect = DragDropEffect::None;
OnDragDrop(&dropData, mousePosition, effect);
OnDragDrop(&dropData, mousePosition, effect);*/
return;
}
case SDL_EVENT_DROP_TEXT:
{
auto dpiScale = GetDpiScale();
const Float2 mousePos = ClientToScreen({ event.drop.x * dpiScale, event.drop.y * dpiScale});
DragDropEffect effect = DragDropEffect::None;
auto daata = event.drop.data;
auto str = String(event.drop.data);
LOG(Info, "SDL_EVENT_DROP_TEXT: {}", str);
SDLDropTextData dropData;
OnDragDrop(&dropData, mousePos, effect);
/*SDLDropTextData dropData;
String str = StringAnsi(event.drop.data).ToString();
dropData.Text = StringView(str);
@@ -676,11 +722,23 @@ void SDLWindow::HandleEvent(SDL_Event& event)
SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y);
mousePosition = ScreenToClient(mousePosition);
DragDropEffect effect = DragDropEffect::None;
OnDragDrop(&dropData, mousePosition, effect);
OnDragDrop(&dropData, mousePosition, effect);*/
return;
}
case SDL_EVENT_DROP_COMPLETE:
{
LOG(Info, "SDL_EVENT_DROP_COMPLETE");
auto dpiScale = GetDpiScale();
const Float2 mousePos = ClientToScreen({ event.drop.x * dpiScale, event.drop.y * dpiScale});
DragDropEffect effect = DragDropEffect::None;
auto daata = event.drop.data;
OnDragLeave();
if (SDLPlatform::UsesWayland())
{
//_dragOver = false;
}
return;
}
#endif
@@ -694,11 +752,14 @@ void SDLWindow::HandleEvent(SDL_Event& event)
#if PLATFORM_LINUX
case SDL_EVENT_MOUSE_BUTTON_UP:
{
if (SDLPlatform::UsesWayland() && _dragOver)
if (SDLPlatform::UsesWayland() && waylandDraggingActive)
{
LOG(Info, "SDL_EVENT_MOUSE_BUTTON_UP, dragging");
// We are dragging a window, keep the button held down
return;
}
else
LOG(Info, "SDL_EVENT_MOUSE_BUTTON_UP");
break;
}
#endif
@@ -1207,272 +1268,45 @@ void SDLWindow::UpdateCursor()
SDL_SetCursor(Cursors[index]);
}
wl_data_offer* WaylandDataOffer = nullptr; // The last accepted offer
uint32 WaylandDataOfferSerial = 0; // The last accepted serial for offer
StringAnsi WaylandDataOfferMimeType;
SDLWindow* DragTargetWindow = nullptr;
Float2 DragTargetPosition;
void WaylandDataOffer_Offer(void* data, wl_data_offer* offer, const char *mime_type)
//extern wl_data_device* dataDevice;
//wl_data_source* dataSource;
/*void OnBeforeSurfaceCommit(void* data)
{
// We are being offered these types of data
//LOG(Info, "WaylandDataOffer_Offer: {}", String(mime_type));
//if (WaylandDataOffer == nullptr)
// return;
wl_display_flush((wl_display*)SDL_GetPointerProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER, nullptr));
if (StringAnsi(mime_type) == "x.flaxengine.window.snap")
WaylandDataOfferMimeType = StringAnsi(mime_type);
// wl_data_offer_accept(WaylandDataOffer, WaylandDataOfferSerial, mime_type);
}
void WaylandDataOffer_SourceActions(void *data,
struct wl_data_offer *wl_data_offer,
uint32_t source_actions)
{
//
//LOG(Info, "WaylandDataOffer_SourceActions: {}", source_actions);
}
void WaylandDataOffer_Action(void *data,
struct wl_data_offer *wl_data_offer,
uint32_t dnd_action)
{
// DnD: This action will be performed if dropped
//LOG(Info, "WaylandDataOffer_Action: {}", dnd_action);
}
wl_data_offer* WaylandDataSelectionOffer = nullptr;
wl_data_offer_listener WaylandDataOfferListener = { WaylandDataOffer_Offer, WaylandDataOffer_SourceActions, WaylandDataOffer_Action};
void WaylandDataDevice_DataOffer(void *data, wl_data_device *wl_data_device, wl_data_offer *id)
{
//LOG(Info, "WaylandDataDevice_DataOffer: {}", (uint64)id);
int ret = wl_data_offer_add_listener(id, &WaylandDataOfferListener, nullptr);
if (ret != 0)
LOG(Error, "wl_data_offer_add_listener failed");
}
void WaylandDataDevice_Enter(void *data, wl_data_device *wl_data_device, uint32 serial, wl_surface *surface, wl_fixed_t x, wl_fixed_t y, wl_data_offer *id)
{
// DnD: The cursor entered a target surface
LOG(Info, "WaylandDataDevice_Enter serial: {}, surface: {}, pos: {}x{}, id: {}", serial, (uint64)surface, wl_fixed_to_double(x), wl_fixed_to_double(y), (uint64)id);
WaylandDataOffer = id;
WaylandDataOfferSerial = serial;
DragTargetPosition = Float2(MAX_float, MAX_float);
SDLWindow* sourceWindow = (SDLWindow*)data;
if (!SurfaceToWindowMap.TryGet(surface, DragTargetWindow))
DragTargetWindow = nullptr;
if (DragTargetWindow != nullptr)
DragTargetWindow = DragTargetWindow;
if (/*SurfaceToWindowMap.TryGet(surface, DragTargetWindow) && */DragTargetWindow != sourceWindow)
{
// Inform that we support the following action at this given point
wl_data_offer_set_actions(id, WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE, WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE);
if (WaylandDataOfferMimeType == "x.flaxengine.window.snap")
wl_data_offer_accept(WaylandDataOffer, WaylandDataOfferSerial, "x.flaxengine.window.snap");
}
else
{
wl_data_offer_set_actions(id, WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE, WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE);
}
}
void WaylandDataDevice_Leave(void *data, wl_data_device *wl_data_device)
{
// DnD: The cursor left the surface area
// id from enter must be destroyed here
LOG(Info, "WaylandDataDevice_Leave");
if (WaylandDataOffer != nullptr)
wl_data_offer_destroy(WaylandDataOffer);
WaylandDataOffer = nullptr;
WaylandDataOfferSerial = 0;
WaylandDataOfferMimeType = StringAnsi::Empty;
}
void WaylandDataDevice_Motion(void *data, wl_data_device *wl_data_device, uint32_t time, wl_fixed_t x, wl_fixed_t y)
{
// DnD: The cursor moves along the surface
Float2 dragPosition(wl_fixed_to_double(x), wl_fixed_to_double(y));
//LOG(Info, "WaylandDataDevice_Motion {},{}", (int)dragPosition.X, (int)dragPosition.Y);
if (DragTargetWindow != nullptr)
{
Float2 mousePos = dragPosition * DragTargetWindow->GetDpiScale();
mousePos = Float2::Floor(mousePos);
if (DragTargetPosition != mousePos)
{
//LOG(Info, "{}: {}", time, mousePos);
Input::Mouse->OnMouseMove(mousePos, DragTargetWindow);
DragTargetPosition = mousePos;
}
}
//SDLWindow* targetWindow;
//if (SurfaceToWindowMap.TryGet(surface, targetWindow) && targetWindow == surfaceWindow)
}
void WaylandDataDevice_Drop(void *data, wl_data_device *wl_data_device)
{
// DnD: The drop is accepted
LOG(Info, "WaylandDataDevice_Drop");
/*int fds[2];
pipe(fds);
wl_data_offer_receive(offer, "text/plain", fds[1]);
close(fds[1]);
// TODO: do something with fds[0]
close(fds[0]);*/
wl_data_offer_finish(WaylandDataOffer);
wl_data_offer_destroy(WaylandDataOffer);
WaylandDataOffer = nullptr;
}
void WaylandDataDevice_Selection(void *data, wl_data_device *wl_data_device, wl_data_offer *id)
{
// Clipboard: We can read the clipboard content
/*
int fds[2];
pipe(fds);
wl_data_offer_receive(offer, "text/plain", fds[1]);
close(fds[1]);
wl_display_roundtrip(display);
while (true)
{
char buf[1024];
ssize_t n = read(fds[0], buf, sizeof(buf));
if (n <= 0)
break;
//fwrite(buf, 1, n, stdout);
}
close(fds[0]);
wl_data_offer_destroy(offer);
*/
LOG(Info, "WaylandDataDevice_Selection: {}", (uint64)id);
if (WaylandDataSelectionOffer != nullptr)
wl_data_offer_destroy(WaylandDataSelectionOffer);
WaylandDataSelectionOffer = id;
}
wl_data_device_listener WaylandDataDeviceListener =
{
WaylandDataDevice_DataOffer,
WaylandDataDevice_Enter,
WaylandDataDevice_Leave,
WaylandDataDevice_Motion,
WaylandDataDevice_Drop,
WaylandDataDevice_Selection
};
xdg_toplevel_drag_v1* toplevelDrag = nullptr;
void WaylandDataSource_Target(void *data,
struct wl_data_source *wl_data_source,
const char *mime_type)
{
// The destination accepts the following types, or null if nothing
SDLWindow* window = static_cast<SDLWindow*>(data);
//LOG(Info, "WaylandDataSource_Target mime: {}", String(mime_type));
}
LOG(Info, "OnBeforeSurfaceCommit");
void WaylandDataSource_Send(void *data,
struct wl_data_source *wl_data_source,
const char *mime_type,
int32_t fd)
{
// Clipboard: The other end has accepted the data?
SDLWindow* window = static_cast<SDLWindow*>(data);
//LOG(Info, "WaylandDataSource_Send mime: {}", String(mime_type));
auto _window = window->GetSDLWindow();
SDL_SetPointerProperty(SDL_GetWindowProperties(_window), "SDL.window.wayland.callback", nullptr);
SDL_SetPointerProperty(SDL_GetWindowProperties(_window), "SDL.window.wayland.callback.data", nullptr);
// write stuff to the file descriptor
//write(fd, text, strlen(text));
//close(fd);
}
xdg_toplevel* toplevel = (xdg_toplevel*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, nullptr);
toplevelDrag = xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag(DragManager, dataSource);
void WaylandDataSource_Cancelled(void* data, wl_data_source *source)
{
// Clipboard: other application has replaced the content in clipboard
SDLWindow* window = static_cast<SDLWindow*>(data);
LOG(Info, "WaylandDataSource_Cancelled");
//wl_data_source_destroy(source);
wl_surface* origin = (wl_surface*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr);
wl_surface* icon = nullptr;
uint32 id = LastPointerSerial;
wl_data_device_start_drag(dataDevice, dataSource, origin, icon, id);
/*if (DragTargetWindow != nullptr)
{
Input::Mouse->OnMouseUp(DragTargetPosition, MouseButton::Left, DragTargetWindow);
}
else*/ if (window != nullptr)
{
Input::Mouse->OnMouseUp(DragTargetPosition, MouseButton::Left, window);
}
}
Float2 offset = Float2::Zero;
Float2 scaledOffset = offset / window->GetDpiScale();
xdg_toplevel_drag_v1_attach(toplevelDrag, toplevel, (int32)scaledOffset.X, (int32)scaledOffset.Y);
void WaylandDataSource_DnDDropPerformed(void *data,
struct wl_data_source *wl_data_source)
{
// The destination is being asked to begin DnD, asking confirmation with ASK actionh
SDLWindow* window = static_cast<SDLWindow*>(data);
LOG(Info, "WaylandDataSource_DnDDropPerformed");
}
void WaylandDataSource_DnDFinished(void *data,
struct wl_data_source *wl_data_source)
{
// The destination has finally accepted the last given dnd_action
SDLWindow* window = static_cast<SDLWindow*>(data);
LOG(Info, "WaylandDataSource_DnDFinished");
/*if (DragTargetWindow != nullptr)
{
Input::Mouse->OnMouseUp(DragTargetPosition, MouseButton::Left, DragTargetWindow);
}
else*/ if (window != nullptr)
{
Input::Mouse->OnMouseUp(DragTargetPosition, MouseButton::Left, window);
}
}
void WaylandDataSource_Action(void *data,
struct wl_data_source *wl_data_source,
uint32_t dnd_action)
{
// DnD: The destination may accept the given action if confirmed
SDLWindow* window = static_cast<SDLWindow*>(data);
//LOG(Info, "WaylandDataSource_Action: {}", String(dnd_action == 0 ? "NONE" : dnd_action == 1 ? "COPY" : dnd_action == 2 ? "MOVE" : dnd_action == 4 ? "ASK" : ""));
}
wl_data_source_listener WaylandDataSourceListener =
{
WaylandDataSource_Target,
WaylandDataSource_Send,
WaylandDataSource_Cancelled,
WaylandDataSource_DnDDropPerformed,
WaylandDataSource_DnDFinished,
WaylandDataSource_Action
};
extern wl_data_device* dataDevice;
wl_data_source* dataSource;
wl_display_flush((wl_display*)SDL_GetPointerProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER, nullptr));
}*/
void SDLWindow::StartDragging(const Float2& offset)
{
LOG(Info, "StartDragging {}", offset);
DoDragDropWayland(String("awindow"));
/*
_dragOver = true;
//wl_display_flush((wl_display*)GetWaylandDisplay());
SDL_PumpEvents();
wl_data_device_set_user_data(dataDevice, this);
// We offer the following types of things for consumption:
@@ -1481,27 +1315,31 @@ void SDLWindow::StartDragging(const Float2& offset)
wl_data_source_set_actions(dataSource, wl_data_device_manager_dnd_action::WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | wl_data_device_manager_dnd_action::WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
wl_data_source_add_listener(dataSource, &WaylandDataSourceListener, this);
toplevelDrag = xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag(DragManager, dataSource);
wl_surface* origin = (wl_surface*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr);
wl_surface* icon = nullptr;
uint32 id = LastPointerSerial;
wl_data_device_start_drag(dataDevice, dataSource, origin, icon, id);
xdg_toplevel* toplevel = (xdg_toplevel*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, nullptr);
/*if (toplevel == nullptr)
if (toplevel == nullptr)
{
auto asdf = xdg_wm_base_get_xdg_surface(WaylandXdgWmBase, origin);
toplevel = xdg_surface_get_toplevel(asdf);
}*/
Float2 scaledOffset = offset / _dpiScale;
xdg_toplevel_drag_v1_attach(toplevelDrag, toplevel, (int32)scaledOffset.X, (int32)scaledOffset.Y);
SDL_SetPointerProperty(SDL_GetWindowProperties(_window), "SDL.window.wayland.callback", (void*)OnBeforeSurfaceCommit);
SDL_SetPointerProperty(SDL_GetWindowProperties(_window), "SDL.window.wayland.callback.data", this);
}
else
{
toplevelDrag = xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag(DragManager, dataSource);
wl_surface* origin = (wl_surface*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr);
wl_surface* icon = nullptr;
uint32 id = LastPointerSerial;
wl_data_device_start_drag(dataDevice, dataSource, origin, icon, id);
Float2 scaledOffset = offset / _dpiScale;
xdg_toplevel_drag_v1_attach(toplevelDrag, toplevel, (int32)scaledOffset.X, (int32)scaledOffset.Y);
}
*/
}
void SDLWindow::StopDragging()
{
LOG(Info, "StopDragging");
/*
wl_data_device_set_user_data(dataDevice, nullptr);
_dragOver = false;
@@ -1516,22 +1354,8 @@ void SDLWindow::StopDragging()
wl_data_source_destroy(dataSource);
dataSource = nullptr;
}
*/
}
void SDLWindow::CreateDockHints()
{
LOG(Info, "CreateDockHints");
}
void SDLWindow::RemoveDockHints()
{
LOG(Info, "RemoveDockHints");
}
#endif

View File

@@ -110,8 +110,6 @@ public:
void SetCursor(CursorType type) override;
void StartDragging(const Float2& offset) override;
void StopDragging() override;
void CreateDockHints() override;
void RemoveDockHints() override;
#if USE_EDITOR && PLATFORM_WINDOWS
// [IUnknown]

View File

@@ -88,8 +88,8 @@ namespace Flax.Deps.Dependencies
Path.Combine(root, "include", "SDL3"),
};
CloneGitRepoFastSince(root, "https://github.com/libsdl-org/SDL", new DateTime(2025, 01, 06));
GitResetToCommit(root, "8ec576ddabdc7edfd68e7a8a3214e84e4026328d");
//CloneGitRepoFastSince(root, "https://github.com/libsdl-org/SDL", new DateTime(2025, 01, 06));
//GitResetToCommit(root, "8ec576ddabdc7edfd68e7a8a3214e84e4026328d");
foreach (var platform in options.Platforms)
{
@@ -135,7 +135,7 @@ namespace Flax.Deps.Dependencies
directoriesToCopy.Add(Path.Combine(buildDir, "include", "SDL3"));
int concurrency = Math.Min(Math.Max(1, (int)(Environment.ProcessorCount * Configuration.ConcurrencyProcessorScale)), Configuration.MaxConcurrency);
RunCmake(root, platform, architecture, $"-B\"{buildDir}\" -DCMAKE_INSTALL_PREFIX=\"{buildDir}\" -DSDL_SHARED={(!buildStatic ? "ON" : "OFF")} -DSDL_STATIC={(buildStatic ? "ON" : "OFF")} -DCMAKE_POSITION_INDEPENDENT_CODE=ON " + string.Join(" ", configs));
RunCmake(root, platform, architecture, $"-B\"{buildDir}\" -DCMAKE_BUILD_TYPE={configuration} -DCMAKE_INSTALL_PREFIX=\"{buildDir}\" -DSDL_SHARED={(!buildStatic ? "ON" : "OFF")} -DSDL_STATIC={(buildStatic ? "ON" : "OFF")} -DCMAKE_POSITION_INDEPENDENT_CODE=ON " + string.Join(" ", configs));
BuildCmake(buildDir, configuration, new Dictionary<string, string>() { {"CMAKE_BUILD_PARALLEL_LEVEL", concurrency.ToString()} });
Utilities.Run("cmake", $"--build . --target install --config {configuration}", null, buildDir, Utilities.RunOptions.DefaultTool);