Ignore:
Timestamp:
Jan 12, 2010, 12:00:10 PM (16 years ago)
Author:
Dmitry A. Kuminov
Message:

gui: DnD: Implemented support for painting in widgets during drag and draw.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/gui/kernel/qdnd_pm.cpp

    r444 r447  
    9393
    9494private:
     95    friend class QDragManager;
    9596
    9697    void initWorkers();
     
    102103    DRAGINFO *di;
    103104    QList<QPMMime::DropWorker*> workers;
     105
     106    QWidget *lastDragOverWidget; // last target widget
     107    USHORT lastDragOverOp; // last DM_DRAGOVER operation
     108
     109    USHORT supportedOps; // operations supported by all items
     110    bool sourceAllowsOp : 1; // does source allow requested operation
     111
     112    USHORT lastDropReply; // last reply to DM_DRAGOVER
     113    USHORT lastOpRequest; // last op requested in DM_DRAGOVER
     114
     115    Qt::DropAction lastProposedAction; // last proposed action
     116    QRect lastAnswerRect; // last accepted rectangle from the target
    104117};
    105118
     
    107120    : initialized(false), dropped(false)
    108121    , gotWorkers(false), di(NULL)
    109 {
    110     QDragManager *manager = QDragManager::self();
    111     Q_ASSERT(!manager->dropData->d);
    112     manager->dropData->d = this;
     122    , lastDragOverWidget(0), lastDragOverOp(0)
     123    , supportedOps(0), sourceAllowsOp(false)
     124    , lastDropReply(DOR_NEVERDROP), lastOpRequest(DO_UNKNOWN)
     125    , lastProposedAction(Qt::CopyAction)
     126{
    113127}
    114128
     
    116130{
    117131    reset();
    118 
    119     QDragManager *manager = QDragManager::self();
    120     if (manager) {
    121         Q_ASSERT(manager->dropData->d == this);
    122         manager->dropData->d = 0;
    123     }
    124132}
    125133
     
    265273}
    266274
     275void QDragManager::init_sys()
     276{
     277    inDrag = false;
     278
     279    Q_ASSERT(dropData);
     280    Q_ASSERT(!dropData->d);
     281    dropData->d = new QPMDragData();
     282}
     283
     284void QDragManager::uninit_sys()
     285{
     286    Q_ASSERT(dropData);
     287    Q_ASSERT(dropData->d);
     288    delete dropData->d;
     289    dropData->d = 0;
     290}
     291
     292void QDragManager::sendDropEvent(QWidget *receiver, QEvent *event)
     293{
     294    Q_ASSERT(!inDrag);
     295    inDrag = true;
     296    QApplication::sendEvent(receiver, event);
     297    // make sure that all issued update requests are handled before we
     298    // return from the DM_DRAGOVER/DM_DRAGLEAVE/DM_DROP message; otherwise
     299    // we'll get screen corruption due to unexpected screen updates while
     300    // dragging
     301    QApplication::sendPostedEvents(0, QEvent::UpdateRequest);
     302    inDrag = false;
     303}
     304
    267305/*!
    268306 *  \internal
    269307 *  Direct manipulation (Drag & Drop) event handler
    270308 */
    271 MRESULT qt_dispatchDragAndDrop(QWidget *widget, const QMSG &qmsg)
    272 {
    273     static QWidget *lastDragOverWidget = 0; // last target widget
    274     static USHORT lastDragOverOp = 0; // last DM_DRAGOVER operation
    275 
    276     static USHORT supportedOps = 0; // operations supported by all items
    277     static bool sourceAllowsOp = false; // does source allow requested operation
    278 
    279     static USHORT lastDropReply = DOR_NEVERDROP; // last reply to DM_DRAGOVER
    280     static USHORT lastOpRequest = DO_UNKNOWN; // last op requested in DM_DRAGOVER
    281 
    282     static Qt::DropAction lastProposedAction = Qt::CopyAction; // last proposed action
    283     static QRect lastAnswerRect; // last accepted rectangle from the target
    284     // @todo use lastAnswerRect to compress DM_DRAGOVER events
    285 
    286     static QPMDragData dragData;
    287 
     309MRESULT QDragManager::dispatchDragAndDrop(QWidget *widget, const QMSG &qmsg)
     310{
    288311    Q_ASSERT(widget);
    289312
     
    291314
    292315    QDragManager *manager = QDragManager::self();
     316    QPMDragData *dragData = manager->dropData->d;
     317    Q_ASSERT(dragData);
     318
     319    // @todo use dragData->lastAnswerRect to compress DM_DRAGOVER events
    293320
    294321    switch (qmsg.msg) {
     
    312339                dragOverWidget = widget;
    313340
    314             bool first = lastDragOverWidget != dragOverWidget;
     341            bool first = dragData->lastDragOverWidget != dragOverWidget;
    315342            if (first) {
    316343                // the first DM_DRAGOVER message
    317                 if (lastDragOverWidget != 0) {
     344                if (dragData->lastDragOverWidget != 0) {
    318345                    // send drag leave to the old widget
    319                     dragData.reset();
     346                    dragData->reset();
    320347                    QPointer<QWidget> dragOverWidgetGuard(dragOverWidget);
    321348                    QDragLeaveEvent dle;
    322                     QApplication::sendEvent(lastDragOverWidget, &dle);
     349                    sendDropEvent(dragData->lastDragOverWidget, &dle);
    323350                    if (!dragOverWidgetGuard) {
    324351                        dragOverWidget = widget->childAt(pnt);
     
    327354                    }
    328355                }
    329                 lastDragOverWidget = dragOverWidget;
    330                 lastDragOverOp = 0;
    331                 supportedOps = DO_COPYABLE | DO_MOVEABLE | DO_LINKABLE;
    332                 sourceAllowsOp = false;
    333                 lastDropReply = DOR_NEVERDROP;
    334                 lastOpRequest = DO_UNKNOWN;
    335                 lastProposedAction = manager->defaultAction(toQDragDropActions(supportedOps),
    336                                                             Qt::NoModifier);
    337                 lastAnswerRect = QRect();
     356                dragData->lastDragOverWidget = dragOverWidget;
     357                dragData->lastDragOverOp = 0;
     358                dragData->supportedOps = DO_COPYABLE | DO_MOVEABLE | DO_LINKABLE;
     359                dragData->sourceAllowsOp = false;
     360                dragData->lastDropReply = DOR_NEVERDROP;
     361                dragData->lastOpRequest = DO_UNKNOWN;
     362                dragData->lastProposedAction =
     363                    manager->defaultAction(toQDragDropActions(dragData->supportedOps),
     364                                           Qt::NoModifier);
     365                dragData->lastAnswerRect = QRect();
    338366                // ensure drag data is reset (just in case of a wrong msg flow...)
    339                 dragData.reset();
     367                dragData->reset();
    340368            }
    341369
     
    362390                        break;
    363391                    }
    364                     supportedOps &= item->fsSupportedOps;
     392                    dragData->supportedOps &= item->fsSupportedOps;
    365393                }
    366394                if (dropReply != DOR_NEVERDROP) {
    367395                    Q_ASSERT(itemCount);
    368                     if (!itemCount || !supportedOps) {
     396                    if (!itemCount || !dragData->supportedOps) {
    369397                        // items don't have even a single common operation...
    370398                        dropReply = DOR_NEVERDROP;
     
    375403            if (dropReply != DOR_NEVERDROP) {
    376404
    377                 if (first || lastDragOverOp != info->usOperation) {
     405                if (first || dragData->lastDragOverOp != info->usOperation) {
    378406                    // the current drop operation was changed by a modifier key
    379                     lastDragOverOp = info->usOperation;
     407                    dragData->lastDragOverOp = info->usOperation;
    380408                    USHORT realOp = info->usOperation;
    381409                    if (realOp == DO_DEFAULT || realOp == DO_UNKNOWN) {
    382410                        // the default operation is requested
    383                         realOp = toPmDragDropOp(lastProposedAction);
     411                        realOp = toPmDragDropOp(dragData->lastProposedAction);
    384412                    }
    385                     sourceAllowsOp =
    386                         ((supportedOps & DO_MOVEABLE) && realOp == DO_MOVE) ||
    387                         ((supportedOps & DO_COPYABLE) && realOp == DO_COPY) ||
    388                         ((supportedOps & DO_LINKABLE) && realOp == DO_LINK);
     413                    dragData->sourceAllowsOp =
     414                        ((dragData->supportedOps & DO_MOVEABLE) && realOp == DO_MOVE) ||
     415                        ((dragData->supportedOps & DO_COPYABLE) && realOp == DO_COPY) ||
     416                        ((dragData->supportedOps & DO_LINKABLE) && realOp == DO_LINK);
    389417                }
    390418
     
    396424                QMimeData *data = manager->source() ? manager->dragPrivate()->data : manager->dropData;
    397425
    398                 Qt::DropAction action = toQDragDropAction(lastOpRequest);
     426                Qt::DropAction action = toQDragDropAction(dragData->lastOpRequest);
    399427
    400428                if (first) {
    401                     dragData.initialize(info);
    402                     QDragEnterEvent dee(pnt, toQDragDropActions(supportedOps), data,
    403                                         QApplication::mouseButtons(),
     429                    dragData->initialize(info);
     430                    QDragEnterEvent dee(pnt,
     431                                        toQDragDropActions(dragData->supportedOps),
     432                                        data, QApplication::mouseButtons(),
    404433                                        QApplication::keyboardModifiers());
    405                     QApplication::sendEvent(dragOverWidget, &dee);
     434                    sendDropEvent(dragOverWidget, &dee);
    406435                    // if not allowed or not accepted, always reply DOR_NODROP
    407436                    // to have DM_DRAGOVER delivered to us again for a new test
    408                     if (sourceAllowsOp && dee.isAccepted()) {
     437                    if (dragData->sourceAllowsOp && dee.isAccepted()) {
    409438                        dropReply = DOR_DROP;
    410439                        action = dee.dropAction();
    411                         lastProposedAction = dee.proposedAction();
    412                         lastAnswerRect = dee.answerRect();
     440                        dragData->lastProposedAction = dee.proposedAction();
     441                        dragData->lastAnswerRect = dee.answerRect();
    413442                    } else {
    414443                        dropReply = DOR_NODROP;
     
    420449                // the target accepts it)
    421450                if (!first || dropReply == DOR_DROP) {
    422                     QDragEnterEvent dme(pnt, toQDragDropActions(supportedOps), data,
    423                                         QApplication::mouseButtons(),
    424                                         QApplication::keyboardModifiers());
     451                    QDragMoveEvent dme(pnt,
     452                                       toQDragDropActions(dragData->supportedOps),
     453                                       data, QApplication::mouseButtons(),
     454                                       QApplication::keyboardModifiers());
    425455                    // accept by default, since enter event was accepted.
    426456                    dme.setDropAction(action);
    427457                    dme.accept();
    428                     QApplication::sendEvent(dragOverWidget, &dme);
    429                     if (sourceAllowsOp && dme.isAccepted()) {
     458                    sendDropEvent(dragOverWidget, &dme);
     459                    if (dragData->sourceAllowsOp && dme.isAccepted()) {
    430460                        dropReply = DOR_DROP;
    431461                        action = dme.dropAction();
    432                         lastProposedAction = dme.proposedAction();
    433                         lastAnswerRect = dme.answerRect();
     462                        dragData->lastProposedAction = dme.proposedAction();
     463                        dragData->lastAnswerRect = dme.answerRect();
    434464                    } else {
    435465                        dropReply = DOR_NODROP;
     
    437467                }
    438468
    439                 lastDropReply = dropReply;
    440                 lastOpRequest = toPmDragDropOp(action);
     469                dragData->lastDropReply = dropReply;
     470                dragData->lastOpRequest = toPmDragDropOp(action);
    441471            }
    442472
    443473            DrgFreeDraginfo(info);
    444474
    445             return MRFROM2SHORT(dropReply, lastOpRequest);
     475            return MRFROM2SHORT(dropReply, dragData->lastOpRequest);
    446476        }
    447477        case DM_DRAGLEAVE: {
     
    449479
    450480            // Odin32 apps produce incorrect message flow, ignore
    451             Q_ASSERT(lastDragOverWidget != 0);
    452             if (lastDragOverWidget == 0)
     481            Q_ASSERT(dragData->lastDragOverWidget != 0);
     482            if (dragData->lastDragOverWidget == 0)
    453483                return 0;
    454484
    455485            QDragLeaveEvent de;
    456             QApplication::sendEvent(lastDragOverWidget, &de);
    457 
    458             lastDragOverWidget = 0;
    459             dragData.reset();
     486            sendDropEvent(dragData->lastDragOverWidget, &de);
     487
     488            dragData->lastDragOverWidget = 0;
     489            dragData->reset();
    460490
    461491            return 0;
     
    465495
    466496            // Odin32 apps produce incorrect message flow, ignore
    467             Q_ASSERT(lastDragOverWidget != 0);
    468             if (lastDragOverWidget == 0)
     497            Q_ASSERT(dragData->lastDragOverWidget != 0);
     498            if (dragData->lastDragOverWidget == 0)
    469499                return 0;
    470500
    471501            // Odin32 apps send DM_DROP even if we replied DOR_NEVERDROP or
    472502            // DOR_NODROP, simulate DM_DRAGLEAVE
    473             Q_ASSERT(lastDropReply == DOR_DROP);
    474             if (lastDropReply != DOR_DROP) {
     503            Q_ASSERT(dragData->lastDropReply == DOR_DROP);
     504            if (dragData->lastDropReply != DOR_DROP) {
    475505                QMSG qmsg2 = qmsg;
    476506                qmsg2.msg = DM_DRAGLEAVE;
    477                 qt_dispatchDragAndDrop(widget, qmsg2);
     507                dispatchDragAndDrop(widget, qmsg2);
    478508                return 0;
    479509            }
     
    490520            pnt = widget->mapFromGlobal(pnt);
    491521
    492             Q_ASSERT(lastOpRequest == info->usOperation);
    493 
    494             Q_ASSERT(lastDragOverWidget->acceptDrops());
    495             if (!lastDragOverWidget->acceptDrops()) {
     522            Q_ASSERT(dragData->lastOpRequest == info->usOperation);
     523
     524            Q_ASSERT(dragData->lastDragOverWidget->acceptDrops());
     525            if (!dragData->lastDragOverWidget->acceptDrops()) {
    496526                DrgDeleteDraginfoStrHandles(info);
    497527                DrgFreeDraginfo(info);
     
    499529            }
    500530
    501             QDragManager *manager = QDragManager::self();
    502531            QMimeData *data = manager->source() ? manager->dragPrivate()->data : manager->dropData;
    503532
    504             Qt::DropAction action = toQDragDropAction(lastOpRequest);
    505 
    506             dragData.setDropped(true);
     533            Qt::DropAction action = toQDragDropAction(dragData->lastOpRequest);
     534
     535            dragData->setDropped(true);
    507536
    508537            QDropEvent de(pnt, action, data, QApplication::mouseButtons(),
    509538                          QApplication::keyboardModifiers());
    510             if (lastDropReply == DOR_DROP)
     539            if (dragData->lastDropReply == DOR_DROP)
    511540                de.setDropAction(action);
    512541
    513             QApplication::sendEvent(lastDragOverWidget, &de);
    514 
    515             if (lastDropReply == DOR_DROP)
     542            sendDropEvent(dragData->lastDragOverWidget, &de);
     543
     544            if (dragData->lastDropReply == DOR_DROP)
    516545                de.accept();
    517546
    518             lastDragOverWidget = 0;
    519             dragData.reset(de.isAccepted());
     547            dragData->lastDragOverWidget = 0;
     548            dragData->reset(de.isAccepted());
    520549
    521550            ULONG targetReply = de.isAccepted() ?
Note: See TracChangeset for help on using the changeset viewer.