Implement new window dragging system
This commit is contained in:
@@ -33,8 +33,23 @@
|
||||
#endif
|
||||
#elif PLATFORM_LINUX
|
||||
#include "Engine/Platform/Linux/IncludeX11.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include <wayland/xdg-toplevel-drag-v1.h>
|
||||
#include <wayland/xdg-shell.h>
|
||||
|
||||
extern Dictionary<wl_surface*, SDLWindow*> SurfaceToWindowMap;
|
||||
extern SDLWindow* LastPointerWindow;
|
||||
extern Int2 LastPointerPosition;
|
||||
extern uint32 ImplicitGrabSerial;
|
||||
extern xdg_toplevel_drag_manager_v1* DragManager;
|
||||
extern wl_seat* WaylandSeat;
|
||||
extern wl_data_device_manager* WaylandDataDeviceManager;
|
||||
extern xdg_wm_base* WaylandXdgWmBase;
|
||||
extern bool waylandDraggingActive;
|
||||
#endif
|
||||
|
||||
extern Window* draggedWindow;
|
||||
|
||||
#define DefaultDPI 96
|
||||
|
||||
namespace
|
||||
@@ -52,6 +67,11 @@ void GetRelativeWindowOffset(WindowType type, SDLWindow* parentWindow, Int2& pos
|
||||
Int2 GetSDLWindowScreenPosition(const SDLWindow* window);
|
||||
void SetSDLWindowScreenPosition(const SDLWindow* window, const int x, const int y);
|
||||
|
||||
bool IsPopupWindow(WindowType type)
|
||||
{
|
||||
return type == WindowType::Popup || type == WindowType::Tooltip;
|
||||
}
|
||||
|
||||
class SDLDropFilesData : public IGuiData
|
||||
{
|
||||
public:
|
||||
@@ -214,9 +234,9 @@ void* GetNativeWindowPointer(SDL_Window* 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);
|
||||
windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr);
|
||||
if (windowPtr == nullptr)
|
||||
windowPtr = (void*)SDL_GetNumberProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
|
||||
windowPtr = (void*)SDL_GetNumberProperty(props, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
|
||||
#elif PLATFORM_MAC
|
||||
windowPtr = SDL_GetPointerProperty(props, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, nullptr);
|
||||
#elif PLATFORM_ANDROID
|
||||
@@ -266,6 +286,9 @@ SDLWindow::~SDLWindow()
|
||||
if (_window == nullptr)
|
||||
return;
|
||||
|
||||
#if PLATFORM_LINUX
|
||||
SurfaceToWindowMap.RemoveValue(this);
|
||||
#endif
|
||||
SDL_StopTextInput(_window);
|
||||
SDL_DestroyWindow(_window);
|
||||
|
||||
@@ -419,8 +442,14 @@ void SDLWindow::HandleEvent(SDL_Event& event)
|
||||
// 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);
|
||||
if ((buttons & SDL_BUTTON_MASK(SDL_BUTTON_LEFT)) != 0 && draggedWindow == nullptr)
|
||||
{
|
||||
// TODO: verify mouse position, window focus
|
||||
bool result = false;
|
||||
OnLeftButtonHit(WindowHitCodes::Caption, result);
|
||||
if (result)
|
||||
draggedWindow = this;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
@@ -543,10 +572,49 @@ void SDLWindow::HandleEvent(SDL_Event& event)
|
||||
}
|
||||
return;
|
||||
}
|
||||
#if false
|
||||
case SDL_EVENT_DROP_BEGIN:
|
||||
#if true
|
||||
case SDL_EVENT_CLIPBOARD_UPDATE:
|
||||
{
|
||||
Focus();
|
||||
LOG(Info, "SDL_EVENT_CLIPBOARD_UPDATE");
|
||||
return;
|
||||
}
|
||||
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:
|
||||
{
|
||||
//LOG(Info, "SDL_EVENT_DROP_BEGIN");
|
||||
|
||||
static Float2 dragStartPosition = Float2::Zero;
|
||||
|
||||
auto dpiScale = GetDpiScale();
|
||||
//const Float2 mousePos = ClientToScreen({ event.drop.x * dpiScale, event.drop.y * dpiScale});
|
||||
const Float2 mousePos = dragStartPosition + Float2(event.drop.x * dpiScale, event.drop.y * dpiScale);
|
||||
DragDropEffect effect = DragDropEffect::None;
|
||||
auto daata = event.drop.data;
|
||||
|
||||
SDLDropTextData dropData;
|
||||
|
||||
|
||||
|
||||
if (event.type == SDL_EVENT_DROP_BEGIN)
|
||||
{
|
||||
dragStartPosition = Platform::GetMousePosition();
|
||||
OnDragEnter(&dropData, mousePos, effect);
|
||||
}
|
||||
else if (event.type == SDL_EVENT_DROP_POSITION)
|
||||
{
|
||||
Input::Mouse->OnMouseMove(mousePos, this);
|
||||
OnDragOver(&dropData, mousePos, effect);
|
||||
}
|
||||
else if (event.type == SDL_EVENT_DROP_FILE)
|
||||
OnDragDrop(&dropData, mousePos, effect);
|
||||
else if (event.type == SDL_EVENT_DROP_TEXT)
|
||||
OnDragDrop(&dropData, mousePos, effect);
|
||||
else if (event.type == SDL_EVENT_DROP_COMPLETE)
|
||||
OnDragLeave();
|
||||
/*Focus();
|
||||
Float2 mousePosition;
|
||||
SDL_GetGlobalMouseState(&mousePosition.X, &mousePosition.Y);
|
||||
mousePosition = ScreenToClient(mousePosition);
|
||||
@@ -554,49 +622,68 @@ void SDLWindow::HandleEvent(SDL_Event& event)
|
||||
DragDropEffect effect;
|
||||
SDLDropTextData dropData;
|
||||
OnDragEnter(&dropData, mousePosition, effect);
|
||||
OnDragOver(&dropData, mousePosition, effect);
|
||||
return;
|
||||
OnDragOver(&dropData, mousePosition, effect);*/
|
||||
break;
|
||||
}
|
||||
case SDL_EVENT_DROP_POSITION:
|
||||
/*case SDL_EVENT_DROP_POSITION:
|
||||
{
|
||||
auto dpiScale = GetDpiScale();
|
||||
//const Float2 mousePos = ClientToScreen({ event.drop.x * dpiScale, event.drop.y * dpiScale});
|
||||
const Float2 mousePos(event.drop.x * dpiScale, event.drop.y * dpiScale);
|
||||
DragDropEffect effect = DragDropEffect::None;
|
||||
auto daata = event.drop.data;
|
||||
|
||||
SDLDropTextData dropData;
|
||||
OnDragOver(&dropData, Float2(static_cast<float>(event.drop.x), static_cast<float>(event.drop.y)), effect);
|
||||
return;
|
||||
OnDragOver(&dropData, mousePos, effect);
|
||||
|
||||
break;
|
||||
}
|
||||
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);
|
||||
LOG(Info, "SDL_EVENT_DROP_FILE");
|
||||
auto dpiScale = GetDpiScale();
|
||||
const Float2 mousePos = ClientToScreen({ event.drop.x * dpiScale, event.drop.y * dpiScale});
|
||||
DragDropEffect effect = DragDropEffect::None;
|
||||
OnDragDrop(&dropData, mousePosition, effect);
|
||||
auto daata = event.drop.data;
|
||||
|
||||
SDLDropTextData dropData;
|
||||
OnDragDrop(&dropData, mousePos, 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);
|
||||
auto dpiScale = GetDpiScale();
|
||||
const Float2 mousePos = ClientToScreen({ event.drop.x * dpiScale, event.drop.y * dpiScale});
|
||||
DragDropEffect effect = DragDropEffect::None;
|
||||
OnDragDrop(&dropData, mousePosition, effect);
|
||||
auto daata = event.drop.data;
|
||||
auto str = String(event.drop.data);
|
||||
|
||||
LOG(Info, "SDL_EVENT_DROP_TEXT: {}", str);
|
||||
|
||||
SDLDropTextData dropData;
|
||||
OnDragDrop(&dropData, mousePos, effect);
|
||||
|
||||
return;
|
||||
}
|
||||
case SDL_EVENT_DROP_COMPLETE:
|
||||
{
|
||||
LOG(Info, "SDL_EVENT_DROP_COMPLETE");
|
||||
auto dpiScale = GetDpiScale();
|
||||
const Float2 mousePos = ClientToScreen({ event.drop.x * dpiScale, event.drop.y * dpiScale});
|
||||
DragDropEffect effect = DragDropEffect::None;
|
||||
auto daata = event.drop.data;
|
||||
|
||||
OnDragLeave();
|
||||
|
||||
if (SDLPlatform::UsesWayland())
|
||||
{
|
||||
//_dragOver = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
#endif
|
||||
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
|
||||
{
|
||||
@@ -605,6 +692,44 @@ void SDLWindow::HandleEvent(SDL_Event& event)
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
//#if PLATFORM_LINUX
|
||||
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
||||
{
|
||||
LOG(Info, "SDL_EVENT_MOUSE_BUTTON_DOWN");
|
||||
break;
|
||||
}
|
||||
case SDL_EVENT_MOUSE_BUTTON_UP:
|
||||
{
|
||||
#if PLATFORM_LINUX
|
||||
if (SDLPlatform::UsesWayland() && waylandDraggingActive)
|
||||
{
|
||||
LOG(Info, "SDL_EVENT_MOUSE_BUTTON_UP, dragging");
|
||||
// We are dragging a window, keep the button held down
|
||||
return;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
LOG(Info, "SDL_EVENT_MOUSE_BUTTON_UP: {}", GetTitle());
|
||||
#if PLATFORM_WINDOWS
|
||||
if (draggedWindow != nullptr && 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 = draggedWindow->ScreenToClient(mousePos);
|
||||
|
||||
SDL_Event event2 = event;
|
||||
event2.button.windowID = draggedWindow->_windowId;
|
||||
event2.button.x = clientPos.X;
|
||||
event2.button.y = clientPos.Y;
|
||||
|
||||
SDLInput::HandleEvent(draggedWindow, event2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
//#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -639,9 +764,9 @@ void SDLWindow::Show()
|
||||
else if (_settings.Parent == nullptr)
|
||||
BringToFront();
|
||||
|
||||
// Reused top-most windows (DockHintWindow) doesn't stay on top for some reason
|
||||
if (_settings.IsTopmost && _settings.Type != WindowType::Tooltip)
|
||||
SDL_SetWindowAlwaysOnTop(_window, true);
|
||||
// Reused top-most windows doesn't stay on top for some reason
|
||||
if (_settings.IsTopmost && !IsPopupWindow(_settings.Type))
|
||||
SetIsAlwaysOnTop(true);
|
||||
|
||||
if (_isTrackingMouse)
|
||||
{
|
||||
@@ -662,6 +787,11 @@ void SDLWindow::Hide()
|
||||
|
||||
SDL_HideWindow(_window);
|
||||
|
||||
#if PLATFORM_LINUX
|
||||
//if (SDLPlatform::UsesWayland() && _dragOver)
|
||||
// StopDragging();
|
||||
#endif
|
||||
|
||||
WindowBase::Hide();
|
||||
}
|
||||
|
||||
@@ -760,10 +890,20 @@ bool SDLWindow::IsForegroundWindow() const
|
||||
|
||||
void SDLWindow::BringToFront(bool force)
|
||||
{
|
||||
#if PLATFORM_WINDOWS // FIXME
|
||||
auto activateWhenRaised = SDL_GetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED);
|
||||
SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, "0");
|
||||
SDL_RaiseWindow(_window);
|
||||
SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, activateWhenRaised);
|
||||
#endif
|
||||
if (SDLPlatform::UsesX11())
|
||||
{
|
||||
auto activateWhenRaised = SDL_GetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED);
|
||||
SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, "0");
|
||||
SDL_RaiseWindow(_window);
|
||||
SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, activateWhenRaised);
|
||||
SDL_SyncWindow(_window);
|
||||
}
|
||||
}
|
||||
|
||||
void SDLWindow::SetClientBounds(const Rectangle& clientArea)
|
||||
@@ -777,11 +917,6 @@ void SDLWindow::SetClientBounds(const Rectangle& clientArea)
|
||||
SDL_SetWindowSize(_window, newW, newH);
|
||||
}
|
||||
|
||||
bool IsPopupWindow(WindowType type)
|
||||
{
|
||||
return type == WindowType::Popup || type == WindowType::Tooltip;
|
||||
}
|
||||
|
||||
void GetRelativeWindowOffset(WindowType type, SDLWindow* parentWindow, Int2& positionOffset)
|
||||
{
|
||||
if (!IsPopupWindow(type))
|
||||
@@ -848,7 +983,7 @@ void SDLWindow::SetIsFullscreen(bool isFullscreen)
|
||||
if (!isFullscreen)
|
||||
{
|
||||
// The window is set to always-on-top for some reason when leaving fullscreen
|
||||
SDL_SetWindowAlwaysOnTop(_window, false);
|
||||
SetIsAlwaysOnTop(false);
|
||||
}
|
||||
|
||||
WindowBase::SetIsFullscreen(isFullscreen);
|
||||
@@ -1116,5 +1251,68 @@ void SDLWindow::UpdateCursor()
|
||||
SDL_SetCursor(Cursors[index]);
|
||||
}
|
||||
|
||||
//bool draggingActive = false;
|
||||
DragDropEffect SDLWindow::DoDragDrop(const StringView& data, const Float2& offset, Window* dragSourceWindow)
|
||||
{
|
||||
// TODO: this needs to be non-blocking in all platforms
|
||||
LOG(Info, "StartDragging {}", offset);
|
||||
|
||||
Float2 dragOffset = offset;
|
||||
if (_settings.HasBorder)
|
||||
{
|
||||
#if PLATFORM_LINUX
|
||||
if (SDLPlatform::UsesWayland() && dragSourceWindow == this)
|
||||
{
|
||||
// Wayland includes the decorations in the client-space coordinates, adjust the offset for it.
|
||||
// Assume the title decoration is 25px thick...
|
||||
float topOffset = 25.0f;
|
||||
dragOffset += Float2(0.0f, topOffset);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PLATFORM_LINUX
|
||||
if (SDLPlatform::UsesWayland())
|
||||
DoDragDropWayland(String("notawindow"), dragSourceWindow, dragOffset);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Show();
|
||||
|
||||
//draggingActive = true;
|
||||
|
||||
/*auto watch = [](void* userdata, SDL_Event* event) -> bool
|
||||
{
|
||||
if (event->window.type == SDL_EVENT_WINDOW_EXPOSED)
|
||||
{
|
||||
LOG(Info, "exposedo");
|
||||
}
|
||||
else
|
||||
LOG(Info, "eventy");*/
|
||||
/*SDLPlatform::Tick();
|
||||
Engine::OnUpdate();//Scripting::Update(); // For docking updates
|
||||
Engine::OnDraw();*//*
|
||||
return true;
|
||||
};
|
||||
|
||||
SDL_AddEventWatch(watch, nullptr);*/
|
||||
|
||||
/*while (draggingActive)
|
||||
{
|
||||
SDLPlatform::Tick();
|
||||
Engine::OnUpdate();//Scripting::Update(); // For docking updates
|
||||
Engine::OnDraw();
|
||||
|
||||
Platform::Sleep(1);
|
||||
}*/
|
||||
|
||||
//SDL_RemoveEventWatch(watch, nullptr);
|
||||
|
||||
// The mouse up event was ignored earlier, release the button now
|
||||
//Input::Mouse->OnMouseUp(Platform::GetMousePosition(), MouseButton::Left, this);
|
||||
}
|
||||
return DragDropEffect::None;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user