diff options
author | Alexandru Croitor <alexandru.croitor@theqtcompany.com> | 2016-01-20 13:21:26 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2016-01-23 15:37:03 +0000 |
commit | 4bf3b18d3089987e8b1e6a1a0bb9cd6a024e85c7 (patch) | |
tree | e08ab3477af4d743cce7ba1f438e37d6201e7955 /src/core/web_contents_adapter.cpp | |
parent | 96f120fd9ec94befcf0cc510ef40a7730677c0ad (diff) |
Fix un-processed drag events not being handled on OSX.
When a QDragMoveEvent is posted, we have to notify Chromium, and wait
synchronously, for the possible drag and drop action at the respective
coordinates. This is done by executing an inner event loop.
The drag move event was processed in the inner event loop as a
side-effect, specifically when another event (like a QMouseMove or
QKeyPress) was forwarded to Chromium, which in turn called DoWork
implicitly.
The side effect led to incorrect behavior, when the
mouse button is released and the drag operation should be finished.
What actually happened is that additional queued DragMove events
were being sent by OSX after the mouse release, and the process
was stuck in the inner event loop, because Chromium's DoWork was
never called. And only after moving the mouse a bit (and thus
forwarding MouseMove events), the inner event loop was quit, and
the drag operation finished.
To actually make Chromium handle the DragMove event, we have to
manually call DoWork on the inner event loop.
Also because the possible drag and drop action is sent via IPC from the
render process to the main process, there is a race condition that the
the message might not be handled on the first manual call of DoWork,
so we set up a QTimer to continuously call DoWork, thus polling for
the message. Once the message is handled, the timer is stopped. In
practice this leads to at most two timer timeouts.
Change-Id: I8dc37a9c47ea5b675e15ebd138bc0e616b522049
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@theqtcompany.com>
Diffstat (limited to 'src/core/web_contents_adapter.cpp')
-rw-r--r-- | src/core/web_contents_adapter.cpp | 25 |
1 files changed, 25 insertions, 0 deletions
diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 657a2eed3..ae13e226d 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -78,6 +78,7 @@ #include <QGuiApplication> #include <QStringList> #include <QStyleHints> +#include <QTimer> #include <QVariant> #include <QtCore/qmimedata.h> #include <QtGui/qaccessible.h> @@ -322,6 +323,7 @@ WebContentsAdapterPrivate::WebContentsAdapterPrivate() , currentDropData(nullptr) , currentDropAction(Qt::IgnoreAction) , inDragUpdateLoop(false) + , updateDragCursorMessagePollingTimer(new QTimer) { } @@ -364,6 +366,7 @@ WebContentsAdapter::WebContentsAdapter(content::WebContents *webContents) { Q_D(WebContentsAdapter); d->webContents.reset(webContents); + initUpdateDragCursorMessagePollingTimer(); } WebContentsAdapter::~WebContentsAdapter() @@ -1097,7 +1100,10 @@ Qt::DropAction WebContentsAdapter::updateDragPosition(QDragMoveEvent *e, const Q base::RunLoop loop; d->inDragUpdateLoop = true; d->dragUpdateLoopQuitClosure = loop.QuitClosure(); + + d->updateDragCursorMessagePollingTimer->start(); loop.Run(); + d->updateDragCursorMessagePollingTimer->stop(); return d->currentDropAction; } @@ -1134,6 +1140,25 @@ void WebContentsAdapter::leaveDrag() rvh->DragTargetDragLeave(); } +void WebContentsAdapter::initUpdateDragCursorMessagePollingTimer() +{ + Q_D(WebContentsAdapter); + // Poll for drag cursor updated message 60 times per second. In practice, the timer is fired + // at most twice, after which it is stopped. + d->updateDragCursorMessagePollingTimer->setInterval(16); + d->updateDragCursorMessagePollingTimer->setSingleShot(false); + + QObject::connect(d->updateDragCursorMessagePollingTimer.data(), &QTimer::timeout, [](){ + base::MessagePump::Delegate *delegate = base::MessageLoop::current(); + DCHECK(delegate); + + // Execute Chromium tasks if there are any present. Specifically we are interested to handle + // the RenderViewHostImpl::OnUpdateDragCursor message, that gets sent from the render + // process. + while (delegate->DoWork()) {} + }); +} + WebContentsAdapterClient::RenderProcessTerminationStatus WebContentsAdapterClient::renderProcessExitStatus(int terminationStatus) { auto status = WebContentsAdapterClient::RenderProcessTerminationStatus(-1); |