_windows window and tab dragging done

This commit is contained in:
2025-01-19 21:56:10 +02:00
parent 28957fea3e
commit 0aefdf4411
10 changed files with 438 additions and 160 deletions

View File

@@ -418,7 +418,7 @@ public:
public:
/// <summary>
/// Starts drag and drop operation
/// Starts a drag and drop operation.
/// </summary>
/// <param name="data">The data.</param>
/// <returns>The result.</returns>
@@ -427,6 +427,18 @@ public:
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>
/// Starts the mouse tracking.
/// </summary>
@@ -753,20 +765,6 @@ public:
{
}
/// <summary>
/// Create docking hint points for snapping the draggable window.
/// </summary>
API_FUNCTION() virtual void CreateDockHints()
{
}
/// <summary>
/// Remove docking hint points.
/// </summary>
API_FUNCTION() virtual void RemoveDockHints()
{
}
public:
void OnShow();
void OnResize(int32 width, int32 height);

View File

@@ -7,10 +7,20 @@
#include "Engine/Core/Collections/Array.h"
#include "Engine/Platform/WindowsManager.h"
#include "Engine/Platform/Win32/IncludeWindowsHeaders.h"
#include "Engine/Input/Mouse.h"
#include <SDL3/SDL_hints.h>
#include <SDL3/SDL_init.h>
#include <SDL3/SDL_system.h>
#include <SDL3/SDL_timer.h>
#include "SDLInput.h"
#include <Engine/Core/Log.h>
#if true
Window* draggedWindow = nullptr;
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
bool SDLCALL SDLPlatform::EventMessageHook(void* userdata, MSG* msg)
@@ -31,23 +41,73 @@ bool SDLCALL SDLPlatform::EventMessageHook(void* userdata, MSG* msg)
ASSERT((window) != nullptr); \
} while (false)
if (draggedWindow != nullptr)
{
LOG(Info, "event hook message: {}", msg->message);
}
if (msg->message == WM_NCLBUTTONDOWN)
{
Window* window;
GET_WINDOW_WITH_HWND(window, msg->hwnd);
draggedWindow = window;
draggedWindowStartPosition = draggedWindow->GetClientPosition();
draggedWindowMousePosition.X = static_cast<float>(static_cast<LONG>(WINDOWS_GET_X_LPARAM(msg->lParam)));
draggedWindowMousePosition.Y = static_cast<float>(static_cast<LONG>(WINDOWS_GET_Y_LPARAM(msg->lParam)));
draggedWindowMousePosition -= draggedWindowStartPosition;
//auto hit = static_cast<WindowHitCodes>(msg->wParam);
//if (SDLPlatform::CheckWindowDragging(window, hit))
// return false;
//bool result = false;
//window->OnLeftButtonHit(static_cast<WindowHitCodes>(msg->wParam), result);
//if (result)
// return false;
auto hit = static_cast<WindowHitCodes>(msg->wParam);
if (SDLPlatform::CheckWindowDragging(window, hit))
return false;
//::ClientToScreen(static_cast<HWND>(window->GetNativePtr()), &p);
//const Float2 mousePos(static_cast<float>(p.x), static_cast<float>(p.y));
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 = draggedWindowMousePosition.X;
event.button.y = 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;
#undef GET_WINDOW_WITH_HWND
}
#endif
bool SDLPlatform::InitPlatform()
{
#if true
// Workaround required for handling window dragging events properly for DockHintWindow
SDL_SetWindowsMessageHook(&EventMessageHook, nullptr);
#endif
if (WindowsPlatform::Init())
return true;

View File

@@ -10,6 +10,7 @@
#include "Engine/Platform/BatteryInfo.h"
#include "Engine/Platform/WindowsManager.h"
#include "Engine/Platform/SDL/SDLInput.h"
#include "Engine/Engine/Engine.h"
#include <SDL3/SDL_hints.h>
#include <SDL3/SDL_init.h>
@@ -25,6 +26,7 @@
#include "Engine/Platform/MessageBox.h"
#include <SDL3/SDL_messagebox.h>
#endif
#include <SDL3/SDL_timer.h>
#define DefaultDPI 96
@@ -142,10 +144,15 @@ bool SDLPlatform::CheckWindowDragging(Window* window, WindowHitCodes hit)
return handled;
}
extern Window* draggedWindow;
extern Float2 draggedWindowStartPosition;
extern Float2 draggedWindowMousePosition;
void SDLPlatform::Tick()
{
SDLInput::Update();
#if false
if (DraggedWindowId != 0)
{
Float2 mousePos;
@@ -200,6 +207,129 @@ void SDLPlatform::Tick()
#endif
}
}
#endif
auto watch = [](void* userdata, SDL_Event* event) -> bool
{
Window* draggedWindow = *(Window**)userdata;
if (draggedWindow == nullptr)
return true;
SDLWindow* window = SDLWindow::GetWindowFromEvent(*event);
if (event->type == SDL_EVENT_WINDOW_EXPOSED)
{
/*SDL_Event mouseDownEvent{ 0 };
mouseDownEvent.button.type = SDL_EVENT_MOUSE_BUTTON_DOWN;
mouseDownEvent.button.down = true;
mouseDownEvent.button.timestamp = SDL_GetTicksNS();
mouseDownEvent.button.windowID = SDL_GetWindowID(window->GetSDLWindow());
mouseDownEvent.button.button = SDL_BUTTON_LEFT;
mouseDownEvent.button.clicks = 1;
mouseDownEvent.button.x = 0;//static_cast<float>(static_cast<LONG>(WINDOWS_GET_X_LPARAM(msg->lParam)));
mouseDownEvent.button.y = 0;//static_cast<float>(static_cast<LONG>(WINDOWS_GET_Y_LPARAM(msg->lParam)));
if (window)
window->HandleEvent(*event);*/
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_MOUSE_BUTTON_UP)
{
LOG(Info, "ate SDL_EVENT_MOUSE_BUTTON_UP");
return false;
}*/
else if (event->type == SDL_EVENT_WINDOW_MOVED)
{
Float2 start = draggedWindowStartPosition;
Float2 newPos = Float2(static_cast<float>(event->window.data1), static_cast<float>(event->window.data2));
Float2 offset = newPos - start;
Float2 mousePos = draggedWindowMousePosition/* + offset*/;
SDL_Event mouseMovedEvent { 0 };
mouseMovedEvent.motion.type = SDL_EVENT_MOUSE_MOTION;
mouseMovedEvent.motion.windowID = SDL_GetWindowID(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);
/*bool* dragging = (bool*)userdata;
if (event->type == SDL_EVENT_WINDOW_EXPOSED)
{
// This event is usually sent when the window is focused and requires redrawing,
// but we are more interested in these events when the window is being dragged,
// blocking the main thread during the drag operation. Assume the window is being
// dragged when we have received the event more than once per cycle.
bool result = true;
if (*dragging)
{
// Send a simulated mouse button down event, we can't tell when
// the real button down event arrives...
SDLWindow* window = SDLWindow::GetWindowFromEvent(*event);
SDL_Event mouseDownEvent{ 0 };
mouseDownEvent.button.type = SDL_EVENT_MOUSE_BUTTON_DOWN;
mouseDownEvent.button.down = true;
mouseDownEvent.button.timestamp = SDL_GetTicksNS();
mouseDownEvent.button.windowID = SDL_GetWindowID(window->GetSDLWindow());
mouseDownEvent.button.button = SDL_BUTTON_LEFT;
mouseDownEvent.button.clicks = 1;
mouseDownEvent.button.x = 0;//static_cast<float>(static_cast<LONG>(WINDOWS_GET_X_LPARAM(msg->lParam)));
mouseDownEvent.button.y = 0;//static_cast<float>(static_cast<LONG>(WINDOWS_GET_Y_LPARAM(msg->lParam)));
if (window)
window->HandleEvent(*event);
Engine::OnUpdate();//Scripting::Update(); // For docking updates
Engine::OnDraw();
return false;
}
else
*dragging = true;
return true;
}*/
/*else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN && *dragging)
{
SDLWindow* window = SDLWindow::GetWindowFromEvent(*event);
if (window)
window->HandleEvent(*event);
return false;
}*/
/*if (dragging)
{
LOG(Info, "events during dragging: {}", event->type); // usually SDL_EVENT_WINDOW_MOVED
}*/
return true;
};
bool suc = SDL_AddEventWatch(watch, &draggedWindow);
if (!suc)
suc = suc;
SDL_PumpEvents();
SDL_Event events[32];
@@ -214,6 +344,24 @@ void SDLPlatform::Tick()
else
SDLPlatform::HandleEvent(events[i]);
}
SDL_RemoveEventWatch(watch, &draggedWindow);
if (draggedWindow != nullptr)
{
// We are no longer dragging since event loop is no longer blocked
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(draggedWindow->GetSDLWindow());
event.button.button = SDL_BUTTON_LEFT;
event.button.clicks = 1;
event.button.x = 0;//static_cast<float>(static_cast<LONG>(WINDOWS_GET_X_LPARAM(msg->lParam)));
event.button.y = 0;//static_cast<float>(static_cast<LONG>(WINDOWS_GET_Y_LPARAM(msg->lParam)));
SDL_PushEvent(&event);
draggedWindow = nullptr;
}
}
bool SDLPlatform::HandleEvent(SDL_Event& event)
@@ -275,8 +423,10 @@ Float2 SDLPlatform::GetMousePosition()
// Use the last known reported position we got from window events.
pos = Input::GetMouseScreenPosition();
}
else
SDL_GetGlobalMouseState(&pos.X, &pos.Y);
//else
// SDL_GetGlobalMouseState(&pos.X, &pos.Y);
#else
pos = Input::GetMouseScreenPosition();
#endif
return pos;
}

View File

@@ -406,6 +406,8 @@ SDLWindow* SDLWindow::GetWindowWithSDLWindow(SDL_Window* window)
return nullptr;
}
extern Window* draggedWindow;
void SDLWindow::HandleEvent(SDL_Event& event)
{
if (_isClosing)
@@ -413,6 +415,11 @@ void SDLWindow::HandleEvent(SDL_Event& event)
switch (event.type)
{
/*case SDL_EVENT_WINDOW_EXPOSED:
{
LOG(Info, "SDL_EVENT_WINDOW_EXPOSED");
break;
}*/
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
{
Close(ClosingReason::User);
@@ -738,9 +745,15 @@ void SDLWindow::HandleEvent(SDL_Event& event)
#endif
break;
}
#if PLATFORM_LINUX
//#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");
@@ -748,10 +761,26 @@ void SDLWindow::HandleEvent(SDL_Event& event)
return;
}
else
LOG(Info, "SDL_EVENT_MOUSE_BUTTON_UP");
#endif
{
LOG(Info, "SDL_EVENT_MOUSE_BUTTON_UP: {}", GetTitle());
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);
}
}
break;
}
#endif
//#endif
default:
break;
}
@@ -916,10 +945,12 @@ bool SDLWindow::IsForegroundWindow() const
void SDLWindow::BringToFront(bool force)
{
/*auto activateWhenRaised = SDL_GetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED);
#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);*/
SDL_SetHint(SDL_HINT_WINDOW_ACTIVATE_WHEN_RAISED, activateWhenRaised);
#endif
}
void SDLWindow::SetClientBounds(const Rectangle& clientArea)
@@ -1203,7 +1234,7 @@ void SDLWindow::UpdateCursor()
{
if (_cursor == CursorType::Hidden)
{
//SDL_HideCursor();
SDL_HideCursor();
if (_isTrackingMouse)
Input::Mouse->SetRelativeMode(true, this);
@@ -1259,39 +1290,10 @@ void SDLWindow::UpdateCursor()
SDL_SetCursor(Cursors[index]);
}
//extern wl_data_device* dataDevice;
//wl_data_source* dataSource;
/*void OnBeforeSurfaceCommit(void* data)
{
wl_display_flush((wl_display*)SDL_GetPointerProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER, nullptr));
SDLWindow* window = static_cast<SDLWindow*>(data);
LOG(Info, "OnBeforeSurfaceCommit");
auto _window = window->GetSDLWindow();
SDL_SetPointerProperty(SDL_GetWindowProperties(_window), "SDL.window.wayland.callback", nullptr);
SDL_SetPointerProperty(SDL_GetWindowProperties(_window), "SDL.window.wayland.callback.data", nullptr);
xdg_toplevel* toplevel = (xdg_toplevel*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, nullptr);
toplevelDrag = xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag(DragManager, dataSource);
wl_surface* origin = (wl_surface*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr);
wl_surface* icon = nullptr;
uint32 id = LastPointerSerial;
wl_data_device_start_drag(dataDevice, dataSource, origin, icon, id);
Float2 offset = Float2::Zero;
Float2 scaledOffset = offset / window->GetDpiScale();
xdg_toplevel_drag_v1_attach(toplevelDrag, toplevel, (int32)scaledOffset.X, (int32)scaledOffset.Y);
wl_display_flush((wl_display*)SDL_GetPointerProperty(SDL_GetGlobalProperties(), SDL_PROP_GLOBAL_VIDEO_WAYLAND_WL_DISPLAY_POINTER, nullptr));
}*/
void SDLWindow::StartDragging(const Float2& offset, Window* dragSourceWindow)
//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;
@@ -1308,41 +1310,51 @@ void SDLWindow::StartDragging(const Float2& offset, Window* dragSourceWindow)
#endif
}
//SetOpacity(0.1f);
#if PLATFORM_LINUX
SetOpacity(0.1f);
if (SDLPlatform::UsesWayland()
DoDragDropWayland(String("notawindow"), dragSourceWindow, dragOffset);
#endif
/*
_dragOver = true;
wl_data_device_set_user_data(dataDevice, this);
// We offer the following types of things for consumption:
dataSource = wl_data_device_manager_create_data_source(WaylandDataDeviceManager);
wl_data_source_offer(dataSource, "x.flaxengine.window.snap");
wl_data_source_set_actions(dataSource, wl_data_device_manager_dnd_action::WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | wl_data_device_manager_dnd_action::WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
wl_data_source_add_listener(dataSource, &WaylandDataSourceListener, this);
xdg_toplevel* toplevel = (xdg_toplevel*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, nullptr);
if (toplevel == nullptr)
{
SDL_SetPointerProperty(SDL_GetWindowProperties(_window), "SDL.window.wayland.callback", (void*)OnBeforeSurfaceCommit);
SDL_SetPointerProperty(SDL_GetWindowProperties(_window), "SDL.window.wayland.callback.data", this);
}
else
#endif
{
toplevelDrag = xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag(DragManager, dataSource);
Show();
//draggingActive = true;
wl_surface* origin = (wl_surface*)SDL_GetPointerProperty(SDL_GetWindowProperties(_window), SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, nullptr);
wl_surface* icon = nullptr;
uint32 id = LastPointerSerial;
wl_data_device_start_drag(dataDevice, dataSource, origin, icon, id);
/*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;
};
Float2 scaledOffset = offset / _dpiScale;
xdg_toplevel_drag_v1_attach(toplevelDrag, toplevel, (int32)scaledOffset.X, (int32)scaledOffset.Y);
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;
}
void SDLWindow::StartDragging(const Float2& offset, Window* dragSourceWindow)
{
}
void SDLWindow::StopDragging()
@@ -1350,22 +1362,7 @@ void SDLWindow::StopDragging()
LOG(Info, "StopDragging");
SetOpacity(1.0f);
/*
wl_data_device_set_user_data(dataDevice, nullptr);
_dragOver = false;
if (toplevelDrag != nullptr)
{
xdg_toplevel_drag_v1_destroy(toplevelDrag);
toplevelDrag = nullptr;
}
if (dataSource != nullptr)
{
wl_data_source_destroy(dataSource);
dataSource = nullptr;
}
*/
//draggingActive = false;
}
#endif

View File

@@ -103,6 +103,7 @@ public:
String GetTitle() const override;
void SetTitle(const StringView& title) override;
DragDropEffect DoDragDrop(const StringView& data) override;
DragDropEffect DoDragDrop(const StringView& data, const Float2& offset, Window* dragSourceWindow);
void StartTrackingMouse(bool useMouseScreenOffset) override;
void EndTrackingMouse() override;
void StartClippingCursor(const Rectangle& bounds) override;