- Timestamp:
- Dec 25, 2009, 12:21:47 AM (16 years ago)
- Location:
- trunk/src/gui/kernel
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/gui/kernel/qdnd_pm.cpp
r438 r439 57 57 #include "qt_os2.h" 58 58 59 #define QDND_DEBUG // in pair with qmime_pm.cpp 60 61 #ifdef QDND_DEBUG 62 # define DEBUG(a) qDebug a 63 #else 64 # define DEBUG(a) do {} while(0) 65 #endif 66 59 67 QT_BEGIN_NAMESPACE 60 68 … … 79 87 DRAGINFO *info() const { return di; } 80 88 81 bool provides( const char *format);82 const char *format( int fn);83 Q ByteArray encodedData( const char *format);89 bool hasFormat_sys(const QString &mimeType); 90 QStringList formats_sys(); 91 QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type); 84 92 85 93 private: … … 152 160 } 153 161 154 #if defined(QT_DEBUG_DND) 155 qDebug( "QPMDragData: %d drop workers for DRAGINFO %p", 156 workers.count(), di ); 157 #endif 162 DEBUG(() << "QPMDragData:" << workers.count() << "drop workers for DRAGINFO" << di); 158 163 159 164 // init all workers … … 182 187 di = NULL; 183 188 initialized = dropped = gotWorkers = FALSE; 189 } 190 191 bool QPMDragData::hasFormat_sys(const QString &mimeType) 192 { 193 return false; 194 } 195 196 QStringList QPMDragData::formats_sys() 197 { 198 return QStringList(); 199 } 200 201 QVariant QPMDragData::retrieveData_sys(const QString &mimeType, 202 QVariant::Type type) 203 { 204 QVariant result; 205 206 // we may only do data transfer after DM_DROP is sent. Return shortly. 207 if (!isDropped()) 208 return result; 209 210 return result; 184 211 } 185 212 … … 527 554 bool QDropData::hasFormat_sys(const QString &mimeType) const 528 555 { 529 // @todo implement 556 Q_ASSERT(d); 557 if (d) 558 return d->hasFormat_sys(mimeType); 530 559 return false; 531 560 } … … 534 563 { 535 564 QStringList fmts; 536 // @todo implement 565 Q_ASSERT(d); 566 if (d) 567 fmts = d->formats_sys(); 537 568 return fmts; 538 569 } … … 541 572 { 542 573 QVariant result; 543 // @todo implement 574 Q_ASSERT(d); 575 if (d) 576 result = d->retrieveData_sys(mimeType, type); 544 577 return result; 545 578 } … … 548 581 549 582 { 550 #ifdef QDND_DEBUG 551 qDebug("QDragManager::drag(QDrag *drag)"); 552 #endif 583 DEBUG(() << "QDragManager::drag"); 553 584 554 585 // @todo implement -
trunk/src/gui/kernel/qmime.h
r347 r439 111 111 112 112 /* 113 Encapsulation of conversion between MIME and OS/2 PM clipboard. 113 Encapsulation of conversion between MIME and OS/2 PM clipboard formats and 114 between MIME and Direct Manipulation (DND) objects. 114 115 */ 115 116 116 117 typedef unsigned long ULONG; 118 119 class QPMCoopDragWorker; 117 120 118 121 class Q_GUI_EXPORT QPMMime 119 122 { 120 123 public: 124 125 #if !defined(QT_NO_DRAGANDDROP) 126 127 class DragWorker 128 { 129 public: 130 DragWorker() : data(0) {} 131 virtual ~DragWorker() {} 132 133 const QMimeData *source() const { return src; } 134 135 virtual void init() {} 136 // methods always implemented 137 virtual bool cleanup( bool isCancelled) = 0; 138 virtual bool isExclusive() const = 0; 139 virtual ULONG itemCount() const = 0; 140 virtual HWND hwnd() const = 0; 141 // methods implemented if isExclusive() == TRUE and itemCount() == 0 142 virtual DRAGINFO *createDragInfo(const char *name, USHORT supportedOps) 143 { return NULL; } 144 // methods implemented if itemCount() >= 0 145 virtual QByteArray composeFormatString() { return QByteArray(); } 146 virtual bool prepare(const char *drm, const char *drf, DRAGITEM *item, 147 ULONG itemIndex) { return FALSE; } 148 virtual void defaultFileType(const char *&type, const char *&ext) {}; 149 150 private: 151 const QMimeData *src; 152 friend class QPMCoopDragWorker; 153 friend class QDragManager; 154 }; 155 156 class DefaultDragWorker : public DragWorker, public QPMObjectWindow 157 { 158 private: 159 DefaultDragWorker(bool exclusive); 160 public: 161 virtual ~DefaultDragWorker(); 162 163 // DragpWorker interface 164 bool cleanup(bool isCancelled); 165 bool isExclusive() const; 166 ULONG itemCount() const; 167 HWND hwnd() const { return QPMObjectWindow::hwnd(); } 168 QByteArray composeFormatString(); 169 bool prepare(const char *drm, const char *drf, DRAGITEM *item, 170 ULONG itemIndex); 171 void defaultFileType(const char *&type, const char *&ext); 172 173 // QPMObjectWindow interface 174 MRESULT message(ULONG msg, MPARAM mp1, MPARAM mp2); 175 176 class Provider 177 { 178 public: 179 virtual const char *format( const char *drf ) const = 0; 180 virtual bool provide(const char *drf, const QByteArray &allData, 181 ULONG itemIndex, QByteArray &itemData) = 0; 182 virtual void fileType(const char *drf, const char *&type, 183 const char *&ext) {}; 184 }; 185 186 bool addProvider(const char *drf, Provider *provider, 187 ULONG itemCount = 1); 188 189 static bool canRender(const char *drm); 190 191 private: 192 struct Data; 193 Data *d; 194 friend class QPMMime; 195 }; 196 197 class DropWorker 198 { 199 public: 200 DropWorker() : nfo(0) {} 201 virtual ~DropWorker() {} 202 203 DRAGINFO *info() const { return nfo; } 204 205 virtual void init() {} 206 virtual void cleanup(bool isAccepted, bool isActAccepted) {} 207 virtual bool isExclusive() const = 0; 208 209 virtual bool hasFormat(const QString &mimeType) const = 0; 210 virtual QStringList formats() const = 0; 211 virtual QVariant retrieveData(const QString &mimeType, QVariant::Type type) const = 0; 212 213 private: 214 DRAGINFO *nfo; 215 friend class QPMDragData; 216 }; 217 218 class DefaultDropWorker : public DropWorker, public QPMObjectWindow 219 { 220 private: 221 DefaultDropWorker(); 222 public: 223 virtual ~DefaultDropWorker(); 224 225 // DropWorker interface 226 void cleanup(bool isAccepted, bool isActAccepted); 227 bool isExclusive() const; 228 bool hasFormat(const QString &mimeType) const; 229 QStringList formats() const; 230 QVariant retrieveData(const QString &mimeType, QVariant::Type type) const; 231 232 // QPMObjectWindow interface 233 MRESULT message(ULONG msg, MPARAM mp1, MPARAM mp2); 234 235 class Provider 236 { 237 public: 238 virtual const char *drf(const QString &mimeType) const = 0; 239 virtual bool provide(const QString &mimeType, ULONG itemIndex, 240 const QByteArray &itemData, 241 QByteArray &allData) = 0; 242 }; 243 244 bool addProvider(const QString &mimeType, Provider *provider); 245 bool addExclusiveProvider(const QString &mimeType, Provider *provider); 246 247 static bool canRender(DRAGITEM *item, const char *drf ); 248 static bool getSupportedRMFs(DRAGITEM *item, QPtrList<QStrList> &list); 249 250 private: 251 struct Data; 252 Data *d; 253 friend class QPMMime; 254 }; 255 256 #endif // !QT_NO_DRAGANDDROP 257 121 258 QPMMime(); 122 259 virtual ~QPMMime(); … … 139 276 QVariant::Type preferredType) const = 0; 140 277 278 #if !defined(QT_NO_DRAGANDDROP) 279 // Direct Manipulation (DND) converter interface 280 virtual DragWorker *dragWorkerFor(const QString &mimeType, 281 QMimeData *mimeData) { return 0; } 282 virtual DropWorker *dropWorkerFor(DRAGINFO *info) { return 0; } 283 #endif // !QT_NO_DRAGANDDROP 284 141 285 protected: 142 286 … … 148 292 149 293 static QString formatName(ULONG format); 294 295 #if !defined(QT_NO_DRAGANDDROP) 296 static QByteArray queryHSTR(HSTR hstr); 297 static QByteArray querySourceNameFull(DRAGITEM *item); 298 static bool canTargetRenderAsOS2File(DRAGITEM *item, QByteArray *fullName = 0); 299 static bool parseRMFs(HSTR rmfs, QList<QList<QByteArray> > &list); 300 static bool parseRMF(HSTR rmf, QByteArray &mechanism, QByteArray &format); 301 302 static DefaultDragWorker *defaultCoopDragWorker(); 303 static DefaultDragWorker *defaultExclDragWorker(); 304 static DefaultDropWorker *defaultDropWorker(); 305 #endif // !QT_NO_DRAGANDDROP 150 306 151 307 private: -
trunk/src/gui/kernel/qmime_pm.cpp
r423 r439 60 60 #include "qdir.h" 61 61 62 #define QMIME_DEBUG 62 #define QDND_DEBUG // in pair with qdnd_pm.cpp 63 64 #ifdef QDND_DEBUG 65 # define DEBUG(a) qDebug a 66 #else 67 # define DEBUG(a) do {} while(0) 68 #endif 63 69 64 70 QT_BEGIN_NAMESPACE 71 72 #if !defined(QT_NO_DRAGANDDROP) 73 74 // @todo remove 75 //#define DRT_URL "UniformResourceLocator" 76 // 77 //#define DRM_OS2FILE "DRM_OS2FILE" 78 //#define DRM_SHAREDMEM "DRM_SHAREDMEM" 79 // 80 //#define DRF_UNKNOWN "DRF_UNKNOWN" 81 //#define DRF_TEXT "DRF_TEXT" 82 //#define DRF_POINTERDATA "DRF_POINTERDATA" 83 // 84 //#define MIME_TEXT_PLAIN "text/plain" 85 //#define MIME_TEXT_PLAIN_CHARSET_SYSTEM "text/plain;charset=system" 86 //#define MIME_TEXT_URI_LIST "text/uri-list" 87 88 /*! \internal 89 According to my tests, DrgFreeDragtransfer() appears to be bogus: when the 90 drag source attempts to free the DRAGTRANSFER structure passed to it in 91 DM_RENDERPREPARE/DM_RENDER by another process, the shared memory object is not 92 actually released until DrgFreeDragtransfer() is called for the second time. 93 This method tries to fix this problem. 94 95 \note The problem (and the solution) was not tested on platforms other than 96 eCS! 97 */ 98 void qt_DrgFreeDragtransfer(DRAGTRANSFER *xfer) 99 { 100 Q_ASSERT(xfer); 101 if (xfer) { 102 BOOL ok = DrgFreeDragtransfer(xfer); 103 Q_ASSERT(ok); 104 if (ok) { 105 ULONG size = ~0, flags = 0; 106 APIRET rc = DosQueryMem(xfer, &size, &flags); 107 Q_ASSERT(rc == 0); 108 if (rc == 0 && !(flags & PAG_FREE)) { 109 PID pid; 110 TID tid; 111 ok = WinQueryWindowProcess(xfer->hwndClient, &pid, &tid); 112 Q_ASSERT(ok); 113 if (ok) { 114 PPIB ppib = 0; 115 DosGetInfoBlocks(0, &ppib); 116 if (ppib->pib_ulpid != pid) { 117 DEBUG(() << "qt_DrgFreeDragtransfer: Will free xfer" 118 << xfer << "TWICE (other process)!"); 119 DrgFreeDragtransfer(xfer); 120 } 121 } 122 } 123 } 124 } 125 } 126 127 #define SEA_TYPE ".TYPE" 128 129 /*! \internal 130 Sets a single .TYPE EA vaule on a given fle. 131 */ 132 static void qt_SetFileTypeEA(const char *name, const char *type) 133 { 134 #pragma pack(1) 135 136 struct MY_FEA2 { 137 ULONG oNextEntryOffset; /* Offset to next entry. */ 138 BYTE fEA; /* Extended attributes flag. */ 139 BYTE cbName; /* Length of szName, not including NULL. */ 140 USHORT cbValue; /* Value length. */ 141 CHAR szName[0]; /* Extended attribute name. */ 142 /* EA value follows here */ 143 }; 144 145 struct MY_FEA2LIST { 146 ULONG cbList; /* Total bytes of structure including full list. */ 147 MY_FEA2 list[0]; /* Variable-length FEA2 structures. */ 148 }; 149 150 struct MY_FEA2_VAL { 151 USHORT usEAType; /* EA value type (one of EAT_* constants) */ 152 USHORT usValueLen; /* Length of the value data following */ 153 CHAR aValueData[0]; /* value data */ 154 }; 155 156 struct MY_FEA2_MVMT { 157 USHORT usEAType; /* Always EAT_MVMT */ 158 USHORT usCodePage; /* 0 - default */ 159 USHORT cbNumEntries; /* Number of MYFEA2_VAL structs following */ 160 MY_FEA2_VAL aValues[0]; /* MYFEA2_VAL value structures */ 161 }; 162 163 #pragma pack() 164 165 uint typeLen = qstrlen(type); 166 uint valLen = sizeof(MY_FEA2_VAL) + typeLen; 167 uint mvmtLen = sizeof(MY_FEA2_MVMT) + valLen; 168 uint fea2Len = sizeof(MY_FEA2) + sizeof(SEA_TYPE); 169 uint fullLen = sizeof(MY_FEA2LIST) + fea2Len + mvmtLen; 170 171 uchar *eaData = new uchar[fullLen]; 172 173 MY_FEA2LIST *fea2List = (MY_FEA2LIST *)eaData; 174 fea2List->cbList = fullLen; 175 176 MY_FEA2 *fea2 = fea2List->list; 177 fea2->oNextEntryOffset = 0; 178 fea2->fEA = 0; 179 fea2->cbName = sizeof(SEA_TYPE) - 1; 180 fea2->cbValue = mvmtLen; 181 strcpy(fea2->szName, SEA_TYPE); 182 183 MY_FEA2_MVMT *mvmt = (MY_FEA2_MVMT *)(fea2->szName + sizeof(SEA_TYPE)); 184 mvmt->usEAType = EAT_MVMT; 185 mvmt->usCodePage = 0; 186 mvmt->cbNumEntries = 1; 187 188 MY_FEA2_VAL *val = mvmt->aValues; 189 val->usEAType = EAT_ASCII; 190 val->usValueLen = typeLen; 191 memcpy(val->aValueData, type, typeLen); 192 193 EAOP2 eaop2; 194 eaop2.fpGEA2List = 0; 195 eaop2.fpFEA2List = (FEA2LIST *)fea2List; 196 eaop2.oError = 0; 197 198 APIRET rc = DosSetPathInfo(name, FIL_QUERYEASIZE, 199 &eaop2, sizeof(eaop2), 0); 200 #ifndef QT_NO_DEBUG 201 if (rc) 202 qWarning("qt_SetFileTypeEA: DosSetPathInfo failed with %ld", rc); 203 #endif 204 205 delete[] eaData; 206 } 207 208 static int hex_to_int(uchar c) 209 { 210 if (c >= 'A' && c <= 'F') return c - 'A' + 10; 211 if (c >= 'a' && c <= 'f') return c - 'a' + 10; 212 if (c >= '0' && c <= '9') return c - '0'; 213 return -1; 214 } 215 216 static inline int hex_to_int(char c) 217 { 218 return hex_to_int((uchar) c); 219 } 220 221 // ----------------------------------------------------------------------------- 222 223 struct QPMMime::DefaultDragWorker::Data 224 { 225 Data(bool excl) : exclusive(excl) {} 226 227 struct Request 228 { 229 Request(ULONG i, Provider *p, const char *m, const char *f) 230 : index(i), provider(p), drm(m), drf(f) 231 , xfer(0), rendered(false), sharedMem(0) {} 232 233 ~Request() 234 { 235 // free memory allocated for the target that requested DRM_SHAREDMEM 236 if (sharedMem) 237 DosFreeMem(sharedMem); 238 Q_ASSERT(!xfer); 239 } 240 241 ULONG index; 242 Provider *provider; 243 QCString drm; 244 QCString drf; 245 DRAGTRANSFER *xfer; 246 bool rendered; 247 PVOID sharedMem; 248 }; 249 250 inline bool isInitialized() { return providers.count() != 0; } 251 void cleanupRequests(); 252 253 struct DrfProvider 254 { 255 DrfProvider() : prov(0) {} 256 DrfProvider(const char *d, Provider *p) : drf(d), prov(p) {} 257 const QByteArray drf; 258 Provider * const prov; 259 }; 260 261 typedef QList<DrfProvider> DrfProviderList; 262 263 Provider *providerFor(const char *drf) 264 { 265 foreach (const DrfProvider &dp, providers) 266 if (qstrcmp(dp.drf, drf) == 0) 267 return dp.prov; 268 return 0; 269 } 270 271 const bool exclusive : 1; 272 DrfProviderList providers; 273 274 ULONG itemCnt; 275 QHash<ULONG, Request*> requests; 276 bool renderOk : 1; 277 }; 278 279 void QPMMime::DefaultDragWorker::Data::cleanupRequests() 280 { 281 if (requests.count()) { 282 #ifndef QT_NO_DEBUG 283 qWarning("In the previous DnD session, the drop target sent " 284 "DM_RENDERPREPARE/DM_RENDER\n" 285 "for some drag item but didn't send DM_ENDCONVERSATION!"); 286 #endif 287 qDeleteAll(requests); 288 requests.clear(); 289 } 290 } 291 292 QPMMime::DefaultDragWorker::DefaultDragWorker(bool exclusive) 293 : d(new Data(exclusive)) 294 { 295 d->itemCnt = 0; 296 d->renderOk = true; 297 } 298 299 QPMMime::DefaultDragWorker::~DefaultDragWorker() 300 { 301 d->cleanupRequests(); 302 delete d; 303 } 304 305 bool QPMMime::DefaultDragWorker::cleanup(bool isCancelled) 306 { 307 // the return value is: true if the source-side Move for the given 308 // drag object should be *dis*allowed, false otherwise (including cases 309 // when this DragWorker didn't participate to the conversation at all) 310 311 // sanity check 312 Q_ASSERT(d->isInitialized()); 313 if (!d->isInitialized()) 314 return true; 315 316 bool moveDisallowed = false; 317 318 DEBUG(() << "DefaultDragWorker: Session ended (cancelled" << isCancelled 319 << "requests.left" << d->requests.count() << ")"); 320 321 if (d->requests.count()) { 322 // always disallow Move if not all requests got DM_ENDCONVERSATION 323 moveDisallowed = true; 324 } else { 325 // disallow Move if rendering of some item failed 326 moveDisallowed = !d->renderOk; 327 } 328 329 DEBUG(() << "DefaultDragWorker: moveDisallowed" << moveDisallowed); 330 331 // Note: remaining requests will be lazily deleted by cleanupRequests() 332 // when a new DND session is started 333 334 d->renderOk = true; 335 d->itemCnt = 0; 336 337 // Indicate we're cleaned up (i.e. the DND session is finished) 338 d->providers.clear(); 339 340 return moveDisallowed; 341 } 342 343 bool QPMMime::DefaultDragWorker::isExclusive() const 344 { 345 return d->exclusive; 346 } 347 348 ULONG QPMMime::DefaultDragWorker::itemCount() const 349 { 350 return d->itemCnt; 351 } 352 353 QByteArray QPMMime::DefaultDragWorker::composeFormatString() 354 { 355 QByteArray formats; 356 357 // sanity checks 358 Q_ASSERT(d->isInitialized()); 359 if (!d->isInitialized()) 360 return formats; 361 362 bool first = true; 363 foreach(const Data::DrfProvider &p, d->providers) { 364 if (first) 365 first = false; 366 else 367 formats += ","; 368 formats += p.drf; 369 } 370 371 Q_ASSERT(!formats.isNull()); 372 if (formats.isNull()) 373 return formats; 374 375 // DRM_SHAREDMEM comes first to prevent native DRM_OS2FILE 376 // rendering on the target side w/o involving the source. 377 // Also, we add <DRM_SHAREDMEM,DRF_POINTERDATA> just like WPS does it 378 // (however, it doesn't help when dropping objects to it -- WPS still 379 // chooses DRM_OS2FILE). 380 formats = "("DRM_SHAREDMEM","DRM_OS2FILE")x(" + formats + ")," 381 "<"DRM_SHAREDMEM","DRF_POINTERDATA">"; 382 383 DEBUG(() << "DefaultDragWorker: formats" << formats 384 << ", itemCnt" << d->itemCnt); 385 386 return formats; 387 } 388 389 bool QPMMime::DefaultDragWorker::prepare(const char *drm, const char *drf, 390 DRAGITEM *item, ULONG itemIndex) 391 { 392 // sanity checks 393 Q_ASSERT(d->isInitialized()); 394 if (!d->isInitialized()) 395 return false; 396 397 Q_ASSERT(item && itemIndex < d->itemCnt); 398 if (!item || itemIndex >= d->itemCnt) 399 return false; 400 401 DEBUG(() << "DefaultDragWorker: Preparing item" << itemIndex << "(id " 402 << item->ulItemID << ") for <" << drm << "," << drf ">"); 403 404 Provider *p = d->providerFor(drf); 405 406 if (!canRender(drm) || p == NULL) { 407 DEBUG(() << "DefaultDragWorker: Cannot render the given RMF"); 408 return false; 409 } 410 411 Data::Request *req = d->requests.value(item->ulItemID); 412 413 if (req) { 414 // this item has been already prepared, ensure it has also been 415 // rendered already 416 Q_ASSERT(req->index == itemIndex); 417 Q_ASSERT(req->rendered); 418 if (req->index != itemIndex || !req->rendered) 419 return false; 420 // remove the old request to free resources 421 delete d->requests.take(item->ulItemID); 422 } 423 424 // store the request 425 req = new Data::Request(itemIndex, p, drm, drf); 426 d->requests.insert(item->ulItemID, req); 427 428 return true; 429 } 430 431 void QPMMime::DefaultDragWorker::defaultFileType(const char *&type, 432 const char *&ext) 433 { 434 Q_ASSERT(d->providers.count()); 435 if (d->providers.count()) { 436 Provider *p = d->providers.first().prov; 437 Q_ASSERT(p); 438 if (p) 439 p->fileType(d->providers.first().drf, type, ext); 440 } 441 } 442 443 MRESULT QPMMime::DefaultDragWorker::message(ULONG msg, MPARAM mp1, MPARAM mp2) 444 { 445 if (msg == DM_RENDER) { 446 DRAGTRANSFER *xfer = (DRAGTRANSFER *) mp1; 447 448 // sanity checks 449 Q_ASSERT(d->isInitialized()); 450 Q_ASSERT(xfer); 451 if (!d->isInitialized() || !xfer) 452 return (MRESULT)FALSE; 453 454 Q_ASSERT(xfer->hwndClient && xfer->pditem); 455 if (!xfer->hwndClient || !xfer->pditem) 456 return (MRESULT)FALSE; 457 458 Data::Request *req = d->requests.value(xfer->pditem->ulItemID); 459 460 // check that this item has been prepared (should always be the case 461 // because the target would never know our hwnd() otherwise) 462 Q_ASSERT(req); // prepared 463 Q_ASSERT(!req->xfer); // no DM_RENDER requested 464 if (!req || req->xfer) 465 return (MRESULT)FALSE; 466 467 DEBUG(() << "DefaultDragWorker: Got DM_RENDER to" 468 << queryHSTR(xfer->hstrSelectedRMF) << "for item" << req->index 469 << "(id " << xfer->pditem->ulItemID << ")"); 470 471 QCString drm, drf; 472 if (!parseRMF(xfer->hstrSelectedRMF, drm, drf)) 473 Q_ASSERT(/* parseRMF() = */ FALSE); 474 475 if (req->drm != drm || req->drf != drf) { 476 xfer->fsReply = DMFL_RENDERRETRY; 477 return (MRESULT)FALSE; 478 } 479 480 // indicate that DM_RENDER was requested 481 req->xfer = xfer; 482 483 DEBUG(() << "DefaultDragWorker: Will render from [" 484 << req->provider->format(drf) << "] using provider" 485 << req->provider); 486 487 // We would lile to post WM_USER to ourselves to do actual rendering 488 // after we return from DM_RENDER. But we are inside DrgDrag() at this 489 // point (our DND implementation is fully synchronous by design), so 490 // PM will not deliver this message to us until we return from 491 // DrgDrag(). Thus, we have to send it. 492 493 WinSendMsg(hwnd(), WM_USER, MPFROMLONG(xfer->pditem->ulItemID), 494 MPFROMP(req)); 495 496 return (MRESULT)TRUE; 497 } 498 499 if (msg == WM_USER) { 500 // sanity checks 501 Q_ASSERT(d->isInitialized()); 502 if (!d->isInitialized()) 503 return (MRESULT)FALSE; 504 505 ULONG itemId = LONGFROMMP(mp1); 506 507 // sanity checks 508 Data::Request *req = d->requests.value(itemId); 509 Q_ASSERT(req); // prepared 510 Q_ASSERT(req->xfer != NULL); // DM_RENDER requested 511 Q_ASSERT(!req->rendered); // not yet rendered 512 Q_ASSERT((Data::Request *) PVOIDFROMMP(mp2) == req); 513 if (!req || req->xfer == NULL || req->rendered || 514 (Data::Request *) PVOIDFROMMP(mp2) != req) 515 return (MRESULT)FALSE; 516 517 Q_ASSERT(source() && req->provider && req->index < d->itemCnt); 518 if (!source() || !req->provider || req->index >= d->itemCnt) 519 return (MRESULT)FALSE; 520 521 DEBUG(() << "DefaultDragWorker: Got DO_RENDER for item " << req->index 522 << "(id " << req->xfer->pditem->ulItemID << ")" 523 << "provider"<< req->provider << "drm" << req->drm.data() 524 << "drf" << req->drf.data()); 525 526 bool renderOk = false; 527 QByteArray allData = 528 source()->encodedData(req->provider->format(req->drf)); 529 QByteArray itemData; 530 531 renderOk = req->provider->provide(req->drf, allData, 532 req->index, itemData); 533 534 if (renderOk) { 535 enum DRM { OS2File, SharedMem } drmType; 536 if (qstrcmp(req->drm, DRM_SHAREDMEM) == 0) drmType = SharedMem; 537 else drmType = OS2File; 538 539 if (drmType == OS2File) { 540 QCString renderToName = queryHSTR(req->xfer->hstrRenderToName); 541 Q_ASSERT(!renderToName.isEmpty()); 542 renderOk = !renderToName.isEmpty(); 543 if (renderOk) { 544 DEBUG(() << "DefaultDragWorker: Will write to" << renderToName); 545 QFile file(QFile::decodeName(renderToName)); 546 renderOk = file.open(IO_WriteOnly); 547 if (renderOk) { 548 Q_LONG written = 549 file.writeBlock(itemData.data(), itemData.size()); 550 renderOk = written == (Q_LONG) itemData.size() && 551 file.status() == IO_Ok; 552 file.close(); 553 if (renderOk && req->xfer->pditem->hstrType) { 554 // since WPS ignores hstrType, write it manually 555 // to the .TYPE EA of the created file 556 qt_SetFileTypeEA(renderToName, 557 queryHSTR(req->xfer->pditem->hstrType)); 558 } 559 } 560 } 561 } else { 562 PID pid; 563 TID tid; 564 bool isSameProcess = false; 565 renderOk = WinQueryWindowProcess(req->xfer->hwndClient, 566 &pid, &tid); 567 if (renderOk) { 568 PPIB ppib = NULL; 569 DosGetInfoBlocks(NULL, &ppib); 570 isSameProcess = ppib->pib_ulpid == pid; 571 572 ULONG sz = itemData.size() + sizeof (ULONG); 573 char *ptr = NULL; 574 APIRET rc = isSameProcess ? 575 DosAllocMem((PPVOID) &ptr, sz, 576 PAG_COMMIT | PAG_READ | PAG_WRITE) : 577 DosAllocSharedMem((PPVOID) &ptr, NULL, sz, 578 OBJ_GIVEABLE | PAG_COMMIT | 579 PAG_READ | PAG_WRITE); 580 renderOk = rc == 0; 581 if (renderOk && !isSameProcess) { 582 rc = DosGiveSharedMem(ptr, pid, PAG_READ); 583 renderOk = rc == 0; 584 } 585 if (renderOk) { 586 *(ULONG *) ptr = itemData.size(); 587 memcpy(ptr + sizeof (ULONG), itemData.data(), 588 itemData.size()); 589 req->xfer->hstrRenderToName = (HSTR) ptr; 590 req->sharedMem = ptr; 591 DEBUG(() << "DefaultDragWorker: Created shared memory " 592 "object" << ptr); 593 #ifndef QT_NO_DEBUG 594 } else { 595 qWarning("DefaultDragWorker: DosAllocSharedMem/" 596 "DosGiveSharedMem failed with %ld", rc); 597 #endif 598 } 599 #ifndef QT_NO_DEBUG 600 } else { 601 qWarning("DefaultDragWorker: WinQueryWindowProcess failed" 602 "with 0x%lX", WinGetLastError(NULLHANDLE)); 603 #endif 604 } 605 } 606 } 607 608 req->rendered = true; 609 // cumulative render result 610 d->renderOk &= renderOk; 611 612 DEBUG(() << "DefaultDragWorker: renderOk" << renderOk 613 << "overall.renderOk" << d->renderOk); 614 615 // note that we don't allow the target to retry 616 USHORT reply = renderOk ? DMFL_RENDEROK : DMFL_RENDERFAIL; 617 DrgPostTransferMsg(req->xfer->hwndClient, DM_RENDERCOMPLETE, 618 req->xfer, reply, 0, false); 619 620 // DRAGTRANSFER is no more necessary, free it early 621 qt_DrgFreeDragtransfer(req->xfer); 622 #if defined(QT_DEBUG_DND) 623 { 624 ULONG size = ~0, flags = 0; 625 DosQueryMem(req->xfer, &size, &flags); 626 DEBUG(("DefaultDragWorker: Freed DRAGTRANSFER: " 627 "req->xfer %p size %lu (0x%08lX) flags 0x%08lX", 628 req->xfer, size, size, flags); 629 } 630 #endif 631 req->xfer = NULL; 632 633 return (MRESULT)FALSE; 634 } 635 636 if (msg == DM_ENDCONVERSATION) { 637 // we don't check that isInitialized() is true here, because WPS 638 // (and probably some other apps) may send this message after 639 // cleanup() is called up on return from DrgDrag 640 641 ULONG itemId = LONGFROMMP(mp1); 642 ULONG flags = LONGFROMMP(mp2); 643 644 // sanity check (don't assert, see above) 645 Data::Request *req = d->requests.value(itemId); 646 Q_ASSERT(req); 647 if (!req) 648 return (MRESULT)FALSE; 649 650 DEBUG(() << "DefaultDragWorker: Got DM_ENDCONVERSATION for item " << req->index 651 << " (id " << itemId << ") provider" << req->provider 652 << "drm" << req->drm << "drf" << req->drf 653 << "rendered" << req->rendered << "outdated" << !d->isInitialized()); 654 655 // proceed further only if it's not an outdated request 656 // from the previous DND session 657 if (d->isInitialized()) { 658 if (!req->rendered) { 659 // we treat cancelling the render request (for any reason) 660 // as a failure 661 d->renderOk = false; 662 } else { 663 // the overall success is true only if target says Okay 664 d->renderOk &= flags == DMFL_TARGETSUCCESSFUL; 665 } 666 } 667 668 // delete the request 669 delete d->requests.take(itemId); 670 671 return (MRESULT)FALSE; 672 } 673 674 return (MRESULT)FALSE; 675 } 676 677 bool QPMMime::DefaultDragWorker::addProvider(const char *drf, Provider *provider, 678 ULONG itemCnt /* = 1 */) 679 { 680 // make sure remaining requests from the previous DND session are deleted 681 d->cleanupRequests(); 682 683 Q_ASSERT(drf && provider && itemCnt >= 1); 684 if (drf && provider && itemCnt >= 1) { 685 if (d->providers.count() == 0) { 686 // first provider 687 d->itemCnt = itemCnt; 688 d->providers.insert(Data::DrfProvider(drf, provider)); 689 return true; 690 } 691 // next provider, must not be exclusive and itemCnt must match 692 if (!d->exclusive && d->itemCnt == itemCnt) { 693 // ensure there are no dups (several providers for the same drf) 694 if (!d->providerFor(drf)) 695 d->providers.insert(Data::DrfProvider(drf, provider)); 696 return true; 697 } 698 } 699 return false; 700 } 701 702 // static 703 bool QPMMime::DefaultDragWorker::canRender(const char *drm) 704 { 705 return qstrcmp(drm, DRM_SHAREDMEM) == 0 || 706 qstrcmp(drm, DRM_OS2FILE) == 0; 707 } 708 709 //------------------------------------------------------------------------------ 710 711 struct QPMMime::DefaultDropWorker::Data 712 { 713 struct MimeProvider 714 { 715 MimeProvider() : prov(NULL) {} 716 MimeProvider(const QString &m, Provider *p) : mime(m), prov(p) {} 717 const QString mime; 718 Provider * const prov; 719 }; 720 721 typedef QList<MimeProvider> MimeProviderList; 722 723 Provider *providerFor(const QString &mime) 724 { 725 foreach (const MimeProvider &p, providers) { 726 if (p.mime == mime) 727 return p.prov; 728 } 729 return NULL; 730 } 731 732 bool exclusive : 1; 733 MimeProviderList providers; 734 735 bool sending_DM_RENDER : 1; 736 bool got_DM_RENDERCOMPLETE : 1; 737 USHORT flags_DM_RENDERCOMPLETE; 738 int waiting_DM_RENDERCOMPLETE; 739 }; 740 741 QPMMime::DefaultDropWorker::DefaultDropWorker() : d(new Data()) 742 { 743 d->exclusive = false; 744 d->sending_DM_RENDER = d->got_DM_RENDERCOMPLETE = false; 745 d->flags_DM_RENDERCOMPLETE = 0; 746 d->waiting_DM_RENDERCOMPLETE = 0; 747 } 748 749 QPMMime::DefaultDropWorker::~DefaultDropWorker() 750 { 751 delete d; 752 } 753 754 void QPMMime::DefaultDropWorker::cleanup(bool isAccepted, bool isActAccepted) 755 { 756 if (d->waiting_DM_RENDERCOMPLETE != 0) { 757 #ifndef QT_NO_DEBUG 758 qWarning("The previous drag source didn't post DM_RENDERCOMPLETE!\n" 759 "Contact the drag source developer."); 760 #endif 761 qApp->eventLoop()->exitLoop(); 762 } 763 764 d->providers.clear(); 765 d->exclusive = false; 766 d->sending_DM_RENDER = d->got_DM_RENDERCOMPLETE = false; 767 d->flags_DM_RENDERCOMPLETE = 0; 768 d->waiting_DM_RENDERCOMPLETE = 0; 769 } 770 771 bool QPMMime::DefaultDropWorker::isExclusive() const 772 { 773 return d->exclusive; 774 } 775 776 bool QPMMime::DefaultDropWorker::provides(const char *format) const 777 { 778 return d->providerFor(format) != NULL; 779 } 780 781 int QPMMime::DefaultDropWorker::formatCount() const 782 { 783 return d->providers.count(); 784 } 785 786 const char *QPMMime::DefaultDropWorker::format(int fn) const 787 { 788 if (fn >= 0 && (uint) fn < d->providers.count()) 789 return d->providers[ fn ].mime; 790 return NULL; 791 } 792 793 static QCString composeTempFileName() 794 { 795 static char defTmpDir[ 3 ] = { 0 }; 796 const char *tmpDir = getenv("TEMP"); 797 if (!tmpDir) tmpDir = getenv("TMP"); 798 if (!tmpDir || !QFile::exists(QFile::decodeName(tmpDir))) { 799 if (!defTmpDir[ 0 ]) { 800 ULONG bootDrive = 0; 801 DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, 802 &bootDrive, sizeof (bootDrive)); 803 defTmpDir[ 0 ] = bootDrive; 804 defTmpDir[ 1 ] = ':'; 805 } 806 tmpDir = defTmpDir; 807 } 808 809 static bool srandDone = false; 810 if (!srandDone) { 811 srand(time(NULL)); 812 srandDone = true; 813 } 814 815 ULONG num = rand(); 816 enum { Attempts = 100 }; 817 int attempts = Attempts; 818 819 QCString tmpName; 820 do { 821 tmpName.sprintf("%s\\%08lX.tmp", tmpDir, num); 822 if (!QFile::exists(QFile::decodeName(tmpName))) 823 break; 824 num = rand(); 825 } while (--attempts > 0); 826 827 Q_ASSERT(attempts > 0); 828 if (attempts <= 0) 829 tmpName.resize(0); 830 831 return tmpName; 832 } 833 834 QByteArray QPMMime::DefaultDropWorker::encodedData(const char *format) const 835 { 836 DEBUG("DefaultDropWorker::encodedData(" << format << ")"); 837 838 QByteArray data; 839 840 Q_ASSERT(info()); 841 if (!info()) 842 return data; 843 844 ULONG itemCount = DrgQueryDragitemCount(info()); 845 Q_ASSERT(itemCount); 846 if (!itemCount) 847 return data; 848 849 Provider *provider = d->providerFor(format); 850 if (!provider) 851 return data; 852 853 const char *drf = provider->drf(format); 854 Q_ASSERT(drf); 855 if (!drf) 856 return data; 857 858 // Note: Allocating and freeing DRAGTRANSFER structures is a real mess. It's 859 // absolutely unclear how they can be reused for multiple items and/or render 860 // requests. My practice shows, that they cannot be reused at all, especially 861 // when the source and the target are the same process: if we have multiple 862 // items and use the same DRAGTRANSFER for all of them, the source will call 863 // DrgFreeDragtransfer() every time that will eventually destroy the memory 864 // object before the target finishes to work with it, so that the next 865 // DrgFreeDragtransfer() will generate a segfault in PMCTLS. Also note that 866 // using a number > 1 as an argument to DrgAllocDragtransfer() won't help 867 // because that will still allocate a single memory object. Thus, we will 868 // always allocate a new struct per every item. It seems to work. 869 870 QCString renderToName = composeTempFileName(); 871 HSTR hstrRenderToName = DrgAddStrHandle(renderToName); 872 873 HSTR rmfOS2File = 874 DrgAddStrHandle(QCString().sprintf("<"DRM_OS2FILE",%s>", drf)); 875 HSTR rmfSharedMem = 876 DrgAddStrHandle(QCString().sprintf("<"DRM_SHAREDMEM",%s>", drf)); 877 878 MRESULT mrc; 879 bool renderOk = false; 880 881 DRAGTRANSFER *xfer = NULL; 882 QCString srcFileName; 883 884 QByteArray allData, itemData; 885 886 for (ULONG i = 0; i < itemCount; ++i) { 887 DRAGITEM *item = DrgQueryDragitemPtr(info(), i); 888 Q_ASSERT(item); 889 if (!item) { 890 renderOk = false; 891 break; 892 } 893 894 enum { None, OS2File, SharedMem } drm = None; 895 bool needToTalk = true; 896 897 // determine the mechanism to use (prefer DRM_SHAREDMEM) 898 899 if (DrgVerifyRMF(item, DRM_SHAREDMEM, drf) && 900 DrgVerifyRMF(item, DRM_SHAREDMEM, DRF_POINTERDATA)) 901 drm = SharedMem; 902 if (DrgVerifyRMF(item, DRM_OS2FILE, drf)) { 903 srcFileName = querySourceNameFull(item); 904 // If the source provides the full file name, we prefer DRM_OS2FILE 905 // even if there is also DRM_SHAREDMEM available because we don't 906 // need to do any communication in this case at all. This will help 907 // with some native drag sources (such as DragText) that cannot send 908 // DM_RENDERCOMPLETE synchronously (before we return from DM_DROP) 909 // and would hang otherwise. 910 if (!srcFileName.isEmpty()) { 911 needToTalk = false; 912 drm = OS2File; 913 } else if (drm == None) { 914 srcFileName = renderToName; 915 drm = OS2File; 916 } 917 } 918 Q_ASSERT(drm != None); 919 if (drm == None) { 920 renderOk = false; 921 break; 922 } 923 924 if (needToTalk) { 925 // need to perform a conversation with the source, 926 // allocate a new DRAGTRANSFER structure for each item 927 xfer = DrgAllocDragtransfer(1); 928 Q_ASSERT(xfer); 929 if (!xfer) { 930 renderOk = false; 931 break; 932 } 933 934 xfer->cb = sizeof(DRAGTRANSFER); 935 xfer->hwndClient = hwnd(); 936 xfer->ulTargetInfo = (ULONG) info(); 937 xfer->usOperation = info()->usOperation; 938 939 xfer->pditem = item; 940 if (drm == OS2File) { 941 xfer->hstrSelectedRMF = rmfOS2File; 942 xfer->hstrRenderToName = hstrRenderToName; 943 } else { 944 xfer->hstrSelectedRMF = rmfSharedMem; 945 xfer->hstrRenderToName = 0; 946 } 947 948 DEBUG(() << "DefaultDropWorker: Will use" 949 << queryHSTR(xfer->hstrSelectedRMF) << "to render item" << item); 950 951 mrc = (MRESULT)TRUE; 952 if ((item->fsControl & DC_PREPARE) | 953 (item->fsControl & DC_PREPAREITEM)) { 954 DEBUG(("DefaultDropWorker: Sending DM_RENDERPREPARE to 0x%08lX...", 955 info()->hwndSource)); 956 mrc = DrgSendTransferMsg(info()->hwndSource, DM_RENDERPREPARE, 957 MPFROMP (xfer), 0); 958 DEBUG(("DefaultDropWorker: Finisned sending DM_RENDERPREPARE\n" 959 " mrc %p xfer->fsReply 0x%08hX", mrc, xfer->fsReply); 960 renderOk = (BOOL) mrc; 961 } 962 963 if ((BOOL) mrc) { 964 DEBUG(("DefaultDropWorker: Sending DM_RENDER to 0x%08lX...", 965 item->hwndItem)); 966 d->sending_DM_RENDER = true; 967 mrc = DrgSendTransferMsg(item->hwndItem, DM_RENDER, 968 MPFROMP (xfer), 0); 969 d->sending_DM_RENDER = false; 970 DEBUG(("DefaultDropWorker: Finisned Sending DM_RENDER\n" 971 " mrc %p xfer->fsReply 0x%hX got_DM_RENDERCOMPLETE %d", 972 mrc, xfer->fsReply, d->got_DM_RENDERCOMPLETE)); 973 974 if (!(BOOL) mrc || d->got_DM_RENDERCOMPLETE) { 975 if (d->got_DM_RENDERCOMPLETE) 976 renderOk = (d->flags_DM_RENDERCOMPLETE & DMFL_RENDEROK); 977 else 978 renderOk = false; 979 } else { 980 // synchronously wait for DM_RENDERCOMPLETE 981 d->waiting_DM_RENDERCOMPLETE = qApp->loopLevel() + 1; 982 DEBUG(() << "DefaultDropWorker: Waiting for DM_RENDERCOMPLETE..."); 983 int level = qApp->eventLoop()->enterLoop(); 984 DEBUG(("DefaultDropWorker: Finished waiting for " 985 "DM_RENDERCOMPLETE (%d)\n" 986 " got_DM_RENDERCOMPLETE %d usFS 0x%hX", 987 level, d->got_DM_RENDERCOMPLETE, d->flags_DM_RENDERCOMPLETE)); 988 Q_UNUSED(level); 989 // JFTR: at this point, cleanup() might have been called, 990 // as a result of either program exit or getting another 991 // DM_DRAGOVER (if the source app has crashed) before getting 992 // DM_RENDERCOMPLETE from the source. Use data members with 993 // care! 994 d->waiting_DM_RENDERCOMPLETE = 0; 995 renderOk = d->got_DM_RENDERCOMPLETE && 996 (d->flags_DM_RENDERCOMPLETE & DMFL_RENDEROK); 997 } 998 999 d->got_DM_RENDERCOMPLETE = false; 1000 } 1001 } else { 1002 DEBUG(() << "DefaultDropWorker: Source supports <" << DRM_OS2FILE 1003 << "," << drf << "> and provides a file" << srcFileName 1004 << "for item" << item << "(no need to render)"); 1005 renderOk = true; 1006 } 1007 1008 if (renderOk) { 1009 if (drm == OS2File) { 1010 DEBUG(() << "DefaultDragWorker: Will read from" << srcFileName); 1011 QFile file(QFile::decodeName(srcFileName)); 1012 renderOk = file.open(IO_ReadOnly); 1013 if (renderOk) { 1014 itemData = file.readAll(); 1015 renderOk = file.status() == IO_Ok; 1016 file.close(); 1017 } 1018 bool ok = file.remove(); 1019 Q_ASSERT((ok = ok)); 1020 } else { 1021 Q_ASSERT(xfer->hstrRenderToName); 1022 renderOk = xfer->hstrRenderToName != 0; 1023 if (renderOk) { 1024 const char *ptr = (const char *) xfer->hstrRenderToName; 1025 ULONG size = ~0; 1026 ULONG flags = 0; 1027 APIRET rc = DosQueryMem((PVOID) ptr, &size, &flags); 1028 renderOk = rc == 0; 1029 if (renderOk) { 1030 DEBUG(("DefaultDropWorker: Got shared data %p size %lu " 1031 "(0x%08lX) flags 0x%08lX", ptr, size, size, flags)); 1032 Q_ASSERT(flags & (PAG_COMMIT | PAG_READ | PAG_BASE) == 1033 (PAG_COMMIT | PAG_READ | PAG_BASE)); 1034 renderOk = flags & (PAG_COMMIT | PAG_READ | PAG_BASE) == 1035 (PAG_COMMIT | PAG_READ | PAG_BASE); 1036 #ifndef QT_NO_DEBUG 1037 } else { 1038 qWarning("DefaultDropWorker: DosQueryMem failed with %ld", rc); 1039 #endif 1040 } 1041 if (renderOk) { 1042 ULONG realSize = *(ULONG *) ptr; 1043 DEBUG(() << "DefaultDropWorker: realSize" << realSize); 1044 Q_ASSERT(realSize <= size); 1045 renderOk = realSize <= size; 1046 if (renderOk) { 1047 itemData.resize(realSize); 1048 memcpy(itemData.data(), ptr + sizeof (ULONG), realSize); 1049 } 1050 } 1051 // free memory only if it is given by another process, 1052 // otherwise DefaultDragWorker will free it 1053 if (flags & PAG_SHARED) 1054 DosFreeMem((PVOID) xfer->hstrRenderToName); 1055 } 1056 } 1057 } 1058 1059 if (renderOk) 1060 renderOk = provider->provide(format, i, itemData, allData); 1061 1062 if (needToTalk) { 1063 // free the DRAGTRANSFER structure 1064 DrgFreeDragtransfer(xfer); 1065 #if defined(QT_DEBUG_DND) 1066 { 1067 ULONG size = ~0, flags = 0; 1068 DosQueryMem(xfer, &size, &flags); 1069 DEBUG(("DefaultDropWorker: Freed DRAGTRANSFER: " 1070 "xfer=%p, size=%lu(0x%08lX), flags=0x%08lX", 1071 xfer, size, size, flags)); 1072 } 1073 #endif 1074 xfer = NULL; 1075 } 1076 1077 if (!renderOk) 1078 break; 1079 } 1080 1081 DEBUG(() << "DefaultDropWorker: renderOk" << renderOk); 1082 1083 DrgDeleteStrHandle(rmfSharedMem); 1084 DrgDeleteStrHandle(rmfOS2File); 1085 DrgDeleteStrHandle(hstrRenderToName); 1086 1087 if (renderOk) 1088 data = allData; 1089 1090 return data; 1091 } 1092 1093 MRESULT QPMMime::DefaultDropWorker::message(ULONG msg, MPARAM mp1, MPARAM mp2) 1094 { 1095 switch (msg) { 1096 case DM_RENDERCOMPLETE: { 1097 // sanity check 1098 Q_ASSERT(info()); 1099 if (!info()) 1100 return (MRESULT)FALSE; 1101 1102 DEBUG("DefaultDropWorker: Got DM_RENDERCOMPLETE"); 1103 d->got_DM_RENDERCOMPLETE = true; 1104 d->flags_DM_RENDERCOMPLETE = SHORT1FROMMP(mp2); 1105 1106 if (d->sending_DM_RENDER) 1107 { 1108 DRAGTRANSFER *xfer = (DRAGTRANSFER *) mp1; 1109 #ifndef QT_NO_DEBUG 1110 qWarning("Drag item 0x%08lX sent DM_RENDERCOMPLETE w/o first " 1111 "replying to DM_RENDER!\n" 1112 "Contact the drag source developer.", 1113 xfer->pditem->hwndItem); 1114 #endif 1115 return (MRESULT)FALSE; 1116 } 1117 1118 // stop synchronous waiting for DM_RENDERCOMPLETE 1119 if (d->waiting_DM_RENDERCOMPLETE != 0) 1120 qApp->eventLoop()->exitLoop(); 1121 return (MRESULT)FALSE; 1122 } 1123 default: 1124 break; 1125 } 1126 1127 return (MRESULT)FALSE; 1128 } 1129 1130 bool QPMMime::DefaultDropWorker::addProvider(const char *format, 1131 Provider *provider) 1132 { 1133 Q_ASSERT(format && provider); 1134 if (format && provider && !d->exclusive) { 1135 // ensure there are no dups (several providers for the same mime) 1136 if (!d->providerFor(format)) 1137 d->providers.insert(Data::MimeProvider(format, provider)); 1138 return true; 1139 } 1140 return false; 1141 } 1142 1143 bool QPMMime::DefaultDropWorker::addExclusiveProvider(const char *format, 1144 Provider *provider) 1145 { 1146 Q_ASSERT(format && provider); 1147 if (format && provider && !d->exclusive) { 1148 d->exclusive = true; 1149 d->providers.clear(); 1150 d->providers.insert(Data::MimeProvider(format, provider)); 1151 return true; 1152 } 1153 return false; 1154 } 1155 1156 // static 1157 bool QPMMime::DefaultDropWorker::canRender(DRAGITEM *item, const char *drf) 1158 { 1159 return DrgVerifyRMF(item, DRM_OS2FILE, drf) || 1160 (DrgVerifyRMF(item, DRM_SHAREDMEM, drf) && 1161 DrgVerifyRMF(item, DRM_SHAREDMEM, DRF_POINTERDATA)); 1162 } 1163 1164 // static 1165 /*! \internal 1166 Parses the rendering mechanism/format specification of the given \a item 1167 and stores only those mechanism branches in the given \a list that represent 1168 mechanisms supported by this worker. Returns false if fails to parse the 1169 RMF specification. Note that if no supported mechanisms are found, true is 1170 returned but the \a list will simply contain zero items. 1171 \note The method clears the given \a list variable before proceeding and sets 1172 auto-deletion to true. 1173 \sa canRender(), PMMime::parseRMFs() 1174 */ 1175 bool QPMMime::DefaultDropWorker::getSupportedRMFs(DRAGITEM *item, 1176 QPtrList<QStrList> &list) 1177 { 1178 if (!parseRMFs(item->hstrRMF, list)) 1179 return false; 1180 1181 for (QStrList *mech = list.first(); mech;) { 1182 const char *drm = mech->first(); 1183 if (qstrcmp(drm, DRM_OS2FILE) == 0) { 1184 mech = list.next(); 1185 continue; 1186 } 1187 if (qstrcmp(drm, DRM_SHAREDMEM) == 0) { 1188 const char *drf = mech->next(); 1189 // accept DRM_SHAREDMEM only if there is DRF_POINTERDATA 1190 for(; drf; drf = mech->next()) { 1191 if (qstrcmp(drf, DRF_POINTERDATA) == 0) 1192 break; 1193 } 1194 if (drf) { 1195 mech = list.next(); 1196 continue; 1197 } 1198 } 1199 // remove the unsupported mechanism branch from the list 1200 bool wasLast = list.getLast() == mech; 1201 list.removeRef(mech); 1202 // after deleting the last item, the current one will be set to the new 1203 // last item which was already analyzed earlier, so set to 0 to stop 1204 mech = wasLast ? 0 : list.current(); 1205 } 1206 1207 return true; 1208 } 1209 1210 #endif // !QT_NO_DRAGANDDROP 1211 1212 //------------------------------------------------------------------------------ 65 1213 66 1214 class QPMMimeList … … 159 1307 if (!cf) { 160 1308 #ifndef QT_NO_DEBUG 161 qWarning("QPMMime: WinAddAtom failed with %lX",1309 qWarning("QPMMime: WinAddAtom failed with 0x%lX", 162 1310 WinGetLastError(NULLHANDLE)); 163 1311 #endif
Note:
See TracChangeset
for help on using the changeset viewer.