Index: /trunk/src/gui/kernel/qclipboard_pm.cpp
===================================================================
--- /trunk/src/gui/kernel/qclipboard_pm.cpp	(revision 333)
+++ /trunk/src/gui/kernel/qclipboard_pm.cpp	(revision 334)
@@ -74,5 +74,5 @@
 {
 public:
-    QClipboardWatcher() : isDirty(true) {}
+    QClipboardWatcher() {}
 
     bool hasFormat_sys(const QString &mimetype) const;
@@ -82,16 +82,12 @@
 private:
 
-    void peekData() const;
+    bool peekData(bool leaveOpen = false) const;
 
     mutable QList<ULONG> formats;
     mutable QList<QPMMime::Match> matches;
-    mutable bool isDirty;
 };
 
-void QClipboardWatcher::peekData() const
-{
-    if (!isDirty)
-        return;
-
+bool QClipboardWatcher::peekData(bool leaveOpen) const
+{
     if (!WinOpenClipbrd(NULLHANDLE)) {
 #ifndef QT_NO_DEBUG
@@ -99,23 +95,37 @@
                  "failed with 0x%lX", WinGetLastError(NULLHANDLE));
 #endif
-        return;
-    }
-
-    formats.clear();
+        return false;
+    }
+
+    QList<ULONG> newFormats;
     ULONG cf = 0;
     while ((cf = WinEnumClipbrdFmts(NULLHANDLE, cf)))
-        formats << cf;
-
-    WinCloseClipbrd(NULLHANDLE);
-
+        newFormats << cf;
+
+    if (!leaveOpen)
+        WinCloseClipbrd(NULLHANDLE);
+
+    // optimization: we don't want to call the potentially expensive
+    // allConvertersFromFormats() unlesss we really got a different set
+    if (newFormats == formats)
+        return true;
+
+    formats = newFormats;
     matches = QPMMime::allConvertersFromFormats(formats);
-    isDirty = false;
+
+#ifdef QCLIPBOARD_DEBUG
+    foreach(QPMMime::Match match, matches)
+        DEBUG(("QClipboardWatcher::peekData: converter %p mime \"%ls\" "
+               "format 0x%lX priority %d", match.converter, match.mime.utf16(),
+               match.format, match.priority));
+#endif
+
+    return true;
 }
 
 bool QClipboardWatcher::hasFormat_sys(const QString &mime) const
 {
-    peekData();
-    if (isDirty)
-        return false; // peekData() failed
+    if (!peekData())
+        return false;
 
     foreach (QPMMime::Match match, matches)
@@ -130,7 +140,6 @@
     QStringList fmts;
 
-    peekData();
-    if (isDirty)
-        return fmts; // peekData() failed
+    if (!peekData())
+        return fmts;
 
     foreach (QPMMime::Match match, matches)
@@ -145,7 +154,6 @@
     QVariant result;
 
-    peekData();
-    if (isDirty)
-        return result; // peekData() failed
+    if (!peekData(true /*leaveOpen*/))
+        return result;
 
     foreach (QPMMime::Match match, matches) {
@@ -157,7 +165,9 @@
                                                             data, match.mime, type);
             }
-            return result;
-        }
-    }
+            break;
+        }
+    }
+
+    WinCloseClipbrd(NULLHANDLE);
 
     return result;
@@ -175,7 +185,9 @@
 
     void setAsClipboardViewer();
-    bool ownsClipboard();
+    bool ownsClipboard() const;
     void putAllMimeToClipboard(bool isDelayed);
     void flushClipboard();
+
+    const QMimeData *mimeData() const;
 
     static QClipboardData *instance()
@@ -202,4 +214,6 @@
     QList<QPMMime::Match> matches;
     HWND prevClipboardViewer;
+
+    QClipboardWatcher watcher;
 
     bool ignore_WM_DESTROYCLIPBOARD;
@@ -265,5 +279,5 @@
 }
 
-bool QClipboardData::ownsClipboard()
+bool QClipboardData::ownsClipboard() const
 {
     return src && hwnd() == WinQueryClipbrdOwner(NULLHANDLE);
@@ -346,4 +360,12 @@
         setSource(0);
     }
+}
+
+const QMimeData *QClipboardData::mimeData() const
+{
+    // short cut for local copy / paste
+    if (ownsClipboard() && src)
+        return src;
+    return &watcher;
 }
 
@@ -481,6 +503,8 @@
 const QMimeData *QClipboard::mimeData(Mode mode) const
 {
-    // @todo implement
-    return 0;
+    if (mode != Clipboard)
+        return 0;
+
+    return QClipboardData::instance()->mimeData();
 }
 
Index: /trunk/src/gui/kernel/qmime.h
===================================================================
--- /trunk/src/gui/kernel/qmime.h	(revision 333)
+++ /trunk/src/gui/kernel/qmime.h	(revision 334)
@@ -127,6 +127,8 @@
                                      ULONG &flags, ULONG *data) const = 0;
 
+    typedef QPair<QString, ULONG> MimeCFPair;
+
     // for converting to Qt
-    virtual QStringList mimesForFormats(const QList<ULONG> &formats) const = 0;
+    virtual QList<MimeCFPair> mimesForFormats(const QList<ULONG> &formats) const = 0;
     virtual QVariant convertFromFormat(ULONG format, ULONG flags, ULONG data,
                                        const QString &mimeType,
@@ -145,6 +147,6 @@
     struct Match
     {
-        Match(QPMMime *c, const QString f, int p) :
-            converter(c), mime(f), format(0), priority(p) {}
+        Match(QPMMime *c, const QString f, ULONG cf, int p) :
+            converter(c), mime(f), format(cf), priority(p) {}
 
         Match(QPMMime *c, ULONG f, int p) :
@@ -153,5 +155,5 @@
         QPMMime *converter;
         QString mime; // used by allConvertersFromFormats()
-        ULONG format; // used by allConvertersFromMimeData()
+        ULONG format; // used by allConvertersFromFormats()/allConvertersFromMimeData()
         int priority;
     };
Index: /trunk/src/gui/kernel/qmime_pm.cpp
===================================================================
--- /trunk/src/gui/kernel/qmime_pm.cpp	(revision 333)
+++ /trunk/src/gui/kernel/qmime_pm.cpp	(revision 334)
@@ -246,10 +246,11 @@
 
 /*!
-    \fn QStringList QPMMime::mimesForFormats(const QList<ULONG> &formats) const
+    \fn QList<MimeCFPair> QPMMime::mimesForFormats(const QList<ULONG> &formats) const
 
     Returns a list of mime types that will be created form the specified \a list
     of \a formats, in order of precedence (the most suitable mime type comes
     first), or an empty list if neither of the \a formats is supported by this
-    converter.
+    converter. Note that each pair in the returned list consists of the mime
+    type name and the corresponding format identifier.
 
     All subclasses must reimplement this pure virtual function.
@@ -276,15 +277,16 @@
     QList<QPMMime*> mimes = theMimeList()->mimes();
     for (int i = mimes.size()-1; i >= 0; --i) {
-        QStringList fmts = mimes[i]->mimesForFormats(formats);
+        QList<MimeCFPair> fmts = mimes[i]->mimesForFormats(formats);
         int priority = 0;
-        foreach (QString fmt, fmts) {
+        foreach (MimeCFPair fmt, fmts) {
             ++priority;
             QList<Match>::iterator it = matches.begin();
             for (; it != matches.end(); ++it) {
                 Match &match = *it;
-                if (match.mime == fmt) {
+                if (match.mime == fmt.first) {
                     // replace if priority is higher, ignore otherwise
                     if (priority < match.priority) {
                         match.converter = mimes[i];
+                        match.format = fmt.second;
                         match.priority = priority;
                     }
@@ -293,5 +295,5 @@
             }
             if (it == matches.end()) {
-                matches += Match(mimes[i], fmt, priority);
+                matches += Match(mimes[i], fmt.first, fmt.second, priority);
             }
         }
@@ -344,5 +346,5 @@
                              ULONG &flags, ULONG *data) const;
 
-    QStringList mimesForFormats(const QList<ULONG> &formats) const;
+    QList<MimeCFPair> mimesForFormats(const QList<ULONG> &formats) const;
     QVariant convertFromFormat(ULONG format, ULONG flags, ULONG data,
                                const QString &mimeType,
@@ -388,6 +390,6 @@
         int maxsize = str.size()+str.size()/40+3;
         r.fill('\0', maxsize);
-        char* o = r.data();
-        const char* d = str.data();
+        char *o = r.data();
+        const char *d = str.data();
         const int s = str.size();
         bool cr = false;
@@ -454,12 +456,13 @@
 }
 
-QStringList QPMMimeText::mimesForFormats(const QList<ULONG> &formats) const
-{
-    QStringList mimes;
+QList<QPMMime::MimeCFPair> QPMMimeText::mimesForFormats(const QList<ULONG> &formats) const
+{
+    QList<MimeCFPair> mimes;
     foreach(ULONG cf, formats) {
-        if (cf == CF_TEXT || cf == CF_TextUnicode){
-            mimes << QLatin1String("text/plain");
-            break;
-        }
+        // prefer unicode over local8Bit
+        if (cf == CF_TextUnicode)
+            mimes.prepend(qMakePair(QString(QLatin1String("text/plain")), cf));
+        if (cf == CF_TEXT)
+            mimes.append(qMakePair(QString(QLatin1String("text/plain")), cf));
     }
     return mimes;
@@ -470,5 +473,41 @@
                                         QVariant::Type preferredType) const
 {
-    return QVariant();
+    QVariant ret;
+
+    // @todo why is it startsWith? the rest of the mime specification (encoding,
+    // etc) isn't taken into account... Anyway, copied the logic from Windows.
+    if (!mimeType.startsWith("text/plain"))
+        return ret;
+    if (!(flags & CFI_POINTER) || !data)
+        return ret;
+
+    QString str;
+
+    if (format == CF_TEXT) {
+        const char *d = (const char *)data;
+        QByteArray r("");
+        if (*d) {
+            const int s = qstrlen(d);
+            r.fill('\0', s);
+            char *o = r.data();
+            int j = 0;
+            for (int i = 0; i < s; i++) {
+                char c = d[i];
+                if (c != '\r')
+                    o[j++] = c;
+            }
+        }
+        str = QString::fromLocal8Bit(r);
+    } else if (format == CF_TextUnicode) {
+        str = QString::fromUtf16((const unsigned short *)data);
+        str.replace(QLatin1String("\r\n"), QLatin1String("\n"));
+    }
+
+    if (preferredType == QVariant::String)
+        ret = str;
+    else
+        ret = str.toUtf8();
+
+    return ret;
 }
 
