Changeset 326 for trunk/src


Ignore:
Timestamp:
Nov 19, 2009, 2:44:19 AM (16 years ago)
Author:
Dmitry A. Kuminov
Message:

gui/kernel: QClipboard: Added watching for the clipboard data changes and support for delayed data rendering.

Location:
trunk/src/gui/kernel
Files:
2 edited

Legend:

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

    r324 r326  
    9292    if (!WinOpenClipbrd(NULLHANDLE)) {
    9393#ifndef QT_NO_DEBUG
    94         qWarning("QClipboardWatcher: WinOpenClipbrd failed with 0x%lX",
    95                  WinGetLastError(NULLHANDLE));
     94        qWarning("QClipboardWatcher::peekData: WinOpenClipbrd "
     95                 "failed with 0x%lX", WinGetLastError(NULLHANDLE));
    9696#endif
    9797        return;
     
    168168    ~QClipboardData();
    169169
    170     void setSource(QMimeData *s)
     170    void setSource(QMimeData *s);
     171
     172    void setAsClipboardViewer();
     173    bool ownsClipboard();
     174    void renderAllFormats(bool isDelayed);
     175
     176    static QClipboardData *instance()
    171177    {
    172         if (s == src)
    173             return;
    174         delete src;
    175         src = s;
    176     }
    177 
    178     QMimeData *source()
     178        if (instancePtr == 0) {
     179            instancePtr = new QClipboardData;
     180        }
     181        Q_ASSERT(instancePtr);
     182        return instancePtr;
     183    }
     184
     185    static void deleteInstance()
    179186    {
    180         return src;
    181     }
    182 
     187        delete instancePtr;
     188        instancePtr = 0;
     189    }
     190
     191private:
     192    bool openClipboard();
     193    void closeClipboard();
    183194    bool setClipboard(QPMMime *converter, ULONG format, bool isDelayed);
     195    void renderFormat(ULONG format);
    184196
    185197    MRESULT message(ULONG msg, MPARAM mp1, MPARAM mp2);
    186198
    187 private:
    188199    QMimeData *src;
     200    QList<QPMMime::Match> matches;
     201    HWND prevClipboardViewer;
     202
     203    bool ignore_WM_DESTROYCLIPBOARD;
     204
     205    static QClipboardData *instancePtr;
    189206};
    190207
    191 QClipboardData::QClipboardData() : src(0)
     208// static
     209QClipboardData *QClipboardData::instancePtr = 0;
     210
     211QClipboardData::QClipboardData()
     212    : src(0), prevClipboardViewer(NULLHANDLE)
     213    , ignore_WM_DESTROYCLIPBOARD(false)
    192214{
    193215}
     
    195217QClipboardData::~QClipboardData()
    196218{
     219    renderAllFormats(false);
     220    setSource(0);
     221
     222    // make sure we are not the clipboard viewer any more
     223    if (hwnd() == WinQueryClipbrdViewer(NULLHANDLE))
     224        WinSetClipbrdViewer(NULLHANDLE, prevClipboardViewer);
     225}
     226
     227void QClipboardData::setSource(QMimeData *s)
     228{
     229    if (s == src)
     230        return;
    197231    delete src;
     232    src = s;
     233
     234    // build the list of all mime <-> cf matches
     235    matches.clear();
     236    if (src)
     237        matches = QPMMime::allConvertersFromMimeData(src);
     238}
     239
     240void QClipboardData::setAsClipboardViewer()
     241{
     242    HWND clipboardViewer = WinQueryClipbrdViewer(NULLHANDLE);
     243    if (hwnd() != clipboardViewer) {
     244        prevClipboardViewer = clipboardViewer;
     245        BOOL ok = WinSetClipbrdViewer(NULLHANDLE, hwnd());
     246        Q_UNUSED(ok);
     247#ifndef QT_NO_DEBUG
     248        if (!ok)
     249            qWarning("QClipboardData::setAsClipboardViewer: WinSetClipbrdViewer "
     250                     " failed with 0x%lX", WinGetLastError(NULLHANDLE));
     251#endif
     252    }
     253}
     254
     255bool QClipboardData::ownsClipboard()
     256{
     257    return src && hwnd() == WinQueryClipbrdOwner(NULLHANDLE);
     258}
     259
     260bool QClipboardData::openClipboard()
     261{
     262    if (!WinOpenClipbrd(NULLHANDLE)) {
     263#ifndef QT_NO_DEBUG
     264        qWarning("QClipboardData::openClipboard: WinOpenClipbrd "
     265                 "failed with 0x%lX", WinGetLastError(NULLHANDLE));
     266#endif
     267        return false;
     268    }
     269    return true;
     270}
     271
     272void QClipboardData::closeClipboard()
     273{
     274    WinCloseClipbrd(NULLHANDLE);
    198275}
    199276
     
    223300#ifdef QCLIPBOARD_DEBUG
    224301    qDebug("QClipboardData::setClipboard: convert to CF 0x%lX, flags 0x%lX,"
    225            "data 0x%lX, ok %d", format, flags, data, ok);
     302           "data 0x%lX, delayed %d, ok %d", format, flags, data, isDelayed, ok);
    226303#endif
    227304
     
    229306}
    230307
     308void QClipboardData::renderFormat(ULONG format)
     309{
     310#ifdef QCLIPBOARD_DEBUG
     311    qDebug("QClipboardData::renderFormat: CF 0x%lX", format);
     312#endif
     313
     314    if (!src)
     315        return;
     316
     317    if (!openClipboard())
     318        return;
     319
     320    foreach(QPMMime::Match match, matches) {
     321        if (match.format == format) {
     322            setClipboard(match.converter, match.format, false);
     323            break;
     324        }
     325    }
     326
     327    closeClipboard();
     328}
     329
     330void QClipboardData::renderAllFormats(bool isDelayed)
     331{
     332#ifdef QCLIPBOARD_DEBUG
     333    qDebug() << "QClipboardData::renderAllFormats: isDelayed" << isDelayed;
     334#endif
     335
     336    if (!openClipboard())
     337        return;
     338
     339    // delete the clipboard contents before we render everything to make sure
     340    // nothing is left there from another owner
     341    ignore_WM_DESTROYCLIPBOARD = true;
     342    BOOL ok = WinEmptyClipbrd(NULLHANDLE);
     343    ignore_WM_DESTROYCLIPBOARD = false;
     344    if (!ok) {
     345#ifndef QT_NO_DEBUG
     346        qWarning("QClipboardData::renderAllFormats: WinEmptyClipbrd "
     347                 "failed with 0x%lX", WinGetLastError(NULLHANDLE));
     348#endif
     349        return;
     350    }
     351
     352    if (src) {
     353#ifdef QCLIPBOARD_DEBUG
     354        qDebug() << "QClipboardData::renderAllFormats: mimes" << src->formats();
     355#endif
     356        foreach(QPMMime::Match match, matches)
     357            setClipboard(match.converter, match.format, isDelayed);
     358    }
     359
     360    closeClipboard();
     361}
     362
    231363MRESULT QClipboardData::message(ULONG msg, MPARAM mp1, MPARAM mp2)
    232364{
    233     return 0;
    234 }
    235 
    236 static QClipboardData *ptrClipboardData = 0;
    237 
    238 static QClipboardData *clipboardData()
    239 {
    240     if (ptrClipboardData == 0) {
    241         ptrClipboardData = new QClipboardData;
    242     }
    243     return ptrClipboardData;
    244 }
    245 
    246 static void cleanupClipboardData()
    247 {
    248     delete ptrClipboardData;
    249     ptrClipboardData = 0;
     365#ifdef QCLIPBOARD_DEBUG
     366    qDebug("QClipboardData::message: msg %08lX, mp1 %p, mp2 %p",
     367           msg, mp1, mp2);
     368#endif
     369
     370    switch (msg) {
     371
     372        case WM_DRAWCLIPBOARD: {
     373            // ask QClipboard to emit changed() signals
     374            QClipboardEvent e(reinterpret_cast<QEventPrivate *>(1));
     375            qt_sendSpontaneousEvent(QApplication::clipboard(), &e);
     376
     377            if (hwnd() != WinQueryClipbrdOwner(NULLHANDLE) && src) {
     378                // we no longer the clipboard, clean up the clipboard object
     379                setSource(0);
     380            }
     381            // PM doesn't inform the previous clipboard viewer if another
     382            // app changes it (nor does it support viewer chains in some other
     383            // way). The best we can do is to propagate the message to the
     384            // previous clipboard viewer ourselves (though there is no guarantee
     385            // that all non-Qt apps will do the same).
     386            if (prevClipboardViewer) {
     387                // propagate the message to the previous clipboard viewer
     388                BOOL ok = WinPostMsg(prevClipboardViewer, msg, mp1, mp2);
     389                if (!ok)
     390                    prevClipboardViewer = NULLHANDLE;
     391            }
     392            break;
     393        }
     394
     395        case WM_DESTROYCLIPBOARD:
     396            if (!ignore_WM_DESTROYCLIPBOARD)
     397                setSource(0);
     398            break;
     399
     400        case WM_RENDERFMT:
     401            renderFormat((ULONG)mp1);
     402            break;
     403
     404        case WM_RENDERALLFMTS:
     405            renderAllFormats(false);
     406            break;
     407
     408        default:
     409            break;
     410    }
     411
     412    return (MRESULT)TRUE;
    250413}
    251414
    252415////////////////////////////////////////////////////////////////////////////////
    253416
    254 static bool ignore_WM_DESTROYCLIPBOARD = FALSE;
    255 
    256417QClipboard::~QClipboard()
    257418{
    258     cleanupClipboardData();
     419    QClipboardData::deleteInstance();
    259420}
    260421
    261422void QClipboard::setMimeData(QMimeData *src, Mode mode)
    262423{
     424#ifdef QCLIPBOARD_DEBUG
     425    qDebug() << "QClipboard::setMimeData: src" << src << "mode" << mode;
     426#endif
     427
    263428    if (mode != Clipboard) {
    264429        delete src;
     
    266431    }
    267432
    268     if (!WinOpenClipbrd(NULLHANDLE)) {
    269 #ifndef QT_NO_DEBUG
    270         qWarning("QClipboard::setMimeData: WinOpenClipbrd failed with 0x%lX",
    271                  WinGetLastError(NULLHANDLE));
    272 #endif
    273         delete src;
    274         return;
    275     }
    276 
    277     QClipboardData *d = clipboardData();
     433    QClipboardData *d = QClipboardData::instance();
    278434    d->setSource(src);
    279 
    280     ignore_WM_DESTROYCLIPBOARD = TRUE;
    281     BOOL ok = WinEmptyClipbrd(NULLHANDLE);
    282     ignore_WM_DESTROYCLIPBOARD = FALSE;
    283 #ifndef QT_NO_DEBUG
    284     if (!ok)
    285         qWarning("QClipboard::setMimeData: WinEmptyClipbrd failed with 0x%lX",
    286                  WinGetLastError(NULLHANDLE));
    287 #else
    288     Q_UNUSED(ok);
    289 #endif
    290435
    291436    if (!src)
     
    295440                         QCoreApplication::instance()->d_func()->in_exec;
    296441
    297     QStringList formats = src->formats();
    298     foreach(QString mime, formats) {
    299 #ifdef QCLIPBOARD_DEBUG
    300         qDebug() << "QClipboard::setMimeData: src mime" << mime;
    301 #endif
    302         QList<QPMMime::Match> matches = QPMMime::allConvertersFromMimeData(src);
    303         foreach(QPMMime::Match match, matches) {
    304             d->setClipboard(match.converter, match.format, !runsEventLoop);
    305         }
    306     }
    307 
    308     WinCloseClipbrd(NULLHANDLE);
     442    d->renderAllFormats(runsEventLoop);
    309443}
    310444
    311445void QClipboard::clear(Mode mode)
    312446{
    313     // @todo implement
     447    setMimeData(0, Clipboard);
    314448}
    315449
    316450bool QClipboard::event(QEvent *e)
    317451{
    318     // @todo implement
    319     return false;
     452    if (e->type() != QEvent::Clipboard)
     453        return QObject::event(e);
     454
     455    if (!((QClipboardEvent*)e)->data()) {
     456        // this is sent by QApplication to render all formats at app shut down
     457        QClipboardData::instance()->renderAllFormats(false);
     458    } else {
     459        // this is sent by QClipboardData to notify about clipboard data change
     460        emitChanged(QClipboard::Clipboard);
     461    }
     462
     463    return true;
    320464}
    321465
    322466void QClipboard::connectNotify(const char *signal)
    323467{
    324     // @todo implement
     468    if (qstrcmp(signal, SIGNAL(dataChanged())) == 0) {
     469        // ensure we are up and running (by instantiating QClipboardData and
     470        // setting it as the clipboard viewer to receive notifications on
     471        // clipboard contents chages) but block signals so the dataChange signal
     472        // is not emitted while being connected to.
     473        bool blocked = blockSignals(true);
     474        QClipboardData::instance()->setAsClipboardViewer();
     475        blockSignals(blocked);
     476    }
    325477}
    326478
     
    338490bool QClipboard::ownsMode(Mode mode) const
    339491{
    340     // @todo implement
     492    if (mode == Clipboard) {
     493        return QClipboardData::instance()->ownsClipboard();
     494    }
    341495    return false;
    342496}
     
    344498void QClipboard::ownerDestroyed()
    345499{
     500    // not used
    346501}
    347502
  • trunk/src/gui/kernel/qmime.h

    r324 r326  
    137137private:
    138138    friend class QClipboardWatcher;
     139    friend class QClipboardData;
    139140    friend class QClipboard;
    140141
Note: See TracChangeset for help on using the changeset viewer.