Implement client-side window decorations for Editor windows
This commit is contained in:
@@ -269,6 +269,11 @@ String PlatformBase::GetDisplayServer()
|
||||
return String::Empty;
|
||||
}
|
||||
|
||||
bool PlatformBase::SupportsNativeDecorations()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool PlatformBase::Is64BitApp()
|
||||
|
||||
@@ -374,6 +374,11 @@ public:
|
||||
/// </summary>
|
||||
API_PROPERTY() static String GetDisplayServer();
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if system provides decorations for windows.
|
||||
/// </summary>
|
||||
API_PROPERTY() static bool SupportsNativeDecorations();
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if is running 64 bit application (otherwise 32 bit). It's compile-time constant.
|
||||
/// </summary>
|
||||
|
||||
@@ -35,6 +35,12 @@
|
||||
#include <wayland/xdg-shell.h>
|
||||
#include <wayland/xdg-toplevel-drag-v1.h>
|
||||
|
||||
namespace SDLImpl
|
||||
{
|
||||
extern String WaylandDisplayEnv;
|
||||
extern String XDGCurrentDesktop;
|
||||
}
|
||||
|
||||
class LinuxDropFilesData : public IGuiData
|
||||
{
|
||||
public:
|
||||
@@ -1611,8 +1617,7 @@ bool SDLPlatform::InitInternal()
|
||||
if (!CommandLine::Options.Headless.IsTrue() && waylandRequested)
|
||||
{
|
||||
// Ignore in X11 session
|
||||
String waylandDisplayEnv;
|
||||
if (!GetEnvironmentVariable(String("WAYLAND_DISPLAY"), waylandDisplayEnv))
|
||||
if (!SDLImpl::WaylandDisplayEnv.IsEmpty())
|
||||
{
|
||||
WaylandImpl::WaylandDisplay = (wl_display*)SDL_GetPointerProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER, nullptr);
|
||||
if (WaylandImpl::WaylandDisplay != nullptr)
|
||||
@@ -1721,11 +1726,15 @@ DragDropEffect SDLWindow::DoDragDrop(const StringView& data, const Float2& offse
|
||||
if (SDLPlatform::UsesWayland())
|
||||
{
|
||||
Float2 dragOffset = offset;
|
||||
if (_settings.HasBorder && dragSourceWindow == this)
|
||||
if (SDLPlatform::SupportsNativeDecorations() && _settings.HasBorder && dragSourceWindow == this)
|
||||
{
|
||||
// Wayland includes the decorations in the client-space coordinates, adjust the offset for it.
|
||||
// Assume the title decoration is 25px thick...
|
||||
// Assume the title decoration based on the current desktop environment...
|
||||
float topOffset = 25.0f;
|
||||
if (SDLImpl::XDGCurrentDesktop.Compare(String("KDE"), StringSearchCase::IgnoreCase) == 0)
|
||||
topOffset = 25.0f;
|
||||
else if (SDLImpl::XDGCurrentDesktop.Compare(String("GNOME"), StringSearchCase::IgnoreCase) == 0)
|
||||
topOffset = 48.0f;
|
||||
dragOffset += Float2(0.0f, topOffset);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,25 +27,41 @@
|
||||
|
||||
#define DefaultDPI 96
|
||||
|
||||
namespace
|
||||
namespace SDLImpl
|
||||
{
|
||||
int32 SystemDpi = 96;
|
||||
String UserLocale("en");
|
||||
bool WindowDecorationsSupported = true;
|
||||
String WaylandDisplayEnv;
|
||||
String XDGCurrentDesktop;
|
||||
}
|
||||
|
||||
bool SDLPlatform::Init()
|
||||
{
|
||||
#if PLATFORM_LINUX
|
||||
bool waylandSession = false;
|
||||
if (!GetEnvironmentVariable(String("WAYLAND_DISPLAY"), SDLImpl::WaylandDisplayEnv))
|
||||
waylandSession = true;
|
||||
GetEnvironmentVariable(String("XDG_CURRENT_DESKTOP"), SDLImpl::XDGCurrentDesktop);
|
||||
|
||||
if (CommandLine::Options.X11.IsTrue())
|
||||
{
|
||||
SDL_SetHintWithPriority(SDL_HINT_VIDEO_DRIVER, "x11", SDL_HINT_OVERRIDE);
|
||||
waylandSession = false;
|
||||
}
|
||||
else if (CommandLine::Options.Wayland.IsTrue())
|
||||
SDL_SetHintWithPriority(SDL_HINT_VIDEO_DRIVER, "wayland", SDL_HINT_OVERRIDE);
|
||||
else
|
||||
else if (waylandSession)
|
||||
{
|
||||
// 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);
|
||||
SDL_SetHintWithPriority(SDL_HINT_VIDEO_DRIVER, "wayland", SDL_HINT_OVERRIDE);
|
||||
}
|
||||
|
||||
// Workaround for libdecor in Gnome+Wayland causing freezes when interacting with the native decorations
|
||||
if (waylandSession && SDLImpl::XDGCurrentDesktop.Compare(String("GNOME"), StringSearchCase::IgnoreCase) == 0)
|
||||
{
|
||||
SDL_SetHint(SDL_HINT_VIDEO_WAYLAND_ALLOW_LIBDECOR, "0");
|
||||
SDLImpl::WindowDecorationsSupported = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -95,9 +111,9 @@ bool SDLPlatform::Init()
|
||||
if (language.StartsWith("en"))
|
||||
{
|
||||
if (country != nullptr)
|
||||
UserLocale = String::Format(TEXT("{0}-{1}"), String(language), String(locales[i]->country));
|
||||
SDLImpl::UserLocale = String::Format(TEXT("{0}-{1}"), String(language), String(locales[i]->country));
|
||||
else
|
||||
UserLocale = String(language);
|
||||
SDLImpl::UserLocale = String(language);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -124,7 +140,7 @@ bool SDLPlatform::Init()
|
||||
SDLInput::Init();
|
||||
SDLWindow::Init();
|
||||
|
||||
SystemDpi = (int)(SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()) * DefaultDPI);
|
||||
SDLImpl::SystemDpi = (int)(SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()) * DefaultDPI);
|
||||
|
||||
//SDL_StartTextInput(); // TODO: Call this only when text input is expected (shows virtual keyboard in some cases)
|
||||
|
||||
@@ -183,6 +199,11 @@ String SDLPlatform::GetDisplayServer()
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SDLPlatform::SupportsNativeDecorations()
|
||||
{
|
||||
return SDLImpl::WindowDecorationsSupported;
|
||||
}
|
||||
|
||||
BatteryInfo SDLPlatform::GetBatteryInfo()
|
||||
{
|
||||
BatteryInfo info;
|
||||
@@ -213,12 +234,12 @@ BatteryInfo SDLPlatform::GetBatteryInfo()
|
||||
|
||||
int32 SDLPlatform::GetDpi()
|
||||
{
|
||||
return SystemDpi;
|
||||
return SDLImpl::SystemDpi;
|
||||
}
|
||||
|
||||
String SDLPlatform::GetUserLocaleName()
|
||||
{
|
||||
return UserLocale;
|
||||
return SDLImpl::UserLocale;
|
||||
}
|
||||
|
||||
void SDLPlatform::OpenUrl(const StringView& url)
|
||||
|
||||
@@ -74,6 +74,7 @@ public:
|
||||
static void LogInfo();
|
||||
static void Tick();
|
||||
static String GetDisplayServer();
|
||||
static bool SupportsNativeDecorations();
|
||||
static void SetHighDpiAwarenessEnabled(bool enable);
|
||||
static BatteryInfo GetBatteryInfo();
|
||||
static int32 GetDpi();
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
#define NOGDI
|
||||
#include <SDL3/SDL_events.h>
|
||||
#include <SDL3/SDL_hints.h>
|
||||
#include <SDL3/SDL_properties.h>
|
||||
#include <SDL3/SDL_video.h>
|
||||
#undef CreateWindow
|
||||
@@ -45,12 +44,12 @@ static_assert(false, "Unsupported Platform");
|
||||
|
||||
#define DefaultDPI 96
|
||||
|
||||
namespace WindowImpl
|
||||
namespace SDLImpl
|
||||
{
|
||||
SDLWindow* LastEventWindow = nullptr;
|
||||
static SDL_Cursor* Cursors[SDL_SYSTEM_CURSOR_COUNT] = { nullptr };
|
||||
SDL_Cursor* Cursors[SDL_SYSTEM_CURSOR_COUNT] = { nullptr };
|
||||
extern String XDGCurrentDesktop;
|
||||
}
|
||||
using namespace WindowImpl;
|
||||
|
||||
SDL_HitTestResult OnWindowHitTest(SDL_Window* win, const SDL_Point* area, void* data);
|
||||
void GetRelativeWindowOffset(WindowType type, SDLWindow* parentWindow, Int2& positionOffset);
|
||||
@@ -208,7 +207,7 @@ SDLWindow::SDLWindow(const CreateWindowSettings& settings)
|
||||
}
|
||||
#endif
|
||||
|
||||
LastEventWindow = this;
|
||||
SDLImpl::LastEventWindow = this;
|
||||
|
||||
#if PLATFORM_LINUX
|
||||
// Initialize using the shared Display instance from SDL
|
||||
@@ -263,8 +262,8 @@ void* SDLWindow::GetX11Display() const
|
||||
|
||||
SDLWindow::~SDLWindow()
|
||||
{
|
||||
if (LastEventWindow == this)
|
||||
LastEventWindow = nullptr;
|
||||
if (SDLImpl::LastEventWindow == this)
|
||||
SDLImpl::LastEventWindow = nullptr;
|
||||
|
||||
if (_window == nullptr)
|
||||
return;
|
||||
@@ -281,45 +280,48 @@ SDLWindow::~SDLWindow()
|
||||
_visible = false;
|
||||
}
|
||||
|
||||
WindowHitCodes SDLWindow::OnWindowHit(const Float2 point)
|
||||
{
|
||||
WindowHitCodes hit = WindowHitCodes::Client;
|
||||
if (!IsFullscreen())
|
||||
{
|
||||
Float2 screenPosition = ClientToScreen(point);
|
||||
bool handled = false;
|
||||
OnHitTest(screenPosition, hit, handled);
|
||||
if (!handled)
|
||||
{
|
||||
int margin = _settings.HasBorder ? 0 : 0;
|
||||
auto size = GetClientSize();
|
||||
//if (point.Y < 0)
|
||||
// hit = WindowHitCodes::Caption;
|
||||
if (point.Y < margin && point.X < margin)
|
||||
hit = WindowHitCodes::TopLeft;
|
||||
else if (point.Y < margin && point.X > size.X - margin)
|
||||
hit = WindowHitCodes::TopRight;
|
||||
else if (point.Y < margin)
|
||||
hit = WindowHitCodes::Top;
|
||||
else if (point.X < margin && point.Y > size.Y - margin)
|
||||
hit = WindowHitCodes::BottomLeft;
|
||||
else if (point.X < margin)
|
||||
hit = WindowHitCodes::Left;
|
||||
else if (point.X > size.X - margin && point.Y > size.Y - margin)
|
||||
hit = WindowHitCodes::BottomRight;
|
||||
else if (point.X > size.X - margin)
|
||||
hit = WindowHitCodes::Right;
|
||||
else if (point.Y > size.Y - margin)
|
||||
hit = WindowHitCodes::Bottom;
|
||||
else
|
||||
hit = WindowHitCodes::Client;
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
SDL_HitTestResult OnWindowHitTest(SDL_Window* win, const SDL_Point* area, void* data)
|
||||
{
|
||||
SDLWindow* window = (SDLWindow*)data;
|
||||
if (window->IsFullscreen())
|
||||
return SDL_HITTEST_NORMAL;
|
||||
|
||||
Float2 clientPosition = Float2(static_cast<float>(area->x), static_cast<float>(area->y));
|
||||
Float2 screenPosition = window->ClientToScreen(clientPosition);
|
||||
|
||||
WindowHitCodes hit = WindowHitCodes::Client;
|
||||
bool handled = false;
|
||||
window->OnHitTest(screenPosition, hit, handled);
|
||||
|
||||
if (!handled)
|
||||
{
|
||||
int margin = window->GetSettings().HasBorder ? 0 : 0;
|
||||
auto size = window->GetClientSize();
|
||||
//if (clientPosition.Y < 0)
|
||||
// return SDL_HITTEST_DRAGGABLE;
|
||||
if (clientPosition.Y < margin && clientPosition.X < margin)
|
||||
return SDL_HITTEST_RESIZE_TOPLEFT;
|
||||
else if (clientPosition.Y < margin && clientPosition.X > size.X - margin)
|
||||
return SDL_HITTEST_RESIZE_TOPRIGHT;
|
||||
else if (clientPosition.Y < margin)
|
||||
return SDL_HITTEST_RESIZE_TOP;
|
||||
else if (clientPosition.X < margin && clientPosition.Y > size.Y - margin)
|
||||
return SDL_HITTEST_RESIZE_BOTTOMLEFT;
|
||||
else if (clientPosition.X < margin)
|
||||
return SDL_HITTEST_RESIZE_LEFT;
|
||||
else if (clientPosition.X > size.X - margin && clientPosition.Y > size.Y - margin)
|
||||
return SDL_HITTEST_RESIZE_BOTTOMRIGHT;
|
||||
else if (clientPosition.X > size.X - margin)
|
||||
return SDL_HITTEST_RESIZE_RIGHT;
|
||||
else if (clientPosition.Y > size.Y - margin)
|
||||
return SDL_HITTEST_RESIZE_BOTTOM;
|
||||
else
|
||||
return SDL_HITTEST_NORMAL;
|
||||
}
|
||||
|
||||
SDLWindow* window = static_cast<SDLWindow*>(data);
|
||||
const Float2 point(static_cast<float>(area->x), static_cast<float>(area->y));
|
||||
WindowHitCodes hit = window->OnWindowHit(point);
|
||||
switch (hit)
|
||||
{
|
||||
case WindowHitCodes::Caption:
|
||||
@@ -350,9 +352,9 @@ SDLWindow* SDLWindow::GetWindowFromEvent(const SDL_Event& event)
|
||||
SDL_Window* window = SDL_GetWindowFromEvent(&event);
|
||||
if (window == nullptr)
|
||||
return nullptr;
|
||||
if (LastEventWindow == nullptr || window != LastEventWindow->_window)
|
||||
LastEventWindow = GetWindowWithSDLWindow(window);
|
||||
return LastEventWindow;
|
||||
if (SDLImpl::LastEventWindow == nullptr || window != SDLImpl::LastEventWindow->_window)
|
||||
SDLImpl::LastEventWindow = GetWindowWithSDLWindow(window);
|
||||
return SDLImpl::LastEventWindow;
|
||||
}
|
||||
|
||||
SDLWindow* SDLWindow::GetWindowWithSDLWindow(SDL_Window* window)
|
||||
@@ -779,8 +781,8 @@ Float2 SDLWindow::ClientToScreen(const Float2& clientPos) const
|
||||
void SDLWindow::FlashWindow()
|
||||
{
|
||||
#if PLATFORM_LINUX
|
||||
// Flashing brings the window on top of other windows, disable it for now
|
||||
if (SDLPlatform::UsesWayland())
|
||||
// KDE bug: flashing brings the window on top of other windows, disable it for now...
|
||||
if (SDLPlatform::UsesWayland() && SDLImpl::XDGCurrentDesktop.Compare(String("KDE"), StringSearchCase::IgnoreCase) == 0)
|
||||
return;
|
||||
#endif
|
||||
SDL_FlashWindow(_window, SDL_FLASH_UNTIL_FOCUSED);
|
||||
@@ -989,9 +991,9 @@ void SDLWindow::UpdateCursor()
|
||||
break;
|
||||
}
|
||||
|
||||
if (Cursors[index] == nullptr)
|
||||
Cursors[index] = SDL_CreateSystemCursor(static_cast<SDL_SystemCursor>(index));
|
||||
SDL_SetCursor(Cursors[index]);
|
||||
if (SDLImpl::Cursors[index] == nullptr)
|
||||
SDLImpl::Cursors[index] = SDL_CreateSystemCursor(static_cast<SDL_SystemCursor>(index));
|
||||
SDL_SetCursor(SDLImpl::Cursors[index]);
|
||||
}
|
||||
|
||||
void SDLWindow::SetIcon(TextureData& icon)
|
||||
|
||||
@@ -69,6 +69,7 @@ public:
|
||||
void* GetWaylandDisplay() const;
|
||||
void* GetX11Display() const;
|
||||
#endif
|
||||
WindowHitCodes OnWindowHit(const Float2 point);
|
||||
|
||||
// [WindowBase]
|
||||
void* GetNativePtr() const override;
|
||||
|
||||
@@ -10,13 +10,16 @@
|
||||
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Platform/IGuiData.h"
|
||||
#include "Engine/Platform/Base/DragDropHelper.h"
|
||||
#include "Engine/Input/Input.h"
|
||||
#include "Engine/Input/Mouse.h"
|
||||
#endif
|
||||
#include "../Win32/IncludeWindowsHeaders.h"
|
||||
|
||||
#include "Engine/Platform/Win32/IncludeWindowsHeaders.h"
|
||||
#include <propidl.h>
|
||||
|
||||
#if USE_EDITOR
|
||||
#include <oleidl.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
Reference in New Issue
Block a user