From a3ceea583b9d14f809e4bf24a9c86fb9179a7797 Mon Sep 17 00:00:00 2001 From: Titta Heikkala Date: Thu, 21 Oct 2010 11:09:33 +0300 Subject: Support for clipboard between Qt and Symbian applications Clipboard now supports copying text between Qt and Symbian applications. Text is always copied to QClipboard and to Symbian clipboard. If QClipboard is empty, Symbian clipboard is checked and text is pasted from there. Corresponding test cases added. Task-number: QT-2085 Reviewed-by: Janne Koskinen Merge-request: 870 Reviewed-by: Janne Koskinen --- src/gui/kernel/qclipboard_s60.cpp | 85 ++++++++++++++++++++++++++++---- tests/auto/qclipboard/test/test.pro | 2 + tests/auto/qclipboard/tst_qclipboard.cpp | 79 +++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+), 10 deletions(-) diff --git a/src/gui/kernel/qclipboard_s60.cpp b/src/gui/kernel/qclipboard_s60.cpp index f07e066..7b145a8 100644 --- a/src/gui/kernel/qclipboard_s60.cpp +++ b/src/gui/kernel/qclipboard_s60.cpp @@ -50,16 +50,15 @@ #include "qwidget.h" #include "qevent.h" #include "private/qcore_symbian_p.h" +#include "txtetext.h" #include // Symbian's clipboard #include QT_BEGIN_NAMESPACE -//### Mime Type mapping to UIDs - const TUid KQtCbDataStream = {0x2001B2DD}; - +const TInt KPlainTextBegin = 0; class QClipboardData { @@ -141,7 +140,6 @@ void writeToStreamLX(const QMimeData* aData, RWriteStream& aStream) { HBufC* stringData = TPtrC(reinterpret_cast((*iter).utf16())).AllocLC(); QByteArray ba = aData->data((*iter)); - qDebug() << "copy to clipboard mime: " << *iter << " data: " << ba; // mime type aStream << TCardinality(stringData->Size()); aStream << *(stringData); @@ -152,6 +150,43 @@ void writeToStreamLX(const QMimeData* aData, RWriteStream& aStream) } } +void writeToSymbianStoreLX(const QMimeData* aData, CClipboard* clipboard) +{ + // This function both leaves and throws exceptions. There must be no destructor + // dependencies between cleanup styles, and no cleanup stack dependencies on stacked objects. + if (aData->hasText()) { + CPlainText* text = CPlainText::NewL(); + CleanupStack::PushL(text); + + TPtrC textPtr(qt_QString2TPtrC(aData->text())); + text->InsertL(KPlainTextBegin, textPtr); + text->CopyToStoreL(clipboard->Store(), clipboard->StreamDictionary(), + KPlainTextBegin, textPtr.Length()); + CleanupStack::PopAndDestroy(text); + } +} + +void readSymbianStoreLX(QMimeData* aData, CClipboard* clipboard) +{ + // This function both leaves and throws exceptions. There must be no destructor + // dependencies between cleanup styles, and no cleanup stack dependencies on stacked objects. + CPlainText* text = CPlainText::NewL(); + CleanupStack::PushL(text); + TInt dataLength = text->PasteFromStoreL(clipboard->Store(), clipboard->StreamDictionary(), + KPlainTextBegin); + if (dataLength == 0) { + User::Leave(KErrNotFound); + } + HBufC* hBuf = HBufC::NewL(dataLength); + TPtr buf = hBuf->Des(); + text->Extract(buf, KPlainTextBegin, dataLength); + + QString string = qt_TDesC2QString(buf); + CleanupStack::PopAndDestroy(text); + + aData->setText(string); +} + void readFromStreamLX(QMimeData* aData,RReadStream& aStream) { // This function both leaves and throws exceptions. There must be no destructor @@ -174,7 +209,6 @@ void readFromStreamLX(QMimeData* aData,RReadStream& aStream) ba.reserve(dataSize); aStream.ReadL(reinterpret_cast(ba.data_ptr()->data),dataSize); ba.data_ptr()->size = dataSize; - qDebug() << "paste from clipboard mime: " << mimeType << " data: " << ba; aData->setData(mimeType,ba); } } @@ -192,18 +226,41 @@ const QMimeData* QClipboard::mimeData(Mode mode) const { if (mode != Clipboard) return 0; QClipboardData *d = clipboardData(); + bool dataExists(false); if (d) { TRAPD(err,{ RFs fs = qt_s60GetRFs(); CClipboard* cb = CClipboard::NewForReadingLC(fs); Q_ASSERT(cb); + //stream for qt RStoreReadStream stream; TStreamId stid = (cb->StreamDictionary()).At(KQtCbDataStream); - stream.OpenLC(cb->Store(),stid); - QT_TRYCATCH_LEAVING(readFromStreamLX(d->source(),stream)); - CleanupStack::PopAndDestroy(2,cb); - return d->source(); + if (stid != 0) { + stream.OpenLC(cb->Store(),stid); + QT_TRYCATCH_LEAVING(readFromStreamLX(d->source(),stream)); + CleanupStack::PopAndDestroy(&stream); + dataExists = true; + } + else { + //symbian clipboard + RStoreReadStream symbianStream; + TStreamId symbianStId = (cb->StreamDictionary()).At(KClipboardUidTypePlainText); + if (symbianStId != 0) { + symbianStream.OpenLC(cb->Store(), symbianStId); + QT_TRYCATCH_LEAVING(readSymbianStoreLX(d->source(), cb)); + CleanupStack::PopAndDestroy(&symbianStream); + dataExists = true; + } + } + CleanupStack::PopAndDestroy(cb); + if (dataExists) { + return d->source(); + } + else { + return 0; + } + }); if (err != KErrNone){ qDebug()<< "clipboard is empty/err: " << err; @@ -223,6 +280,7 @@ void QClipboard::setMimeData(QMimeData* src, Mode mode) TRAPD(err,{ RFs fs = qt_s60GetRFs(); CClipboard* cb = CClipboard::NewForWritingLC(fs); + //stream for qt RStoreWriteStream stream; TStreamId stid = stream.CreateLC(cb->Store()); QT_TRYCATCH_LEAVING(writeToStreamLX(src,stream)); @@ -230,7 +288,14 @@ void QClipboard::setMimeData(QMimeData* src, Mode mode) stream.CommitL(); (cb->StreamDictionary()).AssignL(KQtCbDataStream,stid); cb->CommitL(); - CleanupStack::PopAndDestroy(2,cb); + + //stream for symbian + RStoreWriteStream symbianStream; + TStreamId symbianStId = symbianStream.CreateLC(cb->Store()); + QT_TRYCATCH_LEAVING(writeToSymbianStoreLX(src, cb)); + (cb->StreamDictionary()).AssignL(KClipboardUidTypePlainText, symbianStId); + cb->CommitL(); + CleanupStack::PopAndDestroy(3,cb); }); if (err != KErrNone){ qDebug()<< "clipboard write err :" << err; diff --git a/tests/auto/qclipboard/test/test.pro b/tests/auto/qclipboard/test/test.pro index 0f8cad1..97b0c9c 100644 --- a/tests/auto/qclipboard/test/test.pro +++ b/tests/auto/qclipboard/test/test.pro @@ -17,6 +17,8 @@ wince*|symbian: { paster.path = paster symbian: { + LIBS += -lbafl -lestor -letext + load(data_caging_paths) rsc.sources = $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/copier.rsc rsc.sources += $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/paster.rsc diff --git a/tests/auto/qclipboard/tst_qclipboard.cpp b/tests/auto/qclipboard/tst_qclipboard.cpp index d1f3e86..a4fac43 100644 --- a/tests/auto/qclipboard/tst_qclipboard.cpp +++ b/tests/auto/qclipboard/tst_qclipboard.cpp @@ -47,6 +47,11 @@ #ifdef Q_WS_MAC #include #endif +#ifdef Q_OS_SYMBIAN +#include "private/qcore_symbian_p.h" +#include "txtetext.h" +#include +#endif //TESTED_CLASS= //TESTED_FILES= @@ -62,6 +67,10 @@ private slots: void testSignals(); void setMimeData(); void clearBeforeSetText(); +#ifdef Q_OS_SYMBIAN + void pasteCopySymbian(); + void copyPasteSymbian(); +#endif private: bool nativeClipboardWorking(); @@ -335,6 +344,76 @@ void tst_QClipboard::clearBeforeSetText() QCOMPARE(QApplication::clipboard()->text(), text); } +/* + Test that text copied from qt application + can be pasted with symbian clipboard +*/ +#ifdef Q_OS_SYMBIAN +// ### This test case only makes sense in symbian +void tst_QClipboard::pasteCopySymbian() +{ + if (!nativeClipboardWorking()) + QSKIP("Native clipboard not working in this setup", SkipAll); + const QString string("Test string symbian."); + QApplication::clipboard()->setText(string); + + const TInt KPlainTextBegin = 0; + RFs fs = qt_s60GetRFs(); + CClipboard* cb = CClipboard::NewForReadingLC(fs); + + CPlainText* text = CPlainText::NewL(); + CleanupStack::PushL(text); + TInt dataLength = text->PasteFromStoreL(cb->Store(), cb->StreamDictionary(), + KPlainTextBegin); + if (dataLength == 0) { + User::Leave(KErrNotFound); + } + HBufC* hBuf = HBufC::NewL(dataLength); + TPtr buf = hBuf->Des(); + text->Extract(buf, KPlainTextBegin, dataLength); + + QString storeString = qt_TDesC2QString(buf); + CleanupStack::PopAndDestroy(text); + CleanupStack::PopAndDestroy(cb); + + QCOMPARE(string, storeString); +#endif +} + +/* + Test that text copied to symbian clipboard + can be pasted to qt clipboard +*/ +#ifdef Q_OS_SYMBIAN +// ### This test case only makes sense in symbian +void tst_QClipboard::copyPasteSymbian() +{ + if (!nativeClipboardWorking()) + QSKIP("Native clipboard not working in this setup", SkipAll); + const QString string("Test string symbian."); + const TInt KPlainTextBegin = 0; + + RFs fs = qt_s60GetRFs(); + CClipboard* cb = CClipboard::NewForWritingLC(fs); + CStreamStore& store = cb->Store(); + CStreamDictionary& dict = cb->StreamDictionary(); + RStoreWriteStream symbianStream; + TStreamId symbianStId = symbianStream.CreateLC(cb->Store()); + + CPlainText* text = CPlainText::NewL(); + CleanupStack::PushL(text); + TPtrC textPtr(qt_QString2TPtrC(string)); + text->InsertL(KPlainTextBegin, textPtr); + text->CopyToStoreL(store, dict, KPlainTextBegin, textPtr.Length()); + CleanupStack::PopAndDestroy(text); + (cb->StreamDictionary()).AssignL(KClipboardUidTypePlainText, symbianStId); + cb->CommitL(); + CleanupStack::PopAndDestroy(2, cb); + + QCOMPARE(QApplication::clipboard()->text(), string); +#endif +} + QTEST_MAIN(tst_QClipboard) #include "tst_qclipboard.moc" -- cgit v0.12 From 5102cf81c31ff59aca03273daab9d797eb818058 Mon Sep 17 00:00:00 2001 From: Titta Heikkala Date: Thu, 21 Oct 2010 11:09:36 +0300 Subject: Added include for missing file for Symbian3 Symbian3 has KClipboardUidTypePlainText defined in different file to previous Symbian versions. The missing file is now included. Task-number: QT-2085 Reviewed-by: Janne Koskinen Merge-request: 870 Reviewed-by: Janne Koskinen --- src/gui/kernel/qclipboard_s60.cpp | 3 +++ tests/auto/qclipboard/tst_qclipboard.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/gui/kernel/qclipboard_s60.cpp b/src/gui/kernel/qclipboard_s60.cpp index 7b145a8..c9b1d23 100644 --- a/src/gui/kernel/qclipboard_s60.cpp +++ b/src/gui/kernel/qclipboard_s60.cpp @@ -50,6 +50,9 @@ #include "qwidget.h" #include "qevent.h" #include "private/qcore_symbian_p.h" +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include "txtclipboard.h" +#endif #include "txtetext.h" #include diff --git a/tests/auto/qclipboard/tst_qclipboard.cpp b/tests/auto/qclipboard/tst_qclipboard.cpp index a4fac43..3437b53 100644 --- a/tests/auto/qclipboard/tst_qclipboard.cpp +++ b/tests/auto/qclipboard/tst_qclipboard.cpp @@ -52,6 +52,9 @@ #include "txtetext.h" #include #endif +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include "txtclipboard.h" +#endif //TESTED_CLASS= //TESTED_FILES= -- cgit v0.12 From 5f49392232dff904fdd3401cb739a1eaa79f7bd3 Mon Sep 17 00:00:00 2001 From: Jani Hautakangas Date: Wed, 20 Oct 2010 11:32:01 +0200 Subject: Functions that are externally defined to QtOpenGL needs to be imported. This is needed for RVCT4 Reviewed-by: Jason Barron --- src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp | 2 +- src/opengl/qglframebufferobject.cpp | 4 ++-- src/opengl/qglpixelbuffer.cpp | 4 ++-- src/opengl/qglpixmapfilter.cpp | 6 +++--- src/opengl/qpaintengine_opengl.cpp | 2 +- src/opengl/qpixmapdata_gl.cpp | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 5c7ebfa..84c7fed 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -102,7 +102,7 @@ extern Q_GUI_EXPORT bool qt_cleartype_enabled; extern bool qt_applefontsmoothing_enabled; #endif -extern QImage qt_imageForBrush(int brushStyle, bool invert); +Q_DECL_IMPORT extern QImage qt_imageForBrush(int brushStyle, bool invert); ////////////////////////////////// Private Methods ////////////////////////////////////////// diff --git a/src/opengl/qglframebufferobject.cpp b/src/opengl/qglframebufferobject.cpp index a1472f7..3ccefbf 100644 --- a/src/opengl/qglframebufferobject.cpp +++ b/src/opengl/qglframebufferobject.cpp @@ -1171,8 +1171,8 @@ void QGLFramebufferObject::drawTexture(const QPointF &point, QMacCompatGLuint te } #endif -extern int qt_defaultDpiX(); -extern int qt_defaultDpiY(); +Q_DECL_IMPORT extern int qt_defaultDpiX(); +Q_DECL_IMPORT extern int qt_defaultDpiY(); /*! \reimp */ int QGLFramebufferObject::metric(PaintDeviceMetric metric) const diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp index 994947b..3992f34 100644 --- a/src/opengl/qglpixelbuffer.cpp +++ b/src/opengl/qglpixelbuffer.cpp @@ -416,8 +416,8 @@ QPaintEngine *QGLPixelBuffer::paintEngine() const #endif } -extern int qt_defaultDpiX(); -extern int qt_defaultDpiY(); +Q_DECL_IMPORT extern int qt_defaultDpiX(); +Q_DECL_IMPORT extern int qt_defaultDpiY(); /*! \reimp */ int QGLPixelBuffer::metric(PaintDeviceMetric metric) const diff --git a/src/opengl/qglpixmapfilter.cpp b/src/opengl/qglpixmapfilter.cpp index bfa5ef1..74018cd 100644 --- a/src/opengl/qglpixmapfilter.cpp +++ b/src/opengl/qglpixmapfilter.cpp @@ -63,8 +63,8 @@ QT_BEGIN_NAMESPACE // qpixmapfilter.cpp -void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0); -QImage qt_halfScaled(const QImage &source); +Q_DECL_IMPORT void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0); +Q_DECL_IMPORT QImage qt_halfScaled(const QImage &source); void QGLPixmapFilterBase::bindTexture(const QPixmap &src) const { @@ -436,7 +436,7 @@ static inline uint nextMultiple(uint x, uint multiplier) return x + multiplier - mod; } -void qt_memrotate90_gl(const quint32 *src, int srcWidth, int srcHeight, int srcStride, +Q_DECL_IMPORT void qt_memrotate90_gl(const quint32 *src, int srcWidth, int srcHeight, int srcStride, quint32 *dest, int dstStride); bool QGLPixmapBlurFilter::processGL(QPainter *painter, const QPointF &pos, const QPixmap &src, const QRectF &) const diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index 2f17aa6..74b6b9a 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -79,7 +79,7 @@ QT_BEGIN_NAMESPACE -extern QImage qt_imageForBrush(int brushStyle, bool invert); //in qbrush.cpp +Q_DECL_IMPORT extern QImage qt_imageForBrush(int brushStyle, bool invert); //in qbrush.cpp #ifdef QT_MAC_USE_COCOA extern void *qt_current_nsopengl_context(); // qgl_mac.mm #endif diff --git a/src/opengl/qpixmapdata_gl.cpp b/src/opengl/qpixmapdata_gl.cpp index 89000bb..cd7f0c2 100644 --- a/src/opengl/qpixmapdata_gl.cpp +++ b/src/opengl/qpixmapdata_gl.cpp @@ -739,8 +739,8 @@ QGLTexture* QGLPixmapData::texture() const return &m_texture; } -extern int qt_defaultDpiX(); -extern int qt_defaultDpiY(); +Q_DECL_IMPORT extern int qt_defaultDpiX(); +Q_DECL_IMPORT extern int qt_defaultDpiY(); int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const { -- cgit v0.12 From 131774bb881a8a80503f4719fc7a7459521acdf0 Mon Sep 17 00:00:00 2001 From: mread Date: Thu, 21 Oct 2010 10:39:36 +0100 Subject: Using TLS to store QThreadData on Symbian TLS access on Symbian is significantly faster than using pthread_getspecific. In the case of QThreadData, the data associated with a thread, it makes sense to store and access the pointer in TLS rather than using the pthread thread specific functions. However, the pthread thread specific function have some destructor functionality that Symbian TLS does not, so Symbian still uses the pthread functions for setting the QThreadData to get the destruction behaviour. This change has wide ranging performance benefits for QML execution. With improvements shown on a number of the declarative benchmarks. Frame drawing times on test apps are also showing some improvement. The qthread* autotests have been run on Symbian^3 and Ubuntu 10.10 Task-number: QT-4089 Reviewed-by: Shane Kearns --- src/corelib/thread/qthread_unix.cpp | 46 ++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index a7601b6..a44a0e8 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -142,6 +142,39 @@ static void destroy_current_thread_data_key() } Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key) + +// Utility functions for getting, setting and clearing thread specific data. +// In Symbian, TLS access is significantly faster than pthread_getspecific. +// However Symbian does not have the thread destruction cleanup functionality +// that pthread has, so pthread_setspecific is also used. +static QThreadData *get_thread_data() +{ +#ifdef Q_OS_SYMBIAN + return reinterpret_cast(Dll::Tls()); +#else + pthread_once(¤t_thread_data_once, create_current_thread_data_key); + return reinterpret_cast(pthread_getspecific(current_thread_data_key)); +#endif +} + +static void set_thread_data(QThreadData *data) +{ +#ifdef Q_OS_SYMBIAN + qt_symbian_throwIfError(Dll::SetTls(data)); +#endif + pthread_once(¤t_thread_data_once, create_current_thread_data_key); + pthread_setspecific(current_thread_data_key, data); +} + +static void clear_thread_data() +{ +#ifdef Q_OS_SYMBIAN + Dll::FreeTls(); +#endif + pthread_setspecific(current_thread_data_key, 0); +} + + #ifdef Q_OS_SYMBIAN static void init_symbian_thread_handle(RThread &thread) { @@ -158,26 +191,24 @@ static void init_symbian_thread_handle(RThread &thread) QThreadData *QThreadData::current() { - pthread_once(¤t_thread_data_once, create_current_thread_data_key); - - QThreadData *data = reinterpret_cast(pthread_getspecific(current_thread_data_key)); + QThreadData *data = get_thread_data(); if (!data) { void *a; if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread, &a)) { QThread *adopted = static_cast(a); Q_ASSERT(adopted); data = QThreadData::get2(adopted); - pthread_setspecific(current_thread_data_key, data); + set_thread_data(data); adopted->d_func()->running = true; adopted->d_func()->finished = false; static_cast(adopted)->init(); } else { data = new QThreadData; - pthread_setspecific(current_thread_data_key, data); QT_TRY { + set_thread_data(data); data->thread = new QAdoptedThread(data); } QT_CATCH(...) { - pthread_setspecific(current_thread_data_key, 0); + clear_thread_data(); data->deref(); data = 0; QT_RETHROW; @@ -268,8 +299,7 @@ void *QThreadPrivate::start(void *arg) User::SetCritical(User::EProcessCritical); #endif - pthread_once(¤t_thread_data_once, create_current_thread_data_key); - pthread_setspecific(current_thread_data_key, data); + set_thread_data(data); data->ref(); data->quitNow = false; -- cgit v0.12 From 4dc810be62a26efceaea827ce8d979aceadfbe48 Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Thu, 21 Oct 2010 15:51:35 +0300 Subject: QS60Style: The QComboBox/QSpinBox text color is not according to theme Theme text colors are incorrect for spinboxes and comboboxes, they should have same theme colors as lineedit has, as they are using same graphic for "editor" sub-control in them. Task-number: QT-4176 Reviewed-by: Miikka Heikkinen --- src/gui/styles/qs60style.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp index 50e8a5b..ca3a9d0 100644 --- a/src/gui/styles/qs60style.cpp +++ b/src/gui/styles/qs60style.cpp @@ -837,11 +837,8 @@ void QS60StylePrivate::setThemePaletteHash(QPalette *palette) const s60Color(QS60StyleEnums::CL_QsnTextColors, 24, 0)); QApplication::setPalette(widgetPalette, "QLineEdit"); QApplication::setPalette(widgetPalette, "QTextEdit"); - widgetPalette = *palette; - - widgetPalette.setColor(QPalette::HighlightedText, - s60Color(QS60StyleEnums::CL_QsnTextColors, 24, 0)); QApplication::setPalette(widgetPalette, "QComboBox"); + QApplication::setPalette(widgetPalette, "QSpinBox"); widgetPalette = *palette; widgetPalette.setColor(QPalette::WindowText, s60Color(QS60StyleEnums::CL_QsnTextColors, 7, 0)); -- cgit v0.12