diff options
author | Morten Johan Sørvig <morten.sorvig@digia.com> | 2014-02-14 14:58:32 +0100 |
---|---|---|
committer | Morten Johan Sørvig <morten.sorvig@digia.com> | 2014-10-22 23:31:35 +0200 |
commit | ad66fa0dc18f20f3ceb5916ac791231c067b5898 (patch) | |
tree | 109ff0edcdc62e445478de38ec52f113e73767fe /src/plugins/platforms/cocoa | |
parent | 449b62ed436a8e45d1064b76dc9cc3201966bd91 (diff) |
Cocoa: Delay QMimeData requests for DnD events.
We were delaying the conversion from Qt to OS X types,
but not the data request to the application.
Introduce "Eager" and "Lazy" pasteboard promises:
Eager promises request the application data immediately
and can continue to use the existing commit-promises-
on-app-exit logic. Eager promises are the default
type and will be used for copy/paste.
Lazy promises delay requesting the data from the application
for as long as possible, specifically until when
promiseKeeper() is called. Lazy promises are used for
drag-and-drop and are not committed on application
exit.
This brings OS X DnD behavior in line with the
Windows behavior.
[ChangeLog][OS X] Drag-and-drop QMimeData requests are
now delayed until drop time.
Task-number: QTBUG-31301
Change-Id: I8ddbba41593251f4c0c49c29492dce990066e20d
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@theqtcompany.com>
Diffstat (limited to 'src/plugins/platforms/cocoa')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoadrag.mm | 2 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qmacclipboard.h | 17 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qmacclipboard.mm | 56 |
3 files changed, 59 insertions, 16 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoadrag.mm b/src/plugins/platforms/cocoa/qcocoadrag.mm index 2c8d391d2b..47b52c9fdd 100644 --- a/src/plugins/platforms/cocoa/qcocoadrag.mm +++ b/src/plugins/platforms/cocoa/qcocoadrag.mm @@ -132,7 +132,7 @@ Qt::DropAction QCocoaDrag::drag(QDrag *o) QMacPasteboard dragBoard((CFStringRef) NSDragPboard, QMacInternalPasteboardMime::MIME_DND); m_drag->mimeData()->setData(QLatin1String("application/x-qt-mime-type-name"), QByteArray("dummy")); - dragBoard.setMimeData(m_drag->mimeData()); + dragBoard.setMimeData(m_drag->mimeData(), QMacPasteboard::LazyRequest); NSPoint event_location = [m_lastEvent locationInWindow]; NSPoint local_point = [m_lastView convertPoint:event_location fromView:nil]; diff --git a/src/plugins/platforms/cocoa/qmacclipboard.h b/src/plugins/platforms/cocoa/qmacclipboard.h index ba7a2e1aac..c5b6224545 100644 --- a/src/plugins/platforms/cocoa/qmacclipboard.h +++ b/src/plugins/platforms/cocoa/qmacclipboard.h @@ -43,15 +43,25 @@ QT_BEGIN_NAMESPACE +class QMacMimeData; class QMacPasteboard { +public: + enum DataRequestType { EagerRequest, LazyRequest }; +private: struct Promise { Promise() : itemId(0), convertor(0) { } - Promise(int itemId, QMacInternalPasteboardMime *c, QString m, QVariant d, int o=0) : itemId(itemId), offset(o), convertor(c), mime(m), data(d) { } + + static Promise eagerPromise(int itemId, QMacInternalPasteboardMime *c, QString m, QMacMimeData *d, int o = 0); + static Promise lazyPromise(int itemId, QMacInternalPasteboardMime *c, QString m, QMacMimeData *d, int o = 0); + Promise(int itemId, QMacInternalPasteboardMime *c, QString m, QMacMimeData *md, int o, DataRequestType drt); + int itemId, offset; QMacInternalPasteboardMime *convertor; QString mime; - QVariant data; + QPointer<QMacMimeData> mimeData; + QVariant variantData; + DataRequestType dataRequestType; }; QList<Promise> promises; @@ -72,7 +82,8 @@ public: PasteboardRef pasteBoard() const; QMimeData *mimeData() const; - void setMimeData(QMimeData *mime); + + void setMimeData(QMimeData *mime, DataRequestType dataRequestType = EagerRequest); QStringList formats() const; bool hasFormat(const QString &format) const; diff --git a/src/plugins/platforms/cocoa/qmacclipboard.mm b/src/plugins/platforms/cocoa/qmacclipboard.mm index 65665ef790..b235625921 100644 --- a/src/plugins/platforms/cocoa/qmacclipboard.mm +++ b/src/plugins/platforms/cocoa/qmacclipboard.mm @@ -64,6 +64,26 @@ QT_BEGIN_NAMESPACE QMacPasteboard code *****************************************************************************/ +class QMacMimeData : public QMimeData +{ +public: + QVariant variantData(const QString &mime) { return retrieveData(mime, QVariant::Invalid); } +private: + QMacMimeData(); +}; + +QMacPasteboard::Promise::Promise(int itemId, QMacInternalPasteboardMime *c, QString m, QMacMimeData *md, int o, DataRequestType drt) + : itemId(itemId), offset(o), convertor(c), mime(m), dataRequestType(drt) +{ + // Request the data from the application immediately for eager requests. + if (dataRequestType == QMacPasteboard::EagerRequest) { + variantData = md->variantData(m); + mimeData = 0; + } else { + mimeData = md; + } +} + QMacPasteboard::QMacPasteboard(PasteboardRef p, uchar mt) { mac_mime_source = false; @@ -103,6 +123,11 @@ QMacPasteboard::~QMacPasteboard() // commit all promises for paste after exit close for (int i = 0; i < promises.count(); ++i) { const Promise &promise = promises.at(i); + // At this point app teardown has started and control is somewhere in the Q[Core]Application + // destructor. Skip "lazy" promises where the application has not provided data; + // the application will generally not be in a state to provide it. + if (promise.dataRequestType == LazyRequest) + continue; QCFString flavor = QCFString(promise.convertor->flavorFor(promise.mime)); NSInteger pbItemId = promise.itemId; promiseKeeper(paste, reinterpret_cast<PasteboardItemID>(pbItemId), flavor, this); @@ -155,7 +180,17 @@ OSStatus QMacPasteboard::promiseKeeper(PasteboardRef paste, PasteboardItemID id, qPrintable(flavorAsQString), qPrintable(promise.convertor->convertorName()), promise.offset); #endif - QList<QByteArray> md = promise.convertor->convertFromMime(promise.mime, promise.data, flavorAsQString); + // Get the promise data. If this is a "lazy" promise call variantData() + // to request the data from the application. + QVariant promiseData; + if (promise.dataRequestType == LazyRequest) { + if (!promise.mimeData.isNull()) + promiseData = promise.mimeData->variantData(promise.mime); + } else { + promiseData = promise.variantData; + } + + QList<QByteArray> md = promise.convertor->convertFromMime(promise.mime, promiseData, flavorAsQString); if (md.size() <= promise.offset) return cantGetFlavorErr; const QByteArray &ba = md[promise.offset]; @@ -266,16 +301,8 @@ QMimeData return mime; } -class QMacMimeData : public QMimeData -{ -public: - QVariant variantData(const QString &mime) { return retrieveData(mime, QVariant::Invalid); } -private: - QMacMimeData(); -}; - void -QMacPasteboard::setMimeData(QMimeData *mime_src) +QMacPasteboard::setMimeData(QMimeData *mime_src, DataRequestType dataRequestType) { if (!paste) return; @@ -312,12 +339,17 @@ QMacPasteboard::setMimeData(QMimeData *mime_src) continue; QString flavor(c->flavorFor(mimeType)); if (!flavor.isEmpty()) { - QVariant mimeData = static_cast<QMacMimeData*>(mime_src)->variantData(mimeType); + QMacMimeData *mimeData = static_cast<QMacMimeData*>(mime_src); int numItems = c->count(mime_src); for (int item = 0; item < numItems; ++item) { const NSInteger itemID = item+1; //id starts at 1 - promises.append(QMacPasteboard::Promise(itemID, c, mimeType, mimeData, item)); + //QMacPasteboard::Promise promise = (dataRequestType == QMacPasteboard::EagerRequest) ? + // QMacPasteboard::Promise::eagerPromise(itemID, c, mimeType, mimeData, item) : + // QMacPasteboard::Promise::lazyPromise(itemID, c, mimeType, mimeData, item); + + QMacPasteboard::Promise promise(itemID, c, mimeType, mimeData, item, dataRequestType); + promises.append(promise); PasteboardPutItemFlavor(paste, reinterpret_cast<PasteboardItemID>(itemID), QCFString(flavor), 0, kPasteboardFlavorNoFlags); #ifdef DEBUG_PASTEBOARD qDebug(" - adding %d %s [%s] <%s> [%d]", |