From e998db7cea963d9f2cc4d19057e48a87a01a3973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BE=90=E6=89=AC=E6=96=8C?= Date: Mon, 29 Apr 2024 14:37:38 +0800 Subject: [PATCH] MacOSX: Keep DoDragDrop() from re-entering to enable a proper working CEF. DoDragDrop() may make CEF cease to work. One way to reproduce the problem: Do drag-n-drop repeatly, that is, start drag immediately after one drop, then there're chances we can see large amount of DoDragDrop() in the callstack of the UI-thread. And finally leads to stack overflow. Messages processed by CEF are handled when wxEVT_IDLE is triggered. The basic loop are: -> Step1, cocoa call OSXDefaultModeObserverCallBack(in src/osx/core/evtloop_cf.cpp) -> Step2, wxEVT_IDLE is triggered. -> Step3, wxWebViewChroium::OnIdle() takes the cake. -> Step4, CefDoMessageLoopWork() do the jobs for CEF. If DoDragDrop() is invoked during CefDoMessageLoopWork(), and together there comes a recursive call to it, then the previous DoDragDrop() can't return anymore, and will, in turn, prevent CefDoMessageLoopWork() from returning to the caller. And finally overflow the stack. And now we add the global dnd flag to stay away from this kind of tragic. --- src/osx/cocoa/dnd.mm | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/osx/cocoa/dnd.mm b/src/osx/cocoa/dnd.mm index 00b6c3d159e0..83884b514785 100644 --- a/src/osx/cocoa/dnd.mm +++ b/src/osx/cocoa/dnd.mm @@ -485,11 +485,16 @@ - (nullable id)pasteboardPropertyListForType:(nonnull NSPasteboardType)type wxDragResult wxDropSource::DoDragDrop(int flags) { wxASSERT_MSG( m_data, wxT("Drop source: no data") ); - + static bool g_in_dnd = false; + wxDragResult result = wxDragNone; if ((m_data == nullptr) || (m_data->GetFormatCount() == 0)) return result; - + + if (g_in_dnd) + return wxDragNone; + + g_in_dnd = true; NSView* view = m_window->GetPeer()->GetWXWidget(); if (view) { @@ -554,8 +559,8 @@ - (nullable id)pasteboardPropertyListForType:(nonnull NSPasteboardType)type gCurrentSource = nullptr; } - - + + g_in_dnd = false; return result; }