_wayland toplevel drag WIP

This commit is contained in:
2025-01-07 17:57:32 +02:00
parent 4204e7f571
commit 75c44122c6
15 changed files with 4771 additions and 62 deletions

View File

@@ -21,21 +21,22 @@ namespace FlaxEditor.GUI.Docking
private DockState _toSet;
private DockPanel _toDock;
private bool _lateDragOffsetUpdate;
private float _lateDragStartTimer;
private Rectangle _rLeft, _rRight, _rBottom, _rUpper, _rCenter;
private DockHintWindow(FloatWindowDockPanel toMove)
private DockHintWindow(FloatWindowDockPanel toMove, bool lateDragStart)
{
_toMove = toMove;
_toSet = DockState.Float;
var window = toMove.Window.Window;
// Remove focus from drag target
_toMove.Focus();
_toMove.Defocus();
//_toMove.Focus();
//_toMove.Defocus();
// Focus window
window.Focus();
//window.Focus();
// Check if window is maximized and restore window.
if (window.IsMaximized)
@@ -48,43 +49,62 @@ namespace FlaxEditor.GUI.Docking
}
// Calculate dragging offset and move window to the destination position
var mouseScreenPosition = Platform.MousePosition;
var mouseClientPosition = Platform.MousePosition;
CalculateDragOffset(mouseClientPosition);
// If the _toMove window was not focused when initializing this window, the result vector only contains zeros
// and to prevent a failure, we need to perform an update for the drag offset at later time which will be done in the OnMouseMove event handler.
if (mouseScreenPosition != Float2.Zero)
CalculateDragOffset(mouseScreenPosition);
else
_lateDragOffsetUpdate = true;
//if (mouseScreenPosition != Float2.Zero)
// CalculateDragOffset(mouseScreenPosition);
//else
// _lateDragOffsetUpdate = true;
// Get initial size
_defaultWindowSize = window.Size;
// Init proxy window
Proxy.Init(ref _defaultWindowSize);
/*Proxy.Init(ref _defaultWindowSize);
// Bind events
*/
//FlaxEngine.Input.MouseMove += OnMouseMove;
FlaxEngine.Scripting.Update += OnUpdate;
_toMove.Window.Window.MouseUp += OnMouseUp;
/*
Proxy.Window.MouseUp += OnMouseUp;
Proxy.Window.MouseMove += OnMouseMove;
Proxy.Window.LostFocus += OnLostFocus;
_toMove.Window.Window.MouseUp += OnMouseUp; // Intercept the drag release mouse event from source window
*/
// Update window GUI
Proxy.Window.GUI.PerformLayout();
//Proxy.Window.GUI.PerformLayout();
// Update rectangles
UpdateRects();
// Enable hit window presentation
Proxy.Window.RenderingEnabled = true;
/*Proxy.Window.RenderingEnabled = true;
Proxy.Window.Show();
Proxy.Window.Focus();
Proxy.Window.Focus();*/
// Hide base window
window.Hide();
//window.Hide();
if (lateDragStart)
{
// The window needs some time to be fully ready for dragging
//_lateDragStartTimer = 1.5f;
window.StartDragging(_dragOffset);
}
else
window.StartDragging(_dragOffset);
// Start tracking mouse
Proxy.Window.StartTrackingMouse(false);
//Proxy.Window.StartTrackingMouse(false);
}
/// <summary>
@@ -93,7 +113,7 @@ namespace FlaxEditor.GUI.Docking
public void Dispose()
{
// End tracking mouse
Proxy.Window.EndTrackingMouse();
/*Proxy.Window.EndTrackingMouse();
// Disable rendering
Proxy.Window.RenderingEnabled = false;
@@ -106,11 +126,20 @@ namespace FlaxEditor.GUI.Docking
_toMove.Window.Window.MouseUp -= OnMouseUp;
// Hide the proxy
Proxy.Hide();
Proxy.Hide();*/
RemoveDockHints();
//FlaxEngine.Input.MouseMove -= OnMouseMove;
FlaxEngine.Scripting.Update -= OnUpdate;
if (_toMove?.Window?.Window)
_toMove.Window.Window.MouseUp -= OnMouseUp;
if (_toMove == null)
return;
_toMove.Window?.Window.StopDragging();
// Check if window won't be docked
if (_toSet == DockState.Float)
{
@@ -182,7 +211,7 @@ namespace FlaxEditor.GUI.Docking
if (toMove == null)
throw new ArgumentNullException();
return new DockHintWindow(toMove);
return new DockHintWindow(toMove, false);
}
/// <summary>
@@ -200,13 +229,13 @@ namespace FlaxEditor.GUI.Docking
// Move window to the mouse position (with some offset for caption bar)
var window = (WindowRootControl)toMove.Root;
var mouse = Platform.MousePosition;
window.Window.Position = mouse - new Float2(8, 8);
/*var mouse = Platform.MousePosition;
window.Window.Position = mouse - new Float2(8, 8);*/
// Get floating panel
var floatingPanelToMove = window.GetChild(0) as FloatWindowDockPanel;
return new DockHintWindow(floatingPanelToMove);
return new DockHintWindow(floatingPanelToMove, true);
}
/// <summary>
@@ -250,6 +279,47 @@ namespace FlaxEditor.GUI.Docking
Editor.Log($"_dragOffset: {_dragOffset}, mouse: {mouseScreenPosition}, basewinpos: {baseWinPos}");
}
DockHintControl _dockHintDown;
DockHintControl _dockHintUp;
DockHintControl _dockHintLeft;
DockHintControl _dockHintRight;
DockHintControl _dockHintCenter;
private void AddDockHints()
{
if (_toDock == null)
return;
_dockHintDown = AddHintControl(new Float2(0.5f, 1));
_dockHintUp = AddHintControl(new Float2(0.5f, 0));
_dockHintLeft = AddHintControl(new Float2(0, 0.5f));
_dockHintRight = AddHintControl(new Float2(1, 0.5f));
_dockHintCenter = AddHintControl(new Float2(0.5f, 0.5f));
DockHintControl AddHintControl(Float2 pivot)
{
DockHintControl hintControl = _toDock.AddChild<DockHintControl>();
hintControl.Size = new Float2(Proxy.HintWindowsSize);
hintControl.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
hintControl.Pivot = pivot;
hintControl.PivotRelative = true;
//.SetAnchorPreset(AnchorPresets.StretchAll, true);
return hintControl;
}
}
private void RemoveDockHints()
{
if (_toDock == null)
return;
_dockHintDown?.Parent.RemoveChild(_dockHintDown);
_dockHintUp?.Parent.RemoveChild(_dockHintUp);
_dockHintLeft?.Parent.RemoveChild(_dockHintLeft);
_dockHintRight?.Parent.RemoveChild(_dockHintRight);
_dockHintCenter?.Parent.RemoveChild(_dockHintCenter);
_dockHintDown = _dockHintUp = _dockHintLeft = _dockHintRight = _dockHintCenter = null;
}
private void UpdateRects()
{
// Cache mouse position
@@ -257,12 +327,26 @@ namespace FlaxEditor.GUI.Docking
// Check intersection with any dock panel
var uiMouse = _mouse;
_toDock = _toMove.MasterPanel.HitTest(ref uiMouse, _toMove);
var dockPanel = _toMove.MasterPanel.HitTest(ref uiMouse, _toMove);
if (dockPanel != _toDock)
{
//Editor.Log($"UpdateRects: {_mouse}, panel: {dockPanel?.RootWindow?.Window?.Title}");
_toDock?.RootWindow.Window.RemoveDockHints();
RemoveDockHints();
_toDock = dockPanel;
_toDock?.RootWindow.Window.CreateDockHints();
AddDockHints();
}
// Check dock state to use
bool showProxyHints = _toDock != null;
bool showBorderHints = showProxyHints;
bool showCenterHint = showProxyHints;
DockHintControl hoveredHintControl = null;
Float2 hoveredSizeOverride = Float2.Zero;
if (showProxyHints)
{
// If moved window has not only tabs but also child panels disable docking as tab
@@ -277,11 +361,12 @@ namespace FlaxEditor.GUI.Docking
_rectDock = _toDock.DockAreaBounds;
// Cache dock rectangles
var size = _rectDock.Size;
var offset = _rectDock.Location;
var size = _rectDock.Size / Platform.DpiScale;
var offset = _toDock.PointFromScreen(_rectDock.Location);
var borderMargin = 4.0f;
var hintWindowsSize = Proxy.HintWindowsSize * Platform.DpiScale;
var hintWindowsSize = Proxy.HintWindowsSize;
var hintWindowsSize2 = hintWindowsSize * 0.5f;
var hintPreviewSize = new Float2(Math.Max(Proxy.HintWindowsSize * 2, size.X * 0.5f), Math.Max(Proxy.HintWindowsSize * 2, size.Y * 0.5f));
var centerX = size.X * 0.5f;
var centerY = size.Y * 0.5f;
_rUpper = new Rectangle(centerX - hintWindowsSize2, borderMargin, hintWindowsSize, hintWindowsSize) + offset;
@@ -294,71 +379,150 @@ namespace FlaxEditor.GUI.Docking
DockState toSet = DockState.Float;
if (showBorderHints)
{
if (_rUpper.Contains(_mouse))
if (_rUpper.Contains(_toDock.PointFromScreen(_mouse)))
{
toSet = DockState.DockTop;
else if (_rBottom.Contains(_mouse))
hoveredHintControl = _dockHintUp;
hoveredSizeOverride = new Float2(size.X, hintPreviewSize.Y);
}
else if (_rBottom.Contains(_toDock.PointFromScreen(_mouse)))
{
toSet = DockState.DockBottom;
else if (_rLeft.Contains(_mouse))
hoveredHintControl = _dockHintDown;
hoveredSizeOverride = new Float2(size.X, hintPreviewSize.Y);
}
else if (_rLeft.Contains(_toDock.PointFromScreen(_mouse)))
{
toSet = DockState.DockLeft;
else if (_rRight.Contains(_mouse))
hoveredHintControl = _dockHintLeft;
hoveredSizeOverride = new Float2(hintPreviewSize.X, size.Y);
}
else if (_rRight.Contains(_toDock.PointFromScreen(_mouse)))
{
toSet = DockState.DockRight;
hoveredHintControl = _dockHintRight;
hoveredSizeOverride = new Float2(hintPreviewSize.X, size.Y);
}
}
if (showCenterHint && _rCenter.Contains(_mouse))
if (showCenterHint && _rCenter.Contains(_toDock.PointFromScreen(_mouse)))
{
toSet = DockState.DockFill;
_toSet = toSet;
hoveredHintControl = _dockHintCenter;
hoveredSizeOverride = new Float2(size.X, size.Y);
}
// Show proxy hint windows
Proxy.Down.Position = _rBottom.Location;
Proxy.Left.Position = _rLeft.Location;
Proxy.Right.Position = _rRight.Location;
Proxy.Up.Position = _rUpper.Location;
Proxy.Center.Position = _rCenter.Location;
if (toSet != DockState.Float)
Editor.Log($"docking: {toSet}");
_toSet = toSet;
}
else
{
_toSet = DockState.Float;
}
// Update proxy hint windows visibility
Proxy.Down.IsVisible = showProxyHints & showBorderHints;
Proxy.Left.IsVisible = showProxyHints & showBorderHints;
Proxy.Right.IsVisible = showProxyHints & showBorderHints;
Proxy.Up.IsVisible = showProxyHints & showBorderHints;
Proxy.Center.IsVisible = showProxyHints & showCenterHint;
// Calculate proxy/dock/window rectangles
if (_toDock == null)
{
// Floating window over nothing
_rectWindow = new Rectangle(_mouse - _dragOffset, _defaultWindowSize);
//_rectWindow = new Rectangle(_mouse - _dragOffset, _defaultWindowSize);
if (hoveredHintControl != null)
hoveredHintControl.BackgroundColor = Color.Green;
}
else
{
if (hoveredHintControl != _dockHintDown)
{
_dockHintDown.Size = new Float2(Proxy.HintWindowsSize);
_dockHintDown.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
}
if (hoveredHintControl != _dockHintLeft)
{
_dockHintLeft.Size = new Float2(Proxy.HintWindowsSize);
_dockHintLeft.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
}
if (hoveredHintControl != _dockHintRight)
{
_dockHintRight.Size = new Float2(Proxy.HintWindowsSize);
_dockHintRight.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
}
if (hoveredHintControl != _dockHintUp)
{
_dockHintUp.Size = new Float2(Proxy.HintWindowsSize);
_dockHintUp.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
}
if (hoveredHintControl != _dockHintCenter)
{
_dockHintCenter.Size = new Float2(Proxy.HintWindowsSize);
_dockHintCenter.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
}
if (_toSet == DockState.Float)
{
// Floating window over dock panel
_rectWindow = new Rectangle(_mouse - _dragOffset, _defaultWindowSize);
if (hoveredHintControl != null)
hoveredHintControl.BackgroundColor = Color.Red;
}
else
{
// Use only part of the dock panel to show hint
_rectWindow = CalculateDockRect(_toSet, ref _rectDock);
if (hoveredHintControl != null)
{
hoveredHintControl.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(1.0f);
hoveredHintControl.Size = hoveredSizeOverride;
}
}
}
if (showProxyHints)
{
if (hoveredHintControl != _dockHintDown)
_dockHintDown.Location = _rBottom.Location;
if (hoveredHintControl != _dockHintLeft)
_dockHintLeft.Location = _rLeft.Location;
if (hoveredHintControl != _dockHintRight)
_dockHintRight.Location = _rRight.Location;
if (hoveredHintControl != _dockHintUp)
_dockHintUp.Location = _rUpper.Location;
if (hoveredHintControl != _dockHintCenter)
_dockHintCenter.Location = _rCenter.Location;
// Update proxy hint windows visibility
_dockHintDown.Visible = showProxyHints & showBorderHints;
_dockHintLeft.Visible = showProxyHints & showBorderHints;
_dockHintRight.Visible = showProxyHints & showBorderHints;
_dockHintUp.Visible = showProxyHints & showBorderHints;
_dockHintCenter.Visible = showProxyHints & showCenterHint;
}
// Update proxy window
Proxy.Window.ClientBounds = _rectWindow;
//Proxy.Window.ClientBounds = _rectWindow;
}
private void OnMouseUp(ref Float2 location, MouseButton button, ref bool handled)
{
Editor.Log("DockHintWindow.OnMouseUp");
if (button == MouseButton.Left)
{
Dispose();
}
}
private void OnMouseMove(ref Float2 mousePos)
private void OnUpdate()
{
if (_lateDragStartTimer > 0)
{
_lateDragStartTimer -= Time.UnscaledDeltaTime;
if (_lateDragStartTimer <= 0)
_toMove.Window.Window.StartDragging(_dragOffset);
}
var mousePos = Platform.MousePosition;
if (_mouse != mousePos)
{
OnMouseMove(mousePos);
}
}
private void OnMouseMove(Float2 mousePos)
{
// Recalculate the drag offset because the current mouse screen position was invalid when we initialized the window
if (_lateDragOffsetUpdate)
@@ -377,6 +541,15 @@ namespace FlaxEditor.GUI.Docking
{
Dispose();
}
public class DockHintControl : Control
{
public DockHintControl()
{
AnchorPreset = AnchorPresets.StretchAll;
Offsets = Margin.Zero;
}
}
/// <summary>
/// Contains helper proxy windows shared across docking panels. They are used to visualize docking window locations.

View File

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

View File

@@ -51,8 +51,9 @@ namespace FlaxEditor.GUI.Docking
if (_window == null)
return;
_window.Window.StartDragging(Float2.Zero);
// Create docking hint window
DockHintWindow.Create(this);
//DockHintWindow.Create(this);
}
/// <summary>

View File

@@ -75,7 +75,7 @@ namespace FlaxEditor.GUI.Docking
/// <summary>
/// Performs hit test over dock panel.
/// </summary>
/// <param name="position">Screen space position to test.</param>
/// <param name="position">Window space position to test.</param>
/// <param name="excluded">Floating window to omit during searching (and all docked to that one).</param>
/// <returns>Dock panel that has been hit or null if nothing found.</returns>
public DockPanel HitTest(ref Float2 position, FloatWindowDockPanel excluded)
@@ -87,13 +87,39 @@ namespace FlaxEditor.GUI.Docking
var win = FloatingPanels[i];
if (win.Visible && win != excluded)
{
var result = win.HitTest(ref position);
if (result != null)
return result;
if (win.Window.Window.IsFocused) // We can't use screen space position in some platforms, only check windows under the cursor
{
var result = win.HitTest(ref position);
if (result != null)
{
Editor.Log($"hit: {win.Window.Window.Title}");
result = result;
}
else
Editor.Log($"no hit: {win.Window.Window.Title}");
}
else
Editor.Log($"no focus: {win.Window.Window.Title}");
}
}
for (int i = 0; i < FloatingPanels.Count; i++)
{
var win = FloatingPanels[i];
if (win.Visible && win != excluded)
{
if (win.Window.Window.IsFocused) // We can't use screen space position in some platforms, only check windows under the cursor
{
var result = win.HitTest(ref position);
if (result != null)
return result;
}
}
}
// Base
if (!Root?.RootWindow.Window.IsFocused ?? false)
return null;
return base.HitTest(ref position);
}

View File

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

View File

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

View File

@@ -65,6 +65,7 @@ public:
// [PlatformBase]
static bool Init();
static void Exit();
static void LogInfo();
static void Tick();
static void SetHighDpiAwarenessEnabled(bool enable);

View File

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

View File

@@ -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]

View File

@@ -33,5 +33,10 @@ public class Wayland : ThirdPartyModule
// Include generated protocol files for dependency
options.PublicIncludePaths.Add(Path.Combine(FolderPath, "include"));
options.SourceFiles.AddRange(Directory.GetFiles(FolderPath, "*.cpp", SearchOption.TopDirectoryOnly));
options.SourceFiles.AddRange(Directory.GetFiles(FolderPath, "*.c", SearchOption.TopDirectoryOnly));
// TODO: The glue code needs to be generated as C-code: https://gitlab.freedesktop.org/wayland/wayland/-/issues/90
//options.CompileEnv.CustomArgs.Add("-x c");
//options.LinkEnv.InputLibraries.Add("wayland-client");
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

184
Source/ThirdParty/Wayland/xdg-shell.c vendored Normal file
View File

@@ -0,0 +1,184 @@
/* Generated by wayland-scanner 1.23.1 */
/*
* Copyright © 2008-2013 Kristian Høgsberg
* Copyright © 2013 Rafael Antognolli
* Copyright © 2013 Jasper St. Pierre
* Copyright © 2010-2013 Intel Corporation
* Copyright © 2015-2017 Samsung Electronics Co., Ltd
* Copyright © 2015-2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
#ifndef __has_attribute
# define __has_attribute(x) 0 /* Compatibility with non-clang compilers. */
#endif
#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
#define WL_PRIVATE __attribute__ ((visibility("hidden")))
#else
#define WL_PRIVATE
#endif
extern const struct wl_interface wl_output_interface;
extern const struct wl_interface wl_seat_interface;
extern const struct wl_interface wl_surface_interface;
extern const struct wl_interface xdg_popup_interface;
extern const struct wl_interface xdg_positioner_interface;
extern const struct wl_interface xdg_surface_interface;
extern const struct wl_interface xdg_toplevel_interface;
static const struct wl_interface *xdg_shell_types[] = {
NULL,
NULL,
NULL,
NULL,
&xdg_positioner_interface,
&xdg_surface_interface,
&wl_surface_interface,
&xdg_toplevel_interface,
&xdg_popup_interface,
&xdg_surface_interface,
&xdg_positioner_interface,
&xdg_toplevel_interface,
&wl_seat_interface,
NULL,
NULL,
NULL,
&wl_seat_interface,
NULL,
&wl_seat_interface,
NULL,
NULL,
&wl_output_interface,
&wl_seat_interface,
NULL,
&xdg_positioner_interface,
NULL,
};
static const struct wl_message xdg_wm_base_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "create_positioner", "n", xdg_shell_types + 4 },
{ "get_xdg_surface", "no", xdg_shell_types + 5 },
{ "pong", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_wm_base_events[] = {
{ "ping", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_wm_base_interface = {
"xdg_wm_base", 6,
4, xdg_wm_base_requests,
1, xdg_wm_base_events,
};
static const struct wl_message xdg_positioner_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_size", "ii", xdg_shell_types + 0 },
{ "set_anchor_rect", "iiii", xdg_shell_types + 0 },
{ "set_anchor", "u", xdg_shell_types + 0 },
{ "set_gravity", "u", xdg_shell_types + 0 },
{ "set_constraint_adjustment", "u", xdg_shell_types + 0 },
{ "set_offset", "ii", xdg_shell_types + 0 },
{ "set_reactive", "3", xdg_shell_types + 0 },
{ "set_parent_size", "3ii", xdg_shell_types + 0 },
{ "set_parent_configure", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_positioner_interface = {
"xdg_positioner", 6,
10, xdg_positioner_requests,
0, NULL,
};
static const struct wl_message xdg_surface_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "get_toplevel", "n", xdg_shell_types + 7 },
{ "get_popup", "n?oo", xdg_shell_types + 8 },
{ "set_window_geometry", "iiii", xdg_shell_types + 0 },
{ "ack_configure", "u", xdg_shell_types + 0 },
};
static const struct wl_message xdg_surface_events[] = {
{ "configure", "u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_surface_interface = {
"xdg_surface", 6,
5, xdg_surface_requests,
1, xdg_surface_events,
};
static const struct wl_message xdg_toplevel_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "set_parent", "?o", xdg_shell_types + 11 },
{ "set_title", "s", xdg_shell_types + 0 },
{ "set_app_id", "s", xdg_shell_types + 0 },
{ "show_window_menu", "ouii", xdg_shell_types + 12 },
{ "move", "ou", xdg_shell_types + 16 },
{ "resize", "ouu", xdg_shell_types + 18 },
{ "set_max_size", "ii", xdg_shell_types + 0 },
{ "set_min_size", "ii", xdg_shell_types + 0 },
{ "set_maximized", "", xdg_shell_types + 0 },
{ "unset_maximized", "", xdg_shell_types + 0 },
{ "set_fullscreen", "?o", xdg_shell_types + 21 },
{ "unset_fullscreen", "", xdg_shell_types + 0 },
{ "set_minimized", "", xdg_shell_types + 0 },
};
static const struct wl_message xdg_toplevel_events[] = {
{ "configure", "iia", xdg_shell_types + 0 },
{ "close", "", xdg_shell_types + 0 },
{ "configure_bounds", "4ii", xdg_shell_types + 0 },
{ "wm_capabilities", "5a", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_toplevel_interface = {
"xdg_toplevel", 6,
14, xdg_toplevel_requests,
4, xdg_toplevel_events,
};
static const struct wl_message xdg_popup_requests[] = {
{ "destroy", "", xdg_shell_types + 0 },
{ "grab", "ou", xdg_shell_types + 22 },
{ "reposition", "3ou", xdg_shell_types + 24 },
};
static const struct wl_message xdg_popup_events[] = {
{ "configure", "iiii", xdg_shell_types + 0 },
{ "popup_done", "", xdg_shell_types + 0 },
{ "repositioned", "3u", xdg_shell_types + 0 },
};
WL_PRIVATE const struct wl_interface xdg_popup_interface = {
"xdg_popup", 6,
3, xdg_popup_requests,
3, xdg_popup_events,
};

View File

@@ -126,6 +126,7 @@ namespace Flax.Build.Platforms
args.Add("-lXcursor");
args.Add("-lXinerama");
args.Add("-lXfixes");
args.Add("-lwayland-client");
}
/// <inheritdoc />