10 Commits

Author SHA1 Message Date
d5f64dcbaa some mac changes?
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2025-10-12 18:16:53 +03:00
ef83dd5377 Fix logging in gamepad related events 2025-04-26 00:33:07 +03:00
bc241afc09 Fix unlock mouse hotkey not unlocking CursorLockMode.Locked cursor 2025-04-26 00:31:39 +03:00
1357d882cd Fix EditorViewport buttons activating items on scene 2025-04-26 00:31:39 +03:00
fd0617f3ae Cleanup 2025-04-26 00:31:38 +03:00
61cadd0fdf Implement Wayland text clipboard data handling 2025-04-26 00:31:38 +03:00
9552103c58 Add support for VK_EXT_metal_surface extension 2025-04-26 00:31:38 +03:00
51132b1bd4 Update volk to 1.4.304 2025-04-26 00:31:37 +03:00
02f446ccfd Fix mouse relative mode activation triggering mouse move events on Mac 2025-04-26 00:31:37 +03:00
26012d0b74 Initial support for building and running SDL platform on macOS 2025-04-26 00:31:37 +03:00
32 changed files with 6513 additions and 1630 deletions

View File

@@ -12,6 +12,6 @@ cd "`dirname "$0"`"
bash ./Development/Scripts/Mac/CallBuildTool.sh --genproject "$@"
# Build bindings for all editor configurations
echo Building C# bindings...
#echo Building C# bindings...
# TODO: Detect the correct architecture here
Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=ARM64 -platform=Mac --buildTargets=FlaxEditor
#Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=ARM64 -platform=Mac --buildTargets=FlaxEditor

View File

@@ -1591,22 +1591,21 @@ namespace FlaxEditor.Viewport
else
EndMouseCapture();
}
_prevInput = _input;
#if PLATFORM_SDL
_prevInput = _input;
bool useMouse = IsControllingMouse || ContainsPoint(ref _viewMousePos) || _prevInput.IsControllingMouse;
if (canUseInput && ContainsFocus)
_input.Gather(win.Window, useMouse, ref _prevInput);
else
_input.Clear();
#else
bool useMouse = IsControllingMouse || (Mathf.IsInRange(_viewMousePos.X, 0, Width) && Mathf.IsInRange(_viewMousePos.Y, 0, Height));
_prevInput = _input;
var hit = GetChildAt(_viewMousePos, c => c.Visible && !(c is CanvasRootControl) && !(c is UIEditorRoot));
if (_prevInput.IsControllingMouse)
hit = null;
#else
bool useMouse = IsControllingMouse || ContainsPoint(ref _viewMousePos);
var hit = GetChildAt(_viewMousePos, c => c.Visible && !(c is CanvasRootControl) && !(c is UIEditorRoot));
#endif
if (canUseInput && ContainsFocus && hit == null)
_input.Gather(win.Window, useMouse, ref _prevInput);
else
_input.Clear();
#endif
// Track controlling mouse state change
bool wasControllingMouse = _prevInput.IsControllingMouse;

View File

@@ -1061,7 +1061,7 @@ namespace FlaxEditor.Windows
_cursorVisible = Screen.CursorVisible;
_cursorLockMode = Screen.CursorLock;
Screen.CursorVisible = true;
if (Screen.CursorLock == CursorLockMode.Clipped)
if (Screen.CursorLock == CursorLockMode.Clipped || Screen.CursorLock == CursorLockMode.Locked)
Screen.CursorLock = CursorLockMode.None;
// Defocus

View File

@@ -18,7 +18,7 @@ void AndroidVulkanPlatform::GetDeviceExtensions(Array<const char*>& extensions,
extensions.Add(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
}
void AndroidVulkanPlatform::CreateSurface(Window* window, VkInstance instance, VkSurfaceKHR* surface)
void AndroidVulkanPlatform::CreateSurface(Window* window, GPUDeviceVulkan* device, VkInstance instance, VkSurfaceKHR* surface)
{
ASSERT(window);
void* windowHandle = window->GetNativePtr();

View File

@@ -9,6 +9,8 @@
// Support more backbuffers in case driver decides to use more
#define VULKAN_BACK_BUFFERS_COUNT_MAX 8
class GPUDeviceVulkan;
/// <summary>
/// The implementation for the Vulkan API support for Android platform.
/// </summary>
@@ -17,7 +19,7 @@ class AndroidVulkanPlatform : public VulkanPlatformBase
public:
static void GetInstanceExtensions(Array<const char*>& extensions, Array<const char*>& layers);
static void GetDeviceExtensions(Array<const char*>& extensions, Array<const char*>& layers);
static void CreateSurface(Window* window, VkInstance instance, VkSurfaceKHR* surface);
static void CreateSurface(Window* window, GPUDeviceVulkan* device, VkInstance instance, VkSurfaceKHR* surface);
};
typedef AndroidVulkanPlatform VulkanPlatform;

View File

@@ -192,7 +192,7 @@ bool GPUSwapChainVulkan::CreateSwapChain(int32 width, int32 height)
ASSERT_LOW_LAYER(_backBuffers.Count() == 0);
// Create platform-dependent surface
VulkanPlatform::CreateSurface(_window, GPUDeviceVulkan::Instance, &_surface);
VulkanPlatform::CreateSurface(_window, _device, GPUDeviceVulkan::Instance, &_surface);
if (_surface == VK_NULL_HANDLE)
{
LOG(Warning, "Failed to create Vulkan surface.");

View File

@@ -30,7 +30,7 @@ void LinuxVulkanPlatform::GetInstanceExtensions(Array<const char*>& extensions,
extensions.Add(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
}
void LinuxVulkanPlatform::CreateSurface(Window* window, VkInstance instance, VkSurfaceKHR* surface)
void LinuxVulkanPlatform::CreateSurface(Window* window, GPUDeviceVulkan* device, VkInstance instance, VkSurfaceKHR* surface)
{
#if !PLATFORM_SDL
void* windowHandle = window->GetNativePtr();
@@ -41,22 +41,21 @@ void LinuxVulkanPlatform::CreateSurface(Window* window, VkInstance instance, VkS
VALIDATE_VULKAN_RESULT(vkCreateXlibSurfaceKHR(instance, &surfaceCreateInfo, nullptr, surface));
#else
SDLWindow* sdlWindow = static_cast<Window*>(window);
X11::Window x11Window = (X11::Window)sdlWindow->GetX11WindowHandle();
wl_surface* waylandSurface = (wl_surface*)sdlWindow->GetWaylandSurfacePtr();
if (waylandSurface != nullptr)
void* windowHandle = window->GetNativePtr();
if (SDLPlatform::UsesWayland())
{
VkWaylandSurfaceCreateInfoKHR surfaceCreateInfo;
RenderToolsVulkan::ZeroStruct(surfaceCreateInfo, VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR);
surfaceCreateInfo.display = (wl_display*)sdlWindow->GetWaylandDisplay();
surfaceCreateInfo.surface = waylandSurface;
surfaceCreateInfo.surface = (wl_surface*)windowHandle;
VALIDATE_VULKAN_RESULT(vkCreateWaylandSurfaceKHR(instance, &surfaceCreateInfo, nullptr, surface));
}
else if (x11Window != 0)
else if (SDLPlatform::UsesX11())
{
VkXlibSurfaceCreateInfoKHR surfaceCreateInfo;
RenderToolsVulkan::ZeroStruct(surfaceCreateInfo, VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR);
surfaceCreateInfo.dpy = (X11::Display*)sdlWindow->GetX11Display();
surfaceCreateInfo.window = x11Window;
surfaceCreateInfo.window = (X11::Window)windowHandle;
VALIDATE_VULKAN_RESULT(vkCreateXlibSurfaceKHR(instance, &surfaceCreateInfo, nullptr, surface));
}
#endif

View File

@@ -12,6 +12,8 @@
// Prevent wierd error 'Invalid VkValidationCacheEXT Object'
#define VULKAN_USE_VALIDATION_CACHE 0
class GPUDeviceVulkan;
/// <summary>
/// The implementation for the Vulkan API support for Linux platform.
/// </summary>
@@ -19,7 +21,7 @@ class LinuxVulkanPlatform : public VulkanPlatformBase
{
public:
static void GetInstanceExtensions(Array<const char*>& extensions, Array<const char*>& layers);
static void CreateSurface(Window* window, VkInstance instance, VkSurfaceKHR* outSurface);
static void CreateSurface(Window* window, GPUDeviceVulkan* device, VkInstance instance, VkSurfaceKHR* outSurface);
};
typedef LinuxVulkanPlatform VulkanPlatform;

View File

@@ -5,22 +5,39 @@
#include "MacVulkanPlatform.h"
#include "../RenderToolsVulkan.h"
#include "Engine/Platform/Window.h"
#include "Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.h"
#include <Cocoa/Cocoa.h>
#include <QuartzCore/CAMetalLayer.h>
void MacVulkanPlatform::GetInstanceExtensions(Array<const char*>& extensions, Array<const char*>& layers)
{
extensions.Add(VK_KHR_SURFACE_EXTENSION_NAME);
extensions.Add(VK_MVK_MACOS_SURFACE_EXTENSION_NAME);
extensions.Add(VK_MVK_MACOS_SURFACE_EXTENSION_NAME);
extensions.Add(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
}
void MacVulkanPlatform::CreateSurface(Window* window, VkInstance instance, VkSurfaceKHR* surface)
void MacVulkanPlatform::CreateSurface(Window* window, GPUDeviceVulkan* device, VkInstance instance, VkSurfaceKHR* surface)
{
void* windowHandle = window->GetNativePtr();
NSWindow* nswindow = (NSWindow*)windowHandle;
VkMacOSSurfaceCreateInfoMVK surfaceCreateInfo;
RenderToolsVulkan::ZeroStruct(surfaceCreateInfo, VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK);
surfaceCreateInfo.pView = (void*)nswindow.contentView;
VALIDATE_VULKAN_RESULT(vkCreateMacOSSurfaceMVK(instance, &surfaceCreateInfo, nullptr, surface));
#if PLATFORM_SDL
nswindow.contentView.wantsLayer = YES;
nswindow.contentView.layer = [CAMetalLayer layer];
#endif
if (device->InstanceExtensions.Contains(VK_EXT_METAL_SURFACE_EXTENSION_NAME))
{
VkMetalSurfaceCreateInfoEXT surfaceCreateInfo;
RenderToolsVulkan::ZeroStruct(surfaceCreateInfo, VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT);
surfaceCreateInfo.pLayer = (CAMetalLayer*)nswindow.contentView.layer;
VALIDATE_VULKAN_RESULT(vkCreateMetalSurfaceEXT(instance, &surfaceCreateInfo, nullptr, surface));
}
else
{
VkMacOSSurfaceCreateInfoMVK surfaceCreateInfo;
RenderToolsVulkan::ZeroStruct(surfaceCreateInfo, VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK);
surfaceCreateInfo.pView = (void*)nswindow.contentView;
VALIDATE_VULKAN_RESULT(vkCreateMacOSSurfaceMVK(instance, &surfaceCreateInfo, nullptr, surface));
}
}
#endif

View File

@@ -11,6 +11,8 @@
// General/Validation Error:0 VK_ERROR_INITIALIZATION_FAILED: Could not create MTLCounterSampleBuffer for query pool of type VK_QUERY_TYPE_TIMESTAMP. Reverting to emulated behavior. (Error code 0): Cannot allocate sample buffer
#define VULKAN_USE_QUERIES 0
class GPUDeviceVulkan;
/// <summary>
/// The implementation for the Vulkan API support for Mac platform.
/// </summary>
@@ -18,7 +20,7 @@ class MacVulkanPlatform : public VulkanPlatformBase
{
public:
static void GetInstanceExtensions(Array<const char*>& extensions, Array<const char*>& layers);
static void CreateSurface(Window* window, VkInstance instance, VkSurfaceKHR* outSurface);
static void CreateSurface(Window* window, GPUDeviceVulkan* device, VkInstance instance, VkSurfaceKHR* outSurface);
};
typedef MacVulkanPlatform VulkanPlatform;

View File

@@ -14,7 +14,7 @@ void Win32VulkanPlatform::GetInstanceExtensions(Array<const char*>& extensions,
extensions.Add(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
}
void Win32VulkanPlatform::CreateSurface(Window* window, VkInstance instance, VkSurfaceKHR* surface)
void Win32VulkanPlatform::CreateSurface(Window* window, GPUDeviceVulkan* device, VkInstance instance, VkSurfaceKHR* surface)
{
void* windowHandle = window->GetNativePtr();
VkWin32SurfaceCreateInfoKHR surfaceCreateInfo;

View File

@@ -10,6 +10,8 @@
#define VULKAN_USE_PLATFORM_WIN32_KHX 1
#define VULKAN_USE_CREATE_WIN32_SURFACE 1
class GPUDeviceVulkan;
/// <summary>
/// The implementation for the Vulkan API support for Win32 platform.
/// </summary>
@@ -17,7 +19,7 @@ class Win32VulkanPlatform : public VulkanPlatformBase
{
public:
static void GetInstanceExtensions(Array<const char*>& extensions, Array<const char*>& layers);
static void CreateSurface(Window* window, VkInstance instance, VkSurfaceKHR* surface);
static void CreateSurface(Window* window, GPUDeviceVulkan* device, VkInstance instance, VkSurfaceKHR* surface);
};
typedef Win32VulkanPlatform VulkanPlatform;

View File

@@ -14,7 +14,7 @@ void iOSVulkanPlatform::GetInstanceExtensions(Array<const char*>& extensions, Ar
extensions.Add(VK_MVK_IOS_SURFACE_EXTENSION_NAME);
}
void iOSVulkanPlatform::CreateSurface(Window* window, VkInstance instance, VkSurfaceKHR* surface)
void iOSVulkanPlatform::CreateSurface(Window* window, GPUDeviceVulkan* device, VkInstance instance, VkSurfaceKHR* surface)
{
void* windowHandle = window->GetNativePtr();
// Create surface on a main UI Thread

View File

@@ -11,6 +11,8 @@
// General/Validation Error:0 VK_ERROR_INITIALIZATION_FAILED: Could not create MTLCounterSampleBuffer for query pool of type VK_QUERY_TYPE_TIMESTAMP. Reverting to emulated behavior. (Error code 0): Cannot allocate sample buffer
#define VULKAN_USE_QUERIES 0
class GPUDeviceVulkan;
/// <summary>
/// The implementation for the Vulkan API support for iOS platform.
/// </summary>
@@ -18,7 +20,7 @@ class iOSVulkanPlatform : public VulkanPlatformBase
{
public:
static void GetInstanceExtensions(Array<const char*>& extensions, Array<const char*>& layers);
static void CreateSurface(Window* window, VkInstance instance, VkSurfaceKHR* outSurface);
static void CreateSurface(Window* window, GPUDeviceVulkan* device, VkInstance instance, VkSurfaceKHR* outSurface);
};
typedef iOSVulkanPlatform VulkanPlatform;

View File

@@ -273,6 +273,7 @@ bool MacPlatform::Init()
CFRelease(computerName);
}
#if !PLATFORM_SDL
// Find the maximum scale of the display to handle high-dpi displays scaling factor
{
NSArray* screenArray = [NSScreen screens];
@@ -297,6 +298,7 @@ bool MacPlatform::Init()
Input::Mouse = New<MacMouse>();
Input::Keyboard = New<MacKeyboard>();
#endif
return false;
}
@@ -423,11 +425,15 @@ String MacPlatform::GetMainDirectory()
return path;
}
#if !PLATFORM_SDL
Window* MacPlatform::CreateWindow(const CreateWindowSettings& settings)
{
return New<MacWindow>(settings);
}
#endif
int32 MacPlatform::CreateProcess(CreateProcessSettings& settings)
{
LOG(Info, "Command: {0} {1}", settings.FileName, settings.Arguments);

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
// Copyright (c) Wojciech Figat. All rights reserved.
#if PLATFORM_MAC
#if PLATFORM_MAC && !PLATFORM_SDL
#include "../Window.h"
#include "Engine/Platform/Apple/AppleUtils.h"

View File

@@ -432,6 +432,12 @@ public:
Mouse::SetRelativeMode(relativeMode, window);
if (!SDL_SetWindowRelativeMouseMode(windowHandle, relativeMode))
LOG(Error, "Failed to set mouse relative mode: {0}", String(SDL_GetError()));
#if PLATFORM_MAC
// Warping right before entering relative mode seems to generate motion event for relative mode
SDL_PumpEvents();
SDL_FlushEvent(SDL_EVENT_MOUSE_MOTION);
#endif
}
bool IsRelative(Window* window) const override
@@ -450,7 +456,7 @@ class SDLGamepad : public Gamepad
{
private:
SDL_Gamepad* _gamepad;
SDL_Gamepad* _gamepad = nullptr;
SDL_JoystickID _instanceId;
public:
@@ -621,8 +627,6 @@ bool SDLInput::HandleEvent(SDLWindow* window, SDL_Event& event)
SDLGamepad* gamepad = SDLGamepad::GetGamepadById(event.gaxis.which);
SDL_GamepadAxis axis = (SDL_GamepadAxis)event.gaxis.axis;
gamepad->OnAxisMotion(axis, event.gaxis.value);
LOG(Info, "SDL_EVENT_GAMEPAD_AXIS_MOTION");
break;
}
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
@@ -631,16 +635,12 @@ bool SDLInput::HandleEvent(SDLWindow* window, SDL_Event& event)
SDLGamepad* gamepad = SDLGamepad::GetGamepadById(event.gbutton.which);
SDL_GamepadButton button = (SDL_GamepadButton)event.gbutton.button;
gamepad->OnButtonState(button, event.gbutton.down);
LOG(Info, "SDL_EVENT_GAMEPAD_BUTTON_");
break;
}
case SDL_EVENT_GAMEPAD_ADDED:
{
Input::Gamepads.Add(New<SDLGamepad>(event.gdevice.which));
Input::OnGamepadsChanged();
LOG(Info, "SDL_EVENT_GAMEPAD_ADDED");
break;
}
case SDL_EVENT_GAMEPAD_REMOVED:
@@ -656,40 +656,38 @@ bool SDLInput::HandleEvent(SDLWindow* window, SDL_Event& event)
break;
}
}
LOG(Info, "SDL_EVENT_GAMEPAD_REMOVED");
break;
}
case SDL_EVENT_GAMEPAD_REMAPPED:
{
auto ev = event.gdevice;
LOG(Info, "SDL_EVENT_GAMEPAD_REMAPPED");
LOG(Info, "TODO: SDL_EVENT_GAMEPAD_REMAPPED");
break;
}
case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN:
{
LOG(Info, "SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN");
LOG(Info, "TODO: SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN");
break;
}
case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION:
{
LOG(Info, "SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION");
LOG(Info, "TODO: SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION");
break;
}
case SDL_EVENT_GAMEPAD_TOUCHPAD_UP:
{
LOG(Info, "SDL_EVENT_GAMEPAD_TOUCHPAD_UP");
LOG(Info, "TODO: SDL_EVENT_GAMEPAD_TOUCHPAD_UP");
break;
}
case SDL_EVENT_GAMEPAD_SENSOR_UPDATE:
{
LOG(Info, "SDL_EVENT_GAMEPAD_SENSOR_UPDATE");
LOG(Info, "TODO: SDL_EVENT_GAMEPAD_SENSOR_UPDATE");
break;
}
case SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED:
{
auto ev = event.gdevice;
LOG(Info, "SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED");
LOG(Info, "TODO: SDL_EVENT_GAMEPAD_STEAM_HANDLE_UPDATED");
break;
}
}
@@ -707,6 +705,7 @@ Guid GetGamepadGuid(SDL_JoystickID instanceId)
SDLGamepad::SDLGamepad(SDL_JoystickID instanceId)
: SDLGamepad(SDL_OpenGamepad(instanceId), instanceId)
{
LOG(Info, "Gamepad connected: {}", String(SDL_GetGamepadName(_gamepad)));
}
SDLGamepad::SDLGamepad(SDL_Gamepad* gamepad, SDL_JoystickID instanceId)
@@ -726,6 +725,7 @@ SDLGamepad::~SDLGamepad()
void SDLGamepad::SetVibration(const GamepadVibrationState& state)
{
Gamepad::SetVibration(state);
LOG(Info, "TODO: SDLGamepad::SetVibration");
}
bool SDLGamepad::UpdateState()

View File

@@ -22,6 +22,7 @@
#include "Engine/Platform/Linux/IncludeX11.h"
#include <SDL3/SDL_clipboard.h>
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_hints.h>
#include <SDL3/SDL_messagebox.h>
@@ -655,7 +656,7 @@ DragDropEffect Window::DoDragDropX11(const StringView& data)
#if !PLATFORM_SDL
X11::Window mainWindow = _window;
#else
X11::Window mainWindow = static_cast<X11::Window>(GetX11WindowHandle());
X11::Window mainWindow = reinterpret_cast<X11::Window>(GetNativePtr());
#endif
// Make sure SDL hasn't grabbed the pointer, and force ungrab it
@@ -1104,7 +1105,7 @@ void SDLClipboard::SetText(const StringView& text)
if (X11Impl::xDisplay)
{
X11::Window window = (X11::Window)(mainWindow->GetX11WindowHandle());
X11::Window window = (X11::Window)(mainWindow->GetNativePtr());
X11Impl::ClipboardText.Set(text.Get(), text.Length());
X11::XSetSelectionOwner(X11Impl::xDisplay, X11Impl::xAtomClipboard, window, CurrentTime); // CLIPBOARD
//X11::XSetSelectionOwner(xDisplay, xAtomPrimary, window, CurrentTime); // XA_PRIMARY
@@ -1113,9 +1114,7 @@ void SDLClipboard::SetText(const StringView& text)
//X11::XGetSelectionOwner(xDisplay, xAtomPrimary);
}
else
{
LOG(Warning, "Wayland clipboard support is not implemented yet."); // TODO: Wayland
}
SDL_SetClipboardText(StringAnsi(text).GetText());
}
void SDLClipboard::SetRawData(const Span<byte>& data)
@@ -1136,7 +1135,7 @@ String SDLClipboard::GetText()
return result;
if (X11Impl::xDisplay)
{
X11::Window window = static_cast<X11::Window>(mainWindow->GetX11WindowHandle());
X11::Window window = reinterpret_cast<X11::Window>(mainWindow->GetNativePtr());
X11Impl::ClipboardGetText(result, X11Impl::xAtomClipboard, X11Impl::xAtomUTF8String, window);
if (result.HasChars())
@@ -1152,8 +1151,7 @@ String SDLClipboard::GetText()
}
else
{
LOG(Warning, "Wayland clipboard is not implemented yet."); // TODO: Wayland
return String::Empty;
return String(SDL_GetClipboardText());
}
}

View File

@@ -1,12 +1,587 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
#include "SDLInput.h"
#if PLATFORM_SDL && PLATFORM_MAC
static_assert(false, "TODO");
#include "SDLWindow.h"
#include "Engine/Core/Log.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Engine/CommandLine.h"
#include "Engine/Engine/Engine.h"
#include "Engine/Engine/Time.h"
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Input/Input.h"
#include "Engine/Input/Mouse.h"
#include "Engine/Platform/IGuiData.h"
#include "Engine/Platform/MessageBox.h"
#include "Engine/Platform/Platform.h"
#include "Engine/Platform/WindowsManager.h"
#include "Engine/Platform/Base/DragDropHelper.h"
#include "Engine/Platform/SDL/SDLClipboard.h"
#include "Engine/Platform/Unix/UnixFile.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Platform/Apple/AppleUtils.h"
#include <Cocoa/Cocoa.h>
#include <AppKit/AppKit.h>
#include <QuartzCore/CAMetalLayer.h>
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_hints.h>
#include <SDL3/SDL_messagebox.h>
#include <SDL3/SDL_mouse.h>
#include <SDL3/SDL_system.h>
#include <SDL3/SDL_timer.h>
#include <SDL3/SDL_video.h>
namespace MacImpl
{
Window* DraggedWindow = nullptr;
String DraggingData = String();
Float2 DraggingPosition;
Nullable<Float2> LastMouseDragPosition;
#if USE_EDITOR
//CriticalSection MacDragLocker;
bool DraggingActive = false;
bool DraggingIgnoreEvent = false;
NSDraggingSession* MacDragSession = nullptr;
//DoDragDropJob* MacDragJob = nullptr;
int64 MacDragExitFlag = 0;
#endif
}
class MacDropData : public IGuiData
{
public:
Type CurrentType;
String AsText;
Array<String> AsFiles;
Type GetType() const override
{
return CurrentType;
}
String GetAsText() const override
{
return AsText;
}
void GetAsFiles(Array<String>* files) const override
{
files->Add(AsFiles);
}
};
bool SDLPlatform::InitInternal()
{
return false;
}
bool SDLPlatform::UsesWindows()
{
return false;
}
bool SDLPlatform::UsesWayland()
{
return false;
}
bool SDLPlatform::UsesX11()
{
return false;
}
bool SDLPlatform::EventFilterCallback(void* userdata, SDL_Event* event)
{
Window* draggedWindow = *(Window**)userdata;
if (draggedWindow == nullptr)
{
if (MacImpl::DraggingActive)
{
// Handle events during drag operation here since the normal event loop is blocked
if (event->type == SDL_EVENT_WINDOW_EXPOSED)
{
LOG(Info, "Window exposed event");
// The internal timer is sending exposed events every ~16ms
#if USE_EDITOR
// Flush any single-frame shapes to prevent memory leaking (eg. via terrain collision debug during scene drawing with PhysicsColliders or PhysicsDebug flag)
DebugDraw::UpdateContext(nullptr, 0.0f);
#endif
Engine::OnUpdate(); // For docking updates
Engine::OnDraw();
}
else
{
SDLWindow* window = SDLWindow::GetWindowFromEvent(*event);
if (window)
window->HandleEvent(*event);
// We do not receive events at steady rate to keep the engine updated...
#if USE_EDITOR
// Flush any single-frame shapes to prevent memory leaking (eg. via terrain collision debug during scene drawing with PhysicsColliders or PhysicsDebug flag)
DebugDraw::UpdateContext(nullptr, 0.0f);
#endif
Engine::OnUpdate(); // For docking updates
Engine::OnDraw();
if (event->type == SDL_EVENT_DROP_BEGIN || event->type == SDL_EVENT_DROP_FILE || event->type == SDL_EVENT_DROP_TEXT)
return true; // Filtering these event stops other following events from getting added to the queue
else
LOG(Info, "Unhandled event: {}", event->type);
}
return false;
}
return true;
}
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.
#if false
SDLWindow* window = SDLWindow::GetWindowFromEvent(*event);
if (event->type == SDL_EVENT_WINDOW_EXPOSED)
{
// The internal timer is sending exposed events every ~16ms
Engine::OnUpdate(); // For docking updates
Engine::OnDraw();
return false;
}
else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN)
{
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)
{
if (window)
window->HandleEvent(*event);
/*if (WinImpl::DraggedWindowSize != window->GetClientSize())
{
// The window size changed while dragging, most likely due to maximized window restoring back to previous size.
WinImpl::DraggedWindowMousePosition = WinImpl::DraggedWindowStartPosition + WinImpl::DraggedWindowMousePosition - window->GetClientPosition();
WinImpl::DraggedWindowStartPosition = window->GetClientPosition();
WinImpl::DraggedWindowSize = window->GetClientSize();
}
Float2 windowPosition = Float2(static_cast<float>(event->window.data1), static_cast<float>(event->window.data2));
Float2 mousePosition = WinImpl::DraggedWindowMousePosition;
// Generate mouse movement events while dragging the window around
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 = mousePosition.X;
mouseMovedEvent.motion.y = mousePosition.Y;
if (window)
window->HandleEvent(mouseMovedEvent);*/
return false;
}
if (window)
window->HandleEvent(*event);
return false;
#endif
}
void SDLPlatform::PreHandleEvents()
{
SDL_SetEventFilter(EventFilterCallback, &MacImpl::DraggedWindow);
}
void SDLPlatform::PostHandleEvents()
{
SDL_SetEventFilter(EventFilterCallback, &MacImpl::DraggedWindow);
// Handle window dragging release here
if (MacImpl::DraggedWindow != nullptr)
{
Float2 mousePosition;
auto buttons = SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y);
bool buttonReleased = (buttons & SDL_BUTTON_MASK(SDL_BUTTON_LEFT)) == 0;
if (buttonReleased)
{
// 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(MacImpl::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;
MacImpl::DraggedWindow->HandleEvent(buttonUpEvent);
MacImpl::DraggedWindow = nullptr;
}
}
}
bool SDLWindow::HandleEventInternal(SDL_Event& event)
{
switch (event.type)
{
case SDL_EVENT_WINDOW_MOVED:
{
// Quartz 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)
{
if (MacImpl::DraggedWindow == nullptr)
{
// TODO: verify mouse position, window focus
bool result = false;
OnLeftButtonHit(WindowHitCodes::Caption, result);
if (result)
MacImpl::DraggedWindow = this;
}
else
{
Float2 mousePos = Platform::GetMousePosition();
Input::Mouse->OnMouseMove(mousePos, this);
}
}
break;
}
case SDL_EVENT_MOUSE_BUTTON_UP:
case SDL_EVENT_MOUSE_BUTTON_DOWN:
{
if (MacImpl::LastMouseDragPosition.HasValue())
{
// SDL reports wrong mouse position after dragging has ended
Float2 mouseClientPosition = ScreenToClient(MacImpl::LastMouseDragPosition.GetValue());
event.button.x = mouseClientPosition.X;
event.button.y = mouseClientPosition.Y;
}
break;
}
case SDL_EVENT_MOUSE_MOTION:
{
if (MacImpl::LastMouseDragPosition.HasValue())
MacImpl::LastMouseDragPosition.Reset();
if (MacImpl::DraggedWindow != nullptr)
return true;
break;
}
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
{
OnDragLeave(); // Check for release of mouse button too?
break;
}
//case SDL_EVENT_CLIPBOARD_UPDATE:
case SDL_EVENT_DROP_BEGIN:
case SDL_EVENT_DROP_POSITION:
case SDL_EVENT_DROP_FILE:
case SDL_EVENT_DROP_TEXT:
case SDL_EVENT_DROP_COMPLETE:
{
{
// HACK: We can't use Wayland listeners due to SDL also using them at the same time causes
// some of the events to drop and make it impossible to implement dragging on application side.
// We can get enough information through SDL_EVENT_DROP_* events to fill in the blanks for the
// drag and drop implementation.
auto dpiScale = GetDpiScale();
Float2 mousePos = Float2(event.drop.x * dpiScale, event.drop.y * dpiScale);
DragDropEffect effect = DragDropEffect::None;
String text(event.drop.data);
MacDropData dropData;
if (MacImpl::DraggingActive)
{
// We don't have the window dragging data during these events...
text = MacImpl::DraggingData;
mousePos = ScreenToClient(MacImpl::DraggingPosition);
// Ensure mouse position is updated while dragging
Input::Mouse->OnMouseMove(MacImpl::DraggingPosition, this);
MacImpl::LastMouseDragPosition = MacImpl::DraggingPosition;
}
dropData.AsText = text;
if (event.type == SDL_EVENT_DROP_BEGIN)
{
// We don't know the type of dragged data at this point, so call the events for both types
if (!MacImpl::DraggingActive)
{
dropData.CurrentType = IGuiData::Type::Files;
OnDragEnter(&dropData, mousePos, effect);
}
if (effect == DragDropEffect::None)
{
dropData.CurrentType = IGuiData::Type::Text;
OnDragEnter(&dropData, mousePos, effect);
}
}
else if (event.type == SDL_EVENT_DROP_POSITION)
{
Input::Mouse->OnMouseMove(ClientToScreen(mousePos), this);
// We don't know the type of dragged data at this point, so call the events for both types
if (!MacImpl::DraggingActive)
{
dropData.CurrentType = IGuiData::Type::Files;
OnDragOver(&dropData, mousePos, effect);
}
if (effect == DragDropEffect::None)
{
dropData.CurrentType = IGuiData::Type::Text;
OnDragOver(&dropData, mousePos, effect);
}
}
else if (event.type == SDL_EVENT_DROP_FILE)
{
text.Split('\n', dropData.AsFiles);
dropData.CurrentType = IGuiData::Type::Files;
OnDragDrop(&dropData, mousePos, effect);
}
else if (event.type == SDL_EVENT_DROP_TEXT)
{
dropData.CurrentType = IGuiData::Type::Text;
OnDragDrop(&dropData, mousePos, effect);
}
else if (event.type == SDL_EVENT_DROP_COMPLETE)
{
OnDragLeave();
if (MacImpl::DraggingActive)
{
// The previous drop events needs to be flushed to avoid processing them twice
SDL_FlushEvents(SDL_EVENT_DROP_FILE, SDL_EVENT_DROP_POSITION);
}
}
// TODO: Implement handling for feedback effect result (https://github.com/libsdl-org/SDL/issues/10448)
}
break;
}
}
return false;
}
void SDLPlatform::SetHighDpiAwarenessEnabled(bool enable)
{
// TODO: This is now called before Platform::Init, ensure the scaling is changed accordingly during Platform::Init (see ApplePlatform::SetHighDpiAwarenessEnabled)
}
inline bool IsWindowInvalid(Window* win)
{
WindowsManager::WindowsLocker.Lock();
const bool hasWindow = WindowsManager::Windows.Contains(win);
WindowsManager::WindowsLocker.Unlock();
return !hasWindow || !win;
}
Float2 GetWindowTitleSize(const SDLWindow* window)
{
Float2 size = Float2::Zero;
if (window->GetSettings().HasBorder)
{
NSRect frameStart = [(NSWindow*)window->GetNativePtr() frameRectForContentRect:NSMakeRect(0, 0, 0, 0)];
size.Y = frameStart.size.height;
}
return size * MacPlatform::ScreenScale;
}
Float2 GetMousePosition(SDLWindow* window, NSEvent* event)
{
NSRect frame = [(NSWindow*)window->GetNativePtr() frame];
NSPoint point = [event locationInWindow];
return Float2(point.x, frame.size.height - point.y) * MacPlatform::ScreenScale - GetWindowTitleSize(window);
}
Float2 GetMousePosition(SDLWindow* window, const NSPoint& point)
{
NSRect frame = [(NSWindow*)window->GetNativePtr() frame];
CGRect screenBounds = CGDisplayBounds(CGMainDisplayID());
return Float2(point.x, screenBounds.size.height - point.y) * MacPlatform::ScreenScale;
}
void GetDragDropData(const SDLWindow* window, id<NSDraggingInfo> sender, Float2& mousePos, MacDropData& dropData)
{
NSRect frame = [(NSWindow*)window->GetNativePtr() frame];
NSPoint point = [sender draggingLocation];
mousePos = Float2(point.x, frame.size.height - point.y) * MacPlatform::ScreenScale - GetWindowTitleSize(window);
NSPasteboard* pasteboard = [sender draggingPasteboard];
if ([[pasteboard types] containsObject:NSPasteboardTypeString])
{
dropData.CurrentType = IGuiData::Type::Text;
dropData.AsText = AppleUtils::ToString((CFStringRef)[pasteboard stringForType:NSPasteboardTypeString]);
}
else
{
dropData.CurrentType = IGuiData::Type::Files;
NSArray* files = [pasteboard readObjectsForClasses:@[[NSURL class]] options:nil];
for (int32 i = 0; i < [files count]; i++)
{
NSString* url = [[files objectAtIndex:i] path];
NSString* file = [NSURL URLWithString:url].path;
dropData.AsFiles.Add(AppleUtils::ToString((CFStringRef)file));
}
}
}
NSDragOperation GetDragDropOperation(DragDropEffect dragDropEffect)
{
NSDragOperation result = NSDragOperationCopy;
switch (dragDropEffect)
{
case DragDropEffect::None:
//result = NSDragOperationNone;
break;
case DragDropEffect::Copy:
result = NSDragOperationCopy;
break;
case DragDropEffect::Move:
result = NSDragOperationMove;
break;
case DragDropEffect::Link:
result = NSDragOperationLink;
break;
}
return result;
}
#undef INCLUDED_IN_SDL
@interface ClipboardDataProviderImpl : NSObject <NSPasteboardItemDataProvider, NSDraggingSource>
{
@public
SDLWindow* Window;
}
@end
@implementation ClipboardDataProviderImpl
// NSPasteboardItemDataProvider
// ---
- (void)pasteboard:(nullable NSPasteboard*)pasteboard item:(NSPasteboardItem*)item provideDataForType:(NSPasteboardType)type
{
LOG(Info, "pasteboard");
if (IsWindowInvalid(Window)) return;
[pasteboard setString:(NSString*)AppleUtils::ToString(MacImpl::DraggingData) forType:NSPasteboardTypeString];
}
- (void)pasteboardFinishedWithDataProvider:(NSPasteboard*)pasteboard
{
LOG(Info, "pasteboardFinishedWithDataProvider");
}
// NSDraggingSource
// ---
- (NSDragOperation)draggingSession:(NSDraggingSession*)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context
{
if (IsWindowInvalid(Window))
return NSDragOperationNone;
switch(context)
{
case NSDraggingContextOutsideApplication:
LOG(Info, "draggingSession sourceOperationMaskForDraggingContext: outside");
return NSDragOperationCopy;
case NSDraggingContextWithinApplication:
LOG(Info, "draggingSession sourceOperationMaskForDraggingContext: inside");
return NSDragOperationCopy;
default:
LOG(Info, "draggingSession sourceOperationMaskForDraggingContext: unknown");
return NSDragOperationMove;
}
}
- (void)draggingSession:(NSDraggingSession*)session willBeginAtPoint:(NSPoint)screenPoint
{
LOG(Info, "draggingSession willBeginAtPoint");
MacImpl::DraggingPosition = GetMousePosition(Window, screenPoint);
}
- (void)draggingSession:(NSDraggingSession*)session movedToPoint:(NSPoint)screenPoint
{
//LOG(Info, "draggingSession movedToPoint");
MacImpl::DraggingPosition = GetMousePosition(Window, screenPoint);
}
- (void)draggingSession:(NSDraggingSession*)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation
{
LOG(Info, "draggingSession endedAtPoint");
MacImpl::DraggingPosition = GetMousePosition(Window, screenPoint);
#if USE_EDITOR
// Stop background worker once the drag ended
if (MacImpl::MacDragSession && MacImpl::MacDragSession == session)
Platform::AtomicStore(&MacImpl::MacDragExitFlag, 1);
#endif
}
@end
DragDropEffect SDLWindow::DoDragDrop(const StringView& data)
{
NSWindow* window = (NSWindow*)_handle;
ClipboardDataProviderImpl* clipboardDataProvider = [ClipboardDataProviderImpl alloc];
clipboardDataProvider->Window = this;
// Create mouse drag event
NSEvent* event = [NSEvent
mouseEventWithType:NSEventTypeLeftMouseDragged
location:window.mouseLocationOutsideOfEventStream
modifierFlags:0
timestamp:NSApp.currentEvent.timestamp
windowNumber:window.windowNumber
context:nil
eventNumber:0
clickCount:1
pressure:1.0];
// Create drag item
NSPasteboardItem* pasteItem = [NSPasteboardItem new];
[pasteItem setDataProvider:clipboardDataProvider forTypes:[NSArray arrayWithObjects:NSPasteboardTypeString, nil]];
NSDraggingItem* dragItem = [[NSDraggingItem alloc] initWithPasteboardWriter:pasteItem];
[dragItem setDraggingFrame:NSMakeRect(event.locationInWindow.x, event.locationInWindow.y, 100, 100) contents:nil];
// Start dragging session
NSDraggingSession* draggingSession = [window.contentView beginDraggingSessionWithItems:[NSArray arrayWithObject:dragItem] event:event source:clipboardDataProvider];
DragDropEffect result = DragDropEffect::None;
#if USE_EDITOR
// Create background worker that will keep updating GUI (perform rendering)
ASSERT(!MacImpl::MacDragSession);
MacImpl::MacDragSession = draggingSession;
MacImpl::MacDragExitFlag = 0;
MacImpl::DraggingData = data;
MacImpl::DraggingActive = true;
while (Platform::AtomicRead(&MacImpl::MacDragExitFlag) == 0)
{
// The internal event loop will block here during the drag operation,
// events are processed in the event filter callback instead.
SDLPlatform::Tick();
Platform::Sleep(1);
}
MacImpl::DraggingActive = false;
MacImpl::DraggingData.Clear();
MacImpl::MacDragSession = nullptr;
#endif
return result;
}
DragDropEffect SDLWindow::DoDragDrop(const StringView& data, const Float2& offset, Window* dragSourceWindow)
{
Show();
return DragDropEffect::None;
}
#endif

View File

@@ -104,7 +104,8 @@ bool SDLPlatform::Init()
if (InitInternal())
return true;
if (UsesWindows() || UsesX11())
#if !PLATFORM_MAC
if (!UsesWayland())
{
// Disable SDL clipboard support
SDL_SetEventEnabled(SDL_EVENT_CLIPBOARD_UPDATE, false);
@@ -116,6 +117,7 @@ bool SDLPlatform::Init()
SDL_SetEventEnabled(SDL_EVENT_DROP_COMPLETE, false);
SDL_SetEventEnabled(SDL_EVENT_DROP_POSITION, false);
}
#endif
SDLInput::Init();
SDLWindow::Init();
@@ -225,20 +227,22 @@ void SDLPlatform::OpenUrl(const StringView& url)
Float2 SDLPlatform::GetMousePosition()
{
Float2 pos;
#if PLATFORM_LINUX
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");
return Input::GetMouseScreenPosition();
}
else if (UsesX11())
if (UsesX11())
#elif PLATFORM_LINUX || PLATFORM_MAC
{
Float2 pos;
SDL_GetGlobalMouseState(&pos.X, &pos.Y);
else
pos = Input::GetMouseScreenPosition();
return pos;
return pos;
}
#endif
return Input::GetMouseScreenPosition();
}
void SDLPlatform::SetMousePosition(const Float2& pos)

View File

@@ -11,7 +11,10 @@ typedef struct tagMSG MSG;
#elif PLATFORM_LINUX
#include "Engine/Platform/Linux/LinuxPlatform.h"
union _XEvent;
#elif PLATFORM_MAC
#include "Engine/Platform/Mac/MacPlatform.h"
#else
static_assert(false, "Unsupported Platform");
#endif
class SDLWindow;
@@ -29,8 +32,13 @@ class FLAXENGINE_API SDLPlatform
: public LinuxPlatform
{
using base = LinuxPlatform;
#elif PLATFORM_MAC
: public MacPlatform
{
using base = MacPlatform;
#else
{
static_assert(false, "Unsupported Platform");
#endif
friend SDLWindow;
@@ -42,9 +50,11 @@ private:
static bool HandleEvent(SDL_Event& event);
#if PLATFORM_WINDOWS
static bool EventMessageHook(void* userdata, MSG* msg);
static bool SDLPlatform::EventFilterCallback(void* userdata, SDL_Event* event);
static bool EventFilterCallback(void* userdata, SDL_Event* event);
#elif PLATFORM_LINUX
static bool X11EventHook(void* userdata, _XEvent* xevent);
#elif PLATFORM_MAC
static bool EventFilterCallback(void* userdata, SDL_Event* event);
#endif
static void PreHandleEvents();
static void PostHandleEvents();

View File

@@ -30,6 +30,10 @@
#endif
#elif PLATFORM_LINUX
#include "Engine/Platform/Linux/IncludeX11.h"
#elif PLATFORM_MAC
#include <Cocoa/Cocoa.h>
#else
static_assert(false, "Unsupported Platform");
#endif
#define DefaultDPI 96
@@ -153,8 +157,18 @@ SDLWindow::SDLWindow(const CreateWindowSettings& settings)
_dpiScale = SDL_GetWindowDisplayScale(_window);
_dpi = Math::TruncToInt(_dpiScale * DefaultDPI);
SDL_SetWindowMinimumSize(_window, Math::TruncToInt(_settings.MinimumSize.X), Math::TruncToInt(_settings.MinimumSize.Y));
SDL_SetWindowMaximumSize(_window, Math::TruncToInt(_settings.MaximumSize.X), Math::TruncToInt(_settings.MaximumSize.Y));
Int2 minimumSize(Math::TruncToInt(_settings.MinimumSize.X) , Math::TruncToInt(_settings.MinimumSize.Y));
Int2 maximumSize(Math::TruncToInt(_settings.MaximumSize.X) , Math::TruncToInt(_settings.MaximumSize.Y));
SDL_SetWindowMinimumSize(_window, minimumSize.X, minimumSize.Y);
#if PLATFORM_MAC
// BUG: The maximum size is not enforced correctly, set it to real high value instead
if (maximumSize.X == 0)
maximumSize.X = 999999;
if (maximumSize.Y == 0)
maximumSize.Y = 999999;
#endif
SDL_SetWindowMaximumSize(_window, maximumSize.X, maximumSize.Y);
SDL_SetWindowHitTest(_window, &OnWindowHitTest, this);
InitSwapChain();
@@ -178,6 +192,11 @@ SDLWindow::SDLWindow(const CreateWindowSettings& settings)
if (xdndAware != 0)
X11::XChangeProperty(xDisplay, (X11::Window)_handle, xdndAware, (X11::Atom)4, 32, PropModeReplace, (unsigned char*)&xdndVersion, 1);
}
#elif PLATFORM_MAC
NSWindow* win = ((NSWindow*)_handle);
NSView* view = win.contentView;
[win unregisterDraggedTypes];
[win registerForDraggedTypes:@[NSPasteboardTypeFileURL, NSPasteboardTypeString, (NSString*)kUTTypeFileURL, (NSString*)kUTTypeUTF8PlainText]];
#endif
}
#endif
@@ -202,21 +221,11 @@ SDL_Window* SDLWindow::GetSDLWindow() const
#if PLATFORM_LINUX
void* SDLWindow::GetWaylandSurfacePtr() const
{
return SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr);
}
void* SDLWindow::GetWaylandDisplay() const
{
return SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, nullptr);
}
uintptr SDLWindow::GetX11WindowHandle() const
{
return (uintptr)SDL_GetNumberProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
}
void* SDLWindow::GetX11Display() const
{
return SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_X11_DISPLAY_POINTER, nullptr);

View File

@@ -56,7 +56,6 @@ public:
~SDLWindow();
private:
static SDLWindow* GetWindowFromEvent(const SDL_Event& event);
static SDLWindow* GetWindowWithSDLWindow(SDL_Window* window);
void HandleEvent(SDL_Event& event);
@@ -64,18 +63,10 @@ private:
void CheckForWindowResize();
void UpdateCursor();
#if PLATFORM_LINUX
DragDropEffect DoDragDropWayland(const StringView& data, Window* dragSourceWindow = nullptr, Float2 dragOffset = Float2::Zero);
DragDropEffect DoDragDropX11(const StringView& data);
#endif
public:
SDL_Window* GetSDLWindow() const;
#if PLATFORM_LINUX
void* GetWaylandSurfacePtr() const;
void* GetWaylandDisplay() const;
uintptr GetX11WindowHandle() const;
void* GetX11Display() const;
#endif
@@ -128,6 +119,10 @@ public:
Windows::HRESULT __stdcall DragLeave() override;
Windows::HRESULT __stdcall Drop(Windows::IDataObject* pDataObj, Windows::DWORD grfKeyState, Windows::POINTL pt, Windows::DWORD* pdwEffect) override;
#endif
#if PLATFORM_LINUX
DragDropEffect DoDragDropWayland(const StringView& data, Window* dragSourceWindow = nullptr, Float2 dragOffset = Float2::Zero);
DragDropEffect DoDragDropX11(const StringView& data);
#endif
};
#endif

View File

@@ -265,10 +265,12 @@ class AppleThread;
typedef AppleThread Thread;
class MacClipboard;
typedef MacClipboard Clipboard;
#if !PLATFORM_SDL
class MacPlatform;
typedef MacPlatform Platform;
class MacWindow;
typedef MacWindow Window;
#endif
class UnixNetwork;
typedef UnixNetwork Network;
class UserBase;

View File

@@ -43,6 +43,7 @@ public class volk : ThirdPartyModule
break;
case TargetPlatform.Mac:
options.PublicDefinitions.Add("VK_USE_PLATFORM_MACOS_MVK");
options.PublicDefinitions.Add("VK_USE_PLATFORM_METAL_EXT");
break;
case TargetPlatform.iOS:
options.PublicDefinitions.Add("VK_USE_PLATFORM_IOS_MVK");

3365
Source/ThirdParty/volk/volk.c vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -300,7 +300,9 @@ namespace Flax.Build
public static bool WithSDL(NativeCpp.BuildOptions options)
{
bool supportedPlatform = options.Platform.Target == TargetPlatform.Windows || options.Platform.Target == TargetPlatform.Linux;
bool supportedPlatform = options.Platform.Target == TargetPlatform.Windows ||
options.Platform.Target == TargetPlatform.Linux ||
options.Platform.Target == TargetPlatform.Mac;
return UseSDL && supportedPlatform;
}
}

View File

@@ -37,7 +37,6 @@ namespace Flax.Deps.Dependencies
return new[]
{
TargetPlatform.Mac,
TargetPlatform.iOS,
};
default: return new TargetPlatform[0];
}
@@ -48,7 +47,7 @@ namespace Flax.Deps.Dependencies
public override void Build(BuildOptions options)
{
string root = options.IntermediateFolder;
string configuration = "Release";
string configuration = "Debug";
const bool buildStatic = true;
var configs = new string[]
{
@@ -63,6 +62,7 @@ namespace Flax.Deps.Dependencies
"-DSDL_RENDER_VULKAN=OFF",
"-DSDL_DIRECTX=OFF",
"-DSDL_METAL=OFF",
"-DSDL_VULKAN=OFF",
"-DSDL_OPENGL=OFF",
"-DSDL_OPENGLES=OFF",
@@ -88,9 +88,9 @@ namespace Flax.Deps.Dependencies
Path.Combine(root, "include", "SDL3"),
};
CloneGitRepo(root, "https://github.com/libsdl-org/SDL");
GitFetch(root);
GitResetToCommit(root, "877399b2b2cf21e67554ed9046410f268ce1d1b2"); // 3.2.10
//CloneGitRepo(root, "https://github.com/libsdl-org/SDL");
//GitFetch(root);
//GitResetToCommit(root, "337f012de28fff96dc3ad023d08345b6f7cad1ef"); // 3.2.10
foreach (var platform in options.Platforms)
{
@@ -123,8 +123,9 @@ namespace Flax.Deps.Dependencies
break;
}
case TargetPlatform.Linux:
case TargetPlatform.Mac:
{
foreach (var architecture in new TargetArchitecture[] { TargetArchitecture.x64 })
foreach (var architecture in new [] { TargetArchitecture.x64, TargetArchitecture.ARM64 })
{
var buildDir = Path.Combine(root, "build-" + architecture.ToString());
@@ -147,11 +148,6 @@ namespace Flax.Deps.Dependencies
}
break;
}
case TargetPlatform.Mac:
{
// TODO
break;
}
}
}

View File

@@ -52,6 +52,14 @@ namespace Flax.Build.Platforms
options.LinkEnv.InputLibraries.Add("Cocoa.framework");
options.LinkEnv.InputLibraries.Add("QuartzCore.framework");
options.LinkEnv.InputLibraries.Add("AVFoundation.framework");
// SDL3 requires the following frameworks:
options.LinkEnv.InputLibraries.Add("Foundation.framework");
options.LinkEnv.InputLibraries.Add("GameController.framework");
options.LinkEnv.InputLibraries.Add("Carbon.framework");
options.LinkEnv.InputLibraries.Add("ForceFeedback.framework");
options.LinkEnv.InputLibraries.Add("UniformTypeIdentifiers.framework");
options.LinkEnv.InputLibraries.Add("CoreHaptics.framework");
}
protected override void AddArgsCommon(BuildOptions options, List<string> args)