summaryrefslogtreecommitdiffstats
path: root/src/core/web_contents_adapter.cpp
diff options
context:
space:
mode:
authorAlexandru Croitor <alexandru.croitor@theqtcompany.com>2016-01-20 13:21:26 +0100
committerAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2016-01-23 15:37:03 +0000
commit4bf3b18d3089987e8b1e6a1a0bb9cd6a024e85c7 (patch)
treee08ab3477af4d743cce7ba1f438e37d6201e7955 /src/core/web_contents_adapter.cpp
parent96f120fd9ec94befcf0cc510ef40a7730677c0ad (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.cpp25
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);