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>
This commit is contained in:
parent
449b62ed43
commit
ad66fa0dc1
@ -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];
|
||||
|
@ -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;
|
||||
|
@ -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]",
|
||||
|
Loading…
Reference in New Issue
Block a user