Implement new window dragging system
This commit is contained in:
@@ -1,535 +0,0 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using FlaxEngine;
|
|
||||||
using FlaxEngine.GUI;
|
|
||||||
|
|
||||||
namespace FlaxEditor.GUI.Docking
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Helper class used to handle docking windows dragging and docking.
|
|
||||||
/// </summary>
|
|
||||||
public class DockHintWindow
|
|
||||||
{
|
|
||||||
private FloatWindowDockPanel _toMove;
|
|
||||||
|
|
||||||
private Float2 _dragOffset;
|
|
||||||
private Float2 _defaultWindowSize;
|
|
||||||
private Rectangle _rectDock;
|
|
||||||
private Rectangle _rectWindow;
|
|
||||||
private Float2 _mouse;
|
|
||||||
private DockState _toSet;
|
|
||||||
private DockPanel _toDock;
|
|
||||||
private bool _lateDragOffsetUpdate;
|
|
||||||
|
|
||||||
private Rectangle _rLeft, _rRight, _rBottom, _rUpper, _rCenter;
|
|
||||||
|
|
||||||
private DockHintWindow(FloatWindowDockPanel toMove)
|
|
||||||
{
|
|
||||||
_toMove = toMove;
|
|
||||||
_toSet = DockState.Float;
|
|
||||||
var window = toMove.Window.Window;
|
|
||||||
|
|
||||||
// Remove focus from drag target
|
|
||||||
_toMove.Focus();
|
|
||||||
_toMove.Defocus();
|
|
||||||
|
|
||||||
// Focus window
|
|
||||||
window.Focus();
|
|
||||||
|
|
||||||
// Check if window is maximized and restore window.
|
|
||||||
if (window.IsMaximized)
|
|
||||||
{
|
|
||||||
// Restore window and set position to mouse.
|
|
||||||
var mousePos = window.MousePosition;
|
|
||||||
var previousSize = window.Size;
|
|
||||||
window.Restore();
|
|
||||||
window.Position = Platform.MousePosition - mousePos * window.Size / previousSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate dragging offset and move window to the destination position
|
|
||||||
var mouseScreenPosition = Platform.MousePosition;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// Get initial size
|
|
||||||
_defaultWindowSize = window.Size;
|
|
||||||
|
|
||||||
// Init proxy window
|
|
||||||
Proxy.Init(ref _defaultWindowSize);
|
|
||||||
|
|
||||||
// Bind events
|
|
||||||
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();
|
|
||||||
|
|
||||||
// Update rectangles
|
|
||||||
UpdateRects();
|
|
||||||
|
|
||||||
// Enable hit window presentation
|
|
||||||
Proxy.Window.RenderingEnabled = true;
|
|
||||||
Proxy.Window.Show();
|
|
||||||
Proxy.Window.Focus();
|
|
||||||
|
|
||||||
// Hide base window
|
|
||||||
window.Hide();
|
|
||||||
|
|
||||||
// Start tracking mouse
|
|
||||||
Proxy.Window.StartTrackingMouse(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases unmanaged and - optionally - managed resources.
|
|
||||||
/// </summary>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
// End tracking mouse
|
|
||||||
Proxy.Window.EndTrackingMouse();
|
|
||||||
|
|
||||||
// Disable rendering
|
|
||||||
Proxy.Window.RenderingEnabled = false;
|
|
||||||
|
|
||||||
// Unbind events
|
|
||||||
Proxy.Window.MouseUp -= OnMouseUp;
|
|
||||||
Proxy.Window.MouseMove -= OnMouseMove;
|
|
||||||
Proxy.Window.LostFocus -= OnLostFocus;
|
|
||||||
if (_toMove?.Window?.Window)
|
|
||||||
_toMove.Window.Window.MouseUp -= OnMouseUp;
|
|
||||||
|
|
||||||
// Hide the proxy
|
|
||||||
Proxy.Hide();
|
|
||||||
|
|
||||||
if (_toMove == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Check if window won't be docked
|
|
||||||
if (_toSet == DockState.Float)
|
|
||||||
{
|
|
||||||
var window = _toMove.Window?.Window;
|
|
||||||
if (window == null)
|
|
||||||
return;
|
|
||||||
var mouse = Platform.MousePosition;
|
|
||||||
|
|
||||||
// Move base window
|
|
||||||
window.Position = mouse - _dragOffset;
|
|
||||||
|
|
||||||
// Show base window
|
|
||||||
window.Show();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bool hasNoChildPanels = _toMove.ChildPanelsCount == 0;
|
|
||||||
|
|
||||||
// Check if window has only single tab
|
|
||||||
if (hasNoChildPanels && _toMove.TabsCount == 1)
|
|
||||||
{
|
|
||||||
// Dock window
|
|
||||||
_toMove.GetTab(0).Show(_toSet, _toDock);
|
|
||||||
}
|
|
||||||
// Check if dock as tab and has no child panels
|
|
||||||
else if (hasNoChildPanels && _toSet == DockState.DockFill)
|
|
||||||
{
|
|
||||||
// Dock all tabs
|
|
||||||
while (_toMove.TabsCount > 0)
|
|
||||||
{
|
|
||||||
_toMove.GetTab(0).Show(DockState.DockFill, _toDock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var selectedTab = _toMove.SelectedTab;
|
|
||||||
|
|
||||||
// Dock the first tab into the target location
|
|
||||||
if (_toMove.TabsCount > 0)
|
|
||||||
{
|
|
||||||
var firstTab = _toMove.GetTab(0);
|
|
||||||
firstTab.Show(_toSet, _toDock);
|
|
||||||
|
|
||||||
// Dock rest of the tabs
|
|
||||||
while (_toMove.TabsCount > 0)
|
|
||||||
{
|
|
||||||
_toMove.GetTab(0).Show(DockState.DockFill, firstTab);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep selected tab being selected
|
|
||||||
selectedTab?.SelectTab();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Focus target window
|
|
||||||
_toDock.Root.Focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
_toMove = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates the new dragging hit window.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="toMove">Floating dock panel to move.</param>
|
|
||||||
/// <returns>The dock hint window object.</returns>
|
|
||||||
public static DockHintWindow Create(FloatWindowDockPanel toMove)
|
|
||||||
{
|
|
||||||
if (toMove == null)
|
|
||||||
throw new ArgumentNullException();
|
|
||||||
|
|
||||||
return new DockHintWindow(toMove);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates the new dragging hit window.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="toMove">Dock window to move.</param>
|
|
||||||
/// <returns>The dock hint window object.</returns>
|
|
||||||
public static DockHintWindow Create(DockWindow toMove)
|
|
||||||
{
|
|
||||||
if (toMove == null)
|
|
||||||
throw new ArgumentNullException();
|
|
||||||
|
|
||||||
// Show floating
|
|
||||||
toMove.ShowFloating();
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Get floating panel
|
|
||||||
var floatingPanelToMove = window.GetChild(0) as FloatWindowDockPanel;
|
|
||||||
|
|
||||||
return new DockHintWindow(floatingPanelToMove);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Calculates window rectangle in the dock window.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="state">Window dock state.</param>
|
|
||||||
/// <param name="rect">Dock panel rectangle.</param>
|
|
||||||
/// <returns>Calculated window rectangle.</returns>
|
|
||||||
public static Rectangle CalculateDockRect(DockState state, ref Rectangle rect)
|
|
||||||
{
|
|
||||||
Rectangle result = rect;
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case DockState.DockFill:
|
|
||||||
result.Location.Y += DockPanel.DefaultHeaderHeight;
|
|
||||||
result.Size.Y -= DockPanel.DefaultHeaderHeight;
|
|
||||||
break;
|
|
||||||
case DockState.DockTop:
|
|
||||||
result.Size.Y *= DockPanel.DefaultSplitterValue;
|
|
||||||
break;
|
|
||||||
case DockState.DockLeft:
|
|
||||||
result.Size.X *= DockPanel.DefaultSplitterValue;
|
|
||||||
break;
|
|
||||||
case DockState.DockBottom:
|
|
||||||
result.Location.Y += result.Size.Y * (1 - DockPanel.DefaultSplitterValue);
|
|
||||||
result.Size.Y *= DockPanel.DefaultSplitterValue;
|
|
||||||
break;
|
|
||||||
case DockState.DockRight:
|
|
||||||
result.Location.X += result.Size.X * (1 - DockPanel.DefaultSplitterValue);
|
|
||||||
result.Size.X *= DockPanel.DefaultSplitterValue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CalculateDragOffset(Float2 mouseScreenPosition)
|
|
||||||
{
|
|
||||||
var baseWinPos = _toMove.Window.Window.Position;
|
|
||||||
_dragOffset = mouseScreenPosition - baseWinPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateRects()
|
|
||||||
{
|
|
||||||
// Cache mouse position
|
|
||||||
_mouse = Platform.MousePosition;
|
|
||||||
|
|
||||||
// Check intersection with any dock panel
|
|
||||||
var uiMouse = _mouse;
|
|
||||||
_toDock = _toMove.MasterPanel.HitTest(ref uiMouse, _toMove);
|
|
||||||
|
|
||||||
// Check dock state to use
|
|
||||||
bool showProxyHints = _toDock != null;
|
|
||||||
bool showBorderHints = showProxyHints;
|
|
||||||
bool showCenterHint = showProxyHints;
|
|
||||||
if (showProxyHints)
|
|
||||||
{
|
|
||||||
// If moved window has not only tabs but also child panels disable docking as tab
|
|
||||||
if (_toMove.ChildPanelsCount > 0)
|
|
||||||
showCenterHint = false;
|
|
||||||
|
|
||||||
// Disable docking windows with one or more dock panels inside
|
|
||||||
if (_toMove.ChildPanelsCount > 0)
|
|
||||||
showBorderHints = false;
|
|
||||||
|
|
||||||
// Get dock area
|
|
||||||
_rectDock = _toDock.DockAreaBounds;
|
|
||||||
|
|
||||||
// Cache dock rectangles
|
|
||||||
var size = _rectDock.Size;
|
|
||||||
var offset = _rectDock.Location;
|
|
||||||
var borderMargin = 4.0f;
|
|
||||||
var hintWindowsSize = Proxy.HintWindowsSize * Platform.DpiScale;
|
|
||||||
var hintWindowsSize2 = hintWindowsSize * 0.5f;
|
|
||||||
var centerX = size.X * 0.5f;
|
|
||||||
var centerY = size.Y * 0.5f;
|
|
||||||
_rUpper = new Rectangle(centerX - hintWindowsSize2, borderMargin, hintWindowsSize, hintWindowsSize) + offset;
|
|
||||||
_rBottom = new Rectangle(centerX - hintWindowsSize2, size.Y - hintWindowsSize - borderMargin, hintWindowsSize, hintWindowsSize) + offset;
|
|
||||||
_rLeft = new Rectangle(borderMargin, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
|
||||||
_rRight = new Rectangle(size.X - hintWindowsSize - borderMargin, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
|
||||||
_rCenter = new Rectangle(centerX - hintWindowsSize2, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
|
||||||
|
|
||||||
// Hit test
|
|
||||||
DockState toSet = DockState.Float;
|
|
||||||
if (showBorderHints)
|
|
||||||
{
|
|
||||||
if (_rUpper.Contains(_mouse))
|
|
||||||
toSet = DockState.DockTop;
|
|
||||||
else if (_rBottom.Contains(_mouse))
|
|
||||||
toSet = DockState.DockBottom;
|
|
||||||
else if (_rLeft.Contains(_mouse))
|
|
||||||
toSet = DockState.DockLeft;
|
|
||||||
else if (_rRight.Contains(_mouse))
|
|
||||||
toSet = DockState.DockRight;
|
|
||||||
}
|
|
||||||
if (showCenterHint && _rCenter.Contains(_mouse))
|
|
||||||
toSet = DockState.DockFill;
|
|
||||||
_toSet = toSet;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (_toSet == DockState.Float)
|
|
||||||
{
|
|
||||||
// Floating window over dock panel
|
|
||||||
_rectWindow = new Rectangle(_mouse - _dragOffset, _defaultWindowSize);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Use only part of the dock panel to show hint
|
|
||||||
_rectWindow = CalculateDockRect(_toSet, ref _rectDock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update proxy window
|
|
||||||
Proxy.Window.ClientBounds = _rectWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMouseUp(ref Float2 location, MouseButton button, ref bool handled)
|
|
||||||
{
|
|
||||||
if (button == MouseButton.Left)
|
|
||||||
{
|
|
||||||
Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMouseMove(ref Float2 mousePos)
|
|
||||||
{
|
|
||||||
// Recalculate the drag offset because the current mouse screen position was invalid when we initialized the window
|
|
||||||
if (_lateDragOffsetUpdate)
|
|
||||||
{
|
|
||||||
// Calculate dragging offset and move window to the destination position
|
|
||||||
CalculateDragOffset(mousePos);
|
|
||||||
|
|
||||||
// Reset state
|
|
||||||
_lateDragOffsetUpdate = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateRects();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnLostFocus()
|
|
||||||
{
|
|
||||||
Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains helper proxy windows shared across docking panels. They are used to visualize docking window locations.
|
|
||||||
/// </summary>
|
|
||||||
public static class Proxy
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The drag proxy window.
|
|
||||||
/// </summary>
|
|
||||||
public static Window Window;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The left hint proxy window.
|
|
||||||
/// </summary>
|
|
||||||
public static Window Left;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The right hint proxy window.
|
|
||||||
/// </summary>
|
|
||||||
public static Window Right;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The up hint proxy window.
|
|
||||||
/// </summary>
|
|
||||||
public static Window Up;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The down hint proxy window.
|
|
||||||
/// </summary>
|
|
||||||
public static Window Down;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The center hint proxy window.
|
|
||||||
/// </summary>
|
|
||||||
public static Window Center;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The hint windows size.
|
|
||||||
/// </summary>
|
|
||||||
public const float HintWindowsSize = 32.0f;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the hit proxy windows. Those windows are used to indicate drag target areas (left, right, top, bottom, etc.).
|
|
||||||
/// </summary>
|
|
||||||
public static void InitHitProxy()
|
|
||||||
{
|
|
||||||
CreateProxy(ref Left, "DockHint.Left");
|
|
||||||
CreateProxy(ref Right, "DockHint.Right");
|
|
||||||
CreateProxy(ref Up, "DockHint.Up");
|
|
||||||
CreateProxy(ref Down, "DockHint.Down");
|
|
||||||
CreateProxy(ref Center, "DockHint.Center");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes the hint window.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="initSize">Initial size of the proxy window.</param>
|
|
||||||
public static void Init(ref Float2 initSize)
|
|
||||||
{
|
|
||||||
if (Window == null)
|
|
||||||
{
|
|
||||||
var settings = CreateWindowSettings.Default;
|
|
||||||
settings.Title = "DockHint.Window";
|
|
||||||
settings.Size = initSize;
|
|
||||||
settings.AllowInput = true;
|
|
||||||
settings.AllowMaximize = false;
|
|
||||||
settings.AllowMinimize = false;
|
|
||||||
settings.HasBorder = false;
|
|
||||||
settings.HasSizingFrame = false;
|
|
||||||
settings.Type = WindowType.Utility;
|
|
||||||
settings.SupportsTransparency = true;
|
|
||||||
settings.ShowInTaskbar = false;
|
|
||||||
settings.ShowAfterFirstPaint = false;
|
|
||||||
settings.IsTopmost = true;
|
|
||||||
|
|
||||||
Window = Platform.CreateWindow(ref settings);
|
|
||||||
Window.Opacity = 0.6f;
|
|
||||||
Window.GUI.BackgroundColor = Style.Current.DragWindow;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Resize proxy
|
|
||||||
Window.ClientSize = initSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
InitHitProxy();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void CreateProxy(ref Window win, string name)
|
|
||||||
{
|
|
||||||
if (win != null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var settings = CreateWindowSettings.Default;
|
|
||||||
settings.Title = name;
|
|
||||||
settings.Size = new Float2(HintWindowsSize * Platform.DpiScale);
|
|
||||||
settings.AllowInput = false;
|
|
||||||
settings.AllowMaximize = false;
|
|
||||||
settings.AllowMinimize = false;
|
|
||||||
settings.HasBorder = false;
|
|
||||||
settings.HasSizingFrame = false;
|
|
||||||
settings.Type = WindowType.Utility;
|
|
||||||
settings.SupportsTransparency = true;
|
|
||||||
settings.ShowInTaskbar = false;
|
|
||||||
settings.ActivateWhenFirstShown = false;
|
|
||||||
settings.IsTopmost = true;
|
|
||||||
settings.ShowAfterFirstPaint = false;
|
|
||||||
|
|
||||||
win = Platform.CreateWindow(ref settings);
|
|
||||||
win.Opacity = 0.6f;
|
|
||||||
win.GUI.BackgroundColor = Style.Current.DragWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hides proxy windows.
|
|
||||||
/// </summary>
|
|
||||||
public static void Hide()
|
|
||||||
{
|
|
||||||
HideProxy(ref Window);
|
|
||||||
HideProxy(ref Left);
|
|
||||||
HideProxy(ref Right);
|
|
||||||
HideProxy(ref Up);
|
|
||||||
HideProxy(ref Down);
|
|
||||||
HideProxy(ref Center);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void HideProxy(ref Window win)
|
|
||||||
{
|
|
||||||
if (win)
|
|
||||||
{
|
|
||||||
win.Hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases proxy data and windows.
|
|
||||||
/// </summary>
|
|
||||||
public static void Dispose()
|
|
||||||
{
|
|
||||||
DisposeProxy(ref Window);
|
|
||||||
DisposeProxy(ref Left);
|
|
||||||
DisposeProxy(ref Right);
|
|
||||||
DisposeProxy(ref Up);
|
|
||||||
DisposeProxy(ref Down);
|
|
||||||
DisposeProxy(ref Center);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void DisposeProxy(ref Window win)
|
|
||||||
{
|
|
||||||
if (win)
|
|
||||||
{
|
|
||||||
win.Close(ClosingReason.User);
|
|
||||||
win = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -170,7 +170,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
if (_panel.ChildPanelsCount == 0 && _panel.TabsCount == 1 && _panel.IsFloating)
|
if (_panel.ChildPanelsCount == 0 && _panel.TabsCount == 1 && _panel.IsFloating)
|
||||||
{
|
{
|
||||||
// Create docking hint window but in an async manner
|
// Create docking hint window but in an async manner
|
||||||
DockHintWindow.Create(_panel as FloatWindowDockPanel);
|
WindowDragHelper.StartDragging(_panel as FloatWindowDockPanel);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -181,7 +181,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
_panel.SelectTab(index - 1);
|
_panel.SelectTab(index - 1);
|
||||||
|
|
||||||
// Create docking hint window
|
// Create docking hint window
|
||||||
DockHintWindow.Create(win);
|
WindowDragHelper.StartDragging(win, _panel.RootWindow.Window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,6 +182,25 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
/// <param name="size">Window size, set <see cref="Float2.Zero"/> to use default.</param>
|
/// <param name="size">Window size, set <see cref="Float2.Zero"/> to use default.</param>
|
||||||
/// <param name="position">Window location.</param>
|
/// <param name="position">Window location.</param>
|
||||||
public void ShowFloating(Float2 location, Float2 size, WindowStartPosition position = WindowStartPosition.CenterParent)
|
public void ShowFloating(Float2 location, Float2 size, WindowStartPosition position = WindowStartPosition.CenterParent)
|
||||||
|
{
|
||||||
|
CreateFloating(location, size, position, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the window in a floating state.
|
||||||
|
/// </summary>
|
||||||
|
public void CreateFloating()
|
||||||
|
{
|
||||||
|
CreateFloating(Float2.Zero, Float2.Zero);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Creates the window in a floating state.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="location">Window location.</param>
|
||||||
|
/// <param name="size">Window size, set <see cref="Float2.Zero"/> to use default.</param>
|
||||||
|
/// <param name="position">Window location.</param>
|
||||||
|
/// <param name="showWindow">Window visibility.</param>
|
||||||
|
public void CreateFloating(Float2 location, Float2 size, WindowStartPosition position = WindowStartPosition.CenterParent, bool showWindow = false)
|
||||||
{
|
{
|
||||||
Undock();
|
Undock();
|
||||||
|
|
||||||
@@ -199,14 +218,17 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
windowGUI.UnlockChildrenRecursive();
|
windowGUI.UnlockChildrenRecursive();
|
||||||
windowGUI.PerformLayout();
|
windowGUI.PerformLayout();
|
||||||
|
|
||||||
// Show
|
if (showWindow)
|
||||||
window.Show();
|
{
|
||||||
window.BringToFront();
|
// Show
|
||||||
window.Focus();
|
window.Show();
|
||||||
OnShow();
|
window.BringToFront();
|
||||||
|
window.Focus();
|
||||||
|
OnShow();
|
||||||
|
|
||||||
// Perform layout again
|
// Perform layout again
|
||||||
windowGUI.PerformLayout();
|
windowGUI.PerformLayout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Create docking hint window
|
// Create docking hint window
|
||||||
DockHintWindow.Create(this);
|
WindowDragHelper.StartDragging(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -81,7 +81,6 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
public DockPanel HitTest(ref Float2 position, FloatWindowDockPanel excluded)
|
public DockPanel HitTest(ref Float2 position, FloatWindowDockPanel excluded)
|
||||||
{
|
{
|
||||||
// Check all floating windows
|
// Check all floating windows
|
||||||
// TODO: gather windows order and take it into account when performing test
|
|
||||||
for (int i = 0; i < FloatingPanels.Count; i++)
|
for (int i = 0; i < FloatingPanels.Count; i++)
|
||||||
{
|
{
|
||||||
var win = FloatingPanels[i];
|
var win = FloatingPanels[i];
|
||||||
@@ -94,9 +93,44 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Base
|
// Base
|
||||||
|
//if (!Root?.RootWindow.Window.IsFocused ?? false)
|
||||||
|
// return null;
|
||||||
return base.HitTest(ref position);
|
return base.HitTest(ref position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs hit test over dock panel.
|
||||||
|
/// </summary>
|
||||||
|
/// <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>
|
||||||
|
/// <param name="hitResults">Results of the hit test</param>
|
||||||
|
/// <returns>True if any dock panels were hit, otherwise false.</returns>
|
||||||
|
public bool HitTest(ref Float2 position, FloatWindowDockPanel excluded, out DockPanel[] hitResults)
|
||||||
|
{
|
||||||
|
// Check all floating windows
|
||||||
|
List<DockPanel> results = new(FloatingPanels.Count);
|
||||||
|
for (int i = 0; i < FloatingPanels.Count; i++)
|
||||||
|
{
|
||||||
|
var win = FloatingPanels[i];
|
||||||
|
if (win.Visible && win != excluded)
|
||||||
|
{
|
||||||
|
var result = win.HitTest(ref position);
|
||||||
|
if (result != null)
|
||||||
|
results.Add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Base
|
||||||
|
//if (!Root?.RootWindow.Window.IsFocused ?? false)
|
||||||
|
// return null;
|
||||||
|
var baseResult = base.HitTest(ref position);
|
||||||
|
if (baseResult != null)
|
||||||
|
results.Add(baseResult);
|
||||||
|
|
||||||
|
hitResults = results.ToArray();
|
||||||
|
return hitResults.Length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
internal void LinkWindow(DockWindow window)
|
internal void LinkWindow(DockWindow window)
|
||||||
{
|
{
|
||||||
// Add to the windows list
|
// Add to the windows list
|
||||||
|
|||||||
448
Source/Editor/GUI/Docking/WindowDragHelper.cs
Normal file
448
Source/Editor/GUI/Docking/WindowDragHelper.cs
Normal file
@@ -0,0 +1,448 @@
|
|||||||
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using FlaxEngine;
|
||||||
|
using FlaxEngine.GUI;
|
||||||
|
|
||||||
|
namespace FlaxEditor.GUI.Docking
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Helper class used to handle docking windows dragging and docking.
|
||||||
|
/// </summary>
|
||||||
|
public class WindowDragHelper
|
||||||
|
{
|
||||||
|
private FloatWindowDockPanel _toMove;
|
||||||
|
|
||||||
|
private Float2 _dragOffset;
|
||||||
|
private Rectangle _rectDock;
|
||||||
|
private Float2 _mouse;
|
||||||
|
private DockState _toSet;
|
||||||
|
private DockPanel _toDock;
|
||||||
|
private Window _dragSourceWindow;
|
||||||
|
|
||||||
|
private Rectangle _rLeft, _rRight, _rBottom, _rUpper, _rCenter;
|
||||||
|
private Control _dockHintDown, _dockHintUp, _dockHintLeft, _dockHintRight, _dockHintCenter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The hint control size.
|
||||||
|
/// </summary>
|
||||||
|
public const float HintControlSize = 32.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The opacity of the dragged window when hint controls are shown.
|
||||||
|
/// </summary>
|
||||||
|
public const float DragWindowOpacity = 0.4f;
|
||||||
|
|
||||||
|
private WindowDragHelper(FloatWindowDockPanel toMove, Window dragSourceWindow)
|
||||||
|
{
|
||||||
|
_toMove = toMove;
|
||||||
|
_toSet = DockState.Float;
|
||||||
|
var window = toMove.Window.Window;
|
||||||
|
|
||||||
|
// Check if window is maximized and restore window.
|
||||||
|
if (window.IsMaximized)
|
||||||
|
{
|
||||||
|
// Restore window and set position to mouse.
|
||||||
|
var mousePos = window.MousePosition;
|
||||||
|
var previousSize = window.Size;
|
||||||
|
window.Restore();
|
||||||
|
window.Position = Platform.MousePosition - mousePos * window.Size / previousSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind events
|
||||||
|
FlaxEngine.Scripting.Update += OnUpdate;
|
||||||
|
window.MouseUp += OnMouseUp;
|
||||||
|
|
||||||
|
// Update rectangles
|
||||||
|
UpdateRects(Platform.MousePosition);
|
||||||
|
|
||||||
|
_dragSourceWindow = dragSourceWindow;
|
||||||
|
if (_dragSourceWindow != null) // Detaching a tab from existing window
|
||||||
|
{
|
||||||
|
_dragOffset = new Float2(window.Size.X / 2, 10.0f);
|
||||||
|
|
||||||
|
// TODO: when detaching tab in floating window (not main window), the drag source window is still main window?
|
||||||
|
var dragSourceWindowWayland = toMove.MasterPanel?.RootWindow.Window ?? Editor.Instance.Windows.MainWindow;
|
||||||
|
window.DoDragDrop(window.Title, _dragOffset, dragSourceWindowWayland);
|
||||||
|
|
||||||
|
_dragSourceWindow.MouseUp += OnMouseUp; // The mouse up event is sent to the source window on Windows
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_dragOffset = window.MousePosition;
|
||||||
|
window.DoDragDrop(window.Title, _dragOffset, window);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the dragged window stays on top of every other window
|
||||||
|
window.IsAlwaysOnTop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases unmanaged and - optionally - managed resources.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
var window = _toMove?.Window?.Window;
|
||||||
|
|
||||||
|
// Unbind events
|
||||||
|
FlaxEngine.Scripting.Update -= OnUpdate;
|
||||||
|
if (window != null)
|
||||||
|
window.MouseUp -= OnMouseUp;
|
||||||
|
if (_dragSourceWindow != null)
|
||||||
|
_dragSourceWindow.MouseUp -= OnMouseUp;
|
||||||
|
|
||||||
|
RemoveDockHints();
|
||||||
|
|
||||||
|
if (_toMove == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (window != null)
|
||||||
|
{
|
||||||
|
window.Opacity = 1.0f;
|
||||||
|
window.IsAlwaysOnTop = false;
|
||||||
|
window.BringToFront();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if window won't be docked
|
||||||
|
if (_toSet == DockState.Float)
|
||||||
|
{
|
||||||
|
if (window == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Show base window
|
||||||
|
window.Show();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool hasNoChildPanels = _toMove.ChildPanelsCount == 0;
|
||||||
|
|
||||||
|
// Check if window has only single tab
|
||||||
|
if (hasNoChildPanels && _toMove.TabsCount == 1)
|
||||||
|
{
|
||||||
|
// Dock window
|
||||||
|
_toMove.GetTab(0).Show(_toSet, _toDock);
|
||||||
|
}
|
||||||
|
// Check if dock as tab and has no child panels
|
||||||
|
else if (hasNoChildPanels && _toSet == DockState.DockFill)
|
||||||
|
{
|
||||||
|
// Dock all tabs
|
||||||
|
while (_toMove.TabsCount > 0)
|
||||||
|
{
|
||||||
|
_toMove.GetTab(0).Show(DockState.DockFill, _toDock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var selectedTab = _toMove.SelectedTab;
|
||||||
|
|
||||||
|
// Dock the first tab into the target location
|
||||||
|
if (_toMove.TabsCount > 0)
|
||||||
|
{
|
||||||
|
var firstTab = _toMove.GetTab(0);
|
||||||
|
firstTab.Show(_toSet, _toDock);
|
||||||
|
|
||||||
|
// Dock rest of the tabs
|
||||||
|
while (_toMove.TabsCount > 0)
|
||||||
|
{
|
||||||
|
_toMove.GetTab(0).Show(DockState.DockFill, firstTab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep selected tab being selected
|
||||||
|
selectedTab?.SelectTab();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Focus target window
|
||||||
|
_toDock.Root.Focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
_toMove = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start dragging a floating dock panel.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="toMove">Floating dock panel to move.</param>
|
||||||
|
/// <returns>The window drag helper object.</returns>
|
||||||
|
public static WindowDragHelper StartDragging(FloatWindowDockPanel toMove)
|
||||||
|
{
|
||||||
|
if (toMove == null)
|
||||||
|
throw new ArgumentNullException();
|
||||||
|
|
||||||
|
return new WindowDragHelper(toMove, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start dragging a docked panel into a floating window.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="toMove">Dock window to move.</param>
|
||||||
|
/// <param name="dragSourceWindow">The window where dragging started from.</param>
|
||||||
|
/// <returns>The window drag helper object.</returns>
|
||||||
|
public static WindowDragHelper StartDragging(DockWindow toMove, Window dragSourceWindow)
|
||||||
|
{
|
||||||
|
if (toMove == null)
|
||||||
|
throw new ArgumentNullException();
|
||||||
|
|
||||||
|
// Create floating window
|
||||||
|
toMove.CreateFloating();
|
||||||
|
|
||||||
|
// Get floating panel
|
||||||
|
var window = (WindowRootControl)toMove.Root;
|
||||||
|
var floatingPanelToMove = window.GetChild(0) as FloatWindowDockPanel;
|
||||||
|
|
||||||
|
return new WindowDragHelper(floatingPanelToMove, dragSourceWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddDockHints()
|
||||||
|
{
|
||||||
|
if (_toDock == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_toDock.RootWindow.Window != _dragSourceWindow)
|
||||||
|
_toDock.RootWindow.Window.MouseUp += OnMouseUp;
|
||||||
|
|
||||||
|
_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));
|
||||||
|
|
||||||
|
Control AddHintControl(Float2 pivot)
|
||||||
|
{
|
||||||
|
Control hintControl = _toDock.AddChild<Control>();
|
||||||
|
hintControl.AnchorPreset = AnchorPresets.StretchAll;
|
||||||
|
hintControl.Offsets = Margin.Zero;
|
||||||
|
hintControl.Size = new Float2(HintControlSize);
|
||||||
|
hintControl.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
|
||||||
|
hintControl.Pivot = pivot;
|
||||||
|
hintControl.PivotRelative = true;
|
||||||
|
return hintControl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveDockHints()
|
||||||
|
{
|
||||||
|
if (_toDock == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_toDock.RootWindow.Window != _dragSourceWindow)
|
||||||
|
_toDock.RootWindow.Window.MouseUp -= OnMouseUp;
|
||||||
|
|
||||||
|
_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(Float2 mousePos)
|
||||||
|
{
|
||||||
|
// Cache mouse position
|
||||||
|
_mouse = mousePos;
|
||||||
|
|
||||||
|
// Check intersection with any dock panel
|
||||||
|
DockPanel dockPanel = null;
|
||||||
|
if (_toMove.MasterPanel.HitTest(ref _mouse, _toMove, out var hitResults))
|
||||||
|
{
|
||||||
|
dockPanel = hitResults[0];
|
||||||
|
|
||||||
|
// Prefer panel which currently has focus
|
||||||
|
foreach (var hit in hitResults)
|
||||||
|
{
|
||||||
|
if (hit.RootWindow.Window.IsFocused)
|
||||||
|
{
|
||||||
|
dockPanel = hit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prefer panel in the same window we hit earlier
|
||||||
|
if (dockPanel?.RootWindow != _toDock?.RootWindow)
|
||||||
|
{
|
||||||
|
foreach (var hit in hitResults)
|
||||||
|
{
|
||||||
|
if (hit.RootWindow == _toDock?.RootWindow)
|
||||||
|
{
|
||||||
|
dockPanel = _toDock;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dockPanel != _toDock)
|
||||||
|
{
|
||||||
|
RemoveDockHints();
|
||||||
|
_toDock = dockPanel;
|
||||||
|
AddDockHints();
|
||||||
|
|
||||||
|
// Make sure the all the dock hint areas are not under other windows
|
||||||
|
_toDock?.RootWindow.Window.BringToFront();
|
||||||
|
//_toDock?.RootWindow.Window.Focus();
|
||||||
|
|
||||||
|
// Make the dragged window transparent when dock hints are visible
|
||||||
|
_toMove.Window.Window.Opacity = _toDock == null ? 1.0f : DragWindowOpacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check dock state to use
|
||||||
|
bool showProxyHints = _toDock != null;
|
||||||
|
bool showBorderHints = showProxyHints;
|
||||||
|
bool showCenterHint = showProxyHints;
|
||||||
|
Control hoveredHintControl = null;
|
||||||
|
Float2 hoveredSizeOverride = Float2.Zero;
|
||||||
|
if (showProxyHints)
|
||||||
|
{
|
||||||
|
// If moved window has not only tabs but also child panels disable docking as tab
|
||||||
|
if (_toMove.ChildPanelsCount > 0)
|
||||||
|
showCenterHint = false;
|
||||||
|
|
||||||
|
// Disable docking windows with one or more dock panels inside
|
||||||
|
if (_toMove.ChildPanelsCount > 0)
|
||||||
|
showBorderHints = false;
|
||||||
|
|
||||||
|
// Get dock area
|
||||||
|
_rectDock = _toDock.DockAreaBounds;
|
||||||
|
|
||||||
|
// Cache dock rectangles
|
||||||
|
var size = _rectDock.Size / Platform.DpiScale;
|
||||||
|
var offset = _toDock.PointFromScreen(_rectDock.Location);
|
||||||
|
var borderMargin = 4.0f;
|
||||||
|
var hintWindowsSize = HintControlSize;
|
||||||
|
var hintWindowsSize2 = hintWindowsSize * 0.5f;
|
||||||
|
var hintPreviewSize = new Float2(Math.Max(HintControlSize * 2, size.X * 0.5f), Math.Max(HintControlSize * 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;
|
||||||
|
_rBottom = new Rectangle(centerX - hintWindowsSize2, size.Y - hintWindowsSize - borderMargin, hintWindowsSize, hintWindowsSize) + offset;
|
||||||
|
_rLeft = new Rectangle(borderMargin, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
||||||
|
_rRight = new Rectangle(size.X - hintWindowsSize - borderMargin, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
||||||
|
_rCenter = new Rectangle(centerX - hintWindowsSize2, centerY - hintWindowsSize2, hintWindowsSize, hintWindowsSize) + offset;
|
||||||
|
|
||||||
|
// Hit test, and calculate the approximation for filled area when hovered over the hint
|
||||||
|
DockState toSet = DockState.Float;
|
||||||
|
if (showBorderHints)
|
||||||
|
{
|
||||||
|
if (_rUpper.Contains(_toDock.PointFromScreen(_mouse)))
|
||||||
|
{
|
||||||
|
toSet = DockState.DockTop;
|
||||||
|
hoveredHintControl = _dockHintUp;
|
||||||
|
hoveredSizeOverride = new Float2(size.X, hintPreviewSize.Y);
|
||||||
|
}
|
||||||
|
else if (_rBottom.Contains(_toDock.PointFromScreen(_mouse)))
|
||||||
|
{
|
||||||
|
toSet = DockState.DockBottom;
|
||||||
|
hoveredHintControl = _dockHintDown;
|
||||||
|
hoveredSizeOverride = new Float2(size.X, hintPreviewSize.Y);
|
||||||
|
}
|
||||||
|
else if (_rLeft.Contains(_toDock.PointFromScreen(_mouse)))
|
||||||
|
{
|
||||||
|
toSet = DockState.DockLeft;
|
||||||
|
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(_toDock.PointFromScreen(_mouse)))
|
||||||
|
{
|
||||||
|
toSet = DockState.DockFill;
|
||||||
|
hoveredHintControl = _dockHintCenter;
|
||||||
|
hoveredSizeOverride = new Float2(size.X, size.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
_toSet = toSet;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_toSet = DockState.Float;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update sizes and opacity of hint controls
|
||||||
|
if (_toDock != null)
|
||||||
|
{
|
||||||
|
if (hoveredHintControl != _dockHintDown)
|
||||||
|
{
|
||||||
|
_dockHintDown.Size = new Float2(HintControlSize);
|
||||||
|
_dockHintDown.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
|
||||||
|
}
|
||||||
|
if (hoveredHintControl != _dockHintLeft)
|
||||||
|
{
|
||||||
|
_dockHintLeft.Size = new Float2(HintControlSize);
|
||||||
|
_dockHintLeft.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
|
||||||
|
}
|
||||||
|
if (hoveredHintControl != _dockHintRight)
|
||||||
|
{
|
||||||
|
_dockHintRight.Size = new Float2(HintControlSize);
|
||||||
|
_dockHintRight.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
|
||||||
|
}
|
||||||
|
if (hoveredHintControl != _dockHintUp)
|
||||||
|
{
|
||||||
|
_dockHintUp.Size = new Float2(HintControlSize);
|
||||||
|
_dockHintUp.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
|
||||||
|
}
|
||||||
|
if (hoveredHintControl != _dockHintCenter)
|
||||||
|
{
|
||||||
|
_dockHintCenter.Size = new Float2(HintControlSize);
|
||||||
|
_dockHintCenter.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(0.6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_toSet != DockState.Float)
|
||||||
|
{
|
||||||
|
if (hoveredHintControl != null)
|
||||||
|
{
|
||||||
|
hoveredHintControl.BackgroundColor = Style.Current.DragWindow.AlphaMultiplied(1.0f);
|
||||||
|
hoveredHintControl.Size = hoveredSizeOverride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update hint controls visibility and location
|
||||||
|
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;
|
||||||
|
|
||||||
|
_dockHintDown.Visible = showProxyHints & showBorderHints;
|
||||||
|
_dockHintLeft.Visible = showProxyHints & showBorderHints;
|
||||||
|
_dockHintRight.Visible = showProxyHints & showBorderHints;
|
||||||
|
_dockHintUp.Visible = showProxyHints & showBorderHints;
|
||||||
|
_dockHintCenter.Visible = showProxyHints & showCenterHint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMouseUp(ref Float2 location, MouseButton button, ref bool handled)
|
||||||
|
{
|
||||||
|
if (button == MouseButton.Left)
|
||||||
|
Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUpdate()
|
||||||
|
{
|
||||||
|
var mousePos = Platform.MousePosition;
|
||||||
|
|
||||||
|
if (_mouse != mousePos)
|
||||||
|
OnMouseMove(mousePos);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMouseMove(Float2 mousePos)
|
||||||
|
{
|
||||||
|
if (_dragSourceWindow != null)
|
||||||
|
_toMove.Window.Window.Position = mousePos - _dragOffset;
|
||||||
|
|
||||||
|
UpdateRects(mousePos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ using FlaxEditor.Windows;
|
|||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
using FlaxEngine.Json;
|
using FlaxEngine.Json;
|
||||||
using DockHintWindow = FlaxEditor.GUI.Docking.DockHintWindow;
|
using WindowDragHelper = FlaxEditor.GUI.Docking.WindowDragHelper;
|
||||||
using MasterDockPanel = FlaxEditor.GUI.Docking.MasterDockPanel;
|
using MasterDockPanel = FlaxEditor.GUI.Docking.MasterDockPanel;
|
||||||
using FlaxEditor.Content.Settings;
|
using FlaxEditor.Content.Settings;
|
||||||
using FlaxEditor.Options;
|
using FlaxEditor.Options;
|
||||||
@@ -456,13 +456,6 @@ namespace FlaxEditor.Modules
|
|||||||
UpdateToolstrip();
|
UpdateToolstrip();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override void OnExit()
|
|
||||||
{
|
|
||||||
// Cleanup dock panel hint proxy windows (Flax will destroy them by var but it's better to clear them earlier)
|
|
||||||
DockHintWindow.Proxy.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IColorPickerDialog ShowPickColorDialog(Control targetControl, Color initialValue, ColorValueBox.ColorPickerEvent colorChanged, ColorValueBox.ColorPickerClosedEvent pickerClosed, bool useDynamicEditing)
|
private IColorPickerDialog ShowPickColorDialog(Control targetControl, Color initialValue, ColorValueBox.ColorPickerEvent colorChanged, ColorValueBox.ColorPickerClosedEvent pickerClosed, bool useDynamicEditing)
|
||||||
{
|
{
|
||||||
var dialog = new ColorPickerDialog(initialValue, colorChanged, pickerClosed, useDynamicEditing);
|
var dialog = new ColorPickerDialog(initialValue, colorChanged, pickerClosed, useDynamicEditing);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ API_CLASS(Static) class FLAXENGINE_API Time
|
|||||||
friend class Engine;
|
friend class Engine;
|
||||||
friend class TimeService;
|
friend class TimeService;
|
||||||
friend class PhysicsSettings;
|
friend class PhysicsSettings;
|
||||||
|
friend Window;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -429,7 +429,7 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Starts drag and drop operation
|
/// Starts a drag and drop operation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="data">The data.</param>
|
/// <param name="data">The data.</param>
|
||||||
/// <returns>The result.</returns>
|
/// <returns>The result.</returns>
|
||||||
@@ -438,6 +438,18 @@ public:
|
|||||||
return DragDropEffect::None;
|
return DragDropEffect::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts a window drag and drop operation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The data.</param>
|
||||||
|
/// <param name="offset">The offset for positioning the window from cursor.</param>
|
||||||
|
/// <param name="dragSourceWindow">The window where dragging started.</param>
|
||||||
|
/// <returns>The result.</returns>
|
||||||
|
API_FUNCTION() virtual DragDropEffect DoDragDrop(const StringView& data, const Float2& offset, Window* dragSourceWindow)
|
||||||
|
{
|
||||||
|
return DragDropEffect::None;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Starts the mouse tracking.
|
/// Starts the mouse tracking.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1396,11 +1396,7 @@ DragDropEffect Window::DoDragDrop(const StringView& data)
|
|||||||
StringAnsi dataAnsi(data);
|
StringAnsi dataAnsi(data);
|
||||||
LinuxDropTextData dropData;
|
LinuxDropTextData dropData;
|
||||||
dropData.Text = data;
|
dropData.Text = data;
|
||||||
#if !PLATFORM_SDL
|
|
||||||
unsigned long mainWindow = _window;
|
unsigned long mainWindow = _window;
|
||||||
#else
|
|
||||||
unsigned long mainWindow = (unsigned long)_handle;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Begin dragging
|
// Begin dragging
|
||||||
auto screen = X11::XDefaultScreen(xDisplay);
|
auto screen = X11::XDefaultScreen(xDisplay);
|
||||||
|
|||||||
@@ -405,19 +405,24 @@ public:
|
|||||||
auto windowHandle = static_cast<SDLWindow*>(window)->_window;
|
auto windowHandle = static_cast<SDLWindow*>(window)->_window;
|
||||||
if (relativeMode)
|
if (relativeMode)
|
||||||
{
|
{
|
||||||
oldScreenRect = SDL_GetWindowMouseRect(windowHandle);
|
|
||||||
relativeModeWindow = window;
|
relativeModeWindow = window;
|
||||||
SDL_GetMouseState(&oldPosition.X, &oldPosition.Y);
|
SDL_GetMouseState(&oldPosition.X, &oldPosition.Y);
|
||||||
if (!SDL_CursorVisible())
|
if (!SDL_CursorVisible())
|
||||||
{
|
{
|
||||||
// Trap the cursor in current location
|
// Trap the cursor in current location
|
||||||
SDL_Rect clipRect = { (int)oldPosition.X, (int)oldPosition.Y, 1, 1 };
|
SDL_Rect clipRect = { (int)oldPosition.X, (int)oldPosition.Y, 1, 1 };
|
||||||
|
oldScreenRect = SDL_GetWindowMouseRect(windowHandle);
|
||||||
SDL_SetWindowMouseRect(windowHandle, &clipRect);
|
SDL_SetWindowMouseRect(windowHandle, &clipRect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SDL_SetWindowMouseRect(windowHandle, oldScreenRect);
|
if (relativeModeWindow != window)
|
||||||
|
{
|
||||||
|
// FIXME: When floating game window is focused and editor viewport activated, the relative mode gets stuck
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SDL_SetWindowMouseRect(windowHandle, nullptr);//oldScreenRect);
|
||||||
SDL_WarpMouseInWindow(windowHandle, oldPosition.X, oldPosition.Y);
|
SDL_WarpMouseInWindow(windowHandle, oldPosition.X, oldPosition.Y);
|
||||||
oldScreenRect = nullptr;
|
oldScreenRect = nullptr;
|
||||||
relativeModeWindow = nullptr;
|
relativeModeWindow = nullptr;
|
||||||
@@ -519,17 +524,6 @@ bool SDLInput::HandleEvent(SDLWindow* window, SDL_Event& event)
|
|||||||
}
|
}
|
||||||
return true;
|
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(event.drop.x * dpiScale, event.drop.y * dpiScale);// = window->ClientToScreen({ event.drop.x * dpiScale, event.drop.y * dpiScale});
|
|
||||||
Float2 mousePos = window->ClientToScreen({ event.drop.x * dpiScale, event.drop.y * dpiScale});
|
|
||||||
if (window != Engine::MainWindow)
|
|
||||||
mousePos = window->GetPosition() - mousePos;
|
|
||||||
Input::Mouse->OnMouseMove(mousePos, window);
|
|
||||||
return true;
|
|
||||||
}*/
|
|
||||||
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
|
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
|
||||||
{
|
{
|
||||||
Input::Mouse->OnMouseLeave(window);
|
Input::Mouse->OnMouseLeave(window);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,36 @@
|
|||||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
|
||||||
#if PLATFORM_SDL && PLATFORM_WINDOWS
|
#if PLATFORM_SDL && PLATFORM_WINDOWS
|
||||||
|
|
||||||
|
#define BORDERLESS_MAXIMIZE_WORKAROUND 2
|
||||||
|
|
||||||
#include "SDLPlatform.h"
|
#include "SDLPlatform.h"
|
||||||
|
#include "SDLInput.h"
|
||||||
|
|
||||||
#include "Engine/Core/Collections/Array.h"
|
#include "Engine/Core/Collections/Array.h"
|
||||||
#include "Engine/Platform/WindowsManager.h"
|
#include "Engine/Platform/WindowsManager.h"
|
||||||
#include "Engine/Platform/Win32/IncludeWindowsHeaders.h"
|
#include "Engine/Platform/Win32/IncludeWindowsHeaders.h"
|
||||||
|
#include "Engine/Input/Mouse.h"
|
||||||
|
#include "Engine/Core/Log.h"
|
||||||
|
#include "Engine/Engine/Engine.h"
|
||||||
|
|
||||||
#include <SDL3/SDL_hints.h>
|
#include <SDL3/SDL_hints.h>
|
||||||
#include <SDL3/SDL_init.h>
|
#include <SDL3/SDL_init.h>
|
||||||
#include <SDL3/SDL_system.h>
|
#include <SDL3/SDL_system.h>
|
||||||
|
#include <SDL3/SDL_timer.h>
|
||||||
|
|
||||||
|
#if USE_EDITOR
|
||||||
|
#include <oleidl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STYLE_RESIZABLE (WS_THICKFRAME | WS_MAXIMIZEBOX)
|
||||||
|
|
||||||
|
namespace WinImpl
|
||||||
|
{
|
||||||
|
Window* DraggedWindow;
|
||||||
|
Float2 DraggedWindowStartPosition = Float2::Zero;
|
||||||
|
Float2 DraggedWindowMousePosition = Float2::Zero;
|
||||||
|
}
|
||||||
|
|
||||||
// The events for releasing the mouse during window dragging are missing, handle the mouse release event here
|
// The events for releasing the mouse during window dragging are missing, handle the mouse release event here
|
||||||
bool SDLCALL SDLPlatform::EventMessageHook(void* userdata, MSG* msg)
|
bool SDLCALL SDLPlatform::EventMessageHook(void* userdata, MSG* msg)
|
||||||
@@ -35,18 +55,59 @@ bool SDLCALL SDLPlatform::EventMessageHook(void* userdata, MSG* msg)
|
|||||||
{
|
{
|
||||||
Window* window;
|
Window* window;
|
||||||
GET_WINDOW_WITH_HWND(window, msg->hwnd);
|
GET_WINDOW_WITH_HWND(window, msg->hwnd);
|
||||||
|
WinImpl::DraggedWindow = window;
|
||||||
auto hit = static_cast<WindowHitCodes>(msg->wParam);
|
|
||||||
if (SDLPlatform::CheckWindowDragging(window, hit))
|
WinImpl::DraggedWindowStartPosition = WinImpl::DraggedWindow->GetClientPosition();
|
||||||
return false;
|
Float2 mousePos(static_cast<float>(static_cast<LONG>(WINDOWS_GET_X_LPARAM(msg->lParam))), static_cast<float>(static_cast<LONG>(WINDOWS_GET_Y_LPARAM(msg->lParam))));
|
||||||
|
WinImpl::DraggedWindowMousePosition = mousePos;
|
||||||
|
WinImpl::DraggedWindowMousePosition -= WinImpl::DraggedWindowStartPosition;
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
WindowHitCodes hit = static_cast<WindowHitCodes>(msg->wParam);
|
||||||
|
window->OnHitTest(mousePos, hit, result);
|
||||||
|
//if (result && hit != WindowHitCodes::Caption)
|
||||||
|
// return false;
|
||||||
|
|
||||||
|
if (hit == WindowHitCodes::Caption)
|
||||||
|
{
|
||||||
|
SDL_Event event{ 0 };
|
||||||
|
event.button.type = SDL_EVENT_MOUSE_BUTTON_DOWN;
|
||||||
|
event.button.down = true;
|
||||||
|
event.button.timestamp = SDL_GetTicksNS();
|
||||||
|
event.button.windowID = SDL_GetWindowID(window->GetSDLWindow());
|
||||||
|
event.button.button = SDL_BUTTON_LEFT;
|
||||||
|
event.button.clicks = 1;
|
||||||
|
event.button.x = WinImpl::DraggedWindowMousePosition.X;
|
||||||
|
event.button.y = WinImpl::DraggedWindowMousePosition.Y;
|
||||||
|
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
/*else if (msg->message == WM_NCLBUTTONUP || msg->message == WM_CAPTURECHANGED)
|
||||||
|
{
|
||||||
|
windowDragging = false;
|
||||||
|
Window* window;
|
||||||
|
GET_WINDOW_WITH_HWND(window, msg->hwnd);
|
||||||
|
|
||||||
|
SDL_Event event{ 0 };
|
||||||
|
event.button.type = SDL_EVENT_MOUSE_BUTTON_UP;
|
||||||
|
event.button.down = false;
|
||||||
|
event.button.timestamp = SDL_GetTicksNS();
|
||||||
|
event.button.windowID = SDL_GetWindowID(window->GetSDLWindow());
|
||||||
|
event.button.button = SDL_BUTTON_LEFT;
|
||||||
|
event.button.clicks = 1;
|
||||||
|
event.button.x = static_cast<float>(static_cast<LONG>(WINDOWS_GET_X_LPARAM(msg->lParam)));
|
||||||
|
event.button.y = static_cast<float>(static_cast<LONG>(WINDOWS_GET_Y_LPARAM(msg->lParam)));
|
||||||
|
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
}*/
|
||||||
return true;
|
return true;
|
||||||
#undef GET_WINDOW_WITH_HWND
|
#undef GET_WINDOW_WITH_HWND
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SDLPlatform::InitPlatform()
|
bool SDLPlatform::InitInternal()
|
||||||
{
|
{
|
||||||
// Workaround required for handling window dragging events properly for DockHintWindow
|
// Workaround required for handling window dragging events properly
|
||||||
SDL_SetWindowsMessageHook(&EventMessageHook, nullptr);
|
SDL_SetWindowsMessageHook(&EventMessageHook, nullptr);
|
||||||
|
|
||||||
if (WindowsPlatform::Init())
|
if (WindowsPlatform::Init())
|
||||||
@@ -55,10 +116,177 @@ bool SDLPlatform::InitPlatform()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SDLPlatform::EventFilterCallback(void* userdata, SDL_Event* event)
|
||||||
|
{
|
||||||
|
Window* draggedWindow = *(Window**)userdata;
|
||||||
|
if (draggedWindow == nullptr)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// When the window is being dragged on Windows, the internal message loop is blocking
|
||||||
|
// the SDL event queue. We need to handle all relevant events in this event watch callback
|
||||||
|
// to ensure dragging related functionality doesn't break due to engine not getting updated.
|
||||||
|
// This also happens to fix the engine freezing during the dragging operation.
|
||||||
|
|
||||||
|
SDLWindow* window = SDLWindow::GetWindowFromEvent(*event);
|
||||||
|
if (event->type == SDL_EVENT_WINDOW_EXPOSED)
|
||||||
|
{
|
||||||
|
// The internal timer is sending exposed events every ~16ms
|
||||||
|
Engine::OnUpdate();//Scripting::Update(); // For docking updates
|
||||||
|
Engine::OnDraw();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN)
|
||||||
|
{
|
||||||
|
SDLWindow* window = SDLWindow::GetWindowFromEvent(*event);
|
||||||
|
if (window)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
window->OnLeftButtonHit(WindowHitCodes::Caption, result);
|
||||||
|
//if (result)
|
||||||
|
// return false;
|
||||||
|
window->HandleEvent(*event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (event->type == SDL_EVENT_WINDOW_MOVED)
|
||||||
|
{
|
||||||
|
Float2 start = WinImpl::DraggedWindowStartPosition;
|
||||||
|
Float2 newPos = Float2(static_cast<float>(event->window.data1), static_cast<float>(event->window.data2));
|
||||||
|
Float2 offset = newPos - start;
|
||||||
|
Float2 mousePos = WinImpl::DraggedWindowMousePosition;
|
||||||
|
|
||||||
|
SDL_Event mouseMovedEvent { 0 };
|
||||||
|
mouseMovedEvent.motion.type = SDL_EVENT_MOUSE_MOTION;
|
||||||
|
mouseMovedEvent.motion.windowID = SDL_GetWindowID(WinImpl::DraggedWindow->GetSDLWindow());
|
||||||
|
mouseMovedEvent.motion.timestamp = SDL_GetTicksNS();
|
||||||
|
mouseMovedEvent.motion.state = SDL_BUTTON_LEFT;
|
||||||
|
mouseMovedEvent.motion.x = mousePos.X;
|
||||||
|
mouseMovedEvent.motion.y = mousePos.Y;
|
||||||
|
if (window)
|
||||||
|
window->HandleEvent(mouseMovedEvent);
|
||||||
|
if (window)
|
||||||
|
window->HandleEvent(*event);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (window)
|
||||||
|
window->HandleEvent(*event);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLPlatform::PreHandleEvents()
|
||||||
|
{
|
||||||
|
SDL_AddEventWatch(EventFilterCallback, &WinImpl::DraggedWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLPlatform::PostHandleEvents()
|
||||||
|
{
|
||||||
|
SDL_RemoveEventWatch(EventFilterCallback, &WinImpl::DraggedWindow);
|
||||||
|
|
||||||
|
// Handle window dragging release here
|
||||||
|
if (WinImpl::DraggedWindow != nullptr)
|
||||||
|
{
|
||||||
|
Float2 mousePosition;
|
||||||
|
auto buttons = SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y);
|
||||||
|
|
||||||
|
// Send simulated mouse up event
|
||||||
|
SDL_Event buttonUpEvent { 0 };
|
||||||
|
buttonUpEvent.motion.type = SDL_EVENT_MOUSE_BUTTON_UP;
|
||||||
|
buttonUpEvent.button.down = false;
|
||||||
|
buttonUpEvent.motion.windowID = SDL_GetWindowID(WinImpl::DraggedWindow->GetSDLWindow());
|
||||||
|
buttonUpEvent.motion.timestamp = SDL_GetTicksNS();
|
||||||
|
buttonUpEvent.motion.state = SDL_BUTTON_LEFT;
|
||||||
|
buttonUpEvent.button.clicks = 1;
|
||||||
|
buttonUpEvent.motion.x = mousePosition.X;
|
||||||
|
buttonUpEvent.motion.y = mousePosition.Y;
|
||||||
|
WinImpl::DraggedWindow->HandleEvent(buttonUpEvent);
|
||||||
|
WinImpl::DraggedWindow = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDLWindow::HandleEventInternal(SDL_Event& event)
|
||||||
|
{
|
||||||
|
switch (event.type)
|
||||||
|
{
|
||||||
|
case SDL_EVENT_WINDOW_DESTROYED:
|
||||||
|
{
|
||||||
|
#if USE_EDITOR
|
||||||
|
// Disable file dropping
|
||||||
|
if (_settings.AllowDragAndDrop)
|
||||||
|
{
|
||||||
|
const auto result = RevokeDragDrop((HWND)_handle);
|
||||||
|
if (result != S_OK)
|
||||||
|
LOG(Warning, "Window drag and drop service error: 0x{0:x}:{1}", result, 2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||||
|
{
|
||||||
|
if (WinImpl::DraggedWindow != nullptr && WinImpl::DraggedWindow->_windowId != event.button.windowID)
|
||||||
|
{
|
||||||
|
// Send the button event to dragged window as well
|
||||||
|
Float2 mousePos = ClientToScreen({ event.button.x, event.button.y });
|
||||||
|
Float2 clientPos = WinImpl::DraggedWindow->ScreenToClient(mousePos);
|
||||||
|
|
||||||
|
SDL_Event event2 = event;
|
||||||
|
event2.button.windowID = WinImpl::DraggedWindow->_windowId;
|
||||||
|
event2.button.x = clientPos.X;
|
||||||
|
event2.button.y = clientPos.Y;
|
||||||
|
|
||||||
|
SDLInput::HandleEvent(WinImpl::DraggedWindow, event2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDLPlatform::UsesWindows()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDLPlatform::UsesWayland()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDLPlatform::UsesX11()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SDLWindow::Focus()
|
||||||
|
{
|
||||||
|
auto activateWhenRaised = SDL_GetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED);
|
||||||
|
SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, "1");
|
||||||
|
|
||||||
|
// Forcing the window to focus causes issues with opening context menus while window is maximized
|
||||||
|
//auto forceRaiseWindow = SDL_GetHint(SDL_HINT_FORCE_RAISEWINDOW);
|
||||||
|
//SDL_SetHint(SDL_HINT_FORCE_RAISEWINDOW, "1");
|
||||||
|
|
||||||
|
SDL_RaiseWindow(_window);
|
||||||
|
|
||||||
|
SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, activateWhenRaised);
|
||||||
|
//SDL_SetHint(SDL_HINT_FORCE_RAISEWINDOW, forceRaiseWindow);
|
||||||
|
}
|
||||||
|
|
||||||
void SDLPlatform::SetHighDpiAwarenessEnabled(bool enable)
|
void SDLPlatform::SetHighDpiAwarenessEnabled(bool enable)
|
||||||
{
|
{
|
||||||
// Other supported values: "permonitor", "permonitorv2"
|
// Other supported values: "permonitor", "permonitorv2"
|
||||||
SDL_SetHint("SDL_WINDOWS_DPI_AWARENESS", enable ? "system" : "unaware");
|
SDL_SetHint("SDL_WINDOWS_DPI_AWARENESS", enable ? "system" : "unaware");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DragDropEffect SDLWindow::DoDragDrop(const StringView& data, const Float2& offset, Window* dragSourceWindow)
|
||||||
|
{
|
||||||
|
Show();
|
||||||
|
return DragDropEffect::None;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "Engine/Platform/BatteryInfo.h"
|
#include "Engine/Platform/BatteryInfo.h"
|
||||||
#include "Engine/Platform/WindowsManager.h"
|
#include "Engine/Platform/WindowsManager.h"
|
||||||
#include "Engine/Platform/SDL/SDLInput.h"
|
#include "Engine/Platform/SDL/SDLInput.h"
|
||||||
|
#include "Engine/Engine/Engine.h"
|
||||||
|
|
||||||
#include <SDL3/SDL_hints.h>
|
#include <SDL3/SDL_hints.h>
|
||||||
#include <SDL3/SDL_init.h>
|
#include <SDL3/SDL_init.h>
|
||||||
@@ -22,14 +23,10 @@
|
|||||||
|
|
||||||
#if PLATFORM_LINUX
|
#if PLATFORM_LINUX
|
||||||
#include "Engine/Engine/CommandLine.h"
|
#include "Engine/Engine/CommandLine.h"
|
||||||
#include "Engine/Platform/MessageBox.h"
|
|
||||||
#include <SDL3/SDL_messagebox.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DefaultDPI 96
|
#define DefaultDPI 96
|
||||||
|
|
||||||
uint32 SDLPlatform::DraggedWindowId = 0;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
int32 SystemDpi = 96;
|
int32 SystemDpi = 96;
|
||||||
@@ -44,7 +41,12 @@ bool SDLPlatform::Init()
|
|||||||
else if (CommandLine::Options.Wayland)
|
else if (CommandLine::Options.Wayland)
|
||||||
SDL_SetHintWithPriority(SDL_HINT_VIDEO_DRIVER, "wayland", SDL_HINT_OVERRIDE);
|
SDL_SetHintWithPriority(SDL_HINT_VIDEO_DRIVER, "wayland", SDL_HINT_OVERRIDE);
|
||||||
else
|
else
|
||||||
SDL_SetHintWithPriority(SDL_HINT_VIDEO_DRIVER, "wayland", SDL_HINT_OVERRIDE);
|
{
|
||||||
|
// Override the X11 preference when running in Wayland session
|
||||||
|
String waylandDisplayEnv;
|
||||||
|
if (!GetEnvironmentVariable(String("WAYLAND_DISPLAY"), waylandDisplayEnv))
|
||||||
|
SDL_SetHintWithPriority(SDL_HINT_VIDEO_DRIVER, "wayland", SDL_HINT_OVERRIDE);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if PLATFORM_LINUX
|
#if PLATFORM_LINUX
|
||||||
@@ -69,21 +71,15 @@ bool SDLPlatform::Init()
|
|||||||
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION, "0");
|
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_WARP_MOTION, "0");
|
||||||
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE, "1"); // Needed for tracking mode
|
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_CURSOR_VISIBLE, "1"); // Needed for tracking mode
|
||||||
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, "0"); //
|
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, "0"); //
|
||||||
|
SDL_SetHint(SDL_HINT_MOUSE_DOUBLE_CLICK_RADIUS, "8"); // Reduce the default mouse double-click radius
|
||||||
|
|
||||||
//SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1"); // Disables raw mouse input
|
//SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_MODE_WARP, "1"); // Disables raw mouse input
|
||||||
SDL_SetHint(SDL_HINT_WINDOWS_RAW_KEYBOARD, "1");
|
SDL_SetHint(SDL_HINT_WINDOWS_RAW_KEYBOARD, "1");
|
||||||
|
|
||||||
SDL_SetHint(SDL_HINT_VIDEO_WAYLAND_SCALE_TO_DISPLAY, "1");
|
SDL_SetHint(SDL_HINT_VIDEO_WAYLAND_SCALE_TO_DISPLAY, "1");
|
||||||
|
|
||||||
// Disable SDL clipboard support
|
//if (InitInternal())
|
||||||
SDL_SetEventEnabled(SDL_EVENT_CLIPBOARD_UPDATE, false);
|
// return true;
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
if (!SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD))
|
if (!SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD))
|
||||||
Platform::Fatal(String::Format(TEXT("Failed to initialize SDL: {0}."), String(SDL_GetError())));
|
Platform::Fatal(String::Format(TEXT("Failed to initialize SDL: {0}."), String(SDL_GetError())));
|
||||||
@@ -104,10 +100,23 @@ bool SDLPlatform::Init()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
SDL_free(locales);
|
SDL_free(locales);
|
||||||
|
|
||||||
if (InitPlatform())
|
if (InitInternal())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (UsesWindows() || UsesX11())
|
||||||
|
{
|
||||||
|
// Disable SDL clipboard support
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
SDLInput::Init();
|
SDLInput::Init();
|
||||||
|
|
||||||
SystemDpi = (int)(SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()) * DefaultDPI);
|
SystemDpi = (int)(SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()) * DefaultDPI);
|
||||||
@@ -129,74 +138,12 @@ void SDLPlatform::LogInfo()
|
|||||||
LOG(Info, "SDL video driver: {}", String(SDL_GetCurrentVideoDriver()));
|
LOG(Info, "SDL video driver: {}", String(SDL_GetCurrentVideoDriver()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SDLPlatform::CheckWindowDragging(Window* window, WindowHitCodes hit)
|
|
||||||
{
|
|
||||||
bool handled = false;
|
|
||||||
window->OnLeftButtonHit(hit, handled);
|
|
||||||
if (handled)
|
|
||||||
DraggedWindowId = window->_windowId;
|
|
||||||
return handled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDLPlatform::Tick()
|
void SDLPlatform::Tick()
|
||||||
{
|
{
|
||||||
SDLInput::Update();
|
SDLInput::Update();
|
||||||
|
|
||||||
if (DraggedWindowId != 0)
|
PreHandleEvents();
|
||||||
{
|
|
||||||
Float2 mousePos;
|
|
||||||
auto buttons = SDL_GetGlobalMouseState(&mousePos.X, &mousePos.Y);
|
|
||||||
if (!(buttons & SDL_BUTTON_MASK(SDL_BUTTON_LEFT)))
|
|
||||||
{
|
|
||||||
Window* window = nullptr;
|
|
||||||
WindowsManager::WindowsLocker.Lock();
|
|
||||||
for (int32 i = 0; i < WindowsManager::Windows.Count(); i++)
|
|
||||||
{
|
|
||||||
if (WindowsManager::Windows[i]->_windowId == DraggedWindowId)
|
|
||||||
{
|
|
||||||
window = WindowsManager::Windows[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WindowsManager::WindowsLocker.Unlock();
|
|
||||||
|
|
||||||
if (window != nullptr)
|
|
||||||
{
|
|
||||||
int top, left, bottom, right;
|
|
||||||
SDL_GetWindowBordersSize(window->_window, &top, &left, &bottom, &right);
|
|
||||||
mousePos += Float2(static_cast<float>(left), static_cast<float>(-top));
|
|
||||||
Input::Mouse->OnMouseUp(mousePos, MouseButton::Left, window);
|
|
||||||
}
|
|
||||||
DraggedWindowId = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#if PLATFORM_LINUX
|
|
||||||
String dockHintWindow("DockHint.Window");
|
|
||||||
Window* window = nullptr;
|
|
||||||
WindowsManager::WindowsLocker.Lock();
|
|
||||||
for (int32 i = 0; i < WindowsManager::Windows.Count(); i++)
|
|
||||||
{
|
|
||||||
if (WindowsManager::Windows[i]->_title.Compare(dockHintWindow) == 0)
|
|
||||||
//if (WindowsManager::Windows[i]->_windowId == DraggedWindowId)
|
|
||||||
{
|
|
||||||
window = WindowsManager::Windows[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WindowsManager::WindowsLocker.Unlock();
|
|
||||||
|
|
||||||
if (window != nullptr)
|
|
||||||
{
|
|
||||||
int top, left, bottom, right;
|
|
||||||
SDL_GetWindowBordersSize(window->_window, &top, &left, &bottom, &right);
|
|
||||||
mousePos += Float2(static_cast<float>(left), static_cast<float>(-top));
|
|
||||||
Input::Mouse->OnMouseMove(mousePos, window);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_PumpEvents();
|
SDL_PumpEvents();
|
||||||
SDL_Event events[32];
|
SDL_Event events[32];
|
||||||
int count = SDL_PeepEvents(events, SDL_arraysize(events), SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST);
|
int count = SDL_PeepEvents(events, SDL_arraysize(events), SDL_GETEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST);
|
||||||
@@ -208,8 +155,10 @@ void SDLPlatform::Tick()
|
|||||||
else if (events[i].type >= SDL_EVENT_JOYSTICK_AXIS_MOTION && events[i].type <= SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED)
|
else if (events[i].type >= SDL_EVENT_JOYSTICK_AXIS_MOTION && events[i].type <= SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED)
|
||||||
SDLInput::HandleEvent(nullptr, events[i]);
|
SDLInput::HandleEvent(nullptr, events[i]);
|
||||||
else
|
else
|
||||||
SDLPlatform::HandleEvent(events[i]);
|
HandleEvent(events[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PostHandleEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SDLPlatform::HandleEvent(SDL_Event& event)
|
bool SDLPlatform::HandleEvent(SDL_Event& event)
|
||||||
@@ -264,7 +213,18 @@ void SDLPlatform::OpenUrl(const StringView& url)
|
|||||||
Float2 SDLPlatform::GetMousePosition()
|
Float2 SDLPlatform::GetMousePosition()
|
||||||
{
|
{
|
||||||
Float2 pos;
|
Float2 pos;
|
||||||
SDL_GetGlobalMouseState(&pos.X, &pos.Y);
|
if (UsesWayland())
|
||||||
|
{
|
||||||
|
// Wayland doesn't support reporting global mouse position,
|
||||||
|
// use the last known reported position we got from received window events.
|
||||||
|
pos = Input::GetMouseScreenPosition();
|
||||||
|
//if (!SDL_GetGlobalMouseState(&pos.X, &pos.Y))
|
||||||
|
// LOG(Error, "SDL_GetGlobalMouseState() failed");
|
||||||
|
}
|
||||||
|
else if (UsesX11())
|
||||||
|
SDL_GetGlobalMouseState(&pos.X, &pos.Y);
|
||||||
|
else
|
||||||
|
pos = Input::GetMouseScreenPosition();
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,176 +273,4 @@ Window* SDLPlatform::CreateWindow(const CreateWindowSettings& settings)
|
|||||||
return New<SDLWindow>(settings);
|
return New<SDLWindow>(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !PLATFORM_LINUX
|
|
||||||
|
|
||||||
bool SDLPlatform::UsesWayland()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SDLPlatform::UsesX11()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if PLATFORM_LINUX
|
|
||||||
DialogResult MessageBox::Show(Window* parent, const StringView& text, const StringView& caption, MessageBoxButtons buttons, MessageBoxIcon icon)
|
|
||||||
{
|
|
||||||
StringAnsi textAnsi(text);
|
|
||||||
StringAnsi captionAnsi(caption);
|
|
||||||
|
|
||||||
SDL_MessageBoxData data;
|
|
||||||
SDL_MessageBoxButtonData dataButtons[3];
|
|
||||||
data.window = parent ? static_cast<SDLWindow*>(parent)->_window : nullptr;
|
|
||||||
data.title = captionAnsi.GetText();
|
|
||||||
data.message = textAnsi.GetText();
|
|
||||||
data.colorScheme = nullptr;
|
|
||||||
|
|
||||||
switch (icon)
|
|
||||||
{
|
|
||||||
case MessageBoxIcon::Error:
|
|
||||||
case MessageBoxIcon::Hand:
|
|
||||||
case MessageBoxIcon::Stop:
|
|
||||||
data.flags |= SDL_MESSAGEBOX_ERROR;
|
|
||||||
break;
|
|
||||||
case MessageBoxIcon::Asterisk:
|
|
||||||
case MessageBoxIcon::Information:
|
|
||||||
case MessageBoxIcon::Question:
|
|
||||||
data.flags |= SDL_MESSAGEBOX_INFORMATION;
|
|
||||||
break;
|
|
||||||
case MessageBoxIcon::Exclamation:
|
|
||||||
case MessageBoxIcon::Warning:
|
|
||||||
data.flags |= SDL_MESSAGEBOX_WARNING;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (buttons)
|
|
||||||
{
|
|
||||||
case MessageBoxButtons::AbortRetryIgnore:
|
|
||||||
dataButtons[0] =
|
|
||||||
{
|
|
||||||
SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
|
|
||||||
(int)DialogResult::Abort,
|
|
||||||
"Abort"
|
|
||||||
};
|
|
||||||
dataButtons[1] =
|
|
||||||
{
|
|
||||||
SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
|
|
||||||
(int)DialogResult::Retry,
|
|
||||||
"Retry"
|
|
||||||
};
|
|
||||||
dataButtons[2] =
|
|
||||||
{
|
|
||||||
0,
|
|
||||||
(int)DialogResult::Ignore,
|
|
||||||
"Ignore"
|
|
||||||
};
|
|
||||||
data.numbuttons = 3;
|
|
||||||
break;
|
|
||||||
case MessageBoxButtons::OK:
|
|
||||||
dataButtons[0] =
|
|
||||||
{
|
|
||||||
SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT | SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
|
|
||||||
(int)DialogResult::OK,
|
|
||||||
"OK"
|
|
||||||
};
|
|
||||||
data.numbuttons = 1;
|
|
||||||
break;
|
|
||||||
case MessageBoxButtons::OKCancel:
|
|
||||||
dataButtons[0] =
|
|
||||||
{
|
|
||||||
SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
|
|
||||||
(int)DialogResult::OK,
|
|
||||||
"OK"
|
|
||||||
};
|
|
||||||
dataButtons[1] =
|
|
||||||
{
|
|
||||||
SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
|
|
||||||
(int)DialogResult::Cancel,
|
|
||||||
"Cancel"
|
|
||||||
};
|
|
||||||
data.numbuttons = 2;
|
|
||||||
break;
|
|
||||||
case MessageBoxButtons::RetryCancel:
|
|
||||||
dataButtons[0] =
|
|
||||||
{
|
|
||||||
SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
|
|
||||||
(int)DialogResult::Retry,
|
|
||||||
"Retry"
|
|
||||||
};
|
|
||||||
dataButtons[1] =
|
|
||||||
{
|
|
||||||
SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
|
|
||||||
(int)DialogResult::Cancel,
|
|
||||||
"Cancel"
|
|
||||||
};
|
|
||||||
data.numbuttons = 2;
|
|
||||||
break;
|
|
||||||
case MessageBoxButtons::YesNo:
|
|
||||||
dataButtons[0] =
|
|
||||||
{
|
|
||||||
SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
|
|
||||||
(int)DialogResult::Yes,
|
|
||||||
"Yes"
|
|
||||||
};
|
|
||||||
dataButtons[1] =
|
|
||||||
{
|
|
||||||
SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
|
|
||||||
(int)DialogResult::No,
|
|
||||||
"No"
|
|
||||||
};
|
|
||||||
data.numbuttons = 2;
|
|
||||||
break;
|
|
||||||
case MessageBoxButtons::YesNoCancel:
|
|
||||||
{
|
|
||||||
dataButtons[0] =
|
|
||||||
{
|
|
||||||
SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT,
|
|
||||||
(int)DialogResult::Yes,
|
|
||||||
"Yes"
|
|
||||||
};
|
|
||||||
dataButtons[1] =
|
|
||||||
{
|
|
||||||
0,
|
|
||||||
(int)DialogResult::No,
|
|
||||||
"No"
|
|
||||||
};
|
|
||||||
dataButtons[2] =
|
|
||||||
{
|
|
||||||
SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT,
|
|
||||||
(int)DialogResult::Cancel,
|
|
||||||
"Cancel"
|
|
||||||
};
|
|
||||||
data.numbuttons = 3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
data.buttons = dataButtons;
|
|
||||||
|
|
||||||
int result = -1;
|
|
||||||
if (!SDL_ShowMessageBox(&data, &result))
|
|
||||||
{
|
|
||||||
#if PLATFORM_LINUX
|
|
||||||
// Fallback to native messagebox implementation in case some system fonts are missing
|
|
||||||
if (SDLPlatform::UsesX11())
|
|
||||||
{
|
|
||||||
LOG(Warning, "Failed to show SDL message box: {0}", String(SDL_GetError()));
|
|
||||||
return ShowFallback(parent, text, caption, buttons, icon);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
LOG(Error, "Failed to show SDL message box: {0}", String(SDL_GetError()));
|
|
||||||
return DialogResult::Abort;
|
|
||||||
}
|
|
||||||
if (result < 0)
|
|
||||||
return DialogResult::None;
|
|
||||||
return (DialogResult)result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,21 +7,18 @@
|
|||||||
#include "Engine/Platform/Base/Enums.h"
|
#include "Engine/Platform/Base/Enums.h"
|
||||||
#if PLATFORM_WINDOWS
|
#if PLATFORM_WINDOWS
|
||||||
#include "Engine/Platform/Windows/WindowsPlatform.h"
|
#include "Engine/Platform/Windows/WindowsPlatform.h"
|
||||||
|
typedef struct tagMSG MSG;
|
||||||
#elif PLATFORM_LINUX
|
#elif PLATFORM_LINUX
|
||||||
#include "Engine/Platform/Linux/LinuxPlatform.h"
|
#include "Engine/Platform/Linux/LinuxPlatform.h"
|
||||||
|
union _XEvent;
|
||||||
#else
|
#else
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class SDLWindow;
|
class SDLWindow;
|
||||||
union SDL_Event;
|
union SDL_Event;
|
||||||
#if PLATFORM_WINDOWS
|
|
||||||
typedef struct tagMSG MSG;
|
|
||||||
#elif PLATFORM_LINUX
|
|
||||||
union _XEvent;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Windows platform implementation and application management utilities.
|
/// The SDL platform implementation and application management utilities.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class FLAXENGINE_API SDLPlatform
|
class FLAXENGINE_API SDLPlatform
|
||||||
#if PLATFORM_WINDOWS
|
#if PLATFORM_WINDOWS
|
||||||
@@ -38,25 +35,25 @@ class FLAXENGINE_API SDLPlatform
|
|||||||
friend SDLWindow;
|
friend SDLWindow;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static uint32 DraggedWindowId;
|
static bool InitInternal();
|
||||||
|
|
||||||
private:
|
|
||||||
static bool InitPlatform();
|
|
||||||
#if PLATFORM_LINUX
|
#if PLATFORM_LINUX
|
||||||
static bool InitPlatformX11(void* display);
|
static bool InitX11(void* display);
|
||||||
#endif
|
#endif
|
||||||
static bool HandleEvent(SDL_Event& event);
|
static bool HandleEvent(SDL_Event& event);
|
||||||
#if PLATFORM_WINDOWS
|
#if PLATFORM_WINDOWS
|
||||||
static bool __cdecl EventMessageHook(void* userdata, MSG* msg);
|
static bool EventMessageHook(void* userdata, MSG* msg);
|
||||||
|
static bool SDLPlatform::EventFilterCallback(void* userdata, SDL_Event* event);
|
||||||
#elif PLATFORM_LINUX
|
#elif PLATFORM_LINUX
|
||||||
static bool __cdecl X11EventHook(void *userdata, _XEvent *xevent);
|
static bool X11EventHook(void* userdata, _XEvent* xevent);
|
||||||
#endif
|
#endif
|
||||||
|
static void PreHandleEvents();
|
||||||
|
static void PostHandleEvents();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static bool CheckWindowDragging(Window* window, WindowHitCodes hit);
|
|
||||||
#if PLATFORM_LINUX
|
#if PLATFORM_LINUX
|
||||||
static void* GetXDisplay();
|
static void* GetXDisplay();
|
||||||
#endif
|
#endif
|
||||||
|
static bool UsesWindows();
|
||||||
static bool UsesWayland();
|
static bool UsesWayland();
|
||||||
static bool UsesX11();
|
static bool UsesX11();
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#include "Engine/Input/Input.h"
|
#include "Engine/Input/Input.h"
|
||||||
#include "Engine/Input/Keyboard.h"
|
#include "Engine/Input/Keyboard.h"
|
||||||
#include "Engine/Input/Mouse.h"
|
#include "Engine/Input/Mouse.h"
|
||||||
#include "Engine/Platform/IGuiData.h"
|
|
||||||
#include "Engine/Platform/WindowsManager.h"
|
#include "Engine/Platform/WindowsManager.h"
|
||||||
|
|
||||||
#define NOGDI
|
#define NOGDI
|
||||||
@@ -26,8 +25,6 @@
|
|||||||
|
|
||||||
#if PLATFORM_WINDOWS
|
#if PLATFORM_WINDOWS
|
||||||
#include "Engine/Platform/Win32/IncludeWindowsHeaders.h"
|
#include "Engine/Platform/Win32/IncludeWindowsHeaders.h"
|
||||||
#define STYLE_RESIZABLE (WS_THICKFRAME | WS_MAXIMIZEBOX)
|
|
||||||
#define BORDERLESS_MAXIMIZE_WORKAROUND 2
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
#include <oleidl.h>
|
#include <oleidl.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -37,57 +34,44 @@
|
|||||||
|
|
||||||
#define DefaultDPI 96
|
#define DefaultDPI 96
|
||||||
|
|
||||||
namespace
|
namespace WindowImpl
|
||||||
{
|
{
|
||||||
SDLWindow* LastEventWindow = nullptr;
|
SDLWindow* LastEventWindow = nullptr;
|
||||||
static SDL_Cursor* Cursors[SDL_SYSTEM_CURSOR_COUNT] = { nullptr };
|
static SDL_Cursor* Cursors[SDL_SYSTEM_CURSOR_COUNT] = { nullptr };
|
||||||
#if BORDERLESS_MAXIMIZE_WORKAROUND == 2
|
|
||||||
int SkipMaximizeEventsCount = 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
using namespace WindowImpl;
|
||||||
|
|
||||||
void* GetNativeWindowPointer(SDL_Window* window);
|
|
||||||
SDL_HitTestResult OnWindowHitTest(SDL_Window* win, const SDL_Point* area, void* data);
|
SDL_HitTestResult OnWindowHitTest(SDL_Window* win, const SDL_Point* area, void* data);
|
||||||
void GetRelativeWindowOffset(WindowType type, SDLWindow* parentWindow, Int2& positionOffset);
|
void GetRelativeWindowOffset(WindowType type, SDLWindow* parentWindow, Int2& positionOffset);
|
||||||
Int2 GetSDLWindowScreenPosition(const SDLWindow* window);
|
Int2 GetSDLWindowScreenPosition(const SDLWindow* window);
|
||||||
void SetSDLWindowScreenPosition(const SDLWindow* window, const int x, const int y);
|
void SetSDLWindowScreenPosition(const SDLWindow* window, const Int2 position);
|
||||||
|
|
||||||
class SDLDropFilesData : public IGuiData
|
bool IsPopupWindow(WindowType type)
|
||||||
{
|
{
|
||||||
public:
|
return type == WindowType::Popup || type == WindowType::Tooltip;
|
||||||
Array<String> Files;
|
}
|
||||||
|
|
||||||
Type GetType() const override
|
void* GetNativeWindowPointer(SDL_Window* window)
|
||||||
{
|
|
||||||
return Type::Files;
|
|
||||||
}
|
|
||||||
String GetAsText() const override
|
|
||||||
{
|
|
||||||
return String::Empty;
|
|
||||||
}
|
|
||||||
void GetAsFiles(Array<String>* files) const override
|
|
||||||
{
|
|
||||||
files->Add(Files);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class SDLDropTextData : public IGuiData
|
|
||||||
{
|
{
|
||||||
public:
|
void* windowPtr;
|
||||||
StringView Text;
|
auto props = SDL_GetWindowProperties(window);
|
||||||
|
#if PLATFORM_WINDOWS
|
||||||
Type GetType() const override
|
windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr);
|
||||||
{
|
#elif PLATFORM_LINUX
|
||||||
return Type::Text;
|
windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr);
|
||||||
}
|
if (windowPtr == nullptr)
|
||||||
String GetAsText() const override
|
windowPtr = (void*)SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
|
||||||
{
|
#elif PLATFORM_MAC
|
||||||
return String(Text);
|
windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, nullptr);
|
||||||
}
|
#elif PLATFORM_ANDROID
|
||||||
void GetAsFiles(Array<String>* files) const override
|
windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_ANDROID_WINDOW_POINTER, nullptr);
|
||||||
{
|
#elif PLATFORM_IOS
|
||||||
}
|
windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_UIKIT_WINDOW_POINTER, nullptr);
|
||||||
};
|
#else
|
||||||
|
static_assert(false, "unsupported platform");
|
||||||
|
#endif
|
||||||
|
return windowPtr;
|
||||||
|
}
|
||||||
|
|
||||||
SDLWindow::SDLWindow(const CreateWindowSettings& settings)
|
SDLWindow::SDLWindow(const CreateWindowSettings& settings)
|
||||||
: WindowBase(settings)
|
: WindowBase(settings)
|
||||||
@@ -130,8 +114,8 @@ SDLWindow::SDLWindow(const CreateWindowSettings& settings)
|
|||||||
flags |= SDL_WINDOW_TRANSPARENT;
|
flags |= SDL_WINDOW_TRANSPARENT;
|
||||||
|
|
||||||
// Disable parenting of child windows as those are always on top of the parent window and never show up in taskbar
|
// Disable parenting of child windows as those are always on top of the parent window and never show up in taskbar
|
||||||
//if (_settings.Parent != nullptr && (_settings.Type != WindowType::Tooltip && _settings.Type != WindowType::Popup))
|
if (_settings.Parent != nullptr && (_settings.Type != WindowType::Tooltip && _settings.Type != WindowType::Popup))
|
||||||
// _settings.Parent = nullptr;
|
_settings.Parent = nullptr;
|
||||||
|
|
||||||
// The window position needs to be relative to the parent window
|
// The window position needs to be relative to the parent window
|
||||||
Int2 relativePosition(Math::TruncToInt(settings.Position.X), Math::TruncToInt(settings.Position.Y));
|
Int2 relativePosition(Math::TruncToInt(settings.Position.X), Math::TruncToInt(settings.Position.Y));
|
||||||
@@ -190,10 +174,6 @@ SDLWindow::SDLWindow(const CreateWindowSettings& settings)
|
|||||||
if (xdndAware != 0)
|
if (xdndAware != 0)
|
||||||
X11::XChangeProperty(xDisplay, (X11::Window)_handle, xdndAware, (X11::Atom)4, 32, PropModeReplace, (unsigned char*)&xdndVersion, 1);
|
X11::XChangeProperty(xDisplay, (X11::Window)_handle, xdndAware, (X11::Atom)4, 32, PropModeReplace, (unsigned char*)&xdndVersion, 1);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// TODO: Wayland
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -203,32 +183,10 @@ SDLWindow::SDLWindow(const CreateWindowSettings& settings)
|
|||||||
#if PLATFORM_LINUX
|
#if PLATFORM_LINUX
|
||||||
// Initialize using the shared Display instance from SDL
|
// Initialize using the shared Display instance from SDL
|
||||||
if (SDLPlatform::UsesX11() && SDLPlatform::GetXDisplay() == nullptr)
|
if (SDLPlatform::UsesX11() && SDLPlatform::GetXDisplay() == nullptr)
|
||||||
SDLPlatform::InitPlatformX11(GetX11Display());
|
SDLPlatform::InitX11(GetX11Display());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void* GetNativeWindowPointer(SDL_Window* window)
|
|
||||||
{
|
|
||||||
void* windowPtr;
|
|
||||||
auto props = SDL_GetWindowProperties(window);
|
|
||||||
#if PLATFORM_WINDOWS
|
|
||||||
windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr);
|
|
||||||
#elif PLATFORM_LINUX
|
|
||||||
windowPtr = SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr);
|
|
||||||
if (windowPtr == nullptr)
|
|
||||||
windowPtr = (void*)SDL_GetNumberProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
|
|
||||||
#elif PLATFORM_MAC
|
|
||||||
windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, nullptr);
|
|
||||||
#elif PLATFORM_ANDROID
|
|
||||||
windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_ANDROID_WINDOW_POINTER, nullptr);
|
|
||||||
#elif PLATFORM_IOS
|
|
||||||
windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_UIKIT_WINDOW_POINTER, nullptr);
|
|
||||||
#else
|
|
||||||
static_assert(false, "unsupported platform");
|
|
||||||
#endif
|
|
||||||
return windowPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
SDL_Window* SDLWindow::GetSDLWindow() const
|
SDL_Window* SDLWindow::GetSDLWindow() const
|
||||||
{
|
{
|
||||||
return _window;
|
return _window;
|
||||||
@@ -265,7 +223,7 @@ SDLWindow::~SDLWindow()
|
|||||||
|
|
||||||
if (_window == nullptr)
|
if (_window == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SDL_StopTextInput(_window);
|
SDL_StopTextInput(_window);
|
||||||
SDL_DestroyWindow(_window);
|
SDL_DestroyWindow(_window);
|
||||||
|
|
||||||
@@ -366,6 +324,10 @@ void SDLWindow::HandleEvent(SDL_Event& event)
|
|||||||
if (_isClosing)
|
if (_isClosing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Platform specific event handling
|
||||||
|
if (HandleEventInternal(event))
|
||||||
|
return;
|
||||||
|
|
||||||
switch (event.type)
|
switch (event.type)
|
||||||
{
|
{
|
||||||
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
||||||
@@ -375,16 +337,6 @@ void SDLWindow::HandleEvent(SDL_Event& event)
|
|||||||
}
|
}
|
||||||
case SDL_EVENT_WINDOW_DESTROYED:
|
case SDL_EVENT_WINDOW_DESTROYED:
|
||||||
{
|
{
|
||||||
#if USE_EDITOR && PLATFORM_WINDOWS
|
|
||||||
// Disable file dropping
|
|
||||||
if (_settings.AllowDragAndDrop)
|
|
||||||
{
|
|
||||||
const auto result = RevokeDragDrop((HWND)_handle);
|
|
||||||
if (result != S_OK)
|
|
||||||
LOG(Warning, "Window drag and drop service error: 0x{0:x}:{1}", result, 2);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Quit
|
// Quit
|
||||||
#if PLATFORM_WINDOWS
|
#if PLATFORM_WINDOWS
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
@@ -413,16 +365,6 @@ void SDLWindow::HandleEvent(SDL_Event& event)
|
|||||||
case SDL_EVENT_WINDOW_MOVED:
|
case SDL_EVENT_WINDOW_MOVED:
|
||||||
{
|
{
|
||||||
_cachedClientRectangle.Location = Float2(static_cast<float>(event.window.data1), static_cast<float>(event.window.data2));
|
_cachedClientRectangle.Location = Float2(static_cast<float>(event.window.data1), static_cast<float>(event.window.data2));
|
||||||
#if PLATFORM_LINUX
|
|
||||||
if (SDLPlatform::UsesX11())
|
|
||||||
{
|
|
||||||
// X11 doesn't report any mouse events when mouse is over the caption area, send a simulated event instead...
|
|
||||||
Float2 mousePosition;
|
|
||||||
auto buttons = SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y);
|
|
||||||
if ((buttons & SDL_BUTTON_MASK(SDL_BUTTON_LEFT)) != 0)
|
|
||||||
SDLPlatform::CheckWindowDragging(this, WindowHitCodes::Caption);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case SDL_EVENT_WINDOW_HIT_TEST:
|
case SDL_EVENT_WINDOW_HIT_TEST:
|
||||||
@@ -440,46 +382,11 @@ void SDLWindow::HandleEvent(SDL_Event& event)
|
|||||||
_minimized = false;
|
_minimized = false;
|
||||||
_maximized = true;
|
_maximized = true;
|
||||||
|
|
||||||
#if PLATFORM_WINDOWS && BORDERLESS_MAXIMIZE_WORKAROUND == 2
|
|
||||||
if (SkipMaximizeEventsCount > 0)
|
|
||||||
{
|
|
||||||
SkipMaximizeEventsCount--;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_settings.HasBorder && _settings.HasSizingFrame)
|
|
||||||
{
|
|
||||||
// Restore the window back to previous state
|
|
||||||
SDL_RestoreWindow(_window);
|
|
||||||
|
|
||||||
// Remove the resizable flags from borderless windows and maximize the window again
|
|
||||||
auto style = ::GetWindowLong((HWND)_handle, GWL_STYLE);
|
|
||||||
style &= ~STYLE_RESIZABLE;
|
|
||||||
::SetWindowLong((HWND)_handle, GWL_STYLE, style);
|
|
||||||
|
|
||||||
SDL_MaximizeWindow(_window);
|
|
||||||
|
|
||||||
// Re-enable the resizable borderless flags
|
|
||||||
style = ::GetWindowLong((HWND)_handle, GWL_STYLE) | STYLE_RESIZABLE;
|
|
||||||
::SetWindowLong((HWND)_handle, GWL_STYLE, style);
|
|
||||||
|
|
||||||
// The next SDL_EVENT_WINDOW_RESTORED and SDL_EVENT_WINDOW_MAXIMIZED events should be ignored
|
|
||||||
SkipMaximizeEventsCount = 2;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
CheckForWindowResize();
|
CheckForWindowResize();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case SDL_EVENT_WINDOW_RESTORED:
|
case SDL_EVENT_WINDOW_RESTORED:
|
||||||
{
|
{
|
||||||
#if BORDERLESS_MAXIMIZE_WORKAROUND == 2
|
|
||||||
if (SkipMaximizeEventsCount > 0)
|
|
||||||
{
|
|
||||||
SkipMaximizeEventsCount--;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (_maximized)
|
if (_maximized)
|
||||||
{
|
{
|
||||||
_maximized = false;
|
_maximized = false;
|
||||||
@@ -543,68 +450,6 @@ void SDLWindow::HandleEvent(SDL_Event& event)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#if false
|
|
||||||
case SDL_EVENT_DROP_BEGIN:
|
|
||||||
{
|
|
||||||
Focus();
|
|
||||||
Float2 mousePosition;
|
|
||||||
SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y);
|
|
||||||
mousePosition = ScreenToClient(mousePosition);
|
|
||||||
|
|
||||||
DragDropEffect effect;
|
|
||||||
SDLDropTextData dropData;
|
|
||||||
OnDragEnter(&dropData, mousePosition, effect);
|
|
||||||
OnDragOver(&dropData, mousePosition, effect);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case SDL_EVENT_DROP_POSITION:
|
|
||||||
{
|
|
||||||
DragDropEffect effect = DragDropEffect::None;
|
|
||||||
|
|
||||||
SDLDropTextData dropData;
|
|
||||||
OnDragOver(&dropData, Float2(static_cast<float>(event.drop.x), static_cast<float>(event.drop.y)), effect);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case SDL_EVENT_DROP_FILE:
|
|
||||||
{
|
|
||||||
SDLDropFilesData dropData;
|
|
||||||
dropData.Files.Add(StringAnsi(event.drop.data).ToString()); // TODO: collect multiple files at once?
|
|
||||||
|
|
||||||
Focus();
|
|
||||||
|
|
||||||
Float2 mousePosition;
|
|
||||||
SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y);
|
|
||||||
mousePosition = ScreenToClient(mousePosition);
|
|
||||||
DragDropEffect effect = DragDropEffect::None;
|
|
||||||
OnDragDrop(&dropData, mousePosition, effect);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case SDL_EVENT_DROP_TEXT:
|
|
||||||
{
|
|
||||||
SDLDropTextData dropData;
|
|
||||||
String str = StringAnsi(event.drop.data).ToString();
|
|
||||||
dropData.Text = StringView(str);
|
|
||||||
|
|
||||||
Focus();
|
|
||||||
Float2 mousePosition;
|
|
||||||
SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y);
|
|
||||||
mousePosition = ScreenToClient(mousePosition);
|
|
||||||
DragDropEffect effect = DragDropEffect::None;
|
|
||||||
OnDragDrop(&dropData, mousePosition, effect);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case SDL_EVENT_DROP_COMPLETE:
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
|
|
||||||
{
|
|
||||||
#if !PLATFORM_WINDOWS
|
|
||||||
OnDragLeave(); // Check for release of mouse button too?
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -639,9 +484,9 @@ void SDLWindow::Show()
|
|||||||
else if (_settings.Parent == nullptr)
|
else if (_settings.Parent == nullptr)
|
||||||
BringToFront();
|
BringToFront();
|
||||||
|
|
||||||
// Reused top-most windows (DockHintWindow) doesn't stay on top for some reason
|
// Reused top-most windows doesn't stay on top for some reason
|
||||||
if (_settings.IsTopmost && _settings.Type != WindowType::Tooltip)
|
if (_settings.IsTopmost && !IsPopupWindow(_settings.Type))
|
||||||
SDL_SetWindowAlwaysOnTop(_window, true);
|
SetIsAlwaysOnTop(true);
|
||||||
|
|
||||||
if (_isTrackingMouse)
|
if (_isTrackingMouse)
|
||||||
{
|
{
|
||||||
@@ -678,19 +523,7 @@ void SDLWindow::Maximize()
|
|||||||
if (!_settings.AllowMaximize)
|
if (!_settings.AllowMaximize)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if PLATFORM_WINDOWS && BORDERLESS_MAXIMIZE_WORKAROUND == 1
|
|
||||||
// Workaround for "SDL_BORDERLESS_RESIZABLE_STYLE" hint not working as expected when maximizing windows
|
|
||||||
auto style = ::GetWindowLong((HWND)_handle, GWL_STYLE);
|
|
||||||
style &= ~STYLE_RESIZABLE;
|
|
||||||
::SetWindowLong((HWND)_handle, GWL_STYLE, style);
|
|
||||||
|
|
||||||
SDL_MaximizeWindow(_window);
|
SDL_MaximizeWindow(_window);
|
||||||
|
|
||||||
style = ::GetWindowLong((HWND)_handle, GWL_STYLE) | STYLE_RESIZABLE;
|
|
||||||
::SetWindowLong((HWND)_handle, GWL_STYLE, style);
|
|
||||||
#else
|
|
||||||
SDL_MaximizeWindow(_window);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLWindow::SetBorderless(bool isBorderless, bool maximized)
|
void SDLWindow::SetBorderless(bool isBorderless, bool maximized)
|
||||||
@@ -706,45 +539,18 @@ void SDLWindow::SetBorderless(bool isBorderless, bool maximized)
|
|||||||
|
|
||||||
BringToFront();
|
BringToFront();
|
||||||
|
|
||||||
if (isBorderless)
|
SDL_SetWindowBordered(_window, !isBorderless ? true : false);
|
||||||
{
|
if (maximized)
|
||||||
SDL_SetWindowBordered(_window, !isBorderless ? true : false);
|
Maximize();
|
||||||
if (maximized)
|
|
||||||
{
|
|
||||||
Maximize();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Focus();
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
Focus();
|
||||||
SDL_SetWindowBordered(_window, !isBorderless ? true : false);
|
|
||||||
if (maximized)
|
|
||||||
{
|
|
||||||
Maximize();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Focus();
|
|
||||||
}
|
|
||||||
|
|
||||||
CheckForWindowResize();
|
CheckForWindowResize();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLWindow::Restore()
|
void SDLWindow::Restore()
|
||||||
{
|
{
|
||||||
#if PLATFORM_WINDOWS && BORDERLESS_MAXIMIZE_WORKAROUND == 1
|
|
||||||
// Workaround for "SDL_BORDERLESS_RESIZABLE_STYLE" hint not working as expected when maximizing windows
|
|
||||||
auto style = ::GetWindowLong((HWND)_handle, GWL_STYLE);
|
|
||||||
style &= ~STYLE_RESIZABLE;
|
|
||||||
::SetWindowLong((HWND)_handle, GWL_STYLE, style);
|
|
||||||
|
|
||||||
SDL_RestoreWindow(_window);
|
SDL_RestoreWindow(_window);
|
||||||
|
|
||||||
style = ::GetWindowLong((HWND)_handle, GWL_STYLE) | STYLE_RESIZABLE;
|
|
||||||
::SetWindowLong((HWND)_handle, GWL_STYLE, style);
|
|
||||||
#else
|
|
||||||
SDL_RestoreWindow(_window);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SDLWindow::IsClosed() const
|
bool SDLWindow::IsClosed() const
|
||||||
@@ -760,28 +566,19 @@ bool SDLWindow::IsForegroundWindow() const
|
|||||||
|
|
||||||
void SDLWindow::BringToFront(bool force)
|
void SDLWindow::BringToFront(bool force)
|
||||||
{
|
{
|
||||||
auto activateWhenRaised = SDL_GetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED);
|
|
||||||
SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, "0");
|
|
||||||
SDL_RaiseWindow(_window);
|
SDL_RaiseWindow(_window);
|
||||||
SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, activateWhenRaised);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLWindow::SetClientBounds(const Rectangle& clientArea)
|
void SDLWindow::SetClientBounds(const Rectangle& clientArea)
|
||||||
{
|
{
|
||||||
int newX = static_cast<int>(clientArea.GetLeft());
|
Int2 newPos = Int2(clientArea.GetTopLeft());
|
||||||
int newY = static_cast<int>(clientArea.GetTop());
|
|
||||||
int newW = static_cast<int>(clientArea.GetWidth());
|
int newW = static_cast<int>(clientArea.GetWidth());
|
||||||
int newH = static_cast<int>(clientArea.GetHeight());
|
int newH = static_cast<int>(clientArea.GetHeight());
|
||||||
|
|
||||||
SetSDLWindowScreenPosition(this, newX, newY);
|
SetSDLWindowScreenPosition(this, newPos);
|
||||||
SDL_SetWindowSize(_window, newW, newH);
|
SDL_SetWindowSize(_window, newW, newH);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsPopupWindow(WindowType type)
|
|
||||||
{
|
|
||||||
return type == WindowType::Popup || type == WindowType::Tooltip;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetRelativeWindowOffset(WindowType type, SDLWindow* parentWindow, Int2& positionOffset)
|
void GetRelativeWindowOffset(WindowType type, SDLWindow* parentWindow, Int2& positionOffset)
|
||||||
{
|
{
|
||||||
if (!IsPopupWindow(type))
|
if (!IsPopupWindow(type))
|
||||||
@@ -812,9 +609,9 @@ Int2 GetSDLWindowScreenPosition(const SDLWindow* window)
|
|||||||
return position - relativeOffset;
|
return position - relativeOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetSDLWindowScreenPosition(const SDLWindow* window, const int x, const int y)
|
void SetSDLWindowScreenPosition(const SDLWindow* window, const Int2 position)
|
||||||
{
|
{
|
||||||
Int2 relativePosition(x, y);
|
Int2 relativePosition = position;
|
||||||
GetRelativeWindowOffset(window->GetSettings().Type, window->GetSettings().Parent, relativePosition);
|
GetRelativeWindowOffset(window->GetSettings().Type, window->GetSettings().Parent, relativePosition);
|
||||||
SDL_SetWindowPosition(window->GetSDLWindow(), relativePosition.X, relativePosition.Y);
|
SDL_SetWindowPosition(window->GetSDLWindow(), relativePosition.X, relativePosition.Y);
|
||||||
}
|
}
|
||||||
@@ -834,12 +631,12 @@ void SDLWindow::SetPosition(const Float2& position)
|
|||||||
screenPosition += Int2(monitorBounds.GetTopLeft());
|
screenPosition += Int2(monitorBounds.GetTopLeft());
|
||||||
}
|
}
|
||||||
|
|
||||||
SetSDLWindowScreenPosition(this, screenPosition.X, screenPosition.Y);
|
SetSDLWindowScreenPosition(this, screenPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLWindow::SetClientPosition(const Float2& position)
|
void SDLWindow::SetClientPosition(const Float2& position)
|
||||||
{
|
{
|
||||||
SetSDLWindowScreenPosition(this, static_cast<int>(position.X), static_cast<int>(position.Y));
|
SetSDLWindowScreenPosition(this, Int2(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLWindow::SetIsFullscreen(bool isFullscreen)
|
void SDLWindow::SetIsFullscreen(bool isFullscreen)
|
||||||
@@ -848,7 +645,7 @@ void SDLWindow::SetIsFullscreen(bool isFullscreen)
|
|||||||
if (!isFullscreen)
|
if (!isFullscreen)
|
||||||
{
|
{
|
||||||
// The window is set to always-on-top for some reason when leaving fullscreen
|
// The window is set to always-on-top for some reason when leaving fullscreen
|
||||||
SDL_SetWindowAlwaysOnTop(_window, false);
|
SetIsAlwaysOnTop(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowBase::SetIsFullscreen(isFullscreen);
|
WindowBase::SetIsFullscreen(isFullscreen);
|
||||||
@@ -930,25 +727,15 @@ void SDLWindow::SetOpacity(const float opacity)
|
|||||||
LOG(Warning, "SDL_SetWindowOpacity failed: {0}", String(SDL_GetError()));
|
LOG(Warning, "SDL_SetWindowOpacity failed: {0}", String(SDL_GetError()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !PLATFORM_WINDOWS
|
||||||
|
|
||||||
void SDLWindow::Focus()
|
void SDLWindow::Focus()
|
||||||
{
|
{
|
||||||
#if PLATFORM_WINDOWS
|
|
||||||
auto activateWhenRaised = SDL_GetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED);
|
|
||||||
SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, "1");
|
|
||||||
|
|
||||||
// Forcing the window to focus causes issues with opening context menus while window is maximized
|
|
||||||
//auto forceRaiseWindow = SDL_GetHint(SDL_HINT_FORCE_RAISEWINDOW);
|
|
||||||
//SDL_SetHint(SDL_HINT_FORCE_RAISEWINDOW, "1");
|
|
||||||
|
|
||||||
SDL_RaiseWindow(_window);
|
SDL_RaiseWindow(_window);
|
||||||
|
|
||||||
SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, activateWhenRaised);
|
|
||||||
//SDL_SetHint(SDL_HINT_FORCE_RAISEWINDOW, forceRaiseWindow);
|
|
||||||
#else
|
|
||||||
SDL_RaiseWindow(_window);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
String SDLWindow::GetTitle() const
|
String SDLWindow::GetTitle() const
|
||||||
{
|
{
|
||||||
return String(SDL_GetWindowTitle(_window));
|
return String(SDL_GetWindowTitle(_window));
|
||||||
|
|||||||
@@ -57,11 +57,12 @@ private:
|
|||||||
static SDLWindow* GetWindowFromEvent(const SDL_Event& event);
|
static SDLWindow* GetWindowFromEvent(const SDL_Event& event);
|
||||||
static SDLWindow* GetWindowWithSDLWindow(SDL_Window* window);
|
static SDLWindow* GetWindowWithSDLWindow(SDL_Window* window);
|
||||||
void HandleEvent(SDL_Event& event);
|
void HandleEvent(SDL_Event& event);
|
||||||
|
bool HandleEventInternal(SDL_Event& event);
|
||||||
void CheckForWindowResize();
|
void CheckForWindowResize();
|
||||||
void UpdateCursor();
|
void UpdateCursor();
|
||||||
|
|
||||||
#if PLATFORM_LINUX
|
#if PLATFORM_LINUX
|
||||||
DragDropEffect DoDragDropWayland(const StringView& data);
|
DragDropEffect DoDragDropWayland(const StringView& data, Window* dragSourceWindow = nullptr, Float2 dragOffset = Float2::Zero);
|
||||||
DragDropEffect DoDragDropX11(const StringView& data);
|
DragDropEffect DoDragDropX11(const StringView& data);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -104,6 +105,7 @@ public:
|
|||||||
String GetTitle() const override;
|
String GetTitle() const override;
|
||||||
void SetTitle(const StringView& title) override;
|
void SetTitle(const StringView& title) override;
|
||||||
DragDropEffect DoDragDrop(const StringView& data) override;
|
DragDropEffect DoDragDrop(const StringView& data) override;
|
||||||
|
DragDropEffect DoDragDrop(const StringView& data, const Float2& offset, Window* dragSourceWindow) override;
|
||||||
void StartTrackingMouse(bool useMouseScreenOffset) override;
|
void StartTrackingMouse(bool useMouseScreenOffset) override;
|
||||||
void EndTrackingMouse() override;
|
void EndTrackingMouse() override;
|
||||||
void StartClippingCursor(const Rectangle& bounds) override;
|
void StartClippingCursor(const Rectangle& bounds) override;
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ namespace FlaxEngine.GUI
|
|||||||
var rightBottomLocationSS = locationSS + dpiSize;
|
var rightBottomLocationSS = locationSS + dpiSize;
|
||||||
|
|
||||||
// Prioritize tooltip placement within parent window, fall back to virtual desktop
|
// Prioritize tooltip placement within parent window, fall back to virtual desktop
|
||||||
if (rightBottomMonitorBounds.Y < rightBottomLocationSS.Y)
|
/*if (rightBottomMonitorBounds.Y < rightBottomLocationSS.Y)
|
||||||
{
|
{
|
||||||
// Direction: up
|
// Direction: up
|
||||||
locationSS.Y -= dpiSize.Y + flipOffset;
|
locationSS.Y -= dpiSize.Y + flipOffset;
|
||||||
@@ -216,7 +216,7 @@ namespace FlaxEngine.GUI
|
|||||||
{
|
{
|
||||||
// Direction: left
|
// Direction: left
|
||||||
locationSS.X -= dpiSize.X + flipOffset * 2;
|
locationSS.X -= dpiSize.X + flipOffset * 2;
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
2
Source/ThirdParty/Wayland/Wayland.Build.cs
vendored
2
Source/ThirdParty/Wayland/Wayland.Build.cs
vendored
@@ -32,6 +32,6 @@ public class Wayland : ThirdPartyModule
|
|||||||
|
|
||||||
// Include generated protocol files for dependency
|
// Include generated protocol files for dependency
|
||||||
options.PublicIncludePaths.Add(Path.Combine(FolderPath, "include"));
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2325
Source/ThirdParty/Wayland/include/wayland/xdg-shell.h
vendored
Normal file
2325
Source/ThirdParty/Wayland/include/wayland/xdg-shell.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
320
Source/ThirdParty/Wayland/include/wayland/xdg-toplevel-drag-v1.h
vendored
Normal file
320
Source/ThirdParty/Wayland/include/wayland/xdg-toplevel-drag-v1.h
vendored
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
/* Generated by wayland-scanner 1.23.1 */
|
||||||
|
|
||||||
|
#ifndef XDG_TOPLEVEL_DRAG_V1_CLIENT_PROTOCOL_H
|
||||||
|
#define XDG_TOPLEVEL_DRAG_V1_CLIENT_PROTOCOL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "wayland-client.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @page page_xdg_toplevel_drag_v1 The xdg_toplevel_drag_v1 protocol
|
||||||
|
* @section page_ifaces_xdg_toplevel_drag_v1 Interfaces
|
||||||
|
* - @subpage page_iface_xdg_toplevel_drag_manager_v1 - Move a window during a drag
|
||||||
|
* - @subpage page_iface_xdg_toplevel_drag_v1 - Object representing a toplevel move during a drag
|
||||||
|
* @section page_copyright_xdg_toplevel_drag_v1 Copyright
|
||||||
|
* <pre>
|
||||||
|
*
|
||||||
|
* Copyright 2023 David Redondo
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
struct wl_data_source;
|
||||||
|
struct xdg_toplevel;
|
||||||
|
struct xdg_toplevel_drag_manager_v1;
|
||||||
|
struct xdg_toplevel_drag_v1;
|
||||||
|
|
||||||
|
#ifndef XDG_TOPLEVEL_DRAG_MANAGER_V1_INTERFACE
|
||||||
|
#define XDG_TOPLEVEL_DRAG_MANAGER_V1_INTERFACE
|
||||||
|
/**
|
||||||
|
* @page page_iface_xdg_toplevel_drag_manager_v1 xdg_toplevel_drag_manager_v1
|
||||||
|
* @section page_iface_xdg_toplevel_drag_manager_v1_desc Description
|
||||||
|
*
|
||||||
|
* This protocol enhances normal drag and drop with the ability to move a
|
||||||
|
* window at the same time. This allows having detachable parts of a window
|
||||||
|
* that when dragged out of it become a new window and can be dragged over
|
||||||
|
* an existing window to be reattached.
|
||||||
|
*
|
||||||
|
* A typical workflow would be when the user starts dragging on top of a
|
||||||
|
* detachable part of a window, the client would create a wl_data_source and
|
||||||
|
* a xdg_toplevel_drag_v1 object and start the drag as normal via
|
||||||
|
* wl_data_device.start_drag. Once the client determines that the detachable
|
||||||
|
* window contents should be detached from the originating window, it creates
|
||||||
|
* a new xdg_toplevel with these contents and issues a
|
||||||
|
* xdg_toplevel_drag_v1.attach request before mapping it. From now on the new
|
||||||
|
* window is moved by the compositor during the drag as if the client called
|
||||||
|
* xdg_toplevel.move.
|
||||||
|
*
|
||||||
|
* Dragging an existing window is similar. The client creates a
|
||||||
|
* xdg_toplevel_drag_v1 object and attaches the existing toplevel before
|
||||||
|
* starting the drag.
|
||||||
|
*
|
||||||
|
* Clients use the existing drag and drop mechanism to detect when a window
|
||||||
|
* can be docked or undocked. If the client wants to snap a window into a
|
||||||
|
* parent window it should delete or unmap the dragged top-level. If the
|
||||||
|
* contents should be detached again it attaches a new toplevel as described
|
||||||
|
* above. If a drag operation is cancelled without being dropped, clients
|
||||||
|
* should revert to the previous state, deleting any newly created windows
|
||||||
|
* as appropriate. When a drag operation ends as indicated by
|
||||||
|
* wl_data_source.dnd_drop_performed the dragged toplevel window's final
|
||||||
|
* position is determined as if a xdg_toplevel_move operation ended.
|
||||||
|
*
|
||||||
|
* Warning! The protocol described in this file is currently in the testing
|
||||||
|
* phase. Backward compatible changes may be added together with the
|
||||||
|
* corresponding interface version bump. Backward incompatible changes can
|
||||||
|
* only be done by creating a new major version of the extension.
|
||||||
|
* @section page_iface_xdg_toplevel_drag_manager_v1_api API
|
||||||
|
* See @ref iface_xdg_toplevel_drag_manager_v1.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @defgroup iface_xdg_toplevel_drag_manager_v1 The xdg_toplevel_drag_manager_v1 interface
|
||||||
|
*
|
||||||
|
* This protocol enhances normal drag and drop with the ability to move a
|
||||||
|
* window at the same time. This allows having detachable parts of a window
|
||||||
|
* that when dragged out of it become a new window and can be dragged over
|
||||||
|
* an existing window to be reattached.
|
||||||
|
*
|
||||||
|
* A typical workflow would be when the user starts dragging on top of a
|
||||||
|
* detachable part of a window, the client would create a wl_data_source and
|
||||||
|
* a xdg_toplevel_drag_v1 object and start the drag as normal via
|
||||||
|
* wl_data_device.start_drag. Once the client determines that the detachable
|
||||||
|
* window contents should be detached from the originating window, it creates
|
||||||
|
* a new xdg_toplevel with these contents and issues a
|
||||||
|
* xdg_toplevel_drag_v1.attach request before mapping it. From now on the new
|
||||||
|
* window is moved by the compositor during the drag as if the client called
|
||||||
|
* xdg_toplevel.move.
|
||||||
|
*
|
||||||
|
* Dragging an existing window is similar. The client creates a
|
||||||
|
* xdg_toplevel_drag_v1 object and attaches the existing toplevel before
|
||||||
|
* starting the drag.
|
||||||
|
*
|
||||||
|
* Clients use the existing drag and drop mechanism to detect when a window
|
||||||
|
* can be docked or undocked. If the client wants to snap a window into a
|
||||||
|
* parent window it should delete or unmap the dragged top-level. If the
|
||||||
|
* contents should be detached again it attaches a new toplevel as described
|
||||||
|
* above. If a drag operation is cancelled without being dropped, clients
|
||||||
|
* should revert to the previous state, deleting any newly created windows
|
||||||
|
* as appropriate. When a drag operation ends as indicated by
|
||||||
|
* wl_data_source.dnd_drop_performed the dragged toplevel window's final
|
||||||
|
* position is determined as if a xdg_toplevel_move operation ended.
|
||||||
|
*
|
||||||
|
* Warning! The protocol described in this file is currently in the testing
|
||||||
|
* phase. Backward compatible changes may be added together with the
|
||||||
|
* corresponding interface version bump. Backward incompatible changes can
|
||||||
|
* only be done by creating a new major version of the extension.
|
||||||
|
*/
|
||||||
|
extern const struct wl_interface xdg_toplevel_drag_manager_v1_interface;
|
||||||
|
#endif
|
||||||
|
#ifndef XDG_TOPLEVEL_DRAG_V1_INTERFACE
|
||||||
|
#define XDG_TOPLEVEL_DRAG_V1_INTERFACE
|
||||||
|
/**
|
||||||
|
* @page page_iface_xdg_toplevel_drag_v1 xdg_toplevel_drag_v1
|
||||||
|
* @section page_iface_xdg_toplevel_drag_v1_desc Description
|
||||||
|
*
|
||||||
|
* @section page_iface_xdg_toplevel_drag_v1_api API
|
||||||
|
* See @ref iface_xdg_toplevel_drag_v1.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @defgroup iface_xdg_toplevel_drag_v1 The xdg_toplevel_drag_v1 interface
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
extern const struct wl_interface xdg_toplevel_drag_v1_interface;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef XDG_TOPLEVEL_DRAG_MANAGER_V1_ERROR_ENUM
|
||||||
|
#define XDG_TOPLEVEL_DRAG_MANAGER_V1_ERROR_ENUM
|
||||||
|
enum xdg_toplevel_drag_manager_v1_error {
|
||||||
|
/**
|
||||||
|
* data_source already used for toplevel drag
|
||||||
|
*/
|
||||||
|
XDG_TOPLEVEL_DRAG_MANAGER_V1_ERROR_INVALID_SOURCE = 0,
|
||||||
|
};
|
||||||
|
#endif /* XDG_TOPLEVEL_DRAG_MANAGER_V1_ERROR_ENUM */
|
||||||
|
|
||||||
|
#define XDG_TOPLEVEL_DRAG_MANAGER_V1_DESTROY 0
|
||||||
|
#define XDG_TOPLEVEL_DRAG_MANAGER_V1_GET_XDG_TOPLEVEL_DRAG 1
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup iface_xdg_toplevel_drag_manager_v1
|
||||||
|
*/
|
||||||
|
#define XDG_TOPLEVEL_DRAG_MANAGER_V1_DESTROY_SINCE_VERSION 1
|
||||||
|
/**
|
||||||
|
* @ingroup iface_xdg_toplevel_drag_manager_v1
|
||||||
|
*/
|
||||||
|
#define XDG_TOPLEVEL_DRAG_MANAGER_V1_GET_XDG_TOPLEVEL_DRAG_SINCE_VERSION 1
|
||||||
|
|
||||||
|
/** @ingroup iface_xdg_toplevel_drag_manager_v1 */
|
||||||
|
static inline void
|
||||||
|
xdg_toplevel_drag_manager_v1_set_user_data(struct xdg_toplevel_drag_manager_v1 *xdg_toplevel_drag_manager_v1, void *user_data)
|
||||||
|
{
|
||||||
|
wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel_drag_manager_v1, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @ingroup iface_xdg_toplevel_drag_manager_v1 */
|
||||||
|
static inline void *
|
||||||
|
xdg_toplevel_drag_manager_v1_get_user_data(struct xdg_toplevel_drag_manager_v1 *xdg_toplevel_drag_manager_v1)
|
||||||
|
{
|
||||||
|
return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel_drag_manager_v1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t
|
||||||
|
xdg_toplevel_drag_manager_v1_get_version(struct xdg_toplevel_drag_manager_v1 *xdg_toplevel_drag_manager_v1)
|
||||||
|
{
|
||||||
|
return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel_drag_manager_v1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup iface_xdg_toplevel_drag_manager_v1
|
||||||
|
*
|
||||||
|
* Destroy this xdg_toplevel_drag_manager_v1 object. Other objects,
|
||||||
|
* including xdg_toplevel_drag_v1 objects created by this factory, are not
|
||||||
|
* affected by this request.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
xdg_toplevel_drag_manager_v1_destroy(struct xdg_toplevel_drag_manager_v1 *xdg_toplevel_drag_manager_v1)
|
||||||
|
{
|
||||||
|
wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel_drag_manager_v1,
|
||||||
|
XDG_TOPLEVEL_DRAG_MANAGER_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel_drag_manager_v1), WL_MARSHAL_FLAG_DESTROY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup iface_xdg_toplevel_drag_manager_v1
|
||||||
|
*
|
||||||
|
* Create an xdg_toplevel_drag for a drag and drop operation that is going
|
||||||
|
* to be started with data_source.
|
||||||
|
*
|
||||||
|
* This request can only be made on sources used in drag-and-drop, so it
|
||||||
|
* must be performed before wl_data_device.start_drag. Attempting to use
|
||||||
|
* the source other than for drag-and-drop such as in
|
||||||
|
* wl_data_device.set_selection will raise an invalid_source error.
|
||||||
|
*
|
||||||
|
* Destroying data_source while a toplevel is attached to the
|
||||||
|
* xdg_toplevel_drag is undefined.
|
||||||
|
*/
|
||||||
|
static inline struct xdg_toplevel_drag_v1 *
|
||||||
|
xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag(struct xdg_toplevel_drag_manager_v1 *xdg_toplevel_drag_manager_v1, struct wl_data_source *data_source)
|
||||||
|
{
|
||||||
|
struct wl_proxy *id;
|
||||||
|
|
||||||
|
id = wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel_drag_manager_v1,
|
||||||
|
XDG_TOPLEVEL_DRAG_MANAGER_V1_GET_XDG_TOPLEVEL_DRAG, &xdg_toplevel_drag_v1_interface, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel_drag_manager_v1), 0, NULL, data_source);
|
||||||
|
|
||||||
|
return (struct xdg_toplevel_drag_v1 *) id;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef XDG_TOPLEVEL_DRAG_V1_ERROR_ENUM
|
||||||
|
#define XDG_TOPLEVEL_DRAG_V1_ERROR_ENUM
|
||||||
|
enum xdg_toplevel_drag_v1_error {
|
||||||
|
/**
|
||||||
|
* valid toplevel already attached
|
||||||
|
*/
|
||||||
|
XDG_TOPLEVEL_DRAG_V1_ERROR_TOPLEVEL_ATTACHED = 0,
|
||||||
|
/**
|
||||||
|
* drag has not ended
|
||||||
|
*/
|
||||||
|
XDG_TOPLEVEL_DRAG_V1_ERROR_ONGOING_DRAG = 1,
|
||||||
|
};
|
||||||
|
#endif /* XDG_TOPLEVEL_DRAG_V1_ERROR_ENUM */
|
||||||
|
|
||||||
|
#define XDG_TOPLEVEL_DRAG_V1_DESTROY 0
|
||||||
|
#define XDG_TOPLEVEL_DRAG_V1_ATTACH 1
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup iface_xdg_toplevel_drag_v1
|
||||||
|
*/
|
||||||
|
#define XDG_TOPLEVEL_DRAG_V1_DESTROY_SINCE_VERSION 1
|
||||||
|
/**
|
||||||
|
* @ingroup iface_xdg_toplevel_drag_v1
|
||||||
|
*/
|
||||||
|
#define XDG_TOPLEVEL_DRAG_V1_ATTACH_SINCE_VERSION 1
|
||||||
|
|
||||||
|
/** @ingroup iface_xdg_toplevel_drag_v1 */
|
||||||
|
static inline void
|
||||||
|
xdg_toplevel_drag_v1_set_user_data(struct xdg_toplevel_drag_v1 *xdg_toplevel_drag_v1, void *user_data)
|
||||||
|
{
|
||||||
|
wl_proxy_set_user_data((struct wl_proxy *) xdg_toplevel_drag_v1, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @ingroup iface_xdg_toplevel_drag_v1 */
|
||||||
|
static inline void *
|
||||||
|
xdg_toplevel_drag_v1_get_user_data(struct xdg_toplevel_drag_v1 *xdg_toplevel_drag_v1)
|
||||||
|
{
|
||||||
|
return wl_proxy_get_user_data((struct wl_proxy *) xdg_toplevel_drag_v1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t
|
||||||
|
xdg_toplevel_drag_v1_get_version(struct xdg_toplevel_drag_v1 *xdg_toplevel_drag_v1)
|
||||||
|
{
|
||||||
|
return wl_proxy_get_version((struct wl_proxy *) xdg_toplevel_drag_v1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup iface_xdg_toplevel_drag_v1
|
||||||
|
*
|
||||||
|
* Destroy this xdg_toplevel_drag_v1 object. This request must only be
|
||||||
|
* called after the underlying wl_data_source drag has ended, as indicated
|
||||||
|
* by the dnd_drop_performed or cancelled events. In any other case an
|
||||||
|
* ongoing_drag error is raised.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
xdg_toplevel_drag_v1_destroy(struct xdg_toplevel_drag_v1 *xdg_toplevel_drag_v1)
|
||||||
|
{
|
||||||
|
wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel_drag_v1,
|
||||||
|
XDG_TOPLEVEL_DRAG_V1_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel_drag_v1), WL_MARSHAL_FLAG_DESTROY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup iface_xdg_toplevel_drag_v1
|
||||||
|
*
|
||||||
|
* Request that the window will be moved with the cursor during the drag
|
||||||
|
* operation. The offset is a hint to the compositor how the toplevel
|
||||||
|
* should be positioned relative to the cursor hotspot in surface local
|
||||||
|
* coordinates and relative to the geometry of the toplevel being attached.
|
||||||
|
* See xdg_surface.set_window_geometry. For example it might only
|
||||||
|
* be used when an unmapped window is attached. The attached window
|
||||||
|
* does not participate in the selection of the drag target.
|
||||||
|
*
|
||||||
|
* If the toplevel is unmapped while it is attached, it is automatically
|
||||||
|
* detached from the drag. In this case this request has to be called again
|
||||||
|
* if the window should be attached after it is remapped.
|
||||||
|
*
|
||||||
|
* This request can be called multiple times but issuing it while a
|
||||||
|
* toplevel with an active role is attached raises a toplevel_attached
|
||||||
|
* error.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
xdg_toplevel_drag_v1_attach(struct xdg_toplevel_drag_v1 *xdg_toplevel_drag_v1, struct xdg_toplevel *toplevel, int32_t x_offset, int32_t y_offset)
|
||||||
|
{
|
||||||
|
wl_proxy_marshal_flags((struct wl_proxy *) xdg_toplevel_drag_v1,
|
||||||
|
XDG_TOPLEVEL_DRAG_V1_ATTACH, NULL, wl_proxy_get_version((struct wl_proxy *) xdg_toplevel_drag_v1), 0, toplevel, x_offset, y_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
1383
Source/ThirdParty/Wayland/protocols/xdg-shell.xml
vendored
Normal file
1383
Source/ThirdParty/Wayland/protocols/xdg-shell.xml
vendored
Normal file
File diff suppressed because it is too large
Load Diff
142
Source/ThirdParty/Wayland/protocols/xdg-toplevel-drag-v1.xml
vendored
Normal file
142
Source/ThirdParty/Wayland/protocols/xdg-toplevel-drag-v1.xml
vendored
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="xdg_toplevel_drag_v1">
|
||||||
|
|
||||||
|
<copyright>
|
||||||
|
Copyright 2023 David Redondo
|
||||||
|
|
||||||
|
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.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<interface name="xdg_toplevel_drag_manager_v1" version="1">
|
||||||
|
<description summary="Move a window during a drag">
|
||||||
|
This protocol enhances normal drag and drop with the ability to move a
|
||||||
|
window at the same time. This allows having detachable parts of a window
|
||||||
|
that when dragged out of it become a new window and can be dragged over
|
||||||
|
an existing window to be reattached.
|
||||||
|
|
||||||
|
A typical workflow would be when the user starts dragging on top of a
|
||||||
|
detachable part of a window, the client would create a wl_data_source and
|
||||||
|
a xdg_toplevel_drag_v1 object and start the drag as normal via
|
||||||
|
wl_data_device.start_drag. Once the client determines that the detachable
|
||||||
|
window contents should be detached from the originating window, it creates
|
||||||
|
a new xdg_toplevel with these contents and issues a
|
||||||
|
xdg_toplevel_drag_v1.attach request before mapping it. From now on the new
|
||||||
|
window is moved by the compositor during the drag as if the client called
|
||||||
|
xdg_toplevel.move.
|
||||||
|
|
||||||
|
Dragging an existing window is similar. The client creates a
|
||||||
|
xdg_toplevel_drag_v1 object and attaches the existing toplevel before
|
||||||
|
starting the drag.
|
||||||
|
|
||||||
|
Clients use the existing drag and drop mechanism to detect when a window
|
||||||
|
can be docked or undocked. If the client wants to snap a window into a
|
||||||
|
parent window it should delete or unmap the dragged top-level. If the
|
||||||
|
contents should be detached again it attaches a new toplevel as described
|
||||||
|
above. If a drag operation is cancelled without being dropped, clients
|
||||||
|
should revert to the previous state, deleting any newly created windows
|
||||||
|
as appropriate. When a drag operation ends as indicated by
|
||||||
|
wl_data_source.dnd_drop_performed the dragged toplevel window's final
|
||||||
|
position is determined as if a xdg_toplevel_move operation ended.
|
||||||
|
|
||||||
|
Warning! The protocol described in this file is currently in the testing
|
||||||
|
phase. Backward compatible changes may be added together with the
|
||||||
|
corresponding interface version bump. Backward incompatible changes can
|
||||||
|
only be done by creating a new major version of the extension.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="invalid_source" value="0"
|
||||||
|
summary="data_source already used for toplevel drag"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the xdg_toplevel_drag_manager_v1 object">
|
||||||
|
Destroy this xdg_toplevel_drag_manager_v1 object. Other objects,
|
||||||
|
including xdg_toplevel_drag_v1 objects created by this factory, are not
|
||||||
|
affected by this request.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="get_xdg_toplevel_drag">
|
||||||
|
<description summary="get an xdg_toplevel_drag for a wl_data_source">
|
||||||
|
Create an xdg_toplevel_drag for a drag and drop operation that is going
|
||||||
|
to be started with data_source.
|
||||||
|
|
||||||
|
This request can only be made on sources used in drag-and-drop, so it
|
||||||
|
must be performed before wl_data_device.start_drag. Attempting to use
|
||||||
|
the source other than for drag-and-drop such as in
|
||||||
|
wl_data_device.set_selection will raise an invalid_source error.
|
||||||
|
|
||||||
|
Destroying data_source while a toplevel is attached to the
|
||||||
|
xdg_toplevel_drag is undefined.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<arg name="id" type="new_id" interface="xdg_toplevel_drag_v1"/>
|
||||||
|
<arg name="data_source" type="object" interface="wl_data_source"/>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="xdg_toplevel_drag_v1" version="1">
|
||||||
|
<description summary="Object representing a toplevel move during a drag">
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="toplevel_attached" value="0"
|
||||||
|
summary="valid toplevel already attached"/>
|
||||||
|
<entry name="ongoing_drag" value="1"
|
||||||
|
summary="drag has not ended" />
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy an xdg_toplevel_drag_v1 object">
|
||||||
|
Destroy this xdg_toplevel_drag_v1 object. This request must only be
|
||||||
|
called after the underlying wl_data_source drag has ended, as indicated
|
||||||
|
by the dnd_drop_performed or cancelled events. In any other case an
|
||||||
|
ongoing_drag error is raised.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="attach">
|
||||||
|
<description summary="Move a toplevel with the drag operation">
|
||||||
|
Request that the window will be moved with the cursor during the drag
|
||||||
|
operation. The offset is a hint to the compositor how the toplevel
|
||||||
|
should be positioned relative to the cursor hotspot in surface local
|
||||||
|
coordinates and relative to the geometry of the toplevel being attached.
|
||||||
|
See xdg_surface.set_window_geometry. For example it might only
|
||||||
|
be used when an unmapped window is attached. The attached window
|
||||||
|
does not participate in the selection of the drag target.
|
||||||
|
|
||||||
|
If the toplevel is unmapped while it is attached, it is automatically
|
||||||
|
detached from the drag. In this case this request has to be called again
|
||||||
|
if the window should be attached after it is remapped.
|
||||||
|
|
||||||
|
This request can be called multiple times but issuing it while a
|
||||||
|
toplevel with an active role is attached raises a toplevel_attached
|
||||||
|
error.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<arg name="toplevel" type="object" interface="xdg_toplevel"/>
|
||||||
|
<arg name="x_offset" type="int" summary="dragged surface x offset"/>
|
||||||
|
<arg name="y_offset" type="int" summary="dragged surface y offset"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
||||||
|
|
||||||
184
Source/ThirdParty/Wayland/xdg-shell.c
vendored
Normal file
184
Source/ThirdParty/Wayland/xdg-shell.c
vendored
Normal 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,
|
||||||
|
};
|
||||||
|
|
||||||
74
Source/ThirdParty/Wayland/xdg-toplevel-drag-v1.c
vendored
Normal file
74
Source/ThirdParty/Wayland/xdg-toplevel-drag-v1.c
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/* Generated by wayland-scanner 1.23.1 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2023 David Redondo
|
||||||
|
*
|
||||||
|
* 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_data_source_interface;
|
||||||
|
extern const struct wl_interface xdg_toplevel_interface;
|
||||||
|
extern const struct wl_interface xdg_toplevel_drag_v1_interface;
|
||||||
|
|
||||||
|
static const struct wl_interface *xdg_toplevel_drag_v1_types[] = {
|
||||||
|
&xdg_toplevel_drag_v1_interface,
|
||||||
|
&wl_data_source_interface,
|
||||||
|
&xdg_toplevel_interface,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message xdg_toplevel_drag_manager_v1_requests[] = {
|
||||||
|
{ "destroy", "", xdg_toplevel_drag_v1_types + 0 },
|
||||||
|
{ "get_xdg_toplevel_drag", "no", xdg_toplevel_drag_v1_types + 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface xdg_toplevel_drag_manager_v1_interface = {
|
||||||
|
"xdg_toplevel_drag_manager_v1", 1,
|
||||||
|
2, xdg_toplevel_drag_manager_v1_requests,
|
||||||
|
0, NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wl_message xdg_toplevel_drag_v1_requests[] = {
|
||||||
|
{ "destroy", "", xdg_toplevel_drag_v1_types + 0 },
|
||||||
|
{ "attach", "oii", xdg_toplevel_drag_v1_types + 2 },
|
||||||
|
};
|
||||||
|
|
||||||
|
WL_PRIVATE const struct wl_interface xdg_toplevel_drag_v1_interface = {
|
||||||
|
"xdg_toplevel_drag_v1", 1,
|
||||||
|
2, xdg_toplevel_drag_v1_requests,
|
||||||
|
0, NULL,
|
||||||
|
};
|
||||||
|
|
||||||
@@ -126,6 +126,7 @@ namespace Flax.Build.Platforms
|
|||||||
args.Add("-lXcursor");
|
args.Add("-lXcursor");
|
||||||
args.Add("-lXinerama");
|
args.Add("-lXinerama");
|
||||||
args.Add("-lXfixes");
|
args.Add("-lXfixes");
|
||||||
|
args.Add("-lwayland-client");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
Reference in New Issue
Block a user