_wayland toplevel drag WIP
This commit is contained in:
@@ -736,6 +736,36 @@ public:
|
||||
/// <returns>True during the frame the user releases the button</returns>
|
||||
API_FUNCTION() bool GetMouseButtonUp(MouseButton button) const;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Start dragging the window.
|
||||
/// </summary>
|
||||
/// <param name="offset">The position offset for drag from top-left corner.</param>
|
||||
API_FUNCTION() virtual void StartDragging(const Float2& offset)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ends dragging the window.
|
||||
/// </summary>
|
||||
API_FUNCTION() virtual void StopDragging()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create docking hint points for snapping the draggable window.
|
||||
/// </summary>
|
||||
API_FUNCTION() virtual void CreateDockHints()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove docking hint points.
|
||||
/// </summary>
|
||||
API_FUNCTION() virtual void RemoveDockHints()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
void OnShow();
|
||||
void OnResize(int32 width, int32 height);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include <wayland/xdg-shell.h>
|
||||
#include <wayland/xdg-shell.h>
|
||||
#if PLATFORM_SDL && PLATFORM_LINUX
|
||||
|
||||
#include "Engine/Platform/Platform.h"
|
||||
@@ -10,6 +12,7 @@
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Engine/CommandLine.h"
|
||||
#include "Engine/Platform/WindowsManager.h"
|
||||
#include "Engine/Platform/Linux/IncludeX11.h"
|
||||
@@ -18,16 +21,26 @@
|
||||
#include <SDL3/SDL_system.h>
|
||||
#include <SDL3/SDL_hints.h>
|
||||
|
||||
#include <wayland/xdg-toplevel-drag-v1.h>
|
||||
|
||||
// Wayland
|
||||
void WaylandRegistryGlobal(void* data, wl_registry *registry, uint32 id, const char* interface, uint32 version);
|
||||
void WaylandRegistryGlobalRemove(void* data, wl_registry *registry, uint32 id);
|
||||
|
||||
Dictionary<wl_surface*, SDLWindow*> SurfaceToWindowMap;
|
||||
uint32 LastPointerSerial = 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;
|
||||
|
||||
// X11
|
||||
Delegate<void*> LinuxPlatform::xEventReceived;
|
||||
|
||||
// Missing Wayland features:
|
||||
// - Application icon (xdg-toplevel-icon-v1) https://github.com/libsdl-org/SDL/pull/9584
|
||||
// - Window positioning and position tracking
|
||||
// - Color picker (xdg-desktop-portal?) https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Screenshot.html
|
||||
// -
|
||||
|
||||
@@ -844,11 +857,54 @@ 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 false
|
||||
if (!CommandLine::Options.Headless && strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0)
|
||||
{
|
||||
WaylandDisplay = (wl_display*)SDL_GetPointerProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER, nullptr);
|
||||
|
||||
wl_registry* registry = wl_display_get_registry(WaylandDisplay);
|
||||
wl_registry_add_listener(registry, &WaylandRegistryListener, nullptr);
|
||||
|
||||
wl_display_roundtrip(WaylandDisplay);
|
||||
}
|
||||
#else
|
||||
bool waylandRequested = !CommandLine::Options.X11 || CommandLine::Options.Wayland;
|
||||
if (!CommandLine::Options.Headless && waylandRequested)
|
||||
{
|
||||
// Ignore in X11 session
|
||||
String waylandDisplayEnv;
|
||||
if (!GetEnvironmentVariable(String("WAYLAND_DISPLAY"), waylandDisplayEnv))
|
||||
{
|
||||
WaylandDisplay = wl_display_connect(nullptr);
|
||||
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);
|
||||
|
||||
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);
|
||||
wl_data_device_add_listener(dataDevice, &WaylandDataDeviceListener, nullptr);
|
||||
|
||||
wl_display_roundtrip(WaylandDisplay);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -903,6 +959,10 @@ bool SDLPlatform::InitPlatformX11(void* display)
|
||||
return false;
|
||||
}
|
||||
|
||||
void SDLPlatform::Exit()
|
||||
{
|
||||
}
|
||||
|
||||
void* SDLPlatform::GetXDisplay()
|
||||
{
|
||||
return xDisplay;
|
||||
@@ -933,4 +993,161 @@ bool SDLPlatform::UsesX11()
|
||||
return xDisplay != nullptr;
|
||||
}
|
||||
|
||||
void WaylandPointer_Enter(void *data,
|
||||
struct wl_pointer *wl_pointer,
|
||||
uint32_t serial,
|
||||
struct wl_surface *surface,
|
||||
wl_fixed_t surface_x,
|
||||
wl_fixed_t surface_y)
|
||||
{
|
||||
/*SDLWindow* window;
|
||||
if (!SurfaceToWindowMap.TryGet(surface, window))
|
||||
return;
|
||||
|
||||
LastPointerWindow = window;
|
||||
LastPointerPosition = Int2(surface_x, surface_y);*/
|
||||
//LOG(Info, "WaylandPointerEnter serial:{}", serial);
|
||||
LastPointerSerial = serial;
|
||||
}
|
||||
|
||||
void WaylandPointer_Leave(void *data,
|
||||
struct wl_pointer *wl_pointer,
|
||||
uint32_t serial,
|
||||
struct wl_surface *surface)
|
||||
{
|
||||
//LastPointerWindow = nullptr;
|
||||
//LOG(Info, "WaylandPointerLeave serial:{}", serial);
|
||||
LastPointerSerial = serial;
|
||||
}
|
||||
|
||||
void WaylandPointer_Motion(void *data,
|
||||
struct wl_pointer *wl_pointer,
|
||||
uint32_t time,
|
||||
wl_fixed_t surface_x,
|
||||
wl_fixed_t surface_y)
|
||||
{
|
||||
//LOG(Info, "WaylandPointerMotion time:{}", time);
|
||||
//LastPointerPosition = Int2(surface_x, surface_y);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
void WaylandPointer_Axis(void *data,
|
||||
struct wl_pointer *wl_pointer,
|
||||
uint32_t time,
|
||||
uint32_t axis,
|
||||
wl_fixed_t value)
|
||||
{
|
||||
//LOG(Info, "WaylandPointerAxis time:{}", time);
|
||||
}
|
||||
|
||||
void WaylandPointer_Frame(void *data,
|
||||
struct wl_pointer *wl_pointer)
|
||||
{
|
||||
//LOG(Info, "WaylandPointerFrame");
|
||||
}
|
||||
|
||||
void WaylandPointer_AxisSource(void *data,
|
||||
struct wl_pointer *wl_pointer,
|
||||
uint32_t axis_source)
|
||||
{
|
||||
//LOG(Info, "WaylandPointerAxisSource");
|
||||
}
|
||||
|
||||
void WaylandPointer_AxisStop(void *data,
|
||||
struct wl_pointer *wl_pointer,
|
||||
uint32_t time,
|
||||
uint32_t axis)
|
||||
{
|
||||
//LOG(Info, "WaylandPointerAxisStop time:{}", time);
|
||||
}
|
||||
|
||||
void WaylandPointer_AxisDiscrete(void *data,
|
||||
struct wl_pointer *wl_pointer,
|
||||
uint32_t axis,
|
||||
int32_t discrete)
|
||||
{
|
||||
//LOG(Info, "WaylandPointerAxisDiscrete");
|
||||
}
|
||||
|
||||
void WaylandPointer_AxisValue120(void *data,
|
||||
struct wl_pointer *wl_pointer,
|
||||
uint32_t axis,
|
||||
int32_t value120)
|
||||
{
|
||||
//LOG(Info, "WaylandPointerAxisValue120");
|
||||
}
|
||||
|
||||
void WaylandPointer_AxisRelativeDirection(void *data,
|
||||
struct wl_pointer *wl_pointer,
|
||||
uint32_t axis,
|
||||
uint32_t direction)
|
||||
{
|
||||
//LOG(Info, "WaylandPointerAxisRelativeDirection");
|
||||
}
|
||||
|
||||
|
||||
wl_pointer_listener WaylandPointerListener =
|
||||
{
|
||||
WaylandPointer_Enter,
|
||||
WaylandPointer_Leave,
|
||||
WaylandPointer_Motion,
|
||||
WaylandPointer_Button,
|
||||
WaylandPointer_Axis,
|
||||
WaylandPointer_Frame,
|
||||
WaylandPointer_AxisSource,
|
||||
WaylandPointer_AxisStop,
|
||||
WaylandPointer_AxisDiscrete,
|
||||
WaylandPointer_AxisValue120,
|
||||
WaylandPointer_AxisRelativeDirection
|
||||
};
|
||||
|
||||
wl_pointer* WaylandPointer = nullptr;
|
||||
|
||||
void SeatCapabilities(void* data, wl_seat* seat, uint32 capabilities)
|
||||
{
|
||||
if ((capabilities & wl_seat_capability::WL_SEAT_CAPABILITY_POINTER) != 0)
|
||||
{
|
||||
WaylandPointer = wl_seat_get_pointer(seat);
|
||||
wl_pointer_add_listener(WaylandPointer, &WaylandPointerListener, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void SeatName(void* data, wl_seat* seat, const char* name)
|
||||
{
|
||||
}
|
||||
|
||||
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));
|
||||
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")
|
||||
{
|
||||
WaylandSeat = (wl_seat*)wl_registry_bind(registry, id, &wl_seat_interface, Math::Min(9U, version));
|
||||
wl_seat_add_listener(WaylandSeat, &SeatListener, nullptr);
|
||||
}
|
||||
else if (interfaceStr == "wl_data_device_manager")
|
||||
WaylandDataDeviceManager = (wl_data_device_manager*)wl_registry_bind(registry, id, &wl_data_device_manager_interface, Math::Min(3U, version));
|
||||
else if (interfaceStr == "xdg_wm_base")
|
||||
WaylandXdgWmBase = (xdg_wm_base*)wl_registry_bind(registry, id, &xdg_wm_base_interface, Math::Min(6U, version));
|
||||
|
||||
}
|
||||
|
||||
void WaylandRegistryGlobalRemove(void* data, wl_registry *registry, uint32 id)
|
||||
{
|
||||
LOG(Info, "WaylandRegistryGlobalRemove id:{}", id);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -65,6 +65,7 @@ public:
|
||||
|
||||
// [PlatformBase]
|
||||
static bool Init();
|
||||
static void Exit();
|
||||
static void LogInfo();
|
||||
static void Tick();
|
||||
static void SetHighDpiAwarenessEnabled(bool enable);
|
||||
|
||||
@@ -33,6 +33,18 @@
|
||||
#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 Dictionary<wl_surface*, SDLWindow*> SurfaceToWindowMap;
|
||||
extern SDLWindow* LastPointerWindow;
|
||||
extern Int2 LastPointerPosition;
|
||||
extern uint32 LastPointerSerial;
|
||||
extern xdg_toplevel_drag_manager_v1* DragManager;
|
||||
extern wl_seat* WaylandSeat;
|
||||
extern wl_data_device_manager* WaylandDataDeviceManager;
|
||||
extern xdg_wm_base* WaylandXdgWmBase;
|
||||
#endif
|
||||
|
||||
#define DefaultDPI 96
|
||||
@@ -185,6 +197,9 @@ SDLWindow::SDLWindow(const CreateWindowSettings& settings)
|
||||
// Input focus is not set initially for Wayland windows, assume the window is focused until a focus event is received
|
||||
if (_settings.AllowInput && (SDL_GetWindowFlags(_window) & SDL_WINDOW_INPUT_FOCUS) != 0)
|
||||
_forcedFocus = (flags & SDL_WINDOW_INPUT_FOCUS) != 0;
|
||||
|
||||
auto surface = (wl_surface*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr);
|
||||
SurfaceToWindowMap.Add(surface, this);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -293,6 +308,7 @@ SDLWindow::~SDLWindow()
|
||||
if (_window == nullptr)
|
||||
return;
|
||||
|
||||
SurfaceToWindowMap.RemoveValue(this);
|
||||
SDL_StopTextInput(_window);
|
||||
SDL_DestroyWindow(_window);
|
||||
|
||||
@@ -679,6 +695,17 @@ void SDLWindow::HandleEvent(SDL_Event& event)
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
#if PLATFORM_LINUX
|
||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||
{
|
||||
if (SDLPlatform::UsesWayland() && _dragOver)
|
||||
{
|
||||
// We are dragging a window, keep the button held down
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -736,6 +763,9 @@ void SDLWindow::Hide()
|
||||
|
||||
SDL_HideWindow(_window);
|
||||
|
||||
if (SDLPlatform::UsesWayland() && _dragOver)
|
||||
StopDragging();
|
||||
|
||||
WindowBase::Hide();
|
||||
}
|
||||
|
||||
@@ -1190,5 +1220,331 @@ 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)
|
||||
{
|
||||
// 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* 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));
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
// write stuff to the file descriptor
|
||||
//write(fd, text, strlen(text));
|
||||
//close(fd);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/*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");
|
||||
|
||||
/*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;
|
||||
|
||||
void SDLWindow::StartDragging(const Float2& offset)
|
||||
{
|
||||
LOG(Info, "StartDragging {}", offset);
|
||||
|
||||
_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:
|
||||
dataSource = wl_data_device_manager_create_data_source(WaylandDataDeviceManager);
|
||||
wl_data_source_offer(dataSource, "x.flaxengine.window.snap");
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void SDLWindow::StopDragging()
|
||||
{
|
||||
LOG(Info, "StopDragging");
|
||||
|
||||
wl_data_device_set_user_data(dataDevice, nullptr);
|
||||
_dragOver = false;
|
||||
|
||||
if (toplevelDrag != nullptr)
|
||||
{
|
||||
xdg_toplevel_drag_v1_destroy(toplevelDrag);
|
||||
toplevelDrag = nullptr;
|
||||
}
|
||||
|
||||
if (dataSource != nullptr)
|
||||
{
|
||||
wl_data_source_destroy(dataSource);
|
||||
dataSource = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void SDLWindow::CreateDockHints()
|
||||
{
|
||||
LOG(Info, "CreateDockHints");
|
||||
|
||||
|
||||
}
|
||||
|
||||
void SDLWindow::RemoveDockHints()
|
||||
{
|
||||
LOG(Info, "RemoveDockHints");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -108,6 +108,10 @@ public:
|
||||
void StartClippingCursor(const Rectangle& bounds) override;
|
||||
void EndClippingCursor() override;
|
||||
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]
|
||||
|
||||
Reference in New Issue
Block a user