Changeset 458 for trunk/src/gui/kernel/qdnd_pm.cpp
- Timestamp:
- Jan 21, 2010, 12:46:24 PM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/gui/kernel/qdnd_pm.cpp
r454 r458 53 53 #include "qdesktopwidget.h" 54 54 #include "qfile.h" 55 #include "qfileinfo.h" 55 56 #include "qdnd_p.h" 56 57 #include "qdebug.h" … … 90 91 void reset() { reset(false); } 91 92 92 void set Dropped(bool d) { dropped= d; }93 bool i sDropped() const { return dropped; }93 void setInFakeDrop(bool d) { fakeDrop = d; } 94 bool inFakeDrop() const { return fakeDrop; } 94 95 95 96 DRAGINFO *info() const { return di; } 97 bool canSyncRender() const { return canSyncRndr; } 96 98 97 99 bool hasFormat_sys(const QString &mimeType); … … 106 108 107 109 bool initialized : 1; 108 bool dropped: 1;110 bool fakeDrop : 1; 109 111 bool gotWorkers : 1; 112 bool canSyncRndr : 1; 110 113 111 114 DRAGINFO *di; … … 125 128 126 129 QPMDragData::QPMDragData() 127 : initialized(false), dropped(false)128 , gotWorkers(false), di(NULL)130 : initialized(false), fakeDrop(false) 131 , gotWorkers(false), canSyncRndr(false), di(NULL) 129 132 , lastDragOverWidget(0), lastDragOverOp(0) 130 133 , supportedOps(0), sourceAllowsOp(false) … … 147 150 initialized = true; 148 151 di = info; 152 153 // Detect if the source supports synchronous rendering which means it can 154 // process DM_RENDER and reply with DM_RENDERCOMPLETE from within both 155 // DM_DRAGOVER and DM_DROP (i.e. while it is running the DnD session with 156 // DrgDrag()). Mozilla apps are known to only support synchronous rendering 157 // (an attempt to send DM_RENDER to them after DM_DROP will crash them). 158 // By the contrast, EPM only supports asyncronous rendering (it will hang 159 // if we send DM_RENDER and/or wait for DM_RENDERCOMPLETE before returning 160 // from DM_DRAGOVER/DM_DROP). WPS (e.g. desktop folders) seem to support 161 // both (we prefer the syncrhonous rendering in such cases since it lets 162 // Qt apps access dragged data right from QDragEnterEvent/QDragLeaveEvent 163 // and QDropEvent message handlers which is used by many of them for better 164 // visualization. 165 166 // get class name 167 QByteArray className(256, '\0'); 168 LONG classNameLen = WinQueryClassName(info->hwndSource, 169 className.size(), className.data()); 170 className.truncate(classNameLen); 171 172 DEBUG(("QPMDragData::initialize: info->hwndSource %08lX className \"%s\"", 173 info->hwndSource, QString::fromLocal8Bit(className).toUtf8().data())); 174 175 // get EXE name 176 PID pid = 0; 177 TID tid = 0; 178 QByteArray exePath(CCHMAXPATH, '\0'); 179 BOOL ok = WinQueryWindowProcess(info->hwndSource, &pid, &tid); 180 if (ok) { 181 QByteArray buf(4192, '\0'); 182 APIRET arc = DosQuerySysState(QS_PROCESS, 0, pid, tid, 183 buf.data(), buf.size()); 184 if (arc == NO_ERROR) { 185 qsGrec_t *grec = *(qsGrec_t **)buf.data(); 186 qsPrec_t *prec = (qsPrec_t *)((ULONG)grec + sizeof(qsGrec_t)); 187 arc = DosQueryModuleName(prec->hMte, exePath.size(), exePath.data()); 188 if (arc == NO_ERROR) 189 exePath.truncate(qstrlen(exePath)); 190 } 191 } 192 193 DEBUG(("QPMDragData::initialize: pid %lu exePath \"%s\"", 194 pid, QString::fromLocal8Bit(exePath).toUtf8().data())); 195 196 QString exeName = QFileInfo(QFile::decodeName(exePath)).fileName(); 197 198 // start with a positive 199 canSyncRndr = true; 200 201 if (exeName.toUpper() == QLatin1String("EPM.EXE") && 202 qstrcmp(className, "FileWnd") == 0) { 203 // EPM only supports async rendering 204 canSyncRndr = false; 205 } 206 207 DEBUG(("QPMDragData::initialize: canSyncRender %d", canSyncRndr)); 149 208 } 150 209 … … 196 255 workers.clear(); 197 256 di = 0; 198 initialized = dropped = gotWorkers= false;257 initialized = fakeDrop = gotWorkers = canSyncRndr = false; 199 258 } 200 259 … … 229 288 QVariant result; 230 289 231 // we may only do data transfer after DM_DROP is sent. Return shortly. 232 if (!isDropped()) 290 // If the source doesn't support synchronous rendering, we may only do data 291 // transfer after DM_DROP is processed by us. Return shortly. 292 if (!canSyncRender() && !inFakeDrop()) 233 293 return result; 234 294 … … 360 420 void QDragManager::sendDropEvent(QWidget *receiver, QEvent *event) 361 421 { 422 // Note: inDrag = true causes QWidget::getPS() to return a special HPS for 423 // drawing during DnD. However, if we send the message from a fake DM_DROP 424 // that we post to ourselves to render data after the DnD session ends 425 // (inFakeDrop = true), a normal HPS has to be used. 426 427 bool inFakeDrop = dropData->d->inFakeDrop(); 428 362 429 Q_ASSERT(!inDrag); 363 inDrag = true; 430 if (!inFakeDrop) 431 inDrag = true; 432 364 433 QApplication::sendEvent(receiver, event); 365 // make sure that all issued update requests are handled before we 366 // return from the DM_DRAGOVER/DM_DRAGLEAVE/DM_DROP message; otherwise 367 // we'll get screen corruption due to unexpected screen updates while 368 // dragging 369 QApplication::sendPostedEvents(0, QEvent::UpdateRequest); 370 inDrag = false; 434 435 if (!inFakeDrop) { 436 // make sure that all issued update requests are handled before we 437 // return from the DM_DRAGOVER/DM_DRAGLEAVE/DM_DROP message; otherwise 438 // we'll get screen corruption due to unexpected screen updates while 439 // dragging 440 QApplication::sendPostedEvents(0, QEvent::UpdateRequest); 441 inDrag = false; 442 } 371 443 } 372 444 … … 561 633 DEBUG(("DM_DROP: hwnd %lX di %p", qmsg.hwnd, qmsg.mp1)); 562 634 563 // Odin32 apps produce incorrect message flow, ignore 564 Q_ASSERT(dragData->lastDragOverWidget != 0); 565 if (dragData->lastDragOverWidget == 0) 566 return 0; 567 568 // Odin32 apps send DM_DROP even if we replied DOR_NEVERDROP or 569 // DOR_NODROP, simulate DM_DRAGLEAVE 570 Q_ASSERT(dragData->lastDropReply == DOR_DROP); 571 if (dragData->lastDropReply != DOR_DROP) { 572 QMSG qmsg2 = qmsg; 573 qmsg2.msg = DM_DRAGLEAVE; 574 dispatchDragAndDrop(widget, qmsg2); 575 return 0; 635 // sanity 636 Q_ASSERT(!dragData->canSyncRender() || qmsg.mp1); 637 638 DRAGINFO *info = 0; 639 640 if (dragData->canSyncRender() || qmsg.mp1) { 641 // Odin32 apps produce incorrect message flow, ignore 642 Q_ASSERT(dragData->lastDragOverWidget != 0); 643 if (dragData->lastDragOverWidget == 0) 644 return 0; 645 646 // Odin32 apps send DM_DROP even if we replied DOR_NEVERDROP or 647 // DOR_NODROP, simulate DM_DRAGLEAVE 648 Q_ASSERT(dragData->lastDropReply == DOR_DROP); 649 if (dragData->lastDropReply != DOR_DROP) { 650 QMSG qmsg2 = qmsg; 651 qmsg2.msg = DM_DRAGLEAVE; 652 dispatchDragAndDrop(widget, qmsg2); 653 return 0; 654 } 655 656 // sanity 657 Q_ASSERT((DRAGINFO *)qmsg.mp1 == dragData->info()); 658 659 info = (DRAGINFO *)qmsg.mp1; 660 ok = DrgAccessDraginfo(info); 661 Q_ASSERT(ok && info); 662 if (!ok || !info) 663 return 0; 664 665 if (!dragData->canSyncRender()) { 666 // The source doesn't support syncrhonous rendering (i.e. 667 // it won't issue DM_RENDERCOMPLETE until we return from 668 // DM_DROP) so we have to post a message to ourselves to do 669 // it asynchronously. For simplicity, we reuse DM_DRAG with 670 // mp1 = 0 for this purpose. 671 WinPostMsg(qmsg.hwnd, DM_DROP, 0, 0); 672 return 0; 673 } 674 } else { 675 // we're in a fake DM_DROP we posted above 676 dragData->setInFakeDrop(true); 677 info = dragData->info(); 678 Q_ASSERT(info); 576 679 } 577 578 DRAGINFO *info = (DRAGINFO *)qmsg.mp1;579 ok = DrgAccessDraginfo(info);580 Q_ASSERT(ok && info);581 if (!ok || !info)582 return 0;583 680 584 681 // flip y coordinate … … 597 694 598 695 QMimeData *data = manager->source() ? manager->dragPrivate()->data : manager->dropData; 599 600 dragData->setDropped(true);601 696 602 697 QDropEvent de(pnt, dragData->lastAction, data, mouseButtons(),
Note:
See TracChangeset
for help on using the changeset viewer.