diff options
Diffstat (limited to 'src')
294 files changed, 23871 insertions, 640 deletions
diff --git a/src/3rdparty/freetype/src/gzip/zconf.h b/src/3rdparty/freetype/src/gzip/zconf.h index 3ccc3a6..2030a7e 100644 --- a/src/3rdparty/freetype/src/gzip/zconf.h +++ b/src/3rdparty/freetype/src/gzip/zconf.h @@ -5,6 +5,11 @@ /* @(#) $Id: zconf.h,v 1.4 2007/06/01 06:56:17 wl Exp $ */ +#if defined(__ARMCC__) || defined(__CC_ARM) +/* Ultra ugly hack that convinces RVCT to use the systems zlib */ +#include <stdapis/zconf.h> +#else /* defined(__ARMCC__) || defined(__CC_ARM) */ + #ifndef _ZCONF_H #define _ZCONF_H @@ -276,3 +281,5 @@ typedef uLong FAR uLongf; #endif #endif /* _ZCONF_H */ + +#endif /* defined(__ARMCC__) || defined(__CC_ARM) */ diff --git a/src/3rdparty/freetype/src/gzip/zlib.h b/src/3rdparty/freetype/src/gzip/zlib.h index 50d0d3f..0f98fdc 100644 --- a/src/3rdparty/freetype/src/gzip/zlib.h +++ b/src/3rdparty/freetype/src/gzip/zlib.h @@ -28,6 +28,11 @@ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). */ +#if defined(__ARMCC__) || defined(__CC_ARM) +/* Ultra ugly hack that convinces RVCT to use the systems zlib */ +#include <stdapis/zlib.h> +#else /* defined(__ARMCC__) || defined(__CC_ARM) */ + #ifndef _ZLIB_H #define _ZLIB_H @@ -828,3 +833,5 @@ ZEXTERN(int) inflateInit2_ OF((z_streamp strm, int windowBits, #endif #endif /* _ZLIB_H */ + +#endif /* defined(__ARMCC__) || defined(__CC_ARM) */ diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-global.h b/src/3rdparty/harfbuzz/src/harfbuzz-global.h index d4e6b46..393cc7b 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-global.h +++ b/src/3rdparty/harfbuzz/src/harfbuzz-global.h @@ -28,7 +28,13 @@ #ifndef HARFBUZZ_GLOBAL_H #define HARFBUZZ_GLOBAL_H +// Bug in stdlib.h, see more information from fixed_stdlib.h +#if (defined __SYMBIAN32__ && !defined __cplusplus) +#include <fixed_stdlib.h> +#else #include <stdlib.h> +#endif // defined __SYMBIAN32__ && !defined __cplusplus + #include <string.h> #ifdef __cplusplus diff --git a/src/3rdparty/libjpeg/jinclude.h b/src/3rdparty/libjpeg/jinclude.h index 0a4f151..725bd51 100644 --- a/src/3rdparty/libjpeg/jinclude.h +++ b/src/3rdparty/libjpeg/jinclude.h @@ -36,7 +36,12 @@ #endif #ifdef HAVE_STDLIB_H +// Bug in stdlib.h, see more information from fixed_stdlib.h +#if (defined __SYMBIAN32__ && !defined __cplusplus) +#include <fixed_stdlib.h> +#else #include <stdlib.h> +#endif // defined __SYMBIAN32__ && !defined __cplusplus #endif #ifdef NEED_SYS_TYPES_H diff --git a/src/3rdparty/libmng/libmng_types.h b/src/3rdparty/libmng/libmng_types.h index 81fb29f..45be543 100644 --- a/src/3rdparty/libmng/libmng_types.h +++ b/src/3rdparty/libmng/libmng_types.h @@ -198,7 +198,12 @@ #endif /* MNG_INCLUDE_IJG6B */ #if defined(MNG_INTERNAL_MEMMNGMT) || defined(MNG_INCLUDE_FILTERS) -#include <stdlib.h> /* "calloc" & "free" & "abs" */ +// Bug in stdlib.h, see more information from fixed_stdlib.h +#if (defined __SYMBIAN32__ && !defined __cplusplus) +#include <fixed_stdlib.h> +#else +#include <stdlib.h> +#endif // defined __SYMBIAN32__ && !defined __cplusplus #endif #include <limits.h> /* get proper integer widths */ diff --git a/src/3rdparty/libpng/pngconf.h b/src/3rdparty/libpng/pngconf.h index 19e4732..9edb468 100644 --- a/src/3rdparty/libpng/pngconf.h +++ b/src/3rdparty/libpng/pngconf.h @@ -353,7 +353,12 @@ /* Other defines for things like memory and the like can go here. */ #ifdef PNG_INTERNAL +// Bug in stdlib.h, see more information from fixed_stdlib.h +#if (defined __SYMBIAN32__ && !defined __cplusplus) +#include <fixed_stdlib.h> +#else #include <stdlib.h> +#endif // defined __SYMBIAN32__ && !defined __cplusplus /* The functions exported by PNG_EXTERN are PNG_INTERNAL functions, which * aren't usually used outside the library (as far as I know), so it is @@ -1333,7 +1338,9 @@ typedef z_stream FAR * png_zstreamp; defined(WIN32) || defined(_WIN32) || defined(__WIN32__) )) # ifndef PNGAPI -# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800)) +# if (defined(__GNUC__) && defined(__arm__)) || defined (__ARMCC__) +# define PNGAPI +# elif defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800)) || defined(__WINSCW__) # define PNGAPI __cdecl # else # define PNGAPI _cdecl diff --git a/src/3rdparty/libtiff/libtiff/tif_config.h b/src/3rdparty/libtiff/libtiff/tif_config.h index e95f7a4..324fbe8 100644 --- a/src/3rdparty/libtiff/libtiff/tif_config.h +++ b/src/3rdparty/libtiff/libtiff/tif_config.h @@ -104,7 +104,7 @@ /* #undef HAVE_PTHREAD */ /* Define to 1 if you have the <search.h> header file. */ -#if !defined(Q_OS_WINCE) +#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN) #define HAVE_SEARCH_H 1 #endif diff --git a/src/3rdparty/libtiff/libtiff/tif_unix.c b/src/3rdparty/libtiff/libtiff/tif_unix.c index 28de5c9..b60a0e1 100644 --- a/src/3rdparty/libtiff/libtiff/tif_unix.c +++ b/src/3rdparty/libtiff/libtiff/tif_unix.c @@ -35,7 +35,12 @@ #endif #include <stdarg.h> +// Bug in stdlib.h, see more information from fixed_stdlib.h +#if (defined __SYMBIAN32__ && !defined __cplusplus) +#include <fixed_stdlib.h> +#else #include <stdlib.h> +#endif // defined __SYMBIAN32__ && !defined __cplusplus #include <sys/stat.h> #ifdef HAVE_UNISTD_H @@ -181,7 +186,7 @@ TIFFOpen(const char* name, const char* mode) return tif; } -#ifdef __WIN32__ +#if defined (__WIN32__) && !defined(__SYMBIAN32__) #include <windows.h> /* * Open a TIFF file with a Unicode filename, for read/writing. diff --git a/src/3rdparty/libtiff/libtiff/tiffio.h b/src/3rdparty/libtiff/libtiff/tiffio.h index 7aaf561..96223d7 100644 --- a/src/3rdparty/libtiff/libtiff/tiffio.h +++ b/src/3rdparty/libtiff/libtiff/tiffio.h @@ -71,6 +71,11 @@ typedef uint32 toff_t; /* file offset */ #define __WIN32__ #endif +// Bug in stdlib.h, see more information from fixed_stdlib.h +#if (defined __SYMBIAN32__ && !defined __cplusplus) +#include <fixed_stdlib.h> +#endif // defined __SYMBIAN32__ && !defined __cplusplus + /* * On windows you should define USE_WIN32_FILEIO if you are using tif_win32.c * or AVOID_WIN32_FILEIO if you are using something else (like tif_unix.c). diff --git a/src/3rdparty/phonon/phonon/phonon_export.h b/src/3rdparty/phonon/phonon/phonon_export.h index e579f67..5f93ea0 100644 --- a/src/3rdparty/phonon/phonon/phonon_export.h +++ b/src/3rdparty/phonon/phonon/phonon_export.h @@ -32,7 +32,11 @@ # define PHONON_EXPORT Q_DECL_IMPORT # endif # else /* UNIX */ -# define PHONON_EXPORT Q_DECL_EXPORT +# ifdef MAKE_PHONON_LIB /* We are building this library */ +# define PHONON_EXPORT Q_DECL_EXPORT +# else /* We are using this library */ +# define PHONON_EXPORT Q_DECL_IMPORT +# endif # endif #endif diff --git a/src/3rdparty/zlib/zutil.h b/src/3rdparty/zlib/zutil.h index b7d5eff..3ecb1bb 100644 --- a/src/3rdparty/zlib/zutil.h +++ b/src/3rdparty/zlib/zutil.h @@ -21,7 +21,12 @@ # include <stddef.h> # endif # include <string.h> -# include <stdlib.h> +// Bug in stdlib.h, see more information from fixed_stdlib.h +#if (defined __SYMBIAN32__ && !defined __cplusplus) +#include <fixed_stdlib.h> +#else +#include <stdlib.h> +#endif // defined __SYMBIAN32__ && !defined __cplusplus #endif #ifdef NO_ERRNO_H # ifdef _WIN32_WCE diff --git a/src/corelib/arch/arch.pri b/src/corelib/arch/arch.pri index 20b9227..de4de1f 100644 --- a/src/corelib/arch/arch.pri +++ b/src/corelib/arch/arch.pri @@ -4,7 +4,10 @@ win32:HEADERS += arch/qatomic_windows.h \ mac:HEADERS += arch/qatomic_macosx.h \ arch/qatomic_generic.h -!wince*:!win32:!mac:HEADERS += arch/qatomic_alpha.h \ +symbian:HEADERS += arch/qatomic_symbian.h \ + arch/qatomic_generic.h + +!wince*:!win32:!mac:!symbian:HEADERS += arch/qatomic_alpha.h \ arch/qatomic_avr32.h \ arch/qatomic_ia64.h \ arch/qatomic_parisc.h \ diff --git a/src/corelib/arch/generic/qatomic_generic_unix.cpp b/src/corelib/arch/generic/qatomic_generic_unix.cpp index 15918be..876042f 100644 --- a/src/corelib/arch/generic/qatomic_generic_unix.cpp +++ b/src/corelib/arch/generic/qatomic_generic_unix.cpp @@ -39,10 +39,13 @@ ** ****************************************************************************/ +#if !defined(Q_OS_SYMBIAN) || (defined(Q_OS_SYMBIAN) && !defined(Q_CC_RVCT)) + #include "qplatformdefs.h" #include <QtCore/qatomic.h> +QT_BEGIN_NAMESPACE static pthread_mutex_t qAtomicMutex = PTHREAD_MUTEX_INITIALIZER; Q_CORE_EXPORT @@ -116,3 +119,5 @@ void *QBasicAtomicPointer_fetchAndAddOrdered(void * volatile *_q_value, qptrdiff pthread_mutex_unlock(&qAtomicMutex); return returnValue; } +QT_END_NAMESPACE +#endif //!defined(Q_OS_SYMBIAN) && !defined(Q_CC_RVCT) diff --git a/src/corelib/arch/qatomic_arch.h b/src/corelib/arch/qatomic_arch.h index 33641fc..7889147 100644 --- a/src/corelib/arch/qatomic_arch.h +++ b/src/corelib/arch/qatomic_arch.h @@ -80,6 +80,8 @@ QT_BEGIN_HEADER # include "QtCore/qatomic_windowsce.h" #elif defined(QT_ARCH_X86_64) # include "QtCore/qatomic_x86_64.h" +#elif defined(QT_ARCH_SYMBIAN) +# include "QtCore/qatomic_symbian.h" #elif defined(QT_ARCH_SH) # include "QtCore/qatomic_sh.h" #elif defined(QT_ARCH_SH4A) diff --git a/src/corelib/arch/qatomic_arm.h b/src/corelib/arch/qatomic_arm.h index 07ad70c..c025637 100644 --- a/src/corelib/arch/qatomic_arm.h +++ b/src/corelib/arch/qatomic_arm.h @@ -116,6 +116,12 @@ extern "C" typedef int (qt_atomic_eabi_cmpxchg_ptr_t)(void *oldval, void *newval extern Q_CORE_EXPORT char q_atomic_lock; Q_CORE_EXPORT void qt_atomic_yield(int *); +#ifdef Q_CC_RVCT + +Q_CORE_EXPORT __asm char q_atomic_swp(volatile char *ptr, char newval); + +#else + inline char q_atomic_swp(volatile char *ptr, char newval) { register char ret; @@ -126,7 +132,9 @@ inline char q_atomic_swp(volatile char *ptr, char newval) return ret; } -#endif +#endif // Q_CC_RVCT + +#endif // QT_NO_ARM_EABI // Reference counting @@ -213,6 +221,8 @@ inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) // Fetch and store for integers +#ifndef Q_CC_RVCT + inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) { int originalValue; @@ -223,6 +233,8 @@ inline int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) return originalValue; } +#endif + inline int QBasicAtomicInt::fetchAndStoreRelaxed(int newValue) { return fetchAndStoreOrdered(newValue); @@ -323,6 +335,22 @@ Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetRelease(T *expectedValu // Fetch and store for pointers +#ifdef Q_CC_RVCT + +template <typename T> +__asm T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue) +{ + add r2, pc, #0 + bx r2 + arm + swp r2,r1,[r0] + mov r0, r2 + bx lr + thumb +} + +#else + template <typename T> Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue) { @@ -334,6 +362,8 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreOrdered(T *newValue) return originalValue; } +#endif // Q_CC_RVCT + template <typename T> Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndStoreRelaxed(T *newValue) { diff --git a/src/corelib/arch/qatomic_symbian.h b/src/corelib/arch/qatomic_symbian.h new file mode 100644 index 0000000..9b8b341 --- /dev/null +++ b/src/corelib/arch/qatomic_symbian.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QATOMIC_SYMBIAN_H +#define QATOMIC_SYMBIAN_H + +QT_BEGIN_HEADER + +#if defined(Q_CC_RVCT) +# define QT_NO_ARM_EABI +# include <QtCore/qatomic_arm.h> +#elif defined(Q_CC_NOKIAX86) || defined(Q_CC_GCCE) +# include <QtCore/qatomic_generic.h> +#endif + +QT_END_HEADER + +#endif // QATOMIC_SYMBIAN_H diff --git a/src/corelib/arch/qatomic_windows.h b/src/corelib/arch/qatomic_windows.h index 5135575..a1a5a7d 100644 --- a/src/corelib/arch/qatomic_windows.h +++ b/src/corelib/arch/qatomic_windows.h @@ -107,7 +107,7 @@ template <typename T> Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::isFetchAndAddWaitFree() { return true; } -#if defined(Q_CC_MSVC) +#if defined(Q_CC_MSVC) || defined(Q_CC_MWERKS) // MSVC++ 6.0 doesn't generate correct code when optimizations are turned on! #if _MSC_VER < 1300 && defined (_M_IX86) @@ -218,7 +218,7 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueTo #else -#if !defined(Q_OS_WINCE) +#if !defined(Q_OS_WINCE) && !defined(Q_CC_MWERKS) // use compiler intrinsics for all atomic functions //those functions need to be define in the global namespace QT_END_NAMESPACE @@ -319,7 +319,7 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueTo #else // Q_OS_WINCE -#if _WIN32_WCE < 0x600 && defined(_X86_) +#if (_WIN32_WCE < 0x600 && defined(_X86_)) || defined(Q_CC_MWERKS) // For X86 Windows CE build we need to include winbase.h to be able // to catch the inline functions which overwrite the regular // definitions inside of coredll.dll. Though one could use the @@ -327,8 +327,7 @@ Q_INLINE_TEMPLATE T *QBasicAtomicPointer<T>::fetchAndAddOrdered(qptrdiff valueTo // exported at all. #include <winbase.h> #else - -#if _WIN32_WCE >= 0x600 +#if _WIN32_WCE >= 0x600 || defined(Q_CC_MWERKS) #define Q_ARGUMENT_TYPE volatile # if defined(_X86_) # define InterlockedIncrement _InterlockedIncrement diff --git a/src/corelib/arch/symbian/arch.pri b/src/corelib/arch/symbian/arch.pri new file mode 100644 index 0000000..deb94b1 --- /dev/null +++ b/src/corelib/arch/symbian/arch.pri @@ -0,0 +1,5 @@ +# +# Symbian architecture +# +SOURCES += $$QT_ARCH_CPP/qatomic_symbian.cpp \ + $$QT_ARCH_CPP/../generic/qatomic_generic_unix.cpp diff --git a/src/corelib/arch/symbian/qatomic_symbian.cpp b/src/corelib/arch/symbian/qatomic_symbian.cpp new file mode 100644 index 0000000..170b737 --- /dev/null +++ b/src/corelib/arch/symbian/qatomic_symbian.cpp @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qglobal.h> +#include <QtCore/qatomic.h> + +#if defined(Q_CC_RVCT) + +#include "../arm/qatomic_arm.cpp" + +QT_BEGIN_NAMESPACE + +// This declspec needs to be explicit. RVCT has a bug which prevents embedded +// assembler functions from being exported (normally all functions are +// exported, and Q_CORE_EXPORT resolves to nothing). +__declspec(dllexport) __asm char q_atomic_swp(volatile char *ptr, char newval) +{ + add r2, pc, #0 + bx r2 + arm + swpb r2,r1,[r0] + mov r0, r2 + bx lr + thumb +} + +__declspec(dllexport) __asm int QBasicAtomicInt::fetchAndStoreOrdered(int newValue) +{ + add r2, pc, #0 + bx r2 + arm + swp r2,r1,[r0] + mov r0, r2 + bx lr + thumb +} + +QT_END_NAMESPACE + +#endif // Q_CC_RVCT + diff --git a/src/corelib/concurrent/qtconcurrentiteratekernel.cpp b/src/corelib/concurrent/qtconcurrentiteratekernel.cpp index 5c20146..bfc0e82 100644 --- a/src/corelib/concurrent/qtconcurrentiteratekernel.cpp +++ b/src/corelib/concurrent/qtconcurrentiteratekernel.cpp @@ -108,11 +108,17 @@ static qint64 getticks() return 0; return (ts.tv_sec * 1000000000) + ts.tv_nsec; #else + +#ifdef Q_OS_SYMBIAN + return clock(); +#else // no clock_gettime(), fall back to wall time struct timeval tv; gettimeofday(&tv, 0); return (tv.tv_sec * 1000000) + tv.tv_usec; #endif + +#endif } #elif defined(Q_OS_WIN) diff --git a/src/corelib/concurrent/qtconcurrentiteratekernel.h b/src/corelib/concurrent/qtconcurrentiteratekernel.h index 01c54a7..5cf4ebe 100644 --- a/src/corelib/concurrent/qtconcurrentiteratekernel.h +++ b/src/corelib/concurrent/qtconcurrentiteratekernel.h @@ -49,8 +49,10 @@ #include <QtCore/qatomic.h> #include <QtCore/qtconcurrentmedian.h> #include <QtCore/qtconcurrentthreadengine.h> -#include <iterator> +#ifndef QT_NO_STL +# include <iterator> +#endif QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -148,6 +150,7 @@ public: inline void * getPointer() { return 0; } }; +#ifndef QT_NO_STL inline bool selectIteration(std::bidirectional_iterator_tag) { return false; // while @@ -162,6 +165,14 @@ inline bool selectIteration(std::random_access_iterator_tag) { return true; // for } +#else +// no stl support, always use while iteration +template <typename T> +inline bool selectIteration(T) +{ + return false; // while +} +#endif template <typename Iterator, typename T> class IterateKernel : public ThreadEngine<T> @@ -170,7 +181,10 @@ public: typedef T ResultType; IterateKernel(Iterator _begin, Iterator _end) -#ifndef QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION +#if defined (QT_NO_STL) + : begin(_begin), end(_end), current(_begin), currentIndex(0), + forIteration(false), progressReportingEnabled(true) +#elif !defined(QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION) : begin(_begin), end(_end), current(_begin), currentIndex(0), forIteration(selectIteration(typename std::iterator_traits<Iterator>::iterator_category())), progressReportingEnabled(true) #else @@ -178,7 +192,12 @@ public: forIteration(selectIteration(std::iterator_category(_begin))), progressReportingEnabled(true) #endif { +#if defined (QT_NO_STL) + iterationCount = 0; +#else iterationCount = forIteration ? std::distance(_begin, _end) : 0; + +#endif } virtual ~IterateKernel() { } diff --git a/src/corelib/concurrent/qtconcurrentthreadengine.h b/src/corelib/concurrent/qtconcurrentthreadengine.h index 9e7d12e..444e0db 100644 --- a/src/corelib/concurrent/qtconcurrentthreadengine.h +++ b/src/corelib/concurrent/qtconcurrentthreadengine.h @@ -51,6 +51,7 @@ #include <QtCore/qdebug.h> #include <QtCore/qtconcurrentexception.h> #include <QtCore/qwaitcondition.h> +#include <QtCore/qmutex.h> QT_BEGIN_HEADER QT_BEGIN_NAMESPACE diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro index f99d57f..c55c2da 100644 --- a/src/corelib/corelib.pro +++ b/src/corelib/corelib.pro @@ -26,3 +26,11 @@ QMAKE_LIBS += $$QMAKE_LIBS_CORE QMAKE_DYNAMIC_LIST_FILE = $$PWD/QtCore.dynlist contains(DEFINES,QT_EVAL):include(eval.pri) + +symbian: { + TARGET.UID3=0x2001B2DC + + # Workaroud for problems with paging this dll + MMP_RULES -= PAGED + MMP_RULES *= UNPAGED +}
\ No newline at end of file diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index f767bb9..ca243e7 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -44,6 +44,8 @@ #include "qvector.h" #include "qlist.h" #include "qthreadstorage.h" +#include "qdir.h" +#include "qstringlist.h" #ifndef QT_NO_QOBJECT #include <private/qthread_p.h> @@ -62,10 +64,15 @@ # endif #endif -#ifdef Q_CC_MWERKS +#if defined(Q_CC_MWERKS) && defined(Q_OS_MACX) #include <CoreServices/CoreServices.h> #endif +#if defined(Q_OS_SYMBIAN) +#include <e32def.h> +#include <e32debug.h> +#endif + QT_BEGIN_NAMESPACE @@ -1049,6 +1056,20 @@ bool qSharedBuild() */ /*! + \fn QSysInfo::SymVersion QSysInfo::symbianVersion() + + Returns the version of the Symbian operating system on which the + application is run (Symbian only). +*/ + +/*! + \fn QSysInfo::S60Version QSysInfo::s60Version() + + Returns the version of the S60 SDK system on which the + application is run (S60 only). +*/ + +/*! \enum QSysInfo::Endian \value BigEndian Big-endian byte order (also called Network byte order) @@ -1104,7 +1125,7 @@ bool qSharedBuild() \value WV_NT_based NT-based version of Windows \value WV_CE_based CE-based version of Windows - \sa MacVersion + \sa MacVersion, SymVersion */ /*! @@ -1133,7 +1154,39 @@ bool qSharedBuild() \value MV_LEOPARD Apple codename for MV_10_5 \value MV_SNOWLEOPARD Apple codename for MV_10_6 - \sa WinVersion + \sa WinVersion, SymVersion +*/ + +/*! + \enum QSysInfo::SymVersion + + This enum provides symbolic names for the various versions of the + Symbian operating system. On Symbian, the + QSysInfo::symbianVersion() function gives the version of the + system on which the application is run. + + \value SV_9_2 Symbian OS 9.2 + \value SV_9_3 Symbian OS 9.3 + \value SV_9_4 Symbian OS 9.4 + \value SV_Unknown An unknown and currently unsupported platform + + \sa S60Version, WinVersion, MacVersion +*/ + +/*! + \enum QSysInfo::S60Version + + This enum provides symbolic names for the various versions of the + S60 SDK. On S60, the + QSysInfo::s60Version() function gives the version of the + SDK on which the application is run. + + \value SV_S60_3_1 S60 3rd Edition Feature Pack 1 + \value SV_S60_3_2 S60 3rd Edition Feature Pack 2 + \value SV_S60_5_0 S60 5th Edition + \value SV_S60_Unknown An unknown and currently unsupported platform + + \sa SymVersion, WinVersion, MacVersion */ /*! @@ -1711,6 +1764,79 @@ const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion() #endif +#ifdef Q_OS_SYMBIAN +# ifdef Q_WS_S60 +static QSysInfo::S60Version cachedS60Version = QSysInfo::S60Version(-1); + +QSysInfo::S60Version QSysInfo::s60Version() +{ +# ifdef Q_CC_NOKIAX86 + // For emulator builds. Emulators don't support the trick we use to figure + // out which SDK we are running under, so simply hardcode it there. +# if defined(__SERIES60_31__) + return SV_S60_3_1; + +# elif defined(__S60_32__) + return SV_S60_3_2; + +# elif defined(__S60_50__) + return SV_S60_5_0; + +# else + return SV_S60_Unknown; + +# endif + +# else + // For hardware builds. + if (cachedS60Version != -1) + return cachedS60Version; + + QDir dir(QLatin1String("z:\\system\\install")); + QStringList filters; + filters << QLatin1String("Series60v?.*.sis"); + dir.setNameFilters(filters); + + QStringList names = dir.entryList(QDir::NoFilter, QDir::Name | QDir::Reversed | QDir::IgnoreCase); + if (names.size() == 0) + return cachedS60Version = SV_S60_Unknown; + + int major, minor; + major = names[0][9].toAscii() - '0'; + minor = names[0][11].toAscii() - '0'; + if (major == 3) { + if (minor == 1) { + return cachedS60Version = SV_S60_3_1; + } else if (minor == 2) { + return cachedS60Version = SV_S60_3_2; + } + } else if (major == 5) { + if (minor == 0) { + return cachedS60Version = SV_S60_5_0; + } + } + + return cachedS60Version = SV_S60_Unknown; +# endif +} +# else +# error Qt does not support non-S60 Symbian versions yet. +# endif // ifdef Q_WS_S60 +QSysInfo::SymVersion QSysInfo::symbianVersion() +{ + switch (s60Version()) { + case SV_S60_3_1: + return SV_9_2; + case SV_S60_3_2: + return SV_9_3; + case SV_S60_5_0: + return SV_9_4; + default: + return SV_Unknown; + } +} +#endif // ifdef Q_OS_SYMBIAN + /*! \macro void Q_ASSERT(bool test) \relates <QtGlobal> @@ -1860,7 +1986,7 @@ void *qMemSet(void *dest, int c, size_t n) { return memset(dest, c, n); } static QtMsgHandler handler = 0; // pointer to debug handler -#ifdef Q_CC_MWERKS +#if defined(Q_CC_MWERKS) && defined(Q_OS_MACX) extern bool qt_is_gui_used; static void mac_default_handler(const char *msg) { @@ -1872,7 +1998,7 @@ static void mac_default_handler(const char *msg) fprintf(stderr, msg); } } -#endif // Q_CC_MWERKS +#endif // Q_CC_MWERKS && Q_OS_MACX @@ -2006,12 +2132,23 @@ void qt_message_output(QtMsgType msgType, const char *buf) if (handler) { (*handler)(msgType, buf); } else { -#if defined(Q_CC_MWERKS) +#if defined(Q_CC_MWERKS) && defined(Q_OS_MACX) mac_default_handler(buf); #elif defined(Q_OS_WINCE) QString fstr = QString::fromLatin1(buf); fstr += QLatin1String("\n"); OutputDebugString(reinterpret_cast<const wchar_t *> (fstr.utf16())); +#elif defined(Q_OS_SYMBIAN) + // RDebug::Print has a cap of 256 characters so break it up + _LIT(format, "[Qt Message] %S"); + const int maxBlockSize = 256 - ((const TDesC &)format).Length(); + const TPtrC8 ptr(reinterpret_cast<const TUint8*>(buf)); + HBufC* hbuffer = HBufC::NewL(qMin(maxBlockSize, ptr.Length())); + for (int i = 0; i < ptr.Length(); i += hbuffer->Length()) { + hbuffer->Des().Copy(ptr.Mid(i, qMin(maxBlockSize, ptr.Length()-i))); + RDebug::Print(format, hbuffer); + } + delete hbuffer; #else fprintf(stderr, "%s\n", buf); fflush(stderr); @@ -2038,7 +2175,10 @@ void qt_message_output(QtMsgType msgType, const char *buf) _CrtDbgBreak(); #endif -#if (defined(Q_OS_UNIX) || defined(Q_CC_MINGW)) +#if defined(Q_OS_SYMBIAN) + __DEBUGGER(); // on the emulator, get the debugger to kick in if there's one around + User::Invariant(); // Panic the current thread +#elif (defined(Q_OS_UNIX) || defined(Q_CC_MINGW)) abort(); // trap; generates core dump #else exit(1); // goodbye cruel world @@ -2307,7 +2447,7 @@ Q_GLOBAL_STATIC(SeedStorage, randTLS) // Thread Local Storage for seed value */ void qsrand(uint seed) { -#if defined(Q_OS_UNIX) && !defined(QT_NO_THREAD) +#if defined(Q_OS_UNIX) && !defined(QT_NO_THREAD) && !defined(Q_OS_SYMBIAN) SeedStorageType *pseed = randTLS()->localData(); if (!pseed) randTLS()->setLocalData(pseed = new SeedStorageType); @@ -2336,7 +2476,7 @@ void qsrand(uint seed) */ int qrand() { -#if defined(Q_OS_UNIX) && !defined(QT_NO_THREAD) +#if defined(Q_OS_UNIX) && !defined(QT_NO_THREAD) && !defined(Q_OS_SYMBIAN) SeedStorageType *pseed = randTLS()->localData(); if (!pseed) { randTLS()->setLocalData(pseed = new SeedStorageType); diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 36d87e2..27aaac1 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -144,6 +144,7 @@ namespace QT_NAMESPACE {} The operating system, must be one of: (Q_OS_x) DARWIN - Darwin OS (synonym for Q_OS_MAC) + SYMBIAN - Symbian MSDOS - MS-DOS and Windows OS2 - OS/2 OS2EMX - XFree86 on OS/2 (not PM) @@ -182,6 +183,11 @@ namespace QT_NAMESPACE {} # else # define Q_OS_DARWIN32 # endif +#elif defined(__SYMBIAN32__) || defined(SYMBIAN) +# define Q_OS_SYMBIAN +# define Q_NO_POSIX_SIGNALS +// TODO: should this be in qconfig.h +# define QT_NO_GETIFADDRS #elif defined(__CYGWIN__) # define Q_OS_CYGWIN #elif defined(MSDOS) || defined(_MSDOS) @@ -351,7 +357,9 @@ namespace QT_NAMESPACE {} HIGHC - MetaWare High C/C++ PGI - Portland Group C++ GHS - Green Hills Optimizing C++ Compilers + GCCE - GCCE (Symbian GCCE builds) RVCT - ARM Realview Compiler Suite + NOKIAX86 - Nokia x86 (Symbian WINSCW builds) Should be sorted most to least authoritative. @@ -372,6 +380,9 @@ namespace QT_NAMESPACE {} #elif defined(__MWERKS__) # define Q_CC_MWERKS +# if defined(__EMU_SYMBIAN_OS__) +# define Q_CC_NOKIAX86 +# endif /* "explicit" recognized since 4.0d1 */ #elif defined(_MSC_VER) @@ -442,7 +453,15 @@ namespace QT_NAMESPACE {} # define QT_NO_QWS_CURSOR # endif -#elif defined(__CC_ARM) +/* Symbian GCCE */ +#elif defined(__GCCE__) +# define Q_CC_GCCE +# define QT_VISIBILITY_AVAILABLE + +/* ARM Realview Compiler Suite + RVCT compiler also defines __EDG__ and __GNUC__ (if --gnu flag is given), + so check for it before that */ +#elif defined(__ARMCC__) || defined(__CC_ARM) # define Q_CC_RVCT #elif defined(__GNUC__) @@ -684,6 +703,11 @@ namespace QT_NAMESPACE {} # endif # define Q_NO_USING_KEYWORD /* ### check "using" status */ +#elif defined(__WINSCW__) && !defined(Q_CC_NOKIAX86) +# define Q_CC_NOKIAX86 +// # define Q_CC_MWERKS // May be required + + #else # error "Qt has not been tested with this compiler - talk to qt-bugs@trolltech.com" #endif @@ -731,6 +755,7 @@ namespace QT_NAMESPACE {} QWS - Qt for Embedded Linux WIN32 - Windows X11 - X Window System + S60 - Symbian S60 PM - unsupported WIN16 - unsupported */ @@ -759,6 +784,8 @@ namespace QT_NAMESPACE {} # elif defined(Q_OS_MAC32) # define Q_WS_MAC32 # endif +# elif defined(Q_OS_SYMBIAN) +# define Q_WS_S60 # elif !defined(Q_WS_QWS) # define Q_WS_X11 # endif @@ -783,7 +810,7 @@ typedef short qint16; /* 16 bit signed */ typedef unsigned short quint16; /* 16 bit unsigned */ typedef int qint32; /* 32 bit signed */ typedef unsigned int quint32; /* 32 bit unsigned */ -#if defined(Q_OS_WIN) && !defined(Q_CC_GNU) +#if defined(Q_OS_WIN) && !defined(Q_CC_GNU) && !defined(Q_CC_MWERKS) # define Q_INT64_C(c) c ## i64 /* signed 64 bit constant */ # define Q_UINT64_C(c) c ## ui64 /* unsigned 64 bit constant */ typedef __int64 qint64; /* 64 bit signed */ @@ -801,7 +828,7 @@ typedef quint64 qulonglong; #ifndef QT_POINTER_SIZE # if defined(Q_OS_WIN64) # define QT_POINTER_SIZE 8 -# elif defined(Q_OS_WIN32) || defined(Q_OS_WINCE) +# elif defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) # define QT_POINTER_SIZE 4 # endif #endif @@ -853,6 +880,12 @@ QT_END_INCLUDE_NAMESPACE */ #ifndef QT_LINUXBASE /* the LSB defines TRUE and FALSE for us */ +/* Symbian OS defines TRUE = 1 and FALSE = 0, +redefine to built-in booleans to make autotests work properly */ +#ifdef Q_OS_SYMBIAN + #undef TRUE + #undef FALSE +#endif # ifndef TRUE # define TRUE true # define FALSE false @@ -1006,7 +1039,7 @@ typedef int QNoImplicitBoolCast; #if defined(QT_COORD_TYPE) typedef QT_COORD_TYPE qreal; -#elif defined(QT_NO_FPU) || defined(QT_ARCH_ARM) || defined(QT_ARCH_WINDOWSCE) +#elif defined(QT_NO_FPU) || defined(QT_ARCH_ARM) || defined(QT_ARCH_WINDOWSCE) || defined(QT_ARCH_SYMBIAN) typedef float qreal; #else typedef double qreal; @@ -1085,6 +1118,8 @@ class QDataStream; #ifndef Q_DECL_EXPORT # ifdef Q_OS_WIN # define Q_DECL_EXPORT __declspec(dllexport) +# elif defined(Q_CC_NOKIAX86) +# define Q_DECL_EXPORT __declspec(dllexport) # elif defined(QT_VISIBILITY_AVAILABLE) # define Q_DECL_EXPORT __attribute__((visibility("default"))) # endif @@ -1095,6 +1130,8 @@ class QDataStream; #ifndef Q_DECL_IMPORT # if defined(Q_OS_WIN) # define Q_DECL_IMPORT __declspec(dllimport) +# elif defined(Q_CC_NOKIAX86) +# define Q_DECL_IMPORT __declspec(dllimport) # else # define Q_DECL_IMPORT # endif @@ -1104,7 +1141,7 @@ class QDataStream; Create Qt DLL if QT_DLL is defined (Windows only) */ -#if defined(Q_OS_WIN) +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) # if defined(QT_NODLL) # undef QT_MAKEDLL # undef QT_DLL @@ -1249,11 +1286,11 @@ class QDataStream; for Trolltech's internal unit tests. If you want slower loading times and more symbols that can vanish from version to version, feel free to define QT_BUILD_INTERNAL. */ -#if defined(QT_BUILD_INTERNAL) && defined(Q_OS_WIN) && defined(QT_MAKEDLL) +#if defined(QT_BUILD_INTERNAL) && (defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)) && defined(QT_MAKEDLL) # define Q_AUTOTEST_EXPORT Q_DECL_EXPORT -#elif defined(QT_BUILD_INTERNAL) && defined(Q_OS_WIN) && defined(QT_DLL) +#elif defined(QT_BUILD_INTERNAL) && (defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)) && defined(QT_DLL) # define Q_AUTOTEST_EXPORT Q_DECL_IMPORT -#elif defined(QT_BUILD_INTERNAL) && !defined(Q_OS_WIN) && defined(QT_SHARED) +#elif defined(QT_BUILD_INTERNAL) && !(defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)) && defined(QT_SHARED) # define Q_AUTOTEST_EXPORT Q_DECL_EXPORT #else # define Q_AUTOTEST_EXPORT @@ -1355,6 +1392,24 @@ public: }; static const MacVersion MacintoshVersion; #endif +#ifdef Q_OS_SYMBIAN + enum SymVersion { + SV_Unknown = 0x0000, + SV_9_2 = 0x0001, + SV_9_3 = 0x0002, + SV_9_4 = 0x0004 + }; + static SymVersion symbianVersion(); +# ifdef Q_WS_S60 + enum S60Version { + SV_S60_Unknown = 0x0000, + SV_S60_3_1 = 0x0001, + SV_S60_3_2 = 0x0002, + SV_S60_5_0 = 0x0004 + }; + static S60Version s60Version(); +# endif +#endif }; Q_CORE_EXPORT const char *qVersion(); @@ -1382,6 +1437,9 @@ inline QT3_SUPPORT int qWinVersion() { return QSysInfo::WindowsVersion; } #ifdef Q_OS_WINCE #define QT_WA(uni, ansi) uni #define QT_WA_INLINE(uni, ansi) (uni) +#elif defined(Q_CC_MWERKS) +#define QT_WA(uni, ansi) ansi +#define QT_WA_INLINE(uni, ansi) (ansi) #elif defined(UNICODE) #define QT_WA(uni, ansi) if (!(QSysInfo::windowsVersion() & QSysInfo::WV_DOS_based)) { uni } else { ansi } @@ -1419,6 +1477,10 @@ inline void qUnused(T &x) { (void)x; } Debugging and error handling */ +#if defined(Q_OS_SYMBIAN) && defined(NDEBUG) +# define QT_NO_DEBUG +#endif + #if !defined(QT_NO_DEBUG) && !defined(QT_DEBUG) # define QT_DEBUG #endif @@ -1531,7 +1593,7 @@ Q_CORE_EXPORT void qt_check_pointer(const char *, int); # define Q_FUNC_INFO __FUNCSIG__ # endif #else -# if defined(Q_OS_SOLARIS) || defined(Q_CC_XLC) +# if defined(Q_OS_SOLARIS) || defined(Q_CC_XLC) || defined(Q_OS_SYMBIAN) # define Q_FUNC_INFO __FILE__ "(line number unavailable)" # else /* These two macros makes it possible to turn the builtin line expander into a @@ -1540,9 +1602,9 @@ Q_CORE_EXPORT void qt_check_pointer(const char *, int); # define QT_STRINGIFY(x) QT_STRINGIFY2(x) # define Q_FUNC_INFO __FILE__ ":" QT_STRINGIFY(__LINE__) # endif - /* The MIPSpro compiler postpones macro expansion, and therefore macros must be in scope - * when being used. */ -# if !defined(Q_CC_MIPS) + /* The MIPSpro and RVCT compilers postpones macro expansion, + and therefore macros must be in scope when being used. */ +# if !defined(Q_CC_MIPS) && !defined(Q_CC_RVCT) && !defined(Q_CC_NOKIAX86) # undef QT_STRINGIFY2 # undef QT_STRINGIFY # endif @@ -1859,7 +1921,7 @@ public: \ types must declare a 'bool isDetached(void) const;' member for this to work. */ -#if defined Q_CC_MSVC && _MSC_VER < 1300 +#if (defined Q_CC_MSVC && _MSC_VER < 1300) || defined(Q_CC_MWERKS) template <typename T> inline void qSwap_helper(T &value1, T &value2, T*) { @@ -2042,7 +2104,7 @@ typedef uint Flags; #endif /* Q_NO_TYPESAFE_FLAGS */ -#if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) +#if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_RVCT) /* make use of typeof-extension */ template <typename T> class QForeachContainer { diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index a519f4a..43740ed 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -44,6 +44,10 @@ #include <QtCore/qglobal.h> +#ifdef Q_OS_SYMBIAN +# include <e32def.h> +#endif + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -1390,8 +1394,29 @@ public: ImFont, ImCursorPosition, ImSurroundingText, - ImCurrentSelection + ImCurrentSelection, + ImMaximumTextLength, + ImAnchorPosition + }; + + enum InputMethodHint { + ImhNone = 0x0, + ImhHiddenText = 0x1, + ImhNoAutoUppercase = 0x2, + ImhPreferNumbers = 0x4, + ImhPreferUppercase = 0x8, + ImhPreferLowercase = 0x10, + ImhNoPredictiveText = 0x20, + + ImhDigitsOnly = 0x10000, + ImhFormattedNumbersOnly = 0x20000, + ImhUppercaseOnly = 0x40000, + ImhLowercaseOnly = 0x80000, + ImhDialableCharactersOnly = 0x100000, + + ImhExclusiveInputMask = 0xffff0000 }; + Q_DECLARE_FLAGS(InputMethodHints, InputMethodHint) enum ToolButtonStyle { ToolButtonIconOnly, @@ -1485,6 +1510,8 @@ public: typedef unsigned long HANDLE; #elif defined(Q_WS_QWS) typedef void * HANDLE; +#elif defined(Q_WS_S60) + typedef unsigned long int HANDLE; // equivalent to TUint32 #endif typedef WindowFlags WFlags; @@ -1552,6 +1579,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::DropActions) Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::ItemFlags) Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::MatchFlags) Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::TextInteractionFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::InputMethodHints) typedef bool (*qInternalCallback)(void **); diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index 3690d4b..845dc2e 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -62,7 +62,8 @@ win32 { } else:unix { SOURCES += io/qfsfileengine_unix.cpp SOURCES += io/qfsfileengine_iterator_unix.cpp - SOURCES += io/qprocess_unix.cpp + symbian:SOURCES += io/qprocess_symbian.cpp + else:SOURCES += io/qprocess_unix.cpp mac:SOURCES += io/qsettings_mac.cpp linux-*:{ @@ -79,4 +80,9 @@ win32 { SOURCES += io/qfilesystemwatcher_kqueue.cpp HEADERS += io/qfilesystemwatcher_kqueue_p.h } + + symbian { + SOURCES += io/qfilesystemwatcher_symbian.cpp + HEADERS += io/qfilesystemwatcher_symbian_p.h + } } diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index b7861ba..901641c 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE static QString driveSpec(const QString &path) { -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) if (path.size() < 2) return QString(); char c = path.at(0).toAscii(); @@ -147,7 +147,7 @@ private: QString path = p; if ((path.endsWith(QLatin1Char('/')) || path.endsWith(QLatin1Char('\\'))) && path.length() > 1) { -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) if (!(path.length() == 3 && path.at(1) == QLatin1Char(':'))) #endif path.truncate(path.length() - 1); @@ -772,6 +772,8 @@ QString QDir::relativeFilePath(const QString &fileName) const if (fileDrive.toLower() != dirDrive.toLower() || (file.startsWith(QLatin1String("//")) && !dir.startsWith(QLatin1String("//")))) +#elif defined(Q_OS_SYMBIAN) + if (fileDrive.toLower() != dirDrive.toLower()) #else if (fileDrive != dirDrive) #endif @@ -787,7 +789,7 @@ QString QDir::relativeFilePath(const QString &fileName) const int i = 0; while (i < dirElts.size() && i < fileElts.size() && -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) dirElts.at(i).toLower() == fileElts.at(i).toLower()) #else dirElts.at(i) == fileElts.at(i)) @@ -834,7 +836,7 @@ QString QDir::convertSeparators(const QString &pathName) QString QDir::toNativeSeparators(const QString &pathName) { QString n(pathName); -#if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) +#if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) || defined(Q_OS_SYMBIAN) for (int i=0; i<(int)n.length(); i++) { if (n[i] == QLatin1Char('/')) n[i] = QLatin1Char('\\'); @@ -858,7 +860,7 @@ QString QDir::toNativeSeparators(const QString &pathName) QString QDir::fromNativeSeparators(const QString &pathName) { QString n(pathName); -#if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) +#if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) || defined(Q_OS_SYMBIAN) for (int i=0; i<(int)n.length(); i++) { if (n[i] == QLatin1Char('\\')) n[i] = QLatin1Char('/'); @@ -1800,10 +1802,10 @@ QFileInfoList QDir::drives() QChar QDir::separator() { -#if defined(Q_OS_UNIX) - return QLatin1Char('/'); -#elif defined (Q_FS_FAT) || defined(Q_WS_WIN) +#if defined (Q_FS_FAT) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) return QLatin1Char('\\'); +#elif defined(Q_OS_UNIX) + return QLatin1Char('/'); #elif defined (Q_OS_MAC) return QLatin1Char(':'); #else @@ -1903,7 +1905,8 @@ QString QDir::currentPath() Under non-Windows operating systems the \c HOME environment variable is used if it exists, otherwise the path returned by the - rootPath() function is used. + rootPath() function is used, except in Symbian, where c:\\data is + returned. \sa home(), currentPath(), rootPath(), tempPath() */ @@ -2054,7 +2057,7 @@ QString QDir::cleanPath(const QString &path) QString name = path; QChar dir_separator = separator(); if(dir_separator != QLatin1Char('/')) - name.replace(dir_separator, QLatin1Char('/')); + name.replace(dir_separator, QLatin1Char('/')); int used = 0, levels = 0; const int len = name.length(); @@ -2123,7 +2126,7 @@ QString QDir::cleanPath(const QString &path) levels++; } } else if(last != -1 && iwrite - last == 1) { -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) eaten = (iwrite > 2); #else eaten = true; diff --git a/src/corelib/io/qfile.cpp b/src/corelib/io/qfile.cpp index 10b812b..551485d 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -746,9 +746,10 @@ QFile::rename(const QString &newName) error = true; } } - if (error) + if (error) { out.remove(); - else { + } else { + fileEngine()->setFileName(newName); setPermissions(permissions()); unsetError(); setFileName(newName); @@ -794,6 +795,9 @@ QFile::rename(const QString &oldName, const QString &newName) \note To create a valid link on Windows, \a linkName must have a \c{.lnk} file extension. + \note On Symbian, no link is created and false is returned if fileName() + currently specifies a directory. + \sa setFileName() */ diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp index e073a08..b83ab85 100644 --- a/src/corelib/io/qfilesystemwatcher.cpp +++ b/src/corelib/io/qfilesystemwatcher.cpp @@ -59,6 +59,8 @@ # include "qfilesystemwatcher_dnotify_p.h" #elif defined(Q_OS_FREEBSD) || defined(Q_OS_MAC) # include "qfilesystemwatcher_kqueue_p.h" +#elif defined(Q_OS_SYMBIAN) +# include "qfilesystemwatcher_symbian_p.h" #endif QT_BEGIN_NAMESPACE @@ -244,6 +246,8 @@ QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine() return eng; #elif defined(Q_OS_FREEBSD) || defined(Q_OS_MAC) return QKqueueFileSystemWatcherEngine::create(); +#elif defined(Q_OS_SYMBIAN) + return new QSymbianFileSystemWatcherEngine; #else return 0; #endif diff --git a/src/corelib/io/qfilesystemwatcher_symbian.cpp b/src/corelib/io/qfilesystemwatcher_symbian.cpp new file mode 100644 index 0000000..b1a6188 --- /dev/null +++ b/src/corelib/io/qfilesystemwatcher_symbian.cpp @@ -0,0 +1,282 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfilesystemwatcher.h" +#include "qfilesystemwatcher_symbian_p.h" +#include "qfileinfo.h" +#include "qdebug.h" +#include "private/qcore_symbian_p.h" +#include <QDir> + +#ifndef QT_NO_FILESYSTEMWATCHER + + +QT_BEGIN_NAMESPACE + +CNotifyChangeEvent* CNotifyChangeEvent::New(RFs &fs, const TDesC& file, + QSymbianFileSystemWatcherEngine* e) +{ + CNotifyChangeEvent* self = new CNotifyChangeEvent(fs, file, e); + return self; +} + +CNotifyChangeEvent::CNotifyChangeEvent(RFs &fs, const TDesC& file, + QSymbianFileSystemWatcherEngine* e, TInt aPriority) : + CActive(aPriority), + fsSession(fs), + watchedPath(file), + engine(e) +{ + fsSession.NotifyChange(ENotifyAll, iStatus, file); + CActiveScheduler::Add(this); + SetActive(); +} + +CNotifyChangeEvent::~CNotifyChangeEvent() +{ + Cancel(); +} + +void CNotifyChangeEvent::RunL() +{ + if (iStatus.Int() == KErrNone){ + fsSession.NotifyChange(ENotifyAll, iStatus, watchedPath); + SetActive(); + engine->emitPathChanged(this); + } else { + qWarning("CNotifyChangeEvent::RunL() - Failed to order change notifications: %d", iStatus.Int()); + } +} + +void CNotifyChangeEvent::DoCancel() +{ + fsSession.NotifyChangeCancel(); +} + +QSymbianFileSystemWatcherEngine::QSymbianFileSystemWatcherEngine() : + watcherStarted(false) +{ + moveToThread(this); +} + +QSymbianFileSystemWatcherEngine::~QSymbianFileSystemWatcherEngine() +{ + stop(); +} + +QStringList QSymbianFileSystemWatcherEngine::addPaths(const QStringList &paths, + QStringList *files, QStringList *directories) +{ + QMutexLocker locker(&mutex); + QStringList p = paths; + + if (!startWatcher()) { + qWarning("Could not start QSymbianFileSystemWatcherEngine thread"); + + return p; + } + + QMutableListIterator<QString> it(p); + while (it.hasNext()) { + QString path = it.next(); + QFileInfo fi(path); + if (!fi.exists()) + continue; + + bool isDir = fi.isDir(); + if (isDir) { + if (directories->contains(path)) + continue; + } else { + if (files->contains(path)) + continue; + } + + // Use absolute filepath as relative paths seem to have some issues. + QString filePath = fi.absoluteFilePath(); + if(isDir && filePath.at(filePath.size()-1) != QChar('/')) { + filePath += QChar('/'); + } + + currentEvent = NULL; + QMetaObject::invokeMethod(this, + "addNativeListener", + Qt::QueuedConnection, + Q_ARG(QString, filePath)); + + syncCondition.wait(&mutex); + + if (currentEvent) { + currentEvent->isDir = isDir; + + activeObjectToPath.insert(currentEvent, path); + it.remove(); + + if (isDir) + directories->append(path); + else + files->append(path); + } + } + + return p; +} + +QStringList QSymbianFileSystemWatcherEngine::removePaths(const QStringList &paths, + QStringList *files, QStringList *directories) +{ + QMutexLocker locker(&mutex); + + QStringList p = paths; + QMutableListIterator<QString> it(p); + while (it.hasNext()) { + QString path = it.next(); + + currentEvent = activeObjectToPath.key(path); + if (!currentEvent) + continue; + activeObjectToPath.remove(currentEvent); + + QMetaObject::invokeMethod(this, + "removeNativeListener", + Qt::QueuedConnection); + + syncCondition.wait(&mutex); + + it.remove(); + + files->removeAll(path); + directories->removeAll(path); + } + + if (activeObjectToPath.size() == 0) + stop(); + + return p; +} + +void QSymbianFileSystemWatcherEngine::emitPathChanged(CNotifyChangeEvent *e) +{ + QMutexLocker locker(&mutex); + + QString path = activeObjectToPath.value(e); + QFileInfo fi(path); + + if (e->isDir) { + emit directoryChanged(path, !fi.exists()); + } else { + emit fileChanged(path, !fi.exists()); + } +} + +void QSymbianFileSystemWatcherEngine::stop() +{ + QMetaObject::invokeMethod(this, "quit"); + wait(); +} + +// This method must be called inside mutex +bool QSymbianFileSystemWatcherEngine::startWatcher() +{ + bool retval = true; + + if (!watcherStarted) { +#if defined(Q_OS_SYMBIAN) + setStackSize(0x5000); +#endif + start(); + syncCondition.wait(&mutex); + + if (errorCode != KErrNone) { + retval = false; + } else { + watcherStarted = true; + } + } + return retval; +} + + +void QSymbianFileSystemWatcherEngine::run() +{ + // Initialize file session + + errorCode = fsSession.Connect(); + + mutex.lock(); + syncCondition.wakeOne(); + mutex.unlock(); + + if (errorCode == KErrNone) { + exec(); + + foreach(CNotifyChangeEvent* e, activeObjectToPath.keys()) { + e->Cancel(); + delete e; + } + + activeObjectToPath.clear(); + fsSession.Close(); + watcherStarted = false; + } +} + +void QSymbianFileSystemWatcherEngine::addNativeListener(const QString &directoryPath) +{ + QMutexLocker locker(&mutex); + HBufC* buffer = qt_QString2HBufCNewL(QDir::toNativeSeparators(directoryPath)); + currentEvent = CNotifyChangeEvent::New(fsSession, *buffer, this); + delete buffer; + syncCondition.wakeOne(); +} + +void QSymbianFileSystemWatcherEngine::removeNativeListener() +{ + QMutexLocker locker(&mutex); + currentEvent->Cancel(); + delete currentEvent; + currentEvent = NULL; + syncCondition.wakeOne(); +} + + +QT_END_NAMESPACE +#endif // QT_NO_FILESYSTEMWATCHER diff --git a/src/corelib/io/qfilesystemwatcher_symbian_p.h b/src/corelib/io/qfilesystemwatcher_symbian_p.h new file mode 100644 index 0000000..9919114 --- /dev/null +++ b/src/corelib/io/qfilesystemwatcher_symbian_p.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFILESYSTEMWATCHER_SYMBIAN_P_H +#define QFILESYSTEMWATCHER_SYMBIAN_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qfilesystemwatcher_p.h" +#include "qhash.h" +#include "qmutex.h" +#include "qwaitcondition.h" + +#ifndef QT_NO_FILESYSTEMWATCHER + +#include <e32base.h> +#include <f32file.h> + +QT_BEGIN_NAMESPACE + +class QSymbianFileSystemWatcherEngine; + +class CNotifyChangeEvent : public CActive +{ +public: + CNotifyChangeEvent(RFs &fsSession, const TDesC& file, QSymbianFileSystemWatcherEngine* engine, + TInt aPriority = EPriorityStandard); + ~CNotifyChangeEvent(); + static CNotifyChangeEvent* New(RFs &fsSession, const TDesC& file, + QSymbianFileSystemWatcherEngine* engine); + + bool isDir; + +private: + void RunL(); + void DoCancel(); + + RFs &fsSession; + TPath watchedPath; + QSymbianFileSystemWatcherEngine *engine; +}; + +class QSymbianFileSystemWatcherEngine : public QFileSystemWatcherEngine +{ + Q_OBJECT + +public: + QSymbianFileSystemWatcherEngine(); + ~QSymbianFileSystemWatcherEngine(); + + QStringList addPaths(const QStringList &paths, QStringList *files, + QStringList *directories); + QStringList removePaths(const QStringList &paths, QStringList *files, + QStringList *directories); + + void stop(); + +protected: + void run(); + +public Q_SLOTS: + void addNativeListener(const QString &directoryPath); + void removeNativeListener(); + +private: + friend class CNotifyChangeEvent; + void emitPathChanged(CNotifyChangeEvent *e); + + bool startWatcher(); + + RFs fsSession; + QHash<CNotifyChangeEvent*, QString> activeObjectToPath; + QMutex mutex; + QWaitCondition syncCondition; + int errorCode; + bool watcherStarted; + CNotifyChangeEvent *currentEvent; +}; + +#endif // QT_NO_FILESYSTEMWATCHER + +QT_END_NAMESPACE + +#endif // QFILESYSTEMWATCHER_WIN_P_H diff --git a/src/corelib/io/qfsfileengine.h b/src/corelib/io/qfsfileengine.h index a2b732e..f54a6e8 100644 --- a/src/corelib/io/qfsfileengine.h +++ b/src/corelib/io/qfsfileengine.h @@ -83,6 +83,9 @@ public: FileFlags fileFlags(FileFlags type) const; bool setPermissions(uint perms); QString fileName(FileName file) const; +#ifdef Q_OS_SYMBIAN + QString fileNameSymbian(FileName file) const; +#endif uint ownerId(FileOwner) const; QString owner(FileOwner) const; QDateTime fileTime(FileTime time) const; diff --git a/src/corelib/io/qfsfileengine_iterator_unix.cpp b/src/corelib/io/qfsfileengine_iterator_unix.cpp index 2284d9b..fd95f81 100644 --- a/src/corelib/io/qfsfileengine_iterator_unix.cpp +++ b/src/corelib/io/qfsfileengine_iterator_unix.cpp @@ -53,7 +53,7 @@ class QFSFileEngineIteratorPlatformSpecificData public: inline QFSFileEngineIteratorPlatformSpecificData() : dir(0), dirEntry(0), done(false) -#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) +#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN) , mt_file(0) #endif { } @@ -62,7 +62,7 @@ public: dirent *dirEntry; bool done; -#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) +#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN) // for readdir_r dirent *mt_file; #endif @@ -75,7 +75,7 @@ void QFSFileEngineIterator::advance() if (!platform->dir) return; -#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) +#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN) if (::readdir_r(platform->dir, platform->mt_file, &platform->dirEntry) != 0) platform->done = true; #else @@ -86,7 +86,7 @@ void QFSFileEngineIterator::advance() ::closedir(platform->dir); platform->dir = 0; platform->done = true; -#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) +#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN) delete [] platform->mt_file; platform->mt_file = 0; #endif @@ -102,7 +102,7 @@ void QFSFileEngineIterator::deletePlatformSpecifics() { if (platform->dir) { ::closedir(platform->dir); -#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) +#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN) delete [] platform->mt_file; platform->mt_file = 0; #endif @@ -123,7 +123,7 @@ bool QFSFileEngineIterator::hasNext() const if ((int) maxPathName == -1) maxPathName = FILENAME_MAX; maxPathName += sizeof(dirent) + 1; -#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) +#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_CYGWIN) && !defined(Q_OS_SYMBIAN) if (that->platform->mt_file) delete [] that->platform->mt_file; that->platform->mt_file = (dirent *)new char[maxPathName]; diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index 459725c..e595f15 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -51,12 +51,16 @@ #include "qfile.h" #include "qdir.h" #include "qdatetime.h" -#include "qdebug.h" #include "qvarlengtharray.h" #include <sys/mman.h> #include <stdlib.h> #include <limits.h> +#if defined(Q_OS_SYMBIAN) +# include <syslimits.h> +# include <f32file.h> +# include "private/qcore_symbian_p.h" +#endif #include <errno.h> #if !defined(QWS) && defined(Q_OS_MAC) # include <private/qcore_mac_p.h> @@ -64,6 +68,22 @@ QT_BEGIN_NAMESPACE + +#ifdef Q_OS_SYMBIAN +/*! + \internal + + Returns true if supplied path is a relative path +*/ +static bool isRelativePathSymbian(const QString& fileName) +{ + return !(fileName.startsWith(QLatin1Char('/')) + || (fileName.length() >= 2 + && ((fileName.at(0).isLetter() && fileName.at(1) == QLatin1Char(':')) + || (fileName.at(0) == QLatin1Char('/') && fileName.at(1) == QLatin1Char('/'))))); +} +#endif + /*! \internal @@ -376,10 +396,39 @@ bool QFSFileEngine::remove() return unlink(d->nativeFilePath.constData()) == 0; } -bool QFSFileEngine::copy(const QString &) +bool QFSFileEngine::copy(const QString &newName) { +#if defined(Q_OS_SYMBIAN) + Q_D(QFSFileEngine); + RFs rfs; + TInt err = rfs.Connect(); + if (err == KErrNone) { + CFileMan* fm = NULL; + HBufC* oldBuf = NULL; + HBufC* newBuf = NULL; + TRAP (err, + fm = CFileMan::NewL(rfs); + oldBuf = qt_QString2HBufCNewL(QDir::toNativeSeparators(d->filePath)); + RFile rfile; + err = rfile.Open(rfs, *oldBuf, EFileShareReadersOrWriters); + if (err == KErrNone) { + QFileInfo fi(newName); + QString absoluteNewName = fi.absolutePath() + QDir::separator() + fi.fileName(); + newBuf = qt_QString2HBufCNewL(QDir::toNativeSeparators(absoluteNewName)); + err = fm->Copy(rfile, *newBuf); + rfile.Close(); + } + ) // End TRAP + delete oldBuf; + delete newBuf; + delete fm; + rfs.Close(); + } + return (err == KErrNone); +#else // ### Add copy code for Unix here return false; +#endif } bool QFSFileEngine::rename(const QString &newName) @@ -403,7 +452,11 @@ bool QFSFileEngine::mkdir(const QString &name, bool createParentDirectories) con { QString dirName = name; if (createParentDirectories) { +#if defined(Q_OS_SYMBIAN) + dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName)); +#else dirName = QDir::cleanPath(dirName); +#endif for(int oldslash = -1, slash=0; slash != -1; oldslash = slash) { slash = dirName.indexOf(QDir::separator(), oldslash+1); if (slash == -1) { @@ -435,7 +488,11 @@ bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) co { QString dirName = name; if (recurseParentDirectories) { +#if defined(Q_OS_SYMBIAN) + dirName = QDir::toNativeSeparators(QDir::cleanPath(dirName)); +#else dirName = QDir::cleanPath(dirName); +#endif for(int oldslash = 0, slash=dirName.length(); slash > 0; oldslash = slash) { QByteArray chunk = QFile::encodeName(dirName.left(slash)); QT_STATBUF st; @@ -456,7 +513,11 @@ bool QFSFileEngine::rmdir(const QString &name, bool recurseParentDirectories) co bool QFSFileEngine::caseSensitive() const { +#if defined(Q_OS_SYMBIAN) + return false; +#else return true; +#endif } bool QFSFileEngine::setCurrentPath(const QString &path) @@ -470,6 +531,16 @@ QString QFSFileEngine::currentPath(const QString &) { QString result; QT_STATBUF st; +#if defined(Q_OS_SYMBIAN) + char currentName[PATH_MAX+1]; + if (::getcwd(currentName, PATH_MAX)) + result = QDir::fromNativeSeparators(QFile::decodeName(QByteArray(currentName))); + if (result.isEmpty()) { +# if defined(QT_DEBUG) + qWarning("QDir::currentPath: getcwd() failed"); +# endif + } else +#endif if (QT_STAT(".", &st) == 0) { #if defined(__GLIBC__) && !defined(PATH_MAX) char *currentName = ::get_current_dir_name(); @@ -477,18 +548,26 @@ QString QFSFileEngine::currentPath(const QString &) result = QFile::decodeName(QByteArray(currentName)); ::free(currentName); } -#else +#elif !defined(Q_OS_SYMBIAN) char currentName[PATH_MAX+1]; if (::getcwd(currentName, PATH_MAX)) result = QFile::decodeName(QByteArray(currentName)); -#endif -#if defined(QT_DEBUG) +# if defined(QT_DEBUG) if (result.isNull()) qWarning("QDir::currentPath: getcwd() failed"); +# endif #endif } else { -#if defined(QT_DEBUG) +#if defined(Q_OS_SYMBIAN) + // If current dir returned by Open C doesn't exist, + // try to create it (can happen with application private dirs) + // Ignore mkdir failures; we want to be consistent with Open C + // current path regardless. + ::mkdir(QFile::encodeName(currentName), 0777); +#else +# if defined(QT_DEBUG) qWarning("QDir::currentPath: stat(\".\") failed"); +# endif #endif } return result; @@ -497,28 +576,61 @@ QString QFSFileEngine::currentPath(const QString &) QString QFSFileEngine::homePath() { QString home = QFile::decodeName(qgetenv("HOME")); +#if defined(Q_OS_SYMBIAN) + if (home.isEmpty()) + home = QLatin1String("C:/Data"); +#else if (home.isNull()) home = rootPath(); +#endif return home; } QString QFSFileEngine::rootPath() { +#if defined(Q_OS_SYMBIAN) + return QString::fromLatin1("C:/"); +#else return QString::fromLatin1("/"); +#endif } QString QFSFileEngine::tempPath() { - QString temp = QFile::decodeName(qgetenv("TMPDIR")); - if (temp.isEmpty()) - temp = QString::fromLatin1("/tmp/"); +#ifdef Q_OS_SYMBIAN + QString temp = QDir::currentPath().left(2); + temp += QString::fromLatin1( "/system/temp/"); +#else + QString temp = QFile::decodeName(qgetenv("TMPDIR")); + if (temp.isEmpty()) + temp = QString::fromLatin1("/tmp/"); +#endif return temp; } QFileInfoList QFSFileEngine::drives() { QFileInfoList ret; +#if defined(Q_OS_SYMBIAN) + TDriveList driveList; + RFs rfs; + TInt err = rfs.Connect(); + if (err == KErrNone) { + err = rfs.DriveList(driveList); + if (err == KErrNone) { + for(char i=0; i < KMaxDrives; i++) { + if (driveList[i]) { + ret.append(QString("%1:/").arg(QChar('A'+i))); + } + } + } else { + qWarning("QDir::drives: Getting drives failed"); + } + rfs.Close(); + } +#else ret.append(rootPath()); +#endif return ret; } @@ -551,6 +663,32 @@ bool QFSFileEnginePrivate::isSymlink() const return is_link; } +#if defined(Q_OS_SYMBIAN) +static bool _q_isSymbianHidden(const QString &path, bool isDir) +{ + bool retval = false; + RFs rfs; + TInt err = rfs.Connect(); + if (err == KErrNone) { + QFileInfo fi(path); + QString absPath = fi.absoluteFilePath(); + if (isDir && absPath.at(absPath.size()-1) != QChar('/')) { + absPath += QChar('/'); + } + HBufC* buffer = qt_QString2HBufCNewL(QDir::toNativeSeparators(absPath)); + TUint attributes; + err = rfs.Att(*buffer, attributes); + delete buffer; + rfs.Close(); + if (err == KErrNone && (attributes & KEntryAttHidden)) { + retval = true; + } + } + + return retval; +} +#endif + #if !defined(QWS) && defined(Q_OS_MAC) static bool _q_isMacHidden(const QString &path) { @@ -671,20 +809,147 @@ QAbstractFileEngine::FileFlags QFSFileEngine::fileFlags(FileFlags type) const ret |= LocalDiskFlag; if (exists) ret |= ExistsFlag; +#if defined(Q_OS_SYMBIAN) + if (d->filePath == QLatin1String("/") || (d->filePath.at(0).isLetter() && d->filePath.mid(1,d->filePath.length()) == QLatin1String(":/"))) + ret |= RootFlag; + + // In Symbian, all symlinks have hidden attribute for some reason; + // lets make them visible for better compatibility with other platforms. + // If somebody actually wants a hidden link, then they are out of luck. + if (!(ret & RootFlag) && !d->isSymlink()) + if(_q_isSymbianHidden(d->filePath, ret & DirectoryType) +#else if (fileName(BaseName)[0] == QLatin1Char('.') -#if !defined(QWS) && defined(Q_OS_MAC) +# if !defined(QWS) && defined(Q_OS_MAC) || _q_isMacHidden(d->filePath) +# endif #endif ) ret |= HiddenFlag; +#if !defined(Q_OS_SYMBIAN) if (d->filePath == QLatin1String("/")) ret |= RootFlag; +#endif } return ret; } +#ifdef Q_OS_SYMBIAN +QString QFSFileEngine::fileNameSymbian(FileName file) const +{ + Q_D(const QFSFileEngine); + if(file == BaseName) { + int slash = d->filePath.lastIndexOf(QLatin1Char('/')); + if(slash == -1) { + int colon = d->filePath.lastIndexOf(QLatin1Char(':')); + if(colon != -1) + return d->filePath.mid(colon + 1); + return d->filePath; + } + return d->filePath.mid(slash + 1); + } else if(file == PathName) { + if(!d->filePath.size()) + return d->filePath; + + int slash = d->filePath.lastIndexOf(QLatin1Char('/')); + if(slash == -1) { + if(d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) + return d->filePath.left(2); + return QString::fromLatin1("."); + } else { + if(!slash) + return QString::fromLatin1("/"); + if(slash == 2 && d->filePath.length() >= 2 && d->filePath.at(1) == QLatin1Char(':')) + slash++; + return d->filePath.left(slash); + } + } else if(file == AbsoluteName || file == AbsolutePathName) { + QString ret; + if (!isRelativePath()) { + if (d->filePath.size() > 2 && d->filePath.at(1) == QLatin1Char(':') + && d->filePath.at(2) != QLatin1Char('/') || // It's a drive-relative path, so Z:a.txt -> Z:\currentpath\a.txt + d->filePath.startsWith(QLatin1Char('/')) // It's a absolute path to the current drive, so \a.txt -> Z:\a.txt + ) { + ret = QString(QDir::currentPath().left(2) + QDir::fromNativeSeparators(d->filePath)); + } else { + ret = d->filePath; + } + } else { + ret = QDir::cleanPath(QDir::currentPath() + QLatin1Char('/') + d->filePath); + } + + // The path should be absolute at this point. + // From the docs : + // Absolute paths begin with the directory separator "/" + // (optionally preceded by a drive specification under Windows). + if (ret.at(0) != QLatin1Char('/')) { + Q_ASSERT(ret.length() >= 2); + Q_ASSERT(ret.at(0).isLetter()); + Q_ASSERT(ret.at(1) == QLatin1Char(':')); + + // Force uppercase drive letters. + ret[0] = ret.at(0).toUpper(); + } + + if (file == AbsolutePathName) { + int slash = ret.lastIndexOf(QLatin1Char('/')); + if (slash < 0) + return ret; + else if (ret.at(0) != QLatin1Char('/') && slash == 2) + return ret.left(3); // include the slash + else + return ret.left(slash > 0 ? slash : 1); + } + return ret; + } else if(file == CanonicalName || file == CanonicalPathName) { + if (!(fileFlags(ExistsFlag) & ExistsFlag)) + return QString(); + + QString ret = QFSFileEnginePrivate::canonicalized(fileName(AbsoluteName)); + if (!ret.isEmpty() && file == CanonicalPathName) { + int slash = ret.lastIndexOf(QLatin1Char('/')); + if (slash == -1) + ret = QDir::fromNativeSeparators(QDir::currentPath()); + else if (slash == 0) + ret = QLatin1String("/"); + ret = ret.left(slash); + } + return ret; + } else if(file == LinkName) { + if (d->isSymlink()) { + char s[PATH_MAX+1]; + int len = readlink(d->nativeFilePath.constData(), s, PATH_MAX); + if (len > 0) { + s[len] = '\0'; + QString ret = QFile::decodeName(QByteArray(s)); + + if (isRelativePathSymbian(ret)) { + if (!isRelativePathSymbian(d->filePath)) { + ret.prepend(d->filePath.left(d->filePath.lastIndexOf(QLatin1Char('/'))) + + QLatin1Char('/')); + } else { + ret.prepend(QDir::currentPath() + QLatin1Char('/')); + } + } + ret = QDir::cleanPath(ret); + if (ret.size() > 1 && ret.endsWith(QLatin1Char('/'))) + ret.chop(1); + return ret; + } + } + return QString(); + } else if(file == BundleName) { + return QString(); + } + return d->filePath; +} +#endif + QString QFSFileEngine::fileName(FileName file) const { +#ifdef Q_OS_SYMBIAN + return fileNameSymbian(file); +#endif Q_D(const QFSFileEngine); if (file == BundleName) { #if !defined(QWS) && defined(Q_OS_MAC) @@ -828,10 +1093,14 @@ QString QFSFileEngine::fileName(FileName file) const bool QFSFileEngine::isRelativePath() const { Q_D(const QFSFileEngine); +#ifdef Q_OS_SYMBIAN + return isRelativePathSymbian(d->filePath); +#else int len = d->filePath.length(); if (len == 0) return true; return d->filePath[0] != QLatin1Char('/'); +#endif } uint QFSFileEngine::ownerId(FileOwner own) const @@ -867,6 +1136,9 @@ QString QFSFileEngine::owner(FileOwner own) const if (pw) return QFile::decodeName(QByteArray(pw->pw_name)); } else if (own == OwnerGroup) { +#ifdef Q_OS_SYMBIAN + return QString(); +#endif struct group *gr = 0; #if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD) size_max = sysconf(_SC_GETGR_R_SIZE_MAX); diff --git a/src/corelib/io/qfsfileengine_win.cpp b/src/corelib/io/qfsfileengine_win.cpp index b22d6c7..6ae13e9 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -1400,7 +1400,7 @@ bool QFSFileEnginePrivate::doStat() const static QString readLink(const QString &link) { #if !defined(Q_OS_WINCE) -#if !defined(QT_NO_LIBRARY) +#if !defined(QT_NO_LIBRARY) && !defined(Q_CC_MWERKS) QString ret; QT_WA({ bool neededCoInit = false; @@ -1500,7 +1500,7 @@ QString QFSFileEnginePrivate::getLink() const bool QFSFileEngine::link(const QString &newName) { #if !defined(Q_OS_WINCE) -#if !defined(QT_NO_LIBRARY) +#if !defined(QT_NO_LIBRARY) && !defined(Q_CC_MWERKS) bool ret = false; QString linkName = newName; diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index efa4b25..765bf40 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -362,7 +362,7 @@ QIODevice::QIODevice() { #if defined QIODEVICE_DEBUG QFile *file = qobject_cast<QFile *>(this); - printf("%p QIODevice::QIODevice(\"%s\") %s\n", this, className(), + printf("%p QIODevice::QIODevice(\"%s\") %s\n", this, metaObject()->className(), qPrintable(file ? file->fileName() : QString())); #endif } @@ -375,7 +375,7 @@ QIODevice::QIODevice(QObject *parent) : QObject(*new QIODevicePrivate, parent) { #if defined QIODEVICE_DEBUG - printf("%p QIODevice::QIODevice(%p \"%s\")\n", this, parent, className()); + printf("%p QIODevice::QIODevice(%p \"%s\")\n", this, parent, metaObject()->className()); #endif } @@ -1032,6 +1032,15 @@ qint64 QIODevice::readLine(char *data, qint64 maxSize) if (readSoFar) debugBinaryString(data, int(readSoFar)); #endif +#if defined(Q_OS_SYMBIAN) + // Open C fgets strips '\r' but readSoFar gets returned as if it was still there + if ((d->openMode & Text) && + readSoFar > 1 && + data[readSoFar - 1] == '\0' && + data[readSoFar - 2] == '\n') { + --readSoFar; + } +#endif if (readSoFar && data[readSoFar - 1] == '\n') { if (d->openMode & Text) { // QRingBuffer::readLine() isn't Text aware. @@ -1070,6 +1079,12 @@ qint64 QIODevice::readLine(char *data, qint64 maxSize) data[readSoFar] = '\0'; if (d->openMode & Text) { +#if defined(Q_OS_SYMBIAN) + // Open C fgets strips '\r' but readSoFar gets returned as if it was still there + if (readSoFar > 1 && data[readSoFar - 1] == '\0' && data[readSoFar - 2] == '\n') { + --readSoFar; + } +#endif if (readSoFar > 1 && data[readSoFar - 1] == '\n' && data[readSoFar - 2] == '\r') { data[readSoFar - 2] = '\n'; data[readSoFar - 1] = '\0'; diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index a128482..8183527 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -153,7 +153,8 @@ void QProcessPrivate::Channel::clear() used as an input source for QXmlReader, or for generating data to be uploaded using QFtp. - \note On Windows CE, reading and writing to a process is not supported. + \note On Windows CE and Symbian, reading and writing to a process + is not supported. When the process exits, QProcess reenters the \l NotRunning state (the initial state), and emits finished(). @@ -203,6 +204,10 @@ void QProcessPrivate::Channel::clear() setWorkingDirectory(). By default, processes are run in the current working directory of the calling process. + \note On Symbian, setting environment or working directory + is not supported. The working directory will always be the private + directory of the running process. + \section1 Synchronous Process API QProcess provides a set of functions which allow it to be used @@ -436,6 +441,10 @@ QProcessPrivate::QProcessPrivate() #ifdef Q_OS_UNIX serial = 0; #endif +#ifdef Q_OS_SYMBIAN + symbianProcess = NULL; + processLaunched = false; +#endif } /*! \internal @@ -508,6 +517,13 @@ void QProcessPrivate::cleanup() #ifdef Q_OS_UNIX serial = 0; #endif +#ifdef Q_OS_SYMBIAN + if (symbianProcess) { + symbianProcess->Close(); + delete symbianProcess; + symbianProcess = NULL; + } +#endif } /*! \internal @@ -765,7 +781,7 @@ void QProcessPrivate::closeWriteChannel() if (stdinChannel.notifier) { qDeleteInEventHandler(stdinChannel.notifier); stdinChannel.notifier = 0; - } + } } #ifdef Q_OS_WIN // ### Find a better fix, feeding the process little by little @@ -1064,6 +1080,10 @@ QString QProcess::workingDirectory() const process in this directory. The default behavior is to start the process in the working directory of the calling process. + \note The working directory setting is ignored on Symbian; + the private directory of the process is considered its working + directory. + \sa workingDirectory(), start() */ void QProcess::setWorkingDirectory(const QString &dir) @@ -1205,7 +1225,7 @@ void QProcess::setEnvironment(const QStringList &environment) using setEnvironment(). If no environment has been set, the environment of the calling process will be used. - \note The environment settings are ignored on Windows CE, + \note The environment settings are ignored on Windows CE and Symbian, as there is no concept of an environment. \sa setEnvironment(), systemEnvironment() @@ -1636,6 +1656,9 @@ void QProcess::start(const QString &program, OpenMode mode) event loop does not handle the WM_CLOSE message, can only be terminated by calling kill(). + \note Terminating running processes from other processes will typically + cause a panic in Symbian due to platform security. + \sa kill() */ void QProcess::terminate() @@ -1650,6 +1673,9 @@ void QProcess::terminate() On Windows, kill() uses TerminateProcess, and on Unix and Mac OS X, the SIGKILL signal is sent to the process. + \note Killing running processes from other processes will typically + cause a panic in Symbian due to platform security. + \sa terminate() */ void QProcess::kill() @@ -1796,9 +1822,9 @@ QT_BEGIN_INCLUDE_NAMESPACE #ifdef Q_OS_MAC # include <crt_externs.h> # define environ (*_NSGetEnviron()) -#elif defined(Q_OS_WINCE) - static char *qt_wince_environ[] = { 0 }; -#define environ qt_wince_environ +#elif defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) + static char *qt_empty_environ[] = { 0 }; +#define environ qt_empty_environ #elif !defined(Q_OS_WIN) extern char **environ; #endif diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h index 54a96c7..ae40de3 100644 --- a/src/corelib/io/qprocess.h +++ b/src/corelib/io/qprocess.h @@ -53,8 +53,13 @@ QT_MODULE(Core) #ifndef QT_NO_PROCESS -#if (!defined(Q_OS_WIN32) && !defined(Q_OS_WINCE)) || defined(qdoc) +#if (!defined(Q_OS_WIN32) && !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)) || defined(qdoc) typedef qint64 Q_PID; +#elif defined(Q_OS_SYMBIAN) +QT_END_NAMESPACE +# include <e32std.h> +QT_BEGIN_NAMESPACE +typedef TProcessId Q_PID; #else QT_END_NAMESPACE typedef struct _PROCESS_INFORMATION *Q_PID; diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h index 33059dd..554c477 100644 --- a/src/corelib/io/qprocess_p.h +++ b/src/corelib/io/qprocess_p.h @@ -180,7 +180,7 @@ public: QWinEventNotifier *processFinishedNotifier; void startProcess(); -#ifdef Q_OS_UNIX +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) void execChild(const char *workingDirectory, char **path, char **argv, char **envp); #endif bool processStarted(); @@ -221,6 +221,11 @@ public: #ifdef Q_OS_UNIX static void initializeProcessManager(); #endif + +#ifdef Q_OS_SYMBIAN + bool processLaunched; + RProcess* symbianProcess; +#endif }; QT_END_NAMESPACE diff --git a/src/corelib/io/qprocess_symbian.cpp b/src/corelib/io/qprocess_symbian.cpp new file mode 100644 index 0000000..a59976c --- /dev/null +++ b/src/corelib/io/qprocess_symbian.cpp @@ -0,0 +1,1033 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//#define QPROCESS_DEBUG + +#ifdef QPROCESS_DEBUG +#include "qdebug.h" +#define QPROCESS_DEBUG_PRINT(args...) qDebug(args); +#else +#define QPROCESS_DEBUG_PRINT(args...) +#endif + +#ifndef QT_NO_PROCESS + +#define QPROCESS_ASSERT(check, panicReason, args...) \ + if (!(check)) { \ + qWarning(args); \ + User::Panic(KQProcessPanic, panicReason); \ + } + +#include <e32base.h> +#include <e32std.h> +#include <stdio.h> +#include "qplatformdefs.h" + +#include "qstring.h" +#include "qprocess.h" +#include "qprocess_p.h" + +#include <private/qthread_p.h> +#include <qmutex.h> +#include <qmap.h> +#include <qsocketnotifier.h> + +#include <errno.h> + + +QT_BEGIN_NAMESPACE + +_LIT(KQProcessManagerThreadName, "QProcManThread"); +_LIT(KQProcessPanic, "QPROCESS"); +enum TQProcessPanic { + EProcessManagerMediatorRunError = 1, + EProcessManagerMediatorInactive = 2, + EProcessManagerMediatorNotPending = 3, + EProcessManagerMediatorInvalidCmd = 4, + EProcessManagerMediatorCreationFailed = 5, + EProcessManagerMediatorThreadOpenFailed = 6, + EProcessManagerMediatorNullObserver = 7, + EProcessActiveRunError = 10, + EProcessActiveNullParameter = 11, + EProcessManagerMutexCreationFail = 20, + EProcessManagerThreadCreationFail = 21, + EProcessManagerSchedulerCreationFail = 22, + EProcessManagerNullParam = 23 +}; + +// Forward declarations +class QProcessManager; + + +// Active object to listen for child process death +class CProcessActive : public CActive +{ +public: + static CProcessActive* construct(QProcess* process, + RProcess** proc, + int serial, + int deathPipe); + + virtual ~CProcessActive(); + + void start(); + void stop(); + + bool error(); + +protected: + + // From CActive + void RunL(); + TInt RunError(TInt aError); + void DoCancel(); + + CProcessActive(); + +private: + + QProcess* process; + RProcess** pproc; + int serial; + int deathPipe; + bool errorValue; +}; + +// Active object to communicate synchronously with process manager thread +class CProcessManagerMediator : public CActive +{ +public: + static CProcessManagerMediator* construct(); + + virtual ~CProcessManagerMediator(); + + bool add(CProcessActive* processObserver); + void remove(CProcessActive* processObserver); + void terminate(); + +protected: + + enum Commands { + ENoCommand, + EAdd, + ERemove, + ETerminate + }; + + // From CActive + void RunL(); + TInt RunError(TInt aError); + void DoCancel(); + + CProcessManagerMediator(); + + bool notify(CProcessActive* processObserver, Commands command); + +private: + CProcessActive* currentObserver; + Commands currentCommand; + + RThread processManagerThread; +}; + +// Process manager manages child process death listeners +class QProcessManager +{ +public: + QProcessManager(); + ~QProcessManager(); + + void startThread(); + + TInt run(void* param); + bool add(QProcess *process); + void remove(QProcess *process); + + inline void setMediator(CProcessManagerMediator* newMediator) {mediator = newMediator;}; + +private: + inline void lock() {managerMutex.Wait();}; + inline void unlock() {managerMutex.Signal();}; + + QMap<int, CProcessActive *> children; + CProcessManagerMediator* mediator; + RMutex managerMutex; + bool threadStarted; + RThread managerThread; +}; + +static bool qt_rprocess_running(RProcess* proc) +{ + if(proc && proc->Handle()) { + TExitType et = proc->ExitType(); + if (et == EExitPending) { + return true; + } + } + + return false; +} + +static void qt_create_symbian_commandline(const QStringList &arguments, QString& commandLine) +{ + for (int i=0; i<arguments.size(); ++i) { + QString tmp = arguments.at(i); + // in the case of \" already being in the string the \ must also be escaped + tmp.replace( QLatin1String("\\\""), QLatin1String("\\\\\"") ); + // escape a single " because the arguments will be parsed + tmp.replace( QLatin1String("\""), QLatin1String("\\\"") ); + if (tmp.isEmpty() || tmp.contains(QLatin1Char(' ')) || tmp.contains(QLatin1Char('\t'))) { + // The argument must not end with a \ since this would be interpreted + // as escaping the quote -- rather put the \ behind the quote: e.g. + // rather use "foo"\ than "foo\" + QString endQuote(QLatin1String("\"")); + int i = tmp.length(); + while (i>0 && tmp.at(i-1) == QLatin1Char('\\')) { + --i; + endQuote += QLatin1String("\\"); + } + commandLine += QLatin1String(" \"") + tmp.left(i) + endQuote; + } else { + commandLine += QLatin1Char(' ') + tmp; + } + } +} + +static TInt qt_create_symbian_process(RProcess **proc, const QString &programName, const QStringList &arguments) +{ + RProcess* newProc = NULL; + newProc = new RProcess(); + + if (!newProc) { + return KErrNoMemory; + } + + QString commandLine; + qt_create_symbian_commandline(arguments, commandLine); + + TPtrC program_ptr(reinterpret_cast<const TText*>(programName.constData())); + TPtrC cmdline_ptr(reinterpret_cast<const TText*>(commandLine.constData())); + + TInt err = newProc->Create(program_ptr, cmdline_ptr); + + if (err == KErrNotFound){ + // Strip path from program name and try again (i.e. try from default location "\sys\bin") + int index = programName.lastIndexOf(QChar('\\')); + int index2 = programName.lastIndexOf(QChar('/')); + index = qMax(index, index2); + + if(index != -1 && programName.length() >= index){ + QString strippedName; + strippedName = programName.mid(index+1); + QPROCESS_DEBUG_PRINT("qt_create_symbian_process() Process '%s' not found, try stripped version '%s'", qPrintable(programName), qPrintable(strippedName)); + + TPtrC stripped_ptr(reinterpret_cast<const TText*>(strippedName.constData())); + err = newProc->Create(stripped_ptr, cmdline_ptr); + + if (err != KErrNone) { + QPROCESS_DEBUG_PRINT("qt_create_symbian_process() Unable to create process '%s': %d", qPrintable(strippedName), err); + } + } + } + + if (err == KErrNone) { + *proc = newProc; + } else { + delete newProc; + } + + return err; +} + +static qint64 qt_native_read(int fd, char *data, qint64 maxlen) +{ + qint64 ret = 0; + do { + ret = ::read(fd, data, maxlen); + } while (ret == -1 && errno == EINTR); + + QPROCESS_DEBUG_PRINT("qt_native_read(): fd: %d, result: %d, errno = %d", fd, (int)ret, errno); + + return ret; +} + +static qint64 qt_native_write(int fd, const char *data, qint64 len) +{ + qint64 ret = 0; + do { + ret = ::write(fd, data, len); + } while (ret == -1 && errno == EINTR); + + QPROCESS_DEBUG_PRINT("qt_native_write(): fd: %d, result: %d, errno = %d", fd, (int)ret, errno); + + return ret; +} + +static void qt_native_close(int fd) +{ + int ret; + do { + ret = ::close(fd); + } while (ret == -1 && errno == EINTR); +} + +static void qt_create_pipe(int *pipe) +{ + if (pipe[0] != -1) + qt_native_close(pipe[0]); + if (pipe[1] != -1) + qt_native_close(pipe[1]); + if (::pipe(pipe) != 0) { + qWarning("QProcessPrivate::createPipe: Cannot create pipe %p: %s", + pipe, qPrintable(qt_error_string(errno))); + } else { + QPROCESS_DEBUG_PRINT("qt_create_pipe(): Created pipe %d - %d", pipe[0], pipe[1]); + } +} + +// Called from ProcessManagerThread +CProcessActive* CProcessActive::construct(QProcess* process, + RProcess** proc, + int serial, + int deathPipe) +{ + QPROCESS_ASSERT((process || proc || *proc), + EProcessActiveNullParameter, + "CProcessActive::construct(): process (0x%x), proc (0x%x) or *proc == NULL, not creating an instance", process, proc) + + CProcessActive* newInstance = new CProcessActive(); + + if (!newInstance) { + QPROCESS_DEBUG_PRINT("CProcessActive::construct(): Failed to create new instance"); + } else { + newInstance->process = process; + newInstance->pproc = proc; + newInstance->serial = serial; + newInstance->deathPipe = deathPipe; + newInstance->errorValue = false; + } + + return newInstance; +} + +// Called from ProcessManagerThread +CProcessActive::CProcessActive() + : CActive(CActive::EPriorityStandard) +{ + // Nothing to do +} + +// Called from ProcessManagerThread +CProcessActive::~CProcessActive() +{ + process = NULL; + pproc = NULL; +} + +// Called from ProcessManagerThread +void CProcessActive::start() +{ + if (qt_rprocess_running(*pproc)) { + CActiveScheduler::Add(this); + (*pproc)->Logon(iStatus); + SetActive(); + QPROCESS_DEBUG_PRINT("CProcessActive::start(): Started monitoring for process exit."); + } else { + QPROCESS_DEBUG_PRINT("CProcessActive::start(): Process doesn't exist or is already dead"); + // Assume process has already died + qt_native_write(deathPipe, "", 1); + errorValue = true; + } +} + +// Called from ProcessManagerThread +void CProcessActive::stop() +{ + QPROCESS_DEBUG_PRINT("CProcessActive::stop()"); + + // Remove this from scheduler (also cancels the request) + Deque(); +} + +bool CProcessActive::error() +{ + return errorValue; +} + +// Called from ProcessManagerThread +void CProcessActive::RunL() +{ + // If this method gets executed, the monitored process has died + + // Notify main thread + qt_native_write(deathPipe, "", 1); + QPROCESS_DEBUG_PRINT("CProcessActive::RunL() sending death notice to %d", deathPipe); +} + +// Called from ProcessManagerThread +TInt CProcessActive::RunError(TInt aError) +{ + Q_UNUSED(aError); + // Handle RunL leave (should never happen) + QPROCESS_ASSERT(0, EProcessActiveRunError, "CProcessActive::RunError(): Should never get here!") + return 0; +} + +// Called from ProcessManagerThread +void CProcessActive::DoCancel() +{ + QPROCESS_DEBUG_PRINT("CProcessActive::DoCancel()"); + + if (qt_rprocess_running(*pproc)) { + (*pproc)->LogonCancel(iStatus); + QPROCESS_DEBUG_PRINT("CProcessActive::DoCancel(): Stopped monitoring for process exit."); + } else { + QPROCESS_DEBUG_PRINT("CProcessActive::DoCancel(): Process doesn't exist"); + } +} + + +// Called from ProcessManagerThread +CProcessManagerMediator* CProcessManagerMediator::construct() +{ + CProcessManagerMediator* newInstance = new CProcessManagerMediator; + TInt err(KErrNone); + + newInstance->currentCommand = ENoCommand; + newInstance->currentObserver = NULL; + + if (newInstance) { + err = newInstance->processManagerThread.Open(newInstance->processManagerThread.Id()); + QPROCESS_ASSERT((err == KErrNone), + EProcessManagerMediatorThreadOpenFailed, + "CProcessManagerMediator::construct(): Failed to open processManagerThread (err:%d)", err) + } else { + QPROCESS_ASSERT(0, + EProcessManagerMediatorCreationFailed, + "CProcessManagerMediator::construct(): Failed to open construct mediator") + } + + // Activate mediator + CActiveScheduler::Add(newInstance); + newInstance->iStatus = KRequestPending; + newInstance->SetActive(); + QPROCESS_DEBUG_PRINT("CProcessManagerMediator::construct(): new instance successfully created and activated"); + + return newInstance; +} + +// Called from ProcessManagerThread +CProcessManagerMediator::CProcessManagerMediator() + : CActive(CActive::EPriorityStandard) +{ + // Nothing to do +} + +// Called from ProcessManagerThread +CProcessManagerMediator::~CProcessManagerMediator() +{ + processManagerThread.Close(); + currentCommand = ENoCommand; + currentObserver = NULL; +} + +// Called from main thread +bool CProcessManagerMediator::add(CProcessActive* processObserver) +{ + QPROCESS_DEBUG_PRINT("CProcessManagerMediator::add()"); + return notify(processObserver, EAdd); +} + +// Called from main thread +void CProcessManagerMediator::remove(CProcessActive* processObserver) +{ + QPROCESS_DEBUG_PRINT("CProcessManagerMediator::remove()"); + notify(processObserver, ERemove); +} + +// Called from main thread +void CProcessManagerMediator::terminate() +{ + QPROCESS_DEBUG_PRINT("CProcessManagerMediator::terminate()"); + notify(NULL, ETerminate); +} + +// Called from main thread +bool CProcessManagerMediator::notify(CProcessActive* processObserver, Commands command) +{ + bool success(true); + + QPROCESS_DEBUG_PRINT("CProcessManagerMediator::Notify(): Command: %d, processObserver: 0x%x", command, processObserver); + + QPROCESS_ASSERT((command == ETerminate || processObserver), + EProcessManagerMediatorNullObserver, + "CProcessManagerMediator::Notify(): NULL processObserver not allowed for command: %d", command) + + QPROCESS_ASSERT(IsActive(), + EProcessManagerMediatorInactive, + "CProcessManagerMediator::Notify(): Mediator is not active!") + + QPROCESS_ASSERT(iStatus==KRequestPending, + EProcessManagerMediatorNotPending, + "CProcessManagerMediator::Notify(): Mediator request not pending!") + + currentObserver = processObserver; + currentCommand = command; + + // Sync with process manager thread + TRequestStatus pmStatus; + processManagerThread.Rendezvous(pmStatus); + + // Complete request -> RunL will run in the process manager thread + TRequestStatus* status = &iStatus; + processManagerThread.RequestComplete(status, command); + + QPROCESS_DEBUG_PRINT("CProcessManagerMediator::Notify(): Waiting process manager to complete..."); + User::WaitForRequest(pmStatus); + QPROCESS_DEBUG_PRINT("CProcessManagerMediator::Notify(): Wait over"); + + if (currentObserver) { + success = !(currentObserver->error()); + QPROCESS_DEBUG_PRINT("CProcessManagerMediator::Notify(): success = %d", success); + } + + currentObserver = NULL; + currentCommand = ENoCommand; + + return success; +} + +// Called from ProcessManagerThread +void CProcessManagerMediator::RunL() +{ + QPROCESS_DEBUG_PRINT("CProcessManagerMediator::RunL(): currentCommand: %d, iStatus: %d", currentCommand, iStatus.Int()); + switch (currentCommand) { + case EAdd: + currentObserver->start(); + break; + case ERemove: + currentObserver->stop(); + break; + case ETerminate: + Deque(); + CActiveScheduler::Stop(); + return; + default: + QPROCESS_ASSERT(0, + EProcessManagerMediatorInvalidCmd, + "CProcessManagerMediator::RunL(): Invalid command!") + break; + } + + iStatus = KRequestPending; + SetActive(); + + // Notify main thread that we are done + RThread::Rendezvous(KErrNone); +} + +// Called from ProcessManagerThread +TInt CProcessManagerMediator::RunError(TInt aError) +{ + Q_UNUSED(aError); + // Handle RunL leave (should never happen) + QPROCESS_ASSERT(0, + EProcessManagerMediatorRunError, + "CProcessManagerMediator::RunError(): Should never get here!") + return 0; +} + +// Called from ProcessManagerThread +void CProcessManagerMediator::DoCancel() +{ + QPROCESS_DEBUG_PRINT("CProcessManagerMediator::DoCancel()"); + TRequestStatus* status = &iStatus; + processManagerThread.RequestComplete(status, KErrCancel); +} + +Q_GLOBAL_STATIC(QProcessManager, processManager) + +TInt processManagerThreadFunction(TAny* param) +{ + QPROCESS_ASSERT(param, + EProcessManagerNullParam, + "processManagerThreadFunction(): NULL param") + + QProcessManager* manager = reinterpret_cast<QProcessManager*>(param); + + CActiveScheduler* scheduler = new CActiveScheduler(); + + QPROCESS_ASSERT(scheduler, + EProcessManagerSchedulerCreationFail, + "processManagerThreadFunction(): Scheduler creation failed") + + CActiveScheduler::Install(scheduler); + + //Creating mediator also adds it to scheduler and activates it. Failure will panic. + manager->setMediator(CProcessManagerMediator::construct()); + RThread::Rendezvous(KErrNone); + + CActiveScheduler::Start(); + + CActiveScheduler::Install(NULL); + delete scheduler; + + return KErrNone; +} + +QProcessManager::QProcessManager() + : mediator(NULL), threadStarted(false) +{ + TInt err = managerMutex.CreateLocal(); + + QPROCESS_ASSERT(err == KErrNone, + EProcessManagerMutexCreationFail, + "QProcessManager::QProcessManager(): Failed to create new managerMutex (err: %d)", err) +} + +QProcessManager::~QProcessManager() +{ + QPROCESS_DEBUG_PRINT("QProcessManager::~QProcessManager()"); + // Cancel death listening for all child processes + if (mediator) { + QMap<int, CProcessActive *>::Iterator it = children.begin(); + while (it != children.end()) { + // Remove all monitors + CProcessActive *active = it.value(); + mediator->remove(active); + + QPROCESS_DEBUG_PRINT("QProcessManager::~QProcessManager() removed listening for a process"); + ++it; + } + + // Terminate process manager thread. + mediator->terminate(); + delete mediator; + } + + qDeleteAll(children.values()); + children.clear(); + managerThread.Close(); + managerMutex.Close(); +} + +void QProcessManager::startThread() +{ + lock(); + + if (!threadStarted) { + TInt err = managerThread.Create(KQProcessManagerThreadName, + processManagerThreadFunction, + 0x5000, + (RAllocator*)NULL, + (TAny*)this, + EOwnerProcess); + + QPROCESS_ASSERT(err == KErrNone, + EProcessManagerThreadCreationFail, + "QProcessManager::startThread(): Failed to create new managerThread (err:%d)", err) + + threadStarted = true; + + // Manager thread must start running before we continue, so sync with rendezvous + TRequestStatus status; + managerThread.Rendezvous(status); + managerThread.Resume(); + User::WaitForRequest(status); + } + + unlock(); +} + +static QBasicAtomicInt idCounter = Q_BASIC_ATOMIC_INITIALIZER(1); + +bool QProcessManager::add(QProcess *process) +{ + QPROCESS_ASSERT(process, + EProcessManagerNullParam, + "QProcessManager::add(): Failed to add CProcessActive to ProcessManager - NULL process") + + lock(); + + int serial = idCounter.fetchAndAddRelaxed(1); + process->d_func()->serial = serial; + + QPROCESS_DEBUG_PRINT("QProcessManager::add(): serial: %d, deathPipe: %d - %d, symbianProcess: 0x%x", serial, process->d_func()->deathPipe[0], process->d_func()->deathPipe[1], process->d_func()->symbianProcess); + + CProcessActive* newActive = + CProcessActive::construct(process, + &(process->d_func()->symbianProcess), + serial, + process->d_func()->deathPipe[1]); + + if (newActive){ + if (mediator->add(newActive)) { + children.insert(serial, newActive); + unlock(); + return true; + } else { + QPROCESS_DEBUG_PRINT("QProcessManager::add(): Failed to add CProcessActive to ProcessManager"); + delete newActive; + } + } + + unlock(); + + return false; +} + +void QProcessManager::remove(QProcess *process) +{ + QPROCESS_ASSERT(process, + EProcessManagerNullParam, + "QProcessManager::remove(): Failed to remove CProcessActive from ProcessManager - NULL process") + + lock(); + + int serial = process->d_func()->serial; + CProcessActive *active = children.value(serial); + if (!active) { + unlock(); + return; + } + + mediator->remove(active); + + children.remove(serial); + delete active; + + unlock(); +} + +void QProcessPrivate::destroyPipe(int *pipe) +{ + if (pipe[1] != -1) { + qt_native_close(pipe[1]); + pipe[1] = -1; + } + if (pipe[0] != -1) { + qt_native_close(pipe[0]); + pipe[0] = -1; + } +} + +bool QProcessPrivate::createChannel(Channel &channel) +{ + Q_UNUSED(channel); + // No channels used + return false; +} + +void QProcessPrivate::startProcess() +{ + Q_Q(QProcess); + + QPROCESS_DEBUG_PRINT("QProcessPrivate::startProcess()"); + + // Start the process (platform dependent) + q->setProcessState(QProcess::Starting); + + processManager()->startThread(); + + qt_create_pipe(deathPipe); + if (threadData->eventDispatcher) { + deathNotifier = new QSocketNotifier(deathPipe[0], + QSocketNotifier::Read, q); + QObject::connect(deathNotifier, SIGNAL(activated(int)), + q, SLOT(_q_processDied())); + } + + TInt err = qt_create_symbian_process(&symbianProcess, program, arguments); + + if (err == KErrNone) { + pid = symbianProcess->Id(); + + ::fcntl(deathPipe[0], F_SETFL, ::fcntl(deathPipe[0], F_GETFL) | O_NONBLOCK); + + if (!processManager()->add(q)) { + qWarning("QProcessPrivate::startProcess(): Failed to start monitoring for process death."); + err = KErrNoMemory; + } + } + + if (err != KErrNone) { + // Cleanup, report error and return + QPROCESS_DEBUG_PRINT("QProcessPrivate::startProcess() Process open failed, err: %d, '%s'", err, qPrintable(program)); + q->setProcessState(QProcess::NotRunning); + processError = QProcess::FailedToStart; + q->setErrorString(QLatin1String(QT_TRANSLATE_NOOP(QProcess, "Resource error (qt_create_symbian_process failure)"))); + emit q->error(processError); + cleanup(); + return; + } + + processLaunched = true; + + symbianProcess->Resume(); + + QPROCESS_DEBUG_PRINT("QProcessPrivate::startProcess(): this: 0x%x, pid: %d", this, (TUint)pid); + + // Notify child start + _q_startupNotification(); + +} + +bool QProcessPrivate::processStarted() +{ + QPROCESS_DEBUG_PRINT("QProcessPrivate::processStarted() == %s", processLaunched ? "true" : "false"); + + // Since we cannot get information whether process has actually been launched + // or not in Symbian, we need to fake it. Assume process is started if launch was + // successful. + + return processLaunched; +} + +qint64 QProcessPrivate::bytesAvailableFromStdout() const +{ + // In Symbian, zero bytes are always available + return 0; +} + +qint64 QProcessPrivate::bytesAvailableFromStderr() const +{ + // In Symbian, zero bytes are always available + return 0; +} + +qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen) +{ + Q_UNUSED(data); + Q_UNUSED(maxlen); + // In Symbian, zero bytes are always read + return 0; +} + +qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen) +{ + Q_UNUSED(data); + Q_UNUSED(maxlen); + // In Symbian, zero bytes are always read + return 0; +} + +qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen) +{ + Q_UNUSED(data); + Q_UNUSED(maxlen); + // In Symbian, zero bytes are always written + return 0; +} + +void QProcessPrivate::terminateProcess() +{ + // Not allowed by platform security - will panic kern-exec 46 if process has been started. + // Works if process is not yet started. + if (qt_rprocess_running(symbianProcess)) { + symbianProcess->Terminate(0); + } else { + QPROCESS_DEBUG_PRINT("QProcessPrivate::terminateProcess(), Process not running"); + } +} + +void QProcessPrivate::killProcess() +{ + // Not allowed by platform security - will panic kern-exec 46 if process has been started. + // Works if process is not yet started. + if (qt_rprocess_running(symbianProcess)) { + symbianProcess->Kill(0); + } else { + QPROCESS_DEBUG_PRINT("QProcessPrivate::killProcess(), Process not running"); + } +} + +bool QProcessPrivate::waitForStarted(int msecs) +{ + Q_UNUSED(msecs); + // Since we can get no actual feedback from process beyond its death, + // assume that started has already been emitted if process has been launched + return processLaunched; +} + +bool QProcessPrivate::waitForReadyRead(int msecs) +{ + // Functionality not supported in Symbian + Q_UNUSED(msecs); + return false; +} + +bool QProcessPrivate::waitForBytesWritten(int msecs) +{ + // Functionality not supported in Symbian + Q_UNUSED(msecs); + return false; +} + +bool QProcessPrivate::waitForFinished(int msecs) +{ + Q_Q(QProcess); + QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForFinished(%d)", msecs); + + TRequestStatus timerStatus = 0; + TRequestStatus logonStatus = 0; + bool timeoutOccurred = false; + + // Logon to process to observe its death + if (qt_rprocess_running(symbianProcess)) { + symbianProcess->Logon(logonStatus); + + // Create timer + RTimer timer; + timer.CreateLocal(); + TTimeIntervalMicroSeconds32 interval(msecs*1000); + timer.After(timerStatus, interval); + + QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForFinished() - Waiting..."); + User::WaitForRequest(logonStatus, timerStatus); + QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForFinished() - Wait completed"); + + if (timerStatus == KErrNone) { + timeoutOccurred = true; + } + + timer.Cancel(); + timer.Close(); + + symbianProcess->LogonCancel(logonStatus); + + // Eat cancel request completion so that it won't mess up main thread scheduling later + User::WaitForRequest(logonStatus, timerStatus); + } else { + QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForFinished(), qt_rprocess_running returned false"); + } + + if (timeoutOccurred) { + processError = QProcess::Timedout; + q->setErrorString(QLatin1String(QT_TRANSLATE_NOOP(QProcess, "Process operation timed out"))); + return false; + } + + _q_processDied(); + + return true; +} + +bool QProcessPrivate::waitForWrite(int msecs) +{ + // Functionality not supported in Symbian + Q_UNUSED(msecs); + return false; +} + +// Deceptively named function. Exit code is actually got in waitForDeadChild(). +void QProcessPrivate::findExitCode() +{ + Q_Q(QProcess); + processManager()->remove(q); +} + +bool QProcessPrivate::waitForDeadChild() +{ + Q_Q(QProcess); + + // read a byte from the death pipe + char c; + qt_native_read(deathPipe[0], &c, 1); + + if (symbianProcess && symbianProcess->Handle()) { + TExitType et = symbianProcess->ExitType(); + QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForDeadChild() symbianProcess->ExitType: %d", et); + if (et != EExitPending) { + processManager()->remove(q); + exitCode = symbianProcess->ExitReason(); + crashed = (et == EExitPanic); +#if defined QPROCESS_DEBUG + TExitCategoryName catName = symbianProcess->ExitCategory(); + qDebug() << "QProcessPrivate::waitForDeadChild() dead with exitCode" + << exitCode << ", crashed:" << crashed + << ", category:" << QString::fromUtf16(catName.Ptr()); +#endif + } else { + QPROCESS_DEBUG_PRINT("QProcessPrivate::waitForDeadChild() not dead!"); + } + } + + return true; +} + +void QProcessPrivate::_q_notified() +{ + // Nothing to do in Symbian +} + +/*! \internal + */ +bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid) +{ + QPROCESS_DEBUG_PRINT("QProcessPrivate::startDetached()"); + Q_UNUSED(workingDirectory); + + RProcess* newProc = NULL; + + TInt err = qt_create_symbian_process(&newProc, program, arguments); + + if (err == KErrNone) { + if (pid) { + *pid = (qint64)newProc->Id(); + } + + newProc->Resume(); + newProc->Close(); + return true; + } + + return false; +} + + +void QProcessPrivate::initializeProcessManager() +{ + (void) processManager(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_PROCESS diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index b4d8a48..45a03e3 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -512,6 +512,10 @@ QTemporaryFile::QTemporaryFile() { Q_D(QTemporaryFile); d->templateName = QDir::tempPath() + QLatin1String("/qt_temp.XXXXXX"); +#ifdef Q_OS_SYMBIAN + //Just for verify that folder really exist on hardware + fileEngine()->mkdir( QDir::tempPath(), true ); +#endif } /*! diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index d90ecae..9458946 100644 --- a/src/corelib/kernel/kernel.pri +++ b/src/corelib/kernel/kernel.pri @@ -87,9 +87,7 @@ mac { unix { SOURCES += \ - kernel/qcrashhandler.cpp \ - kernel/qsharedmemory_unix.cpp \ - kernel/qsystemsemaphore_unix.cpp + kernel/qcrashhandler.cpp HEADERS += \ kernel/qcrashhandler_p.h @@ -101,10 +99,24 @@ unix { QMAKE_CXXFLAGS += $$QT_CFLAGS_GLIB LIBS +=$$QT_LIBS_GLIB } + + symbian { + SOURCES += \ + kernel/qeventdispatcher_symbian.cpp \ + kernel/qcore_symbian_p.cpp \ + kernel/qsharedmemory_symbian.cpp \ + kernel/qsystemsemaphore_symbian.cpp + HEADERS += \ + kernel/qeventdispatcher_symbian_p.h \ + kernel/qcore_symbian_p.h + } else { SOURCES += \ - kernel/qeventdispatcher_unix.cpp + kernel/qeventdispatcher_unix.cpp \ + kernel/qsharedmemory_unix.cpp \ + kernel/qsystemsemaphore_unix.cpp HEADERS += \ kernel/qeventdispatcher_unix_p.h + } contains(QT_CONFIG, clock-gettime):include($$QT_SOURCE_TREE/config.tests/unix/clock-gettime/clock-gettime.pri) } diff --git a/src/corelib/kernel/qcore_symbian_p.cpp b/src/corelib/kernel/qcore_symbian_p.cpp new file mode 100644 index 0000000..4f18490 --- /dev/null +++ b/src/corelib/kernel/qcore_symbian_p.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <e32base.h> +#include <e32uid.h> +#include "qcore_symbian_p.h" + +QT_BEGIN_NAMESPACE + +/* + Helper function for calling into Symbian classes that expect a TDes&. + This function converts a QString to a TDes by allocating memory that + must be deleted by the caller. +*/ + +Q_CORE_EXPORT HBufC* qt_QString2HBufCNewL(const QString& aString) +{ + HBufC *buffer; +#ifdef QT_NO_UNICODE + TPtrC8 ptr(reinterpret_cast<const TUint8*>(aString.toLocal8Bit().constData())); + buffer = HBufC8::NewL(ptr.Length()); + buffer->Des().Copy(ptr); +#else + TPtrC16 ptr(reinterpret_cast<const TUint16*>(aString.utf16())); + buffer = HBufC16::NewL(ptr.Length()); + buffer->Des().Copy(ptr); +#endif + return buffer; +} + +Q_CORE_EXPORT QString qt_TDesC2QStringL(const TDesC& aDescriptor) +{ +#ifdef QT_NO_UNICODE + return QString::fromLocal8Bit(aDescriptor.Ptr(), aDescriptor.Length()); +#else + return QString::fromUtf16(aDescriptor.Ptr(), aDescriptor.Length()); +#endif +} + +QHBufC::QHBufC() + : m_hBufC(0) +{ +} + +QHBufC::QHBufC(const QHBufC &src) +{ + m_hBufC = src.m_hBufC->AllocL(); +} + +/*! + \internal + Constructs a QHBufC from an HBufC. Note that the QHBufC instance takes + ownership of the HBufC. +*/ +QHBufC::QHBufC(HBufC *src) + : m_hBufC(src) +{ +} + +QHBufC::QHBufC(const QString &src) +{ + m_hBufC = qt_QString2HBufCNewL(src); +} + +QHBufC::~QHBufC() +{ + if (m_hBufC) + delete m_hBufC; +} + +class QS60PluginResolver +{ +public: + QS60PluginResolver() + : initTried(false) {} + + ~QS60PluginResolver() { + lib.Close(); + } + + TLibraryFunction resolve(int ordinal) { + if (!initTried) { + init(); + initTried = true; + } + + if (lib.Handle()) + return lib.Lookup(ordinal); + else + return reinterpret_cast<TLibraryFunction>(NULL); + } + +private: + void init() { + _LIT(KLibName_3_1, "qts60plugin_3_1.dll"); + _LIT(KLibName_3_2, "qts60plugin_3_2.dll"); + _LIT(KLibName_5_0, "qts60plugin_5_0.dll"); + TPtrC libName; + TInt uidValue; + switch (QSysInfo::s60Version()) { + case QSysInfo::SV_S60_3_1: + libName.Set(KLibName_3_1); + uidValue = 0x2001E620; + break; + case QSysInfo::SV_S60_3_2: + libName.Set(KLibName_3_2); + uidValue = 0x2001E621; + break; + case QSysInfo::SV_S60_5_0: // Fall through to default + default: + // Default to 5.0 version, as any unknown platform is likely to be newer than that + libName.Set(KLibName_5_0); + uidValue = 0x2001E622; + break; + } + + TUidType libUid(KDynamicLibraryUid, KSharedLibraryUid, TUid::Uid(uidValue)); + lib.Load(libName, libUid); + } + + RLibrary lib; + bool initTried; +}; + +Q_GLOBAL_STATIC(QS60PluginResolver, qt_s60_plugin_resolver); + +/*! + \internal + Resolves a platform version specific function from S60 plugin. + If plugin is missing or resolving fails for another reason, NULL is returned. +*/ +Q_CORE_EXPORT TLibraryFunction qt_resolveS60PluginFunc(int ordinal) +{ + return qt_s60_plugin_resolver()->resolve(ordinal); +} + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcore_symbian_p.h b/src/corelib/kernel/qcore_symbian_p.h new file mode 100644 index 0000000..3b974c3 --- /dev/null +++ b/src/corelib/kernel/qcore_symbian_p.h @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCORE_SYMBIAN_P_H +#define QCORE_SYMBIAN_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <e32std.h> +#include <QtCore/qglobal.h> +#include <qstring.h> +#include <qrect.h> +#include <qhash.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +Q_CORE_EXPORT HBufC* qt_QString2HBufCNewL(const QString& aString); + +Q_CORE_EXPORT QString qt_TDesC2QStringL(const TDesC& aDescriptor); +inline QString qt_TDes2QStringL(const TDes& aDescriptor) { return qt_TDesC2QStringL(aDescriptor); } + +static inline QSize qt_TSize2QSize(const TSize& ts) +{ + return QSize(ts.iWidth, ts.iHeight); +} + +static inline TSize qt_QSize2TSize(const QSize& qs) +{ + return TSize(qs.width(), qs.height()); +} + +static inline QRect qt_TRect2QRect(const TRect& tr) +{ + return QRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height()); +} + +static inline TRect qt_QRect2TRect(const QRect& qr) +{ + return TRect(TPoint(qr.left(), qr.top()), TSize(qr.width(), qr.height())); +} + +// Returned TPtrC is valid as long as the given parameter is valid and unmodified +static inline TPtrC qt_QString2TPtrC( const QString& string ) +{ + return reinterpret_cast<const TUint16*>(string.utf16()); +} + +class Q_CORE_EXPORT QHBufC +{ +public: + QHBufC(); + QHBufC(const QHBufC &src); + QHBufC(HBufC *src); + QHBufC(const QString &src); + ~QHBufC(); + + inline operator HBufC *() { return m_hBufC; } + inline operator const HBufC *() const { return m_hBufC; } + inline HBufC *data() { return m_hBufC; } + inline const HBufC *data() const { return m_hBufC; } + inline HBufC & operator*() { return *m_hBufC; } + inline const HBufC & operator*() const { return *m_hBufC; } + inline HBufC * operator->() { return m_hBufC; } + inline const HBufC * operator->() const { return m_hBufC; } + + inline bool operator==(const QHBufC ¶m) const { return data() == param.data(); } + inline bool operator!=(const QHBufC ¶m) const { return data() != param.data(); } + +private: + HBufC *m_hBufC; +}; + +inline uint qHash(TUid uid) +{ + return qHash(uid.iUid); +} + +// S60 version specific function ordinals that can be resolved +enum S60PluginFuncOrdinals +{ + S60Plugin_TimeFormatL = 1, + S60Plugin_GetTimeFormatSpec = 2, + S60Plugin_GetLongDateFormatSpec = 3, + S60Plugin_GetShortDateFormatSpec = 4, + S60Plugin_LocalizedDirectoryName = 5 +}; + +Q_CORE_EXPORT TLibraryFunction qt_resolveS60PluginFunc(int ordinal); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif //QCORE_SYMBIAN_P_H diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index f6ce4b3..d99164b 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -62,7 +62,10 @@ #include <qlibraryinfo.h> #include <private/qfactoryloader_p.h> -#ifdef Q_OS_UNIX +#ifdef Q_OS_SYMBIAN +# include <f32file.h> +# include "qeventdispatcher_symbian_p.h" +#elif defined(Q_OS_UNIX) # if !defined(QT_NO_GLIB) # include "qeventdispatcher_glib_p.h" # endif @@ -268,7 +271,9 @@ QCoreApplicationPrivate::~QCoreApplicationPrivate() void QCoreApplicationPrivate::createEventDispatcher() { Q_Q(QCoreApplication); -#if defined(Q_OS_UNIX) +#if defined(Q_OS_SYMBIAN) + eventDispatcher = new QEventDispatcherSymbian(q); +#elif defined(Q_OS_UNIX) # if !defined(QT_NO_GLIB) if (qgetenv("QT_NO_GLIB").isEmpty() && QEventDispatcherGlib::versionSupported()) eventDispatcher = new QEventDispatcherGlib(q); @@ -306,6 +311,11 @@ void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver) Q_UNUSED(currentThread); Q_UNUSED(thr); } +#elif defined(Q_OS_SYMBIAN) && defined (QT_NO_DEBUG) +// no implementation in release builds, but keep the symbol present +void QCoreApplicationPrivate::checkReceiverThread(QObject *receiver) +{ +} #endif void QCoreApplicationPrivate::appendApplicationPathToLibraryPaths() @@ -313,10 +323,17 @@ void QCoreApplicationPrivate::appendApplicationPathToLibraryPaths() #if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) QStringList *app_libpaths = coreappdata()->app_libpaths; Q_ASSERT(app_libpaths); +# if defined(Q_OS_SYMBIAN) + QString app_location( QCoreApplication::applicationDirPath() ); + // File existence check for application's private dir requires additional '\' or + // platform security will not allow it. + if (app_location != QLibraryInfo::location(QLibraryInfo::PluginsPath) && QFile::exists(app_location + QLatin1Char('\\')) && !app_libpaths->contains(app_location)) +# else QString app_location( QCoreApplication::applicationFilePath() ); app_location.truncate(app_location.lastIndexOf(QLatin1Char('/'))); app_location = QDir(app_location).canonicalPath(); if (app_location != QLibraryInfo::location(QLibraryInfo::PluginsPath) && QFile::exists(app_location) && !app_libpaths->contains(app_location)) +# endif app_libpaths->append(app_location); #endif } @@ -444,6 +461,13 @@ QCoreApplication::QCoreApplication(int &argc, char **argv) { init(); QCoreApplicationPrivate::eventDispatcher->startingUp(); +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) && defined(Q_OS_SYMBIAN) + // Refresh factoryloader, as text codecs are requested during lib path + // resolving process and won't be therefore properly loaded. + // Unknown if this is symbian specific issue. + QFactoryLoader::refreshAll(); +#endif + } extern void set_winapp_name(); @@ -602,7 +626,16 @@ bool QCoreApplication::notifyInternal(QObject *receiver, QEvent *event) d->inEventHandler = true; #endif -#if defined(QT_NO_EXCEPTIONS) +#if defined(Q_OS_SYMBIAN) +// __UHEAP_MARK; + TInt error; + bool returnValue = false; + TRAP(error, returnValue = notify(receiver, event)); + if (error != KErrNone) { + qWarning(QString("Symbian OS error: %1").arg(error).toAscii().constData()); + } +// __UHEAP_MARKEND; +#elif defined(QT_NO_EXCEPTIONS) bool returnValue = notify(receiver, event); #else bool returnValue; @@ -941,7 +974,7 @@ void QCoreApplication::exit(int returnCode) The event is \e not deleted when the event has been sent. The normal approach is to create the event on the stack, for example: - \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 0 + \snippet doc/src/snippets/code/src.corelib.kernel.qcoreapplication.cpp 0 \sa postEvent(), notify() */ @@ -1458,7 +1491,7 @@ bool QCoreApplication::event(QEvent *e) Example: - \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 1 + \snippet doc/src/snippets/code/src.corelib.kernel.qcoreapplication.cpp 1 \sa exit(), aboutToQuit(), QApplication::lastWindowClosed() */ @@ -1686,6 +1719,10 @@ bool QCoreApplicationPrivate::isTranslatorInstalled(QTranslator *translator) function also assumes that the current directory has not been changed by the application. + In Symbian this function will return the application private directory + in C-drive, not the path to executable itself, as those are always in + /sys/bin. + \sa applicationFilePath() */ QString QCoreApplication::applicationDirPath() @@ -1697,7 +1734,32 @@ QString QCoreApplication::applicationDirPath() QCoreApplicationPrivate *d = self->d_func(); if (d->cachedApplicationDirPath.isNull()) +#if defined(Q_OS_SYMBIAN) + { + QString appPath; + RProcess proc; + TInt err = proc.Open(proc.Id()); + if (err == KErrNone) { +#if defined(Q_CC_NOKIAX86) + // In emulator, always resolve the private dir on C-drive + appPath.append(QChar('C')); +#else + appPath.append(QChar((proc.FileName())[0])); +#endif + appPath.append(QLatin1String(":\\private\\")); + QString sid; + sid.setNum(proc.SecureId().iId, 16); + appPath.append(sid); + appPath.append(QLatin1Char('\\')); + proc.Close(); + } + + QFileInfo fi(appPath); + d->cachedApplicationDirPath = fi.exists() ? fi.canonicalFilePath() : QString(); + } +#else d->cachedApplicationDirPath = QFileInfo(applicationFilePath()).path(); +#endif return d->cachedApplicationDirPath; } @@ -1751,7 +1813,20 @@ QString QCoreApplication::applicationFilePath() return d->cachedApplicationFilePath; } #endif -#if defined( Q_OS_UNIX ) +#if defined(Q_OS_SYMBIAN) + QString appPath; + RProcess proc; + TInt err = proc.Open(proc.Id()); + if (err == KErrNone) { + TFileName procName = proc.FileName(); + appPath.append(QString(reinterpret_cast<const QChar*>(procName.Ptr()), procName.Length())); + proc.Close(); + } + + d->cachedApplicationFilePath = appPath; + return d->cachedApplicationFilePath; + +#elif defined( Q_OS_UNIX ) # ifdef Q_OS_LINUX // Try looking for a /proc/<pid>/exe symlink first which points to // the absolute path of the executable @@ -2043,7 +2118,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(QMutex, libraryPathMutex, (QMutex::Recursive)) If you want to iterate over the list, you can use the \l foreach pseudo-keyword: - \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 2 + \snippet doc/src/snippets/code/src.corelib.kernel.qcoreapplication.cpp 2 \sa setLibraryPaths(), addLibraryPath(), removeLibraryPath(), QLibrary, {How to Create Qt Plugins} @@ -2054,12 +2129,37 @@ QStringList QCoreApplication::libraryPaths() if (!coreappdata()->app_libpaths) { QStringList *app_libpaths = coreappdata()->app_libpaths = new QStringList; QString installPathPlugins = QLibraryInfo::location(QLibraryInfo::PluginsPath); +#if defined(Q_OS_SYMBIAN) + // Add existing path on all drives for relative PluginsPath in Symbian + if (installPathPlugins.at(1) != QChar(':')) { + QString tempPath = installPathPlugins; + if (tempPath.at(tempPath.length()-1) != QChar('\\')) { + tempPath += QChar('\\'); + } + RFs fs; + TInt err = fs.Connect(); + if (err == KErrNone) { + TPtrC tempPathPtr(reinterpret_cast<const TText*>(tempPath.constData())); + TFindFile finder(fs); + err = finder.FindByDir(tempPathPtr, tempPathPtr); + while (err == KErrNone) { + QString foundDir = QString::fromUtf16(finder.File().Ptr(), finder.File().Length()); + foundDir = QDir(foundDir).canonicalPath(); + if (!app_libpaths->contains(foundDir)) + app_libpaths->append(foundDir); + err = finder.Find(); + } + fs.Close(); + } + } +#else if (QFile::exists(installPathPlugins)) { // Make sure we convert from backslashes to slashes. installPathPlugins = QDir(installPathPlugins).canonicalPath(); if (!app_libpaths->contains(installPathPlugins)) app_libpaths->append(installPathPlugins); } +#endif // If QCoreApplication is not yet instantiated, // make sure we add the application path when we construct the QCoreApplication @@ -2067,7 +2167,7 @@ QStringList QCoreApplication::libraryPaths() const QByteArray libPathEnv = qgetenv("QT_PLUGIN_PATH"); if (!libPathEnv.isEmpty()) { -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) QLatin1Char pathSep(';'); #else QLatin1Char pathSep(':'); @@ -2169,7 +2269,7 @@ void QCoreApplication::removeLibraryPath(const QString &path) A function with the following signature that can be used as an event filter: - \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 3 + \snippet doc/src/snippets/code/src.corelib.kernel.qcoreapplication.cpp 3 \sa setEventFilter() */ @@ -2366,7 +2466,7 @@ int QCoreApplication::loopLevel() The function specified by \a ptr should take no arguments and should return nothing. For example: - \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 4 + \snippet doc/src/snippets/code/src.corelib.kernel.qcoreapplication.cpp 4 Note that for an application- or module-wide cleanup, qAddPostRoutine() is often not suitable. For example, if the @@ -2380,7 +2480,7 @@ int QCoreApplication::loopLevel() parent-child mechanism to call a cleanup function at the right time: - \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 5 + \snippet doc/src/snippets/code/src.corelib.kernel.qcoreapplication.cpp 5 By selecting the right parent object, this can often be made to clean up the module's data at the right moment. @@ -2394,7 +2494,7 @@ int QCoreApplication::loopLevel() translation functions, \c tr() and \c trUtf8(), with these signatures: - \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 6 + \snippet doc/src/snippets/code/src.corelib.kernel.qcoreapplication.cpp 6 This macro is useful if you want to use QObject::tr() or QObject::trUtf8() in classes that don't inherit from QObject. @@ -2403,7 +2503,7 @@ int QCoreApplication::loopLevel() class definition (before the first \c{public:} or \c{protected:}). For example: - \snippet doc/src/snippets/code/src_corelib_kernel_qcoreapplication.cpp 7 + \snippet doc/src/snippets/code/src.corelib.kernel.qcoreapplication.cpp 7 The \a context parameter is normally the class name, but it can be any string. diff --git a/src/corelib/kernel/qcoreapplication.h b/src/corelib/kernel/qcoreapplication.h index f7175ae..65733ac 100644 --- a/src/corelib/kernel/qcoreapplication.h +++ b/src/corelib/kernel/qcoreapplication.h @@ -165,7 +165,7 @@ public: virtual bool winEventFilter(MSG *message, long *result); #endif -#ifdef Q_OS_UNIX +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) static void watchUnixSignal(int signal, bool watch); #endif diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h index 9490ad7..c1118d1 100644 --- a/src/corelib/kernel/qcoreapplication_p.h +++ b/src/corelib/kernel/qcoreapplication_p.h @@ -92,7 +92,7 @@ public: static void sendPostedEvents(QObject *receiver, int event_type, QThreadData *data); static void removePostedEvents_unlocked(QObject *receiver, int type, QThreadData *data); -#if !defined (QT_NO_DEBUG) || defined (QT_MAC_FRAMEWORK_BUILD) +#if !defined (QT_NO_DEBUG) || defined (QT_MAC_FRAMEWORK_BUILD) || defined (Q_OS_SYMBIAN) void checkReceiverThread(QObject *receiver); #endif int &argc; diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp index 11a2d3c..e0be174 100644 --- a/src/corelib/kernel/qcoreevent.cpp +++ b/src/corelib/kernel/qcoreevent.cpp @@ -108,6 +108,7 @@ QT_BEGIN_NAMESPACE \value ApplicationLayoutDirectionChange The default application layout direction has changed. \value ApplicationPaletteChange The default application palette has changed. \value ApplicationWindowIconChange The application's icon has changed. + \value CloseSoftwareInputPanel A widget wants to close the software input panel (SIP). \value ChildAdded An object gets a child (QChildEvent). \value ChildInserted An object gets a child (QChildEvent). Qt3Support only, use ChildAdded instead. \value ChildPolished A widget child gets polished (QChildEvent). @@ -186,6 +187,7 @@ QT_BEGIN_NAMESPACE \value Polish The widget is polished. \value PolishRequest The widget should be polished. \value QueryWhatsThis The widget should accept the event if it has "What's This?" help. + \value RequestSoftwareInputPanel A widget wants to open a software input panel (SIP). \value Resize Widget's size changed (QResizeEvent). \value Shortcut Key press in child for shortcut key handling (QShortcutEvent). \value ShortcutOverride Key press in child, for overriding shortcut key handling (QKeyEvent). diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h index fa472e6..d229ac9 100644 --- a/src/corelib/kernel/qcoreevent.h +++ b/src/corelib/kernel/qcoreevent.h @@ -266,6 +266,9 @@ public: CocoaRequestModal = 190, // Internal for requesting an application modal Cocoa Window MacGLClearDrawable = 191, // Internal Cocoa, the window has changed, so we must clear + RequestSoftwareInputPanel = 192, + CloseSoftwareInputPanel = 193, + // 512 reserved for Qt Jambi's MetaCall event // 513 reserved for Qt Jambi's DeleteOnMainThread event diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp new file mode 100644 index 0000000..c5d91c2 --- /dev/null +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -0,0 +1,960 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qeventdispatcher_symbian_p.h" +#include <private/qthread_p.h> +#include <qcoreapplication.h> +#include <private/qcoreapplication_p.h> +#include <qdatetime.h> + +#include <unistd.h> +#include <errno.h> + +QT_BEGIN_NAMESPACE + +#define WAKE_UP_PRIORITY CActive::EPriorityStandard +#define TIMER_PRIORITY CActive::EPriorityLow +#define COMPLETE_DEFERRED_ACTIVE_OBJECTS_PRIORITY CActive::EPriorityIdle + +static inline int qt_pipe_write(int socket, const char *data, qint64 len) +{ + return ::write(socket, data, len); +} +#if defined(write) +# undef write +#endif + +static inline int qt_pipe_close(int socket) +{ + return ::close(socket); +} +#if defined(close) +# undef close +#endif + +static inline int qt_pipe_fcntl(int socket, int command) +{ + return ::fcntl(socket, command); +} +static inline int qt_pipe2_fcntl(int socket, int command, int option) +{ + return ::fcntl(socket, command, option); +} +#if defined(fcntl) +# undef fcntl +#endif + +static inline int qt_socket_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) +{ + return ::select(nfds, readfds, writefds, exceptfds, timeout); +} + +// This simply interrupts the select and locks the mutex until destroyed. +class QSelectMutexGrabber +{ +public: + QSelectMutexGrabber(int fd, QMutex *mutex) + : m_mutex(mutex) + { + if (m_mutex->tryLock()) + return; + + char dummy = 0; + qt_pipe_write(fd, &dummy, 1); + + m_mutex->lock(); + } + + ~QSelectMutexGrabber() + { + m_mutex->unlock(); + } + +private: + QMutex *m_mutex; +}; + +/* + * This class is designed to aid in implementing event handling in a more round robin fashion. We + * cannot change active objects that we do not own, but the active objects that Qt owns will use + * this as a base class with convenience functions. + * + * Here is how it works: On every RunL, the deriving class should call okToRun(). This will allow + * exactly one run of the active object, and mark it as such. If it is called again, it will return + * false, and add the object to a queue so it can be run later. + * + * The QCompleteDeferredAOs class is a special object that runs after all others, which will + * reactivate the objects that were previously not run. + */ +inline QActiveObject::QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher) + : CActive(priority), + m_dispatcher(dispatcher), + m_hasAlreadyRun(false), + m_hasRunAgain(false), + m_iterationCount(1) +{ +} + +QActiveObject::~QActiveObject() +{ + if (m_hasRunAgain) + m_dispatcher->removeDeferredActiveObject(this); +} + +bool QActiveObject::okToRun() +{ + Q_ASSERT(!m_hasRunAgain); + + if (!m_hasAlreadyRun || m_dispatcher->iterationCount() != m_iterationCount) { + // First occurrence of this event in this iteration. + m_hasAlreadyRun = true; + m_iterationCount = m_dispatcher->iterationCount(); + return true; + } else { + // The event has already occurred. + m_dispatcher->addDeferredActiveObject(this); + m_hasRunAgain = true; + return false; + } +} + +void QActiveObject::reactivateAndComplete() +{ + iStatus = KRequestPending; + SetActive(); + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); + + m_hasRunAgain = false; + m_hasAlreadyRun = false; +} + +QWakeUpActiveObject::QWakeUpActiveObject(QEventDispatcherSymbian *dispatcher) + : CActive(WAKE_UP_PRIORITY), + m_dispatcher(dispatcher) +{ + CActiveScheduler::Add(this); + iStatus = KRequestPending; + SetActive(); +} + +QWakeUpActiveObject::~QWakeUpActiveObject() +{ + Cancel(); +} + +void QWakeUpActiveObject::DoCancel() +{ + if (iStatus.Int() & KRequestPending) { + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); + } +} + +void QWakeUpActiveObject::RunL() +{ + iStatus = KRequestPending; + SetActive(); + m_dispatcher->wakeUpWasCalled(); +} + +QTimerActiveObject::QTimerActiveObject(QEventDispatcherSymbian *dispatcher, SymbianTimerInfo *timerInfo) + : QActiveObject(TIMER_PRIORITY, dispatcher), + m_timerInfo(timerInfo) +{ +} + +QTimerActiveObject::~QTimerActiveObject() +{ + Cancel(); +} + +void QTimerActiveObject::DoCancel() +{ + if (m_timerInfo->interval > 0) { + m_rTimer.Cancel(); + m_rTimer.Close(); + } else { + if (iStatus.Int() & KRequestPending) { + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); + } + } +} + +void QTimerActiveObject::RunL() +{ + if (!okToRun()) + return; + + if (m_timerInfo->interval > 0) { + // Start a new timer immediately so that we don't lose time. + iStatus = KRequestPending; + SetActive(); + m_rTimer.After(iStatus, m_timerInfo->interval*1000); + + m_timerInfo->dispatcher->timerFired(m_timerInfo->timerId); + } else { + // However, we only complete zero timers after the event has finished, + // in order to prevent busy looping when doing nested loops. + + // Keep the refpointer around in order to avoid deletion until the end of this function. + SymbianTimerInfoPtr timerInfoPtr(m_timerInfo); + + m_timerInfo->dispatcher->timerFired(m_timerInfo->timerId); + + iStatus = KRequestPending; + SetActive(); + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); + } +} + +void QTimerActiveObject::Start() +{ + CActiveScheduler::Add(this); + if (m_timerInfo->interval > 0) { + m_rTimer.CreateLocal(); + iStatus = KRequestPending; + SetActive(); + m_rTimer.After(iStatus, m_timerInfo->interval*1000); + } else { + iStatus = KRequestPending; + SetActive(); + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); + } +} + +SymbianTimerInfo::~SymbianTimerInfo() +{ + delete timerAO; +} + +QCompleteDeferredAOs::QCompleteDeferredAOs(QEventDispatcherSymbian *dispatcher) + : CActive(COMPLETE_DEFERRED_ACTIVE_OBJECTS_PRIORITY), + m_dispatcher(dispatcher) +{ + CActiveScheduler::Add(this); + iStatus = KRequestPending; + SetActive(); +} + +QCompleteDeferredAOs::~QCompleteDeferredAOs() +{ + Cancel(); +} + +void QCompleteDeferredAOs::complete() +{ + if (iStatus.Int() & KRequestPending) { + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); + } +} + +void QCompleteDeferredAOs::DoCancel() +{ + if (iStatus.Int() & KRequestPending) { + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); + } +} + +void QCompleteDeferredAOs::RunL() +{ + iStatus = KRequestPending; + SetActive(); + + m_dispatcher->reactivateDeferredActiveObjects(); +} + +QSelectThread::QSelectThread() + : m_quit(false) +{ + if (::pipe(m_pipeEnds) != 0) { + qWarning("Select thread was unable to open a pipe, errno: %i", errno); + } else { + int flags0 = qt_pipe_fcntl(m_pipeEnds[0], F_GETFL); + int flags1 = qt_pipe_fcntl(m_pipeEnds[1], F_GETFL); + // We should check the error code here, but Open C has a bug that returns + // failure even though the operation was successful. + qt_pipe2_fcntl(m_pipeEnds[0], F_SETFL, flags0 | O_NONBLOCK); + qt_pipe2_fcntl(m_pipeEnds[1], F_SETFL, flags1 | O_NONBLOCK); + } +} + +QSelectThread::~QSelectThread() +{ + qt_pipe_close(m_pipeEnds[1]); + qt_pipe_close(m_pipeEnds[0]); +} + +void QSelectThread::run() +{ + Q_D(QThread); + + m_mutex.lock(); + + while (!m_quit) { + fd_set readfds; + fd_set writefds; + fd_set exceptionfds; + + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptionfds); + + int maxfd = 0; + maxfd = qMax(maxfd, updateSocketSet(QSocketNotifier::Read, &readfds)); + maxfd = qMax(maxfd, updateSocketSet(QSocketNotifier::Write, &writefds)); + maxfd = qMax(maxfd, updateSocketSet(QSocketNotifier::Exception, &exceptionfds)); + maxfd = qMax(maxfd, m_pipeEnds[0]); + maxfd++; + + FD_SET(m_pipeEnds[0], &readfds); + + int ret; + int savedSelectErrno; + //do { + ret = qt_socket_select(maxfd, &readfds, &writefds, &exceptionfds, 0); + savedSelectErrno = errno; + //} while (ret == 0); + + char buffer; + + while (::read(m_pipeEnds[0], &buffer, 1) > 0) {} + + if(ret == 0) { + // do nothing + } else if (ret < 0) { + switch (savedSelectErrno) { + case EBADF: + case EINVAL: + case ENOMEM: + case EFAULT: + qWarning("::select() returned an error: %i", savedSelectErrno); + break; + case ECONNREFUSED: + case EPIPE: + qWarning("::select() returned an error: %i (go through sockets)", savedSelectErrno); + // prepare to go through all sockets + // mark in fd sets both: + // good ones + // ones that return -1 in select + // after loop update notifiers for all of them + + // as we dont have "exception" notifier type + // we should force monitoring fd_set of this + // type as well + + // clean @ start + FD_ZERO(&readfds); + FD_ZERO(&writefds); + FD_ZERO(&exceptionfds); + { + for (QHash<QSocketNotifier *, TRequestStatus *>::const_iterator i = m_AOStatuses.begin(); + i != m_AOStatuses.end(); ++i) { + + fd_set onefds; + FD_ZERO(&onefds); + FD_SET(i.key()->socket(), &onefds); + + fd_set excfds; + FD_ZERO(&excfds); + FD_SET(i.key()->socket(), &excfds); + + maxfd = i.key()->socket() + 1; + + struct timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + ret = 0; + + if(i.key()->type() == QSocketNotifier::Read) { + ret = ::select(maxfd, &onefds, 0, &excfds, &timeout); + if(ret != 0) FD_SET(i.key()->socket(), &readfds); + } else if(i.key()->type() == QSocketNotifier::Write) { + ret = ::select(maxfd, 0, &onefds, &excfds, &timeout); + if(ret != 0) FD_SET(i.key()->socket(), &writefds); + } + + } // end for + } + + // traversed all, so update + updateActivatedNotifiers(QSocketNotifier::Read, &readfds); + updateActivatedNotifiers(QSocketNotifier::Write, &writefds); + updateActivatedNotifiers(QSocketNotifier::Exception, &exceptionfds); + + break; + case EINTR: // Should never occur on Symbian, but this is future proof! + default: + qWarning("::select() returned an unknown error: %i", savedSelectErrno); + + break; + } + } else { + updateActivatedNotifiers(QSocketNotifier::Read, &readfds); + updateActivatedNotifiers(QSocketNotifier::Write, &writefds); + updateActivatedNotifiers(QSocketNotifier::Exception, &exceptionfds); + } + + m_waitCond.wait(&m_mutex); + } + + m_mutex.unlock(); +} + +void QSelectThread::requestSocketEvents ( QSocketNotifier *notifier, TRequestStatus *status ) +{ + Q_D(QThread); + + if (!isRunning()) { + start(); + } + + QSelectMutexGrabber lock(m_pipeEnds[1], &m_mutex); + + Q_ASSERT(!m_AOStatuses.contains(notifier)); + + m_AOStatuses.insert(notifier, status); + + m_waitCond.wakeAll(); +} + +void QSelectThread::cancelSocketEvents ( QSocketNotifier *notifier ) +{ + QSelectMutexGrabber lock(m_pipeEnds[1], &m_mutex); + + m_AOStatuses.remove(notifier); + + m_waitCond.wakeAll(); +} + +void QSelectThread::restart() +{ + QSelectMutexGrabber lock(m_pipeEnds[1], &m_mutex); + + m_waitCond.wakeAll(); +} + +int QSelectThread::updateSocketSet(QSocketNotifier::Type type, fd_set *fds) +{ + int maxfd = 0; + if(m_AOStatuses.isEmpty()) { + /* + * Wonder if should return -1 + * to signal that no descriptors + * added to fds + */ + return maxfd; + } + for ( QHash<QSocketNotifier *, TRequestStatus *>::const_iterator i = m_AOStatuses.begin(); + i != m_AOStatuses.end(); ++i) { + if (i.key()->type() == type) { + FD_SET(i.key()->socket(), fds); + maxfd = qMax(maxfd, i.key()->socket()); + } else if(type == QSocketNotifier::Exception) { + /* + * We are registering existing sockets + * always to exception set + * + * Doing double FD_SET shouldn't + * matter + */ + FD_SET(i.key()->socket(), fds); + maxfd = qMax(maxfd, i.key()->socket()); + } + } + + return maxfd; +} + +void QSelectThread::updateActivatedNotifiers(QSocketNotifier::Type type, fd_set *fds) +{ + Q_D(QThread); + if(m_AOStatuses.isEmpty()) { + return; + } + QList<QSocketNotifier *> toRemove; + for (QHash<QSocketNotifier *, TRequestStatus *>::const_iterator i = m_AOStatuses.begin(); + i != m_AOStatuses.end(); ++i) { + if (i.key()->type() == type && FD_ISSET(i.key()->socket(), fds)) { + toRemove.append(i.key()); + TRequestStatus *status = i.value(); + // Thread data is still owned by the main thread. + QEventDispatcherSymbian::RequestComplete(d->threadData->symbian_thread_handle, status, KErrNone); + } else if(type == QSocketNotifier::Exception && FD_ISSET(i.key()->socket(), fds)) { + /* + * check if socket is in exception set + * then signal RequestComplete for it + */ + qWarning("exception on %d", i.key()->socket()); + toRemove.append(i.key()); + TRequestStatus *status = i.value(); + QEventDispatcherSymbian::RequestComplete(d->threadData->symbian_thread_handle, status, KErrNone); + } + } + + for (int c = 0; c < toRemove.size(); ++c) { + m_AOStatuses.remove(toRemove[c]); + } +} + +void QSelectThread::stop() +{ + m_quit = true; + restart(); + wait(); +} + +QSocketActiveObject::QSocketActiveObject(QEventDispatcherSymbian *dispatcher, QSocketNotifier *notifier) + : QActiveObject(CActive::EPriorityStandard, dispatcher), + m_notifier(notifier), + m_inSocketEvent(false), + m_deleteLater(false) +{ + CActiveScheduler::Add(this); + iStatus = KRequestPending; + SetActive(); +} + +QSocketActiveObject::~QSocketActiveObject() +{ + Cancel(); +} + +void QSocketActiveObject::DoCancel() +{ + if (iStatus.Int() & KRequestPending) { + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); + } +} + +void QSocketActiveObject::RunL() +{ + if (!okToRun()) + return; + + m_dispatcher->socketFired(this); +} + +void QSocketActiveObject::deleteLater() +{ + if (m_inSocketEvent) { + m_deleteLater = true; + } else { + delete this; + } +} + +QEventDispatcherSymbian::QEventDispatcherSymbian(QObject *parent) + : QAbstractEventDispatcher(parent), + m_activeScheduler(0), + m_wakeUpAO(0), + m_completeDeferredAOs(0), + m_interrupt(false), + m_wakeUpDone(0), + m_iterationCount(0), + m_noSocketEvents(false) +{ +} + +QEventDispatcherSymbian::~QEventDispatcherSymbian() +{ + m_processHandle.Close(); +} + +void QEventDispatcherSymbian::startingUp() +{ + if( !CActiveScheduler::Current() ) { + m_activeScheduler = new(ELeave)CActiveScheduler(); + CActiveScheduler::Install(m_activeScheduler); + } + m_wakeUpAO = new(ELeave) QWakeUpActiveObject(this); + m_completeDeferredAOs = new(ELeave) QCompleteDeferredAOs(this); + // We already might have posted events, wakeup once to process them + wakeUp(); +} + +void QEventDispatcherSymbian::closingDown() +{ + if (m_selectThread.isRunning()) { + m_selectThread.stop(); + } + + delete m_completeDeferredAOs; + delete m_wakeUpAO; + if (m_activeScheduler) { + delete m_activeScheduler; + } +} + +bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags flags ) +{ + Q_D(QAbstractEventDispatcher); + + // It is safe if this counter overflows. The main importance is that each + // iteration count is different from the last. + m_iterationCount++; + + RThread &thread = d->threadData->symbian_thread_handle; + + bool block; + if (flags & QEventLoop::WaitForMoreEvents) { + block = true; + emit aboutToBlock(); + } else { + block = false; + } + + bool handledAnyEvent = false; + + bool oldNoSocketEventsValue = m_noSocketEvents; + if (flags & QEventLoop::ExcludeSocketNotifiers) { + m_noSocketEvents = true; + } else { + m_noSocketEvents = false; + handledAnyEvent = sendDeferredSocketEvents(); + } + + bool handledSymbianEvent = false; + m_interrupt = false; + + /* + * This QTime variable is used to measure the time it takes to finish + * the event loop. If we take too long in the loop, other processes + * may be starved and killed. After the first event has completed, we + * take the current time, and if the remaining events take longer than + * a preset time, we temporarily lower the priority to force a context + * switch. For applications that do not take unecessarily long in the + * event loop, the priority will not be altered. + */ + QTime time; + enum { + FirstRun, + SubsequentRun, + TimeStarted + } timeState = FirstRun; + + TProcessPriority priority; + + while (1) { + if (block) { + // This is where Qt will spend most of its time. + CActiveScheduler::Current()->WaitForAnyRequest(); + } else { + if (thread.RequestCount() == 0) { + break; + } + // This one should return without delay. + CActiveScheduler::Current()->WaitForAnyRequest(); + } + + if (timeState == SubsequentRun) { + time.start(); + timeState = TimeStarted; + } + + TInt error; + handledSymbianEvent = CActiveScheduler::RunIfReady(error, CActive::EPriorityIdle); + if (error) { + qWarning("CActiveScheduler::RunIfReady() returned error: %i\n", error); + CActiveScheduler::Current()->Error(error); + } + if (!handledSymbianEvent) { + qFatal("QEventDispatcherSymbian::processEvents(): Caught Symbian stray signal"); + } + handledAnyEvent = true; + if (m_interrupt) { + break; + } + block = false; + if (timeState == TimeStarted && time.elapsed() > 100) { + priority = m_processHandle.Priority(); + m_processHandle.SetPriority(EPriorityLow); + time.start(); + // Slight chance of race condition in the next lines, but nothing fatal + // will happen, just wrong priority. + if (m_processHandle.Priority() == EPriorityLow) { + m_processHandle.SetPriority(priority); + } + } + if (timeState == FirstRun) + timeState = SubsequentRun; + }; + + emit awake(); + + m_noSocketEvents = oldNoSocketEventsValue; + + return handledAnyEvent; +} + +void QEventDispatcherSymbian::timerFired(int timerId) +{ + QHash<int, SymbianTimerInfoPtr>::iterator i = m_timerList.find(timerId); + if (i == m_timerList.end()) { + // The timer has been deleted. Ignore this event. + return; + } + + SymbianTimerInfoPtr timerInfo = *i; + + // Prevent infinite timer recursion. + if (timerInfo->inTimerEvent) { + return; + } + + timerInfo->inTimerEvent = true; + + QTimerEvent event(timerInfo->timerId); + QCoreApplication::sendEvent(timerInfo->receiver, &event); + + timerInfo->inTimerEvent = false; + + return; +} + +void QEventDispatcherSymbian::socketFired(QSocketActiveObject *socketAO) +{ + if (m_noSocketEvents) { + m_deferredSocketEvents.append(socketAO); + return; + } + + QEvent e(QEvent::SockAct); + socketAO->m_inSocketEvent = true; + QCoreApplication::sendEvent(socketAO->m_notifier, &e); + socketAO->m_inSocketEvent = false; + + if (socketAO->m_deleteLater) { + delete socketAO; + } else { + socketAO->iStatus = KRequestPending; + socketAO->SetActive(); + reactivateSocketNotifier(socketAO->m_notifier); + } +} + +void QEventDispatcherSymbian::wakeUpWasCalled() +{ + // The reactivation should happen in RunL, right before the call to this function. + // This is because m_wakeUpDone is the "signal" that the object can be completed + // once more. + // Also, by dispatching the posted events after resetting m_wakeUpDone, we guarantee + // that no posted event notification will be lost. If we did it the other way + // around, it would be possible for another thread to post an event right after + // the sendPostedEvents was done, but before the object was ready to be completed + // again. This could deadlock the application if there are no other posted events. + m_wakeUpDone.fetchAndStoreOrdered(0); + sendPostedEvents(); +} + +void QEventDispatcherSymbian::interrupt() +{ + m_interrupt = true; + wakeUp(); +} + +void QEventDispatcherSymbian::wakeUp() +{ + Q_D(QAbstractEventDispatcher); + + if (m_wakeUpAO && m_wakeUpDone.testAndSetAcquire(0, 1)) { + TRequestStatus *status = &m_wakeUpAO->iStatus; + QEventDispatcherSymbian::RequestComplete(d->threadData->symbian_thread_handle, status, KErrNone); + } +} + +bool QEventDispatcherSymbian::sendPostedEvents() +{ + Q_D(QAbstractEventDispatcher); + + // moveToThread calls this and canWait == true -> Events will never get processed + // if we check for d->threadData->canWait + // + // QCoreApplication::postEvent sets canWait = false, but after the object and events + // are moved to a new thread, the canWait in new thread is true i.e. not changed to reflect + // the flag on old thread. That's why events in a new thread will not get processed. + // This migth be actually bug in moveToThread functionality, but because other platforms + // do not check canWait in wakeUp (where we essentially are now) - decided to remove it from + // here as well. + + //if (!d->threadData->canWait) { + QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData); + return true; + //} + //return false; +} + +inline void QEventDispatcherSymbian::addDeferredActiveObject(QActiveObject *object) +{ + if (m_deferredActiveObjects.isEmpty()) { + m_completeDeferredAOs->complete(); + } + m_deferredActiveObjects.append(object); +} + +inline void QEventDispatcherSymbian::removeDeferredActiveObject(QActiveObject *object) +{ + m_deferredActiveObjects.removeAll(object); +} + +void QEventDispatcherSymbian::reactivateDeferredActiveObjects() +{ + while (!m_deferredActiveObjects.isEmpty()) { + QActiveObject *object = m_deferredActiveObjects.takeFirst(); + object->reactivateAndComplete(); + } + + // We do this because we want to return from processEvents. This is because + // each invocation of processEvents should only run each active object once. + // The active scheduler should run them continously, however. + m_interrupt = true; +} + +bool QEventDispatcherSymbian::sendDeferredSocketEvents() +{ + bool sentAnyEvents = false; + while (!m_deferredSocketEvents.isEmpty()) { + sentAnyEvents = true; + socketFired(m_deferredSocketEvents.takeFirst()); + } + + return sentAnyEvents; +} + +void QEventDispatcherSymbian::flush() +{ +} + +bool QEventDispatcherSymbian::hasPendingEvents() +{ + Q_D(QAbstractEventDispatcher); + return (d->threadData->symbian_thread_handle.RequestCount() != 0 + || !d->threadData->canWait || !m_deferredSocketEvents.isEmpty()); +} + +void QEventDispatcherSymbian::registerSocketNotifier ( QSocketNotifier * notifier ) +{ + QSocketActiveObject *socketAO = new (ELeave) QSocketActiveObject(this, notifier); + m_notifiers.insert(notifier, socketAO); + m_selectThread.requestSocketEvents(notifier, &socketAO->iStatus); +} + +void QEventDispatcherSymbian::unregisterSocketNotifier ( QSocketNotifier * notifier ) +{ + m_selectThread.cancelSocketEvents(notifier); + if (m_notifiers.contains(notifier)) { + QSocketActiveObject *sockObj = *m_notifiers.find(notifier); + m_deferredSocketEvents.removeAll(sockObj); + sockObj->deleteLater(); + m_notifiers.remove(notifier); + } +} + +void QEventDispatcherSymbian::reactivateSocketNotifier(QSocketNotifier *notifier) +{ + m_selectThread.requestSocketEvents(notifier, &m_notifiers[notifier]->iStatus); +} + +void QEventDispatcherSymbian::registerTimer ( int timerId, int interval, QObject * object ) +{ + if (interval < 0) { + qWarning("Timer interval < 0"); + interval = 0; + } + + SymbianTimerInfoPtr timer(new SymbianTimerInfo); + timer->timerId = timerId; + timer->interval = interval; + timer->inTimerEvent = false; + timer->receiver = object; + timer->dispatcher = this; + timer->timerAO = new(ELeave) QTimerActiveObject(this, timer.data()); + m_timerList.insert(timerId, timer); + + timer->timerAO->Start(); +} + +bool QEventDispatcherSymbian::unregisterTimer ( int timerId ) +{ + if (!m_timerList.contains(timerId)) { + return false; + } + + SymbianTimerInfoPtr timerInfo = m_timerList.take(timerId); + + return true; +} + +bool QEventDispatcherSymbian::unregisterTimers ( QObject * object ) +{ + QList<TimerInfo> idsToRemove = registeredTimers(object); + + if (idsToRemove.isEmpty()) + return false; + + for (int c = 0; c < idsToRemove.size(); ++c) { + unregisterTimer(idsToRemove[c].first); + } + + return true; +} + +QList<QEventDispatcherSymbian::TimerInfo> QEventDispatcherSymbian::registeredTimers ( QObject * object ) const +{ + QList<TimerInfo> list; + for (QHash<int, SymbianTimerInfoPtr>::const_iterator i = m_timerList.begin(); i != m_timerList.end(); ++i) { + if ((*i)->receiver == object) { + list.push_back(TimerInfo((*i)->timerId, (*i)->interval)); + } + } + + return list; +} + +QT_END_NAMESPACE + diff --git a/src/corelib/kernel/qeventdispatcher_symbian_p.h b/src/corelib/kernel/qeventdispatcher_symbian_p.h new file mode 100644 index 0000000..64ea282 --- /dev/null +++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h @@ -0,0 +1,302 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEVENTDISPATCHER_SYMBIAN_P_H +#define QEVENTDISPATCHER_SYMBIAN_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qhash.h> +#include <qset.h> +#include <qshareddata.h> +#include <qabstracteventdispatcher.h> +#include <private/qabstracteventdispatcher_p.h> +#include <qthread.h> +#include <qmutex.h> +#include <qwaitcondition.h> +#include <qsocketnotifier.h> + +#include <e32base.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/select.h> + +QT_BEGIN_NAMESPACE + + +class QEventDispatcherSymbian; +class QTimerActiveObject; + +class QActiveObject : public CActive +{ +public: + QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher); + ~QActiveObject(); + + bool okToRun(); + + void reactivateAndComplete(); + +protected: + QEventDispatcherSymbian *m_dispatcher; + +private: + bool m_hasAlreadyRun : 1; + bool m_hasRunAgain : 1; + int m_iterationCount; +}; + +class QWakeUpActiveObject : public CActive +{ +public: + QWakeUpActiveObject(QEventDispatcherSymbian *dispatcher); + ~QWakeUpActiveObject(); + + void Complete(); + +protected: + void DoCancel(); + void RunL(); + +private: + QEventDispatcherSymbian *m_dispatcher; +}; + +struct SymbianTimerInfo : public QSharedData +{ + ~SymbianTimerInfo(); + + int timerId; + int interval; + bool inTimerEvent; + QObject *receiver; + QTimerActiveObject *timerAO; + QEventDispatcherSymbian *dispatcher; +}; + +typedef QExplicitlySharedDataPointer<SymbianTimerInfo> SymbianTimerInfoPtr; + +// This is a bit of a proxy class. See comments in SetActive and Start for details. +class QTimerActiveObject : public QActiveObject +{ +public: + QTimerActiveObject(QEventDispatcherSymbian *dispatcher, SymbianTimerInfo *timerInfo); + ~QTimerActiveObject(); + + void Start(); + +protected: + void DoCancel(); + void RunL(); + +private: + SymbianTimerInfo *m_timerInfo; + RTimer m_rTimer; +}; + +class QCompleteDeferredAOs : public CActive +{ +public: + QCompleteDeferredAOs(QEventDispatcherSymbian *dispatcher); + ~QCompleteDeferredAOs(); + + void complete(); + +protected: + void DoCancel(); + void RunL(); + +private: + QEventDispatcherSymbian *m_dispatcher; +}; + +class QSocketActiveObject : public QActiveObject +{ +public: + QSocketActiveObject(QEventDispatcherSymbian *dispatcher, QSocketNotifier *notifier); + ~QSocketActiveObject(); + + void deleteLater(); + +protected: + void DoCancel(); + void RunL(); + +private: + QSocketNotifier *m_notifier; + bool m_inSocketEvent; + bool m_deleteLater; + + friend class QEventDispatcherSymbian; +}; + +class QSelectThread : public QThread +{ + Q_DECLARE_PRIVATE(QThread) + +public: + QSelectThread(); + ~QSelectThread(); + + void requestSocketEvents ( QSocketNotifier *notifier, TRequestStatus *status ); + void cancelSocketEvents ( QSocketNotifier *notifier ); + void restart(); + void stop(); + +protected: + void run(); + +private: + int updateSocketSet(QSocketNotifier::Type type, fd_set *fds); + void updateActivatedNotifiers(QSocketNotifier::Type type, fd_set *fds); + +private: + int m_pipeEnds[2]; + QHash<QSocketNotifier *, TRequestStatus *> m_AOStatuses; + QMutex m_mutex; + QWaitCondition m_waitCond; + bool m_quit; +}; + +class Q_CORE_EXPORT QEventDispatcherSymbian : public QAbstractEventDispatcher +{ + Q_DECLARE_PRIVATE(QAbstractEventDispatcher) + +public: + QEventDispatcherSymbian(QObject *parent = 0); + ~QEventDispatcherSymbian(); + + void flush(); + bool hasPendingEvents(); + void interrupt(); + bool processEvents ( QEventLoop::ProcessEventsFlags flags ); + void registerSocketNotifier ( QSocketNotifier * notifier ); + void registerTimer ( int timerId, int interval, QObject * object ); + QList<TimerInfo> registeredTimers ( QObject * object ) const; + void unregisterSocketNotifier ( QSocketNotifier * notifier ); + bool unregisterTimer ( int timerId ); + bool unregisterTimers ( QObject * object ); + void wakeUp(); + + void startingUp(); + void closingDown(); + + void timerFired(int timerId); + void socketFired(QSocketActiveObject *socketAO); + void wakeUpWasCalled(); + void reactivateSocketNotifier(QSocketNotifier *notifier); + + void addDeferredActiveObject(QActiveObject *object); + void removeDeferredActiveObject(QActiveObject *object); + void reactivateDeferredActiveObjects(); + + inline int iterationCount() const { return m_iterationCount; } + + static void RequestComplete(TRequestStatus *&status, TInt reason); + static void RequestComplete(RThread &threadHandle, TRequestStatus *&status, TInt reason); + +private: + bool sendPostedEvents(); + bool sendDeferredSocketEvents(); + +private: + QSelectThread m_selectThread; + + CActiveScheduler *m_activeScheduler; + + QHash<int, SymbianTimerInfoPtr> m_timerList; + QHash<QSocketNotifier *, QSocketActiveObject *> m_notifiers; + + QWakeUpActiveObject *m_wakeUpAO; + QCompleteDeferredAOs *m_completeDeferredAOs; + + volatile bool m_interrupt; + QAtomicInt m_wakeUpDone; + + unsigned char m_iterationCount; + bool m_noSocketEvents; + QList<QSocketActiveObject *> m_deferredSocketEvents; + + QList<QActiveObject *> m_deferredActiveObjects; + + RProcess m_processHandle; +}; + +#ifdef QT_DEBUG +// EActive is defined to 1 and ERequestPending to 2, but they are both private. +// A little dangerous to rely on, but it is only for debugging. +# define REQUEST_STATUS_ACTIVE_AND_PENDING 3 +# define VERIFY_PENDING_REQUEST_STATUS \ + Q_ASSERT(status->Int() & REQUEST_STATUS_ACTIVE_AND_PENDING == REQUEST_STATUS_ACTIVE_AND_PENDING); +#else +# define REQUEST_STATUS_ACTIVE_AND_PENDING +# define VERIFY_PENDING_REQUEST_STATUS +#endif + +// Convenience functions for doing some sanity checking on our own complete code. +// Unless QT_DEBUG is defined, it is exactly equivalent to the Symbian version. +inline void QEventDispatcherSymbian::RequestComplete(TRequestStatus *&status, TInt reason) +{ + VERIFY_PENDING_REQUEST_STATUS + User::RequestComplete(status, reason); +} +inline void QEventDispatcherSymbian::RequestComplete(RThread &threadHandle, TRequestStatus *&status, TInt reason) +{ + VERIFY_PENDING_REQUEST_STATUS + threadHandle.RequestComplete(status, reason); +} + +#undef REQUEST_STATUS_ACTIVE_AND_PENDING +#undef VERIFY_PENDING_REQUEST_STATUS + +QT_END_NAMESPACE + +#endif // QEVENTDISPATCHER_SYMBIAN_P_H diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 6583b85..860180e 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -1395,8 +1395,10 @@ void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData ++eventsMoved; } } - if (eventsMoved > 0 && targetData->eventDispatcher) + if (eventsMoved > 0 && targetData->eventDispatcher) { + targetData->canWait = false; targetData->eventDispatcher->wakeUp(); + } // the current emitting thread shouldn't restore currentSender after calling moveToThread() if (currentSender) diff --git a/src/corelib/kernel/qsharedmemory.cpp b/src/corelib/kernel/qsharedmemory.cpp index 87e154f..dc9cabf 100644 --- a/src/corelib/kernel/qsharedmemory.cpp +++ b/src/corelib/kernel/qsharedmemory.cpp @@ -44,7 +44,9 @@ #include "qsystemsemaphore.h" #include <qdir.h> #include <qcryptographichash.h> - +#ifdef Q_OS_SYMBIAN +#include <e32const.h> +#endif #include <qdebug.h> QT_BEGIN_NAMESPACE @@ -57,6 +59,7 @@ QT_BEGIN_NAMESPACE the subset that the win/unix kernel allows. On Unix this will be a file name + On Symbian key will be truncated to 80 characters */ QString QSharedMemoryPrivate::makePlatformSafeKey(const QString &key, @@ -70,10 +73,12 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key, QString part1 = key; part1.replace(QRegExp(QLatin1String("[^A-Za-z]")), QString()); result.append(part1); +#ifdef Q_OS_SYMBIAN + return result.left(KMaxKernelName); +#endif QByteArray hex = QCryptographicHash::hash(key.toUtf8(), QCryptographicHash::Sha1).toHex(); result.append(QLatin1String(hex)); - #ifdef Q_OS_WIN return result; #else @@ -118,6 +123,14 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key, process. This means that QSharedMemory should not be used across multiple threads in the same process in HP-UX. + \o Symbian: QSharedMemory does not "own" the shared memory segment. + When all threads or processes that have an instance of QSharedMemory + attached to a particular shared memory segment have either destroyed + their instance of QSharedMemory or exited, the Symbian kernel + releases the shared memory segment automatically. + Also, access to a shared memory segment cannot be limited to read-only + in Symbian. + \endlist Remember to lock the shared memory with lock() before reading from diff --git a/src/corelib/kernel/qsharedmemory_p.h b/src/corelib/kernel/qsharedmemory_p.h index 08f0321..a7524d9 100644 --- a/src/corelib/kernel/qsharedmemory_p.h +++ b/src/corelib/kernel/qsharedmemory_p.h @@ -71,6 +71,9 @@ namespace QSharedMemoryPrivate #ifdef Q_OS_WIN #include <qt_windows.h> +#elif defined(Q_OS_SYMBIAN) +#include <e32std.h> +#include <sys/types.h> #else #include <sys/sem.h> #endif @@ -140,7 +143,11 @@ public: bool attach(QSharedMemory::AccessMode mode); bool detach(); +#ifdef Q_OS_SYMBIAN + void setErrorString(const QString &function, TInt errorCode); +#else void setErrorString(const QString &function); +#endif #ifndef QT_NO_SYSTEMSEMAPHORE bool tryLocker(QSharedMemoryLocker *locker, const QString function) { @@ -156,6 +163,8 @@ public: private: #ifdef Q_OS_WIN HANDLE hand; +#elif defined(Q_OS_SYMBIAN) + RChunk chunk; #else key_t unix_key; #endif diff --git a/src/corelib/kernel/qsharedmemory_symbian.cpp b/src/corelib/kernel/qsharedmemory_symbian.cpp new file mode 100644 index 0000000..b3b50e3 --- /dev/null +++ b/src/corelib/kernel/qsharedmemory_symbian.cpp @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsharedmemory.h" +#include "qsharedmemory_p.h" +#include "qsystemsemaphore.h" +#include "qcore_symbian_p.h" +#include <qdebug.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_SHAREDMEMORY + +#define QSHAREDMEMORY_DEBUG + +QSharedMemoryPrivate::QSharedMemoryPrivate() : QObjectPrivate(), + memory(0), size(0), error(QSharedMemory::NoError), + systemSemaphore(QString()), lockedByMe(false) +{ +} + +void QSharedMemoryPrivate::setErrorString(const QString &function, TInt errorCode) +{ + if (errorCode == KErrNone) + return; + switch (errorCode) { + case KErrAlreadyExists: + error = QSharedMemory::AlreadyExists; + errorString = QSharedMemory::tr("%1: already exists").arg(function); + break; + case KErrNotFound: + error = QSharedMemory::NotFound; + errorString = QSharedMemory::tr("%1: doesn't exists").arg(function); + break; + case KErrArgument: + error = QSharedMemory::InvalidSize; + errorString = QSharedMemory::tr("%1: invalid size").arg(function); + break; + case KErrNoMemory: + error = QSharedMemory::OutOfResources; + errorString = QSharedMemory::tr("%1: out of resources").arg(function); + break; + case KErrPermissionDenied: + error = QSharedMemory::PermissionDenied; + errorString = QSharedMemory::tr("%1: permission denied").arg(function); + break; + default: + errorString = QSharedMemory::tr("%1: unknown error %2").arg(function).arg(errorCode); + error = QSharedMemory::UnknownError; +#if defined QSHAREDMEMORY_DEBUG + qDebug() << errorString << "key" << key; +#endif + } +} + +key_t QSharedMemoryPrivate::handle() +{ + // Not really cost effective to check here if shared memory is attachable, as it requires + // exactly the same call as attaching, so always assume handle is valid and return failure + // from attach. + return 1; +} + +bool QSharedMemoryPrivate::cleanHandle() +{ + chunk.Close(); + return true; +} + +bool QSharedMemoryPrivate::create(int size) +{ + // Get a windows acceptable key + QString safeKey = makePlatformSafeKey(key); + QString function = QLatin1String("QSharedMemory::create"); + if (safeKey.isEmpty()) { + error = QSharedMemory::KeyError; + errorString = QSharedMemory::tr("%1: key error").arg(function); + return false; + } + + HBufC* buffer = qt_QString2HBufCNewL(safeKey); + + TInt err = chunk.CreateGlobal(*buffer, size, size); + + delete buffer; + + setErrorString(function, err); + + if (err != KErrNone) + return false; + + // Zero out the created chunk + Mem::FillZ(chunk.Base(), chunk.Size()); + + return true; +} + +bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode) +{ + // Grab a pointer to the memory block + TBool readOnly = (mode == QSharedMemory::ReadOnly ? true : false); + + if (!chunk.Handle()) { + QString function = QLatin1String("QSharedMemory::handle"); + QString safeKey = makePlatformSafeKey(key); + if (safeKey.isEmpty()) { + error = QSharedMemory::KeyError; + errorString = QSharedMemory::tr("%1: unable to make key").arg(function); + return false; + } + + HBufC* buffer = qt_QString2HBufCNewL(safeKey); + + TInt err = KErrNoMemory; + + if (buffer) { + err = chunk.OpenGlobal(*buffer, false); + } + + delete buffer; + + if (err != KErrNone) { + setErrorString(function, err); + return false; + } + } + + size = chunk.Size(); + memory = chunk.Base(); + + return true; +} + +bool QSharedMemoryPrivate::detach() +{ + chunk.Close(); + + memory = 0; + size = 0; + + return true; +} + +#endif //QT_NO_SHAREDMEMORY + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qsharedmemory_unix.cpp b/src/corelib/kernel/qsharedmemory_unix.cpp index 61d56f4..b664093 100644 --- a/src/corelib/kernel/qsharedmemory_unix.cpp +++ b/src/corelib/kernel/qsharedmemory_unix.cpp @@ -48,11 +48,6 @@ #include <qdebug.h> #include <errno.h> - -#ifndef QT_NO_SHAREDMEMORY - -QT_BEGIN_NAMESPACE - #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> @@ -61,6 +56,10 @@ QT_BEGIN_NAMESPACE #include <fcntl.h> #include <unistd.h> +#ifndef QT_NO_SHAREDMEMORY + +QT_BEGIN_NAMESPACE + QSharedMemoryPrivate::QSharedMemoryPrivate() : QObjectPrivate(), memory(0), size(0), error(QSharedMemory::NoError), #ifndef QT_NO_SYSTEMSEMAPHORE diff --git a/src/corelib/kernel/qsystemsemaphore.cpp b/src/corelib/kernel/qsystemsemaphore.cpp index e8426b3..7e09a6e 100644 --- a/src/corelib/kernel/qsystemsemaphore.cpp +++ b/src/corelib/kernel/qsystemsemaphore.cpp @@ -123,6 +123,11 @@ QT_BEGIN_NAMESPACE operations that were not released. Thus if the process acquires a resource and then exits without releasing it, Unix will release that resource. + + \o Symbian: QSystemSemaphore behaves the same as Windows semaphores. + In other words, the operating system owns the semaphore and ignores + QSystemSemaphore::AccessMode. + \endlist \sa QSharedMemory, QSemaphore @@ -147,7 +152,7 @@ QT_BEGIN_NAMESPACE creates a new semaphore for that key and sets its resource count to \a initialValue. - In Windows, \a mode is ignored, and the system always tries to + In Windows and in Symbian, \a mode is ignored, and the system always tries to create a semaphore for the specified \a key. If the system does not already have a semaphore identified as \a key, it creates the semaphore and sets its resource count to \a initialValue. But if the @@ -198,7 +203,7 @@ QSystemSemaphore::~QSystemSemaphore() enable handling the problem in Unix implementations of semaphores that survive a crash. In Unix, when a semaphore survives a crash, we need a way to force it to reset its resource count, when the system - reuses the semaphore. In Windows, where semaphores can't survive a + reuses the semaphore. In Windows and in Symbian, where semaphores can't survive a crash, this enum has no effect. \value Open If the semaphore already exists, its initial resource @@ -211,7 +216,7 @@ QSystemSemaphore::~QSystemSemaphore() This value should be passed to the constructor, when the first semaphore for a particular key is constructed and you know that if the semaphore already exists it could only be because of a crash. In - Windows, where a semaphore can't survive a crash, Create and Open + Windows and in Symbian, where a semaphore can't survive a crash, Create and Open have the same behavior. */ @@ -231,7 +236,7 @@ void QSystemSemaphore::setKey(const QString &key, int initialValue, AccessMode m return; d->error = NoError; d->errorString = QString(); -#ifndef Q_OS_WIN +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) // optimization to not destroy/create the file & semaphore if (key == d->key && mode == Create && d->createdSemaphore && d->createdFile) { d->initialValue = initialValue; diff --git a/src/corelib/kernel/qsystemsemaphore_p.h b/src/corelib/kernel/qsystemsemaphore_p.h index a4a7389..0e6def3 100644 --- a/src/corelib/kernel/qsystemsemaphore_p.h +++ b/src/corelib/kernel/qsystemsemaphore_p.h @@ -62,6 +62,10 @@ # include <sys/types.h> #endif +#ifdef Q_OS_SYMBIAN +class RSemaphore; +#endif + QT_BEGIN_NAMESPACE class QSystemSemaphorePrivate @@ -77,10 +81,14 @@ public: #ifdef Q_OS_WIN HANDLE handle(QSystemSemaphore::AccessMode mode = QSystemSemaphore::Open); + void setErrorString(const QString &function); +#elif defined(Q_OS_SYMBIAN) + int handle(QSystemSemaphore::AccessMode mode = QSystemSemaphore::Open); + void setErrorString(const QString &function,int err = 0); #else key_t handle(QSystemSemaphore::AccessMode mode = QSystemSemaphore::Open); -#endif void setErrorString(const QString &function); +#endif void cleanHandle(); bool modifySemaphore(int count); @@ -90,13 +98,14 @@ public: #ifdef Q_OS_WIN HANDLE semaphore; HANDLE semaphoreLock; +#elif defined(Q_OS_SYMBIAN) + RSemaphore semaphore; #else int semaphore; bool createdFile; bool createdSemaphore; key_t unix_key; #endif - QString errorString; QSystemSemaphore::SystemSemaphoreError error; }; diff --git a/src/corelib/kernel/qsystemsemaphore_symbian.cpp b/src/corelib/kernel/qsystemsemaphore_symbian.cpp new file mode 100644 index 0000000..cd5c3ff --- /dev/null +++ b/src/corelib/kernel/qsystemsemaphore_symbian.cpp @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsystemsemaphore.h" +#include "qsystemsemaphore_p.h" +#include "qcoreapplication.h" +#include <qdebug.h> + +#include <qcore_symbian_p.h> +#include <e32cmn.h> +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_SYSTEMSEMAPHORE + +QSystemSemaphorePrivate::QSystemSemaphorePrivate() : + error(QSystemSemaphore::NoError) +{ +} + +void QSystemSemaphorePrivate::setErrorString(const QString &function, int err) +{ + if (err == KErrNone){ + return; + } + switch(err){ + case KErrAlreadyExists: + errorString = QCoreApplication::tr("%1: already exists", "QSystemSemaphore").arg(function); + error = QSystemSemaphore::AlreadyExists; + break; + case KErrNotFound: + errorString = QCoreApplication::tr("%1: doesn't exists", "QSystemSemaphore").arg(function); + error = QSystemSemaphore::NotFound; + break; + case KErrNoMemory: + case KErrInUse: + errorString = QCoreApplication::tr("%1: out of resources", "QSystemSemaphore").arg(function); + error = QSystemSemaphore::OutOfResources; + break; +default: + errorString = QCoreApplication::tr("%1: unknown error %2", "QSystemSemaphore").arg(function).arg(err); + error = QSystemSemaphore::UnknownError; + } + +#if defined QSYSTEMSEMAPHORE_DEBUG + qDebug() << errorString << "key" << key; +#endif +} + +int QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode) +{ + // don't allow making handles on empty keys + if (key.isEmpty()) + return 0; + QString safeName = makeKeyFileName(); + HBufC* name = qt_QString2HBufCNewL(safeName); + int err; + err = semaphore.OpenGlobal(*name,EOwnerProcess); + if (err == KErrNotFound){ + err = semaphore.CreateGlobal(*name,initialValue, EOwnerProcess); + } + delete name; + if (err){ + setErrorString(QLatin1String("QSystemSemaphore::handle"),err); + return 0; + } + return semaphore.Handle(); +} + +void QSystemSemaphorePrivate::cleanHandle() +{ + semaphore.Close(); +} + +bool QSystemSemaphorePrivate::modifySemaphore(int count) +{ + if (0 == handle()) + return false; + + if (count > 0) { + semaphore.Signal(count); + } else { + semaphore.Wait(); + } + return true; +} + +#endif //QT_NO_SYSTEMSEMAPHORE + +QT_END_NAMESPACE diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 0a0500d..0d85b93 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -177,13 +177,40 @@ static void construct(QVariant::Private *x, const void *copy) x->data.b = copy ? *static_cast<const bool *>(copy) : false; break; case QVariant::Double: +#if defined(Q_CC_RVCT) + // Using trinary operator with 64bit constants crashes when ran on Symbian device + if (copy){ + x->data.d = *static_cast<const double*>(copy); + } else { + x->data.d = 0.0; + } +#else x->data.d = copy ? *static_cast<const double*>(copy) : 0.0; +#endif break; case QVariant::LongLong: +#if defined(Q_CC_RVCT) + // Using trinary operator with 64bit constants crashes when ran on Symbian device + if (copy){ + x->data.ll = *static_cast<const qlonglong *>(copy); + } else { + x->data.ll = Q_INT64_C(0); + } +#else x->data.ll = copy ? *static_cast<const qlonglong *>(copy) : Q_INT64_C(0); +#endif break; case QVariant::ULongLong: +#if defined(Q_CC_RVCT) + // Using trinary operator with 64bit constants crashes when ran on Symbian device + if (copy){ + x->data.ull = *static_cast<const qulonglong *>(copy); + } else { + x->data.ull = Q_UINT64_C(0); + } +#else x->data.ull = copy ? *static_cast<const qulonglong *>(copy) : Q_UINT64_C(0); +#endif break; case QVariant::Invalid: case QVariant::UserType: diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index 79400a8..420dd1d 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -98,10 +98,10 @@ Q_GLOBAL_STATIC(QMutex, qt_library_mutex) Unix), unless the file name has an absolute path. If the file cannot be found, QLibrary tries the name with different platform-specific file suffixes, like ".so" on Unix, ".dylib" on - the Mac, or ".dll" on Windows. This makes it possible to specify - shared libraries that are only identified by their basename (i.e. - without their suffix), so the same code will work on different - operating systems. + the Mac, or ".dll" on Windows and Symbian. This makes it possible + to specify shared libraries that are only identified by their + basename (i.e. without their suffix), so the same code will work + on different operating systems. The most important functions are load() to dynamically load the library file, isLoaded() to check whether loading was successful, @@ -120,6 +120,11 @@ Q_GLOBAL_STATIC(QMutex, qt_library_mutex) linking", which is done by the link step in the build process when linking an executable against a library. + Note: In Symbian resolving symbols using their names is supported + only if the library is built as STDDLL. Otherwise ordinals must + be used. Also, in Symbian the path of the library is ignored and + system default library location is always used. + The following code snippet loads a library, resolves the symbol "mysymbol", and calls the function if everything succeeded. If something goes wrong, e.g. the library file does not exist or the @@ -288,7 +293,7 @@ static bool qt_parse_pattern(const char *s, uint *version, bool *debug, QByteArr } #endif // QT_NO_PLUGIN_CHECK -#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(QT_NO_PLUGIN_CHECK) +#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_SYMBIAN) && !defined(QT_NO_PLUGIN_CHECK) #if defined(Q_OS_FREEBSD) || defined(Q_OS_LINUX) # define USE_MMAP @@ -361,7 +366,7 @@ static bool qt_unix_query(const QString &library, uint *version, bool *debug, QB char *filedata = 0; ulong fdlen = 0; -#ifdef USE_MMAP +# ifdef USE_MMAP char *mapaddr = 0; size_t maplen = file.size(); mapaddr = (char *) mmap(mapaddr, maplen, PROT_READ, MAP_PRIVATE, file.handle(), 0); @@ -378,14 +383,14 @@ static bool qt_unix_query(const QString &library, uint *version, bool *debug, QB lib->errorString = QLibrary::tr("Could not mmap '%1': %2") .arg(library) .arg(qt_error_string()); -#endif // USE_MMAP +# endif // USE_MMAP // try reading the data into memory instead data = file.readAll(); filedata = data.data(); fdlen = data.size(); -#ifdef USE_MMAP +# ifdef USE_MMAP } -#endif // USE_MMAP +# endif // USE_MMAP // verify that the pattern is present in the plugin const char pattern[] = "pattern=QT_PLUGIN_VERIFICATION_DATA"; @@ -398,7 +403,7 @@ static bool qt_unix_query(const QString &library, uint *version, bool *debug, QB if (!ret && lib) lib->errorString = QLibrary::tr("Plugin verification data mismatch in '%1'").arg(library); -#ifdef USE_MMAP +# ifdef USE_MMAP if (mapaddr != MAP_FAILED && munmap(mapaddr, maplen) != 0) { if (qt_debug_component()) qWarning("munmap: %s", qPrintable(qt_error_string(errno))); @@ -407,13 +412,13 @@ static bool qt_unix_query(const QString &library, uint *version, bool *debug, QB .arg(library) .arg( qt_error_string() ); } -#endif // USE_MMAP +# endif // USE_MMAP file.close(); return ret; } -#endif // Q_OS_UNIX && !Q_OS_MAC && !defined(QT_NO_PLUGIN_CHECK) +#endif // Q_OS_UNIX && !Q_OS_MAC && !defined(Q_OS_SYMBIAN) && !defined(QT_NO_PLUGIN_CHECK) typedef QMap<QString, QLibraryPrivate*> LibraryMap; Q_GLOBAL_STATIC(LibraryMap, libraryMap) @@ -493,6 +498,11 @@ bool QLibraryPrivate::loadPlugin() } if (load()) { instance = (QtPluginInstanceFunction)resolve("qt_plugin_instance"); +#if defined(Q_OS_SYMBIAN) + // If resolving with function name failed (i.e. not STDDLL), try resolving using known ordinal + if (!instance) + instance = (QtPluginInstanceFunction)resolve("2"); +#endif return instance; } return false; @@ -517,6 +527,10 @@ bool QLibrary::isLibrary(const QString &fileName) { #if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) return fileName.endsWith(QLatin1String(".dll")); +#elif defined(Q_OS_SYMBIAN) + // Plugin stubs are also considered libraries in Symbian. + return (fileName.endsWith(QLatin1String(".dll")) || + fileName.endsWith(QLatin1String(".qtplugin"))); #else QString completeSuffix = QFileInfo(fileName).completeSuffix(); if (completeSuffix.isEmpty()) @@ -610,7 +624,7 @@ bool QLibraryPrivate::isPlugin(QSettings *settings) key = reg.at(2).toLatin1(); success = qt_version != 0; } else { -#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) +#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_SYMBIAN) if (!pHnd) { // use unix shortcut to avoid loading the library success = qt_unix_query(fileName, &qt_version, &debug, &key, this); @@ -629,6 +643,10 @@ bool QLibraryPrivate::isPlugin(QSettings *settings) temporary_load = load_sys(); }); #else +# if defined(Q_OS_SYMBIAN) + //Guard against accidentally trying to load non-plugin libraries by making sure the stub exists + if (fileinfo.exists()) +# endif temporary_load = load_sys(); #endif } @@ -647,8 +665,17 @@ bool QLibraryPrivate::isPlugin(QSettings *settings) #endif : (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data"); #else - QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction = - (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data"); + QtPluginQueryVerificationDataFunction qtPluginQueryVerificationDataFunction = NULL; +# if defined(Q_OS_SYMBIAN) + if (temporary_load) { + qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data"); + // If resolving with function name failed (i.e. not STDDLL), try resolving using known ordinal + if (!qtPluginQueryVerificationDataFunction) + qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("1"); + } +# else + qtPluginQueryVerificationDataFunction = (QtPluginQueryVerificationDataFunction) resolve("qt_plugin_query_verification_data"); +# endif #endif if (!qtPluginQueryVerificationDataFunction @@ -819,6 +846,8 @@ QLibrary::QLibrary(QObject *parent) QLibrary will automatically look for the file with the appropriate suffix in accordance with the platform, e.g. ".so" on Unix, ".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.) + + Note: In Symbian the path portion of the \a fileName is ignored. */ QLibrary::QLibrary(const QString& fileName, QObject *parent) :QObject(parent), d(0), did_load(false) @@ -830,13 +859,15 @@ QLibrary::QLibrary(const QString& fileName, QObject *parent) /*! Constructs a library object with the given \a parent that will load the library specified by \a fileName and major version number \a verNum. - Currently, the version number is ignored on Windows. + Currently, the version number is ignored on Windows and Symbian. We recommend omitting the file's suffix in \a fileName, since QLibrary will automatically look for the file with the appropriate suffix in accordance with the platform, e.g. ".so" on Unix, ".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.) - */ + + Note: In Symbian the path portion of the \a fileName is ignored. +*/ QLibrary::QLibrary(const QString& fileName, int verNum, QObject *parent) :QObject(parent), d(0), did_load(false) { @@ -846,12 +877,14 @@ QLibrary::QLibrary(const QString& fileName, int verNum, QObject *parent) /*! Constructs a library object with the given \a parent that will load the library specified by \a fileName and full version number \a version. - Currently, the version number is ignored on Windows. + Currently, the version number is ignored on Windows and Symbian. We recommend omitting the file's suffix in \a fileName, since QLibrary will automatically look for the file with the appropriate suffix in accordance with the platform, e.g. ".so" on Unix, ".dylib" on Mac OS X, and ".dll" on Windows. (See \l{fileName}.) + + Note: In Symbian the path portion of the \a fileName is ignored. */ QLibrary::QLibrary(const QString& fileName, const QString &version, QObject *parent) :QObject(parent), d(0), did_load(false) @@ -893,6 +926,8 @@ QLibrary::~QLibrary() platforms, fileName() will return "libGL.so". If the file name was originally passed as "/usr/lib/libGL", fileName() will return "/usr/lib/libGL.so". + + Note: In Symbian the path portion of the \a fileName is ignored. */ void QLibrary::setFileName(const QString &fileName) @@ -920,7 +955,10 @@ QString QLibrary::fileName() const Sets the fileName property and major version number to \a fileName and \a versionNumber respectively. - The \a versionNumber is ignored on Windows. + The \a versionNumber is ignored on Windows and Symbian. + + Note: In Symbian the path portion of the \a fileName is ignored. + \sa setFileName() */ void QLibrary::setFileNameAndVersion(const QString &fileName, int verNum) @@ -941,7 +979,10 @@ void QLibrary::setFileNameAndVersion(const QString &fileName, int verNum) Sets the fileName property and full version number to \a fileName and \a version respectively. - The \a version parameter is ignored on Windows. + The \a version parameter is ignored on Windows and Symbian. + + Note: In Symbian the path portion of the \a fileName is ignored. + \sa setFileName() */ void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &version) @@ -977,6 +1018,8 @@ void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &ver \snippet doc/src/snippets/code/src_corelib_plugin_qlibrary.cpp 4 + Note: In Symbian resolving with symbol names works only if the loaded + library was built as STDDLL. Otherwise, the ordinals must be used. */ void *QLibrary::resolve(const char *symbol) { @@ -996,6 +1039,9 @@ void *QLibrary::resolve(const char *symbol) The function returns 0 if the symbol could not be resolved or if the library could not be loaded. + Note: In Symbian resolving with symbol names works only if the loaded + library was built as STDDLL. Otherwise, the ordinals must be used. + \sa resolve() */ void *QLibrary::resolve(const QString &fileName, const char *symbol) @@ -1016,6 +1062,9 @@ void *QLibrary::resolve(const QString &fileName, const char *symbol) The function returns 0 if the symbol could not be resolved or if the library could not be loaded. + Note: In Symbian resolving with symbol names works only if the loaded + library was built as STDDLL. Otherwise, the ordinals must be used. + \sa resolve() */ void *QLibrary::resolve(const QString &fileName, int verNum, const char *symbol) @@ -1037,6 +1086,9 @@ void *QLibrary::resolve(const QString &fileName, int verNum, const char *symbol) The function returns 0 if the symbol could not be resolved or if the library could not be loaded. + Note: In Symbian resolving with symbol names works only if the loaded + library was built as STDDLL. Otherwise, the ordinals must be used. + \sa resolve() */ void *QLibrary::resolve(const QString &fileName, const QString &version, const char *symbol) diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp index 08bd2d0..c868d4a 100644 --- a/src/corelib/plugin/qlibrary_unix.cpp +++ b/src/corelib/plugin/qlibrary_unix.cpp @@ -77,18 +77,31 @@ static QString qdlerror() bool QLibraryPrivate::load_sys() { QFileInfo fi(fileName); + +#if defined(Q_OS_SYMBIAN) + QString path; // In Symbian, always resolve with just the filename + QString name; + + // Replace possible ".qtplugin" suffix with ".dll" + if (fi.suffix() == QLatin1String("qtplugin")) + name = fi.completeBaseName() + QLatin1String(".dll"); + else + name = fi.fileName(); +#else QString path = fi.path(); QString name = fi.fileName(); if (path == QLatin1String(".") && !fileName.startsWith(path)) path.clear(); else path += QLatin1Char('/'); - +#endif // The first filename we want to attempt to load is the filename as the callee specified. // Thus, the first attempt we do must be with an empty prefix and empty suffix. QStringList suffixes(QLatin1String("")), prefixes(QLatin1String("")); if (pluginState != IsAPlugin) { +#if !defined(Q_OS_SYMBIAN) prefixes << QLatin1String("lib"); +#endif #if defined(Q_OS_HPUX) // according to // http://docs.hp.com/en/B2355-90968/linkerdifferencesiapa.htm @@ -116,6 +129,9 @@ bool QLibraryPrivate::load_sys() } #elif defined(Q_OS_AIX) suffixes << ".a"; + +#elif defined(Q_OS_SYMBIAN) + suffixes << QLatin1String(".dll"); #else if (!fullVersion.isEmpty()) { suffixes << QString::fromLatin1(".so.%1").arg(fullVersion); @@ -153,7 +169,7 @@ bool QLibraryPrivate::load_sys() else { #if defined(Q_OS_MAC) if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) -#endif +#endif dlFlags |= RTLD_LOCAL; } #endif @@ -185,6 +201,12 @@ bool QLibraryPrivate::load_sys() #else pHnd = dlopen(QFile::encodeName(attempt), dlFlags); #endif + +#if defined(Q_OS_SYMBIAN) + // Never try again in symbian, dlopen already handles the library search logic, + // and there is only one possible suffix. + retry = false; +#else if (!pHnd && fileName.startsWith(QLatin1Char('/')) && QFile::exists(attempt)) { // We only want to continue if dlopen failed due to that the shared library did not exist. // However, we are only able to apply this check for absolute filenames (since they are @@ -192,6 +214,7 @@ bool QLibraryPrivate::load_sys() // This is all because dlerror is flawed and cannot tell us the reason why it failed. retry = false; } +#endif } } diff --git a/src/corelib/plugin/qpluginloader.cpp b/src/corelib/plugin/qpluginloader.cpp index 15ebe3d..a911f1d 100644 --- a/src/corelib/plugin/qpluginloader.cpp +++ b/src/corelib/plugin/qpluginloader.cpp @@ -116,6 +116,16 @@ QT_BEGIN_NAMESPACE link to plugins statically. You can use QLibrary if you need to load dynamic libraries in a statically linked application. + \note In Symbian the plugin stub files must be used whenever a + path to plugin is needed. For the purposes of loading plugins, + the stubs can be considered to have the same name as the actual + plugin binary. In practice they have ".qtplugin" extension + instead of ".dll", but this difference is handled transparently + by QPluginLoader and QLibrary to avoid need for Symbian specific + plugin handling in most Qt applications. Plugin stubs are needed + because Symbian Platform Security denies all access to the directory + where the actual plugin binaries are located. + \sa QLibrary, {Plug & Paint Example} */ @@ -136,6 +146,8 @@ QPluginLoader::QPluginLoader(QObject *parent) Unix, - \c .dylib on Mac OS X, and \c .dll on Windows. The suffix can be verified with QLibrary::isLibrary(). + Note: In Symbian the \a fileName must point to plugin stub file. + \sa setFileName() */ QPluginLoader::QPluginLoader(const QString &fileName, QObject *parent) @@ -170,7 +182,7 @@ QPluginLoader::~QPluginLoader() The root component, returned by this function, is not deleted when the QPluginLoader is destroyed. If you want to ensure that the root component is deleted, you should call unload() as soon you don't - need to access the core component anymore. When the library is + need to access the core component anymore. When the library is finally unloaded, the root component will automatically be deleted. The component object is a QObject. Use qobject_cast() to access @@ -221,9 +233,9 @@ bool QPluginLoader::load() call will fail, and unloading will only happen when every instance has called unload(). - Don't try to delete the root component. Instead rely on + Don't try to delete the root component. Instead rely on that unload() will automatically delete it when needed. - + \sa instance(), load() */ bool QPluginLoader::unload() @@ -261,6 +273,8 @@ bool QPluginLoader::isLoaded() const By default, this property contains an empty string. + Note: In Symbian the \a fileName must point to plugin stub file. + \sa load() */ void QPluginLoader::setFileName(const QString &fileName) @@ -273,7 +287,24 @@ void QPluginLoader::setFileName(const QString &fileName) d = 0; did_load = false; } + +#if defined(Q_OS_SYMBIAN) + // In Symbian we actually look for plugin stub, so modify the filename + // to make canonicalFilePath find the file, if .dll is specified. + QFileInfo fi(fileName); + + if (fi.suffix() == QLatin1String("dll")) { + QString stubName = fileName; + stubName.chop(3); + stubName += QLatin1String("qtplugin"); + fi = QFileInfo(stubName); + } + + QString fn = fi.canonicalFilePath(); +#else QString fn = QFileInfo(fileName).canonicalFilePath(); +#endif + d = QLibraryPrivate::findOrCreate(fn); d->loadHints = lh; if (fn.isEmpty()) diff --git a/src/corelib/plugin/quuid.cpp b/src/corelib/plugin/quuid.cpp index 3e05d28..4365c98 100644 --- a/src/corelib/plugin/quuid.cpp +++ b/src/corelib/plugin/quuid.cpp @@ -558,7 +558,7 @@ bool QUuid::operator>(const QUuid &other) const \sa variant(), version() */ -#if defined(Q_OS_WIN32) +#if defined(Q_OS_WIN32) && ! defined(Q_CC_MWERKS) QT_BEGIN_INCLUDE_NAMESPACE #include <objbase.h> // For CoCreateGuid diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp index 2fb6335..cb44a25 100644 --- a/src/corelib/thread/qthread.cpp +++ b/src/corelib/thread/qthread.cpp @@ -135,35 +135,6 @@ void QThreadData::deref() #endif } - -#ifndef QT_NO_THREAD -/* - QThreadPrivate -*/ - -QThreadPrivate::QThreadPrivate(QThreadData *d) - : QObjectPrivate(), running(false), finished(false), terminated(false), - stackSize(0), priority(QThread::InheritPriority), data(d) -{ -#if defined (Q_OS_UNIX) - thread_id = 0; -#elif defined (Q_WS_WIN) - handle = 0; - id = 0; - waiters = 0; - terminationEnabled = true; - terminatePending = false; -#endif - - if (!data) - data = new QThreadData; -} - -QThreadPrivate::~QThreadPrivate() -{ - data->deref(); -} - /* QAdoptedThread */ @@ -173,17 +144,20 @@ QAdoptedThread::QAdoptedThread(QThreadData *data) { // thread should be running and not finished for the lifetime // of the application (even if QCoreApplication goes away) +#ifndef QT_NO_THREAD d_func()->running = true; d_func()->finished = false; init(); +#endif // fprintf(stderr, "new QAdoptedThread = %p\n", this); } QAdoptedThread::~QAdoptedThread() { +#ifndef QT_NO_THREAD QThreadPrivate::finish(this); - +#endif // fprintf(stderr, "~QAdoptedThread = %p\n", this); } @@ -199,6 +173,35 @@ void QAdoptedThread::run() // this function should never be called qFatal("QAdoptedThread::run(): Internal error, this implementation should never be called."); } +#ifndef QT_NO_THREAD +/* + QThreadPrivate +*/ + +QThreadPrivate::QThreadPrivate(QThreadData *d) + : QObjectPrivate(), running(false), finished(false), terminated(false), + stackSize(0), priority(QThread::InheritPriority), data(d) +{ +#if defined (Q_OS_UNIX) + thread_id = 0; +#elif defined (Q_WS_WIN) + handle = 0; + id = 0; + waiters = 0; +#endif +#if defined (Q_WS_WIN) || defined (Q_OS_SYMBIAN) + terminationEnabled = true; + terminatePending = false; +#endif + + if (!data) + data = new QThreadData; +} + +QThreadPrivate::~QThreadPrivate() +{ + data->deref(); +} /*! \class QThread @@ -716,25 +719,36 @@ QThread::Priority QThread::priority() const #else // QT_NO_THREAD -QT_BEGIN_INCLUDE_NAMESPACE -#include <private/qcoreapplication_p.h> -QT_END_INCLUDE_NAMESPACE - -Q_GLOBAL_STATIC_WITH_ARGS(QThreadData, staticThreadData, (0)); -QThread* QThread::instance = 0; - -QThread::QThread() : QObject(*new QThreadPrivate, (QObject*)0) -{ +QThread::QThread(QObject *parent) + : QObject(*(new QThreadPrivate), (QObject*)0){ Q_D(QThread); d->data->thread = this; - QCoreApplicationPrivate::theMainThread = this; +} + +QThread *QThread::currentThread() +{ + return QThreadData::current()->thread; } QThreadData* QThreadData::current() { - if (QThread::instance) - return QThread::instance->d_func()->data; - return staticThreadData(); + static QThreadData *data = 0; // reinterpret_cast<QThreadData *>(pthread_getspecific(current_thread_data_key)); + if (!data) { + data = new QThreadData; + data->thread = new QAdoptedThread(data); + data->deref(); + } + return data; +} + +/*! \internal + */ +QThread::QThread(QThreadPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ + Q_D(QThread); + // fprintf(stderr, "QThreadData %p taken from private data for thread %p\n", d->data, this); + d->data->thread = this; } #endif // QT_NO_THREAD diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h index d9a6240..7cbb264 100644 --- a/src/corelib/thread/qthread.h +++ b/src/corelib/thread/qthread.h @@ -142,15 +142,18 @@ class Q_CORE_EXPORT QThread : public QObject { public: static Qt::HANDLE currentThreadId() { return Qt::HANDLE(currentThread()); } - static QThread* currentThread() - { if (!instance) instance = new QThread(); return instance; } + static QThread* currentThread(); + +protected: + QThread(QThreadPrivate &dd, QObject *parent = 0); private: - QThread(); + explicit QThread(QObject *parent = 0); static QThread *instance; friend class QCoreApplication; friend class QThreadData; + friend class QAdoptedThread; Q_DECLARE_PRIVATE(QThread) }; diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index 75293ce..0bf773c 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -62,6 +62,10 @@ #include "QtCore/qmap.h" #include "private/qobject_p.h" +#ifdef Q_OS_SYMBIAN +#include <e32base.h> +#endif + QT_BEGIN_NAMESPACE class QAbstractEventDispatcher; @@ -131,6 +135,25 @@ public: QMap<int, void *> tls; QMutex mutex; + +# ifdef Q_OS_SYMBIAN + RThread symbian_thread_handle; +# endif +}; + +// thread wrapper for the main() thread +class QAdoptedThread : public QThread +{ + Q_DECLARE_PRIVATE(QThread) + +public: + QAdoptedThread(QThreadData *data = 0); + ~QAdoptedThread(); + void init(); + + static QThread *createThreadForAdoption(); +private: + void run(); }; #ifndef QT_NO_THREAD @@ -158,46 +181,37 @@ public: QWaitCondition thread_done; static void *start(void *arg); - static void finish(void *arg); +#if defined(Q_OS_SYMBIAN) + static void finish(void *arg, bool lockAnyway=true, bool closeNativeHandle=true); +#else + static void finish(void *); #endif +#endif // Q_OS_UNIX #if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) HANDLE handle; unsigned int id; int waiters; - bool terminationEnabled, terminatePending; static unsigned int __stdcall start(void *); static void finish(void *, bool lockAnyway=true); #endif // Q_OS_WIN32 +#if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) || defined (Q_OS_SYMBIAN) + bool terminationEnabled, terminatePending; +# endif QThreadData *data; static void createEventDispatcher(QThreadData *data); }; -// thread wrapper for the main() thread -class QAdoptedThread : public QThread -{ - Q_DECLARE_PRIVATE(QThread) - -public: - QAdoptedThread(QThreadData *data = 0); - ~QAdoptedThread(); - void init(); - - static QThread *createThreadForAdoption(); -private: - void run(); -}; - #else // QT_NO_THREAD class QThreadPrivate : public QObjectPrivate { public: - QThreadPrivate() : data(QThreadData::current()) {} - ~QThreadPrivate() { } + QThreadPrivate(QThreadData *d = 0) : data(d ? d : new QThreadData) {} + ~QThreadPrivate() { delete data; } QThreadData *data; diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 8f1c698..567c936 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -47,7 +47,12 @@ #if !defined(QT_NO_GLIB) # include "../kernel/qeventdispatcher_glib_p.h" #endif + +#ifdef Q_OS_SYMBIAN +#include <private/qeventdispatcher_symbian_p.h> +#else #include <private/qeventdispatcher_unix_p.h> +#endif #include "qthreadstorage.h" @@ -131,7 +136,13 @@ QThreadData *QThreadData::current() void QAdoptedThread::init() { - d_func()->thread_id = pthread_self(); + Q_D(QThread); + d->thread_id = pthread_self(); +#ifdef Q_OS_SYMBIAN + d->data->symbian_thread_handle = RThread(); + TThreadId threadId = d->data->symbian_thread_handle.Id(); + d->data->symbian_thread_handle.Open(threadId); +#endif } /* @@ -159,7 +170,11 @@ void QThreadPrivate::createEventDispatcher(QThreadData *data) data->eventDispatcher = new QEventDispatcherGlib; else #endif +#ifdef Q_OS_SYMBIAN + data->eventDispatcher = new QEventDispatcherSymbian; +#else data->eventDispatcher = new QEventDispatcherUNIX; +#endif data->eventDispatcher->startingUp(); } @@ -167,12 +182,24 @@ void QThreadPrivate::createEventDispatcher(QThreadData *data) void *QThreadPrivate::start(void *arg) { +#ifndef Q_OS_SYMBIAN pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); pthread_cleanup_push(QThreadPrivate::finish, arg); - +#endif + QThread *thr = reinterpret_cast<QThread *>(arg); QThreadData *data = QThreadData::get2(thr); +#ifdef Q_OS_SYMBIAN + // Because Symbian Open C does not provide a way to convert between + // RThread and pthread_t, we must delay initialization of the RThread + // handle when creating a thread, until we are running in the new thread. + // Here, we pick up the current thread and assign that to the handle. + data->symbian_thread_handle = RThread(); + TThreadId threadId = data->symbian_thread_handle.Id(); + data->symbian_thread_handle.Open(threadId); +#endif + pthread_once(¤t_thread_data_once, create_current_thread_data_key); pthread_setspecific(current_thread_data_key, data); @@ -183,19 +210,33 @@ void *QThreadPrivate::start(void *arg) createEventDispatcher(data); emit thr->started(); +#ifndef Q_OS_SYMBIAN pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_testcancel(); +#endif thr->run(); +#ifndef Q_OS_SYMBIAN pthread_cleanup_pop(1); +#else + QThreadPrivate::finish(arg); +#endif + return 0; } +#ifdef Q_OS_SYMBIAN +void QThreadPrivate::finish(void *arg, bool lockAnyway, bool closeNativeHandle) +#else void QThreadPrivate::finish(void *arg) +#endif { QThread *thr = reinterpret_cast<QThread *>(arg); QThreadPrivate *d = thr->d_func(); - QMutexLocker locker(&d->mutex); +#ifdef Q_OS_SYMBIAN + if (lockAnyway) +#endif + d->mutex.lock(); d->priority = QThread::InheritPriority; d->running = false; @@ -216,7 +257,15 @@ void QThreadPrivate::finish(void *arg) QThreadStorageData::finish((void **)data); d->thread_id = 0; +#ifdef Q_OS_SYMBIAN + if (closeNativeHandle) + d->data->symbian_thread_handle.Close(); +#endif d->thread_done.wakeAll(); +#ifdef Q_OS_SYMBIAN + if (lockAnyway) +#endif + d->mutex.unlock(); } @@ -268,6 +317,9 @@ int QThread::idealThreadCount() cores = (int)sysconf(_SC_NPROC_ONLN); #elif defined(Q_OS_INTEGRITY) // ### TODO - how to get the amound of CPUs on INTEGRITY? +#elif defined(Q_OS_SYMBIAN) + // ### TODO - Get the number of cores from HAL? when multicore architectures (SMP) are supported + cores = 1; #else // the rest: Linux, Solaris, AIX, Tru64 cores = (int)sysconf(_SC_NPROCESSORS_ONLN); @@ -352,7 +404,8 @@ void QThread::start(Priority priority) d->priority = priority; -#if defined(Q_OS_DARWIN) || !defined(Q_OS_OPENBSD) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0) +#if defined(Q_OS_DARWIN) || !defined(Q_OS_OPENBSD) && !defined(Q_OS_SYMBIAN) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0) +// ### Need to implement thread sheduling and priorities for symbian os. Implementation removed for now switch (priority) { case InheritPriority: { @@ -434,7 +487,9 @@ void QThread::start(Priority priority) if (code == EPERM) { // caller does not have permission to set the scheduling // parameters/policy +#ifndef Q_OS_SYMBIAN pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED); +#endif code = pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this); } @@ -447,6 +502,9 @@ void QThread::start(Priority priority) d->running = false; d->finished = false; d->thread_id = 0; +#ifdef Q_OS_SYMBIAN + d->data->symbian_thread_handle.Close(); +#endif } } @@ -458,6 +516,7 @@ void QThread::terminate() if (!d->thread_id) return; +#ifndef Q_OS_SYMBIAN int code = pthread_cancel(d->thread_id); if (code) { qWarning("QThread::start: Thread termination error: %s", @@ -465,6 +524,21 @@ void QThread::terminate() } else { d->terminated = true; } +#else + if (!d->running) + return; + if (!d->terminationEnabled) { + d->terminatePending = true; + return; + } + + d->terminated = true; + QThreadPrivate::finish(this, false, false); + d->data->symbian_thread_handle.Terminate(KErrNone); + d->data->symbian_thread_handle.Close(); +#endif + + } bool QThread::wait(unsigned long time) @@ -489,11 +563,24 @@ bool QThread::wait(unsigned long time) void QThread::setTerminationEnabled(bool enabled) { - Q_ASSERT_X(currentThread() != 0, "QThread::setTerminationEnabled()", + QThread *thr = currentThread(); + Q_ASSERT_X(thr != 0, "QThread::setTerminationEnabled()", "Current thread was not started with QThread."); +#ifndef Q_OS_SYMBIAN pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, NULL); if (enabled) pthread_testcancel(); +#else + QThreadPrivate *d = thr->d_func(); + QMutexLocker locker(&d->mutex); + d->terminationEnabled = enabled; + if (enabled && d->terminatePending) { + d->terminated = true; + QThreadPrivate::finish(thr, false); + locker.unlock(); // don't leave the mutex locked! + pthread_exit(NULL); + } +#endif } void QThread::setPriority(Priority priority) diff --git a/src/corelib/tools/qalgorithms.h b/src/corelib/tools/qalgorithms.h index 3bfa6ad..35da4cd 100644 --- a/src/corelib/tools/qalgorithms.h +++ b/src/corelib/tools/qalgorithms.h @@ -142,7 +142,7 @@ inline void qCount(const Container &container, const T &value, Size &n) } -#if defined Q_CC_MSVC && _MSC_VER < 1300 +#if (defined Q_CC_MSVC && _MSC_VER < 1300) || defined(Q_CC_MWERKS) template <typename T> inline void qSwap(T &value1, T &value2) { diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h index f6422fb..55028f2 100644 --- a/src/corelib/tools/qbytearray.h +++ b/src/corelib/tools/qbytearray.h @@ -122,6 +122,17 @@ template <typename T> class QList; class Q_CORE_EXPORT QByteArray { +private: + struct Data { + QBasicAtomicInt ref; + int alloc, size; + // ### Qt 5.0: We need to add the missing capacity bit + // (like other tool classes have), to maintain the + // reserved memory on resize. + char *data; + char array[1]; + }; + public: inline QByteArray(); QByteArray(const char *); @@ -347,15 +358,6 @@ public: private: operator QNoImplicitBoolCast() const; - struct Data { - QBasicAtomicInt ref; - int alloc, size; - // ### Qt 5.0: We need to add the missing capacity bit - // (like other tool classes have), to maintain the - // reserved memory on resize. - char *data; - char array[1]; - }; static Data shared_null; static Data shared_empty; Data *d; diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp index e438179..917679c 100644 --- a/src/corelib/tools/qcryptographichash.cpp +++ b/src/corelib/tools/qcryptographichash.cpp @@ -41,6 +41,10 @@ #include <qcryptographichash.h> +#ifdef Q_OS_SYMBIAN +#define _MD5_H_ // Needed to disable system header +#endif + #include "../../3rdparty/md5/md5.h" #include "../../3rdparty/md5/md5.cpp" #include "../../3rdparty/md4/md4.h" diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 632c422..41b4794 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -911,7 +911,8 @@ public: inline QMultiHash operator+(const QMultiHash &other) const { QMultiHash result = *this; result += other; return result; } -#ifndef Q_NO_USING_KEYWORD +#if !defined(Q_NO_USING_KEYWORD) && !defined(Q_CC_RVCT) + // RVCT compiler doesn't handle using-keyword right when used functions are overloaded in child class using QHash<Key, T>::contains; using QHash<Key, T>::remove; using QHash<Key, T>::count; @@ -981,7 +982,12 @@ Q_INLINE_TEMPLATE int QMultiHash<Key, T>::remove(const Key &key, const T &value) typename QHash<Key, T>::iterator end(QHash<Key, T>::end()); while (i != end && i.key() == key) { if (i.value() == value) { +#if defined(Q_CC_RVCT) + // RVCT has problems with scoping, apparently. + i = QHash<Key, T>::erase(i); +#else i = erase(i); +#endif ++n; } else { ++i; diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index ab26945..4d042ae 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -123,6 +123,13 @@ Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok); Q_CORE_EXPORT qlonglong qstrtoll(const char *nptr, const char **endptr, register int base, bool *ok); static qulonglong qstrtoull(const char *nptr, const char **endptr, register int base, bool *ok); +#if defined(Q_CC_MWERKS) && defined(Q_OS_WIN32) +inline bool isascii(int c) +{ + return (c >= 0 && c <=127); +} +#endif + /****************************************************************************** ** Helpers for accessing Qt locale database */ @@ -291,7 +298,7 @@ static bool splitLocaleName(const QString &name, QChar *lang_begin, QChar *cntry return lang_len == 2 || lang_len == 3; } -static void getLangAndCountry(const QString &name, QLocale::Language &lang, QLocale::Country &cntry) +void getLangAndCountry(const QString &name, QLocale::Language &lang, QLocale::Country &cntry) { lang = QLocale::C; cntry = QLocale::AnyCountry; @@ -1271,7 +1278,7 @@ QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const return QVariant(); } -#elif defined(Q_OS_UNIX) +#elif defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) static uint unixGetSystemMeasurementSystem() { @@ -1315,7 +1322,7 @@ QVariant QSystemLocale::query(QueryType type, QVariant /* in */) const } } -#else +#elif !defined(Q_OS_SYMBIAN) /*! Returns a fallback locale, that will get used for everything that diff --git a/src/corelib/tools/qlocale_symbian.cpp b/src/corelib/tools/qlocale_symbian.cpp new file mode 100644 index 0000000..c11a7b9 --- /dev/null +++ b/src/corelib/tools/qlocale_symbian.cpp @@ -0,0 +1,878 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QDate> +#include <QLocale> +#include <QTime> +#include <QVariant> + +#include <e32std.h> +#include "private/qcore_symbian_p.h" + +// Located in qlocale.cpp +extern void getLangAndCountry(const QString &name, QLocale::Language &lang, QLocale::Country &cntry); + +QT_BEGIN_NAMESPACE + +static TExtendedLocale _s60Locale; + +// Type definitions for runtime resolved function pointers +typedef void (*FormatFunc)(TTime&, TDes&, const TDesC&, const TLocale&); +typedef TPtrC (*FormatSpecFunc)(TExtendedLocale&); + +// Runtime resolved functions +static FormatFunc ptrTimeFormatL = NULL; +static FormatSpecFunc ptrGetTimeFormatSpec = NULL; +static FormatSpecFunc ptrGetLongDateFormatSpec = NULL; +static FormatSpecFunc ptrGetShortDateFormatSpec = NULL; + +// Default functions if functions cannot be resolved +static void defaultTimeFormatL(TTime&, TDes& des, const TDesC&, const TLocale&) +{ + des.Zero(); +} + +static TPtrC defaultFormatSpec(TExtendedLocale&) +{ + return TPtrC(KNullDesC); +} + +/*! + Definition of struct for mapping Symbian to ISO locale +*/ +struct symbianToISO { + int symbian_language; + char iso_name[8]; +}; + + +/*! + Mapping from Symbian to ISO locale +*/ +static const symbianToISO symbian_to_iso_list[] = { + { ELangEnglish, "en_GB" }, + { ELangFrench, "fr_FR" }, + { ELangGerman, "de_DE" }, + { ELangSpanish, "es_ES" }, + { ELangItalian, "it_IT" }, + { ELangSwedish, "sv_SE" }, + { ELangDanish, "da_DK" }, + { ELangNorwegian, "no_NO" }, + { ELangFinnish, "fi_FI" }, + { ELangAmerican, "en_US" }, + { ELangPortuguese, "pt_PT" }, + { ELangTurkish, "tr_TR" }, + { ELangIcelandic, "is_IS" }, + { ELangRussian, "ru_RU" }, + { ELangHungarian, "hu_HU" }, + { ELangDutch, "nl_NL" }, + { ELangBelgianFlemish, "nl_BE" }, + { ELangCzech, "cs_CZ" }, + { ELangSlovak, "sk_SK" }, + { ELangPolish, "pl_PL" }, + { ELangSlovenian, "sl_SI" }, + { ELangTaiwanChinese, "zh_TW" }, + { ELangHongKongChinese, "zh_HK" }, + { ELangPrcChinese, "zh_CN" }, + { ELangJapanese, "ja_JP" }, + { ELangThai, "th_TH" }, + { ELangArabic, "ar_AE" }, + { ELangTagalog, "tl_PH" }, + { ELangBulgarian, "bg_BG" }, + { ELangCatalan, "ca_ES" }, + { ELangCroatian, "hr_HR" }, + { ELangEstonian, "et_EE" }, + { ELangFarsi, "fa_IR" }, + { ELangCanadianFrench, "fr_CA" }, + { ELangGreek, "el_GR" }, + { ELangHebrew, "he_IL" }, + { ELangHindi, "hi_IN" }, + { ELangIndonesian, "id_ID" }, + { ELangLatvian, "lv_LV" }, + { ELangLithuanian, "lt_LT" }, + { ELangMalay, "ms_MY" }, + { ELangBrazilianPortuguese, "pt_BR" }, + { ELangRomanian, "ro_RO" }, + { ELangSerbian, "sr_YU" }, + { ELangLatinAmericanSpanish, "es" }, + { ELangUkrainian, "uk_UA" }, + { ELangUrdu, "ur_PK" }, // India/Pakistan + { ELangVietnamese, "vi_VN" }, +#ifdef __E32LANG_H__ +// 5.0 + { ELangBasque, "eu_ES" }, + { ELangGalician, "gl_ES" }, +#endif +#if !defined(__SERIES60_31__) + { ELangEnglish_Apac, "en" }, + { ELangEnglish_Taiwan, "en_TW" }, + { ELangEnglish_HongKong, "en_HK" }, + { ELangEnglish_Prc, "en_CN" }, + { ELangEnglish_Japan, "en_JP"}, + { ELangEnglish_Thailand, "en_TH" }, + { ELangMalay_Apac, "ms" } +#endif +}; + +/*! + Returns ISO name corresponding to the Symbian locale code \a sys_fmt. +*/ +static QByteArray symbianLocaleName(int code) +{ + //Number of Symbian to ISO locale mappings + static const int symbian_to_iso_count + = sizeof(symbian_to_iso_list)/sizeof(symbianToISO); + + int cmp = code - symbian_to_iso_list[0].symbian_language; + if (cmp < 0) + return 0; + + if (cmp == 0) + return symbian_to_iso_list[0].iso_name; + + int begin = 0; + int end = symbian_to_iso_count; + + while (end - begin > 1) { + uint mid = (begin + end)/2; + + const symbianToISO *elt = symbian_to_iso_list + mid; + int cmp = code - elt->symbian_language; + if (cmp < 0) + end = mid; + else if (cmp > 0) + begin = mid; + else + return elt->iso_name; + } + + return 0; +} + + +// order is: normal, abbr, nmode, nmode+abbr +static const char *us_locale_dep[] = { + "MM", "dd", "yyyy", "MM", "dd", + "M", "d", "yy", "M", "d", + "MMMM", "dd", "yyyy", "MMMM", "dd", + "MMM", "d", "yy", "MMM", "d" }; + +static const char *eu_locale_dep[] = { + "dd", "MM", "yyyy", "dd", "MM", + "d", "M", "yy", "d", "M", + "dd", "MMMM", "yyyy", "dd", "MMMM", + "d", "MMM", "yy", "d", "MMM" }; + +static const char *jp_locale_dep[] = { + "yyyy", "MM", "dd", "MM", "dd", + "yy", "M", "d", "M", "d", + "yyyy", "MMMM", "dd", "MMMM", "dd", + "yy", "MMM", "d", "MMM", "d" }; + +/*! + Returns a Qt version of the given \a sys_fmt Symbian locale format string. +*/ +static QString s60ToQtFormat(const QString &sys_fmt) +{ + TLocale *locale = _s60Locale.GetLocale(); + + QString result; + QString other; + QString qtformatchars = QString::fromLatin1("adhmsyzAHM"); + + QChar c; + int i = 0; + bool open_escape = false; + bool abbrev_next = false; + bool locale_indep_ordering = false; + bool minus_mode = false; + bool plus_mode = false; + bool n_mode = false; + TTimeFormat tf = locale->TimeFormat(); + + while (i < sys_fmt.size()) { + + c = sys_fmt.at(i); + + // let formatting thru + if (c.unicode() == '%') { + // if we have gathered string, concat it + if (!other.isEmpty()) { + result += other; + other.clear(); + } + // if we have open escape, end it + if (open_escape) { + result += QLatin1Char('\''); + open_escape = false; + } + + ++i; + if (i >= sys_fmt.size()) + break; + + c = sys_fmt.at(i); + + // process specials + abbrev_next = c.unicode() == '*'; + plus_mode = c.unicode() == '+'; + minus_mode = c.unicode() == '-'; + + if (abbrev_next || plus_mode || minus_mode) { + ++i; + if (i >= sys_fmt.size()) + break; + + c = sys_fmt.at(i); + + if (plus_mode || minus_mode) { + // break on undefined plus/minus mode + if (c.unicode() != 'A' && c.unicode() != 'B') + break; + } + } + + switch (c.unicode()) { + case 'F': + { + // locale indep mode on + locale_indep_ordering = true; + break; + } + + case '/': + { + // date sep 0-3 + ++i; + if (i >= sys_fmt.size()) + break; + + c = sys_fmt.at(i); + if (c.isDigit() && c.digitValue() <= 3) { + TChar s = locale->DateSeparator(c.digitValue()); + TUint val = s; + // some indexes return zero for empty + if (val > 0) + result += QChar(val); + } + break; + } + + case 'D': + { + if (!locale_indep_ordering) + break; + + if (!abbrev_next) + result += QLatin1String("dd"); + else + result += QLatin1Char('d'); + + break; + } + + case 'M': + { + if (!locale_indep_ordering) + break; + + if (!n_mode) { + if (!abbrev_next) + result += QLatin1String("MM"); + else + result += QLatin1String("M"); + } else { + if (!abbrev_next) + result += QLatin1String("MMMM"); + else + result += QLatin1String("MMM"); + } + + break; + } + + case 'N': + { + n_mode = true; + + if (!locale_indep_ordering) + break; + + if (!abbrev_next) + result += QLatin1String("MMMM"); + else + result += QLatin1String("MMM"); + + break; + } + + case 'Y': + { + if (!locale_indep_ordering) + break; + + if (!abbrev_next) + result += QLatin1String("yyyy"); + else + result += QLatin1String("yy"); + + break; + } + + case 'E': + { + if (!abbrev_next) + result += QLatin1String("dddd"); + else + result += QLatin1String("ddd"); + + break; + } + + case ':': + { + // timesep 0-3 + ++i; + if (i >= sys_fmt.size()) + break; + + c = sys_fmt.at(i); + if (c.isDigit() && c.digitValue() <= 3) { + TChar s = locale->TimeSeparator(c.digitValue()); + TUint val = s; + // some indexes return zero for empty + if (val > 0) + result += QChar(val); + } + + break; + } + + case 'J': + { + if (tf == ETime24 && !abbrev_next) + result += QLatin1String("hh"); + else + result += QLatin1Char('h'); + + break; + } + + case 'H': + { + if (!abbrev_next) + result += QLatin1String("hh"); + else + result += QLatin1Char('h'); + + break; + } + + case 'I': + { + result += QLatin1Char('h'); + break; + } + + case 'T': + { + if (!abbrev_next) + result += QLatin1String("mm"); + else + result += QLatin1Char('m'); + + break; + } + + case 'S': + { + if (!abbrev_next) + result += QLatin1String("ss"); + else + result += QLatin1Char('s'); + + break; + } + + case 'B': + { + // only done for 12h clock + if (tf == ETime24) + break; + } + + // fallthru to A + case 'A': { + // quickie to get capitalization, can't use s60 string as is because Qt 'hh' format's am/pm logic + TAmPmName ampm = TAmPmName(); + TChar first(ampm[0]); + QString qtampm = QString::fromLatin1(first.IsUpper() ? "AP" : "ap"); + + int pos = locale->AmPmSymbolPosition(); + + if ((minus_mode && pos != ELocaleBefore) || + (plus_mode && pos != ELocaleAfter)) + break; + + if (!abbrev_next && locale->AmPmSpaceBetween()) { + if (pos == ELocaleBefore) + qtampm.append(QLatin1Char(' ')); + else + qtampm.prepend(QLatin1Char(' ')); + } + + result += qtampm; + } + break; + + case '.': { + // decimal sep + TChar s = locale->DecimalSeparator(); + TUint val = s; + if (val > 0) + result += QChar(val); + } + break; + + case 'C': + { + // six digits in s60, three digits in qt + if (!abbrev_next) { + result += QLatin1String("zzz"); + } else { + // next char is number from 0-6, how many digits to display + ++i; + if (i >= sys_fmt.size()) + break; + + c = sys_fmt.at(i); + + if (c.isDigit()) { + // try to match wanted digits + QChar val(c.digitValue()); + + if (val >= 3) { + result += QLatin1String("zzz"); + } else if (val > 0) { + result += QLatin1Char('z'); + } + } + } + break; + } + + // these cases fallthru + case '1': + case '2': + case '3': + case '4': + case '5': + { + + // shouldn't parse these with %F + if (locale_indep_ordering) + break; + + TDateFormat df = locale->DateFormat(); + + const char **locale_dep; + switch (df) { + default: // fallthru to american + case EDateAmerican: + locale_dep = us_locale_dep; + break; + case EDateEuropean: + locale_dep = eu_locale_dep; + break; + case EDateJapanese: + locale_dep = jp_locale_dep; + break; + } + int offset = 0; + if (abbrev_next) + offset += 5; + if (n_mode) + offset += 10; + + result += QLatin1String(locale_dep[offset + (c.digitValue()-1)]); + break; + } + + case '%': // fallthru percent + { + // any junk gets copied as is + } + default: + { + result += c; + break; + } + + case 'Z': // Qt doesn't support these :( + case 'X': + case 'W': + { + break; + } + } + } else { + // double any single quotes, don't begin escape + if (c.unicode() == '\'') { + // end open escape + if (open_escape) { + result += other; + other.clear(); + result += QLatin1Char('\''); + open_escape = false; + } + + other += c; + } + + // gather chars and escape them in one go if any format chars are found + if (!open_escape && qtformatchars.indexOf(c) != -1) { + result += QLatin1Char('\''); + open_escape = true; + } + other += c; + } + + ++i; + } + + if (!other.isEmpty()) + result += other; + if (open_escape) + result += QLatin1Char('\''); + + return result; +} + +/*! + Retrieves Symbian locale decimal separator. +*/ +static QString symbianDecimalPoint() +{ + TLocale *locale = _s60Locale.GetLocale(); + + TChar decPoint = locale->DecimalSeparator(); + int val = decPoint; + return QChar(val); +} + +/*! + Retrieves Symbian locale group separator. +*/ +static QString symbianGroupSeparator() +{ + TLocale *locale = _s60Locale.GetLocale(); + + TChar grpSep = locale->ThousandsSeparator(); + int val = grpSep; + return QChar(val); +} + +/*! + Retrieves Symbian locale zero digit. +*/ +static QString symbianZeroDigit() +{ + TLocale *locale = _s60Locale.GetLocale(); + + // TDigitType enumeration value returned by TLocale + // will always correspond to zero digit unicode value. + TDigitType digit = locale->DigitType(); + return QChar(digit); +} + +/*! + Retrieves a day name from Symbian locale. The \a day is an integer + from 1 to 7. When \a short_format is true the method returns + the day in short format. Otherwise it returns the day in a long format. +*/ +static QString symbianDayName(int day, bool short_format) +{ + day -= 1; + + if (day < 0 || day > 6) + return QString(); + + if (short_format) { + return qt_TDes2QStringL(TDayNameAbb(TDay(day))); + } else { + return qt_TDes2QStringL(TDayName(TDay(day))); + } +} + +/*! + Retrieves a month name from Symbian locale. The \a month is an integer + from 1 to 12. When \a short_format is true the method returns + the month in short format. Otherwise it returns the month in a long format. +*/ +static QString symbianMonthName(int month, bool short_format) +{ + month -= 1; + if (month < 0 || month > 11) + return QString(); + + if (short_format) { + return qt_TDes2QStringL(TMonthNameAbb(TMonth(month))); + } else { + return qt_TDes2QStringL(TMonthName(TMonth(month))); + } +} + +/*! + Retrieves date format from Symbian locale and + transforms it to Qt format. + + When \a short_format is true the method returns + short date format. Otherwise it returns the long format. +*/ +static QString symbianDateFormat(bool short_format) +{ + TPtrC dateFormat; + + if (short_format) { + dateFormat.Set(ptrGetShortDateFormatSpec(_s60Locale)); + } else { + dateFormat.Set(ptrGetLongDateFormatSpec(_s60Locale)); + } + + return s60ToQtFormat(qt_TDesC2QStringL(dateFormat)); +} + +/*! + Retrieves time format from Symbian locale and + transforms it to Qt format. +*/ +static QString symbianTimeFormat() +{ + return s60ToQtFormat(qt_TDesC2QStringL(ptrGetTimeFormatSpec(_s60Locale))); +} + +/*! + Returns localized string representation of given \a date + formatted with Symbian locale date format. + + If \a short_format is true the format will be a short version. + Otherwise it uses a longer version. +*/ +static QString symbianDateToString(const QDate &date, bool short_format) +{ + int month = date.month() - 1; + int day = date.day() - 1; + int year = date.year(); + + TDateTime dateTime; + dateTime.Set(year, TMonth(month), day, 0, 0, 0, 0); + + TTime timeStr(dateTime); + TBuf<KMaxLongDateFormatSpec*2> buffer; + + TPtrC dateFormat; + if (short_format) { + dateFormat.Set(ptrGetShortDateFormatSpec(_s60Locale)); + } else { + dateFormat.Set(ptrGetLongDateFormatSpec(_s60Locale)); + } + + TRAPD(err, ptrTimeFormatL(timeStr, buffer, dateFormat, *_s60Locale.GetLocale());) + + if (err == KErrNone) + return qt_TDes2QStringL(buffer); + else + return QString(); +} + +/*! + Returns localized string representation of given \a time + formatted with Symbian locale time format. +*/ +static QString symbianTimeToString(const QTime &time) +{ + int hour = time.hour(); + int minute = time.minute(); + int second = time.second(); + int milliseconds = 0; + + TDateTime dateTime; + dateTime.Set(0, TMonth(0), 0, hour, minute, second, milliseconds); + + TTime timeStr(dateTime); + TBuf<KMaxTimeFormatSpec*2> buffer; + + TRAPD(err, ptrTimeFormatL( + timeStr, + buffer, + ptrGetTimeFormatSpec(_s60Locale), + *_s60Locale.GetLocale()); + ) + + if (err == KErrNone) + return qt_TDes2QStringL(buffer); + else + return QString(); +} + +/*! + Returns the measurement system stored in Symbian locale + + \sa QLocale::MeasurementSystem +*/ +static QLocale::MeasurementSystem symbianMeasurementSystem() +{ + TLocale *locale = _s60Locale.GetLocale(); + + TUnitsFormat unitFormat = locale->UnitsGeneral(); + if (unitFormat == EUnitsImperial) + return QLocale::ImperialSystem; + else + return QLocale::MetricSystem; +} + +QLocale QSystemLocale::fallbackLocale() const +{ + // load system data before query calls + static bool initDone = false; + if (!initDone) { + _s60Locale.LoadSystemSettings(); + + // Initialize platform version dependent function pointers + ptrTimeFormatL = reinterpret_cast<FormatFunc> + (qt_resolveS60PluginFunc(S60Plugin_TimeFormatL)); + ptrGetTimeFormatSpec = reinterpret_cast<FormatSpecFunc> + (qt_resolveS60PluginFunc(S60Plugin_GetTimeFormatSpec)); + ptrGetLongDateFormatSpec = reinterpret_cast<FormatSpecFunc> + (qt_resolveS60PluginFunc(S60Plugin_GetLongDateFormatSpec)); + ptrGetShortDateFormatSpec = reinterpret_cast<FormatSpecFunc> + (qt_resolveS60PluginFunc(S60Plugin_GetShortDateFormatSpec)); + if (!ptrTimeFormatL) + ptrTimeFormatL = &defaultTimeFormatL; + if (!ptrGetTimeFormatSpec) + ptrGetTimeFormatSpec = &defaultFormatSpec; + if (!ptrGetLongDateFormatSpec) + ptrGetLongDateFormatSpec = &defaultFormatSpec; + if (!ptrGetShortDateFormatSpec) + ptrGetShortDateFormatSpec = &defaultFormatSpec; + } + + TLanguage lang = User::Language(); + QString locale = symbianLocaleName(lang); + return QLocale(locale); +} + +/*! + Generic query method for locale data. Provides indirection. + Denotes the \a type of the query + with \a in as input data depending on the query. + + \sa QSystemLocale::QueryType +*/ +QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const +{ + switch(type) { + case DecimalPoint: + return symbianDecimalPoint(); + case GroupSeparator: + return symbianGroupSeparator(); + + case ZeroDigit: + return symbianZeroDigit(); + + case DayNameLong: + case DayNameShort: + return symbianDayName(in.toInt(), (type == DayNameShort) ); + + case MonthNameLong: + case MonthNameShort: + return symbianMonthName(in.toInt(), (type == MonthNameShort) ); + + case DateFormatLong: + case DateFormatShort: + return symbianDateFormat( (type == DateFormatShort) ); + case TimeFormatLong: + case TimeFormatShort: + return symbianTimeFormat(); + case DateTimeFormatLong: + case DateTimeFormatShort: + return symbianDateFormat( (type == DateTimeFormatShort) ) + QLatin1Char(' ') + symbianTimeFormat(); + case DateToStringShort: + case DateToStringLong: + return symbianDateToString(in.toDate(), (type == DateToStringShort) ); + case TimeToStringShort: + case TimeToStringLong: + return symbianTimeToString(in.toTime()); + case DateTimeToStringShort: + case DateTimeToStringLong: { + const QDateTime dt = in.toDateTime(); + return symbianDateToString(dt.date(), (type == DateTimeToStringShort) ) + + QLatin1Char(' ') + symbianTimeToString(dt.time()); + } + case MeasurementSystem: + return static_cast<int>(symbianMeasurementSystem()); + case LanguageId: + case CountryId: { + TLanguage language = User::Language(); + QString locale = symbianLocaleName(language); + QLocale::Language lang; + QLocale::Country cntry; + getLangAndCountry(locale, lang, cntry); + if (type == LanguageId) + return lang; + // few iso codes have no country and will use this + if (cntry == QLocale::AnyCountry) + return fallbackLocale().country(); + + return cntry; + } + case NegativeSign: + case PositiveSign: + case AMText: + case PMText: + break; + default: + break; + } + return QVariant(); +} + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index 5f13e5a..0215a78 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -923,7 +923,8 @@ public: inline QMultiMap operator+(const QMultiMap &other) const { QMultiMap result = *this; result += other; return result; } -#ifndef Q_NO_USING_KEYWORD +#if !defined(Q_NO_USING_KEYWORD) && !defined(Q_CC_RVCT) + // RVCT compiler doesn't handle using-keyword right when used functions are overloaded in child class using QMap<Key, T>::contains; using QMap<Key, T>::remove; using QMap<Key, T>::count; @@ -993,7 +994,12 @@ Q_INLINE_TEMPLATE int QMultiMap<Key, T>::remove(const Key &key, const T &value) typename QMap<Key, T>::const_iterator end(QMap<Key, T>::constEnd()); while (i != end && !qMapLessThanKey<Key>(key, i.key())) { if (i.value() == value) { +#if defined(Q_CC_RVCT) + // RVCT has problems with scoping, apparently. + i = QMap<Key, T>::erase(i); +#else i = erase(i); +#endif ++n; } else { ++i; diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index ad2d9f2..88b8b8c 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -109,13 +109,19 @@ namespace QtSharedPointer { template <class T> class Basic { +#ifndef Q_CC_NOKIAX86 typedef T *Basic:: *RestrictedBool; +#endif public: typedef T Type; inline T *data() const { return value; } inline bool isNull() const { return !data(); } +#ifndef Q_CC_NOKIAX86 inline operator RestrictedBool() const { return isNull() ? 0 : &Basic::value; } +#else + inline operator bool() const { return isNull() ? 0 : &Basic::value; } +#endif inline bool operator !() const { return isNull(); } inline T &operator*() const { return *data(); } inline T *operator->() const { return data(); } @@ -249,7 +255,7 @@ namespace QtSharedPointer { if (o && !o->strongref) o = 0; if (o) { - verifyReconstruction(actual); + Basic<T>::verifyReconstruction(actual); o->weakref.ref(); o->strongref.ref(); } @@ -277,15 +283,15 @@ public: inline QSharedPointer() { } // inline ~QSharedPointer() { } - inline explicit QSharedPointer(T *ptr) { internalConstruct(ptr); } + inline explicit QSharedPointer(T *ptr) { BaseClass::internalConstruct(ptr); } template <typename Deleter> - inline QSharedPointer(T *ptr, Deleter d) { internalConstruct(ptr, d); } + inline QSharedPointer(T *ptr, Deleter d) { BaseClass::internalConstruct(ptr, d); } inline QSharedPointer(const QSharedPointer<T> &other) : BaseClass(other) { } inline QSharedPointer<T> &operator=(const QSharedPointer<T> &other) { - internalCopy(other); + BaseClass::internalCopy(other); return *this; } @@ -301,7 +307,7 @@ public: inline QSharedPointer<T> &operator=(const QSharedPointer<X> &other) { QSHAREDPOINTER_VERIFY_AUTO_CAST(T, X); // if you get an error in this line, the cast is invalid - internalCopy(other); + BaseClass::internalCopy(other); return *this; } @@ -339,12 +345,18 @@ public: template <class T> class QWeakPointer { +#ifndef Q_CC_NOKIAX86 typedef T *QWeakPointer:: *RestrictedBool; +#endif typedef QtSharedPointer::ExternalRefCountData Data; public: inline bool isNull() const { return d == 0 || d->strongref == 0 || value == 0; } +#ifndef Q_CC_NOKIAX86 inline operator RestrictedBool() const { return isNull() ? 0 : &QWeakPointer::value; } +#else + inline operator bool() const { return isNull() ? 0 : &QWeakPointer::value; } +#endif inline bool operator !() const { return isNull(); } inline QWeakPointer() : d(0), value(0) { } diff --git a/src/corelib/tools/qtextboundaryfinder.cpp b/src/corelib/tools/qtextboundaryfinder.cpp index bc9b675..8a8e95b 100644 --- a/src/corelib/tools/qtextboundaryfinder.cpp +++ b/src/corelib/tools/qtextboundaryfinder.cpp @@ -38,11 +38,11 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#include "private/qharfbuzz_p.h" #include <QtCore/qtextboundaryfinder.h> #include <QtCore/qvarlengtharray.h> #include <private/qunicodetables_p.h> #include <qdebug.h> +#include "private/qharfbuzz_p.h" QT_BEGIN_NAMESPACE diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index e5bf7e4..c2381ce 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -65,6 +65,7 @@ SOURCES += \ tools/qvector.cpp \ tools/qvsnprintf.cpp +symbian:SOURCES+=tools/qlocale_symbian.cpp #zlib support contains(QT_CONFIG, zlib) { @@ -101,4 +102,7 @@ SOURCES += ../3rdparty/harfbuzz/src/harfbuzz-buffer.c \ tools/qharfbuzz.cpp HEADERS += tools/qharfbuzz_p.h -!macx-icc:unix:LIBS += -lm +INCLUDEPATH += ../3rdparty/md5 \ + ../3rdparty/md4 + +!macx-icc:unix:!symbian:LIBS += -lm diff --git a/src/gui/dialogs/dialogs.pri b/src/gui/dialogs/dialogs.pri index f1ec858..92347a7 100644 --- a/src/gui/dialogs/dialogs.pri +++ b/src/gui/dialogs/dialogs.pri @@ -45,7 +45,7 @@ win32 { !win32-borland:!wince*: LIBS += -lshell32 # the filedialog needs this library } -!mac:!embedded:unix { +!mac:!embedded:!symbian:unix { HEADERS += dialogs/qpagesetupdialog_unix_p.h SOURCES += dialogs/qprintdialog_unix.cpp \ dialogs/qpagesetupdialog_unix.cpp @@ -70,7 +70,7 @@ embedded { } } -wince*: FORMS += dialogs/qfiledialog_wince.ui +wince*|symbian: FORMS += dialogs/qfiledialog_embedded.ui else: FORMS += dialogs/qfiledialog.ui INCLUDEPATH += $$PWD @@ -94,4 +94,4 @@ SOURCES += \ FORMS += dialogs/qpagesetupwidget.ui RESOURCES += dialogs/qprintdialog.qrc -RESOURCES += dialogs/qmessagebox.qrc
\ No newline at end of file +RESOURCES += dialogs/qmessagebox.qrc diff --git a/src/gui/dialogs/qdialog.cpp b/src/gui/dialogs/qdialog.cpp index 14d8162..ef562f4 100644 --- a/src/gui/dialogs/qdialog.cpp +++ b/src/gui/dialogs/qdialog.cpp @@ -64,8 +64,12 @@ extern bool qt_wince_is_mobile(); //defined in qguifunctions_wce.cpp extern bool qt_wince_is_smartphone(); //is defined in qguifunctions_wce.cpp #elif defined(Q_WS_X11) # include "../kernel/qt_x11_p.h" +#elif defined(Q_WS_S60) +# include "qfiledialog.h" +#endif +#if defined(Q_OS_SYMBIAN) +#include "qmenubar.h" #endif - #ifndef SPI_GETSNAPTODEFBUTTON # define SPI_GETSNAPTODEFBUTTON 95 #endif @@ -486,7 +490,22 @@ int QDialog::exec() #endif //QT_NO_MENUBAR #endif //Q_OS_WINCE_WM +#ifdef Q_OS_SYMBIAN +#ifndef QT_NO_MENUBAR + QMenuBar *menuBar = 0; + if (!findChild<QMenuBar *>()) + menuBar = new QMenuBar(this); +#endif +#endif + +#if !defined(Q_WS_S60) show(); +#else + if (qobject_cast<QFileDialog *>(this)) + showFullScreen(); + else + show(); +#endif #ifdef Q_WS_MAC d->mac_nativeDialogModalHelp(); @@ -511,6 +530,13 @@ int QDialog::exec() delete menuBar; #endif //QT_NO_MENUBAR #endif //Q_OS_WINCE_WM +#ifdef Q_OS_SYMBIAN +#ifndef QT_NO_MENUBAR + else if (menuBar) + delete menuBar; +#endif //QT_NO_MENUBAR +#endif //Q_OS_SYMBIAN + return res; } diff --git a/src/gui/dialogs/qfiledialog.cpp b/src/gui/dialogs/qfiledialog.cpp index 77382a7..aab79d0 100644 --- a/src/gui/dialogs/qfiledialog.cpp +++ b/src/gui/dialogs/qfiledialog.cpp @@ -58,12 +58,15 @@ #include <qdebug.h> #include <qapplication.h> #include <qstylepainter.h> -#ifndef Q_OS_WINCE +#if !defined(Q_OS_WINCE) && !defined(Q_WS_S60) #include "ui_qfiledialog.h" #else -#include "ui_qfiledialog_wince.h" +#define Q_EMBEDDED_SMALLSCREEN +#include "ui_qfiledialog_embedded.h" +#if defined(Q_OS_WINCE) extern bool qt_priv_ptr_valid; #endif +#endif QT_BEGIN_NAMESPACE @@ -2078,7 +2081,7 @@ void QFileDialogPrivate::init(const QString &directory, const QString &nameFilte q->restoreState(settings.value(QLatin1String("filedialog")).toByteArray()); #endif -#ifdef Q_OS_WINCE +#if defined(Q_EMBEDDED_SMALLSCREEN) qFileDialogUi->lookInLabel->setVisible(false); qFileDialogUi->fileNameLabel->setVisible(false); qFileDialogUi->fileTypeLabel->setVisible(false); @@ -3191,7 +3194,10 @@ QStringList QFSCompletor::splitPath(const QString &path) const QString pathCopy = QDir::toNativeSeparators(path); QString sep = QDir::separator(); -#ifdef Q_OS_WIN +#if defined(Q_OS_SYMBIAN) + if (pathCopy == QLatin1String("\\")) + return QStringList(pathCopy); +#elif defined(Q_OS_WIN) if (pathCopy == QLatin1String("\\") || pathCopy == QLatin1String("\\\\")) return QStringList(pathCopy); QString doubleSlash(QLatin1String("\\\\")); @@ -3203,7 +3209,11 @@ QStringList QFSCompletor::splitPath(const QString &path) const QRegExp re(QLatin1String("[") + QRegExp::escape(sep) + QLatin1String("]")); -#ifdef Q_OS_WIN +#if defined(Q_OS_SYMBIAN) + QStringList parts = pathCopy.split(re, QString::SkipEmptyParts); + if (pathCopy.endsWith(sep)) + parts.append(QString()); +#elif defined(Q_OS_WIN) QStringList parts = pathCopy.split(re, QString::SkipEmptyParts); if (!doubleSlash.isEmpty() && !parts.isEmpty()) parts[0].prepend(doubleSlash); @@ -3215,7 +3225,7 @@ QStringList QFSCompletor::splitPath(const QString &path) const parts[0] = sep[0]; #endif -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) bool startsFromRoot = !parts.isEmpty() && parts[0].endsWith(QLatin1Char(':')); #else bool startsFromRoot = path[0] == sep[0]; diff --git a/src/gui/dialogs/qfiledialog_wince.ui b/src/gui/dialogs/qfiledialog_embedded.ui index 8aa9e1b..8aa9e1b 100644 --- a/src/gui/dialogs/qfiledialog_wince.ui +++ b/src/gui/dialogs/qfiledialog_embedded.ui diff --git a/src/gui/dialogs/qfiledialog_p.h b/src/gui/dialogs/qfiledialog_p.h index ab4199e..de7e332 100644 --- a/src/gui/dialogs/qfiledialog_p.h +++ b/src/gui/dialogs/qfiledialog_p.h @@ -99,7 +99,7 @@ class QFSCompletor : public QCompleter { public: QFSCompletor(QFileSystemModel *model, QObject *parent = 0) : QCompleter(model, parent), proxyModel(0), sourceModel(model) { -#ifdef Q_OS_WIN +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) setCaseSensitivity(Qt::CaseInsensitive); #endif } @@ -224,7 +224,7 @@ public: static inline QString toInternal(const QString &path) { -#if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) +#if defined(Q_FS_FAT) || defined(Q_OS_OS2EMX) || defined(Q_OS_SYMBIAN) QString n(path); for (int i = 0; i < (int)n.length(); ++i) if (n[i] == QLatin1Char('\\')) n[i] = QLatin1Char('/'); @@ -295,7 +295,7 @@ public: bool defaultFileTypes; bool fileNameLabelExplicitlySat; QStringList nameFilters; - + // Members for using native dialogs: bool nativeDialogInUse; // setVisible_sys returns true if it ends up showing a native diff --git a/src/gui/dialogs/qfileinfogatherer.cpp b/src/gui/dialogs/qfileinfogatherer.cpp index 23a2cbc..a2abe54 100644 --- a/src/gui/dialogs/qfileinfogatherer.cpp +++ b/src/gui/dialogs/qfileinfogatherer.cpp @@ -287,6 +287,8 @@ QString QFileInfoGatherer::translateDriveName(const QFileInfo &drive) const #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) if (driveName.startsWith(QLatin1Char('/'))) // UNC host return drive.fileName(); +#endif +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) if (driveName.endsWith(QLatin1Char('/'))) driveName.chop(1); #endif diff --git a/src/gui/dialogs/qfilesystemmodel.cpp b/src/gui/dialogs/qfilesystemmodel.cpp index 03017c3..44adc75 100644 --- a/src/gui/dialogs/qfilesystemmodel.cpp +++ b/src/gui/dialogs/qfilesystemmodel.cpp @@ -355,7 +355,7 @@ QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QS // ### TODO can we use bool QAbstractFileEngine::caseSensitive() const? QStringList pathElements = absolutePath.split(QLatin1Char('/'), QString::SkipEmptyParts); if ((pathElements.isEmpty()) -#if !defined(Q_OS_WIN) || defined(Q_OS_WINCE) +#if (!defined(Q_OS_WIN) || defined(Q_OS_WINCE)) && !defined(Q_OS_SYMBIAN) && QDir::fromNativeSeparators(longPath) != QLatin1String("/") #endif ) @@ -384,9 +384,21 @@ QFileSystemModelPrivate::QFileSystemNode *QFileSystemModelPrivate::node(const QS r = translateVisibleLocation(rootNode, r); index = q->index(r, 0, QModelIndex()); pathElements.pop_front(); - } else { + } else +#endif + +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + { if (!pathElements.at(0).contains(QLatin1String(":"))) +#if defined(Q_CC_NOKIAX86) + { + // Workaround for bizarre compiler crash. + QString rootPath = QDir(longPath).rootPath(); + pathElements.prepend(rootPath); + } +#else pathElements.prepend(QDir(longPath).rootPath()); +#endif if (pathElements.at(0).endsWith(QLatin1Char('/'))) pathElements[0].chop(1); } @@ -1596,12 +1608,25 @@ void QFileSystemModelPrivate::_q_directoryChanged(const QString &directory, cons if (parentNode->children.count() == 0) return; QStringList toRemove; +#if defined(Q_OS_SYMBIAN) + // Filename case must be exact in qBinaryFind below, so create a list of all lowercase names. + QStringList newFiles; + for(int i = 0; i < files.size(); i++) { + newFiles << files.at(i).toLower(); + } +#else QStringList newFiles = files; +#endif qSort(newFiles.begin(), newFiles.end()); QHash<QString, QFileSystemNode*>::const_iterator i = parentNode->children.constBegin(); while (i != parentNode->children.constEnd()) { QStringList::iterator iterator; - iterator = qBinaryFind(newFiles.begin(), newFiles.end(), i.value()->fileName); + iterator = qBinaryFind(newFiles.begin(), newFiles.end(), +#if defined(Q_OS_SYMBIAN) + i.value()->fileName.toLower()); +#else + i.value()->fileName); +#endif if (iterator == newFiles.end()) { toRemove.append(i.value()->fileName); } @@ -1924,8 +1949,8 @@ bool QFileSystemModelPrivate::passNameFilters(const QFileSystemNode *node) const return true; } -#include "moc_qfilesystemmodel.cpp" +QT_END_NAMESPACE -#endif // QT_NO_FILESYSTEMMODEL +#include "moc_qfilesystemmodel.cpp" -QT_END_NAMESPACE +#endif // QT_NO_FILESYSTEMMODEL
\ No newline at end of file diff --git a/src/gui/dialogs/qmessagebox.cpp b/src/gui/dialogs/qmessagebox.cpp index b121a8f..00baf01 100644 --- a/src/gui/dialogs/qmessagebox.cpp +++ b/src/gui/dialogs/qmessagebox.cpp @@ -275,7 +275,7 @@ void QMessageBoxPrivate::updateSize() #ifdef Q_WS_QWS // the width of the screen, less the window border. int hardLimit = screenSize.width() - (q->frameGeometry().width() - q->geometry().width()); -#elif defined(Q_OS_WINCE) +#elif defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) // the width of the screen, less the window border. int hardLimit = screenSize.width() - (q->frameGeometry().width() - q->geometry().width()); #else diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index e8ace65..ed1891c 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -515,6 +515,7 @@ #include <QtGui/qpixmapcache.h> #include <QtGui/qstyleoption.h> #include <QtGui/qevent.h> +#include <QInputContext> #include <private/qgraphicsitem_p.h> #include <private/qgraphicswidget_p.h> @@ -7609,7 +7610,7 @@ class QGraphicsTextItemPrivate { public: QGraphicsTextItemPrivate() - : control(0), pageNumber(0), useDefaultImpl(false), tabChangesFocus(false) + : control(0), pageNumber(0), useDefaultImpl(false), tabChangesFocus(false), clickCausedFocus(0) { } mutable QTextControl *control; @@ -7630,6 +7631,8 @@ public: bool useDefaultImpl; bool tabChangesFocus; + uint clickCausedFocus : 1; + QGraphicsTextItem *qq; }; @@ -7956,7 +7959,13 @@ void QGraphicsTextItem::mousePressEvent(QGraphicsSceneMouseEvent *event) dd->useDefaultImpl = false; return; } + dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -7968,7 +7977,13 @@ void QGraphicsTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) QGraphicsItem::mouseMoveEvent(event); return; } + dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -7988,7 +8003,23 @@ void QGraphicsTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) } return; } + + if (event->button() == Qt::LeftButton && qApp->autoSipEnabled() + && (!dd->clickCausedFocus || qApp->autoSipOnMouseFocus())) { + QEvent _event(QEvent::RequestSoftwareInputPanel); + QApplication::sendEvent(event->widget(), &_event); + } else { + QGraphicsItem::mouseReleaseEvent(event); + } + dd->clickCausedFocus = 0; + dd->sendControlEvent(event); + + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8007,6 +8038,11 @@ void QGraphicsTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) } dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8015,6 +8051,11 @@ void QGraphicsTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) void QGraphicsTextItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) { dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8023,6 +8064,18 @@ void QGraphicsTextItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) void QGraphicsTextItem::keyPressEvent(QKeyEvent *event) { dd->sendControlEvent(event); + QList<QGraphicsView *> views = scene()->views(); + for (int i = 0; i < views.size(); ++i) { + QGraphicsView *view = views.at(i); + Q_ASSERT(view->viewport()); + if(view->viewport()->hasFocus()) { + QInputContext *qic = view->viewport()->inputContext(); + if(qic){ + qic->update(); + } + break; + } + } } /*! @@ -8031,6 +8084,18 @@ void QGraphicsTextItem::keyPressEvent(QKeyEvent *event) void QGraphicsTextItem::keyReleaseEvent(QKeyEvent *event) { dd->sendControlEvent(event); + QList<QGraphicsView *> views = scene()->views(); + for (int i = 0; i < views.size(); ++i) { + QGraphicsView *view = views.at(i); + Q_ASSERT(view->viewport()); + if(view->viewport()->hasFocus()) { + QInputContext *qic = view->viewport()->inputContext(); + if(qic){ + qic->update(); + } + break; + } + } } /*! @@ -8039,7 +8104,22 @@ void QGraphicsTextItem::keyReleaseEvent(QKeyEvent *event) void QGraphicsTextItem::focusInEvent(QFocusEvent *event) { dd->sendControlEvent(event); + if (event->reason() == Qt::MouseFocusReason) { + dd->clickCausedFocus = 1; + } update(); + QList<QGraphicsView *> views = scene()->views(); + for (int i = 0; i < views.size(); ++i) { + QGraphicsView *view = views.at(i); + Q_ASSERT(view->viewport()); + if(view->viewport()->hasFocus()) { + QInputContext *qic = view->viewport()->inputContext(); + if(qic){ + qic->reset(); + } + break; + } + } } /*! @@ -8049,6 +8129,18 @@ void QGraphicsTextItem::focusOutEvent(QFocusEvent *event) { dd->sendControlEvent(event); update(); + QList<QGraphicsView *> views = scene()->views(); + for (int i = 0; i < views.size(); ++i) { + QGraphicsView *view = views.at(i); + Q_ASSERT(view->viewport()); + if(view->viewport()->hasFocus()) { + QInputContext *qic = view->viewport()->inputContext(); + if(qic){ + qic->reset(); + } + break; + } + } } /*! @@ -8057,6 +8149,11 @@ void QGraphicsTextItem::focusOutEvent(QFocusEvent *event) void QGraphicsTextItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event) { dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8065,6 +8162,11 @@ void QGraphicsTextItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event) void QGraphicsTextItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event) { dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8073,6 +8175,11 @@ void QGraphicsTextItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event) void QGraphicsTextItem::dragMoveEvent(QGraphicsSceneDragDropEvent *event) { dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8081,6 +8188,11 @@ void QGraphicsTextItem::dragMoveEvent(QGraphicsSceneDragDropEvent *event) void QGraphicsTextItem::dropEvent(QGraphicsSceneDragDropEvent *event) { dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8097,6 +8209,11 @@ void QGraphicsTextItem::inputMethodEvent(QInputMethodEvent *event) void QGraphicsTextItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8105,6 +8222,11 @@ void QGraphicsTextItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) void QGraphicsTextItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) { dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! @@ -8113,6 +8235,11 @@ void QGraphicsTextItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) void QGraphicsTextItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { dd->sendControlEvent(event); + Q_ASSERT(event->widget()); + QInputContext *qic = event->widget()->inputContext(); + if(qic) { + qic->update(); + } } /*! diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index a795fb4..8137f8e 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -1195,6 +1195,11 @@ QGraphicsView::QGraphicsView(QWidget *parent) // using a simple reference count. The same goes for acceptDrops and mouse // tracking. setAttribute(Qt::WA_InputMethodEnabled); + + // viewport part of the graphics view has to be enabled + // as well, because when events come this widget is asked + // for input context and so on + viewport()->setAttribute(Qt::WA_InputMethodEnabled); } /*! @@ -1209,6 +1214,11 @@ QGraphicsView::QGraphicsView(QGraphicsScene *scene, QWidget *parent) setAcceptDrops(true); setBackgroundRole(QPalette::Base); setAttribute(Qt::WA_InputMethodEnabled); + + // viewport part of the graphics view has to be enabled + // as well, because when events come this widget is asked + // for input context and so on + viewport()->setAttribute(Qt::WA_InputMethodEnabled); } /*! @@ -1221,6 +1231,11 @@ QGraphicsView::QGraphicsView(QGraphicsViewPrivate &dd, QWidget *parent) setAcceptDrops(true); setBackgroundRole(QPalette::Base); setAttribute(Qt::WA_InputMethodEnabled); + + // viewport part of the graphics view has to be enabled + // as well, because when events come this widget is asked + // for input context and so on + viewport()->setAttribute(Qt::WA_InputMethodEnabled); } /*! diff --git a/src/gui/gui.pro b/src/gui/gui.pro index f224e67..30aaa51 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -4,7 +4,7 @@ QT = core DEFINES += QT_BUILD_GUI_LIB QT_NO_USING_NAMESPACE win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x65000000 -!win32:!embedded:!mac:CONFIG += x11 +!win32:!embedded:!mac:!symbian:CONFIG += x11 unix:QMAKE_PKGCONFIG_REQUIRES = QtCore @@ -42,3 +42,7 @@ QMAKE_DYNAMIC_LIST_FILE = $$PWD/QtGui.dynlist DEFINES += Q_INTERNAL_QAPP_SRC +symbian:TARGET.UID3=0x2001B2DD + +# ro-section in gui can exceed default allocated space, so more rw-section little further +symbian-sbsv2: MMP_RULES += "LINKEROPTION armcc --rw-base 0x800000"
\ No newline at end of file diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri index ca52974..b5e3ee5 100644 --- a/src/gui/image/image.pri +++ b/src/gui/image/image.pri @@ -61,6 +61,9 @@ mac { HEADERS += image/qpixmap_mac_p.h SOURCES += image/qpixmap_mac.cpp } +symbian { + SOURCES += image/qpixmap_s60.cpp +} # Built-in image format support HEADERS += \ diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index 7fcb2b9..f85e21a 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -76,6 +76,10 @@ # include <private/qpixmap_x11_p.h> #endif +#if defined(Q_OS_SYMBIAN) +# include <private/qt_s60_p.h> +#endif + #include "qpixmap_raster_p.h" QT_BEGIN_NAMESPACE @@ -1859,7 +1863,10 @@ int QPixmap::defaultDepth() return 32; // XXX #elif defined(Q_WS_MAC) return 32; +#elif defined(Q_OS_SYMBIAN) + return S60->screenDepth; #endif + } typedef void (*_qt_pixmap_cleanup_hook_64)(qint64); diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h index 1863273..9ef5347 100644 --- a/src/gui/image/qpixmap.h +++ b/src/gui/image/qpixmap.h @@ -62,6 +62,10 @@ class QX11Info; class QPixmapData; +#if defined(Q_OS_SYMBIAN) +class CFbsBitmap; +#endif + class Q_GUI_EXPORT QPixmap : public QPaintDevice { public: @@ -152,6 +156,11 @@ public: static QPixmap fromMacCGImageRef(CGImageRef image); #endif +#if defined(Q_OS_SYMBIAN) + CFbsBitmap *toSymbianCFbsBitmap() const; + static QPixmap fromSymbianCFbsBitmap(CFbsBitmap *bitmap); +#endif + inline QPixmap copy(int x, int y, int width, int height) const; QPixmap copy(const QRect &rect = QRect()) const; diff --git a/src/gui/image/qpixmap_s60.cpp b/src/gui/image/qpixmap_s60.cpp new file mode 100644 index 0000000..3ea50ff --- /dev/null +++ b/src/gui/image/qpixmap_s60.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include <w32std.h> +#include <fbs.h> + +#include <private/qt_s60_p.h> +#include "qpixmap.h" +#include "qpixmap_raster_p.h" +#include <qwidget.h> + +QT_BEGIN_NAMESPACE + +QPixmap QPixmap::grabWindow(WId winId, int x, int y, int w, int h ) +{ + CWsScreenDevice* screenDevice = S60->screenDevice(); + TSize screenSize = screenDevice->SizeInPixels(); + + TSize srcSize; + // Find out if this is one of our windows. + QSymbianControl *sControl; + sControl = winId->MopGetObject(sControl); + if (sControl && sControl->widget()->windowType() == Qt::Desktop) { + // Grabbing desktop widget + srcSize = screenSize; + } else { + TPoint relativePos = winId->PositionRelativeToScreen(); + x += relativePos.iX; + y += relativePos.iY; + srcSize = winId->Size(); + } + + TRect srcRect(TPoint(x, y), srcSize); + // Clip to the screen + srcRect.Intersection(TRect(screenSize)); + + if (w > 0 && h > 0) { + TRect subRect(TPoint(x, y), TSize(w, h)); + // Clip to the subRect + srcRect.Intersection(subRect); + } + + if (srcRect.IsEmpty()) + return QPixmap(); + + TDisplayMode displayMode = screenDevice->DisplayMode(); + CFbsBitmap* temporary = new (ELeave) CFbsBitmap(); + TInt error = temporary->Create(srcRect.Size(), displayMode); + if (error == KErrNone) + error = screenDevice->CopyScreenToBitmap(temporary, srcRect); + + if (error != KErrNone) { + CBase::Delete(temporary); + return QPixmap(); + } + + QPixmap pixmap = QPixmap::fromSymbianCFbsBitmap(temporary); + CBase::Delete(temporary); + return pixmap; +} + +/*! +\since 4.6 + +Returns a \c CFbsBitmap that is equivalent to the QPixmap by copying the data. + +It is the caller's responsibility to delete the \c CFbsBitmap after use. + +\warning This function is only available on Symbian OS. + +\sa fromSymbianCFbsBitmap() +*/ + +CFbsBitmap *QPixmap::toSymbianCFbsBitmap() const +{ + if (isNull()) + return 0; + + TDisplayMode mode; + const QImage img = toImage(); + QImage::Format destFormat = img.format(); + switch (img.format()) { + case QImage::Format_Mono: + destFormat = QImage::Format_MonoLSB; + // Fall through intended + case QImage::Format_MonoLSB: + mode = EGray2; + break; + case QImage::Format_Indexed8: + if (img.isGrayscale()) + mode = EGray256; + else + mode = EColor256; + break; + case QImage::Format_RGB32: + mode = EColor16MU; + break; + case QImage::Format_ARGB6666_Premultiplied: + case QImage::Format_ARGB8565_Premultiplied: + case QImage::Format_ARGB8555_Premultiplied: + destFormat = QImage::Format_ARGB32_Premultiplied; + // Fall through intended + case QImage::Format_ARGB32_Premultiplied: +#if !defined(__SERIES60_31__) && !defined(__S60_32__) + // ### TODO: Add runtime detection as well? + mode = EColor16MAP; + break; +#endif + destFormat = QImage::Format_ARGB32; + // Fall through intended + case QImage::Format_ARGB32: + mode = EColor16MA; + break; + case QImage::Format_RGB555: + destFormat = QImage::Format_RGB16; + // Fall through intended + case QImage::Format_RGB16: + mode = EColor64K; + break; + case QImage::Format_RGB666: + destFormat = QImage::Format_RGB888; + // Fall through intended + case QImage::Format_RGB888: + mode = EColor16M; + break; + case QImage::Format_RGB444: + mode = EColor4K; + break; + case QImage::Format_Invalid: + return 0; + default: + qWarning("Image format not supported: %d", img.format()); + return 0; + } + + CFbsBitmap* bitmap = new (ELeave) CFbsBitmap(); + TSize size(width(), height()); + if (bitmap->Create(size, mode) != KErrNone) { + CBase::Delete(bitmap); + return 0; + } + + const QImage converted = img.convertToFormat(destFormat); + + bitmap->LockHeap(); + const uchar *sptr = converted.bits(); + uchar *dptr = (uchar*)bitmap->DataAddress(); + Mem::Copy(dptr, sptr, converted.numBytes()); + bitmap->UnlockHeap(); + return bitmap; +} + +/*! +\since 4.6 + +Returns a QPixmap that is equivalent to the \c CFbsBitmap by copying the data. +If the CFbsBitmap is not valid or is compressed in memory, this function will +return a null QPixmap. + +\warning This function is only available on Symbian OS. + +\sa toSymbianCFbsBitmap(), {QPixmap#Pixmap Conversion}{Pixmap Conversion} +*/ + +QPixmap QPixmap::fromSymbianCFbsBitmap(CFbsBitmap *bitmap) +{ + int width = bitmap->SizeInPixels().iWidth; + int height = bitmap->SizeInPixels().iHeight; + + if (!bitmap || width <= 0 || height <= 0 || bitmap->IsCompressedInRAM()) + return QPixmap(); + + TDisplayMode displayMode = bitmap->DisplayMode(); + QImage::Format format = qt_TDisplayMode2Format(displayMode); + int bytesPerLine = CFbsBitmap::ScanLineLength(width, displayMode); + bitmap->LockHeap(); + QImage image = QImage((const uchar*)bitmap->DataAddress(), width, height, bytesPerLine, format); + if (displayMode == EGray2) { + image.setNumColors(2); + image.setColor(0, QColor(Qt::color0).rgba()); + image.setColor(1, QColor(Qt::color1).rgba()); + } else if (displayMode == EGray256) { + for (int i=0; i < 256; ++i) + image.setColor(i, qRgb(i, i, i)); + }else if (displayMode == EColor256) { + const TColor256Util *palette = TColor256Util::Default(); + for (int i=0; i < 256; ++i) + image.setColor(i, (QRgb)(palette->Color256(i).Value())); + } + QPixmap pixmap = QPixmap::fromImage(image.copy()); + bitmap->UnlockHeap(); + return pixmap; +} + +QT_END_NAMESPACE diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp index 458d6b9..c9973d0 100644 --- a/src/gui/image/qpixmapcache.cpp +++ b/src/gui/image/qpixmapcache.cpp @@ -86,7 +86,9 @@ QT_BEGIN_NAMESPACE \sa QCache, QPixmap */ -#if defined(Q_WS_QWS) || defined(Q_OS_WINCE) +#if defined(Q_OS_SYMBIAN) +static int cache_limit = 1024; // 1048 KB cache limit for symbian +#elif defined(Q_WS_QWS) || defined(Q_OS_WINCE) static int cache_limit = 2048; // 2048 KB cache limit for embedded #else static int cache_limit = 10240; // 10 MB cache limit for desktop diff --git a/src/gui/image/qpixmapdatafactory.cpp b/src/gui/image/qpixmapdatafactory.cpp index 699489d..03d62d3 100644 --- a/src/gui/image/qpixmapdatafactory.cpp +++ b/src/gui/image/qpixmapdatafactory.cpp @@ -47,7 +47,7 @@ #ifdef Q_WS_X11 # include <private/qpixmap_x11_p.h> #endif -#ifdef Q_WS_WIN +#if defined(Q_WS_WIN) || defined(Q_WS_S60) # include <private/qpixmap_raster_p.h> #endif #ifdef Q_WS_MAC @@ -75,7 +75,7 @@ QPixmapData* QSimplePixmapDataFactory::create(QPixmapData::PixelType type) #if defined(Q_WS_X11) return new QX11PixmapData(type); -#elif defined(Q_WS_WIN) +#elif defined(Q_WS_WIN) || defined(Q_WS_S60) return new QRasterPixmapData(type); #elif defined(Q_WS_MAC) return new QMacPixmapData(type); diff --git a/src/gui/inputmethod/inputmethod.pri b/src/gui/inputmethod/inputmethod.pri index d321cd4..f688364 100644 --- a/src/gui/inputmethod/inputmethod.pri +++ b/src/gui/inputmethod/inputmethod.pri @@ -23,4 +23,9 @@ mac:!embedded { HEADERS += inputmethod/qmacinputcontext_p.h SOURCES += inputmethod/qmacinputcontext_mac.cpp } +symbian { + HEADERS += inputmethod/qcoefepinputcontext_p.h + SOURCES += inputmethod/qcoefepinputcontext_s60.cpp + LIBS += -lfepbase +} diff --git a/src/gui/inputmethod/qcoefepinputcontext_p.h b/src/gui/inputmethod/qcoefepinputcontext_p.h new file mode 100644 index 0000000..c2677b1 --- /dev/null +++ b/src/gui/inputmethod/qcoefepinputcontext_p.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QCOEFEPINPUTCONTEXT_P_H +#define QCOEFEPINPUTCONTEXT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#ifndef QT_NO_IM + +#include "qinputcontext.h" +#include <qhash.h> +#include <private/qcore_symbian_p.h> +#include <private/qt_s60_p.h> + +#include <fepbase.h> +#include <aknedsts.h> + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QCoeFepInputContext : public QInputContext, + public MCoeFepAwareTextEditor, + public MCoeFepAwareTextEditor_Extension1, + public MObjectProvider +{ + Q_OBJECT + +public: + QCoeFepInputContext(QObject *parent = 0); + ~QCoeFepInputContext(); + + QString identifierName() { return QLatin1String("coefep"); } + QString language(); + + void reset(); + void update(); + + bool filterEvent(const QEvent *event); + void mouseHandler( int x, QMouseEvent *event); + bool isComposing() const { return m_isEditing; } + + void setFocusWidget(QWidget * w); + void widgetDestroyed(QWidget *w); + + TCoeInputCapabilities inputCapabilities(); + +private: + void commitCurrentString(); + void updateHints(); + void applyHints(Qt::InputMethodHints hints); + void applyFormat(QList<QInputMethodEvent::Attribute> *attributes); + + // From MCoeFepAwareTextEditor +public: + void StartFepInlineEditL(const TDesC& aInitialInlineText, TInt aPositionOfInsertionPointInInlineText, + TBool aCursorVisibility, const MFormCustomDraw* aCustomDraw, + MFepInlineTextFormatRetriever& aInlineTextFormatRetriever, + MFepPointerEventHandlerDuringInlineEdit& aPointerEventHandlerDuringInlineEdit); + void UpdateFepInlineTextL(const TDesC& aNewInlineText, TInt aPositionOfInsertionPointInInlineText); + void SetInlineEditingCursorVisibilityL(TBool aCursorVisibility); + void CancelFepInlineEdit(); + TInt DocumentLengthForFep() const; + TInt DocumentMaximumLengthForFep() const; + void SetCursorSelectionForFepL(const TCursorSelection& aCursorSelection); + void GetCursorSelectionForFep(TCursorSelection& aCursorSelection) const; + void GetEditorContentForFep(TDes& aEditorContent, TInt aDocumentPosition, TInt aLengthToRetrieve) const; + void GetFormatForFep(TCharFormat& aFormat, TInt aDocumentPosition) const; + void GetScreenCoordinatesForFepL(TPoint& aLeftSideOfBaseLine, TInt& aHeight, TInt& aAscent, + TInt aDocumentPosition) const; +private: + void DoCommitFepInlineEditL(); + MCoeFepAwareTextEditor_Extension1* Extension1(TBool& aSetToTrue); + + // From MCoeFepAwareTextEditor_Extension1 +public: + void SetStateTransferingOwnershipL(MCoeFepAwareTextEditor_Extension1::CState* aState, TUid aTypeSafetyUid); + MCoeFepAwareTextEditor_Extension1::CState* State(TUid aTypeSafetyUid); + + // From MObjectProvider +public: + TTypeUid::Ptr MopSupplyObject(TTypeUid id); + +private: + QSymbianControl *m_parent; + CAknEdwinState *m_fepState; + QString m_preeditString; + Qt::InputMethodHints m_lastImHints; + TUint m_textCapabilities; + bool m_isEditing; + bool m_inDestruction; + int m_cursorVisibility; + int m_inlinePosition; + MFepInlineTextFormatRetriever *m_formatRetriever; + MFepPointerEventHandlerDuringInlineEdit *m_pointerHandler; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_IM + +#endif // QCOEFEPINPUTCONTEXT_P_H diff --git a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp new file mode 100644 index 0000000..0a5fd22 --- /dev/null +++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp @@ -0,0 +1,767 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_NO_IM + +#include "qcoefepinputcontext_p.h" +#include <qapplication.h> +#include <private/qapplication_p.h> +#include <qtextformat.h> + +#include <fepitfr.h> + +#include <limits.h> +// You only find these enumerations on SDK 5 onwards, so we need to provide our own +// to remain compatible with older releases. They won't be called by pre-5.0 SDKs. + +// MAknEdStateObserver::EAknCursorPositionChanged +#define QT_EAknCursorPositionChanged MAknEdStateObserver::EAknEdwinStateEvent(6) +// MAknEdStateObserver::EAknActivatePenInputRequest +#define QT_EAknActivatePenInputRequest MAknEdStateObserver::EAknEdwinStateEvent(7) + +QT_BEGIN_NAMESPACE + +QCoeFepInputContext::QCoeFepInputContext(QObject *parent) + : QInputContext(parent), + m_fepState(new (ELeave) CAknEdwinState), + m_lastImHints(Qt::ImhNone), + m_textCapabilities(TCoeInputCapabilities::EAllText), + m_isEditing(false), + m_inDestruction(false), + m_cursorVisibility(1), + m_inlinePosition(0), + m_formatRetriever(0), + m_pointerHandler(0) +{ + m_fepState->SetObjectProvider(this); + m_fepState->SetFlags(EAknEditorFlagDefault); + m_fepState->SetDefaultInputMode( EAknEditorTextInputMode ); + m_fepState->SetPermittedInputModes( EAknEditorAllInputModes ); + m_fepState->SetLocalLanguage(ELangEnglish); + m_fepState->SetDefaultLanguage(ELangEnglish); + m_fepState->SetDefaultCase( EAknEditorLowerCase ); + m_fepState->SetPermittedCases( EAknEditorLowerCase|EAknEditorUpperCase ); + m_fepState->SetSpecialCharacterTableResourceId( 0 ); + m_fepState->SetNumericKeymap( EAknEditorStandardNumberModeKeymap ); +} + +QCoeFepInputContext::~QCoeFepInputContext() +{ + m_inDestruction = true; + + // This is to make sure that the FEP manager "forgets" about us, + // otherwise we may get callbacks even after we're destroyed. + // The call is asynchronous though, so we must spin the event loop + // to make sure it gets detected. However we will not spin eventloop + // in case that app is closing, since eventDispatcher is already deleted. + CCoeEnv::Static()->InputCapabilitiesChanged(); + if(!QApplicationPrivate::is_app_closing) { + QApplication::processEvents(); + } + + if (m_fepState) + delete m_fepState; +} + +void QCoeFepInputContext::reset() +{ + CCoeEnv::Static()->Fep()->CancelTransaction(); +} + +void QCoeFepInputContext::update() +{ + updateHints(); + + // For pre-5.0 SDKs, we don't do text updates on S60 side. + if (QSysInfo::s60Version() != QSysInfo::SV_S60_5_0) { + return; + } + + // Don't be fooled (as I was) by the name of this enumeration. + // What it really does is tell the virtual keyboard UI that the text has been + // updated and it should be reflected in the internal display of the VK. + m_fepState->ReportAknEdStateEventL(QT_EAknCursorPositionChanged); +} + +void QCoeFepInputContext::setFocusWidget(QWidget *w) +{ + commitCurrentString(); + + CCoeEnv::Static()->Fep()->CancelTransaction(); + + QInputContext::setFocusWidget(w); + + updateHints(); +} + +void QCoeFepInputContext::widgetDestroyed(QWidget *w) +{ + // Make sure that the input capabilities of whatever new widget got focused are queried. + CCoeControl *ctrl = w->effectiveWinId(); + if (ctrl->IsFocused()) { + ctrl->SetFocus(false); + ctrl->SetFocus(true); + } +} + +/*! + Definition of struct for mapping Symbian to ISO locale + ### REMOVE + See below. +*/ +struct symbianToISO { + int symbian_language; + char iso_name[8]; +}; + +/*! + Mapping from Symbian to ISO locale + ### REMOVE + This was taken from the preliminary QLocale port to S60, and should be + removed once that is finished. +*/ +static const symbianToISO symbian_to_iso_list[] = { + { ELangEnglish, "en_GB" }, + { ELangFrench, "fr_FR" }, + { ELangGerman, "de_DE" }, + { ELangSpanish, "es_ES" }, + { ELangItalian, "it_IT" }, + { ELangSwedish, "sv_SE" }, + { ELangDanish, "da_DK" }, + { ELangNorwegian, "no_NO" }, + { ELangFinnish, "fi_FI" }, + { ELangAmerican, "en_US" }, + { ELangPortuguese, "pt_PT" }, + { ELangTurkish, "tr_TR" }, + { ELangIcelandic, "is_IS" }, + { ELangRussian, "ru_RU" }, + { ELangHungarian, "hu_HU" }, + { ELangDutch, "nl_NL" }, + { ELangBelgianFlemish, "nl_BE" }, + { ELangCzech, "cs_CZ" }, + { ELangSlovak, "sk_SK" }, + { ELangPolish, "pl_PL" }, + { ELangSlovenian, "sl_SI" }, + { ELangTaiwanChinese, "zh_TW" }, + { ELangHongKongChinese, "zh_HK" }, + { ELangPrcChinese, "zh_CN" }, + { ELangJapanese, "ja_JP" }, + { ELangThai, "th_TH" }, + { ELangArabic, "ar_AE" }, + { ELangTagalog, "tl_PH" }, + { ELangBulgarian, "bg_BG" }, + { ELangCatalan, "ca_ES" }, + { ELangCroatian, "hr_HR" }, + { ELangEstonian, "et_EE" }, + { ELangFarsi, "fa_IR" }, + { ELangCanadianFrench, "fr_CA" }, + { ELangGreek, "el_GR" }, + { ELangHebrew, "he_IL" }, + { ELangHindi, "hi_IN" }, + { ELangIndonesian, "id_ID" }, + { ELangLatvian, "lv_LV" }, + { ELangLithuanian, "lt_LT" }, + { ELangMalay, "ms_MY" }, + { ELangBrazilianPortuguese, "pt_BR" }, + { ELangRomanian, "ro_RO" }, + { ELangSerbian, "sr_YU" }, + { ELangLatinAmericanSpanish, "es" }, + { ELangUkrainian, "uk_UA" }, + { ELangUrdu, "ur_PK" }, // India/Pakistan + { ELangVietnamese, "vi_VN" }, +#ifdef __E32LANG_H__ +// 5.0 + { ELangBasque, "eu_ES" }, + { ELangGalician, "gl_ES" }, +#endif + //{ ELangEnglish_Apac, "en" }, + //{ ELangEnglish_Taiwan, "en_TW" }, + //{ ELangEnglish_HongKong, "en_HK" }, + //{ ELangEnglish_Prc, "en_CN" }, + //{ ELangEnglish_Japan, "en_JP"}, + //{ ELangEnglish_Thailand, "en_TH" }, + //{ ELangMalay_Apac, "ms" } +}; + +/*! + Number of Symbian to ISO locale mappings + ### Remove. + See comment for array above. +*/ +static const int symbian_to_iso_count + = sizeof(symbian_to_iso_list)/sizeof(symbianToISO); + +QString QCoeFepInputContext::language() +{ + TLanguage lang = m_fepState->LocalLanguage(); + if (lang < symbian_to_iso_count) { + return QLatin1String(symbian_to_iso_list[lang].iso_name); + } else { + return QLatin1String("C"); + } +} + +bool QCoeFepInputContext::filterEvent(const QEvent *event) +{ + // The CloseSoftwareInputPanel event is not handled here, because the VK will automatically + // close when it discovers that the underlying widget does not have input capabilities. + + if (!focusWidget()) + return false; + + if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { + const QKeyEvent *keyEvent = static_cast<const QKeyEvent *>(event); + Q_ASSERT(m_lastImHints == focusWidget()->inputMethodHints()); + if (keyEvent->key() == Qt::Key_F20 && m_lastImHints & Qt::ImhHiddenText) { + // Special case in Symbian. On editors with secret text, F20 is for some reason + // considered to be a backspace. + QKeyEvent modifiedEvent(keyEvent->type(), Qt::Key_Backspace, keyEvent->modifiers(), + keyEvent->text(), keyEvent->isAutoRepeat(), keyEvent->count()); + QApplication::sendEvent(focusWidget(), &modifiedEvent); + return true; + } + } + + // For pre-5.0 SDKs, we don't launch the keyboard. + if (QSysInfo::s60Version() != QSysInfo::SV_S60_5_0) { + return false; + } + + if (event->type() == QEvent::RequestSoftwareInputPanel) { + // Notify S60 that we want the virtual keyboard to show up. + QSymbianControl *sControl; + sControl = focusWidget()->effectiveWinId()->MopGetObject(sControl); + Q_ASSERT(sControl); + + // The FEP UI temporarily steals focus when it shows up the first time, causing + // all sorts of weird effects on the focused widgets. Since it will immediately give + // back focus to us, we temporarily disable focus handling until the job's done. + if (sControl) { + sControl->setIgnoreFocusChanged(true); + } + + m_fepState->ReportAknEdStateEventL(MAknEdStateObserver::QT_EAknActivatePenInputRequest); + + if (sControl) { + sControl->setIgnoreFocusChanged(false); + } + return true; + } + + return false; +} + +void QCoeFepInputContext::mouseHandler( int x, QMouseEvent *event) +{ + Q_ASSERT(m_isEditing); + + if (!m_pointerHandler) { + QInputContext::mouseHandler(x, event); + } + + TPointerEvent::TType type; + TUint modifiers = 0; + + if (event->type() == QEvent::MouseButtonPress) { + if (event->button() == Qt::LeftButton) { + type = TPointerEvent::EButton1Down; + } else if (event->button() == Qt::RightButton) { + type = TPointerEvent::EButton3Down; + } else if (event->button() == Qt::MidButton) { + type = TPointerEvent::EButton2Down; + } else { + return; + } + } else if (event->type() == QEvent::MouseButtonRelease) { + if (event->button() == Qt::LeftButton) { + type = TPointerEvent::EButton1Up; + } else if (event->button() == Qt::RightButton) { + type = TPointerEvent::EButton3Up; + } else if (event->button() == Qt::MidButton) { + type = TPointerEvent::EButton2Up; + } else { + return; + } + } else if (event->type() == QEvent::MouseMove) { + type = TPointerEvent::EMove; + } else if (event->type() == QEvent::DragMove) { + type = TPointerEvent::EDrag; + } else { + return; + } + + if (event->modifiers() & Qt::ShiftModifier) { + modifiers |= EModifierShift; + } + if (event->modifiers() & Qt::AltModifier) { + modifiers |= EModifierAlt; + } + if (event->modifiers() & Qt::ControlModifier) { + modifiers |= EModifierCtrl; + } + if (event->modifiers() & Qt::KeypadModifier) { + modifiers |= EModifierKeypad; + } + + m_pointerHandler->HandlePointerEventInInlineTextL(type, modifiers, x); +} + +TCoeInputCapabilities QCoeFepInputContext::inputCapabilities() +{ + if (m_inDestruction) { + return TCoeInputCapabilities(TCoeInputCapabilities::ENone, 0, 0); + } + + return TCoeInputCapabilities(m_textCapabilities, this, 0); +} + +static QTextCharFormat qt_TCharFormat2QTextCharFormat(const TCharFormat &cFormat) +{ + QTextCharFormat qFormat; + + QBrush foreground(QColor(cFormat.iFontPresentation.iTextColor.Internal())); + qFormat.setForeground(foreground); + + qFormat.setFontStrikeOut(cFormat.iFontPresentation.iStrikethrough == EStrikethroughOn); + qFormat.setFontUnderline(cFormat.iFontPresentation.iUnderline == EUnderlineOn); + + return qFormat; +} + +void QCoeFepInputContext::updateHints() +{ + QWidget *w = focusWidget(); + if (w) { + Qt::InputMethodHints hints = w->inputMethodHints(); + if (hints != m_lastImHints) { + m_lastImHints = hints; + applyHints(hints); + } + } +} + +void QCoeFepInputContext::applyHints(Qt::InputMethodHints hints) +{ + using namespace Qt; + + bool numbersOnly = hints & ImhDigitsOnly || hints & ImhFormattedNumbersOnly + || hints & ImhDialableCharactersOnly; + bool noOnlys = !(numbersOnly || hints & ImhUppercaseOnly + || hints & ImhLowercaseOnly); + TInt flags; + Qt::InputMethodHints oldHints = hints; + + // Some sanity checking. Make sure that only one preference is set. + InputMethodHints prefs = ImhPreferNumbers | ImhPreferUppercase | ImhPreferLowercase; + prefs &= hints; + if (prefs != ImhPreferNumbers && prefs != ImhPreferUppercase && prefs != ImhPreferLowercase) { + hints &= ~prefs; + } + if (!noOnlys) { + // Make sure that the preference is within the permitted set. + if (hints & ImhPreferNumbers && !(hints & ImhDigitsOnly || hints & ImhFormattedNumbersOnly + || hints & ImhDialableCharactersOnly)) { + hints &= ~ImhPreferNumbers; + } else if (hints & ImhPreferUppercase && !(hints & ImhUppercaseOnly)) { + hints &= ~ImhPreferUppercase; + } else if (hints & ImhPreferLowercase && !(hints & ImhLowercaseOnly)) { + hints &= ~ImhPreferLowercase; + } + // If there is no preference, set it to something within the permitted set. + if (!(hints & ImhPreferNumbers || hints & ImhPreferUppercase || hints & ImhPreferLowercase)) { + if (hints & ImhLowercaseOnly) { + hints |= ImhPreferLowercase; + } else if (hints & ImhUppercaseOnly) { + hints |= ImhPreferUppercase; + } else if (hints & ImhDigitsOnly || hints & ImhFormattedNumbersOnly + || hints & ImhDialableCharactersOnly) { + hints |= ImhPreferNumbers; + } + } + } + + if (hints & ImhPreferNumbers) { + m_fepState->SetDefaultInputMode(EAknEditorNumericInputMode); + m_fepState->SetCurrentInputMode(EAknEditorNumericInputMode); + } else { + m_fepState->SetDefaultInputMode(EAknEditorTextInputMode); + m_fepState->SetCurrentInputMode(EAknEditorTextInputMode); + } + flags = 0; + if (numbersOnly) { + flags |= EAknEditorNumericInputMode; + } + if (hints & ImhUppercaseOnly || hints & ImhLowercaseOnly) { + flags |= EAknEditorTextInputMode; + } + if (flags == 0) { + flags = EAknEditorAllInputModes; + } + m_fepState->SetPermittedInputModes(flags); + m_fepState->ReportAknEdStateEventL(MAknEdStateObserver::EAknEdwinStateInputModeUpdate); + + if (hints & ImhPreferLowercase) { + m_fepState->SetDefaultCase(EAknEditorLowerCase); + m_fepState->SetCurrentCase(EAknEditorLowerCase); + } else if (hints & ImhPreferUppercase) { + m_fepState->SetDefaultCase(EAknEditorUpperCase); + m_fepState->SetCurrentCase(EAknEditorUpperCase); + } else if (hints & ImhNoAutoUppercase) { + m_fepState->SetDefaultCase(EAknEditorLowerCase); + m_fepState->SetCurrentCase(EAknEditorLowerCase); + } else { + m_fepState->SetDefaultCase(EAknEditorTextCase); + m_fepState->SetCurrentCase(EAknEditorTextCase); + } + flags = 0; + if (hints & ImhUppercaseOnly) { + flags |= EAknEditorUpperCase; + } + if (hints & ImhLowercaseOnly) { + flags |= EAknEditorLowerCase; + } + if (flags == 0) { + flags = EAknEditorAllCaseModes; + if (hints & ImhNoAutoUppercase) { + flags &= ~EAknEditorTextCase; + } + } + m_fepState->SetPermittedCases(flags); + m_fepState->ReportAknEdStateEventL(MAknEdStateObserver::EAknEdwinStateCaseModeUpdate); + + flags = 0; + if (hints & ImhUppercaseOnly && !(hints & ImhLowercaseOnly) + || hints & ImhLowercaseOnly && !(hints & ImhUppercaseOnly)) { + flags |= EAknEditorFlagFixedCase; + } + // Using T9 and hidden text together may actually crash the FEP, so check for hidden text too. + if (hints & ImhNoPredictiveText || hints & ImhHiddenText) { + flags |= EAknEditorFlagNoT9; + } + m_fepState->SetFlags(flags); + m_fepState->ReportAknEdStateEventL(MAknEdStateObserver::EAknEdwinStateFlagsUpdate); + + if (hints & ImhFormattedNumbersOnly) { + flags = EAknEditorCalculatorNumberModeKeymap; + } else if (hints & ImhDigitsOnly) { + flags = EAknEditorPlainNumberModeKeymap; + } else { + // ImhDialableCharactersOnly is the fallback as well, so we don't need to check for + // that flag. + flags = EAknEditorStandardNumberModeKeymap; + } + m_fepState->SetNumericKeymap(static_cast<TAknEditorNumericKeymap>(flags)); + + if (hints & ImhHiddenText) { + m_textCapabilities = TCoeInputCapabilities::EAllText | TCoeInputCapabilities::ESecretText; + } else { + m_textCapabilities = TCoeInputCapabilities::EAllText; + } + + CCoeEnv::Static()->InputCapabilitiesChanged(); +} + +void QCoeFepInputContext::applyFormat(QList<QInputMethodEvent::Attribute> *attributes) +{ + TCharFormat cFormat; + TInt numChars = 0; + TInt charPos = 0; + int oldSize = attributes->size(); + while (m_formatRetriever) { + m_formatRetriever->GetFormatOfFepInlineText(cFormat, numChars, charPos); + if (numChars <= 0) { + // This shouldn't happen according to S60 docs, but apparently does sometimes. + break; + } + attributes->append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, + charPos, + numChars, + QVariant(qt_TCharFormat2QTextCharFormat(cFormat)))); + charPos += numChars; + if (charPos >= m_preeditString.size()) { + break; + } + } + + if (attributes->size() == oldSize) { + // S60 didn't provide any format, so let's give our own instead. + attributes->append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, + 0, + m_preeditString.size(), + standardFormat(PreeditFormat))); + } +} + +void QCoeFepInputContext::StartFepInlineEditL(const TDesC& aInitialInlineText, + TInt aPositionOfInsertionPointInInlineText, TBool aCursorVisibility, const MFormCustomDraw* /*aCustomDraw*/, + MFepInlineTextFormatRetriever& aInlineTextFormatRetriever, + MFepPointerEventHandlerDuringInlineEdit& aPointerEventHandlerDuringInlineEdit) +{ + QWidget *w = focusWidget(); + if (!w) + return; + + m_isEditing = true; + + QList<QInputMethodEvent::Attribute> attributes; + + m_cursorVisibility = aCursorVisibility ? 1 : 0; + m_inlinePosition = aPositionOfInsertionPointInInlineText; + m_preeditString = qt_TDesC2QStringL(aInitialInlineText); + + m_formatRetriever = &aInlineTextFormatRetriever; + m_pointerHandler = &aPointerEventHandlerDuringInlineEdit; + + applyFormat(&attributes); + + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, + m_inlinePosition, + m_cursorVisibility, + QVariant())); + QInputMethodEvent event(m_preeditString, attributes); + sendEvent(event); +} + +void QCoeFepInputContext::UpdateFepInlineTextL(const TDesC& aNewInlineText, + TInt aPositionOfInsertionPointInInlineText) +{ + QWidget *w = focusWidget(); + if (!w) + return; + + m_inlinePosition = aPositionOfInsertionPointInInlineText; + + QList<QInputMethodEvent::Attribute> attributes; + applyFormat(&attributes); + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, + m_inlinePosition, + m_cursorVisibility, + QVariant())); + m_preeditString = qt_TDesC2QStringL(aNewInlineText); + QInputMethodEvent event(m_preeditString, attributes); + sendEvent(event); +} + +void QCoeFepInputContext::SetInlineEditingCursorVisibilityL(TBool aCursorVisibility) +{ + QWidget *w = focusWidget(); + if (!w) + return; + + m_cursorVisibility = aCursorVisibility ? 1 : 0; + + QList<QInputMethodEvent::Attribute> attributes; + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, + m_inlinePosition, + m_cursorVisibility, + QVariant())); + QInputMethodEvent event(m_preeditString, attributes); + sendEvent(event); +} + +void QCoeFepInputContext::CancelFepInlineEdit() +{ + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("", attributes); + event.setCommitString("", 0, 0); + m_preeditString.clear(); + sendEvent(event); + + m_isEditing = false; +} + +TInt QCoeFepInputContext::DocumentLengthForFep() const +{ + QWidget *w = focusWidget(); + if (!w) + return 0; + + QVariant variant = w->inputMethodQuery(Qt::ImSurroundingText); + return variant.value<QString>().size() + m_preeditString.size(); +} + +TInt QCoeFepInputContext::DocumentMaximumLengthForFep() const +{ + QWidget *w = focusWidget(); + if (!w) + return 0; + + QVariant variant = w->inputMethodQuery(Qt::ImMaximumTextLength); + int size; + if (variant.isValid()) { + size = variant.toInt(); + } else { + size = INT_MAX; // Sensible default for S60. + } + return size; +} + +void QCoeFepInputContext::SetCursorSelectionForFepL(const TCursorSelection& aCursorSelection) +{ + QWidget *w = focusWidget(); + if (!w) + return; + + int pos = aCursorSelection.iAnchorPos; + int length = aCursorSelection.iCursorPos - pos; + + QList<QInputMethodEvent::Attribute> attributes; + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, pos, length, QVariant()); + QInputMethodEvent event(m_preeditString, attributes); + sendEvent(event); +} + +void QCoeFepInputContext::GetCursorSelectionForFep(TCursorSelection& aCursorSelection) const +{ + QWidget *w = focusWidget(); + if (!w) + return; + + int cursor = w->inputMethodQuery(Qt::ImCursorPosition).toInt() + m_preeditString.size(); + int anchor = w->inputMethodQuery(Qt::ImAnchorPosition).toInt() + m_preeditString.size(); + aCursorSelection.iAnchorPos = anchor; + aCursorSelection.iCursorPos = cursor; +} + +void QCoeFepInputContext::GetEditorContentForFep(TDes& aEditorContent, TInt aDocumentPosition, + TInt aLengthToRetrieve) const +{ + QWidget *w = focusWidget(); + if (!w) + return; + + QString text = w->inputMethodQuery(Qt::ImSurroundingText).value<QString>(); + // FEP expects the preedit string to be part of the editor content, so let's mix it in. + int cursor = w->inputMethodQuery(Qt::ImCursorPosition).toInt(); + text.insert(cursor, m_preeditString); + aEditorContent.Copy(qt_QString2TPtrC(text.mid(aDocumentPosition, aLengthToRetrieve))); +} + +void QCoeFepInputContext::GetFormatForFep(TCharFormat& aFormat, TInt aDocumentPosition) const +{ + QWidget *w = focusWidget(); + if (!w) + return; + + QFont font = w->inputMethodQuery(Qt::ImFont).value<QFont>(); + QFontMetrics metrics(font); + //QString name = font.rawName(); + QString name = font.defaultFamily(); // TODO! FIXME! Should be the above. + QHBufC hBufC(name); + aFormat = TCharFormat(hBufC->Des(), metrics.height()); + + aDocumentPosition = w->inputMethodQuery(Qt::ImCursorPosition).toInt(); +} + +void QCoeFepInputContext::GetScreenCoordinatesForFepL(TPoint& aLeftSideOfBaseLine, TInt& aHeight, + TInt& aAscent, TInt aDocumentPosition) const +{ + QWidget *w = focusWidget(); + if (!w) + return; + + QRect rect = w->inputMethodQuery(Qt::ImMicroFocus).value<QRect>(); + aLeftSideOfBaseLine.iX = rect.left(); + aLeftSideOfBaseLine.iY = rect.bottom(); + + QFont font = w->inputMethodQuery(Qt::ImFont).value<QFont>(); + QFontMetrics metrics(font); + aHeight = metrics.height(); + aAscent = metrics.ascent(); + + aDocumentPosition = w->inputMethodQuery(Qt::ImCursorPosition).toInt(); +} + +void QCoeFepInputContext::DoCommitFepInlineEditL() +{ + commitCurrentString(); + + m_isEditing = false; +} + +void QCoeFepInputContext::commitCurrentString() +{ + if (m_preeditString.size() == 0) { + return; + } + + QList<QInputMethodEvent::Attribute> attributes; + QInputMethodEvent event("", attributes); + event.setCommitString(m_preeditString, 0, 0);//m_preeditString.size()); + m_preeditString.clear(); + sendEvent(event); +} + +MCoeFepAwareTextEditor_Extension1* QCoeFepInputContext::Extension1(TBool& aSetToTrue) +{ + aSetToTrue = ETrue; + return this; +} + +void QCoeFepInputContext::SetStateTransferingOwnershipL(MCoeFepAwareTextEditor_Extension1::CState* aState, + TUid /*aTypeSafetyUid*/) +{ + // Note: The S60 docs are wrong! See the State() function. + if (m_fepState) + delete m_fepState; + m_fepState = static_cast<CAknEdwinState *>(aState); +} + +MCoeFepAwareTextEditor_Extension1::CState* QCoeFepInputContext::State(TUid /*aTypeSafetyUid*/) +{ + // Note: The S60 docs are horribly wrong when describing the + // SetStateTransferingOwnershipL function and this function. They say that the former + // sets a CState object identified by the TUid, and the latter retrieves it. + // In reality, the CState is expected to always be a CAknEdwinState (even if it was not + // previously set), and the TUid is ignored. All in all, there is a single CAknEdwinState + // per QCoeFepInputContext, which should be deleted if the SetStateTransferingOwnershipL + // function is used to set a new one. + return m_fepState; +} + +TTypeUid::Ptr QCoeFepInputContext::MopSupplyObject(TTypeUid /*id*/) +{ + return TTypeUid::Null(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_IM diff --git a/src/gui/inputmethod/qinputcontext.cpp b/src/gui/inputmethod/qinputcontext.cpp index f78b86a..00a9225 100644 --- a/src/gui/inputmethod/qinputcontext.cpp +++ b/src/gui/inputmethod/qinputcontext.cpp @@ -209,9 +209,21 @@ void QInputContext::setFocusWidget(QWidget *widget) way. Although the input events have accept() and ignore() methods, leave it untouched. - \a event is currently restricted to QKeyEvent. But some input - method related events such as QWheelEvent or QTabletEvent may be - added in future. + \a event is currently restricted to events of these types: + + \list + \i CloseSoftwareInputPanel + \i KeyPress + \i KeyRelease + \i MouseButtonDblClick + \i MouseButtonPress + \i MouseButtonRelease + \i MouseMove + \i RequestSoftwareInputPanel + \endlist + + But some input method related events such as QWheelEvent or + QTabletEvent may be added in future. The filtering opportunity is always given to the input context as soon as possible. It has to be taken place before any other key @@ -415,13 +427,6 @@ QTextFormat QInputContext::standardFormat(StandardFormat s) const switch (s) { case QInputContext::PreeditFormat: { fmt.setUnderlineStyle(QTextCharFormat::DashUnderline); -#ifndef Q_WS_WIN - int h1, s1, v1, h2, s2, v2; - pal.color(QPalette::Base).getHsv(&h1, &s1, &v1); - pal.color(QPalette::Background).getHsv(&h2, &s2, &v2); - bg.setHsv(h1, s1, (v1 + v2) / 2); - fmt.setBackground(QBrush(bg)); -#endif break; } case QInputContext::SelectionFormat: { @@ -459,6 +464,31 @@ bool QInputContext::x11FilterEvent(QWidget * /*keywidget*/, XEvent * /*event*/) } #endif // Q_WS_X11 +#ifdef Q_WS_S60 +/*! + This function may be overridden only if input method is depending + on Symbian and you need raw TWsEvent. Otherwise, this function must not. + + This function is designed to filter raw key events on S60, but + other input methods may use this to implement some special + features. + + Return true if the \a event has been consumed. Otherwise, the + unfiltered \a event will be translated into QEvent and forwarded + to filterEvent(). Filtering at both s60FilterEvent() and + filterEvent() in single input method is allowed. + + \a keywidget is a client widget into which a text is inputted. \a + event is inputted TWsEvent. + + \sa filterEvent() +*/ +bool QInputContext::s60FilterEvent(QWidget * /*keywidget*/, TWsEvent * /*event*/) +{ + return false; +} +#endif // Q_WS_S60 + QT_END_NAMESPACE #endif //Q_NO_IM diff --git a/src/gui/inputmethod/qinputcontext.h b/src/gui/inputmethod/qinputcontext.h index bcaa7fe..bc4c63c 100644 --- a/src/gui/inputmethod/qinputcontext.h +++ b/src/gui/inputmethod/qinputcontext.h @@ -67,6 +67,10 @@ QT_BEGIN_HEADER +#ifdef Q_WS_S60 +class TWsEvent; +#endif + QT_BEGIN_NAMESPACE QT_MODULE(Gui) @@ -76,7 +80,6 @@ class QFont; class QPopupMenu; class QInputContextPrivate; - class Q_GUI_EXPORT QInputContext : public QObject { Q_OBJECT @@ -105,6 +108,9 @@ public: #if defined(Q_WS_X11) virtual bool x11FilterEvent( QWidget *keywidget, XEvent *event ); #endif // Q_WS_X11 +#if defined(Q_WS_S60) + virtual bool s60FilterEvent( QWidget *keywidget, TWsEvent *event ); +#endif // Q_WS_S60 virtual bool filterEvent( const QEvent *event ); void sendEvent(const QInputMethodEvent &event); diff --git a/src/gui/inputmethod/qinputcontextfactory.cpp b/src/gui/inputmethod/qinputcontextfactory.cpp index 06625f9..188b13a 100644 --- a/src/gui/inputmethod/qinputcontextfactory.cpp +++ b/src/gui/inputmethod/qinputcontextfactory.cpp @@ -71,6 +71,9 @@ #ifdef Q_WS_MAC #include "qmacinputcontext_p.h" #endif +#ifdef Q_WS_S60 +#include "qcoefepinputcontext_p.h" +#endif #include "private/qfactoryloader_p.h" #include "qmutex.h" @@ -145,6 +148,11 @@ QInputContext *QInputContextFactory::create( const QString& key, QObject *parent result = new QMacInputContext; } #endif +#if defined(Q_WS_S60) + if (key == QLatin1String("coefep")) { + result = new QCoeFepInputContext; + } +#endif #if defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS) Q_UNUSED(key); #else @@ -182,6 +190,9 @@ QStringList QInputContextFactory::keys() #if defined(Q_WS_MAC) result << QLatin1String("mac"); #endif +#if defined(Q_WS_S60) + result << QLatin1String("coefep"); +#endif #if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) result += loader()->keys(); #endif // QT_NO_LIBRARY @@ -217,6 +228,10 @@ QStringList QInputContextFactory::languages( const QString &key ) if (key == QLatin1String("mac")) return QStringList(QString()); #endif +#if defined(Q_WS_S60) + if (key == QLatin1String("coefep")) + return QStringList(QString()); +#endif #if defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS) Q_UNUSED(key); #else @@ -241,6 +256,10 @@ QString QInputContextFactory::displayName( const QString &key ) if (key == QLatin1String("xim")) return QInputContext::tr( "XIM" ); #endif +#ifdef Q_WS_S60 + if (key == QLatin1String("coefep")) + return QInputContext::tr( "FEP" ); +#endif #if defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS) Q_UNUSED(key); #else @@ -272,6 +291,10 @@ QString QInputContextFactory::description( const QString &key ) if (key == QLatin1String("mac")) return QInputContext::tr( "Mac OS X input method" ); #endif +#if defined(Q_WS_S60) + if (key == QLatin1String("coefep")) + return QInputContext::tr( "S60 FEP input method" ); +#endif #if defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS) Q_UNUSED(key); #else diff --git a/src/gui/inputmethod/qwininputcontext_win.cpp b/src/gui/inputmethod/qwininputcontext_win.cpp index e3e8aa4..d670f5a 100644 --- a/src/gui/inputmethod/qwininputcontext_win.cpp +++ b/src/gui/inputmethod/qwininputcontext_win.cpp @@ -759,7 +759,12 @@ void QInputContextPrivate::updateImeStatus(QWidget *w, bool hasFocus) { if (!w) return; - bool e = w->testAttribute(Qt::WA_InputMethodEnabled) && w->isEnabled(); + // It's always the proxy that carries the hints. + QWidget *focusProxyWidget = w->focusProxy(); + if (!focusProxyWidget) + focusProxyWidget = w; + bool e = w->testAttribute(Qt::WA_InputMethodEnabled) && w->isEnabled() + && !(focusProxyWidget->inputMethodHints() & Qt::ImhExclusiveInputMask); bool hasIme = e && hasFocus; #ifdef Q_IME_DEBUG qDebug("%s HasFocus = %d hasIme = %d e = %d ", w->className(), hasFocus, hasIme, e); diff --git a/src/gui/inputmethod/qximinputcontext_x11.cpp b/src/gui/inputmethod/qximinputcontext_x11.cpp index c320fb4..60ea15b 100644 --- a/src/gui/inputmethod/qximinputcontext_x11.cpp +++ b/src/gui/inputmethod/qximinputcontext_x11.cpp @@ -610,7 +610,7 @@ void QXIMInputContext::setFocusWidget(QWidget *w) QInputContext::setFocusWidget(w); - if (!w) + if (!w || w->inputMethodHints() & Qt::ImhExclusiveInputMask) return; ICData *data = ximData.value(w->effectiveWinId()); diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index c77395a..159a997 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -2008,6 +2008,7 @@ void QAbstractItemView::keyPressEvent(QKeyEvent *event) } break; case Qt::Key_Back: + case Qt::Key_Context2: // TODO: aportale, remove KEYPAD_NAVIGATION_HACK when softkey support is there if (QApplication::keypadNavigationEnabled() && hasEditFocus()) setEditFocus(false); else diff --git a/src/gui/itemviews/qcolumnview_p.h b/src/gui/itemviews/qcolumnview_p.h index 8f75bec..432e5e8 100644 --- a/src/gui/itemviews/qcolumnview_p.h +++ b/src/gui/itemviews/qcolumnview_p.h @@ -55,7 +55,7 @@ #include "qcolumnview.h" -#ifndef QT_NO_QCOlUMNVIEW +#ifndef QT_NO_QCOLUMNVIEW #include <private/qabstractitemview_p.h> diff --git a/src/gui/itemviews/qdirmodel.cpp b/src/gui/itemviews/qdirmodel.cpp index 7da7c7a..a82ffd9 100644 --- a/src/gui/itemviews/qdirmodel.cpp +++ b/src/gui/itemviews/qdirmodel.cpp @@ -868,8 +868,10 @@ QModelIndex QDirModel::index(const QString &path, int column) const return QModelIndex(); QString absolutePath = QDir(path).absolutePath(); -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) absolutePath = absolutePath.toLower(); +#endif +#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) // On Windows, "filename......." and "filename" are equivalent if (absolutePath.endsWith(QLatin1Char('.'))) { int i; @@ -909,7 +911,10 @@ QModelIndex QDirModel::index(const QString &path, int column) const pathElements.pop_front(); if (childAppended) emit const_cast<QDirModel*>(this)->layoutChanged(); - } else if (pathElements.at(0).endsWith(QLatin1Char(':'))) { + } else +#endif +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) + if (pathElements.at(0).endsWith(QLatin1Char(':'))) { pathElements[0] += QLatin1Char('/'); } #else @@ -931,11 +936,9 @@ QModelIndex QDirModel::index(const QString &path, int column) const for (int j = parent->children.count() - 1; j >= 0; --j) { const QFileInfo& fi = parent->children.at(j).info; QString childFileName; -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) childFileName = idx.isValid() ? fi.fileName() : fi.absoluteFilePath(); +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) childFileName = childFileName.toLower(); -#else - childFileName = idx.isValid() ? fi.fileName() : fi.absoluteFilePath(); #endif if (childFileName == element) { if (i == pathElements.count() - 1) @@ -952,7 +955,7 @@ QModelIndex QDirModel::index(const QString &path, int column) const if (parent->info.isRoot()) newPath = parent->info.absoluteFilePath() + element; else - newPath= parent->info.absoluteFilePath() + QLatin1Char('/') + element; + newPath = parent->info.absoluteFilePath() + QLatin1Char('/') + element; #else QString newPath = parent->info.absoluteFilePath() + QLatin1Char('/') + element; #endif @@ -1304,6 +1307,8 @@ QString QDirModelPrivate::name(const QModelIndex &index) const #if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) if (name.startsWith(QLatin1Char('/'))) // UNC host return info.fileName(); +#endif +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) if (name.endsWith(QLatin1Char('/'))) name.chop(1); #endif diff --git a/src/gui/itemviews/qheaderview.cpp b/src/gui/itemviews/qheaderview.cpp index 86ece40..f888f5f 100644 --- a/src/gui/itemviews/qheaderview.cpp +++ b/src/gui/itemviews/qheaderview.cpp @@ -3560,7 +3560,7 @@ bool QHeaderViewPrivate::read(QDataStream &in) in >> minimumSectionSize; in >> align; - defaultAlignment = (Qt::Alignment)align; + defaultAlignment = Qt::Alignment(align); in >> global; globalResizeMode = (QHeaderView::ResizeMode)global; diff --git a/src/gui/itemviews/qitemdelegate.cpp b/src/gui/itemviews/qitemdelegate.cpp index a748199..fda6255 100644 --- a/src/gui/itemviews/qitemdelegate.cpp +++ b/src/gui/itemviews/qitemdelegate.cpp @@ -1321,7 +1321,7 @@ QStyleOptionViewItem QItemDelegate::setOptions(const QModelIndex &index, // set text alignment value = index.data(Qt::TextAlignmentRole); if (value.isValid()) - opt.displayAlignment = (Qt::Alignment)value.toInt(); + opt.displayAlignment = Qt::Alignment(value.toInt()); // set foreground brush value = index.data(Qt::ForegroundRole); diff --git a/src/gui/itemviews/qstandarditemmodel.cpp b/src/gui/itemviews/qstandarditemmodel.cpp index 10aac9a..61e410d 100644 --- a/src/gui/itemviews/qstandarditemmodel.cpp +++ b/src/gui/itemviews/qstandarditemmodel.cpp @@ -899,7 +899,7 @@ Qt::ItemFlags QStandardItem::flags() const if (!v.isValid()) return (Qt::ItemIsSelectable|Qt::ItemIsEnabled|Qt::ItemIsEditable |Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled); - return ((Qt::ItemFlags)(v.toInt())); + return Qt::ItemFlags(v.toInt()); } /*! @@ -1890,7 +1890,7 @@ void QStandardItem::read(QDataStream &in) in >> d->values; qint32 flags; in >> flags; - setFlags((Qt::ItemFlags)flags); + setFlags(Qt::ItemFlags(flags)); } /*! diff --git a/src/gui/itemviews/qstyleditemdelegate.cpp b/src/gui/itemviews/qstyleditemdelegate.cpp index 7f2c8ed..b75f151 100644 --- a/src/gui/itemviews/qstyleditemdelegate.cpp +++ b/src/gui/itemviews/qstyleditemdelegate.cpp @@ -322,7 +322,7 @@ void QStyledItemDelegate::initStyleOption(QStyleOptionViewItem *option, value = index.data(Qt::TextAlignmentRole); if (value.isValid() && !value.isNull()) - option->displayAlignment = (Qt::Alignment)value.toInt(); + option->displayAlignment = Qt::Alignment(value.toInt()); value = index.data(Qt::ForegroundRole); if (qVariantCanConvert<QBrush>(value)) diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index cb2b014..8f0692b 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -90,6 +90,27 @@ win32 { !contains(DEFINES, QT_NO_DIRECTDRAW):LIBS += ddraw.lib } +symbian { + SOURCES += \ + kernel/qapplication_s60.cpp \ + kernel/qeventdispatcher_s60.cpp \ + kernel/qwidget_s60.cpp \ + kernel/qcursor_s60.cpp \ + kernel/qdesktopwidget_s60.cpp \ + kernel/qkeymapper_s60.cpp\ + kernel/qclipboard_s60.cpp\ + kernel/qdnd_s60.cpp \ + kernel/qsound_s60.cpp + + HEADERS += \ + kernel/qt_s60_p.h \ + kernel/qeventdispatcher_s60_p.h + LIBS += -lbafl -lestor + + INCLUDEPATH += $$MW_LAYER_SYSTEMINCLUDE +} + + unix:x11 { INCLUDEPATH += ../3rdparty/xorg HEADERS += \ diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 4cf0ad7..eaaeb4b 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -74,6 +74,9 @@ #ifdef Q_WS_X11 #include <private/qt_x11_p.h> +#endif + +#if defined(Q_WS_X11) || defined(Q_WS_S60) #include "qinputcontextfactory.h" #endif @@ -133,6 +136,8 @@ bool QApplicationPrivate::quitOnLastWindowClosed = true; #ifdef Q_OS_WINCE int QApplicationPrivate::autoMaximizeThreshold = -1; bool QApplicationPrivate::autoSipEnabled = false; +#else +bool QApplicationPrivate::autoSipEnabled = true; #endif QApplicationPrivate::QApplicationPrivate(int &argc, char **argv, QApplication::Type type) @@ -430,7 +435,12 @@ bool Q_GUI_EXPORT qt_tab_all_widgets = true; bool qt_in_tab_key_event = false; int qt_antialiasing_threshold = -1; static int drag_time = 500; +#ifdef Q_WS_S60 +// The screens are a bit too small to for your thumb when using only 4 pixels drag distance. +static int drag_distance = 8; +#else static int drag_distance = 4; +#endif static Qt::LayoutDirection layout_direction = Qt::LeftToRight; QSize QApplicationPrivate::app_strut = QSize(0,0); // no default application strut bool QApplicationPrivate::animate_ui = true; @@ -441,12 +451,17 @@ bool QApplicationPrivate::animate_tooltip = false; bool QApplicationPrivate::fade_tooltip = false; bool QApplicationPrivate::animate_toolbox = false; bool QApplicationPrivate::widgetCount = false; +bool QApplicationPrivate::auto_sip_on_mouse_focus = false; QString* QApplicationPrivate::styleOverride = 0; #if defined(Q_WS_WIN) && !defined(Q_OS_WINCE) bool QApplicationPrivate::inSizeMove = false; #endif #ifdef QT_KEYPAD_NAVIGATION +# if defined(Q_WS_S60) +bool QApplicationPrivate::keypadNavigation = true; +# else bool QApplicationPrivate::keypadNavigation = false; +# endif QWidget *QApplicationPrivate::oldEditFocus = 0; #endif @@ -1068,6 +1083,7 @@ QApplication::~QApplication() QApplicationPrivate::animate_tooltip = false; QApplicationPrivate::fade_tooltip = false; QApplicationPrivate::widgetCount = false; + QApplicationPrivate::auto_sip_on_mouse_focus = false; // trigger unregistering of QVariant's GUI types extern int qUnregisterGuiVariant(); @@ -1220,11 +1236,15 @@ bool QApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventLis \since 4.5 \brief toggles automatic SIP (software input panel) visibility - The auto SIP property is only available as part of Qt for Windows CE. - Set this property to true to automatically display the SIP when entering widgets that accept keyboard input. This property only affects widgets with - the WA_InputMethodEnabled attribute set. + the WA_InputMethodEnabled attribute set, and is typically used to launch + a virtual keyboard on devices which have very few or no keys. + + The property only has an effect on platforms which use software input + panels, such as Windows CE and Symbian. + + The default is platform dependent. */ #ifdef Q_OS_WINCE @@ -1237,6 +1257,7 @@ int QApplication::autoMaximizeThreshold() const { return QApplicationPrivate::autoMaximizeThreshold; } +#endif void QApplication::setAutoSipEnabled(const bool enabled) { @@ -1247,7 +1268,6 @@ bool QApplication::autoSipEnabled() const { return QApplicationPrivate::autoSipEnabled; } -#endif #ifndef QT_NO_STYLE_STYLESHEET @@ -1319,6 +1339,8 @@ QStyle *QApplication::style() style = QLatin1String("Windows"); // default styles for Windows #elif defined(Q_WS_X11) && defined(Q_OS_SOLARIS) style = QLatin1String("CDE"); // default style for X11 on Solaris +#elif defined(Q_WS_S60) + style = QLatin1String("S60"); // default style for S60 #elif defined(Q_WS_X11) && defined(Q_OS_IRIX) style = QLatin1String("SGI"); // default style for X11 on IRIX #elif defined(Q_WS_X11) || defined(Q_WS_QWS) @@ -2080,6 +2102,16 @@ void QApplicationPrivate::setFocusWidget(QWidget *focus, Qt::FocusReason reason) prev->setEditFocus(false); } #endif +#ifndef QT_NO_IM + if (focus) { + QInputContext *prevIc; + prevIc = prev->inputContext(); + if (prevIc && prevIc != focus->inputContext()) { + QEvent closeSIPEvent(QEvent::CloseSoftwareInputPanel); + QApplication::sendEvent(prev, &closeSIPEvent); + } + } +#endif QFocusEvent out(QEvent::FocusOut, reason); QPointer<QWidget> that = prev; QApplication::sendEvent(prev, &out); @@ -3431,6 +3463,39 @@ Qt::LayoutDirection QApplication::layoutDirection() return layout_direction; } +/*! + \property autoSipOnMouseFocus + \since 4.6 + \brief toggles SIP (software input panel) launch policy + + This property holds whether widgets should request a software input + panel when it is focused with the mouse. This is typically used to + launch a virtual keyboard on devices which have very few or no keys. + + If the property is set to true, the widget asks for an input panel + on the mouse click which causes the widget to be focused. If the + property is set to false, the user must click a second time before + the widget asks for an input panel. + + \note If the widget is focused by other means than a mouse click, + the next click is will trigger an input panel request, + regardless of the value of this property. + + The default is platform dependent. + + \sa QEvent::RequestSoftwareInputPanel, QInputContext +*/ + +void QApplication::setAutoSipOnMouseFocus(bool enable) +{ + QApplicationPrivate::auto_sip_on_mouse_focus = enable; +} + +bool QApplication::autoSipOnMouseFocus() +{ + return QApplicationPrivate::auto_sip_on_mouse_focus; +} + /*! \obsolete @@ -3707,6 +3772,13 @@ bool QApplication::notify(QObject *receiver, QEvent *e) QPoint relpos = mouse->pos(); if (e->spontaneous()) { +#ifndef QT_NO_IM + QInputContext *ic = w->inputContext(); + if (ic + && w->testAttribute(Qt::WA_InputMethodEnabled) + && ic->filterEvent(mouse)) + return true; +#endif if (e->type() == QEvent::MouseButtonPress) { QWidget *fw = w; @@ -4017,6 +4089,20 @@ bool QApplication::notify(QObject *receiver, QEvent *e) break; #endif + case QEvent::RequestSoftwareInputPanel: + case QEvent::CloseSoftwareInputPanel: +#ifndef QT_NO_IM + if (receiver->isWidgetType()) { + QWidget *w = static_cast<QWidget *>(receiver); + QInputContext *ic = w->inputContext(); + if (ic && ic->filterEvent(e)) { + break; + } + } +#endif + res = d->notify_helper(receiver, e); + break; + default: res = d->notify_helper(receiver, e); break; @@ -4678,7 +4764,7 @@ void QApplicationPrivate::emitLastWindowClosed() If \a enable is true, Qt::Key_Up and Qt::Key_Down are used to change focus. - This feature is available in Qt for Embedded Linux only. + This feature is available in Qt for Embedded Linux and Symbian only. \sa keypadNavigationEnabled() */ @@ -4689,9 +4775,9 @@ void QApplication::setKeypadNavigationEnabled(bool enable) /*! Returns true if Qt is set to use keypad navigation; otherwise returns - false. The default is false. + false. The default value is true on Symbian, but false on other platforms. - This feature is available in Qt for Embedded Linux only. + This feature is available in Qt for Embedded Linux and Symbian only. \sa setKeypadNavigationEnabled() */ @@ -4748,8 +4834,8 @@ bool QApplication::keypadNavigationEnabled() The default value on X11 is 400 milliseconds. On Windows and Mac OS X, the operating system's value is used. - On Microsoft Windows, calling this function sets the double click interval - for all applications. + On Microsoft Windows and Symbian, calling this function sets the + double click interval for all applications. */ /*! @@ -4932,6 +5018,11 @@ QInputContext *QApplication::inputContext() const qic = QInputContextFactory::create(QLatin1String("xim"), that); that->d_func()->inputContext = qic; } +#elif defined(Q_WS_S60) + if (!d->inputContext) { + QApplication *that = const_cast<QApplication *>(this); + that->d_func()->inputContext = QInputContextFactory::create(QString::fromLatin1("coefep"), that); + } #endif return d->inputContext; } diff --git a/src/gui/kernel/qapplication.h b/src/gui/kernel/qapplication.h index 1d6941d..e1b8b26 100644 --- a/src/gui/kernel/qapplication.h +++ b/src/gui/kernel/qapplication.h @@ -61,6 +61,10 @@ QT_BEGIN_HEADER +#if defined(Q_WS_S60) +class TWsEvent; +#endif + QT_BEGIN_NAMESPACE QT_MODULE(Gui) @@ -84,6 +88,7 @@ class QApplicationPrivate; #endif #define qApp (static_cast<QApplication *>(QCoreApplication::instance())) + class Q_GUI_EXPORT QApplication : public QCoreApplication { Q_OBJECT @@ -92,6 +97,8 @@ class Q_GUI_EXPORT QApplication : public QCoreApplication Q_PROPERTY(int cursorFlashTime READ cursorFlashTime WRITE setCursorFlashTime) Q_PROPERTY(int doubleClickInterval READ doubleClickInterval WRITE setDoubleClickInterval) Q_PROPERTY(int keyboardInputInterval READ keyboardInputInterval WRITE setKeyboardInputInterval) + Q_PROPERTY(bool autoSipOnMouseFocus READ autoSipOnMouseFocus + WRITE setAutoSipOnMouseFocus) #ifndef QT_NO_WHEELEVENT Q_PROPERTY(int wheelScrollLines READ wheelScrollLines WRITE setWheelScrollLines) #endif @@ -104,8 +111,8 @@ class Q_GUI_EXPORT QApplication : public QCoreApplication #endif #ifdef Q_OS_WINCE Q_PROPERTY(int autoMaximizeThreshold READ autoMaximizeThreshold WRITE setAutoMaximizeThreshold) - Q_PROPERTY(bool autoSipEnabled READ autoSipEnabled WRITE setAutoSipEnabled) #endif + Q_PROPERTY(bool autoSipEnabled READ autoSipEnabled WRITE setAutoSipEnabled) public: enum Type { Tty, GuiClient, GuiServer }; @@ -223,6 +230,12 @@ public: virtual int x11ClientMessage(QWidget*, XEvent*, bool passive_only); int x11ProcessEvent(XEvent*); #endif +#if defined(Q_WS_S60) + int s60ProcessEvent(TWsEvent *event); + virtual bool s60EventFilter(TWsEvent *aEvent); + void symbianHandleCommand(int command); + void symbianResourceChange(int type); +#endif #if defined(Q_WS_QWS) virtual bool qwsEventFilter(QWSEvent *); int qwsProcessEvent(QWSEvent*); @@ -239,7 +252,6 @@ public: void winFocus(QWidget *, bool); static void winMouseButtonUp(); #endif - #ifndef QT_NO_SESSIONMANAGER // session management bool isSessionRestored() const; @@ -284,9 +296,11 @@ public Q_SLOTS: #ifdef Q_OS_WINCE void setAutoMaximizeThreshold(const int threshold); int autoMaximizeThreshold() const; +#endif void setAutoSipEnabled(const bool enabled); bool autoSipEnabled() const; -#endif + void setAutoSipOnMouseFocus(bool); + bool autoSipOnMouseFocus(); static void closeAllWindows(); static void aboutQt(); diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 7487f0a..a6fc602 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -221,8 +221,8 @@ public: static void emitLastWindowClosed(); #ifdef Q_OS_WINCE static int autoMaximizeThreshold; - static bool autoSipEnabled; #endif + static bool autoSipEnabled; static QGraphicsSystem *graphicsSystem() #if !defined(Q_WS_QWS) @@ -233,7 +233,6 @@ public: void createEventDispatcher(); QString appName() const; - static void dispatchEnterLeave(QWidget *enter, QWidget *leave); //modality @@ -355,6 +354,7 @@ public: static bool fade_tooltip; static bool animate_toolbox; static bool widgetCount; // Coupled with -widgetcount switch + static bool auto_sip_on_mouse_focus; #ifdef Q_WS_MAC static bool native_modal_dialog_active; #endif @@ -420,6 +420,9 @@ public: QWidget *buttonDown, QWidget *alienWidget); static bool sendMouseEvent(QWidget *receiver, QMouseEvent *event, QWidget *alienWidget, QWidget *native, QWidget **buttonDown, QPointer<QWidget> &lastMouseReceiver); +#ifdef Q_WS_S60 + static TUint resolveS60ScanCode(TInt scanCode, TUint keysym); +#endif #if defined(Q_WS_WIN) || defined(Q_WS_X11) void sendSyntheticEnterLeave(QWidget *widget); #endif @@ -429,6 +432,10 @@ private: QMap<const QScreen*, QRect> maxWindowRects; #endif +#ifdef Q_WS_S60 + static QHash<TInt, TUint> scanCodeCache; +#endif + static QApplicationPrivate *self; static bool shouldSetFocus(QWidget *w, Qt::FocusPolicy policy); }; diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp new file mode 100644 index 0000000..2f7bdcf --- /dev/null +++ b/src/gui/kernel/qapplication_s60.cpp @@ -0,0 +1,1165 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qapplication_p.h" +#include "qsessionmanager.h" +#include "qevent.h" +#include "qeventdispatcher_s60_p.h" +#include "qwidget.h" +#include "qdesktopwidget.h" +#include "private/qbackingstore_p.h" +#include "qt_s60_p.h" +#include "private/qevent_p.h" +#include "qstring.h" +#include "qdebug.h" +#include "qimage.h" +#include "private/qkeymapper_p.h" +#include "private/qfont_p.h" +#ifndef QT_NO_STYLE_S60 +#include "private/qs60style_p.h" +#endif +#include "private/qwindowsurface_s60_p.h" +#include "qpaintengine.h" +#include "private/qmenubar_p.h" + +#include "apgwgnam.h" // For CApaWindowGroupName +#include <MdaAudioTonePlayer.h> // For CMdaAudioToneUtility + +#ifndef QT_NO_IM +#include "qinputcontext.h" +#include <private/qcoefepinputcontext_p.h> +#endif // QT_NO_IM + +#include "private/qstylesheetstyle_p.h" + +QT_BEGIN_NAMESPACE + +static WId autoGrabWindow = 0; // Not the same as QWidget::grab*() +#if defined(QT_DEBUG) +static bool appNoGrab = false; // Grabbing enabled +#endif + +Q_GUI_EXPORT QS60Data *qt_s60Data = 0; +extern bool qt_sendSpontaneousEvent(QObject*,QEvent*); + +extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp + +QWidget *qt_button_down = 0; // widget got last button-down + +bool qt_nograb() // application no-grab option +{ +#if defined(QT_DEBUG) + return appNoGrab; +#else + return false; +#endif +} + +// Modified from http://www3.symbian.com/faq.nsf/0/0F1464EE96E737E780256D5E00503DD1?OpenDocument +class QS60Beep : public CBase, public MMdaAudioToneObserver +{ +public: + static QS60Beep* NewL(TInt aFrequency, TTimeIntervalMicroSeconds iDuration); + void Play(); + ~QS60Beep(); +private: + void ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds iDuration); + void MatoPrepareComplete(TInt aError); + void MatoPlayComplete(TInt aError); +private: + typedef enum TBeepState + { + EBeepNotPrepared, + EBeepPrepared, + EBeepPlaying + }; +private: + CMdaAudioToneUtility* iToneUtil; + TBeepState iState; + TInt iFrequency; + TTimeIntervalMicroSeconds iDuration; +}; + +QS60Beep::~QS60Beep() +{ + delete iToneUtil; +} + +QS60Beep* QS60Beep::NewL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration) +{ + QS60Beep* self=new (ELeave) QS60Beep(); + CleanupStack::PushL(self); + self->ConstructL(aFrequency, aDuration); + CleanupStack::Pop(); + return self; +}; + +void QS60Beep::ConstructL(TInt aFrequency, TTimeIntervalMicroSeconds aDuration) +{ + iToneUtil=CMdaAudioToneUtility::NewL(*this); + iState=EBeepNotPrepared; + iFrequency=aFrequency; + iDuration=aDuration; + iToneUtil->PrepareToPlayTone(iFrequency,iDuration); +} + +void QS60Beep::Play() +{ + if(iState!=EBeepNotPrepared){ + if(iState==EBeepPlaying) { + iToneUtil->CancelPlay(); + iState=EBeepPrepared; + } + } + + iToneUtil->Play(); + iState=EBeepPlaying; +} + +void QS60Beep::MatoPrepareComplete(TInt aError) +{ + if(aError==KErrNone) { + iState=EBeepPrepared; + } +} + +void QS60Beep::MatoPlayComplete(TInt aError) +{ + Q_UNUSED(aError); + iState=EBeepPrepared; +} + + +QHash<TInt, TUint> QApplicationPrivate::scanCodeCache; + +static Qt::KeyboardModifiers mapToQtModifiers(TUint s60Modifiers) +{ + Qt::KeyboardModifiers result = Qt::NoModifier; + + if (s60Modifiers & EModifierKeypad) + result |= Qt::KeypadModifier; + if (s60Modifiers & EModifierShift || s60Modifiers & EModifierLeftShift + || s60Modifiers & EModifierRightShift) + result |= Qt::ShiftModifier; + if (s60Modifiers & EModifierCtrl || s60Modifiers & EModifierLeftCtrl + || s60Modifiers & EModifierRightCtrl) + result |= Qt::ControlModifier; + if (s60Modifiers & EModifierAlt || s60Modifiers & EModifierLeftAlt + || s60Modifiers & EModifierRightAlt) + result |= Qt::AltModifier; + + return result; +} + +static void mapS60MouseEventTypeToQt(QEvent::Type *type, Qt::MouseButton *button, const TPointerEvent *pEvent) +{ + switch (pEvent->iType) { + case TPointerEvent::EButton1Down: + *type = QEvent::MouseButtonPress; + *button = Qt::LeftButton; + break; + case TPointerEvent::EButton1Up: + *type = QEvent::MouseButtonRelease; + *button = Qt::LeftButton; + break; + case TPointerEvent::EButton2Down: + *type = QEvent::MouseButtonPress; + *button = Qt::MidButton; + break; + case TPointerEvent::EButton2Up: + *type = QEvent::MouseButtonRelease; + *button = Qt::MidButton; + break; + case TPointerEvent::EButton3Down: + *type = QEvent::MouseButtonPress; + *button = Qt::RightButton; + break; + case TPointerEvent::EButton3Up: + *type = QEvent::MouseButtonRelease; + *button = Qt::RightButton; + break; + case TPointerEvent::EDrag: + *type = QEvent::MouseMove; + *button = Qt::NoButton; + break; + case TPointerEvent::EMove: + // Qt makes no distinction between move and drag + *type = QEvent::MouseMove; + *button = Qt::NoButton; + break; + default: + *type = QEvent::None; + *button = Qt::NoButton; + break; + } + if (pEvent->iModifiers & EModifierDoubleClick){ + *type = QEvent::MouseButtonDblClick; + } + + if (*type == QEvent::MouseButtonPress || *type == QEvent::MouseButtonDblClick) + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons | (*button); + else if (*type == QEvent::MouseButtonRelease) + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons &(~(*button)); + + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons & Qt::MouseButtonMask; +} + +//### Can be replaced with CAknLongTapDetector if animation is required. +//NOTE: if CAknLongTapDetector is used make sure it gets variated out of 3.1 and 3.2,. +//also MLongTapObserver needs to be changed to MAknLongTapDetectorCallBack if CAknLongTapDetector is used. +class QLongTapTimer : public CTimer +{ +public: + static QLongTapTimer* NewL(QAbstractLongTapObserver *observer); + QLongTapTimer(QAbstractLongTapObserver *observer); + void ConstructL(); +public: + void PointerEventL(const TPointerEvent &event); + void RunL(); +protected: +private: + QAbstractLongTapObserver *m_observer; + TPointerEvent m_event; + QPoint m_pressedCoordinates; + int m_dragDistance; +}; + +QLongTapTimer* QLongTapTimer::NewL(QAbstractLongTapObserver *observer) +{ + QLongTapTimer* self = new QLongTapTimer(observer); + self->ConstructL(); + return self; +} +void QLongTapTimer::ConstructL() +{ + CTimer::ConstructL(); +} + +QLongTapTimer::QLongTapTimer(QAbstractLongTapObserver *observer):CTimer(CActive::EPriorityHigh) +{ + m_observer = observer; + m_dragDistance = qApp->startDragDistance(); + CActiveScheduler::Add(this); +} + +void QLongTapTimer::PointerEventL(const TPointerEvent& event) +{ + if ( event.iType == TPointerEvent::EDrag || event.iType == TPointerEvent::EButtonRepeat) + { + QPoint diff(QPoint(event.iPosition.iX,event.iPosition.iY) - m_pressedCoordinates); + if (diff.manhattanLength() < m_dragDistance) + return; + } + Cancel(); + m_event = event; + if (event.iType == TPointerEvent::EButton1Down) + { + m_pressedCoordinates = QPoint(event.iPosition.iX,event.iPosition.iY); + // must be same as KLongTapDelay in aknlongtapdetector.h + After(800000); + } +} +void QLongTapTimer::RunL() +{ + if (m_observer) + m_observer->HandleLongTapEventL(m_event.iPosition, m_event.iParentPosition); +} + +QSymbianControl::QSymbianControl(QWidget *w) + : CCoeControl(), qwidget(w), m_ignoreFocusChanged(false) +{ +} + +void QSymbianControl::ConstructL(bool topLevel, bool desktop) +{ + if (!desktop) + { + if (topLevel) + CreateWindowL(S60->windowGroup()); + + SetFocusing(true); + m_longTapDetector = QLongTapTimer::NewL(this); + } +} + +QSymbianControl::~QSymbianControl() +{ + S60->appUi()->RemoveFromStack(this); + delete m_longTapDetector; +} + +void QSymbianControl::setWidget(QWidget *w) +{ + qwidget = w; +} +void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation ) +{ + QWidget *alienWidget; + QPoint widgetPos = QPoint(aPenEventLocation.iX, aPenEventLocation.iY); + QPoint globalPos = QPoint(aPenEventScreenLocation.iX,aPenEventScreenLocation.iY); + alienWidget = qwidget->childAt(widgetPos); + if (!alienWidget) + alienWidget = qwidget; + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons &(~Qt::LeftButton); + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons | Qt::RightButton; + QMouseEvent mEvent(QEvent::MouseButtonPress, alienWidget->mapFrom(qwidget, widgetPos), globalPos, + Qt::RightButton, QApplicationPrivate::mouse_buttons, Qt::NoModifier); + sendMouseEvent(alienWidget, &mEvent); + m_previousEventLongTap = false; +} + +void QSymbianControl::HandlePointerEventL(const TPointerEvent& pEvent) +{ + //### refactor me, getting too complex + m_longTapDetector->PointerEventL(pEvent); + QMouseEvent::Type type; + Qt::MouseButton button; + mapS60MouseEventTypeToQt(&type, &button, &pEvent); + + if (m_previousEventLongTap) + if (type == QEvent::MouseButtonRelease){ + button = Qt::RightButton; + QApplicationPrivate::mouse_buttons = QApplicationPrivate::mouse_buttons & ~Qt::RightButton; + m_previousEventLongTap = false; + } + if (type == QMouseEvent::None) + return; + + // store events for later sending/saving + QWidget *alienWidget; + typedef QPair<QWidget*,QMouseEvent> Event; + QList<Event > events; + + QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY); + TPoint controlScreenPos = PositionRelativeToScreen(); + QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos; + + if (type == QEvent::MouseButtonPress || type == QEvent::MouseButtonDblClick) + { + // get the button press target + alienWidget = qwidget->childAt(widgetPos); + if (!alienWidget) + alienWidget = qwidget; + S60->mousePressTarget = alienWidget; + //pointer grab + SetGloballyCapturing(ETrue); + SetPointerCapture(ETrue); + } + else if (type == QEvent::MouseButtonRelease) + { + //release pointer grab + SetGloballyCapturing(EFalse); + SetPointerCapture(EFalse); + } + alienWidget = S60->mousePressTarget; + + if (alienWidget != S60->lastPointerEventTarget) + if (type == QEvent::MouseButtonPress || QEvent::MouseButtonDblClick || type == QEvent::MouseMove) + { + //moved to another widget, create enter and leave events + if (S60->lastPointerEventTarget) + { + QMouseEvent mEventLeave(QEvent::Leave, S60->lastPointerEventTarget->mapFromGlobal(S60->lastCursorPos), S60->lastCursorPos, + button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers)); + events.append(Event(S60->lastPointerEventTarget,mEventLeave)); + } + QMouseEvent mEventEnter(QEvent::Enter, alienWidget->mapFromGlobal(globalPos), globalPos, + button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers)); + + events.append(Event(alienWidget,mEventEnter)); + } + S60->lastCursorPos = globalPos; + S60->lastPointerEventPos = widgetPos; + S60->lastPointerEventTarget = alienWidget; + if (alienWidget) + { + QMouseEvent mEvent(type, alienWidget->mapFromGlobal(globalPos), globalPos, + button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers)); + events.append(Event(alienWidget,mEvent)); + QEventDispatcherS60 *dispatcher; + // It is theoretically possible for someone to install a different event dispatcher. + if (dispatcher = qobject_cast<QEventDispatcherS60 *>(alienWidget->d_func()->threadData->eventDispatcher)) { + if (dispatcher->excludeUserInputEvents()) { + for (int i=0;i < events.count();++i) + { + Event next = events[i]; + dispatcher->saveInputEvent(this, next.first, new QMouseEvent(next.second)); + } + return; + } + } + } + for (int i=0;i < events.count();++i) + { + Event next = events[i]; + sendMouseEvent(next.first, &(next.second)); + } +} + +void QSymbianControl::sendMouseEvent(QWidget *widget, QMouseEvent *mEvent) +{ + qt_sendSpontaneousEvent(widget, mEvent); +} + +TKeyResponse QSymbianControl::OfferKeyEventL(const TKeyEvent& keyEvent, TEventCode type) +{ + switch (type) { + //case EEventKeyDown: // <-- Intentionally left out. See below. + case EEventKeyUp: + case EEventKey: + { + // S60 has a confusing way of delivering key events. There are three types of + // events: EKeyEvent, EKeyEventDown and EKeyEventUp. When a key is pressed, the + // two first events are generated. When releasing the key, the last one is + // generated. + // Because S60 does not generate keysyms for EKeyEventDown and EKeyEventUp events, + // we need to do some special tricks to map it to the Qt way. First, we completely + // discard EKeyEventDown events, since they are redundant. Second, since + // EKeyEventUp does not give us a keysym, we need to cache the keysyms from + // the EKeyEvent events. This is what resolveS60ScanCode does. + + + // ### hackish way to send Qt application to background when pressing right softkey + /* + if( keyEvent.iScanCode == EStdKeyDevice1 ) { + S60->window_group->SetOrdinalPosition(-1); + qApp->setActiveWindow(0); + return EKeyWasNotConsumed; + } + */ + + TUint s60Keysym = QApplicationPrivate::resolveS60ScanCode(keyEvent.iScanCode, + keyEvent.iCode); + int keyCode; + if (s60Keysym >= 0x20 && s60Keysym < ENonCharacterKeyBase) { + // Normal characters keys. + keyCode = s60Keysym; + } else { + // Special S60 keys. + keyCode = qt_keymapper_private()->mapS60KeyToQt(s60Keysym); + } + Qt::KeyboardModifiers mods = mapToQtModifiers(keyEvent.iModifiers); + QKeyEventEx qKeyEvent(type == EEventKeyUp ? QEvent::KeyRelease : QEvent::KeyPress, keyCode, + mods, qt_keymapper_private()->translateKeyEvent(keyCode, mods), + false, 1, keyEvent.iScanCode, s60Keysym, mods); +// WId wid = reinterpret_cast<RWindowGroup *>(keyEvent.Handle())->Child(); +// if (!wid) +// Could happen if window isn't shown yet. +// return EKeyWasNotConsumed; + QWidget *widget; + widget = QWidget::keyboardGrabber(); + if (!widget) { + if (QApplicationPrivate::popupWidgets != 0) { + widget = QApplication::activePopupWidget()->focusWidget(); + if (!widget) { + widget = QApplication::activePopupWidget(); + } + } else { + widget = QApplicationPrivate::focus_widget; + if (!widget) { + widget = qwidget; + } + } + } + + QEventDispatcherS60 *dispatcher; + // It is theoretically possible for someone to install a different event dispatcher. + if (dispatcher = qobject_cast<QEventDispatcherS60 *>(widget->d_func()->threadData->eventDispatcher)) { + if (dispatcher->excludeUserInputEvents()) { + dispatcher->saveInputEvent(this, widget, new QKeyEventEx(qKeyEvent)); + return EKeyWasConsumed; + } + } + return sendKeyEvent(widget, &qKeyEvent); + } + } + return EKeyWasNotConsumed; +} + +void QSymbianControl::sendInputEvent(QWidget *widget, QInputEvent *inputEvent) +{ + switch (inputEvent->type()) { + case QEvent::KeyPress: + case QEvent::KeyRelease: + sendKeyEvent(widget, static_cast<QKeyEvent *>(inputEvent)); + break; + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: + sendMouseEvent(widget, static_cast<QMouseEvent *>(inputEvent)); + break; + default: + // Shouldn't get here. + Q_ASSERT_X(0 == 1, "QSymbianControl::sendInputEvent()", "inputEvent->type() is unknown"); + break; + } +} + +TKeyResponse QSymbianControl::sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent) +{ +#ifndef QT_NO_IM + if (widget && widget->isEnabled() && widget->testAttribute(Qt::WA_InputMethodEnabled)) { + QInputContext *qic = widget->inputContext(); + if(qic && qic->filterEvent(keyEvent)) + return EKeyWasConsumed; + } +#endif // QT_NO_IM + + if (widget && qt_sendSpontaneousEvent(widget, keyEvent)) + if (keyEvent->isAccepted()) + return EKeyWasConsumed; + + return EKeyWasNotConsumed; +} + +#ifndef QT_NO_IM +TCoeInputCapabilities QSymbianControl::InputCapabilities() const +{ + QWidget *w = 0; + + if(qwidget->hasFocus()) { + w = qwidget; + } else { + w = qwidget->focusWidget(); + } + + QCoeFepInputContext *ic; + if (w && w->isEnabled() && w->testAttribute(Qt::WA_InputMethodEnabled) + && (ic = qobject_cast<QCoeFepInputContext *>(w->inputContext()))) { + return ic->inputCapabilities(); + } else { + return TCoeInputCapabilities(TCoeInputCapabilities::ENone, 0, 0); + } +} +#endif + +void QSymbianControl::Draw(const TRect& r) const +{ + QWindowSurface *surface = qwidget->windowSurface(); + if (!surface) + return; + + QPaintEngine *engine = surface->paintDevice()->paintEngine(); + if (!engine) + return; + if (engine->type() == QPaintEngine::Raster) { + QS60WindowSurface *s60Surface = static_cast<QS60WindowSurface *>(qwidget->windowSurface()); + CFbsBitmap *bitmap = s60Surface->symbianBitmap(); + CWindowGc &gc = SystemGc(); + if (qwidget->d_func()->isOpaque) + gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha); + gc.BitBlt(r.iTl, bitmap, r); + } else { + surface->flush(qwidget, QRegion(qt_TRect2QRect(r)), QPoint()); + } +} + +void QSymbianControl::SizeChanged() +{ + CCoeControl::SizeChanged(); + + QSize oldSize = qwidget->size(); + QSize newSize(Size().iWidth, Size().iHeight); + + if (oldSize != newSize) { + QRect cr = qwidget->geometry(); + cr.setSize(newSize); + qwidget->data->crect = cr; + if (qwidget->isVisible()) { + QTLWExtra *tlwExtra = qwidget->d_func()->maybeTopData(); + bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt(); + if (!slowResize && tlwExtra) + tlwExtra->inTopLevelResize = true; + QResizeEvent e(newSize, oldSize); + qt_sendSpontaneousEvent(qwidget, &e); + if (!qwidget->testAttribute(Qt::WA_StaticContents)) + qwidget->d_func()->syncBackingStore(); + if (!slowResize && tlwExtra) + tlwExtra->inTopLevelResize = false; + } + } +} + +void QSymbianControl::PositionChanged() +{ + CCoeControl::PositionChanged(); + + QPoint oldPos = qwidget->geometry().topLeft(); + QPoint newPos(Position().iX, Position().iY); + + if (oldPos != newPos) { + QRect cr = qwidget->geometry(); + cr.moveTopLeft(newPos); + qwidget->data->crect = cr; + QTLWExtra *top = qwidget->d_func()->maybeTopData(); + if (top) + top->normalGeometry = cr; + if (qwidget->isVisible()) { + QMoveEvent e(newPos, oldPos); + qt_sendSpontaneousEvent(qwidget, &e); + } else { + QMoveEvent * e = new QMoveEvent(newPos, oldPos); + QApplication::postEvent(qwidget, e); + } + } +} + +void QSymbianControl::FocusChanged(TDrawNow aDrawNow) +{ + if (m_ignoreFocusChanged) + return; + + // Popups never get focused, but still receive the FocusChanged when they are hidden. + if (QApplicationPrivate::popupWidgets != 0 + || (qwidget->windowType() & Qt::Popup) == Qt::Popup) + return; + + if (IsFocused()) { + QApplication::setActiveWindow(qwidget); + // If widget is fullscreen, hide status pane and button container + // otherwise show them. + CEikStatusPane* statusPane = S60->statusPane(); + CEikButtonGroupContainer* buttonGroup = S60->buttonGroupContainer(); + bool isFullscreen = qwidget->windowState() & Qt::WindowFullScreen; + if (statusPane && (statusPane->IsVisible() == isFullscreen)) + statusPane->MakeVisible(!isFullscreen); + if (buttonGroup && (buttonGroup->IsVisible() == isFullscreen)) + buttonGroup->MakeVisible(!isFullscreen); + } else { + QApplication::setActiveWindow(0); + } +} + +void QSymbianControl::HandleResourceChange(int resourceType) +{ + switch (resourceType) { + case KInternalStatusPaneChange: + qwidget->d_func()->setWindowIcon_sys(true); + break; + case KUidValueCoeFontChangeEvent: + // font change event + break; + case KEikDynamicLayoutVariantSwitch: + { + if (qwidget->isFullScreen()) { + SetExtentToWholeScreen(); + } else if (qwidget->isMaximized()) { + TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect(); + SetExtent(r.iTl, r.Size()); + } + break; + } + default: + break; + } + + CCoeControl::HandleResourceChange(resourceType); + +} +void QSymbianControl::CancelLongTapTimer() +{ + m_longTapDetector->Cancel(); +} + +TTypeUid::Ptr QSymbianControl::MopSupplyObject(TTypeUid id) +{ + if (id.iUid == ETypeId) + return id.MakePtr(this); + + return CCoeControl::MopSupplyObject(id); +} + +void qt_init(QApplicationPrivate *priv, int) +{ + S60 = new QS60Data; + +#ifdef QT_NO_DEBUG + if (!qgetenv("QT_S60_AUTO_FLUSH_WSERV").isEmpty()) +#endif + S60->wsSession().SetAutoFlush(ETrue); + + S60->updateScreenSize(); + + + TDisplayMode mode = S60->screenDevice()->DisplayMode(); + S60->screenDepth = TDisplayModeUtils::NumDisplayModeBitsPerPixel(mode); + + RProcess me; + TSecureId securId = me.SecureId(); + S60->uid = securId.operator TUid(); + + // New code to configure the window group name such that window server knows the associated application's UID + CApaWindowGroupName *wgn = CApaWindowGroupName::NewL(S60->wsSession()); + wgn->SetAppUid(S60->uid); + User::LeaveIfError(wgn->SetWindowGroupName((S60->windowGroup()))); + delete wgn; + +/* + ### Commented out for now as parameter handling not needed in SOS(yet). Code below will break testlib with -o flag + int argc = priv->argc; + char **argv = priv->argv; + + // Get command line params + int j = argc ? 1 : 0; + for (int i=1; i<argc; i++) { + if (argv[i] && *argv[i] != '-') { + argv[j++] = argv[i]; + continue; + } + +#if defined(QT_DEBUG) + if (qstrcmp(argv[i], "-nograb") == 0) + appNoGrab = !appNoGrab; + else +#endif // QT_DEBUG + ; + } +*/ +} + +/***************************************************************************** + qt_cleanup() - cleans up when the application is finished + *****************************************************************************/ +void qt_cleanup() +{ + QFontCache::cleanup(); // Has to happen now, since QFontEngineS60 has FBS handles +// S60 structure and window server session are freed in eventdispatcher destructor as they are needed there + + // It's important that this happens here, before the event dispatcher gets + // deleted, because the input context needs the event loop one last time before + // it dies. + delete QApplicationPrivate::inputContext; + QApplicationPrivate::inputContext = 0; +} + +void QApplicationPrivate::initializeWidgetPaletteHash() +{ + // TODO: Implement QApplicationPrivate::initializeWidgetPaletteHash() + // Possibly a task fot the S60Style guys +} + +void QApplicationPrivate::createEventDispatcher() +{ + Q_Q(QApplication); + eventDispatcher = new QEventDispatcherS60(q); +} + +QString QApplicationPrivate::appName() const +{ + return QCoreApplicationPrivate::appName(); +} + +bool QApplicationPrivate::modalState() +{ + return false; +} + +void QApplicationPrivate::enterModal_sys(QWidget *widget) +{ + // TODO: Implement QApplicationPrivate::enterModal_sys(QWidget *widget) +} + +void QApplicationPrivate::leaveModal_sys(QWidget *widget) +{ + // TODO: Implement QApplicationPrivate::leaveModal_sys(QWidget *widget) +} + +void QApplicationPrivate::openPopup(QWidget *popup) +{ + if (!QApplicationPrivate::popupWidgets) + QApplicationPrivate::popupWidgets = new QWidgetList; + QApplicationPrivate::popupWidgets->append(popup); + + if (QApplicationPrivate::popupWidgets->count() == 1 && !qt_nograb()) { + Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created)); + WId id = popup->effectiveWinId(); + id->SetPointerCapture(true); + id->SetGloballyCapturing(true); + + autoGrabWindow = id; + } + + // popups are not focus-handled by the window system (the first + // popup grabbed the keyboard), so we have to do that manually: A + // new popup gets the focus + if (popup->focusWidget()) { + popup->focusWidget()->setFocus(Qt::PopupFocusReason); + } else if (QApplicationPrivate::popupWidgets->count() == 1) { // this was the first popup + if (QWidget *fw = QApplication::focusWidget()) { + static_cast<QSymbianControl*>(fw->effectiveWinId())->CancelLongTapTimer(); + QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason); + q_func()->sendEvent(fw, &e); + } + } +} + +void QApplicationPrivate::closePopup(QWidget *popup) +{ + if (!QApplicationPrivate::popupWidgets) + return; + QApplicationPrivate::popupWidgets->removeAll(popup); + + if (QApplicationPrivate::popupWidgets->isEmpty()) { // this was the last popup + delete QApplicationPrivate::popupWidgets; + QApplicationPrivate::popupWidgets = 0; + if (!qt_nograb()) { // grabbing not disabled + Q_ASSERT(popup->testAttribute(Qt::WA_WState_Created)); + WId id = popup->effectiveWinId(); + id->SetPointerCapture(false); + id->SetGloballyCapturing(false); + if (QWidgetPrivate::mouseGrabber != 0) + QWidgetPrivate::mouseGrabber->grabMouse(); + + autoGrabWindow = 0; + if (QWidgetPrivate::keyboardGrabber != 0) + QWidgetPrivate::keyboardGrabber->grabKeyboard(); + + QWidget *fw = QApplicationPrivate::active_window ? QApplicationPrivate::active_window->focusWidget() + : q_func()->focusWidget(); + if (fw) { + if (fw != q_func()->focusWidget()) { + fw->setFocus(Qt::PopupFocusReason); + } else { + QFocusEvent e(QEvent::FocusIn, Qt::PopupFocusReason); + q_func()->sendEvent(fw, &e); + } + } + } + } else { + // popups are not focus-handled by the window system (the + // first popup grabbed the keyboard), so we have to do that + // manually: A popup was closed, so the previous popup gets + // the focus. + QWidget* aw = QApplicationPrivate::popupWidgets->last(); + if (QWidget *fw = QApplication::focusWidget()) { + QFocusEvent e(QEvent::FocusOut, Qt::PopupFocusReason); + q_func()->sendEvent(fw, &e); + } + } +} + +QWidget * QApplication::topLevelAt(QPoint const& point) +{ + QWidget *found = 0; + int lowestZ = INT_MAX; + QWidgetList list = QApplication::topLevelWidgets(); + for (int i = 0; i < list.count(); ++i) { + QWidget *widget = list.at(i); + if (widget->isVisible() && !(widget->windowType() == Qt::Desktop)) { + Q_ASSERT(widget->testAttribute(Qt::WA_WState_Created)); + if (widget->geometry().adjusted(0,0,1,1).contains(point)) { + // At this point we know there is a Qt widget under the point. + // Now we need to make sure it is the top most in the z-order. + RDrawableWindow* rw = widget->d_func()->topData()->rwindow; + int z = rw->OrdinalPosition(); + if (z < lowestZ) { + lowestZ = z; + found = widget; + } + } + } + } + return found; +} + +void QApplication::alert(QWidget *widget, int duration) +{ + // TODO: Implement QApplication::alert(QWidget *widget, int duration) +} + +int QApplication::doubleClickInterval() +{ + TTimeIntervalMicroSeconds32 us; + TInt distance; + S60->wsSession().GetDoubleClickSettings(us, distance); + return (us.Int() / 1000); +} + +void QApplication::setDoubleClickInterval(int ms) +{ + TTimeIntervalMicroSeconds32 newUs( ms * 1000); + TTimeIntervalMicroSeconds32 us; + TInt distance; + S60->wsSession().GetDoubleClickSettings(us, distance); + if (us != newUs) + S60->wsSession().SetDoubleClick(newUs, distance); +} + +int QApplication::keyboardInputInterval() +{ + return QApplicationPrivate::keyboard_input_time; +} + +void QApplication::setKeyboardInputInterval(int ms) +{ + QApplicationPrivate::keyboard_input_time = ms; +} + +int QApplication::cursorFlashTime() +{ + return QApplicationPrivate::cursor_flash_time; +} + +void QApplication::setCursorFlashTime(int msecs) +{ + QApplicationPrivate::cursor_flash_time = msecs; +} + +void QApplication::beep() +{ + TInt frequency=440; + TTimeIntervalMicroSeconds duration(500000); + QS60Beep* beep=NULL; + TRAPD(err, beep=QS60Beep::NewL(frequency, duration)); + if(!err) { + beep->Play(); + } + delete beep; + beep=NULL; +} + +int QApplication::s60ProcessEvent(TWsEvent *event) +{ + bool handled = s60EventFilter(event); + if (handled) + return 1; + + // Qt event handling. Handle some events regardless of if the handle is in our + // widget map or not. + CCoeControl* control = reinterpret_cast<CCoeControl*>(event->Handle()); + const bool controlInMap = QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control); + switch (event->Type()) { +#ifndef QT_NO_IM + case EEventKey: + case EEventKeyUp: + case EEventKeyDown: + { + // The control doesn't seem to be any of our widgets, so rely on the focused + // widget instead. If the user needs the control, it can be found inside the + // event structure. + QWidget *w = qApp ? qApp->focusWidget() : 0; + if (w) { + QInputContext *ic = w->inputContext(); + if (ic && ic->s60FilterEvent(w, event)) { + return 1; + } else { + return 0; + } + } + break; + } +#endif + case EEventPointerEnter: + if (controlInMap) + return 1; // Qt::Enter will be generated in HandlePointerL + break; + case EEventPointerExit: + if (controlInMap) { + if (S60) { + // mouseEvent outside our window, send leave event to last focused widget + QMouseEvent mEvent(QEvent::Leave, S60->lastPointerEventPos, S60->lastCursorPos, + Qt::NoButton, QApplicationPrivate::mouse_buttons, Qt::NoModifier); + if (S60->lastPointerEventTarget) + qt_sendSpontaneousEvent(S60->lastPointerEventTarget,&mEvent); + S60->lastPointerEventTarget = 0; + } + return 1; + } + break; + case EEventScreenDeviceChanged: + if (S60) + S60->updateScreenSize(); + if (qt_desktopWidget) { + QSize oldSize = qt_desktopWidget->size(); + qt_desktopWidget->data->crect.setWidth(S60->screenWidthInPixels); + qt_desktopWidget->data->crect.setHeight(S60->screenHeightInPixels); + QResizeEvent e(qt_desktopWidget->size(), oldSize); + QApplication::sendEvent(qt_desktopWidget, &e); + } + return 0; // Propagate to CONE + case EEventWindowVisibilityChanged: + if (controlInMap) { + const TWsVisibilityChangedEvent *visChangedEvent = event->VisibilityChanged(); + QWidget *w = QWidgetPrivate::mapper->value(control); + if (!w->d_func()->maybeTopData()) + break; + if (visChangedEvent->iFlags & TWsVisibilityChangedEvent::ENotVisible) { + delete w->d_func()->topData()->backingStore; + w->d_func()->topData()->backingStore = 0; + } else if ((visChangedEvent->iFlags & TWsVisibilityChangedEvent::EPartiallyVisible) + && !w->d_func()->maybeBackingStore()) { + w->d_func()->topData()->backingStore = new QWidgetBackingStore(w); + w->update(); + } + return 1; + } + break; + default: + break; + } + + if (!controlInMap) + return -1; + + return 0; +} + +bool QApplication::s60EventFilter(TWsEvent *aEvent) +{ + return false; +} + +/*! + Handles commands which are typically handled by CAknAppUi::HandleCommandL() + Qts Ui integration into Symbian is partially achieved by deriving from CAknAppUi. + Currently, exit, menu and softkey commands are handled + + \sa s60EventFilter(), s60ProcessEvent() +*/ +void QApplication::symbianHandleCommand(int command) +{ + switch (command) { + case EEikCmdExit: + case EAknSoftkeyBack: + case EAknSoftkeyExit: + qApp->exit(); + break; + default: + // For now assume all unknown menu items are Qt menu items + QMenuBarPrivate::symbianCommands(command); + break; + } +} + +void QApplication::symbianResourceChange(int type) +{ + switch (type) { + case KEikDynamicLayoutVariantSwitch: + { +#ifndef QT_NO_STYLE_S60 + QS60Style *s60Style = 0; + +#ifndef QT_NO_STYLE_STYLESHEET + QStyleSheetStyle *proxy = qobject_cast<QStyleSheetStyle*>(QApplication::style()); + if (proxy) + s60Style = qobject_cast<QS60Style*>(proxy->baseStyle()); + else +#endif + s60Style = qobject_cast<QS60Style*>(QApplication::style()); + + if (s60Style) + s60Style->handleDynamicLayoutVariantSwitch(); +#endif + } + break; + +#ifndef QT_NO_STYLE_S60 + case KAknsMessageSkinChange: + if (QS60Style *s60Style = qobject_cast<QS60Style*>(QApplication::style())) + s60Style->handleSkinChange(); + break; +#endif + + default: + break; + } +} + +#ifndef QT_NO_WHEELEVENT +int QApplication::wheelScrollLines() +{ + return QApplicationPrivate::wheel_scroll_lines; +} + +void QApplication::setWheelScrollLines(int n) +{ + QApplicationPrivate::wheel_scroll_lines = n; +} +#endif //QT_NO_WHEELEVENT + +bool QApplication::isEffectEnabled(Qt::UIEffect effect) +{ + // TODO: Implement QApplication::isEffectEnabled(Qt::UIEffect effect) + return false; +} + +void QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable) +{ + // TODO: Implement QApplication::setEffectEnabled(Qt::UIEffect effect, bool enable) +} + +TUint QApplicationPrivate::resolveS60ScanCode(TInt scanCode, TUint keysym) +{ + if (keysym) { + // If keysym is specified, cache it. + scanCodeCache.insert(scanCode, keysym); + return keysym; + } else { + // If not, retrieve the cached version. + return scanCodeCache[scanCode]; + } +} + +#ifndef QT_NO_SESSIONMANAGER +QSessionManager::QSessionManager(QApplication * app, QString &id, QString& key) +{ + +} + +QSessionManager::~QSessionManager() +{ + +} + +bool QSessionManager::allowsInteraction() +{ + return false; +} + +void QSessionManager::cancel() +{ + +} +#endif //QT_NO_SESSIONMANAGER +QT_END_NAMESPACE + + diff --git a/src/gui/kernel/qclipboard_s60.cpp b/src/gui/kernel/qclipboard_s60.cpp new file mode 100644 index 0000000..f89f3e5 --- /dev/null +++ b/src/gui/kernel/qclipboard_s60.cpp @@ -0,0 +1,277 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qclipboard.h" + +#ifndef QT_NO_CLIPBOARD + +#include "qapplication.h" +#include "qbitmap.h" +#include "qdatetime.h" +#include "qbuffer.h" +#include "qwidget.h" +#include "qevent.h" +#include <QtDebug> + +// Symbian's clipboard +#include <baclipb.h> +QT_BEGIN_NAMESPACE + +//### Mime Type mapping to UIDs + +const TUid KQtCbDataStream = {0x666777}; + + +class QClipboardData +{ +public: + QClipboardData(); + ~QClipboardData(); + + void setSource(QMimeData* s) + { + if (s == src) + return; + delete src; + src = s; + } + QMimeData* source() + { return src; } + bool connected() + { return connection; } + void clear(); + RFs fsSession(); + + +private: + QMimeData* src; + RFs iFs; + bool connection; +}; + +QClipboardData::QClipboardData():src(0),connection(true) +{ + clear(); + if (KErrNone != iFs.Connect()) + { + qWarning("QClipboardData::fileserver connnect failed"); + connection = false; + } +} + +QClipboardData::~QClipboardData() +{ + iFs.Close(); + connection = false; + delete src; +} + +void QClipboardData::clear() +{ + QMimeData* newSrc = new QMimeData; + delete src; + src = newSrc; +} +RFs QClipboardData::fsSession() +{ + return iFs; +} + +static QClipboardData *internalCbData = 0; + +static void cleanupClipboardData() +{ + delete internalCbData; + internalCbData = 0; +} + +static QClipboardData *clipboardData() +{ + if (internalCbData == 0) { + internalCbData = new QClipboardData; + if (internalCbData) + { + if (!internalCbData->connected()) + { + delete internalCbData; + internalCbData = 0; + } + else + { + qAddPostRoutine(cleanupClipboardData); + } + } + } + return internalCbData; +} + +void writeToStream(const QMimeData* aData, RWriteStream& aStream) +{ + QStringList headers = aData->formats(); + aStream << TCardinality(headers.count()); + for (QStringList::const_iterator iter= headers.constBegin();iter != headers.constEnd();iter++) + { + HBufC* stringData = TPtrC(reinterpret_cast<const TUint16*>((*iter).utf16())).AllocLC(); + QByteArray ba = aData->data((*iter)); + qDebug() << "copy to clipboard mime: " << *iter << " data: " << ba; + // mime type + aStream << TCardinality(stringData->Size()); + aStream << *(stringData); + // mime data + aStream << TCardinality(ba.size()); + aStream.WriteL(reinterpret_cast<const uchar*>(ba.constData()),ba.size()); + CleanupStack::PopAndDestroy(stringData); + } +} + +void readFromStream(QMimeData* aData,RReadStream& aStream) +{ + TCardinality mimeTypeCount; + aStream >> mimeTypeCount; + for (int i = 0; i< mimeTypeCount;i++) + { + // mime type + TCardinality mimeTypeSize; + aStream >> mimeTypeSize; + HBufC* mimeTypeBuf = HBufC::NewLC(aStream,mimeTypeSize); + QString mimeType = QString::fromUtf16(mimeTypeBuf->Des().Ptr(),mimeTypeBuf->Length()); + // mime data + TCardinality dataSize; + aStream >> dataSize; + QByteArray ba; + ba.reserve(dataSize); + aStream.ReadL(reinterpret_cast<uchar*>(ba.data_ptr()->data),dataSize); + ba.data_ptr()->size = dataSize; + qDebug() << "paste from clipboard mime: " << mimeType << " data: " << ba; + aData->setData(mimeType,ba); + CleanupStack::PopAndDestroy(mimeTypeBuf); + + } +} + + +/***************************************************************************** + QClipboard member functions + *****************************************************************************/ + +void QClipboard::clear(Mode mode) +{ + setText(QString(), mode); +} +const QMimeData* QClipboard::mimeData(Mode mode) const +{ + if (mode != Clipboard) return 0; + QClipboardData *d = clipboardData(); + if (d) + { + //###fixme when exceptions are added to Qt + TRAPD(err,{ + RFs fs = d->fsSession(); + CClipboard* cb = CClipboard::NewForReadingLC(fs); + Q_ASSERT(cb); + RStoreReadStream stream; + TStreamId stid = (cb->StreamDictionary()).At(KQtCbDataStream); + stream.OpenLC(cb->Store(),stid); + readFromStream(d->source(),stream); + CleanupStack::PopAndDestroy(2,cb); + return d->source(); + }); + if (err != KErrNone){ + qDebug()<< "clipboard is empty/err: " << err; + } + + } + return 0; +} + + +void QClipboard::setMimeData(QMimeData* src, Mode mode) +{ + if (mode != Clipboard) return; + QClipboardData *d = clipboardData(); + if (d) + { + //###fixme when exceptions are added to Qt + TRAPD(err,{ + RFs fs = d->fsSession(); + CClipboard* cb = CClipboard::NewForWritingLC(fs); + RStoreWriteStream stream; + TStreamId stid = stream.CreateLC(cb->Store()); + writeToStream(src,stream); + d->setSource(src); + stream.CommitL(); + (cb->StreamDictionary()).AssignL(KQtCbDataStream,stid); + cb->CommitL(); + CleanupStack::PopAndDestroy(2,cb); + }); + if (err != KErrNone){ + qDebug()<< "clipboard write err :" << err; + } + } + emitChanged(QClipboard::Clipboard); +} + +bool QClipboard::supportsMode(Mode mode) const +{ + return (mode == Clipboard); +} + +bool QClipboard::ownsMode(Mode mode) const +{ + if (mode == Clipboard) + qWarning("QClipboard::ownsClipboard: UNIMPLEMENTED!"); + return false; +} + +bool QClipboard::event(QEvent *e) +{ + return true; +} + +void QClipboard::connectNotify( const char * ) +{ +} + +void QClipboard::ownerDestroyed() +{ +} +QT_END_NAMESPACE +#endif // QT_NO_CLIPBOARD
\ No newline at end of file diff --git a/src/gui/kernel/qcursor.cpp b/src/gui/kernel/qcursor.cpp index 598f4ba..21a4287 100644 --- a/src/gui/kernel/qcursor.cpp +++ b/src/gui/kernel/qcursor.cpp @@ -561,7 +561,6 @@ QCursor::operator QVariant() const { return QVariant(QVariant::Cursor, this); } - +QT_END_NAMESPACE #endif // QT_NO_CURSOR -QT_END_NAMESPACE diff --git a/src/gui/kernel/qcursor_s60.cpp b/src/gui/kernel/qcursor_s60.cpp new file mode 100644 index 0000000..a281130 --- /dev/null +++ b/src/gui/kernel/qcursor_s60.cpp @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <private/qcursor_p.h> +#include <qcursor.h> +#include <qt_s60_p.h> + +#ifdef QT_NO_CURSOR +QT_BEGIN_NAMESPACE + +QPoint QCursor::pos() +{ + return S60->lastCursorPos; +} + +void QCursor::setPos(int x, int y) +{ + S60->lastCursorPos = QPoint(x, y); +} + +QT_END_NAMESPACE +#endif // QT_NO_CURSOR diff --git a/src/gui/kernel/qdesktopwidget_s60.cpp b/src/gui/kernel/qdesktopwidget_s60.cpp new file mode 100644 index 0000000..eefd0ef --- /dev/null +++ b/src/gui/kernel/qdesktopwidget_s60.cpp @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdesktopwidget.h" +#include "qapplication_p.h" +#include "qwidget_p.h" +#include "qt_s60_p.h" +#include <w32std.h> + +#include "hal.h" +#include "hal_data.h" + +QT_BEGIN_NAMESPACE + +class QDesktopWidgetPrivate : public QWidgetPrivate +{ + +public: + QDesktopWidgetPrivate(); + ~QDesktopWidgetPrivate(); + + static void init(QDesktopWidget *that); + static void cleanup(); + + static int screenCount; + static int primaryScreen; + + static QVector<QRect> *rects; + static QVector<QRect> *workrects; + + static int refcount; +}; + +int QDesktopWidgetPrivate::screenCount = 1; +int QDesktopWidgetPrivate::primaryScreen = 0; +QVector<QRect> *QDesktopWidgetPrivate::rects = 0; +QVector<QRect> *QDesktopWidgetPrivate::workrects = 0; +int QDesktopWidgetPrivate::refcount = 0; + +QDesktopWidgetPrivate::QDesktopWidgetPrivate() +{ + ++refcount; +} + +QDesktopWidgetPrivate::~QDesktopWidgetPrivate() +{ + if (!--refcount) + cleanup(); +} + +void QDesktopWidgetPrivate::init(QDesktopWidget *that) +{ + int screenCount=0; + + if (HAL::Get(0, HALData::EDisplayNumberOfScreens, screenCount) == KErrNone) + QDesktopWidgetPrivate::screenCount = screenCount; + else + QDesktopWidgetPrivate::screenCount = 0; + + rects = new QVector<QRect>(); + workrects = new QVector<QRect>(); + + rects->resize(QDesktopWidgetPrivate::screenCount); + workrects->resize(QDesktopWidgetPrivate::screenCount); + + // ### TODO: Implement proper multi-display support + rects->resize(1); + rects->replace(0, that->rect()); + workrects->resize(1); + workrects->replace(0, that->rect()); +} + +void QDesktopWidgetPrivate::cleanup() +{ + delete rects; + rects = 0; + delete workrects; + workrects = 0; +} + + +QDesktopWidget::QDesktopWidget() + : QWidget(*new QDesktopWidgetPrivate, 0, Qt::Desktop) +{ + setObjectName(QLatin1String("desktop")); + QDesktopWidgetPrivate::init(this); +} + +QDesktopWidget::~QDesktopWidget() +{ + QDesktopWidgetPrivate::cleanup(); +} + +bool QDesktopWidget::isVirtualDesktop() const +{ + return true; +} + +int QDesktopWidget::primaryScreen() const +{ + return QDesktopWidgetPrivate::primaryScreen; +} + +int QDesktopWidget::numScreens() const +{ + Q_D(const QDesktopWidget); + return QDesktopWidgetPrivate::screenCount; +} + +QWidget *QDesktopWidget::screen(int /* screen */) +{ + return this; +} + +const QRect QDesktopWidget::availableGeometry(int /* screen */) const +{ + TRect clientRect = static_cast<CEikAppUi*>(S60->appUi())->ClientRect(); + return qt_TRect2QRect(clientRect); +} + +const QRect QDesktopWidget::screenGeometry(int /* screen */) const +{ + Q_D(const QDesktopWidget); + return QRect(0, 0, S60->screenWidthInPixels, S60->screenHeightInPixels); + } + +int QDesktopWidget::screenNumber(const QWidget *widget) const +{ + return QDesktopWidgetPrivate::primaryScreen; +} + +int QDesktopWidget::screenNumber(const QPoint &point) const +{ + return QDesktopWidgetPrivate::primaryScreen; +} + +void QDesktopWidget::resizeEvent(QResizeEvent *) +{ + Q_D(QDesktopWidget); + QVector<QRect> oldrects; + oldrects = *d->rects; + QVector<QRect> oldworkrects; + oldworkrects = *d->workrects; + int oldscreencount = d->screenCount; + + QDesktopWidgetPrivate::cleanup(); + QDesktopWidgetPrivate::init(this); + + for (int i = 0; i < qMin(oldscreencount, d->screenCount); ++i) { + QRect oldrect = oldrects[i]; + QRect newrect = d->rects->at(i); + if (oldrect != newrect) + emit resized(i); + } + + for (int j = 0; j < qMin(oldscreencount, d->screenCount); ++j) { + QRect oldrect = oldworkrects[j]; + QRect newrect = d->workrects->at(j); + if (oldrect != newrect) + emit workAreaResized(j); + } +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qdnd_s60.cpp b/src/gui/kernel/qdnd_s60.cpp new file mode 100644 index 0000000..c459f8f --- /dev/null +++ b/src/gui/kernel/qdnd_s60.cpp @@ -0,0 +1,395 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qapplication.h" + +#ifndef QT_NO_DRAGANDDROP + +#include "qwidget.h" +#include "qdatetime.h" +#include "qbitmap.h" +#include "qcursor.h" +#include "qevent.h" +#include "qpainter.h" +#include "qdnd_p.h" + +#include <COECNTRL.H> +// pointer cursor +#include <w32std.h> +#include <gdi.h> +QT_BEGIN_NAMESPACE +//### artistic impression of Symbians default DnD cursor ? + +static QPixmap *defaultPm = 0; +static const int default_pm_hotx = -50; +static const int default_pm_hoty = -50; +static const char *const default_pm[] = { +"13 9 3 1", +". c None", +" c #000000", +"X c #FFFFFF", +"X X X X X X X", +" X X X X X X ", +"X ......... X", +" X.........X ", +"X ......... X", +" X.........X ", +"X ......... X", +" X X X X X X ", +"X X X X X X X", +}; +//### actions need to be redefined for S60 +// Shift/Ctrl handling, and final drop status +static Qt::DropAction global_accepted_action = Qt::MoveAction; +static Qt::DropActions possible_actions = Qt::IgnoreAction; + + +// static variables in place of a proper cross-process solution +static QDrag *drag_object; +static bool qt_symbian_dnd_dragging = false; + + +static Qt::KeyboardModifiers oldstate; + +class QShapedPixmapWidget +{ +public: + QShapedPixmapWidget(RWsSession aWsSession,RWindowTreeNode* aNode) + { + sprite = RWsSprite(aWsSession); + cursorSprite.iBitmap = 0; + cursorSprite.iMaskBitmap = 0; + cursorSprite.iInvertMask = EFalse; + cursorSprite.iOffset = TPoint(0,0); + cursorSprite.iInterval = TTimeIntervalMicroSeconds32(0); + cursorSprite.iDrawMode = CGraphicsContext::EDrawModePEN; + sprite.Construct(*aNode,TPoint(0,0), ESpriteNoShadows | ESpriteNoChildClip); + sprite.AppendMember(cursorSprite); + sprite.Activate(); + } + ~QShapedPixmapWidget() + { + sprite.Close(); + cursorSprite.iBitmap = 0; + delete cursorBitmap; + cursorBitmap = 0; //redundant... + } + void disableCursor() + { + cursorSprite.iBitmap = 0; + sprite.UpdateMember(0,cursorSprite); + } + void enableCursor() + { + cursorSprite.iBitmap = cursorBitmap; + sprite.UpdateMember(0,cursorSprite); + } + void setPixmap(QPixmap pm) + { + //### heaplock centralized. + QImage temp = pm.toImage(); + QSize size = pm.size(); + temp.bits(); + CFbsBitmap *curbm = new (ELeave) CFbsBitmap(); + curbm->Create(TSize(size.width(),size.height()),EColor16MA); + curbm->LockHeap(ETrue); + memcpy((uchar*)curbm->DataAddress(),temp.bits(),temp.numBytes()); + curbm->UnlockHeap(ETrue); + delete cursorSprite.iBitmap; + cursorSprite.iBitmap = curbm; + cursorBitmap = curbm; + sprite.UpdateMember(0,cursorSprite); + } + CFbsBitmap *cursorBitmap; + RWsPointerCursor pointerCursor; + RWsSprite sprite; + TSpriteMember cursorSprite; + +}; + + +static QShapedPixmapWidget *qt_symbian_dnd_deco = 0; + +void QDragManager::updatePixmap() +{ + if (qt_symbian_dnd_deco) { + QPixmap pm; + QPoint pm_hot(default_pm_hotx,default_pm_hoty); + if (drag_object) { + pm = drag_object->pixmap(); + if (!pm.isNull()) + pm_hot = drag_object->hotSpot(); + } + if (pm.isNull()) { + if (!defaultPm) + defaultPm = new QPixmap(default_pm); + pm = *defaultPm; + } + qt_symbian_dnd_deco->setPixmap(pm); + } +} + +void QDragManager::timerEvent(QTimerEvent *) { } + +void QDragManager::move(const QPoint&) { +} + +void QDragManager::updateCursor() +{ +} + + +bool QDragManager::eventFilter(QObject *o, QEvent *e) +{ + if (beingCancelled) { + return false; + } + if (!o->isWidgetType()) + return false; + + switch(e->type()) { + case QEvent::MouseButtonPress: + { + } + case QEvent::MouseMove: + { + if (!object) { //#### this should not happen + qWarning("QDragManager::eventFilter: No object"); + return true; + } + QDragManager *manager = QDragManager::self(); + QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData; + if (manager->object) + possible_actions = manager->dragPrivate()->possible_actions; + else + possible_actions = Qt::IgnoreAction; + + QMouseEvent *me = (QMouseEvent *)e; + + if (me->buttons()) { + Qt::DropAction prevAction = global_accepted_action; + QWidget *cw = QApplication::widgetAt(me->globalPos()); + // map the Coords relative to the window. + if (!cw) + return true; + TPoint windowPos = cw->effectiveWinId()->PositionRelativeToScreen(); + qt_symbian_dnd_deco->sprite.SetPosition(TPoint(me->globalX()- windowPos.iX,me->globalY()- windowPos.iY)); + + while (cw && !cw->acceptDrops() && !cw->isWindow()) + cw = cw->parentWidget(); + + if (object->target() != cw) { + if (object->target()) { + QDragLeaveEvent dle; + QApplication::sendEvent(object->target(), &dle); + willDrop = false; + global_accepted_action = Qt::IgnoreAction; + updateCursor(); + restoreCursor = true; + object->d_func()->target = 0; + } + if (cw && cw->acceptDrops()) { + object->d_func()->target = cw; + QDragEnterEvent dee(cw->mapFromGlobal(me->globalPos()), possible_actions, dropData, + me->buttons(), me->modifiers()); + QApplication::sendEvent(object->target(), &dee); + willDrop = dee.isAccepted() && dee.dropAction() != Qt::IgnoreAction; + global_accepted_action = willDrop ? dee.dropAction() : Qt::IgnoreAction; + updateCursor(); + restoreCursor = true; + } + } else if (cw) { + QDragMoveEvent dme(cw->mapFromGlobal(me->globalPos()), possible_actions, dropData, + me->buttons(), me->modifiers()); + if (global_accepted_action != Qt::IgnoreAction) { + dme.setDropAction(global_accepted_action); + dme.accept(); + } + QApplication::sendEvent(cw, &dme); + willDrop = dme.isAccepted(); + global_accepted_action = willDrop ? dme.dropAction() : Qt::IgnoreAction; + updatePixmap(); + updateCursor(); + } + if (global_accepted_action != prevAction) + emitActionChanged(global_accepted_action); + } + return true; // Eat all mouse events + } + + case QEvent::MouseButtonRelease: + { + qApp->removeEventFilter(this); + if (restoreCursor) { + qt_symbian_dnd_deco->disableCursor(); + willDrop = false; + restoreCursor = false; + } + if (object && object->target()) { + + QMouseEvent *me = (QMouseEvent *)e; + + QDragManager *manager = QDragManager::self(); + QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData; + + QDropEvent de(object->target()->mapFromGlobal(me->globalPos()), possible_actions, dropData, + me->buttons(), me->modifiers()); + QApplication::sendEvent(object->target(), &de); + if (de.isAccepted()) + global_accepted_action = de.dropAction(); + else + global_accepted_action = Qt::IgnoreAction; + + if (object) + object->deleteLater(); + drag_object = object = 0; + } + eventLoop->exit(); + return true; // Eat all mouse events + } + + default: + break; + } + return false; +} + +Qt::DropAction QDragManager::drag(QDrag *o) +{ + Q_ASSERT(!qt_symbian_dnd_dragging); + if (object == o || !o || !o->source()) + return Qt::IgnoreAction; + + if (object) { + cancel(); + qApp->removeEventFilter(this); + beingCancelled = false; + } + + object = drag_object = o; + RWsSession winSession = o->source()->effectiveWinId()->ControlEnv()->WsSession(); + Q_ASSERT(!qt_symbian_dnd_deco); + qt_symbian_dnd_deco = new QShapedPixmapWidget(winSession, o->source()->effectiveWinId()->DrawableWindow()); + + oldstate = Qt::NoModifier; // #### Should use state that caused the drag + willDrop = false; + updatePixmap(); + updateCursor(); + restoreCursor = true; + + object->d_func()->target = 0; + TPoint windowPos = source()->effectiveWinId()->PositionRelativeToScreen(); + qt_symbian_dnd_deco->sprite.SetPosition(TPoint(QCursor::pos().x()- windowPos.iX ,QCursor::pos().y() - windowPos.iY)); + + QPoint hotspot = drag_object->hotSpot(); + qt_symbian_dnd_deco->cursorSprite.iOffset = TPoint(- hotspot.x(),- hotspot.y()); + qt_symbian_dnd_deco->sprite.UpdateMember(0,qt_symbian_dnd_deco->cursorSprite); + + qApp->installEventFilter(this); + + global_accepted_action = Qt::MoveAction; + qt_symbian_dnd_dragging = true; + + eventLoop = new QEventLoop; + // block + (void) eventLoop->exec(QEventLoop::AllEvents); + delete eventLoop; + eventLoop = 0; + + delete qt_symbian_dnd_deco; + qt_symbian_dnd_deco = 0; + qt_symbian_dnd_dragging = false; + + + return global_accepted_action; +} + + +void QDragManager::cancel(bool deleteSource) +{ + beingCancelled = true; + + if (object->target()) { + QDragLeaveEvent dle; + QApplication::sendEvent(object->target(), &dle); + } + + if (drag_object) { + if (deleteSource) + object->deleteLater(); + drag_object = object = 0; + } + + delete qt_symbian_dnd_deco; + qt_symbian_dnd_deco = 0; + + global_accepted_action = Qt::IgnoreAction; +} + + +void QDragManager::drop() +{ +} + +QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type type) const +{ + if (!drag_object) + return QVariant(); + QByteArray data = drag_object->mimeData()->data(mimetype); + if (type == QVariant::String) + return QString::fromUtf8(data); + return data; +} + +bool QDropData::hasFormat_sys(const QString &format) const +{ + return formats().contains(format); +} + +QStringList QDropData::formats_sys() const +{ + if (drag_object) + return drag_object->mimeData()->formats(); + return QStringList(); +} + +QT_END_NAMESPACE +#endif // QT_NO_DRAGANDDROP diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 2aed287..ba85eea 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -1665,6 +1665,17 @@ Qt::ButtonState QContextMenuEvent::state() const several are specified for any character in the string the behaviour is undefined. + \value Selection + If set, the edit cursor should be moved to the specified position + in the editor text contents. In contrast with \c Cursor, this + attribute does not work on the preedit text, but on the surrounding + text. The cursor will be moved after the commit string has been + committed, and the preedit string will be located at the new edit + position. + The start position specifies the new position and the length + variable can be used to set a selection starting from that point. + The value is unused. + \sa Attribute */ diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 449730d..7696d05 100644 --- a/src/gui/kernel/qevent.h +++ b/src/gui/kernel/qevent.h @@ -241,7 +241,7 @@ public: inline QT3_SUPPORT_CONSTRUCTOR QKeyEvent(Type type, int key, int /*ascii*/, int modifiers, const QString& text = QString(), bool autorep = false, ushort count = 1) - : QInputEvent(type, (Qt::KeyboardModifiers)(modifiers & (int)Qt::KeyButtonMask)), txt(text), k(key), + : QInputEvent(type, Qt::KeyboardModifiers(modifiers & (int)Qt::KeyButtonMask)), txt(text), k(key), c(count), autor(autorep) { if (key >= Qt::Key_Back && key <= Qt::Key_MediaLast) @@ -424,7 +424,8 @@ public: TextFormat, Cursor, Language, - Ruby + Ruby, + Selection }; class Attribute { public: diff --git a/src/gui/kernel/qeventdispatcher_s60.cpp b/src/gui/kernel/qeventdispatcher_s60.cpp new file mode 100644 index 0000000..6ac2863 --- /dev/null +++ b/src/gui/kernel/qeventdispatcher_s60.cpp @@ -0,0 +1,124 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qwidget.h> + +#include "qeventdispatcher_s60_p.h" + +QT_BEGIN_NAMESPACE + +QEventDispatcherS60::QEventDispatcherS60(QObject *parent) + : QEventDispatcherSymbian(parent), + m_noInputEvents(false) +{ +} + +QEventDispatcherS60::~QEventDispatcherS60() +{ + for (int c = 0; c < m_deferredInputEvents.size(); ++c) { + delete m_deferredInputEvents[c].event; + } +} + +bool QEventDispatcherS60::processEvents ( QEventLoop::ProcessEventsFlags flags ) +{ + bool ret = false; + + bool oldNoInputEventsValue = m_noInputEvents; + if (flags & QEventLoop::ExcludeUserInputEvents) { + m_noInputEvents = true; + } else { + m_noInputEvents = false; + ret = sendDeferredInputEvents() || ret; + } + + ret = QEventDispatcherSymbian::processEvents(flags) || ret; + + m_noInputEvents = oldNoInputEventsValue; + + return ret; +} + +bool QEventDispatcherS60::hasPendingEvents() +{ + return !m_deferredInputEvents.isEmpty() || QEventDispatcherSymbian::hasPendingEvents(); +} + +void QEventDispatcherS60::saveInputEvent(QSymbianControl *control, QWidget *widget, QInputEvent *event) +{ + DeferredInputEvent inputEvent = {control, widget, event}; + m_deferredInputEvents.append(inputEvent); + connect(widget, SIGNAL(destroyed(QObject *)), SLOT(removeInputEventsForWidget(QObject *))); +} + +bool QEventDispatcherS60::sendDeferredInputEvents() +{ + bool eventsSent = false; + while (!m_deferredInputEvents.isEmpty()) { + DeferredInputEvent inputEvent = m_deferredInputEvents.takeFirst(); +#ifndef QT_NO_EXCEPTIONS + try { +#endif + inputEvent.control->sendInputEvent(inputEvent.widget, inputEvent.event); +#ifndef QT_NO_EXCEPTIONS + } catch (...) { + delete inputEvent.event; + throw; + } +#endif + delete inputEvent.event; + eventsSent = true; + } + + return eventsSent; +} + +void QEventDispatcherS60::removeInputEventsForWidget(QObject *object) +{ + for (int c = 0; c < m_deferredInputEvents.size(); ++c) { + if (m_deferredInputEvents[c].widget == object) { + delete m_deferredInputEvents[c].event; + m_deferredInputEvents.removeAt(c--); + } + } +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qeventdispatcher_s60_p.h b/src/gui/kernel/qeventdispatcher_s60_p.h new file mode 100644 index 0000000..e42af95 --- /dev/null +++ b/src/gui/kernel/qeventdispatcher_s60_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEVENTDISPATCHER_S60_P_H +#define QEVENTDISPATCHER_S60_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qeventdispatcher_symbian_p.h> +#include "qt_s60_p.h" + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QEventDispatcherS60 : public QEventDispatcherSymbian +{ + Q_OBJECT + +public: + QEventDispatcherS60(QObject *parent = 0); + ~QEventDispatcherS60(); + + bool processEvents ( QEventLoop::ProcessEventsFlags flags ); + bool hasPendingEvents(); + + bool excludeUserInputEvents() { return m_noInputEvents; } + + void saveInputEvent(QSymbianControl *control, QWidget *widget, QInputEvent *event); + +private: + bool sendDeferredInputEvents(); + +private Q_SLOTS: + void removeInputEventsForWidget(QObject *object); + +private: + bool m_noInputEvents; + + struct DeferredInputEvent + { + QSymbianControl *control; + QWidget *widget; + QInputEvent *event; + }; + QList<DeferredInputEvent> m_deferredInputEvents; +}; + +QT_END_NAMESPACE + +#endif // QEVENTDISPATCHER_S60_P_H diff --git a/src/gui/kernel/qkeymapper_p.h b/src/gui/kernel/qkeymapper_p.h index f1d938c..8937aaf 100644 --- a/src/gui/kernel/qkeymapper_p.h +++ b/src/gui/kernel/qkeymapper_p.h @@ -58,6 +58,7 @@ #include <qlist.h> #include <qlocale.h> #include <qevent.h> +#include <qhash.h> #if defined (Q_WS_MAC64) # include <private/qt_mac_p.h> @@ -203,6 +204,13 @@ public: UInt32 keyboard_dead; KeyboardLayoutItem *keyLayout[256]; #elif defined(Q_WS_QWS) +#elif defined(Q_WS_S60) +private: + QHash<TUint, int> s60ToQtKeyMap; + void fillKeyMap(); +public: + QString translateKeyEvent(int keySym, Qt::KeyboardModifiers modifiers); + int mapS60KeyToQt(TUint s60key); #endif }; diff --git a/src/gui/kernel/qkeymapper_s60.cpp b/src/gui/kernel/qkeymapper_s60.cpp new file mode 100644 index 0000000..bb074c1 --- /dev/null +++ b/src/gui/kernel/qkeymapper_s60.cpp @@ -0,0 +1,247 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qkeymapper_p.h" +#include <e32keys.h> + +QT_BEGIN_NAMESPACE + +QKeyMapperPrivate::QKeyMapperPrivate() +{ + fillKeyMap(); +} + +QKeyMapperPrivate::~QKeyMapperPrivate() +{ +} + +QList<int> QKeyMapperPrivate::possibleKeys(QKeyEvent *e) +{ + QList<int> result; + return result; +} + +void QKeyMapperPrivate::clearMappings() +{ + // stub +} + +QString QKeyMapperPrivate::translateKeyEvent(int keySym, Qt::KeyboardModifiers modifiers) +{ + if (keySym >= Qt::Key_Escape) + return QString(); + + // Symbian doesn't actually use modifiers, but gives us the character code directly. + + return QString(QChar(keySym)); +} + +void QKeyMapperPrivate::fillKeyMap() +{ + using namespace Qt; + static const struct { + TUint s60Key; + int qtKey; + } map[] = { + {EKeyBell, Key_unknown}, + {EKeyBackspace, Key_Backspace}, + {EKeyTab, Key_Tab}, + {EKeyLineFeed, Key_unknown}, + {EKeyVerticalTab, Key_unknown}, + {EKeyFormFeed, Key_unknown}, + {EKeyEnter, Key_Enter}, + {EKeyEscape, Key_Escape}, + {EKeySpace, Key_Space}, + {EKeyDelete, Key_Delete}, + {EKeyPrintScreen, Key_SysReq}, + {EKeyPause, Key_Pause}, + {EKeyHome, Key_Home}, + {EKeyEnd, Key_End}, + {EKeyPageUp, Key_PageUp}, + {EKeyPageDown, Key_PageDown}, + {EKeyInsert, Key_Insert}, + {EKeyLeftArrow, Key_Left}, + {EKeyRightArrow, Key_Right}, + {EKeyUpArrow, Key_Up}, + {EKeyDownArrow, Key_Down}, + {EKeyLeftShift, Key_Shift}, + {EKeyRightShift, Key_Shift}, + {EKeyLeftAlt, Key_Alt}, + {EKeyRightAlt, Key_AltGr}, + {EKeyLeftCtrl, Key_Control}, + {EKeyRightCtrl, Key_Control}, + {EKeyLeftFunc, Key_Super_L}, + {EKeyRightFunc, Key_Super_R}, + {EKeyCapsLock, Key_CapsLock}, + {EKeyNumLock, Key_NumLock}, + {EKeyScrollLock, Key_ScrollLock}, + {EKeyF1, Key_F1}, + {EKeyF2, Key_F2}, + {EKeyF3, Key_F3}, + {EKeyF4, Key_F4}, + {EKeyF5, Key_F5}, + {EKeyF6, Key_F6}, + {EKeyF7, Key_F7}, + {EKeyF8, Key_F8}, + {EKeyF9, Key_F9}, + {EKeyF10, Key_F10}, + {EKeyF11, Key_F11}, + {EKeyF12, Key_F12}, + {EKeyF13, Key_F13}, + {EKeyF14, Key_F14}, + {EKeyF15, Key_F15}, + {EKeyF16, Key_F16}, + {EKeyF17, Key_F17}, + {EKeyF18, Key_F18}, + {EKeyF19, Key_F19}, + {EKeyF20, Key_F20}, + {EKeyF21, Key_F21}, + {EKeyF22, Key_F22}, + {EKeyF23, Key_F23}, + {EKeyF24, Key_F24}, + {EKeyOff, Key_unknown}, + {EKeyIncContrast, Key_unknown}, + {EKeyDecContrast, Key_unknown}, + {EKeyBacklightOn, Key_unknown}, + {EKeyBacklightOff, Key_unknown}, + {EKeyBacklightToggle, Key_unknown}, + {EKeySliderDown, Key_unknown}, + {EKeySliderUp, Key_unknown}, + {EKeyMenu, Key_Menu}, + {EKeyDictaphonePlay, Key_unknown}, + {EKeyDictaphoneStop, Key_unknown}, + {EKeyDictaphoneRecord, Key_unknown}, + {EKeyHelp, Key_unknown}, + {EKeyDial, Key_Call}, + {EKeyScreenDimension0, Key_unknown}, + {EKeyScreenDimension1, Key_unknown}, + {EKeyScreenDimension2, Key_unknown}, + {EKeyScreenDimension3, Key_unknown}, + {EKeyIncVolume, Key_unknown}, + {EKeyDecVolume, Key_unknown}, + {EKeyDevice0, Key_Context1}, // Found by manual testing, left softkey. + {EKeyDevice1, Key_Context2}, // Found by manual testing. + {EKeyDevice2, Key_unknown}, + {EKeyDevice3, Key_Select}, // Found by manual testing. + {EKeyDevice4, Key_unknown}, + {EKeyDevice5, Key_unknown}, + {EKeyDevice6, Key_unknown}, + {EKeyDevice7, Key_unknown}, + {EKeyDevice8, Key_unknown}, + {EKeyDevice9, Key_unknown}, + {EKeyDeviceA, Key_unknown}, + {EKeyDeviceB, Key_unknown}, + {EKeyDeviceC, Key_unknown}, + {EKeyDeviceD, Key_unknown}, + {EKeyDeviceE, Key_unknown}, + {EKeyDeviceF, Key_unknown}, + {EKeyApplication0, Key_Launch0}, + {EKeyApplication1, Key_Launch1}, + {EKeyApplication2, Key_Launch2}, + {EKeyApplication3, Key_Launch3}, + {EKeyApplication4, Key_Launch4}, + {EKeyApplication5, Key_Launch5}, + {EKeyApplication6, Key_Launch6}, + {EKeyApplication7, Key_Launch7}, + {EKeyApplication8, Key_Launch8}, + {EKeyApplication9, Key_Launch9}, + {EKeyApplicationA, Key_LaunchA}, + {EKeyApplicationB, Key_LaunchB}, + {EKeyApplicationC, Key_LaunchC}, + {EKeyApplicationD, Key_LaunchD}, + {EKeyApplicationE, Key_LaunchE}, + {EKeyApplicationF, Key_LaunchF}, + {EKeyYes, Key_Yes}, + {EKeyNo, Key_No}, + {EKeyIncBrightness, Key_unknown}, + {EKeyDecBrightness, Key_unknown}, + {EKeyKeyboardExtend, Key_unknown}, + {EKeyDevice10, Key_unknown}, + {EKeyDevice11, Key_unknown}, + {EKeyDevice12, Key_unknown}, + {EKeyDevice13, Key_unknown}, + {EKeyDevice14, Key_unknown}, + {EKeyDevice15, Key_unknown}, + {EKeyDevice16, Key_unknown}, + {EKeyDevice17, Key_unknown}, + {EKeyDevice18, Key_unknown}, + {EKeyDevice19, Key_unknown}, + {EKeyDevice1A, Key_unknown}, + {EKeyDevice1B, Key_unknown}, + {EKeyDevice1C, Key_unknown}, + {EKeyDevice1D, Key_unknown}, + {EKeyDevice1E, Key_unknown}, + {EKeyDevice1F, Key_unknown}, + {EKeyApplication10, Key_unknown}, + {EKeyApplication11, Key_unknown}, + {EKeyApplication12, Key_unknown}, + {EKeyApplication13, Key_unknown}, + {EKeyApplication14, Key_unknown}, + {EKeyApplication15, Key_unknown}, + {EKeyApplication16, Key_unknown}, + {EKeyApplication17, Key_unknown}, + {EKeyApplication18, Key_unknown}, + {EKeyApplication19, Key_unknown}, + {EKeyApplication1A, Key_unknown}, + {EKeyApplication1B, Key_unknown}, + {EKeyApplication1C, Key_unknown}, + {EKeyApplication1D, Key_unknown}, + {EKeyApplication1E, Key_unknown}, + {EKeyApplication1F, Key_unknown} + }; + const int mapSize = int(sizeof(map)/sizeof(map[0])); + s60ToQtKeyMap.reserve(mapSize + 5); // +5? docs: Ideally, slightly more than number of items + for (int i = 0; i < mapSize; ++i) + s60ToQtKeyMap.insert(map[i].s60Key, map[i].qtKey); +} + +int QKeyMapperPrivate::mapS60KeyToQt(TUint s60key) +{ + QHash<TUint, int>::const_iterator mapping; + mapping = s60ToQtKeyMap.find(s60key); + if (mapping != s60ToQtKeyMap.end()) { + return *mapping; + } else { + return Qt::Key_unknown; + } +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qsound.cpp b/src/gui/kernel/qsound.cpp index fb152cf..8246ee3 100644 --- a/src/gui/kernel/qsound.cpp +++ b/src/gui/kernel/qsound.cpp @@ -153,6 +153,9 @@ public: \o Qt for Embedded Linux \o A built-in mixing sound server is used, accessing \c /dev/dsp directly. Only the WAVE format is supported. + \o Symbian + \o CMdaAudioPlayerUtility is used. All formats that Symbian OS or devices support + are supported also by Qt. \endtable Note that QSound does not support \l{resources.html}{resources}. diff --git a/src/gui/kernel/qsound_s60.cpp b/src/gui/kernel/qsound_s60.cpp new file mode 100644 index 0000000..7eb6463 --- /dev/null +++ b/src/gui/kernel/qsound_s60.cpp @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + + +#ifndef QT_NO_SOUND + +#include "qdir.h" +#include "qapplication.h" +#include "qsound.h" +#include "qsound_p.h" +#include "qfileinfo.h" +#include <private/qcore_symbian_p.h> + +#include <e32std.h> +#include <MdaAudioSamplePlayer.h> + +QT_BEGIN_NAMESPACE + +class QAuServerS60; + +class QAuBucketS60 : public QAuBucket, public MMdaAudioPlayerCallback +{ +public: + QAuBucketS60( QAuServerS60 *server, QSound *sound); + ~QAuBucketS60(); + + void play(); + void stop(); + + inline QSound* sound() const { return m_sound; } + +public: // from MMdaAudioPlayerCallback + void MapcInitComplete(TInt aError, const TTimeIntervalMicroSeconds& aDuration); + void MapcPlayComplete(TInt aError); + +private: + QSound *m_sound; + QAuServerS60 *m_server; + bool m_prepared; + bool m_playCalled; + CMdaAudioPlayerUtility* m_playUtility; +}; + + +class QAuServerS60 : public QAuServer +{ +public: + QAuServerS60( QObject* parent ); + + void init( QSound* s ) + { + QAuBucketS60 *bucket = new QAuBucketS60( this, s ); + setBucket( s, bucket ); + } + + void play( QSound* s ) + { + bucket( s )->play(); + } + + void stop( QSound* s ) + { + bucket( s )->stop(); + } + + bool okay() { return true; } + +protected: + void playCompleted(QAuBucketS60* bucket, int error) + { + QSound *sound = bucket->sound(); + if(!error) { + // We need to handle repeats by ourselves, since with Symbian API we don't + // know how many loops have been played when user asks it + if( decLoop( sound ) ) { + play( sound ); + } + } else { + // We don't have a way to inform about errors -> just decrement loops + // in order that QSound::isFinished will return true; + while(decLoop(sound)); + } + } + +protected: + QAuBucketS60* bucket( QSound *s ) + { + return (QAuBucketS60*)QAuServer::bucket( s ); + } + + friend class QAuBucketS60; + +}; + +QAuServerS60::QAuServerS60(QObject* parent) : + QAuServer(parent) +{ + setObjectName(QLatin1String("QAuServerS60")); +} + + +QAuServer* qt_new_audio_server() +{ + return new QAuServerS60(qApp); +} + +QAuBucketS60::QAuBucketS60( QAuServerS60 *server, QSound *sound ) + : m_sound( sound ), m_server( server ), m_prepared(false), m_playCalled(false) +{ + TRAPD(err, m_playUtility = CMdaAudioPlayerUtility::NewL(*this); + QString filepath = QFileInfo( m_sound->fileName() ).absoluteFilePath(); + filepath = QDir::toNativeSeparators(filepath); + m_playUtility->OpenFileL(qt_QString2TPtrC(filepath))); + if(err){ + m_server->playCompleted(this, err); + } +} + +void QAuBucketS60::play() +{ + if(m_prepared) { + // OpenFileL call is completed we can start playing immediately + m_playUtility->Play(); + } else { + m_playCalled = true; + } + +} + +void QAuBucketS60::stop() +{ + m_playCalled = false; + m_playUtility->Stop(); +} + +void QAuBucketS60::MapcPlayComplete(TInt aError) +{ + m_server->playCompleted(this, aError); +} + +void QAuBucketS60::MapcInitComplete(TInt aError, const TTimeIntervalMicroSeconds& /*aDuration*/) +{ + if(aError) { + m_server->playCompleted(this, aError); + } else { + m_prepared = true; + if(m_playCalled){ + play(); + } + } +} + +QAuBucketS60::~QAuBucketS60() +{ + if(m_playUtility){ + m_playUtility->Stop(); + m_playUtility->Close(); + } + + delete m_playUtility; +} + + +#endif // QT_NO_SOUND + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h new file mode 100644 index 0000000..d2fa5da --- /dev/null +++ b/src/gui/kernel/qt_s60_p.h @@ -0,0 +1,284 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_S60_P_H +#define QT_S60_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtGui/qwindowdefs.h" +#include "private/qcore_symbian_p.h" +#include "qhash.h" +#include "qpoint.h" +#include "QtGui/qfont.h" +#include "QtGui/qimage.h" +#include "QtGui/qevent.h" +#include "qpointer.h" +#include <w32std.h> +#include <coecntrl.h> +#include <eikenv.h> +#include <eikappui.h> +#include <aknutils.h> // AknLayoutUtils +#include <avkon.hrh> // EEikStatusPaneUidTitle +#include <akntitle.h> // CAknTitlePane +#include <akncontext.h> // CAknContextPane +#include <eikspane.h> // CEikStatusPane + +QT_BEGIN_NAMESPACE + +// Application internal HandleResourceChangeL events, +// system evens seems to start with 0x10 +const TInt KInternalStatusPaneChange = 0x50000000; + +struct QS60Data; +extern QS60Data *qt_s60Data; + +#define S60 qt_s60Data + +class QS60Data +{ +public: + TUid uid; + int screenDepth; + QPoint lastCursorPos; + QPoint lastPointerEventPos; + QPointer<QWidget> lastPointerEventTarget; + QPointer<QWidget> mousePressTarget; + int screenWidthInPixels; + int screenHeightInPixels; + int screenWidthInTwips; + int screenHeightInTwips; + int defaultDpiX; + int defaultDpiY; + static inline void updateScreenSize(); + static inline RWsSession& wsSession(); + static inline RWindowGroup& windowGroup(); + static inline CWsScreenDevice* screenDevice(); + static inline CCoeAppUi* appUi(); + static inline CEikStatusPane* statusPane(); + static inline CCoeControl* statusPaneSubPane(TInt aPaneId); + static inline CAknTitlePane* titlePane(); + static inline CAknContextPane* contextPane(); + static inline CEikButtonGroupContainer* buttonGroupContainer(); +}; + +class QAbstractLongTapObserver +{ +public: + virtual void HandleLongTapEventL( const TPoint& aPenEventLocation, + const TPoint& aPenEventScreenLocation ) = 0; +}; +class QLongTapTimer; + +class QSymbianControl : public CCoeControl, public QAbstractLongTapObserver +{ +public: + DECLARE_TYPE_ID(0x51740000) // Fun fact: the two first values are "Qt" in ASCII. + +public: + QSymbianControl(QWidget *w); + void ConstructL(bool topLevel = false, bool desktop = false); + ~QSymbianControl(); + void HandleResourceChange(int resourceType); + void HandlePointerEventL(const TPointerEvent& aPointerEvent); + TKeyResponse OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType); +#ifndef QT_NO_IM + TCoeInputCapabilities InputCapabilities() const; +#endif + TTypeUid::Ptr MopSupplyObject(TTypeUid id); + + inline QWidget* widget() const { return qwidget; }; + void setWidget(QWidget *w); + void sendInputEvent(QWidget *widget, QInputEvent *inputEvent); + void setIgnoreFocusChanged(bool enabled) { m_ignoreFocusChanged = enabled; } + void CancelLongTapTimer(); + +protected: + void Draw(const TRect& aRect) const; + void SizeChanged(); + void PositionChanged(); + void FocusChanged(TDrawNow aDrawNow); + +private: + TKeyResponse sendKeyEvent(QWidget *widget, QKeyEvent *keyEvent); + void sendMouseEvent(QWidget *widget, QMouseEvent *mEvent); + void HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation ); + +private: + QWidget *qwidget; + bool m_ignoreFocusChanged; + QLongTapTimer* m_longTapDetector; + bool m_previousEventLongTap; +}; + +inline void QS60Data::updateScreenSize() +{ + TPixelsTwipsAndRotation params; + int mode = S60->screenDevice()->CurrentScreenMode(); + S60->screenDevice()->GetScreenModeSizeAndRotation(mode, params); + S60->screenWidthInPixels = params.iPixelSize.iWidth; + S60->screenHeightInPixels = params.iPixelSize.iHeight; + S60->screenWidthInTwips = params.iTwipsSize.iWidth; + S60->screenHeightInTwips = params.iTwipsSize.iHeight; + + TReal inches = S60->screenHeightInTwips / (TReal)KTwipsPerInch; + S60->defaultDpiY = S60->screenHeightInPixels / inches; + inches = S60->screenWidthInTwips / (TReal)KTwipsPerInch; + S60->defaultDpiX = S60->screenWidthInPixels / inches; +} + +inline RWsSession& QS60Data::wsSession() +{ + return CCoeEnv::Static()->WsSession(); +} + +inline RWindowGroup& QS60Data::windowGroup() +{ + return CCoeEnv::Static()->RootWin(); +} + +inline CWsScreenDevice* QS60Data::screenDevice() +{ + return CCoeEnv::Static()->ScreenDevice(); +} + +inline CCoeAppUi* QS60Data::appUi() +{ + return CCoeEnv::Static()-> AppUi(); +} + +inline CEikStatusPane* QS60Data::statusPane() +{ + return CEikonEnv::Static()->AppUiFactory()->StatusPane(); +} + +// Returns the application's status pane control, if not present returns NULL. +inline CCoeControl* QS60Data::statusPaneSubPane( TInt aPaneId ) +{ + const TUid paneUid = { aPaneId }; + CEikStatusPane* statusPane = S60->statusPane(); + if (statusPane && statusPane->PaneCapabilities(paneUid).IsPresent()) { + CCoeControl* control = NULL; + // ControlL shouldn't leave because the pane is present + TRAPD(err, control = statusPane->ControlL(paneUid)); + return err != KErrNone ? NULL : control; + } + return NULL; +} + +// Returns the application's title pane, if not present returns NULL. +inline CAknTitlePane* QS60Data::titlePane() +{ + return static_cast<CAknTitlePane*>(S60->statusPaneSubPane(EEikStatusPaneUidTitle)); +} + +// Returns the application's title pane, if not present returns NULL. +inline CAknContextPane* QS60Data::contextPane() +{ + return static_cast<CAknContextPane*>(S60->statusPaneSubPane(EEikStatusPaneUidContext)); +} + +inline CEikButtonGroupContainer* QS60Data::buttonGroupContainer() +{ + return CEikonEnv::Static()->AppUiFactory()->Cba(); +} + +static inline QFont qt_TFontSpec2QFontL(const TFontSpec &fontSpec) +{ + return QFont( + qt_TDesC2QStringL(fontSpec.iTypeface.iName), + fontSpec.iHeight / KTwipsPerPoint, + fontSpec.iFontStyle.StrokeWeight() == EStrokeWeightNormal ? QFont::Normal : QFont::Bold, + fontSpec.iFontStyle.Posture() == EPostureItalic + ); +} + +static inline QImage::Format qt_TDisplayMode2Format(TDisplayMode mode) +{ + QImage::Format format; + switch(mode) { + case EGray2: + format = QImage::Format_MonoLSB; + break; + case EColor256: + case EGray256: + format = QImage::Format_Indexed8; + break; + case EColor4K: + format = QImage::Format_RGB444; + break; + case EColor64K: + format = QImage::Format_RGB16; + break; + case EColor16M: + format = QImage::Format_RGB666; + break; + case EColor16MU: + format = QImage::Format_RGB32; + break; + case EColor16MA: + format = QImage::Format_ARGB32; + break; +#if !defined(__SERIES60_31__) && !defined(__S60_32__) + case EColor16MAP: + format = QImage::Format_ARGB32_Premultiplied; + break; +#endif + default: + format = QImage::Format_Invalid; + break; + } + return format; +} + + +QT_END_NAMESPACE + +#endif // QT_S60_P_H diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index baf3278..b376f20 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -99,6 +99,10 @@ #endif #include <private/qpaintengine_raster_p.h> +#if defined(Q_WS_S60) +#include "private/qt_s60_p.h" +#endif + #include "qwidget_p.h" #include "qaction_p.h" #include "qlayout_p.h" @@ -196,6 +200,7 @@ QWidgetPrivate::QWidgetPrivate(int version) : ,needWindowChange(0) ,isGLWidget(0) #endif + ,imHints(Qt::ImhNone) ,polished(0) , size_policy(QSizePolicy::Preferred, QSizePolicy::Preferred) @@ -390,6 +395,7 @@ void QWidget::setEditFocus(bool on) QApplication::sendEvent(f, &event); QApplication::sendEvent(f->style(), &event); } + f->repaint(); // Widget might want to repaint a focus indicator } #endif @@ -1253,7 +1259,7 @@ void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow) d->create_sys(window, initializeWindow, destroyOldWindow); // a real toplevel window needs a backing store - if (isWindow()) { + if (isWindow() && windowType() != Qt::Desktop) { delete d->topData()->backingStore; // QWidgetBackingStore will check this variable, hence it must be 0 d->topData()->backingStore = 0; @@ -1987,6 +1993,9 @@ void QWidgetPrivate::setOpaque(bool opaque) #ifdef Q_WS_WIN winUpdateIsOpaque(); #endif +#ifdef Q_WS_S60 + s60UpdateIsOpaque(); +#endif } void QWidgetPrivate::updateIsTranslucent() @@ -2000,6 +2009,9 @@ void QWidgetPrivate::updateIsTranslucent() #ifdef Q_WS_WIN winUpdateIsOpaque(); #endif +#ifdef Q_WS_S60 + s60UpdateIsOpaque(); +#endif } /*! @@ -2035,11 +2047,19 @@ static inline void fillRegion(QPainter *painter, const QRegion &rgn, const QPoin extern void qt_mac_fill_background(QPainter *painter, const QRegion &rgn, const QPoint &offset, const QBrush &brush); qt_mac_fill_background(painter, rgn, offset, brush); #else - const QRegion translated = rgn.translated(offset); - const QRect rect(translated.boundingRect()); - painter->setClipRegion(translated); - painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft()); -#endif +#if !defined(QT_NO_STYLE_S60) + // Defined in qs60style.cpp + extern bool qt_s60_fill_background(QPainter *painter, const QRegion &rgn, + const QPoint &offset, const QBrush &brush); + if (!qt_s60_fill_background(painter, rgn, offset, brush)) +#endif // !defined(QT_NO_STYLE_S60) + { + const QRegion translated = rgn.translated(offset); + const QRect rect(translated.boundingRect()); + painter->setClipRegion(translated); + painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft()); + } +#endif // Q_WS_MAC } else { const QVector<QRect> &rects = rgn.rects(); for (int i = 0; i < rects.size(); ++i) @@ -2061,6 +2081,7 @@ void QWidgetPrivate::paintBackground(QPainter *painter, const QRegion &rgn, cons painter->setCompositionMode(QPainter::CompositionMode_Source); //copy alpha straight in #endif fillRegion(painter, rgn, offset, bg); + } if (q->autoFillBackground()) @@ -2612,7 +2633,7 @@ bool QWidget::isMaximized() const */ Qt::WindowStates QWidget::windowState() const { - return (Qt::WindowStates)data->window_state; + return Qt::WindowStates(data->window_state); } /*!\internal @@ -2624,7 +2645,7 @@ Qt::WindowStates QWidget::windowState() const */ void QWidget::overrideWindowState(Qt::WindowStates newstate) { - QWindowStateChangeEvent e((Qt::WindowStates)data->window_state, true); + QWindowStateChangeEvent e(Qt::WindowStates(data->window_state), true); data->window_state = newstate; QApplication::sendEvent(this, &e); } @@ -6746,7 +6767,7 @@ void QWidgetPrivate::show_helper() // On Windows, show the popup now so that our own focus handling // stores the correct old focus widget even if it's stolen in the // showevent -#if defined(Q_WS_WIN) || defined(Q_WS_MAC) +#if defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_WS_S60) if (!isEmbedded && q->windowType() == Qt::Popup) qApp->d_func()->openPopup(q); #endif @@ -6763,7 +6784,7 @@ void QWidgetPrivate::show_helper() show_sys(); -#if !defined(Q_WS_WIN) && !defined(Q_WS_MAC) +#if !defined(Q_WS_WIN) && !defined(Q_WS_MAC) && !defined(Q_WS_S60) if (!isEmbedded && q->windowType() == Qt::Popup) qApp->d_func()->openPopup(q); #endif @@ -7333,7 +7354,7 @@ QSize QWidgetPrivate::adjustedSize() const #else // all others QRect screen = QApplication::desktop()->screenGeometry(q->pos()); #endif -#if defined (Q_OS_WINCE) +#if defined (Q_OS_WINCE) || defined (Q_OS_SYMBIAN) s.setWidth(qMin(s.width(), screen.width())); s.setHeight(qMin(s.height(), screen.height())); #else @@ -8471,7 +8492,7 @@ void QWidget::inputMethodEvent(QInputMethodEvent *event) \a query specifies which property is queried. - \sa inputMethodEvent(), QInputMethodEvent, QInputContext + \sa inputMethodEvent(), QInputMethodEvent, QInputContext, inputMethodHints */ QVariant QWidget::inputMethodQuery(Qt::InputMethodQuery query) const { @@ -8480,11 +8501,54 @@ QVariant QWidget::inputMethodQuery(Qt::InputMethodQuery query) const return QRect(width()/2, 0, 1, height()); case Qt::ImFont: return font(); + case Qt::ImAnchorPosition: + // Fallback. + return inputMethodQuery(Qt::ImCursorPosition); default: return QVariant(); } } +/*! + \property QWidget::inputMethodHints + \brief What input method specific hints the widget has. + + This is only relevant for input widgets. It is used by + the input method to retrieve hints as to how the input method + should operate. For example, if the Qt::ImhFormattedNumbersOnly flag + is set, the input method may change its visual components to reflect + that only numbers can be entered. + + \note The flags are only hints, so the particular input method + implementation is free to ignore them. If you want to be + sure that a certain type of characters are entered, + you should also set a QValidator on the widget. + + The default value is Qt::ImhNone. + + \since 4.6 + + \sa inputMethodQuery(), QInputContext +*/ +Qt::InputMethodHints QWidget::inputMethodHints() const +{ + Q_D(const QWidget); + return d->imHints; +} + +void QWidget::setInputMethodHints(Qt::InputMethodHints hints) +{ + Q_D(QWidget); + d->imHints = hints; + // Optimisation to update input context only it has already been created. + if (d->ic || qApp->d_func()->inputContext) { + QInputContext *ic = inputContext(); + if (ic) + ic->update(); + } +} + + #ifndef QT_NO_DRAGANDDROP /*! @@ -10312,7 +10376,7 @@ void QWidget::setShortcutAutoRepeat(int id, bool enable) */ void QWidget::updateMicroFocus() { -#if !defined(QT_NO_IM) && (defined(Q_WS_X11) || defined(Q_WS_QWS)) +#if !defined(QT_NO_IM) && (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_S60)) Q_D(QWidget); // and optimisation to update input context only it has already been created. if (d->ic || qApp->d_func()->inputContext) { diff --git a/src/gui/kernel/qwidget.h b/src/gui/kernel/qwidget.h index f54ebf9..0dd470d 100644 --- a/src/gui/kernel/qwidget.h +++ b/src/gui/kernel/qwidget.h @@ -212,6 +212,7 @@ class Q_GUI_EXPORT QWidget : public QObject, public QPaintDevice #endif Q_PROPERTY(QLocale locale READ locale WRITE setLocale RESET unsetLocale) Q_PROPERTY(QString windowFilePath READ windowFilePath WRITE setWindowFilePath DESIGNABLE isWindow) + Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ inputMethodHints WRITE setInputMethodHints) public: enum RenderFlag { @@ -673,6 +674,10 @@ protected: virtual void inputMethodEvent(QInputMethodEvent *); public: virtual QVariant inputMethodQuery(Qt::InputMethodQuery) const; + + Qt::InputMethodHints inputMethodHints() const; + void setInputMethodHints(Qt::InputMethodHints hints); + protected: void resetInputContext(); protected Q_SLOTS: @@ -744,6 +749,10 @@ private: friend bool isWidgetOpaque(const QWidget *); friend class QGLWidgetPrivate; #endif +#ifdef Q_WS_S60 + friend class QSymbianControl; + friend class QS60WindowSurface; +#endif #ifdef Q_WS_X11 friend void qt_net_update_user_time(QWidget *tlw, unsigned long timestamp); friend void qt_net_remove_user_time(QWidget *tlw); diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 2461820..d5f1b98 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -79,6 +79,13 @@ #include "QtGui/qscreen_qws.h" #endif +#if defined(Q_WS_S60) +class RDrawableWindow; +class CCoeControl; +class CAknTitlePane; +class CAknContextPane; +#endif + QT_BEGIN_NAMESPACE // Extra QWidget data @@ -142,6 +149,10 @@ struct QTLWExtra { uint isMove : 1; uint embedded : 1; #endif +#if defined(Q_WS_S60) + uint activated : 1; // RWindowBase::Activated has been called + RDrawableWindow *rwindow; +#endif #if defined(Q_WS_QWS) && !defined (QT_NO_QWS_MANAGER) QWSManager *qwsManager; #endif @@ -261,6 +272,10 @@ public: void applyMaxAndMinSizeOnWindow(); #endif +#ifdef Q_WS_S60 + void s60UpdateIsOpaque(); +#endif + void raise_sys(); void lower_sys(); void stackUnder_sys(QWidget *); @@ -365,7 +380,7 @@ public: void x11UpdateIsOpaque(); #endif -#if defined (Q_WS_WIN) +#if defined (Q_WS_WIN) || defined (Q_WS_S60) void reparentChildren(); #endif @@ -596,7 +611,9 @@ public: uint isGLWidget : 1; #endif -#if defined(Q_WS_X11) || defined (Q_WS_WIN) || defined(Q_WS_MAC) + Qt::InputMethodHints imHints; + +#if defined(Q_WS_X11) || defined (Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_WS_S60) #ifdef Q_WS_MAC void setWSGeometry(bool dontShow=false, const QRect &oldRect = QRect()); #else @@ -624,7 +641,7 @@ public: QSizePolicy size_policy; QLocale locale; -#ifdef Q_WS_X11 +#if defined(Q_WS_X11) || defined(Q_WS_S60) static QWidget *mouseGrabber; static QWidget *keyboardGrabber; #endif @@ -669,6 +686,7 @@ public: } QSize adjustedSize() const; + }; inline QWExtra *QWidgetPrivate::extraData() const diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp new file mode 100644 index 0000000..11cb974 --- /dev/null +++ b/src/gui/kernel/qwidget_s60.cpp @@ -0,0 +1,1007 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwidget_p.h" +#include "qdesktopwidget.h" +#include "qapplication.h" +#include "qapplication_p.h" +#include "private/qbackingstore_p.h" +#include "qevent.h" +#include "qt_s60_p.h" + +#include "qbitmap.h" +#include "private/qwindowsurface_s60_p.h" + +#include <qinputcontext.h> + +QT_BEGIN_NAMESPACE + +extern bool qt_nograb(); + +QWidget *QWidgetPrivate::mouseGrabber = 0; +QWidget *QWidgetPrivate::keyboardGrabber = 0; + +void QWidgetPrivate::setWSGeometry(bool dontShow) +{ + +} + +void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) +{ + Q_Q(QWidget); + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + + if ((q->windowType() == Qt::Desktop)) + return; + if (extra) { // any size restrictions? + w = qMin(w,extra->maxw); + h = qMin(h,extra->maxh); + w = qMax(w,extra->minw); + h = qMax(h,extra->minh); + } + + if (q->isWindow()) + topData()->normalGeometry = QRect(0, 0, -1, -1); + else { + uint s = data.window_state; + s &= ~(Qt::WindowMaximized | Qt::WindowFullScreen); + data.window_state = s; + } + + QPoint oldPos(q->pos()); + QSize oldSize(q->size()); + QRect oldGeom(data.crect); + + bool isResize = w != oldSize.width() || h != oldSize.height(); + if (!isMove && !isResize) + return; + + if (isResize) + data.window_state &= ~Qt::WindowMaximized; + + if(q->isWindow()) { + if (w == 0 || h == 0) { + q->setAttribute(Qt::WA_OutsideWSRange, true); + if (q->isVisible() && q->testAttribute(Qt::WA_Mapped)) + hide_sys(); + data.crect = QRect(x, y, w, h); + data.window_state &= ~Qt::WindowFullScreen; + } else if (q->isVisible() && q->testAttribute(Qt::WA_OutsideWSRange)) { + q->setAttribute(Qt::WA_OutsideWSRange, false); + + // put the window in its place and show it + q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h))); + data.crect.setRect(x, y, w, h); + + show_sys(); + } else { + QRect r = QRect(x, y, w, h); + data.crect = r; + q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h))); + topData()->normalGeometry = data.crect; + } + } else { + data.crect.setRect(x, y, w, h); + + QTLWExtra *tlwExtra = q->window()->d_func()->maybeTopData(); + const bool inTopLevelResize = tlwExtra ? tlwExtra->inTopLevelResize : false; + + if (q->isVisible() && (!inTopLevelResize || q->internalWinId())) { + // Top-level resize optimization does not work for native child widgets; + // disable it for this particular widget. + if (inTopLevelResize) + tlwExtra->inTopLevelResize = false; + if (!isResize && maybeBackingStore()) + moveRect(QRect(oldPos, oldSize), x - oldPos.x(), y - oldPos.y()); + else + invalidateBuffer_resizeHelper(oldPos, oldSize); + + if (inTopLevelResize) + tlwExtra->inTopLevelResize = true; + } + if (q->testAttribute(Qt::WA_WState_Created)) + setWSGeometry(); + } + + if (q->isVisible()) { + if (isMove && q->pos() != oldPos) { + QMoveEvent e(q->pos(), oldPos); + QApplication::sendEvent(q, &e); + } + if (isResize) { + bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt(); + const bool setTopLevelResize = !slowResize && q->isWindow() && extra && extra->topextra + && !extra->topextra->inTopLevelResize; + if (setTopLevelResize) + extra->topextra->inTopLevelResize = true; + QResizeEvent e(q->size(), oldSize); + QApplication::sendEvent(q, &e); + if (!q->testAttribute(Qt::WA_StaticContents) && q->internalWinId()) + q->internalWinId()->DrawDeferred(); + if (setTopLevelResize) + extra->topextra->inTopLevelResize = false; + } + } else { + if (isMove && q->pos() != oldPos) + q->setAttribute(Qt::WA_PendingMoveEvent, true); + if (isResize) + q->setAttribute(Qt::WA_PendingResizeEvent, true); + } +} + +void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow) +{ + Q_Q(QWidget); + + Qt::WindowType type = q->windowType(); + Qt::WindowFlags &flags = data.window_flags; + QWidget *parentWidget = q->parentWidget(); + + bool topLevel = (flags & Qt::Window); + bool popup = (type == Qt::Popup); + bool dialog = (type == Qt::Dialog + || type == Qt::Sheet + || (flags & Qt::MSWindowsFixedSizeDialogHint)); + bool desktop = (type == Qt::Desktop); + bool tool = (type == Qt::Tool || type == Qt::Drawer); + + WId id = 0; + + if (popup) + flags |= Qt::WindowStaysOnTopHint; // a popup stays on top + + // always initialize + if (!window) + initializeWindow = true; + + TRect clientRect = static_cast<CEikAppUi*>(S60->appUi())->ClientRect(); + int sw = clientRect.Width(); + int sh = clientRect.Height(); + + if (desktop) { + TSize screenSize = S60->screenDevice()->SizeInPixels(); + data.crect.setRect(0, 0, screenSize.iWidth, screenSize.iHeight); + q->setAttribute(Qt::WA_DontShowOnScreen); + } else if(topLevel && !q->testAttribute(Qt::WA_Resized)){ + int width = sw; + int height = sh; + if (extra) { + width = qMax(qMin(width, extra->maxw), extra->minw); + height = qMax(qMin(height, extra->maxh), extra->minh); + } + data.crect.setSize(QSize(width, height)); + } + + CCoeControl *destroyw = 0; + + if(window) { + if (destroyOldWindow) + destroyw = data.winid; + id = window; + setWinId(window); + TRect tr = window->Rect(); + data.crect.setRect(tr.iTl.iX, tr.iTl.iY, tr.Width(), tr.Height()); + + } else if (topLevel) { + if (!q->testAttribute(Qt::WA_Moved) && !q->testAttribute(Qt::WA_DontShowOnScreen)) + data.crect.moveTopLeft(QPoint(clientRect.iTl.iX, clientRect.iTl.iY)); + QSymbianControl *control= new QSymbianControl(q); + control->ConstructL(true,desktop); + if (!desktop) { + QTLWExtra *topExtra = topData(); + topExtra->rwindow = control->DrawableWindow(); + // Request mouse move events. + topExtra->rwindow->PointerFilter(EPointerFilterEnterExit + | EPointerFilterMove | EPointerFilterDrag, 0); + topExtra->rwindow->EnableVisibilityChangeEvents(); + + if (!isOpaque) { + RWindow *rwindow = static_cast<RWindow*>(topExtra->rwindow); + TDisplayMode gotDM = (TDisplayMode)rwindow->SetRequiredDisplayMode(EColor16MA); + if (rwindow->SetTransparencyAlphaChannel() == KErrNone) + rwindow->SetBackgroundColor(TRgb(255, 255, 255, 0)); + } + } + + + id = (WId)control; + + setWinId(id); + + q->setAttribute(Qt::WA_WState_Created); + + int x, y, w, h; + data.crect.getRect(&x, &y, &w, &h); + control->SetRect(TRect(TPoint(x, y), TSize(w, h))); + } else if (q->testAttribute(Qt::WA_NativeWindow) || paintOnScreen()) { // create native child widget + QSymbianControl *control = new QSymbianControl(q); + control->ConstructL(!parentWidget); + setWinId(control); + WId parentw = parentWidget->effectiveWinId(); + control->SetContainerWindowL(*parentw); + + q->setAttribute(Qt::WA_WState_Created); + int x, y, w, h; + data.crect.getRect(&x, &y, &w, &h); + control->SetRect(TRect(TPoint(x, y), TSize(w, h))); + } + + if (destroyw) { + destroyw->ControlEnv()->AppUi()->RemoveFromStack(destroyw); + CBase::Delete(destroyw); + } +} + + +void QWidgetPrivate::show_sys() +{ + Q_Q(QWidget); + + if (q->testAttribute(Qt::WA_OutsideWSRange)) + return; + + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + + q->setAttribute(Qt::WA_Mapped); + + if (q->testAttribute(Qt::WA_DontShowOnScreen)) { + invalidateBuffer(q->rect()); + return; + } + + if (q->isWindow() && q->internalWinId()) { + + WId id = q->internalWinId(); + if (!extra->topextra->activated) { + id->ActivateL(); + extra->topextra->activated = 1; + } + TInt stackingFlags; + if ((q->windowType() & Qt::Popup) == Qt::Popup) { + stackingFlags = ECoeStackFlagRefusesAllKeys | ECoeStackFlagRefusesFocus; + } else { + stackingFlags = ECoeStackFlagStandard; + } + id->ControlEnv()->AppUi()->AddToStackL(id, ECoeStackPriorityDefault, stackingFlags); + id->MakeVisible(true); + + // Force setting of the icon after window is made visible, + // this is needed even WA_SetWindowIcon is not set, as in that case we need + // to reset to the application level window icon + setWindowIcon_sys(true); + } + + invalidateBuffer(q->rect()); +} + +void QWidgetPrivate::hide_sys() +{ + Q_Q(QWidget); + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + deactivateWidgetCleanup(); + WId id = q->internalWinId(); + if (q->isWindow() && id) { + id->SetFocus(false); + id->MakeVisible(false); + id->ControlEnv()->AppUi()->RemoveFromStack(id); + if (QWidgetBackingStore *bs = maybeBackingStore()) + bs->releaseBuffer(); + } else { + invalidateBuffer(q->rect()); + } + + q->setAttribute(Qt::WA_Mapped, false); +} + +void QWidgetPrivate::setFocus_sys() +{ + Q_Q(QWidget); + if (q->testAttribute(Qt::WA_WState_Created) && q->window()->windowType() != Qt::Popup) + q->effectiveWinId()->SetFocus(true); +} + +void QWidgetPrivate::raise_sys() +{ + Q_Q(QWidget); + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + QTLWExtra *tlwExtra = maybeTopData(); + if (q->internalWinId() && tlwExtra) { + tlwExtra->rwindow->SetOrdinalPosition(0); + } +} + +void QWidgetPrivate::lower_sys() +{ + Q_Q(QWidget); + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + QTLWExtra *tlwExtra = maybeTopData(); + if (q->internalWinId() && tlwExtra) { + tlwExtra->rwindow->SetOrdinalPosition(-1); + } + if(!q->isWindow()) + invalidateBuffer(q->rect()); +} + +void QWidgetPrivate::setModal_sys() +{ + +} + +void QWidgetPrivate::stackUnder_sys(QWidget* w) +{ + Q_Q(QWidget); + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + QTLWExtra *tlwExtra = maybeTopData(); + QTLWExtra *tlwExtraSibling = w->d_func()->maybeTopData(); + if (q->internalWinId() && tlwExtra && w->internalWinId() && tlwExtraSibling) + tlwExtra->rwindow->SetOrdinalPosition(tlwExtraSibling->rwindow->OrdinalPosition() + 1); + if(!q->isWindow() || !w->internalWinId()) + invalidateBuffer(q->rect()); +} + +void QWidgetPrivate::reparentChildren() +{ + Q_Q(QWidget); + QObjectList chlist = q->children(); + for (int i = 0; i < chlist.size(); ++i) { // reparent children + QObject *obj = chlist.at(i); + if (obj->isWidgetType()) { + QWidget *w = (QWidget *)obj; + if (!w->testAttribute(Qt::WA_WState_Created)) + continue; + if (!w->isWindow()) { + w->d_func()->invalidateBuffer(w->rect()); + WId parent = q->effectiveWinId(); + WId child = w->effectiveWinId(); + if (parent != child) + child->SetParent(parent); + // ### TODO: We probably also need to update the component array here + w->d_func()->reparentChildren(); + } else { + bool showIt = w->isVisible(); + QPoint old_pos = w->pos(); + w->setParent(q, w->windowFlags()); + w->move(old_pos); + if (showIt) + w->show(); + } + } + } +} + +void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f) +{ + Q_Q(QWidget); + bool wasCreated = q->testAttribute(Qt::WA_WState_Created); + + if (q->isVisible() && q->parentWidget() && parent != q->parentWidget()) + q->parentWidget()->d_func()->invalidateBuffer(q->geometry()); + + if (q->testAttribute(Qt::WA_DropSiteRegistered)) + q->setAttribute(Qt::WA_DropSiteRegistered, false); + + WId old_winid = wasCreated ? data.winid : 0; + if ((q->windowType() == Qt::Desktop)) + old_winid = 0; + setWinId(0); + + // hide and reparent our own window away. Otherwise we might get + // destroyed when emitting the child remove event below. See QWorkspace. + if (wasCreated && old_winid) { + old_winid->MakeVisible(false); + old_winid->ControlEnv()->AppUi()->RemoveFromStack(old_winid); + old_winid->SetParent(0); + } + + QObjectPrivate::setParent_helper(parent); + bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide); + + data.window_flags = f; + data.fstrut_dirty = true; + q->setAttribute(Qt::WA_WState_Created, false); + q->setAttribute(Qt::WA_WState_Visible, false); + q->setAttribute(Qt::WA_WState_Hidden, false); + adjustFlags(data.window_flags, q); + // keep compatibility with previous versions, we need to preserve the created state + // (but we recreate the winId for the widget being reparented, again for compatibility) + if (wasCreated || (!q->isWindow() && parent->testAttribute(Qt::WA_WState_Created))) + createWinId(); + if (q->isWindow() || (!parent || parent->isVisible()) || explicitlyHidden) + q->setAttribute(Qt::WA_WState_Hidden); + q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden); + + if (wasCreated) + reparentChildren(); + + if (old_winid) { + CBase::Delete(old_winid); + } + + if (q->testAttribute(Qt::WA_AcceptDrops) + || (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered))) + q->setAttribute(Qt::WA_DropSiteRegistered, true); + + invalidateBuffer(q->rect()); +} + +void QWidgetPrivate::setConstraints_sys() +{ + +} + + +void QWidgetPrivate::s60UpdateIsOpaque() +{ + Q_Q(QWidget); + + if (!q->testAttribute(Qt::WA_WState_Created) || !q->testAttribute(Qt::WA_TranslucentBackground)) + return; + + if ((data.window_flags & Qt::FramelessWindowHint) == 0) + return; + + if (!isOpaque) { + QTLWExtra *topExtra = topData(); + RWindow *rwindow = static_cast<RWindow*>(topExtra->rwindow); + TDisplayMode gotDM = (TDisplayMode)rwindow->SetRequiredDisplayMode(EColor16MA); + if (rwindow->SetTransparencyAlphaChannel() == KErrNone) + rwindow->SetBackgroundColor(TRgb(255, 255, 255, 0)); + } else { + QTLWExtra *topExtra = topData(); + RWindow *rwindow = static_cast<RWindow*>(topExtra->rwindow); + rwindow->SetTransparentRegion(TRegionFix<1>()); + } +} + +CFbsBitmap* qt_pixmapToNativeBitmapL(QPixmap pixmap, bool invert) +{ + CFbsBitmap* fbsBitmap = new(ELeave)CFbsBitmap; + TSize size(pixmap.size().width(), pixmap.size().height()); + TDisplayMode mode(EColor16MU); + + bool isNull = pixmap.isNull(); + int depth = pixmap.depth(); + + // TODO: dummy assumptions from bit amounts for each color + // Will fix later on when native pixmap is implemented + switch(pixmap.depth()) { + case 1: + mode = EGray2; + break; + case 4: + mode = EColor16; + break; + case 8: + mode = EColor256; + break; + case 12: + mode = EColor4K; + break; + case 16: + mode = EColor64K; + break; + case 24: + mode = EColor16M; + break; + case 32: + case EColor16MU: + break; + default: + qFatal("Unsupported pixmap depth"); + break; + } + + User::LeaveIfError(fbsBitmap->Create(size, mode)); + fbsBitmap->LockHeap(); + QImage image = pixmap.toImage(); + + if(invert) + image.invertPixels(); + + int height = pixmap.size().height(); + for(int i=0;i<height;i++ ) + { + TPtr8 scanline(image.scanLine(i), image.bytesPerLine(), image.bytesPerLine()); + fbsBitmap->SetScanLine( scanline, i ); + } + + fbsBitmap->UnlockHeap(); + return fbsBitmap; +} + +void QWidgetPrivate::setWindowIcon_sys(bool forceReset) +{ + Q_Q(QWidget); + + if (!q->testAttribute(Qt::WA_WState_Created) || !q->isWindow() ) + return; + + QTLWExtra* topData = this->topData(); + if (topData->iconPixmap && !forceReset) + // already been set + return; + + TRect cPaneRect; + TBool found = AknLayoutUtils::LayoutMetricsRect( AknLayoutUtils::EContextPane, cPaneRect ); + CAknContextPane* contextPane = S60->contextPane(); + if( found && contextPane ) { // We have context pane with valid metrics + QIcon icon = q->windowIcon(); + if (!icon.isNull()) { + // Valid icon -> set it as an context pane picture + QSize size = icon.actualSize(QSize(cPaneRect.Size().iWidth, cPaneRect.Size().iHeight)); + QPixmap pm = icon.pixmap(size); + QBitmap mask = pm.mask(); + if (mask.isNull()) { + mask = QBitmap(pm.size()); + mask.fill(Qt::color1); + } + + // Convert to CFbsBitmp + // TODO: When QPixmap is adapted to use native CFbsBitmap, + // it could be set directly to context pane + CFbsBitmap* nBitmap = qt_pixmapToNativeBitmapL(pm, false); + CFbsBitmap* nMask = qt_pixmapToNativeBitmapL(mask, true); + + contextPane->SetPicture(nBitmap,nMask); + } else { + // Icon set to null -> set context pane picture to default + contextPane->SetPictureToDefaultL(); + } + } +} + +void QWidgetPrivate::setWindowTitle_sys(const QString &caption) +{ + Q_Q(QWidget); + if(q->isWindow()) { + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + CAknTitlePane* titlePane = S60->titlePane(); + if(titlePane) + titlePane->SetTextL(qt_QString2TPtrC(caption)); + } +} + +void QWidgetPrivate::setWindowIconText_sys(const QString &iconText) +{ + +} + +void QWidgetPrivate::scroll_sys(int dx, int dy) +{ + Q_Q(QWidget); + + scrollChildren(dx, dy); + if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) { + scrollRect(q->rect(), dx, dy); + } else { + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + RDrawableWindow* rw = topData()->rwindow; + rw->Scroll(TPoint(dx, dy)); + } +} + +void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r) +{ + Q_Q(QWidget); + + if (!paintOnScreen() || !q->internalWinId() || !q->internalWinId()->OwnsWindow()) { + scrollRect(r, dx, dy); + } else { + Q_ASSERT(q->testAttribute(Qt::WA_WState_Created)); + RDrawableWindow* rw = topData()->rwindow; + rw->Scroll(TPoint(dx, dy), qt_QRect2TRect(r)); + } +} + +/*! + For this function to work in the emulator, you must add: + TRANSPARENCY + To a line in the wsini.ini file. +*/ +void QWidgetPrivate::setWindowOpacity_sys(qreal) +{ + // ### TODO: Implement uniform window transparency +} + +void QWidgetPrivate::updateFrameStrut() +{ + +} + +void QWidgetPrivate::updateSystemBackground() +{ + +} + +void QWidgetPrivate::registerDropSite(bool on) +{ + +} + +void QWidgetPrivate::createTLSysExtra() +{ + extra->topextra->backingStore = 0; + extra->topextra->activated = 0; + extra->topextra->rwindow = 0; +} + +void QWidgetPrivate::deleteTLSysExtra() +{ + delete extra->topextra->backingStore; + extra->topextra->backingStore = 0; +} + +void QWidgetPrivate::createSysExtra() +{ + +} + +void QWidgetPrivate::deleteSysExtra() +{ + +} + +QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys() +{ + return new QS60WindowSurface(q_func()); +} + +void QWidgetPrivate::setMask_sys(const QRegion& region) +{ + +} + +int QWidget::metric(PaintDeviceMetric m) const +{ + Q_D(const QWidget); + int val; + if (m == PdmWidth) { + val = data->crect.width(); + } else if (m == PdmHeight) { + val = data->crect.height(); + } else { + CWsScreenDevice *scr = S60->screenDevice(); + switch(m) { + case PdmDpiX: + case PdmPhysicalDpiX: + if (d->extra && d->extra->customDpiX) { + val = d->extra->customDpiX; + } else { + const QWidgetPrivate *p = d; + while (p->parent) { + p = static_cast<const QWidget *>(p->parent)->d_func(); + if (p->extra && p->extra->customDpiX) { + val = p->extra->customDpiX; + break; + } + } + if (p == d || !(p->extra && p->extra->customDpiX)) + val = S60->defaultDpiX; + } + break; + case PdmDpiY: + case PdmPhysicalDpiY: + if (d->extra && d->extra->customDpiY) { + val = d->extra->customDpiY; + } else { + const QWidgetPrivate *p = d; + while (p->parent) { + p = static_cast<const QWidget *>(p->parent)->d_func(); + if (p->extra && p->extra->customDpiY) { + val = p->extra->customDpiY; + break; + } + } + if (p == d || !(p->extra && p->extra->customDpiY)) + val = S60->defaultDpiY; + } + break; + case PdmWidthMM: + { + TInt twips = scr->HorizontalPixelsToTwips(data->crect.width()); + val = (int)(twips * (25.4/KTwipsPerInch)); + break; + } + case PdmHeightMM: + { + TInt twips = scr->VerticalPixelsToTwips(data->crect.height()); + val = (int)(twips * (25.4/KTwipsPerInch)); + break; + } + case PdmNumColors: + val = TDisplayModeUtils::NumDisplayModeColors(scr->DisplayMode()); + break; + case PdmDepth: + val = TDisplayModeUtils::NumDisplayModeBitsPerPixel(scr->DisplayMode()); + break; + default: + val = 0; + qWarning("QWidget::metric: Invalid metric command"); + } + } + return val; +} + +QPaintEngine *QWidget::paintEngine() const +{ + return 0; +} + +QPoint QWidget::mapToGlobal(const QPoint &pos) const +{ + Q_D(const QWidget); + if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) { + + QPoint p = pos + data->crect.topLeft(); + return (isWindow() || !parentWidget()) ? p : parentWidget()->mapToGlobal(p); + + } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel + QPoint tp = geometry().topLeft(); + return pos + tp; + } + + // This is the native window case. Consider using CCoeControl::PositionRelativeToScreen() + // if we decide to go with CCoeControl + return QPoint(); +} + +QPoint QWidget::mapFromGlobal(const QPoint &pos) const +{ + Q_D(const QWidget); + if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) { + QPoint p = (isWindow() || !parentWidget()) ? pos : parentWidget()->mapFromGlobal(pos); + return p - data->crect.topLeft(); + } else if ((d->data.window_flags & Qt::Window) && internalWinId()) { //toplevel + QPoint tp = geometry().topLeft(); + return pos - tp; + } + + // ### TODO native window + return QPoint(); +} + +void QWidget::setWindowState(Qt::WindowStates newstate) +{ + Q_D(QWidget); + Qt::WindowStates oldstate = windowState(); + if (oldstate == newstate) + return; + + if (isWindow()) { + createWinId(); + Q_ASSERT(testAttribute(Qt::WA_WState_Created)); + QTLWExtra *top = d->topData(); + + // Ensure the initial size is valid, since we store it as normalGeometry below. + if (!testAttribute(Qt::WA_Resized) && !isVisible()) + adjustSize(); + + if ((oldstate & Qt::WindowMaximized) != (newstate & Qt::WindowMaximized)) { + if ((newstate & Qt::WindowMaximized)) { + const QRect normalGeometry = geometry(); + + const QRect r = top->normalGeometry; + setGeometry(qApp->desktop()->availableGeometry(this)); + top->normalGeometry = r; + + if (top->normalGeometry.width() < 0) + top->normalGeometry = normalGeometry; + } else { + // restore original geometry + setGeometry(top->normalGeometry); + } + } + if ((oldstate & Qt::WindowFullScreen) != (newstate & Qt::WindowFullScreen)) { + CEikStatusPane* statusPane = S60->statusPane(); + CEikButtonGroupContainer* buttonGroup = S60->buttonGroupContainer(); + if (newstate & Qt::WindowFullScreen) { + const QRect normalGeometry = geometry(); + const QRect r = top->normalGeometry; + setGeometry(qApp->desktop()->screenGeometry(this)); + if (statusPane) + statusPane->MakeVisible(false); + if (buttonGroup) + buttonGroup->MakeVisible(false); + top->normalGeometry = r; + if (top->normalGeometry.width() < 0) + top->normalGeometry = normalGeometry; + } else { + if (statusPane) + statusPane->MakeVisible(true); + if (buttonGroup) + buttonGroup->MakeVisible(true); + if (newstate & Qt::WindowMaximized) { + const QRect r = top->normalGeometry; + setGeometry(qApp->desktop()->availableGeometry(this)); + top->normalGeometry = r; + } else { + setGeometry(top->normalGeometry); + } + } + } + if ((oldstate & Qt::WindowMinimized) != (newstate & Qt::WindowMinimized)) { + if (newstate & Qt::WindowMinimized) { + if (isVisible()) { + WId id = effectiveWinId(); + id->MakeVisible(false); + id->ControlEnv()->AppUi()->RemoveFromStack(id); + } + } else { + if (isVisible()) { + WId id = effectiveWinId(); + id->MakeVisible(true); + id->ControlEnv()->AppUi()->AddToStackL(id); + } + const QRect normalGeometry = geometry(); + const QRect r = top->normalGeometry; + top->normalGeometry = r; + if (top->normalGeometry.width() < 0) + top->normalGeometry = normalGeometry; + } + } + } + + data->window_state = newstate; + + if (newstate & Qt::WindowActive) + activateWindow(); + + QWindowStateChangeEvent e(oldstate); + QApplication::sendEvent(this, &e); +} + + +void QWidget::destroy(bool destroyWindow, bool destroySubWindows) +{ + Q_D(QWidget); + if (!isWindow() && parentWidget()) + parentWidget()->d_func()->invalidateBuffer(geometry()); + d->deactivateWidgetCleanup(); + if (testAttribute(Qt::WA_WState_Created)) { + +#ifndef QT_NO_IM + if (d->ic) { + delete d->ic; + } else { + QInputContext *ic = inputContext(); + if (ic) { + ic->widgetDestroyed(this); + } + } +#endif + + setAttribute(Qt::WA_WState_Created, false); + QObjectList childList = children(); + for (int i = 0; i < childList.size(); ++i) { // destroy all widget children + register QObject *obj = childList.at(i); + if (obj->isWidgetType()) + static_cast<QWidget*>(obj)->destroy(destroySubWindows, + destroySubWindows); + } + if (QWidgetPrivate::mouseGrabber == this) + releaseMouse(); + if (QWidgetPrivate::keyboardGrabber == this) + releaseKeyboard(); + if (destroyWindow && !(windowType() == Qt::Desktop) && internalWinId()) { + WId id = internalWinId(); + id->SetFocus(false); + id->ControlEnv()->AppUi()->RemoveFromStack(id); + CBase::Delete(id); + + // Hack to activate window under destroyed one. With this activation + // the next visible window will get keyboard focus + WId wid = CEikonEnv::Static()->AppUi()->TopFocusedControl(); + if (wid) { + QWidget *widget = QWidget::find(wid); + QApplication::setActiveWindow(widget); + } + + } + + d->setWinId(0); + } +} + +QWidget *QWidget::mouseGrabber() +{ + return QWidgetPrivate::mouseGrabber; +} + +QWidget *QWidget::keyboardGrabber() +{ + return QWidgetPrivate::keyboardGrabber; +} + +void QWidget::grabKeyboard() +{ + if (!qt_nograb()) { + if (QWidgetPrivate::keyboardGrabber && QWidgetPrivate::keyboardGrabber != this) + QWidgetPrivate::keyboardGrabber->releaseKeyboard(); + + // ### TODO: Native keyboard grab + + QWidgetPrivate::keyboardGrabber = this; + } +} + +void QWidget::releaseKeyboard() +{ + if (!qt_nograb() && QWidgetPrivate::keyboardGrabber == this) { + // ### TODO: Native keyboard release + QWidgetPrivate::keyboardGrabber = 0; + } +} + +void QWidget::grabMouse() +{ + if (!qt_nograb()) { + if (QWidgetPrivate::mouseGrabber && QWidgetPrivate::mouseGrabber != this) + QWidgetPrivate::mouseGrabber->releaseMouse(); + Q_ASSERT(testAttribute(Qt::WA_WState_Created)); + WId id = effectiveWinId(); + id->SetPointerCapture(true); + QWidgetPrivate::mouseGrabber = this; + } +} + +void QWidget::releaseMouse() +{ + if (!qt_nograb() && QWidgetPrivate::mouseGrabber == this) { + Q_ASSERT(testAttribute(Qt::WA_WState_Created)); + WId id = effectiveWinId(); + id->SetPointerCapture(false); + QWidgetPrivate::mouseGrabber = 0; + } +} + +void QWidget::activateWindow() +{ + Q_D(QWidget); + QWidget *tlw = window(); + if (tlw->isVisible()) { + S60->windowGroup().SetOrdinalPosition(0); + window()->createWinId(); + RDrawableWindow* rw = tlw->d_func()->topData()->rwindow; + rw->SetOrdinalPosition(0); + } +} + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qwindowdefs.h b/src/gui/kernel/qwindowdefs.h index 8598030..0fe8e1a 100644 --- a/src/gui/kernel/qwindowdefs.h +++ b/src/gui/kernel/qwindowdefs.h @@ -131,6 +131,11 @@ QT_END_HEADER #endif // Q_WS_QWS +#if defined(Q_WS_S60) +class CCoeControl; +typedef CCoeControl * WId; +#endif // Q_WS_S60 + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri index 528559c..693e506 100644 --- a/src/gui/painting/painting.pri +++ b/src/gui/painting/painting.pri @@ -82,6 +82,7 @@ SOURCES += \ DEFINES += QT_RASTER_IMAGEENGINE win32:DEFINES += QT_RASTER_PAINTENGINE embedded:DEFINES += QT_RASTER_PAINTENGINE + symbian:DEFINES += QT_RASTER_PAINTENGINE SOURCES += \ painting/qpaintengine_raster.cpp \ painting/qdrawhelper.cpp \ @@ -162,14 +163,14 @@ unix:x11 { painting/qprintengine_mac.mm \ } -unix:!mac { +unix:!mac:!symbian { HEADERS += \ painting/qprinterinfo_unix_p.h SOURCES += \ painting/qprinterinfo_unix.cpp } -win32|x11|mac|embedded { +win32|x11|mac|embedded|symbian { SOURCES += painting/qbackingstore.cpp HEADERS += painting/qbackingstore_p.h } @@ -186,6 +187,13 @@ embedded { painting/qpaintdevice_qws.cpp } +symbian { + SOURCES += \ + painting/qpaintdevice_s60.cpp \ + painting/qregion_s60.cpp \ + painting/qcolormap_s60.cpp +} + x11|embedded { contains(QT_CONFIG,qtopia) { DEFINES += QT_NO_CUPS QT_NO_LPR @@ -367,3 +375,18 @@ win32:contains(QT_CONFIG, direct3d) { SOURCES += painting/qwindowsurface_d3d.cpp } +symbian { + HEADERS += painting/qwindowsurface_s60_p.h + SOURCES += painting/qwindowsurface_s60.cpp + armccIfdefBlock = \ + "$${LITERAL_HASH}if defined(ARMV6)" \ + "MACRO QT_HAVE_ARMV6" \ + "SOURCEPATH painting" \ + "SOURCE qblendfunctions_armv6_rvct.s" \ + "SOURCE qdrawhelper_armv6_rvct.s" \ + "$${LITERAL_HASH}endif" + + MMP_RULES += armccIfdefBlock + QMAKE_CXXFLAGS.ARMCC *= -O3 +} + diff --git a/src/gui/painting/qblendfunctions_armv6_rvct.s b/src/gui/painting/qblendfunctions_armv6_rvct.s new file mode 100644 index 0000000..312bd07 --- /dev/null +++ b/src/gui/painting/qblendfunctions_armv6_rvct.s @@ -0,0 +1,223 @@ +;/**************************************************************************** +;** +;** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +;** Contact: Qt Software Information (qt-info@nokia.com) +;** +;** This file is part of the QtGui module of the Qt Toolkit. +;** +;** $QT_BEGIN_LICENSE:LGPL$ +;** No Commercial Usage +;** This file contains pre-release code and may not be distributed. +;** You may use this file in accordance with the terms and conditions +;** contained in the either Technology Preview License Agreement or the +;** Beta Release License Agreement. +;** +;** GNU Lesser General Public License Usage +;** Alternatively, this file may be used under the terms of the GNU Lesser +;** General Public License version 2.1 as published by the Free Software +;** Foundation and appearing in the file LICENSE.LGPL included in the +;** packaging of this file. Please review the following information to +;** ensure the GNU Lesser General Public License version 2.1 requirements +;** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +;** +;** In addition, as a special exception, Nokia gives you certain +;** additional rights. These rights are described in the Nokia Qt LGPL +;** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +;** package. +;** +;** GNU General Public License Usage +;** Alternatively, this file may be used under the terms of the GNU +;** General Public License version 3.0 as published by the Free Software +;** Foundation and appearing in the file LICENSE.GPL included in the +;** packaging of this file. Please review the following information to +;** ensure the GNU General Public License version 3.0 requirements will be +;** met: http://www.gnu.org/copyleft/gpl.html. +;** +;** If you are unsure which license is appropriate for your use, please +;** contact the sales department at qt-sales@nokia.com. +;** $QT_END_LICENSE$ +;** +;****************************************************************************/ + +; +; W A R N I N G +; ------------- +; +; This file is not part of the Qt API. It exists purely as an +; implementation detail. This header file may change from version to +; version without notice, or even be removed. +; +; We mean it. +; + + + ARM + PRESERVE8 + + INCLUDE qdrawhelper_armv6_rvct.inc + + +;----------------------------------------------------------------------------- +; qt_blend_rgb32_on_rgb32_arm +; +; @brief +; +; @param dest Destination pixels (r0) +; @param dbpl Destination bytes per line (r1) +; @param src Source pixels (r2) +; @param sbpl Source bytes per line (r3) +; @param w Width (s0 -> r4) +; @param h Height (s1 -> r5) +; @param const_alpha Constant alpha (s2 -> r6) +; +;--------------------------------------------------------------------------- +qt_blend_rgb32_on_rgb32_armv6 Function + stmfd sp!, {r4-r12, r14} + + ; read arguments off the stack + add r8, sp, #10 * 4 + ldmia r8, {r9-r11} + + ; Reorganize registers + + mov r4, r10 + mov r5, r1 + mov r6, r3 + + mov r1, r2 + mov r2, r9 + mov r3, r11 + + ; Now we have registers + ; @param dest Destination pixels (r0) + ; @param src Source pixels (r1) + ; @param w Width (r2) + ; @param const_alpha Constant alpha (r3) + ; @param h Height (r4) + ; @param dbpl Destination bytes per line (r5) + ; @param sbpl Source bytes per line (r6) + + cmp r3, #256 ; test if we have fully opaque constant alpha value + bne rgb32_blend_const_alpha ; branch if not + +rgb32_blend_loop + + subs r4, r4, #1 + bmi rgb32_blend_exit ; while(h--) + +rgb321 PixCpySafe r0, r1, r2 + + add r0, r0, r5 ; dest = dest + dbpl + add r1, r1, r6 ; src = src + sbpl + + b rgb32_blend_loop + + +rgb32_blend_const_alpha + + ;ldr r14, =ComponentHalf ; load 0x800080 to r14 + mov r14, #0x800000 + add r14, r14, #0x80 + + sub r3, r3, #1 ; const_alpha -= 1; + +rgb32_blend_loop_const_alpha + + subs r4, r4, #1 + bmi rgb32_blend_exit ; while(h--) + +rgb322 BlendRowSafe PixelSourceOverConstAlpha + + add r0, r0, r5 ; dest = dest + dbpl + add r1, r1, r6 ; src = src + sbpl + + b rgb32_blend_loop_const_alpha + +rgb32_blend_exit + + ldmfd sp!, {r4-r12, pc} ; pop and return + + + +;----------------------------------------------------------------------------- +; qt_blend_argb32_on_argb32_arm +; +; @brief +; +; @param dest Destination pixels (r0) +; @param dbpl Destination bytes per line (r1) +; @param src Source pixels (r2) +; @param sbpl Source bytes per line (r3) +; @param w Width (s0 -> r4) +; @param h Height (s1 -> r5) +; @param const_alpha Constant alpha (s2 -> r6) +; +;--------------------------------------------------------------------------- +qt_blend_argb32_on_argb32_armv6 Function + stmfd sp!, {r4-r12, r14} + + ; read arguments off the stack + add r8, sp, #10 * 4 + ldmia r8, {r9-r11} + + ; Reorganize registers + + mov r4, r10 + mov r5, r1 + mov r6, r3 + + mov r1, r2 + mov r2, r9 + mov r3, r11 + + ; Now we have registers + ; @param dest Destination pixels (r0) + ; @param src Source pixels (r1) + ; @param w Width (r2) + ; @param const_alpha Constant alpha (r3) + ; @param h Height (r4) + ; @param dbpl Destination bytes per line (r5) + ; @param sbpl Source bytes per line (r6) + + ;ldr r14, =ComponentHalf ; load 0x800080 to r14 + mov r14, #0x800000 + add r14, r14, #0x80 + + cmp r3, #256 ; test if we have fully opaque constant alpha value + bne argb32_blend_const_alpha ; branch if not + +argb32_blend_loop + + subs r4, r4, #1 + bmi argb32_blend_exit ; while(h--) + +argb321 BlendRowSafe PixelSourceOver + + add r0, r0, r5 ; dest = dest + dbpl + add r1, r1, r6 ; src = src + sbpl + + b argb32_blend_loop + +argb32_blend_const_alpha + + sub r3, r3, #1 ; const_alpha -= 1; + +argb32_blend_loop_const_alpha + + subs r4, r4, #1 + bmi argb32_blend_exit ; while(h--) + +argb322 BlendRowSafe PixelSourceOverConstAlpha + + add r0, r0, r5 ; dest = dest + dbpl + add r1, r1, r6 ; src = src + sbpl + + b argb32_blend_loop_const_alpha + +argb32_blend_exit + + ldmfd sp!, {r4-r12, pc} ; pop and return + + + END ; File end + diff --git a/src/gui/painting/qcolormap_s60.cpp b/src/gui/painting/qcolormap_s60.cpp new file mode 100644 index 0000000..1b58598 --- /dev/null +++ b/src/gui/painting/qcolormap_s60.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qcolormap.h" +#include "qcolor.h" + +QT_BEGIN_NAMESPACE + +class QColormapPrivate +{ +public: + inline QColormapPrivate() + : ref(1) + { } + + QAtomicInt ref; +}; + +void QColormap::initialize() +{ +} + +void QColormap::cleanup() +{ +} + +QColormap QColormap::instance(int) +{ + return QColormap(); +} + +QColormap::QColormap() : d(new QColormapPrivate) +{} + +QColormap::QColormap(const QColormap &colormap) :d (colormap.d) +{ d->ref.ref(); } + +QColormap::~QColormap() +{ + if (!d->ref.deref()) + delete d; +} + +QColormap::Mode QColormap::mode() const +{ return QColormap::Direct; } + +int QColormap::depth() const +{ + return 32; +} + +int QColormap::size() const +{ + return -1; +} + +uint QColormap::pixel(const QColor &color) const +{ return color.rgba(); } + +const QColor QColormap::colorAt(uint pixel) const +{ return QColor(pixel); } + +const QVector<QColor> QColormap::colormap() const +{ return QVector<QColor>(); } + +QColormap &QColormap::operator=(const QColormap &colormap) +{ qAtomicAssign(d, colormap.d); return *this; } + +QT_END_NAMESPACE + diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index 9f2831d..ed4dd57 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -38,15 +38,18 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + #include <private/qdrawhelper_p.h> #include <private/qpaintengine_raster_p.h> #include <private/qpainter_p.h> #include <private/qdrawhelper_x86_p.h> +#include <private/qdrawhelper_armv6_p.h> #include <private/qmath_p.h> #include <qmath.h> QT_BEGIN_NAMESPACE + #define MASK(src, a) src = BYTE_MUL(src, a) #if defined(Q_OS_IRIX) && defined(Q_CC_GNU) && __GNUC__ == 3 && __GNUC__ < 4 && QT_POINTER_SIZE == 8 @@ -1497,7 +1500,35 @@ static const uint * QT_FASTCALL fetchConicalGradient(uint *buffer, const Operato return b; } - +#if defined(Q_CC_RVCT) +// Force ARM code generation for comp_func_* -methods +# pragma push +# pragma arm +# if defined(QT_HAVE_ARMV6) +static __forceinline void preload(const uint *start) +{ + asm( "pld [start]" ); +} +static const uint L2CacheLineLength = 32; +static const uint L2CacheLineLengthInInts = L2CacheLineLength/sizeof(uint); +# define PRELOAD_INIT(x) preload(x); +# define PRELOAD_INIT2(x,y) PRELOAD_INIT(x) PRELOAD_INIT(y) +# define PRELOAD_COND(x) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts); +// Two consecutive preloads stall, so space them out a bit by using different modulus. +# define PRELOAD_COND2(x,y) if (((uint)&x[i])%L2CacheLineLength == 0) preload(&x[i] + L2CacheLineLengthInInts); \ + if (((uint)&y[i])%L2CacheLineLength == 16) preload(&y[i] + L2CacheLineLengthInInts); +# else +# define PRELOAD_INIT(x) +# define PRELOAD_INIT2(x,y) +# define PRELOAD_COND(x) +# define PRELOAD_COND2(x,y) +# endif +#else +# define PRELOAD_INIT(x) +# define PRELOAD_INIT2(x,y) +# define PRELOAD_COND(x) +# define PRELOAD_COND2(x,y) +#endif /* The constant alpha factor describes an alpha factor that gets applied to the result of the composition operation combining it with the destination. @@ -1530,8 +1561,11 @@ static void QT_FASTCALL comp_func_solid_Clear(uint *dest, int length, uint, uint QT_MEMFILL_UINT(dest, length, 0); } else { int ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = BYTE_MUL(dest[i], ialpha); + } } } @@ -1541,8 +1575,11 @@ static void QT_FASTCALL comp_func_Clear(uint *dest, const uint *, int length, ui QT_MEMFILL_UINT(dest, length, 0); } else { int ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = BYTE_MUL(dest[i], ialpha); + } } } @@ -1557,8 +1594,11 @@ static void QT_FASTCALL comp_func_solid_Source(uint *dest, int length, uint colo } else { int ialpha = 255 - const_alpha; color = BYTE_MUL(color, const_alpha); - for (int i = 0; i < length; ++i) + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = color + BYTE_MUL(dest[i], ialpha); + } } } @@ -1568,8 +1608,11 @@ static void QT_FASTCALL comp_func_Source(uint *dest, const uint *src, int length ::memcpy(dest, src, length * sizeof(uint)); } else { int ialpha = 255 - const_alpha; - for (int i = 0; i < length; ++i) + PRELOAD_INIT2(dest, src) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) dest[i] = INTERPOLATE_PIXEL_255(src[i], const_alpha, dest[i], ialpha); + } } } @@ -1594,20 +1637,26 @@ static void QT_FASTCALL comp_func_solid_SourceOver(uint *dest, int length, uint } else { if (const_alpha != 255) color = BYTE_MUL(color, const_alpha); - for (int i = 0; i < length; ++i) + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = color + BYTE_MUL(dest[i], qAlpha(~color)); + } } } static void QT_FASTCALL comp_func_SourceOver(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint s = src[i]; dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); } } else { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint s = BYTE_MUL(src[i], const_alpha); dest[i] = s + BYTE_MUL(dest[i], qAlpha(~s)); } @@ -1623,7 +1672,9 @@ static void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, { if (const_alpha != 255) color = BYTE_MUL(color, const_alpha); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; dest[i] = d + BYTE_MUL(color, qAlpha(~d)); } @@ -1631,13 +1682,16 @@ static void QT_FASTCALL comp_func_solid_DestinationOver(uint *dest, int length, static void QT_FASTCALL comp_func_DestinationOver(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; dest[i] = d + BYTE_MUL(src[i], qAlpha(~d)); } } else { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = BYTE_MUL(src[i], const_alpha); dest[i] = d + BYTE_MUL(s, qAlpha(~d)); @@ -1651,13 +1705,17 @@ static void QT_FASTCALL comp_func_DestinationOver(uint *dest, const uint *src, i */ static void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint color, uint const_alpha) { + PRELOAD_INIT(dest) if (const_alpha == 255) { - for (int i = 0; i < length; ++i) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = BYTE_MUL(color, qAlpha(dest[i])); + } } else { color = BYTE_MUL(color, const_alpha); uint cia = 255 - const_alpha; for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(d), d, cia); } @@ -1666,12 +1724,16 @@ static void QT_FASTCALL comp_func_solid_SourceIn(uint *dest, int length, uint co static void QT_FASTCALL comp_func_SourceIn(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { - for (int i = 0; i < length; ++i) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) dest[i] = BYTE_MUL(src[i], qAlpha(dest[i])); + } } else { uint cia = 255 - const_alpha; for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = BYTE_MUL(src[i], const_alpha); dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, cia); @@ -1690,19 +1752,25 @@ static void QT_FASTCALL comp_func_solid_DestinationIn(uint *dest, int length, ui if (const_alpha != 255) { a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; } + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = BYTE_MUL(dest[i], a); } } static void QT_FASTCALL comp_func_DestinationIn(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { - for (int i = 0; i < length; ++i) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) dest[i] = BYTE_MUL(dest[i], qAlpha(src[i])); + } } else { int cia = 255 - const_alpha; for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint a = BYTE_MUL(qAlpha(src[i]), const_alpha) + cia; dest[i] = BYTE_MUL(dest[i], a); } @@ -1716,13 +1784,17 @@ static void QT_FASTCALL comp_func_DestinationIn(uint *dest, const uint *src, int static void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint color, uint const_alpha) { + PRELOAD_INIT(dest) if (const_alpha == 255) { - for (int i = 0; i < length; ++i) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = BYTE_MUL(color, qAlpha(~dest[i])); + } } else { color = BYTE_MUL(color, const_alpha); int cia = 255 - const_alpha; for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, cia); } @@ -1731,12 +1803,16 @@ static void QT_FASTCALL comp_func_solid_SourceOut(uint *dest, int length, uint c static void QT_FASTCALL comp_func_SourceOut(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { - for (int i = 0; i < length; ++i) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) dest[i] = BYTE_MUL(src[i], qAlpha(~dest[i])); + } } else { int cia = 255 - const_alpha; for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint s = BYTE_MUL(src[i], const_alpha); uint d = dest[i]; dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, cia); @@ -1754,18 +1830,25 @@ static void QT_FASTCALL comp_func_solid_DestinationOut(uint *dest, int length, u uint a = qAlpha(~color); if (const_alpha != 255) a = BYTE_MUL(a, const_alpha) + 255 - const_alpha; - for (int i = 0; i < length; ++i) + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = BYTE_MUL(dest[i], a); + } } static void QT_FASTCALL comp_func_DestinationOut(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { - for (int i = 0; i < length; ++i) + for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) dest[i] = BYTE_MUL(dest[i], qAlpha(~src[i])); + } } else { int cia = 255 - const_alpha; for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint sia = BYTE_MUL(qAlpha(~src[i]), const_alpha) + cia; dest[i] = BYTE_MUL(dest[i], sia); } @@ -1784,20 +1867,26 @@ static void QT_FASTCALL comp_func_solid_SourceAtop(uint *dest, int length, uint color = BYTE_MUL(color, const_alpha); } uint sia = qAlpha(~color); - for (int i = 0; i < length; ++i) + PRELOAD_INIT(dest) + for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(dest[i]), dest[i], sia); + } } static void QT_FASTCALL comp_func_SourceAtop(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint s = src[i]; uint d = dest[i]; dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); } } else { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint s = BYTE_MUL(src[i], const_alpha); uint d = dest[i]; dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(d), d, qAlpha(~s)); @@ -1817,7 +1906,9 @@ static void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, color = BYTE_MUL(color, const_alpha); a = qAlpha(color) + 255 - const_alpha; } + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; dest[i] = INTERPOLATE_PIXEL_255(d, a, color, qAlpha(~d)); } @@ -1825,8 +1916,10 @@ static void QT_FASTCALL comp_func_solid_DestinationAtop(uint *dest, int length, static void QT_FASTCALL comp_func_DestinationAtop(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint s = src[i]; uint d = dest[i]; dest[i] = INTERPOLATE_PIXEL_255(d, qAlpha(s), s, qAlpha(~d)); @@ -1834,6 +1927,7 @@ static void QT_FASTCALL comp_func_DestinationAtop(uint *dest, const uint *src, i } else { int cia = 255 - const_alpha; for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint s = BYTE_MUL(src[i], const_alpha); uint d = dest[i]; uint a = qAlpha(s) + cia; @@ -1854,7 +1948,9 @@ static void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, color = BYTE_MUL(color, const_alpha); uint sia = qAlpha(~color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; dest[i] = INTERPOLATE_PIXEL_255(color, qAlpha(~d), d, sia); } @@ -1862,14 +1958,17 @@ static void QT_FASTCALL comp_func_solid_XOR(uint *dest, int length, uint color, static void QT_FASTCALL comp_func_XOR(uint *dest, const uint *src, int length, uint const_alpha) { + PRELOAD_INIT2(dest, src) if (const_alpha == 255) { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); } } else { for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = BYTE_MUL(src[i], const_alpha); dest[i] = INTERPOLATE_PIXEL_255(s, qAlpha(~d), d, qAlpha(~s)); @@ -1920,7 +2019,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Plus_impl(uint *dest, int { uint s = color; + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; #define MIX(mask) (qMin(((qint64(s)&mask) + (qint64(d)&mask)), qint64(mask))) d = (MIX(AMASK) | MIX(RMASK) | MIX(GMASK) | MIX(BMASK)); @@ -1940,7 +2041,9 @@ static void QT_FASTCALL comp_func_solid_Plus(uint *dest, int length, uint color, template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Plus_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -1976,7 +2079,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Multiply_impl(uint *dest, int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2002,7 +2107,9 @@ static void QT_FASTCALL comp_func_solid_Multiply(uint *dest, int length, uint co template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Multiply_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2040,7 +2147,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Screen_impl(uint *dest, i int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2066,7 +2175,9 @@ static void QT_FASTCALL comp_func_solid_Screen(uint *dest, int length, uint colo template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Screen_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2115,7 +2226,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Overlay_impl(uint *dest, int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2141,7 +2254,9 @@ static void QT_FASTCALL comp_func_solid_Overlay(uint *dest, int length, uint col template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Overlay_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2184,7 +2299,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Darken_impl(uint *dest, i int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2210,7 +2327,9 @@ static void QT_FASTCALL comp_func_solid_Darken(uint *dest, int length, uint colo template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Darken_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2253,7 +2372,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Lighten_impl(uint *dest, int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2279,7 +2400,9 @@ static void QT_FASTCALL comp_func_solid_Lighten(uint *dest, int length, uint col template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Lighten_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2332,7 +2455,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorDodge_impl(uint *des int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2358,7 +2483,9 @@ static void QT_FASTCALL comp_func_solid_ColorDodge(uint *dest, int length, uint template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorDodge_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2411,7 +2538,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_ColorBurn_impl(uint *dest int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2437,7 +2566,9 @@ static void QT_FASTCALL comp_func_solid_ColorBurn(uint *dest, int length, uint c template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_ColorBurn_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2487,7 +2618,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_HardLight_impl(uint *dest int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2513,7 +2646,9 @@ static void QT_FASTCALL comp_func_solid_HardLight(uint *dest, int length, uint c template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_HardLight_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2572,7 +2707,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_SoftLight_impl(uint *dest int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2598,7 +2735,9 @@ static void QT_FASTCALL comp_func_solid_SoftLight(uint *dest, int length, uint c template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_SoftLight_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2641,7 +2780,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_solid_Difference_impl(uint *des int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2667,7 +2808,9 @@ static void QT_FASTCALL comp_func_solid_Difference(uint *dest, int length, uint template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Difference_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2704,7 +2847,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void QT_FASTCALL comp_func_solid_Exclusion_imp int sg = qGreen(color); int sb = qBlue(color); + PRELOAD_INIT(dest) for (int i = 0; i < length; ++i) { + PRELOAD_COND(dest) uint d = dest[i]; int da = qAlpha(d); @@ -2730,7 +2875,9 @@ static void QT_FASTCALL comp_func_solid_Exclusion(uint *dest, int length, uint c template <typename T> Q_STATIC_TEMPLATE_FUNCTION inline void comp_func_Exclusion_impl(uint *dest, const uint *src, int length, const T &coverage) { + PRELOAD_INIT2(dest, src) for (int i = 0; i < length; ++i) { + PRELOAD_COND2(dest, src) uint d = dest[i]; uint s = src[i]; @@ -2756,6 +2903,11 @@ static void QT_FASTCALL comp_func_Exclusion(uint *dest, const uint *src, int len comp_func_Exclusion_impl(dest, src, length, QPartialCoverage(const_alpha)); } +#if defined(Q_CC_RVCT) +// Restore pragma state from previous #pragma arm +# pragma pop +#endif + static void QT_FASTCALL rasterop_solid_SourceOrDestination(uint *dest, int length, uint color, @@ -7404,7 +7556,7 @@ static void qt_alphamapblit_quint32(QRasterBuffer *rasterBuffer, #endif { int ialpha = 255 - coverage; - dest[i] = BYTE_MUL(c, uint(coverage)) + BYTE_MUL(dest[i], ialpha); + dest[i] = INTERPOLATE_PIXEL_255(c, coverage, dest[i], ialpha); } } } @@ -7445,7 +7597,7 @@ static void qt_alphamapblit_quint32(QRasterBuffer *rasterBuffer, #endif { int ialpha = 255 - coverage; - dest[xp] = BYTE_MUL(c, uint(coverage)) + BYTE_MUL(dest[xp], ialpha); + dest[xp] = INTERPOLATE_PIXEL_255(c, coverage, dest[xp], ialpha); } } @@ -8031,6 +8183,96 @@ static uint detectCPUFeatures() #endif } +#if defined(Q_CC_RVCT) && defined(QT_HAVE_ARMV6) +// Move these to qdrawhelper_arm.c when all +// functions are implemented using arm assembly. +static CompositionFunctionSolid qt_functionForModeSolid_ARMv6[numCompositionFunctions] = { + comp_func_solid_SourceOver, + comp_func_solid_DestinationOver, + comp_func_solid_Clear, + comp_func_solid_Source, + comp_func_solid_Destination, + comp_func_solid_SourceIn, + comp_func_solid_DestinationIn, + comp_func_solid_SourceOut, + comp_func_solid_DestinationOut, + comp_func_solid_SourceAtop, + comp_func_solid_DestinationAtop, + comp_func_solid_XOR, + comp_func_solid_Plus, + comp_func_solid_Multiply, + comp_func_solid_Screen, + comp_func_solid_Overlay, + comp_func_solid_Darken, + comp_func_solid_Lighten, + comp_func_solid_ColorDodge, + comp_func_solid_ColorBurn, + comp_func_solid_HardLight, + comp_func_solid_SoftLight, + comp_func_solid_Difference, + comp_func_solid_Exclusion, + rasterop_solid_SourceOrDestination, + rasterop_solid_SourceAndDestination, + rasterop_solid_SourceXorDestination, + rasterop_solid_NotSourceAndNotDestination, + rasterop_solid_NotSourceOrNotDestination, + rasterop_solid_NotSourceXorDestination, + rasterop_solid_NotSource, + rasterop_solid_NotSourceAndDestination, + rasterop_solid_SourceAndNotDestination +}; + +static CompositionFunction qt_functionForMode_ARMv6[numCompositionFunctions] = { + comp_func_SourceOver_armv6, + comp_func_DestinationOver, + comp_func_Clear, + comp_func_Source_armv6, + comp_func_Destination, + comp_func_SourceIn, + comp_func_DestinationIn, + comp_func_SourceOut, + comp_func_DestinationOut, + comp_func_SourceAtop, + comp_func_DestinationAtop, + comp_func_XOR, + comp_func_Plus, + comp_func_Multiply, + comp_func_Screen, + comp_func_Overlay, + comp_func_Darken, + comp_func_Lighten, + comp_func_ColorDodge, + comp_func_ColorBurn, + comp_func_HardLight, + comp_func_SoftLight, + comp_func_Difference, + comp_func_Exclusion, + rasterop_SourceOrDestination, + rasterop_SourceAndDestination, + rasterop_SourceXorDestination, + rasterop_NotSourceAndNotDestination, + rasterop_NotSourceOrNotDestination, + rasterop_NotSourceXorDestination, + rasterop_NotSource, + rasterop_NotSourceAndDestination, + rasterop_SourceAndNotDestination +}; + +static void qt_blend_color_argb_armv6(int count, const QSpan *spans, void *userData) +{ + QSpanData *data = reinterpret_cast<QSpanData *>(userData); + + CompositionFunctionSolid func = qt_functionForModeSolid_ARMv6[data->rasterBuffer->compositionMode]; + while (count--) { + uint *target = ((uint *)data->rasterBuffer->scanLine(spans->y)) + spans->x; + func(target, spans->len, data->solid.color, spans->coverage); + ++spans; + } +} + +#endif // Q_CC_RVCT && QT_HAVE_ARMV6 + + void qInitDrawhelperAsm() { static uint features = 0xffffffff; @@ -8146,6 +8388,20 @@ void qInitDrawhelperAsm() #endif // QT_NO_DEBUG +#if defined(Q_CC_RVCT) && defined(QT_HAVE_ARMV6) + functionForModeAsm = qt_functionForMode_ARMv6; + functionForModeSolidAsm = qt_functionForModeSolid_ARMv6; + + qt_memfill32 = qt_memfill32_armv6; + + qDrawHelper[QImage::Format_ARGB32_Premultiplied].blendColor = qt_blend_color_argb_armv6; + + qBlendFunctions[QImage::Format_RGB32][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_armv6; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_armv6; + qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_armv6; + qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_armv6; +#endif // Q_CC_RVCT && QT_HAVE_ARMV6 + if (functionForModeSolidAsm) { const int destinationMode = QPainter::CompositionMode_Destination; functionForModeSolidAsm[destinationMode] = functionForModeSolid_C[destinationMode]; diff --git a/src/gui/painting/qdrawhelper_armv6_p.h b/src/gui/painting/qdrawhelper_armv6_p.h new file mode 100644 index 0000000..a4c1df2 --- /dev/null +++ b/src/gui/painting/qdrawhelper_armv6_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDRAWHELPER_ARMV6_P_H +#define QDRAWHELPER_ARMV6_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qdrawhelper_p.h> + +QT_BEGIN_NAMESPACE + +#if defined(Q_CC_RVCT) && defined(QT_HAVE_ARMV6) + +extern "C" void qt_blend_rgb32_on_rgb32_armv6(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + +extern "C" void qt_blend_argb32_on_argb32_armv6(uchar *destPixels, int dbpl, + const uchar *srcPixels, int sbpl, + int w, int h, + int const_alpha); + +extern "C" void qt_memfill32_armv6(quint32 *dest, quint32 value, int count); + +extern "C" void comp_func_Source_armv6(uint *dest, const uint *src, int length, uint const_alpha); +extern "C" void comp_func_SourceOver_armv6(uint *dest, const uint *src, int length, uint const_alpha); + +#endif // QT_HAVE_ARMV6 + +QT_END_NAMESPACE + +#endif // QDRAWHELPER_ARMV6_P_H diff --git a/src/gui/painting/qdrawhelper_armv6_rvct.inc b/src/gui/painting/qdrawhelper_armv6_rvct.inc new file mode 100644 index 0000000..b3e0605 --- /dev/null +++ b/src/gui/painting/qdrawhelper_armv6_rvct.inc @@ -0,0 +1,496 @@ +;/**************************************************************************** +;** +;** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +;** Contact: Qt Software Information (qt-info@nokia.com) +;** +;** This file is part of the QtGui module of the Qt Toolkit. +;** +;** $QT_BEGIN_LICENSE:LGPL$ +;** No Commercial Usage +;** This file contains pre-release code and may not be distributed. +;** You may use this file in accordance with the terms and conditions +;** contained in the either Technology Preview License Agreement or the +;** Beta Release License Agreement. +;** +;** GNU Lesser General Public License Usage +;** Alternatively, this file may be used under the terms of the GNU Lesser +;** General Public License version 2.1 as published by the Free Software +;** Foundation and appearing in the file LICENSE.LGPL included in the +;** packaging of this file. Please review the following information to +;** ensure the GNU Lesser General Public License version 2.1 requirements +;** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +;** +;** In addition, as a special exception, Nokia gives you certain +;** additional rights. These rights are described in the Nokia Qt LGPL +;** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +;** package. +;** +;** GNU General Public License Usage +;** Alternatively, this file may be used under the terms of the GNU +;** General Public License version 3.0 as published by the Free Software +;** Foundation and appearing in the file LICENSE.GPL included in the +;** packaging of this file. Please review the following information to +;** ensure the GNU General Public License version 3.0 requirements will be +;** met: http://www.gnu.org/copyleft/gpl.html. +;** +;** If you are unsure which license is appropriate for your use, please +;** contact the sales department at qt-sales@nokia.com. +;** $QT_END_LICENSE$ +;** +;****************************************************************************/ + +; +; W A R N I N G +; ------------- +; +; This file is not part of the Qt API. It exists purely as an +; implementation detail. This header file may change from version to +; version without notice, or even be removed. +; +; We mean it. +; + +;----------------------------------------------------------------------------- +; Globals. +; Earch marcro expects that caller has loaded 0x800080 to r14. +;----------------------------------------------------------------------------- + +ComponentHalf EQU 0x800080 + +;----------------------------------------------------------------------------- +; ARM assembly implementations of accelerated graphics operations. +; +; Conventions: +; +; - r0 = Target buffer pointer +; - r1 = Source buffer pointer +; - r2 = Length of the buffer to blend +; - r3 = Constant alpha for source buffer +; +;----------------------------------------------------------------------------- + +; A macro for transparently defining ARM functions + MACRO +$func Function + AREA Function_$func, CODE + GLOBAL $func + ALIGN 4 + CODE32 +$func + MEND + + +;----------------------------------------------------------------------------- +; Armv6 boosted implementation of BYTE_MUL(...) function found in qdrawhelper_p.h. +; +; @param dst Destination register where to store the result +; @param x Value to multiply +; @param a Multiplicator byte +; @param r14 Component half 0x800080 +; +; @note Trashes x, r8 +;----------------------------------------------------------------------------- + MACRO + ByteMul $dst, $x, $a + + ; static inline uint BYTE_MUL(uint x, uint a) + + ; uint r8 = (x & 0xff00ff) * a + 0x800080 + uxtb16 r8, $x ; r8 = r8 & 0x00FF00FF + mla r8, r8, $a, r14 + + ; x = ((r >> 8) & 0xff00ff) * a + 0x800080 + uxtb16 $x, $x, ror #8 + mla $x, $x, $a, r14 + + + ; r8 = (r8 + ((r8 >> 8) & 0xff00ff) ) >> 8 + ; r8 &= 0xff00ff + uxtab16 r8, r8, r8, ror #8 + uxtb16 r8, r8, ror #8 + + ; x = x + ((x >>8) & 0xff00ff) + uxtab16 $x, $x, $x, ror #8 + + ; x &= 0xff00ff00 + ; x |= r8 + uxtb16 $x, $x, ror #8 + orr $dst, r8, $x, lsl #8 + + MEND + +;----------------------------------------------------------------------------- +; Armv6 boosted implementation of INTERPOLATE_PIXEL_255(...) function found in +; qdrawhelper_p.h. +; +; @param dst Destination register where to store the result +; @param x First value to multiply +; @param a Multiplicator byte for first value +; @param y Second value to multiply +; @param b Multiplicator byte for second value +; @param r14 Component half 0x800080 +; +; +; @note Trashes x, r8, r14 +;----------------------------------------------------------------------------- + MACRO + InterpolatePixel255 $dst, $x, $a, $y, $b + + ; static inline uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b) + + ; First calculate the parts where we need 0x800080 + + ; uint r8 = (((x & 0xff00ff) * a) + 0x800080) + uxtb16 r8, $x ; r8 = r8 & 0x00FF00FF + mla r8, r8, $a, r14 + + ; x = ((((x >> 8) & 0xff00ff) * a) + 0x800080) + uxtb16 $x, $x, ror #8 + mla $x, $x, $a, r14 + + ; Now we are trashing r14 to free it for other purposes + + ; uint r14 = (y & 0xff00ff) * b + uxtb16 r14, $y ; r14 = y & 0x00FF00FF + mul r14, r14, $b + + ; r8 = r8 + r14 + add r8, r8, r14 + + ; r8 = (r8 + ((r8 >> 8) & 0xff00ff) ) >> 8 + ; r8 &= 0xff00ff + uxtab16 r8, r8, r8, ror #8 + uxtb16 r8, r8, ror #8 + + ; r14 = ((y >> 8) & 0xff00ff) * b + uxtb16 r14, $y, ror #8 ; r14 = ((y >> 8) & 0xFF00FF) + mul r14, r14, $b + + ; x = x + r14 + add $x, $x, r14 + + ; x = x + ((x >>8) & 0xff00ff) + uxtab16 $x, $x, $x, ror #8 + + ; x &= 0xff00ff00 + ; x |= r8 + uxtb16 $x, $x, ror #8 + orr $dst, r8, $x, lsl #8 + + MEND + +;----------------------------------------------------------------------------- +; +;----------------------------------------------------------------------------- + MACRO +$label Blend4Pixels $BlendPixel + + ; Blend first 4 pixels + + ldmia r1!, {r4-r7} + ldm r0, {r9-r12} + +b4p1_$label $BlendPixel r9, r4, r3 +b4p2_$label $BlendPixel r10, r5, r3 +b4p3_$label $BlendPixel r11, r6, r3 +b4p4_$label $BlendPixel r12, r7, r3 + + stmia r0!, {r9-r12} + + MEND + +;----------------------------------------------------------------------------- +; +;----------------------------------------------------------------------------- + MACRO +$label Blend8Pixels $BlendPixel + +b8p1_$label Blend4Pixels $BlendPixel +b8p2_$label Blend4Pixels $BlendPixel + + MEND + +;----------------------------------------------------------------------------- +; +;----------------------------------------------------------------------------- + MACRO +$label Blend16Pixels $BlendPixel + +b16p1_$label Blend8Pixels $BlendPixel +b16p2_$label Blend8Pixels $BlendPixel + + MEND + +;----------------------------------------------------------------------------- +; +;----------------------------------------------------------------------------- + MACRO +$label Blend32Pixels $BlendPixel + +b32p1_$label Blend16Pixels $BlendPixel +b32p2_$label Blend16Pixels $BlendPixel + + MEND + +;----------------------------------------------------------------------------- +; A macro for source over compositing one row of pixels and saving the results +; to destination buffer. +; +; @param dest Destination buffer (r0) +; @param src Source buffer (r1) +; @param length Length (r2) +; @param const_alpha Constant alpha (r3) +; @param r14 Component Half (0x800080) (r14) +; +; @note Advances r0, r1 +; @note Trashes r2, r4-r12 +;----------------------------------------------------------------------------- + MACRO +$label BlendRow $BlendPixel + + pld [r1] + +bloop_$label + ; Blend 32 pixels per loop iteration + subs r2, r2, #32 + bmi b_remaining_$label + +brp1_$label Blend32Pixels $BlendPixel + + b bloop_$label + +b_remaining_$label + + ; Remaining 31 pixels + + addmi r2, r2, #32 + + ; Blend 16 pixels + tst r2, #16 + beq b_remaining8_$label + +brp2_$label Blend16Pixels $BlendPixel + +b_remaining8_$label + + ; Blend 8 pixels + tst r2, #8 + beq b_remaining4_$label + +brp3_$label Blend8Pixels $BlendPixel + +b_remaining4_$label + + ; Blend 4 pixels + tst r2, #4 + beq b_remaining3_$label + +brp4_$label Blend4Pixels $BlendPixel + +b_remaining3_$label + + ; Remaining 3 pixels + + tst r2, #2 + beq b_last_$label + + ldmia r1!, {r4-r5} + ldm r0, {r9-r10} + +brp5_$label $BlendPixel r9, r4, r3 +brp6_$label $BlendPixel r10, r5, r3 + + stmia r0!, {r9-r10} + +b_last_$label + + tst r2, #1 + beq bexit_$label + + ldr r4, [r1] + ldr r9, [r0] + +bpl_$label $BlendPixel r9, r4, r3 + + str r9, [r0] + +bexit_$label + + MEND + +;----------------------------------------------------------------------------- +; A macro for source over compositing one row of pixels and saving the results +; to destination buffer. Restores all registers. +; +; @param dest Destination buffer (r0) +; @param src Source buffer (r1) +; @param length Length (r2) +; @param const_alpha Constant alpha (r3) +; @param r14 Component Half (0x800080) (r14) +; +; @note Advances r0, r1 +; @note Trashes r2, r4-r12 +;----------------------------------------------------------------------------- + MACRO +$label BlendRowSafe $BlendPixel + + stmfd sp!, {r0-r6} ; Preserves registers only up to r6 + +brs_$label BlendRow $BlendPixel + + ldmfd sp!, {r0-r6} + + MEND + + +;----------------------------------------------------------------------------- +; Pix Copy. +; NOTE! Cache line size of ARM1136JF-S and ARM1136J-S is 32 bytes (8 pixels). +; +; @param dst Destination pixels (r0) +; @param src Source pixels (r1) +; @param len Length (r2) +; +; @note Trashes r3-r10 +;----------------------------------------------------------------------------- + MACRO +$label PixCpy $dst, $src, $len + + pld [$src] + +pcpy_loop_$label + ; Copy 8 pixels per loop iteration + pld [$src, #96] + subs $len, $len, #8 + ldmgeia $src!, {r3-r10} + stmgeia $dst!, {r3-r10} + bgt pcpy_loop_$label + +pcpy_remaining_$label + + ; Copy up to 7 remaining pixels + + ; Copy 4 pixels + tst $len, #4 + ldmneia $src!, {r3-r6} + stmneia $dst!, {r3-r6} + + tst $len, #2 + ldmneia $src!, {r3-r4} + stmneia $dst!, {r3-r4} + + tst $len, #1 + ldrne r3, [$src] + strne r3, [$dst] + + MEND + +;----------------------------------------------------------------------------- +; General Pix Copy. Maximum 8 pixels at time. Restores all registers. +; +; @param dst Destination pixels (r0) +; @param src Source pixels (r1) +; @param len Length (r2) +; +; @note Trashes r3-r10 +;----------------------------------------------------------------------------- + MACRO +$label PixCpySafe $dst, $src, $len + + stmfd sp!, {r0-r6} ; Preserves registers only up to r6 + +pcs_$label PixCpy $dst, $src, $len + + ldmfd sp!, {r0-r6} ; pop + + MEND + + +;----------------------------------------------------------------------------- +; A macro for source over compositing one pixel and saving the result to +; dst register. +; +; @param dst Destination register, must contain destination pixel upon entry +; @param src Source register, must contain source pixel upon entry +; @param const_alpha Constant source alpha +; @param r14 Component half 0x800080 +; +; @note Trashes const_alpha, r8 +;----------------------------------------------------------------------------- + MACRO +$label PixelSourceOver $dst, $src, $const_alpha + + ; Negate src and extract alpha + mvn $const_alpha, $src ; bitwise not + uxtb $const_alpha, $const_alpha, ror #24 ; r3 = ((r3 & 0xFF000000) >> 24); + + ;cmp $const_alpha, #255 ; test for full transparency ( negated ) + ;beq exit_$label + cmp $const_alpha, #0 ; test for full opacity ( negated ) + moveq $dst, $src + beq exit_$label + + ByteMul $dst, $dst, $const_alpha + add $dst, $src, $dst + +exit_$label + MEND + +;----------------------------------------------------------------------------- +; A macro for source over compositing one pixel and saving the result to +; dst register. +; +; @param dst Destination register, must contain destination pixel upon entry +; @param src Source register, must contain source pixel upon entry +; @param const_alpha Constant source alpha +; @param r14 Component half 0x800080 +; +; @note Trashes src, const_alpha, r8 +;----------------------------------------------------------------------------- + MACRO +$label PixelSourceOverConstAlpha $dst, $src, $const_alpha + + ; store alpha because we are going to trash it + stmfd sp!, {$const_alpha} + + ByteMul $src, $src, $const_alpha + + ; Negate src and extract alpha + mvn $const_alpha, $src ; bitwise not + uxtb $const_alpha, $const_alpha, ror #24 ; r3 = ((r3 & 0xFF000000) >> 24); + + ByteMul $dst, $dst, $const_alpha + + add $dst, $src, $dst + + ; recover alpha + ldmfd sp!, {$const_alpha} + + MEND + +;----------------------------------------------------------------------------- +; A macro for source over compositing one pixel and saving the result to +; a register. +; +; @param dst Destination register, must contain destination pixel upon entry +; @param src Source register, must contain source pixel upon entry +; @param const_alpha Constant source alpha +; @param r14 Component half 0x800080 +; +; @note Trashes src, r8 +;----------------------------------------------------------------------------- + MACRO +$label PixelSourceConstAlpha $dst, $src, $const_alpha + + ; store r2 and r14 because we are going to trash them + stmfd sp!, {r2, r14} + + rsb r2, $const_alpha, #255 + InterpolatePixel255 $dst, $src, $const_alpha, $dst, r2 + + ; recover r2 and r14 + ldmfd sp!, {r2, r14} + + MEND + + END ; File end diff --git a/src/gui/painting/qdrawhelper_armv6_rvct.s b/src/gui/painting/qdrawhelper_armv6_rvct.s new file mode 100644 index 0000000..3ffe48b --- /dev/null +++ b/src/gui/painting/qdrawhelper_armv6_rvct.s @@ -0,0 +1,178 @@ +;/**************************************************************************** +;** +;** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +;** Contact: Qt Software Information (qt-info@nokia.com) +;** +;** This file is part of the QtGui module of the Qt Toolkit. +;** +;** $QT_BEGIN_LICENSE:LGPL$ +;** No Commercial Usage +;** This file contains pre-release code and may not be distributed. +;** You may use this file in accordance with the terms and conditions +;** contained in the either Technology Preview License Agreement or the +;** Beta Release License Agreement. +;** +;** GNU Lesser General Public License Usage +;** Alternatively, this file may be used under the terms of the GNU Lesser +;** General Public License version 2.1 as published by the Free Software +;** Foundation and appearing in the file LICENSE.LGPL included in the +;** packaging of this file. Please review the following information to +;** ensure the GNU Lesser General Public License version 2.1 requirements +;** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +;** +;** In addition, as a special exception, Nokia gives you certain +;** additional rights. These rights are described in the Nokia Qt LGPL +;** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +;** package. +;** +;** GNU General Public License Usage +;** Alternatively, this file may be used under the terms of the GNU +;** General Public License version 3.0 as published by the Free Software +;** Foundation and appearing in the file LICENSE.GPL included in the +;** packaging of this file. Please review the following information to +;** ensure the GNU General Public License version 3.0 requirements will be +;** met: http://www.gnu.org/copyleft/gpl.html. +;** +;** If you are unsure which license is appropriate for your use, please +;** contact the sales department at qt-sales@nokia.com. +;** $QT_END_LICENSE$ +;** +;****************************************************************************/ + +; +; W A R N I N G +; ------------- +; +; This file is not part of the Qt API. It exists purely as an +; implementation detail. This header file may change from version to +; version without notice, or even be removed. +; +; We mean it. +; + + ARM + PRESERVE8 + + INCLUDE qdrawhelper_armv6_rvct.inc + +;----------------------------------------------------------------------------- +; qt_memfill32_armv6 +; +; @brief Not yet in use! +; +; @param dest Destination buffer (r0) +; @param value Value (r1) +; @param count Count (r2) +; +;--------------------------------------------------------------------------- +qt_memfill32_armv6 Function + stmfd sp!, {r4-r12, r14} + + mov r3, r1 + mov r4, r1 + mov r5, r1 + mov r6, r1 + mov r7, r1 + mov r8, r1 + mov r9, r1 + +mfill_loop + ; Fill 32 pixels per loop iteration + subs r2, r2, #32 + stmgeia r0!, {r1, r3, r4, r5, r6, r7, r8, r9} + stmgeia r0!, {r1, r3, r4, r5, r6, r7, r8, r9} + stmgeia r0!, {r1, r3, r4, r5, r6, r7, r8, r9} + stmgeia r0!, {r1, r3, r4, r5, r6, r7, r8, r9} + bgt mfill_loop + +mfill_remaining + + ; Fill up to 31 remaining pixels + + ; Fill 16 pixels + tst r2, #16 + stmneia r0!, {r1, r3, r4, r5, r6, r7, r8, r9} + stmneia r0!, {r1, r3, r4, r5, r6, r7, r8, r9} + + ; Fill 8 pixels + tst r2, #8 + stmneia r0!, {r1, r3, r4, r5, r6, r7, r8, r9} + + ; Fill 4 pixels + tst r2, #4 + stmneia r0!, {r1, r3, r4, r5} + + ; Fill 2 pixels + tst r2, #2 + stmneia r0!, {r1, r3} + + ; Fill last one + tst r2, #1 + strne r1, [r0] + + ldmfd sp!, {r4-r12, pc} ; pop and return + +;----------------------------------------------------------------------------- +; comp_func_Source_arm +; +; @brief +; +; @param dest Destination buffer (r0) +; @param src Source buffer (r1) +; @param length Length (r2) +; @param const_alpha Constant alpha (r3) +; +;--------------------------------------------------------------------------- +comp_func_Source_armv6 Function + stmfd sp!, {r4-r12, r14} + + cmp r3, #255 ; if(r3 == 255) + bne src2 ; branch if not + +src1 PixCpy r0, r1, r2 + + ldmfd sp!, {r4-r12, pc} ; pop and return + +src2 + ;ldr r14, =ComponentHalf ; load 0x800080 to r14 + mov r14, #0x800000 + add r14, r14, #0x80 + +src22 BlendRow PixelSourceConstAlpha + + ldmfd sp!, {r4-r12, pc} ; pop and return + +;----------------------------------------------------------------------------- +; comp_func_SourceOver_arm +; +; @brief +; +; @param dest Destination buffer (r0) +; @param src Source buffer (r1) +; @param length Length (r2) +; @param const_alpha Constant alpha (r3) +; +;--------------------------------------------------------------------------- +comp_func_SourceOver_armv6 Function + stmfd sp!, {r4-r12, r14} + + ;ldr r14, =ComponentHalf ; load 0x800080 to r14 + mov r14, #0x800000 + add r14, r14, #0x80 + + cmp r3, #255 ; if(r3 == 255) + bne srcovr2 ; branch if not + +srcovr1 BlendRow PixelSourceOver + + ldmfd sp!, {r4-r12, pc} ; pop and return + +srcovr2 + +srcovr22 BlendRow PixelSourceOverConstAlpha + + ldmfd sp!, {r4-r12, pc} ; pop and return + + + END ; File end + diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h index de97683..ddda7f7 100644 --- a/src/gui/painting/qdrawhelper_p.h +++ b/src/gui/painting/qdrawhelper_p.h @@ -87,7 +87,7 @@ QT_BEGIN_NAMESPACE #if defined(Q_CC_RVCT) // RVCT doesn't like static template functions # define Q_STATIC_TEMPLATE_FUNCTION -# define Q_STATIC_INLINE_FUNCTION inline +# define Q_STATIC_INLINE_FUNCTION static __forceinline #else # define Q_STATIC_TEMPLATE_FUNCTION static # define Q_STATIC_INLINE_FUNCTION static inline @@ -300,19 +300,23 @@ struct QSpanData }; -static inline uint BYTE_MUL_RGB16(uint x, uint a) { +Q_STATIC_INLINE_FUNCTION uint BYTE_MUL_RGB16(uint x, uint a) { a += 1; uint t = (((x & 0x07e0)*a) >> 8) & 0x07e0; t |= (((x & 0xf81f)*(a>>2)) >> 6) & 0xf81f; return t; } -static inline uint BYTE_MUL_RGB16_32(uint x, uint a) { +Q_STATIC_INLINE_FUNCTION uint BYTE_MUL_RGB16_32(uint x, uint a) { uint t = (((x & 0xf81f07e0) >> 5)*a) & 0xf81f07e0; t |= (((x & 0x07e0f81f)*a) >> 5) & 0x07e0f81f; return t; } +#if defined(Q_CC_RVCT) +# pragma push +# pragma arm +#endif Q_STATIC_INLINE_FUNCTION uint BYTE_MUL(uint x, uint a) { uint t = (x & 0xff00ff) * a; t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8; @@ -324,8 +328,11 @@ Q_STATIC_INLINE_FUNCTION uint BYTE_MUL(uint x, uint a) { x |= t; return x; } +#if defined(Q_CC_RVCT) +# pragma pop +#endif -static inline uint PREMUL(uint x) { +Q_STATIC_INLINE_FUNCTION uint PREMUL(uint x) { uint a = x >> 24; uint t = (x & 0xff00ff) * a; t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8; @@ -390,7 +397,7 @@ public: return qt_colorConvert<quint16, quint32>(data, 0); } - static inline quint32p fromRawData(quint32 v) + Q_STATIC_INLINE_FUNCTION quint32p fromRawData(quint32 v) { quint32p p; p.data = v; @@ -421,7 +428,7 @@ class qrgb565; class qargb8565 { public: - static inline bool hasAlpha() { return true; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return true; } inline qargb8565() {} inline qargb8565(quint32 v); @@ -438,8 +445,8 @@ public: data[1] &= 0xdf; return *this; } - static inline quint8 alpha(quint8 a) { return (a + 1) >> 3; } - static inline quint8 ialpha(quint8 a) { return 0x20 - alpha(a); } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 3; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x20 - alpha(a); } inline qargb8565 byte_mul(quint8 a) const; inline qargb8565 operator+(qargb8565 v) const; @@ -456,7 +463,7 @@ private: class qrgb565 { public: - static inline bool hasAlpha() { return false; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return false; } qrgb565(int v = 0) : data(v) {} @@ -471,8 +478,8 @@ public: inline quint8 alpha() const { return 0xff; } inline qrgb565 truncedAlpha() { return *this; } - static inline quint8 alpha(quint8 a) { return (a + 1) >> 3; } - static inline quint8 ialpha(quint8 a) { return 0x20 - alpha(a); } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 3; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x20 - alpha(a); } inline qrgb565 byte_mul(quint8 a) const; @@ -647,7 +654,7 @@ class qrgb555; class qargb8555 { public: - static inline bool hasAlpha() { return true; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return true; } qargb8555() {} inline qargb8555(quint32 v); @@ -659,8 +666,8 @@ public: inline quint8 alpha() const { return data[0]; } inline qargb8555 truncedAlpha() { data[0] &= 0xf8; return *this; } - static inline quint8 alpha(quint8 a) { return (a + 1) >> 3; } - static inline quint8 ialpha(quint8 a) { return 0x20 - alpha(a); } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 3; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x20 - alpha(a); } inline qargb8555 operator+(qargb8555 v) const; inline qargb8555 byte_mul(quint8 a) const; @@ -677,7 +684,7 @@ private: class qrgb555 { public: - static inline bool hasAlpha() { return false; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return false; } inline qrgb555(int v = 0) : data(v) {} @@ -726,8 +733,8 @@ public: inline quint8 alpha() const { return 0xff; } inline qrgb555 truncedAlpha() { return *this; } - static inline quint8 alpha(quint8 a) { return (a + 1) >> 3; } - static inline quint8 ialpha(quint8 a) { return 0x20 - alpha(a); } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 3; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x20 - alpha(a); } inline bool operator==(const qrgb555 &v) const { return v.data == data; } inline bool operator!=(const qrgb555 &v) const { return v.data != data; } @@ -875,7 +882,7 @@ class qrgb666; class qargb6666 { public: - static inline bool hasAlpha() { return true; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return true; } inline qargb6666() {} inline qargb6666(quint32 v) { *this = qargb6666(quint32p(v)); } @@ -887,8 +894,8 @@ public: inline quint8 alpha() const; inline qargb6666 truncedAlpha() { return *this; } - static inline quint8 alpha(quint8 a) { return (a + 1) >> 2; } - static inline quint8 ialpha(quint8 a) { return (255 - a + 1) >> 2; } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 2; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return (255 - a + 1) >> 2; } inline qargb6666 byte_mul(quint8 a) const; inline qargb6666 operator+(qargb6666 v) const; @@ -905,7 +912,7 @@ private: class qrgb666 { public: - static inline bool hasAlpha() { return false; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return false; } inline qrgb666() {} inline qrgb666(quint32 v); @@ -915,8 +922,8 @@ public: inline quint8 alpha() const { return 0xff; } inline qrgb666 truncedAlpha() { return *this; } - static inline quint8 alpha(quint8 a) { return (a + 1) >> 2; } - static inline quint8 ialpha(quint8 a) { return (255 - a + 1) >> 2; } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 2; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return (255 - a + 1) >> 2; } inline qrgb666 operator+(qrgb666 v) const; inline qrgb666 byte_mul(quint8 a) const; @@ -1073,7 +1080,7 @@ quint32 qargb6666::rawValue() const class qrgb888 { public: - static inline bool hasAlpha() { return false; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return false; } inline qrgb888() {} inline qrgb888(quint32 v); @@ -1082,8 +1089,8 @@ public: inline quint8 alpha() const { return 0xff; } inline qrgb888 truncedAlpha() { return *this; } - static inline quint8 alpha(quint8 a) { return a; } - static inline quint8 ialpha(quint8 a) { return 255 - a; } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return a; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 255 - a; } inline qrgb888 byte_mul(quint8 a) const; inline qrgb888 operator+(qrgb888 v) const; @@ -1262,7 +1269,7 @@ class qrgb444; class qargb4444 { public: - static inline bool hasAlpha() { return true; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return true; } inline qargb4444() {} inline qargb4444(quint32 v) { *this = qargb4444(quint32p(v)); } @@ -1276,8 +1283,8 @@ public: inline quint8 alpha() const { return ((data & 0xf000) >> 8) | ((data & 0xf000) >> 12); } inline qargb4444 truncedAlpha() { return *this; } - static inline quint8 alpha(quint8 a) { return (a + 1) >> 4; } - static inline quint8 ialpha(quint8 a) { return 0x10 - alpha(a); } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 4; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x10 - alpha(a); } inline qargb4444 byte_mul(quint8 a) const; inline bool operator==(const qargb4444 &v) const { return data == v.data; } @@ -1293,7 +1300,7 @@ private: class qrgb444 { public: - static inline bool hasAlpha() { return false; } + Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return false; } inline qrgb444() {} inline qrgb444(quint32 v); @@ -1305,8 +1312,8 @@ public: inline qrgb444 operator+(qrgb444 v) const; inline quint8 alpha() const { return 0xff; } inline qrgb444 truncedAlpha() { return *this; } - static inline quint8 alpha(quint8 a) { return (a + 1) >> 4; } - static inline quint8 ialpha(quint8 a) { return 0x10 - alpha(a); } + Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 4; } + Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x10 - alpha(a); } inline qrgb444 byte_mul(quint8 a) const; inline bool operator==(const qrgb444 &v) const { return data == v.data; } @@ -1767,7 +1774,14 @@ do { \ } \ } while (0) +#if defined(Q_CC_RVCT) +# pragma push +# pragma arm +#endif Q_STATIC_INLINE_FUNCTION int qt_div_255(int x) { return (x + (x>>8) + 0x80) >> 8; } +#if defined(Q_CC_RVCT) +# pragma pop +#endif inline ushort qConvertRgb32To16(uint c) { @@ -1810,7 +1824,7 @@ inline int qBlue565(quint16 rgb) { } #if 1 -static inline uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) { +Q_STATIC_INLINE_FUNCTION uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) { uint t = (x & 0xff00ff) * a + (y & 0xff00ff) * b; t >>= 8; t &= 0xff00ff; @@ -1821,7 +1835,11 @@ static inline uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) { return x; } -static inline uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b) { +#if defined(Q_CC_RVCT) +# pragma push +# pragma arm +#endif +Q_STATIC_INLINE_FUNCTION uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b) { uint t = (x & 0xff00ff) * a + (y & 0xff00ff) * b; t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8; t &= 0xff00ff; @@ -1832,9 +1850,12 @@ static inline uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b) { x |= t; return x; } +#if defined(Q_CC_RVCT) +# pragma pop +#endif #else // possible implementation for 64 bit -static inline uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) { +Q_STATIC_INLINE_FUNCTION uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) { ulong t = (((ulong(x)) | ((ulong(x)) << 24)) & 0x00ff00ff00ff00ff) * a; t += (((ulong(y)) | ((ulong(y)) << 24)) & 0x00ff00ff00ff00ff) * b; t >>= 8; @@ -1842,7 +1863,7 @@ static inline uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b) { return (uint(t)) | (uint(t >> 24)); } -static inline uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b) { +Q_STATIC_INLINE_FUNCTION uint INTERPOLATE_PIXEL_255(uint x, uint a, uint y, uint b) { ulong t = (((ulong(x)) | ((ulong(x)) << 24)) & 0x00ff00ff00ff00ff) * a; t += (((ulong(y)) | ((ulong(y)) << 24)) & 0x00ff00ff00ff00ff) * b; t = (t + ((t >> 8) & 0xff00ff00ff00ff) + 0x80008000800080); @@ -1857,7 +1878,7 @@ Q_STATIC_INLINE_FUNCTION uint BYTE_MUL(uint x, uint a) { return (uint(t)) | (uint(t >> 24)); } -static inline uint PREMUL(uint x) { +Q_STATIC_INLINE_FUNCTION uint PREMUL(uint x) { uint a = x >> 24; ulong t = (((ulong(x)) | ((ulong(x)) << 24)) & 0x00ff00ff00ff00ff) * a; t = (t + ((t >> 8) & 0xff00ff00ff00ff) + 0x80008000800080); diff --git a/src/gui/painting/qgraphicssystem.cpp b/src/gui/painting/qgraphicssystem.cpp index 7b1f637..7248d27 100644 --- a/src/gui/painting/qgraphicssystem.cpp +++ b/src/gui/painting/qgraphicssystem.cpp @@ -44,7 +44,7 @@ #ifdef Q_WS_X11 # include <private/qpixmap_x11_p.h> #endif -#ifdef Q_WS_WIN +#if defined(Q_WS_WIN) || defined(Q_WS_S60) # include <private/qpixmap_raster_p.h> #endif #ifdef Q_WS_MAC @@ -64,7 +64,7 @@ QPixmapData *QGraphicsSystem::createDefaultPixmapData(QPixmapData::PixelType typ #endif #if defined(Q_WS_X11) return new QX11PixmapData(type); -#elif defined(Q_WS_WIN) +#elif defined(Q_WS_WIN) || defined(Q_WS_S60) return new QRasterPixmapData(type); #elif defined(Q_WS_MAC) return new QMacPixmapData(type); diff --git a/src/gui/painting/qgraphicssystemfactory.cpp b/src/gui/painting/qgraphicssystemfactory.cpp index d6afa53..99158c8 100644 --- a/src/gui/painting/qgraphicssystemfactory.cpp +++ b/src/gui/painting/qgraphicssystemfactory.cpp @@ -64,7 +64,7 @@ QGraphicsSystem *QGraphicsSystemFactory::create(const QString& key) if (system.isEmpty()) { system = QLatin1String("opengl"); } -#elif defined (QT_GRAPHICSSYSTEM_RASTER) && !defined(Q_WS_WIN) +#elif defined (QT_GRAPHICSSYSTEM_RASTER) && !defined(Q_WS_WIN) && !defined(Q_WS_S60) if (system.isEmpty()) { system = QLatin1String("raster"); } diff --git a/src/gui/painting/qgrayraster.c b/src/gui/painting/qgrayraster.c index 73e50da..b057b5f 100644 --- a/src/gui/painting/qgrayraster.c +++ b/src/gui/painting/qgrayraster.c @@ -158,7 +158,12 @@ #include <private/qrasterdefs_p.h> #include <private/qgrayraster_p.h> +// Bug in stdlib.h, see more information from fixed_stdlib.h +#if (defined __SYMBIAN32__ && !defined __cplusplus) +#include <fixed_stdlib.h> +#else #include <stdlib.h> +#endif // defined __SYMBIAN32__ && !defined __cplusplus #include <stdio.h> /* This macro is used to indicate that a function parameter is unused. */ diff --git a/src/gui/painting/qpaintdevice_s60.cpp b/src/gui/painting/qpaintdevice_s60.cpp new file mode 100644 index 0000000..a2c4499 --- /dev/null +++ b/src/gui/painting/qpaintdevice_s60.cpp @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpaintdevice.h" +#include "qpainter.h" +#include "qwidget.h" +#include "qbitmap.h" +#include "qapplication.h" +#include <private/qapplication_p.h> +#include "qprinter.h" + +QT_BEGIN_NAMESPACE + +QPaintDevice::QPaintDevice() +{ + painters = 0; +} + + +QPaintDevice::~QPaintDevice() +{ + if (paintingActive()) + qWarning("QPaintDevice: Cannot destroy paint device that is being " + "painted. Be sure to QPainter::end() painters!"); +} + +int QPaintDevice::metric(PaintDeviceMetric) const +{ + qWarning("QPaintDevice::metrics: Device has no metric information"); + return 0; +} + + +QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 1a1c204..95b4100 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -91,6 +91,8 @@ # include <private/qfontengine_qpf_p.h> # endif # include <private/qabstractfontengine_p.h> +#elif defined(Q_WS_S60) && defined(QT_NO_FREETYPE) +# include <private/qfontengine_s60_p.h> #endif #if defined(Q_WS_WIN64) @@ -3186,7 +3188,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte ensurePen(); ensureState(); -#if defined (Q_WS_WIN) || defined(Q_WS_MAC) +#if defined (Q_WS_WIN) || defined(Q_WS_MAC) || (defined(Q_WS_S60) && defined(QT_NO_FREETYPE)) bool drawCached = true; @@ -3219,7 +3221,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte return; } -#else // Q_WS_WIN || Q_WS_MAC +#else // Q_WS_WIN || Q_WS_MAC || Q_WS_S60 && QT_NO_FREETYPE QFontEngine *fontEngine = ti.fontEngine; @@ -3239,7 +3241,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte } #endif // Q_WS_QWS -#if (defined(Q_WS_X11) || defined(Q_WS_QWS)) && !defined(QT_NO_FREETYPE) +#if (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_S60)) && !defined(QT_NO_FREETYPE) #if defined(Q_WS_QWS) && !defined(QT_NO_QWS_QPF2) if (fontEngine->type() == QFontEngine::QPF2) { @@ -4186,8 +4188,14 @@ int QCustomRasterPaintDevice::bytesPerLine() const { return (width() * depth() + 7) / 8; } -#endif // Q_WS_QWS +#elif defined(Q_WS_S60) + +void QRasterBuffer::prepareBuffer(int width, int height) +{ +} + +#endif // Q_WS_S60 /*! \class QCustomRasterPaintDevice diff --git a/src/gui/painting/qpathclipper_p.h b/src/gui/painting/qpathclipper_p.h index 981ca84..8e14eb5 100644 --- a/src/gui/painting/qpathclipper_p.h +++ b/src/gui/painting/qpathclipper_p.h @@ -160,8 +160,6 @@ public: Direction directionTo(int vertex) const; int vertex(Direction direction) const; - bool isBezier() const; - private: int m_next[2][2]; }; @@ -347,11 +345,6 @@ inline int QPathEdge::vertex(Direction direction) const return direction == Backward ? first : second; } -inline bool QPathEdge::isBezier() const -{ - return bezier >= 0; -} - inline QPathVertex::QPathVertex(const QPointF &p, int e) : edge(e) , x(p.x()) diff --git a/src/gui/painting/qregion.h b/src/gui/painting/qregion.h index c090877..f67b2b7 100644 --- a/src/gui/painting/qregion.h +++ b/src/gui/painting/qregion.h @@ -59,7 +59,7 @@ QT_MODULE(Gui) template <class T> class QVector; class QVariant; -#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_OS_WINCE) +#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) struct QRegionPrivate; #endif @@ -199,7 +199,7 @@ private: #elif defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA) mutable RgnHandle unused; // Here for binary compatability reasons. ### Qt 5 remove. #endif -#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_OS_WINCE) +#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_WS_S60) QRegionPrivate *qt_rgn; #endif }; diff --git a/src/gui/painting/qregion_s60.cpp b/src/gui/painting/qregion_s60.cpp new file mode 100644 index 0000000..4d96910 --- /dev/null +++ b/src/gui/painting/qregion_s60.cpp @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qbitmap.h" +#include "qbuffer.h" +#include "qimage.h" +#include "qpolygon.h" +#include "qregion.h" + +QT_BEGIN_NAMESPACE + +QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), 0 }; + +QT_END_NAMESPACE diff --git a/src/gui/painting/qtessellator.cpp b/src/gui/painting/qtessellator.cpp index e02f02d..a3f00e2 100644 --- a/src/gui/painting/qtessellator.cpp +++ b/src/gui/painting/qtessellator.cpp @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE #ifdef DEBUG #define QDEBUG qDebug #else -#define QDEBUG if (1); else qDebug +#define QDEBUG if (1){} else qDebug #endif static const bool emit_clever = true; @@ -703,7 +703,6 @@ struct QCoincidingEdge { } }; - static void cancelEdges(QCoincidingEdge &e1, QCoincidingEdge &e2) { if (e1.before) { diff --git a/src/gui/painting/qwindowsurface_s60.cpp b/src/gui/painting/qwindowsurface_s60.cpp new file mode 100644 index 0000000..2a20b44 --- /dev/null +++ b/src/gui/painting/qwindowsurface_s60.cpp @@ -0,0 +1,234 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qglobal.h> // for Q_WS_WIN define (non-PCH) + +#include <QtGui/qpaintdevice.h> +#include <private/qwidget_p.h> +#include "qwindowsurface_s60_p.h" +#include "qt_s60_p.h" +#include "private/qdrawhelper_p.h" + +QT_BEGIN_NAMESPACE + +struct QS60WindowSurfacePrivate +{ + QImage device; + CFbsBitmap *bitmap; + uchar* bytes; + + // Since only one CFbsBitmap is allowed to be locked at a time, this is static. + static QS60WindowSurface* lockedSurface; +}; +QS60WindowSurface* QS60WindowSurfacePrivate::lockedSurface = NULL; + +QS60WindowSurface::QS60WindowSurface(QWidget* widget) + : QWindowSurface(widget), d_ptr(new QS60WindowSurfacePrivate) +{ + d_ptr->bytes = 0; + d_ptr->bitmap = 0; + + TDisplayMode mode = S60->screenDevice()->DisplayMode(); + bool isOpaque = qt_widget_private(widget)->isOpaque; + if (mode == EColor16MA && isOpaque) + mode = EColor16MU; // Faster since 16MU -> 16MA is typically accelerated + else if (mode == EColor16MU && !isOpaque) + mode = EColor16MA; // Try for transparency anyway + + + // We create empty CFbsBitmap here -> it will be resized in setGeometry + d_ptr->bitmap = new (ELeave) CFbsBitmap; + User::LeaveIfError( d_ptr->bitmap->Create(TSize(0, 0), mode ) ); + + updatePaintDeviceOnBitmap(); + + setStaticContentsSupport(true); +} + +QS60WindowSurface::~QS60WindowSurface() +{ + // Ensure that locking and unlocking of this surface were symmetrical + Q_ASSERT(QS60WindowSurfacePrivate::lockedSurface != this); + + delete d_ptr->bitmap; + delete d_ptr; +} + +void QS60WindowSurface::beginPaint(const QRegion &rgn) +{ + if(!d_ptr->bitmap) + return; + + Q_ASSERT(!QS60WindowSurfacePrivate::lockedSurface); + QS60WindowSurfacePrivate::lockedSurface = this; + lockBitmapHeap(); + + if (!qt_widget_private(window())->isOpaque) { + QRgb *data = reinterpret_cast<QRgb *>(d_ptr->device.bits()); + const int row_stride = d_ptr->device.bytesPerLine() / 4; + + const QVector<QRect> rects = rgn.rects(); + for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) { + const int x_start = it->x(); + const int width = it->width(); + + const int y_start = it->y(); + const int height = it->height(); + + QRgb *row = data + row_stride * y_start; + for (int y = 0; y < height; ++y) { + qt_memfill(row + x_start, 0U, width); + row += row_stride; + } + } + } +} + +void QS60WindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &) +{ + const QVector<QRect> subRects = region.rects(); + for (int i = 0; i < subRects.count(); ++i) { + TRect tr = qt_QRect2TRect(subRects[i]); + widget->winId()->DrawNow(tr); + } +} + +bool QS60WindowSurface::scroll(const QRegion &area, int dx, int dy) +{ + QRect rect = area.boundingRect(); + + if (dx == 0 && dy == 0) + return false; + + if (d_ptr->device.isNull()) + return false; + + CFbsBitmapDevice *bitmapDevice = CFbsBitmapDevice::NewL(d_ptr->bitmap); + CBitmapContext *bitmapContext; + TInt err = bitmapDevice->CreateBitmapContext(bitmapContext); + if (err != KErrNone) { + CBase::Delete(bitmapDevice); + return false; + } + bitmapContext->CopyRect(TPoint(dx, dy), qt_QRect2TRect(rect)); + CBase::Delete(bitmapContext); + CBase::Delete(bitmapDevice); + return true; +} + +void QS60WindowSurface::endPaint(const QRegion &rgn) +{ + if(!d_ptr->bitmap) + return; + + Q_ASSERT(QS60WindowSurfacePrivate::lockedSurface); + unlockBitmapHeap(); + QS60WindowSurfacePrivate::lockedSurface = NULL; +} + +QPaintDevice* QS60WindowSurface::paintDevice() +{ + return &d_ptr->device; +} + +void QS60WindowSurface::setGeometry(const QRect& rect) +{ + if (rect == geometry()) + return; + + QWindowSurface::setGeometry(rect); + + TRect nativeRect(qt_QRect2TRect(rect)); + User::LeaveIfError(d_ptr->bitmap->Resize(nativeRect.Size())); + + if (!rect.isNull()) + updatePaintDeviceOnBitmap(); +} + +void QS60WindowSurface::lockBitmapHeap() +{ + if (!QS60WindowSurfacePrivate::lockedSurface) + return; + + // Get some local variables to make later code lines more clear to read + CFbsBitmap*& bitmap = QS60WindowSurfacePrivate::lockedSurface->d_ptr->bitmap; + QImage& device = QS60WindowSurfacePrivate::lockedSurface->d_ptr->device; + uchar*& bytes = QS60WindowSurfacePrivate::lockedSurface->d_ptr->bytes; + + bitmap->LockHeap(); + uchar *newBytes = (uchar*)bitmap->DataAddress(); + if (newBytes != bytes) { + bytes = newBytes; + + // Get some values for QImage creation + TDisplayMode mode = bitmap->DisplayMode(); + if (mode == EColor16MA + && qt_widget_private(QS60WindowSurfacePrivate::lockedSurface->window())->isOpaque) + mode = EColor16MU; + QImage::Format format = qt_TDisplayMode2Format( mode ); + TSize bitmapSize = bitmap->SizeInPixels(); + int bytesPerLine = CFbsBitmap::ScanLineLength( bitmapSize.iWidth, mode); + + device = QImage( bytes, bitmapSize.iWidth, bitmapSize.iHeight, bytesPerLine, format ); + } +} + +void QS60WindowSurface::unlockBitmapHeap() +{ + if (!QS60WindowSurfacePrivate::lockedSurface) + return; + + QS60WindowSurfacePrivate::lockedSurface->d_ptr->bitmap->UnlockHeap(); +} + +void QS60WindowSurface::updatePaintDeviceOnBitmap() +{ + // This forces the actual device to be updated based on CFbsBitmap + beginPaint(QRegion()); + endPaint(QRegion()); +} + +CFbsBitmap *QS60WindowSurface::symbianBitmap() const +{ + return d_ptr->bitmap; +} + +QT_END_NAMESPACE diff --git a/src/gui/painting/qwindowsurface_s60_p.h b/src/gui/painting/qwindowsurface_s60_p.h new file mode 100644 index 0000000..40a866d --- /dev/null +++ b/src/gui/painting/qwindowsurface_s60_p.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSURFACE_S60_P_H +#define QWINDOWSURFACE_S60_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <qglobal.h> +#include "private/qwindowsurface_p.h" + +class CFbsBitmap; + +QT_BEGIN_NAMESPACE + +struct QS60WindowSurfacePrivate; + +class QS60WindowSurface : public QWindowSurface +{ +public: + QS60WindowSurface(QWidget *widget); + ~QS60WindowSurface(); + + QPaintDevice *paintDevice(); + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + bool scroll(const QRegion &area, int dx, int dy); + + void beginPaint(const QRegion &); + void endPaint(const QRegion &); + + void setGeometry(const QRect &rect); + + static void lockBitmapHeap(); + static void unlockBitmapHeap(); + + CFbsBitmap *symbianBitmap() const; + +private: + void updatePaintDeviceOnBitmap(); + +private: + QS60WindowSurfacePrivate* d_ptr; + +}; + +QT_END_NAMESPACE + +#endif // QWINDOWSURFACE_S60_P_H diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp new file mode 100644 index 0000000..6d24d54 --- /dev/null +++ b/src/gui/styles/qs60style.cpp @@ -0,0 +1,2882 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qs60style_p.h" + +#include "qapplication.h" +#include "qpainter.h" +#include "qstyleoption.h" +#include "qresizeevent" +#include "qpixmapcache" + +#include "qcalendarwidget.h" +#include "qdial.h" +#include "qdialog.h" +#include "qgroupbox.h" +#include "qheaderview.h" +#include "qlist.h" +#include "qlistwidget.h" +#include "qlistview.h" +#include "qmenu.h" +#include "qmenubar.h" +#include "qpushbutton.h" +#include "qscrollarea.h" +#include "qscrollbar.h" +#include "qtabbar.h" +#include "qtablewidget.h" +#include "qtableview.h" +#include "qtextedit.h" +#include "qtoolbar.h" +#include "qtoolbutton.h" +#include "qtreeview.h" + +#include "private/qtoolbarextension_p.h" +#include "private/qcombobox_p.h" +#include "private/qwidget_p.h" +#include "private/qapplication_p.h" + +#if !defined(QT_NO_STYLE_S60) || defined(QT_PLUGIN) + +QT_BEGIN_NAMESPACE + +// from text/qfont.cpp +extern Q_GUI_EXPORT int qt_defaultDpiY(); + +const QS60StylePrivate::SkinElementFlags QS60StylePrivate::KDefaultSkinElementFlags = + SkinElementFlags(SF_PointNorth | SF_StateEnabled); + +static const QByteArray propertyKeyLayouts = "layouts"; +static const QByteArray propertyKeyCurrentlayout = "currentlayout"; + +const layoutHeader QS60StylePrivate::m_layoutHeaders[] = { +// *** generated layout data *** +{240,320,1,14,true,QLatin1String("QVGA Landscape Mirrored")}, +{240,320,1,14,false,QLatin1String("QVGA Landscape")}, +{320,240,1,14,true,QLatin1String("QVGA Portrait Mirrored")}, +{320,240,1,14,false,QLatin1String("QVGA Portrait")}, +{360,640,1,14,true,QLatin1String("NHD Landscape Mirrored")}, +{360,640,1,14,false,QLatin1String("NHD Landscape")}, +{640,360,1,14,true,QLatin1String("NHD Portrait Mirrored")}, +{640,360,1,14,false,QLatin1String("NHD Portrait")}, +{352,800,1,12,true,QLatin1String("E90 Landscape Mirrored")}, +{352,800,1,12,false,QLatin1String("E90 Landscape")} +// *** End of generated data *** +}; +const int QS60StylePrivate::m_numberOfLayouts = + (int)sizeof(QS60StylePrivate::m_layoutHeaders)/sizeof(QS60StylePrivate::m_layoutHeaders[0]); + +const short QS60StylePrivate::data[][MAX_PIXELMETRICS] = { +// *** generated pixel metrics *** +{5,0,-909,0,0,1,0,0,-1,8,15,22,15,15,7,198,-909,-909,-909,19,15,2,0,0,21,-909,21,-909,4,4,1,-909,-909,0,2,0,0,13,23,17,17,21,21,2,115,21,0,-909,-909,-909,-909,0,0,15,1,-909,0,0,-909,15,-909,-909,-909,-909,32,21,51,27,51,4,4,5,10,15,-909,5,58,12,5,0,7,4,4,9,4,4,-909,1,-909,-909,-909,-909,4,4,3,1}, +{5,0,-909,0,0,1,0,0,-1,8,15,22,15,15,7,198,-909,-909,-909,19,15,2,0,0,21,-909,21,-909,4,4,1,-909,-909,0,2,0,0,13,23,17,17,21,21,2,115,21,0,-909,-909,-909,-909,0,0,15,1,-909,0,0,-909,15,-909,-909,-909,-909,32,21,51,27,51,4,4,5,10,15,-909,5,58,12,5,0,4,4,7,9,4,4,-909,1,-909,-909,-909,-909,4,4,3,1}, +{5,0,-909,0,0,1,0,0,-1,8,14,22,15,15,7,164,-909,-909,-909,19,15,2,0,0,21,-909,27,-909,4,4,1,-909,-909,0,7,6,0,13,23,17,17,21,21,7,115,21,0,-909,-909,-909,-909,0,0,15,1,-909,0,0,-909,15,-909,-909,-909,-909,32,21,65,27,65,4,4,5,10,15,-909,5,58,13,5,0,7,4,4,9,4,4,-909,1,-909,-909,-909,-909,4,4,3,1}, +{5,0,-909,0,0,1,0,0,-1,8,14,22,15,15,7,164,-909,-909,-909,19,15,2,0,0,21,-909,27,-909,4,4,1,-909,-909,0,7,6,0,13,23,17,17,21,21,7,115,21,0,-909,-909,-909,-909,0,0,15,1,-909,0,0,-909,15,-909,-909,-909,-909,32,21,65,27,65,4,4,5,10,15,-909,5,58,13,5,0,4,4,7,9,4,4,-909,1,-909,-909,-909,-909,4,4,3,1}, +{7,0,-909,0,0,2,0,0,-1,20,53,28,19,19,9,258,-909,-909,-909,29,19,26,0,0,32,-909,72,-909,5,5,2,-909,-909,0,7,21,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,25,2,-909,0,0,-909,25,-909,-909,-909,-909,87,27,77,35,77,5,5,6,8,19,-909,7,74,19,7,0,8,5,5,12,5,5,-909,2,-909,-909,-909,-909,7,7,3,1}, +{7,0,-909,0,0,2,0,0,-1,20,53,28,19,19,9,258,-909,-909,-909,29,19,26,0,0,32,-909,72,-909,5,5,2,-909,-909,0,7,21,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,25,2,-909,0,0,-909,25,-909,-909,-909,-909,87,27,77,35,77,5,5,6,8,19,-909,7,74,19,7,0,5,5,8,12,5,5,-909,2,-909,-909,-909,-909,7,7,3,1}, +{7,0,-909,0,0,2,0,0,-1,20,52,28,19,19,9,258,-909,-909,-909,29,19,6,0,0,32,-909,60,-909,5,5,2,-909,-909,0,7,32,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,26,2,-909,0,0,-909,26,-909,-909,-909,-909,87,27,98,35,98,5,5,6,8,19,-909,7,74,22,7,0,8,5,5,12,5,5,-909,2,-909,-909,-909,-909,7,7,3,1}, +{7,0,-909,0,0,2,0,0,-1,20,52,28,19,19,9,258,-909,-909,-909,29,19,6,0,0,32,-909,60,-909,5,5,2,-909,-909,0,7,32,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,26,2,-909,0,0,-909,26,-909,-909,-909,-909,87,27,98,35,98,5,5,6,8,19,-909,7,74,22,7,0,5,5,8,12,5,5,-909,2,-909,-909,-909,-909,7,7,3,1}, +{7,0,-909,0,0,2,0,0,-1,10,20,27,18,18,9,301,-909,-909,-909,29,18,5,0,0,35,-909,32,-909,5,5,2,-909,-909,0,2,8,0,16,28,21,21,26,26,2,170,26,0,-909,-909,-909,-909,0,0,21,5,-909,0,0,-909,-909,-909,-909,-909,-909,54,26,265,34,265,5,5,6,3,18,-909,7,72,19,7,0,8,6,5,11,6,5,-909,2,-909,-909,-909,-909,5,5,3,1}, +{7,0,-909,0,0,2,0,0,-1,10,20,27,18,18,9,301,-909,-909,-909,29,18,5,0,0,35,-909,32,-909,5,5,2,-909,-909,0,2,8,0,16,28,21,21,26,26,2,170,26,0,-909,-909,-909,-909,0,0,21,6,-909,0,0,-909,-909,-909,-909,-909,-909,54,26,265,34,265,5,5,6,3,18,-909,7,72,19,7,0,5,6,8,11,6,5,-909,2,-909,-909,-909,-909,5,5,3,1} +// *** End of generated data *** +}; + +const short *QS60StylePrivate::m_pmPointer = QS60StylePrivate::data[0]; + +// theme background texture +QPixmap *QS60StylePrivate::m_background = 0; + +// theme palette +QPalette *QS60StylePrivate::m_themePalette = 0; + +const struct QS60StylePrivate::frameElementCenter QS60StylePrivate::m_frameElementsData[] = { + {SE_ButtonNormal, QS60StyleEnums::SP_QsnFrButtonTbCenter}, + {SE_ButtonPressed, QS60StyleEnums::SP_QsnFrButtonTbCenterPressed}, + {SE_FrameLineEdit, QS60StyleEnums::SP_QsnFrInputCenter}, + {SE_ListHighlight, QS60StyleEnums::SP_QsnFrListCenter}, + {SE_OptionsMenu, QS60StyleEnums::SP_QsnFrPopupCenter}, + {SE_SettingsList, QS60StyleEnums::SP_QsnFrSetOptCenter}, + {SE_TableItem, QS60StyleEnums::SP_QsnFrCaleCenter}, + {SE_TableHeaderItem, QS60StyleEnums::SP_QsnFrCaleHeadingCenter}, + {SE_ToolTip, QS60StyleEnums::SP_QsnFrPopupPreviewCenter}, + {SE_ToolBar, QS60StyleEnums::SP_QsnFrPopupSubCenter}, + {SE_ToolBarButton, QS60StyleEnums::SP_QsnFrSctrlButtonCenter}, + {SE_ToolBarButtonPressed, QS60StyleEnums::SP_QsnFrSctrlButtonCenterPressed}, + {SE_PanelBackground, QS60StyleEnums::SP_QsnFrSetOptCenter}, + {SE_ButtonInactive, QS60StyleEnums::SP_QsnFrButtonCenterInactive}, + {SE_Editor, QS60StyleEnums::SP_QsnFrNotepadCenter}, +}; + +static const int frameElementsCount = + int(sizeof(QS60StylePrivate::m_frameElementsData)/sizeof(QS60StylePrivate::m_frameElementsData[0])); + +const int KNotFound = -909; +const double KTabFontMul = 0.72; + +QS60StylePrivate::~QS60StylePrivate() +{ + clearCaches(); //deletes also background image + deleteThemePalette(); +} + +void QS60StylePrivate::drawSkinElement(SkinElements element, QPainter *painter, + const QRect &rect, SkinElementFlags flags) +{ + switch (element) { + case SE_ButtonNormal: + drawFrame(SF_ButtonNormal, painter, rect, flags | SF_PointNorth); + break; + case SE_ButtonPressed: + drawFrame(SF_ButtonPressed, painter, rect, flags | SF_PointNorth); + break; + case SE_FrameLineEdit: + drawFrame(SF_FrameLineEdit, painter, rect, flags | SF_PointNorth); + break; + case SE_ProgressBarGrooveHorizontal: + drawRow(QS60StyleEnums::SP_QgnGrafBarFrameSideL, QS60StyleEnums::SP_QgnGrafBarFrameCenter, + QS60StyleEnums::SP_QgnGrafBarFrameSideR, Qt::Horizontal, painter, rect, flags | SF_PointNorth); + break; + case SE_ProgressBarGrooveVertical: + drawRow(QS60StyleEnums::SP_QgnGrafBarFrameSideL, QS60StyleEnums::SP_QgnGrafBarFrameCenter, + QS60StyleEnums::SP_QgnGrafBarFrameSideR, Qt::Vertical, painter, rect, flags | SF_PointEast); + break; + case SE_ProgressBarIndicatorHorizontal: + drawPart(QS60StyleEnums::SP_QgnGrafBarProgress, painter, rect, flags | SF_PointNorth); + break; + case SE_ProgressBarIndicatorVertical: + drawPart(QS60StyleEnums::SP_QgnGrafBarProgress, painter, rect, flags | SF_PointWest); + break; + case SE_ScrollBarGrooveHorizontal: + drawRow(QS60StyleEnums::SP_QsnCpScrollBgBottom, QS60StyleEnums::SP_QsnCpScrollBgMiddle, + QS60StyleEnums::SP_QsnCpScrollBgTop, Qt::Horizontal, painter, rect, flags | SF_PointEast); + break; + case SE_ScrollBarGrooveVertical: + drawRow(QS60StyleEnums::SP_QsnCpScrollBgTop, QS60StyleEnums::SP_QsnCpScrollBgMiddle, + QS60StyleEnums::SP_QsnCpScrollBgBottom, Qt::Vertical, painter, rect, flags | SF_PointNorth); + break; + case SE_ScrollBarHandleHorizontal: + drawRow(QS60StyleEnums::SP_QsnCpScrollHandleBottom, QS60StyleEnums::SP_QsnCpScrollHandleMiddle, + QS60StyleEnums::SP_QsnCpScrollHandleTop, Qt::Horizontal, painter, rect, flags | SF_PointEast); + break; + case SE_ScrollBarHandleVertical: + drawRow(QS60StyleEnums::SP_QsnCpScrollHandleTop, QS60StyleEnums::SP_QsnCpScrollHandleMiddle, + QS60StyleEnums::SP_QsnCpScrollHandleBottom, Qt::Vertical, painter, rect, flags | SF_PointNorth); + break; + case SE_SliderHandleHorizontal: + drawPart(QS60StyleEnums::SP_QgnIndiSliderEdit, painter, rect, flags | SF_PointNorth); + break; + case SE_SliderHandleVertical: + drawPart(QS60StyleEnums::SP_QgnIndiSliderEdit, painter, rect, flags | SF_PointEast); + break; + case SE_TabBarTabEastActive: + drawRow(QS60StyleEnums::SP_QgnGrafTabActiveL, QS60StyleEnums::SP_QgnGrafTabActiveM, + QS60StyleEnums::SP_QgnGrafTabActiveR, Qt::Vertical, painter, rect, flags | SF_PointEast); + break; + case SE_TabBarTabEastInactive: + drawRow(QS60StyleEnums::SP_QgnGrafTabPassiveL, QS60StyleEnums::SP_QgnGrafTabPassiveM, + QS60StyleEnums::SP_QgnGrafTabPassiveR, Qt::Vertical, painter, rect, flags | SF_PointEast); + break; + case SE_TabBarTabNorthActive: + drawRow(QS60StyleEnums::SP_QgnGrafTabActiveL, QS60StyleEnums::SP_QgnGrafTabActiveM, + QS60StyleEnums::SP_QgnGrafTabActiveR, Qt::Horizontal, painter, rect, flags | SF_PointNorth); + break; + case SE_TabBarTabNorthInactive: + drawRow(QS60StyleEnums::SP_QgnGrafTabPassiveL, QS60StyleEnums::SP_QgnGrafTabPassiveM, + QS60StyleEnums::SP_QgnGrafTabPassiveR, Qt::Horizontal, painter, rect, flags | SF_PointNorth); + break; + case SE_TabBarTabSouthActive: + drawRow(QS60StyleEnums::SP_QgnGrafTabActiveR, QS60StyleEnums::SP_QgnGrafTabActiveM, + QS60StyleEnums::SP_QgnGrafTabActiveL, Qt::Horizontal, painter, rect, flags | SF_PointSouth); + break; + case SE_TabBarTabSouthInactive: + drawRow(QS60StyleEnums::SP_QgnGrafTabPassiveR, QS60StyleEnums::SP_QgnGrafTabPassiveM, + QS60StyleEnums::SP_QgnGrafTabPassiveL, Qt::Horizontal, painter, rect, flags | SF_PointSouth); + break; + case SE_TabBarTabWestActive: + drawRow(QS60StyleEnums::SP_QgnGrafTabActiveR, QS60StyleEnums::SP_QgnGrafTabActiveM, + QS60StyleEnums::SP_QgnGrafTabActiveL, Qt::Vertical, painter, rect, flags | SF_PointWest); + break; + case SE_TabBarTabWestInactive: + drawRow(QS60StyleEnums::SP_QgnGrafTabPassiveR, QS60StyleEnums::SP_QgnGrafTabPassiveM, + QS60StyleEnums::SP_QgnGrafTabPassiveL, Qt::Vertical, painter, rect, flags | SF_PointWest); + break; + case SE_ListHighlight: + drawFrame(SF_ListHighlight, painter, rect, flags | SF_PointNorth); + break; + case SE_OptionsMenu: + drawFrame(SF_OptionsMenu, painter, rect, flags | SF_PointNorth); + break; + case SE_SettingsList: + drawFrame(SF_SettingsList, painter, rect, flags | SF_PointNorth); + break; + case SE_TableItem: + drawFrame(SF_TableItem, painter, rect, flags | SF_PointNorth); + break; + case SE_TableHeaderItem: + drawFrame(SF_TableHeaderItem, painter, rect, flags | SF_PointNorth); + break; + case SE_ToolTip: + drawFrame(SF_ToolTip, painter, rect, flags | SF_PointNorth); + break; + case SE_ToolBar: + drawFrame(SF_ToolBar, painter, rect, flags | SF_PointNorth); + break; + case SE_ToolBarButton: + drawFrame(SF_ToolBarButton, painter, rect, flags | SF_PointNorth); + break; + case SE_ToolBarButtonPressed: + drawFrame(SF_ToolBarButtonPressed, painter, rect, flags | SF_PointNorth); + break; + case SE_PanelBackground: + drawFrame(SF_PanelBackground, painter, rect, flags | SF_PointNorth); + break; + case SE_ScrollBarHandlePressedHorizontal: + drawRow(QS60StyleEnums::SP_QsnCpScrollHandleBottomPressed, QS60StyleEnums::SP_QsnCpScrollHandleMiddlePressed, + QS60StyleEnums::SP_QsnCpScrollHandleTopPressed, Qt::Horizontal, painter, rect, flags | SF_PointEast); + break; + case SE_ScrollBarHandlePressedVertical: + drawRow(QS60StyleEnums::SP_QsnCpScrollHandleTopPressed, QS60StyleEnums::SP_QsnCpScrollHandleMiddlePressed, + QS60StyleEnums::SP_QsnCpScrollHandleBottomPressed, Qt::Vertical, painter, rect, flags | SF_PointNorth); + break; + case SE_ButtonInactive: + drawFrame(SF_ButtonInactive, painter, rect, flags | SF_PointNorth); + break; + case SE_Editor: + drawFrame(SF_Editor, painter, rect, flags | SF_PointNorth); + break; + default: + break; + } +} + +void QS60StylePrivate::drawSkinPart(QS60StyleEnums::SkinParts part, + QPainter *painter, const QRect &rect, SkinElementFlags flags) +{ + drawPart(part, painter, rect, flags); +} + +short QS60StylePrivate::pixelMetric(int metric) +{ + Q_ASSERT(metric < MAX_PIXELMETRICS); + const short returnValue = m_pmPointer[metric]; + return returnValue; +} + +void QS60StylePrivate::setStyleProperty(const char *name, const QVariant &value) +{ + if (name == propertyKeyCurrentlayout) { + static const QStringList layouts = styleProperty(propertyKeyLayouts).toStringList(); + const QString layout = value.toString(); + Q_ASSERT(layouts.contains(layout)); + const int layoutIndex = layouts.indexOf(layout); + setCurrentLayout(layoutIndex); + QApplication::setLayoutDirection(m_layoutHeaders[layoutIndex].mirroring ? Qt::RightToLeft : Qt::LeftToRight); + clearCaches(); + refreshUI(); + } +} + +QVariant QS60StylePrivate::styleProperty(const char *name) const +{ + if (name == propertyKeyLayouts) { + static QStringList layouts; + if (layouts.isEmpty()) + for (int i = 0; i < QS60StylePrivate::m_numberOfLayouts; i++) + layouts.append(QS60StylePrivate::m_layoutHeaders[i].layoutName); + return layouts; + } + return QVariant(); +} + +QColor QS60StylePrivate::stateColor(const QColor &color, const QStyleOption *option) +{ + QColor retColor (color); + if (option && !(option->state & QStyle::State_Enabled)) { + QColor hsvColor = retColor.toHsv(); + int colorSat = hsvColor.saturation(); + int colorVal = hsvColor.value(); + colorSat = (colorSat!=0) ? (colorSat>>1) : 128; + colorVal = (colorVal!=0) ? (colorVal>>1) : 128; + hsvColor.setHsv(hsvColor.hue(), colorSat, colorVal); + retColor = hsvColor.toRgb(); + } + return retColor; +} + +QColor QS60StylePrivate::lighterColor(const QColor &baseColor) +{ + QColor result(baseColor); + bool modifyColor = false; + if (result.saturation() == 0) { + result.setHsv(result.hue(), 128, result.value()); + modifyColor = true; + } + if (result.value() == 0) { + result.setHsv(result.hue(), result.saturation(), 128); + modifyColor = true; + } + if (modifyColor) + result = result.lighter(175); + else + result = result.lighter(225); + return result; +} + +bool QS60StylePrivate::drawsOwnThemeBackground(const QWidget *widget) +{ + return qobject_cast<const QDialog *> (widget); +} + +QFont QS60StylePrivate::s60Font( + QS60StyleEnums::FontCategories fontCategory, int pointSize) const +{ + QFont result; + int actualPointSize = pointSize; + if (actualPointSize <= 0) { + const QFont appFont = QApplication::font(); + actualPointSize = appFont.pointSize(); + if (actualPointSize <= 0) + actualPointSize = appFont.pixelSize() * 72 / qt_defaultDpiY(); + } + Q_ASSERT(actualPointSize > 0); + const QPair<QS60StyleEnums::FontCategories, int> key(fontCategory, actualPointSize); + if (!m_mappedFontsCache.contains(key)) { + result = s60Font_specific(fontCategory, actualPointSize); + m_mappedFontsCache.insert(key, result); + } else { + result = m_mappedFontsCache.value(key); + if (result.pointSize() != actualPointSize) + result.setPointSize(actualPointSize); + } + return result; +} + +void QS60StylePrivate::clearCaches(QS60StylePrivate::CacheClearReason reason) +{ + switch(reason){ + case CC_LayoutChange: + // when layout changes, the colors remain in cache, but graphics and fonts can change + m_mappedFontsCache.clear(); + deleteBackground(); + QPixmapCache::clear(); + break; + case CC_ThemeChange: + m_colorCache.clear(); + QPixmapCache::clear(); + deleteBackground(); + break; + case CC_UndefinedChange: + default: + m_colorCache.clear(); + m_mappedFontsCache.clear(); + QPixmapCache::clear(); + deleteBackground(); + break; + } +} + +// Since S60Style has 'button' and 'tooltip' as a graphic, we don't have any native color which to use +// for QPalette::Button and QPalette::ToolTipBase. Therefore S60Style needs to guesstimate +// palette colors by calculating average rgb values for button pixels. +// Returns Qt::black if there is an issue with the graphics (image is NULL, or no bits() found). +QColor QS60StylePrivate::colorFromFrameGraphics(QS60StylePrivate::SkinFrameElements frame) const +{ + const bool cachedColorExists = m_colorCache.contains(frame); + if (!cachedColorExists) { + const int frameCornerWidth = QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerWidth); + const int frameCornerHeight = QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerHeight); + Q_ASSERT(2*frameCornerWidth<32); + Q_ASSERT(2*frameCornerHeight<32); + + const QImage frameImage = QS60StylePrivate::frame(frame, QSize(32,32)).toImage(); + if (frameImage.isNull()) + return Qt::black; + + const QRgb *pixelRgb = (const QRgb*)frameImage.bits(); + const int pixels = frameImage.numBytes()/sizeof(QRgb); + const int bytesPerLine = frameImage.bytesPerLine(); + Q_ASSERT(bytesPerLine); + + int estimatedRed = 0; + int estimatedGreen = 0; + int estimatedBlue = 0; + + int skips = 0; + int estimations = 0; + + const int topBorderLastPixel = frameCornerHeight*frameImage.width()-1; + const int bottomBorderFirstPixel = frameImage.width()*frameImage.height()-frameCornerHeight*frameImage.width()-1; + const int rightBorderFirstPixel = frameImage.width()-frameCornerWidth; + const int leftBorderLastPixel = frameCornerWidth; + + while ((skips + estimations) < pixels) { + if ((skips+estimations) > topBorderLastPixel && + (skips+estimations) < bottomBorderFirstPixel) { + for (int rowIndex = 0; rowIndex < frameImage.width(); rowIndex++) { + if (rowIndex > leftBorderLastPixel && + rowIndex < rightBorderFirstPixel) { + estimatedRed += qRed(*pixelRgb); + estimatedGreen += qGreen(*pixelRgb); + estimatedBlue += qBlue(*pixelRgb); + } + pixelRgb++; + estimations++; + } + } else { + pixelRgb++; + skips++; + } + } + QColor frameColor(estimatedRed/estimations, estimatedGreen/estimations, estimatedBlue/estimations); + m_colorCache.insert(frame, frameColor); + return !estimations ? Qt::black : frameColor; + } else { + return m_colorCache.value(frame); + } + +} + +void QS60StylePrivate::setThemePalette(QApplication *app) const +{ + Q_UNUSED(app) + QPalette widgetPalette = QPalette(Qt::white); + setThemePalette(&widgetPalette); + QApplication::setPalette(widgetPalette); +} + +void QS60StylePrivate::setThemePalette(QStyleOption *option) const +{ + setThemePalette(&option->palette); +} + +QPalette* QS60StylePrivate::themePalette() +{ + return m_themePalette; +} + +void QS60StylePrivate::setBackgroundTexture(QApplication *app) const +{ + Q_UNUSED(app) + QPalette applicationPalette = QApplication::palette(); + applicationPalette.setBrush(QPalette::Window, QS60StylePrivate::backgroundTexture()); + QApplication::setPalette(applicationPalette); +} + +void QS60StylePrivate::deleteBackground() +{ + if (QS60StylePrivate::m_background) { + delete QS60StylePrivate::m_background; + QS60StylePrivate::m_background = 0; + } +} + +int QS60StylePrivate::focusRectPenWidth() +{ + return pixelMetric(QS60Style::PM_DefaultFrameWidth); +} + +void QS60StylePrivate::setCurrentLayout(int index) +{ + m_pmPointer = data[index]; +} + +void QS60StylePrivate::drawPart(QS60StyleEnums::SkinParts skinPart, + QPainter *painter, const QRect &rect, SkinElementFlags flags) +{ + static const bool doCache = +#if defined(Q_WS_S60) + // Freezes on 3.1. Anyways, caching is only really needed on touch UI + !(QSysInfo::s60Version() == QSysInfo::SV_S60_3_1 || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2); +#else + true; +#endif + const QPixmap skinPartPixMap((doCache ? cachedPart : part)(skinPart, rect.size(), flags)); + if (!skinPartPixMap.isNull()) + painter->drawPixmap(rect.topLeft(), skinPartPixMap); +} + +void QS60StylePrivate::drawFrame(SkinFrameElements frameElement, QPainter *painter, const QRect &rect, SkinElementFlags flags) +{ + static const bool doCache = +#if defined(Q_WS_S60) + // Freezes on 3.1. Anyways, caching is only really needed on touch UI + !(QSysInfo::s60Version() == QSysInfo::SV_S60_3_1 || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2); +#else + true; +#endif + const QPixmap frameElementPixMap((doCache ? cachedFrame : frame)(frameElement, rect.size(), flags)); + if (!frameElementPixMap.isNull()) + painter->drawPixmap(rect.topLeft(), frameElementPixMap); +} + +void QS60StylePrivate::drawRow(QS60StyleEnums::SkinParts start, + QS60StyleEnums::SkinParts middle, QS60StyleEnums::SkinParts end, + Qt::Orientation orientation, QPainter *painter, const QRect &rect, + SkinElementFlags flags) +{ + QSize startEndSize(partSize(start, flags)); + startEndSize.scale(rect.size(), Qt::KeepAspectRatio); + + QRect startRect = QRect(rect.topLeft(), startEndSize); + QRect middleRect = rect; + QRect endRect; + + if (orientation == Qt::Horizontal) { + startRect.setWidth(qMin(rect.width() >>1 - 1, startRect.width())); + endRect = startRect.translated(rect.width() - startRect.width(), 0); + middleRect.adjust(startRect.width(), 0, -startRect.width(), 0); + if (startRect.bottomRight().x() > endRect.topLeft().x()) { + const int overlap = (startRect.bottomRight().x() - endRect.topLeft().x())>>1; + startRect.setWidth(startRect.width()-overlap); + endRect.adjust(overlap,0,0,0); + } + } else { + startRect.setHeight(qMin(rect.height() >>1 - 1, startRect.height())); + endRect = startRect.translated(0, rect.height() - startRect.height()); + middleRect.adjust(0, startRect.height(), 0, -startRect.height()); + if (startRect.topRight().y() > endRect.bottomLeft().y()) { + const int overlap = (startRect.topRight().y() - endRect.bottomLeft().y())>>1; + startRect.setHeight(startRect.height()-overlap); + endRect.adjust(0,overlap,0,0); + } + } + +#if 0 + painter->save(); + painter->setOpacity(.3); + painter->fillRect(startRect, Qt::red); + painter->fillRect(middleRect, Qt::green); + painter->fillRect(endRect, Qt::blue); + painter->restore(); +#else + drawPart(start, painter, startRect, flags); + if (middleRect.isValid()) + drawPart(middle, painter, middleRect, flags); + drawPart(end, painter, endRect, flags); +#endif +} + +QPixmap QS60StylePrivate::cachedPart(QS60StyleEnums::SkinParts part, + const QSize &size, SkinElementFlags flags) +{ + QPixmap result; + const QString cacheKey = + QString::fromLatin1("S60Style: SkinParts=%1 QSize=%2|%3 SkinPartFlags=%4") + .arg((int)part).arg(size.width()).arg(size.height()).arg((int)flags); + if (!QPixmapCache::find(cacheKey, result)) { + result = QS60StylePrivate::part(part, size, flags); + QPixmapCache::insert(cacheKey, result); + } + return result; +} + +QPixmap QS60StylePrivate::cachedFrame(SkinFrameElements frame, const QSize &size, SkinElementFlags flags) +{ + QPixmap result; + const QString cacheKey = + QString::fromLatin1("S60Style: SkinFrameElements=%1 QSize=%2|%3 SkinElementFlags=%4") + .arg((int)frame).arg(size.width()).arg(size.height()).arg((int)flags); + if (!QPixmapCache::find(cacheKey, result)) { + result = QS60StylePrivate::frame(frame, size, flags); + QPixmapCache::insert(cacheKey, result); + } + return result; +} + +void QS60StylePrivate::refreshUI() +{ + QList<QWidget *> widgets = QApplication::allWidgets(); + + for (int i = 0; i < widgets.size(); ++i) { + QWidget *widget = widgets.at(i); + if (widget == 0) + continue; + + if (widget->style()) { + widget->style()->polish(widget); + QEvent event(QEvent::StyleChange); + qApp->sendEvent(widget, &event); + } + widget->update(); + widget->updateGeometry(); + } +} + +void QS60StylePrivate::setFont(QWidget *widget) const +{ + QS60StyleEnums::FontCategories fontCategory = QS60StyleEnums::FC_Undefined; + if (!widget) + return; + if (qobject_cast<QPushButton *>(widget)){ + fontCategory = QS60StyleEnums::FC_Primary; + } else if (qobject_cast<QToolButton *>(widget)){ + fontCategory = QS60StyleEnums::FC_Primary; + } else if (qobject_cast<QHeaderView *>(widget)){ + fontCategory = QS60StyleEnums::FC_Secondary; + } else if (qobject_cast<QGroupBox *>(widget)){ + fontCategory = QS60StyleEnums::FC_Title; + } + if (fontCategory != QS60StyleEnums::FC_Undefined) { + const QFont suggestedFont = + s60Font(fontCategory, widget->font().pointSizeF()); + widget->setFont(suggestedFont); + } +} + +void QS60StylePrivate::setThemePalette(QWidget *widget) const +{ + if(!widget) + return; + QPalette widgetPalette = widget->palette(); + + //header view and its viewport need to be set 100% transparent button color, since drawing code will + //draw transparent theme graphics to table column and row headers. + if (qobject_cast<QHeaderView *>(widget)){ + widgetPalette.setColor(QPalette::Active, QPalette::ButtonText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 23, 0)); + QHeaderView* header = qobject_cast<QHeaderView *>(widget); + widgetPalette.setColor(QPalette::Button, Qt::transparent ); + if ( header->viewport() ) + header->viewport()->setPalette(widgetPalette); + QApplication::setPalette(widgetPalette, "QHeaderView"); + } +} + +void QS60StylePrivate::setThemePalette(QPalette *palette) const +{ + if (!palette) + return; + + // basic colors + palette->setColor(QPalette::WindowText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0)); + palette->setColor(QPalette::ButtonText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0)); + palette->setColor(QPalette::Text, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0)); + palette->setColor(QPalette::ToolTipText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 55, 0)); + palette->setColor(QPalette::BrightText, palette->color(QPalette::WindowText).lighter()); + palette->setColor(QPalette::HighlightedText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 10, 0)); + palette->setColor(QPalette::Link, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnHighlightColors, 3, 0)); + palette->setColor(QPalette::LinkVisited, palette->color(QPalette::Link).darker()); + palette->setColor(QPalette::Highlight, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnHighlightColors, 2, 0)); + // set background image as a texture brush + palette->setBrush(QPalette::Window, QS60StylePrivate::backgroundTexture()); + // set these as transparent so that styled full screen theme background is visible + palette->setColor(QPalette::AlternateBase, Qt::transparent); + palette->setBrush(QPalette::Base, Qt::transparent); + // set button and tooltipbase based on pixel colors + const QColor buttonColor = this->colorFromFrameGraphics(QS60StylePrivate::SF_ButtonNormal); + palette->setColor(QPalette::Button, buttonColor ); + const QColor toolTipColor = this->colorFromFrameGraphics(QS60StylePrivate::SF_ToolTip); + palette->setColor(QPalette::ToolTipBase, toolTipColor ); + palette->setColor(QPalette::Light, palette->color(QPalette::Button).lighter()); + palette->setColor(QPalette::Dark, palette->color(QPalette::Button).darker()); + palette->setColor(QPalette::Midlight, palette->color(QPalette::Button).lighter(125)); + palette->setColor(QPalette::Mid, palette->color(QPalette::Button).darker(150)); + palette->setColor(QPalette::Shadow, Qt::black); + + setThemePaletteHash(palette); + QS60StylePrivate::storeThemePalette(palette); +} + +void QS60StylePrivate::deleteThemePalette() +{ + if (m_themePalette) { + delete m_themePalette; + m_themePalette = 0; + } +} + +void QS60StylePrivate::storeThemePalette(QPalette *palette) +{ + deleteThemePalette(); + //store specified palette for latter use. + m_themePalette = new QPalette(*palette); +} + +// set widget specific palettes +void QS60StylePrivate::setThemePaletteHash(QPalette *palette) const +{ + if (!palette) + return; + + //store the original palette + QPalette widgetPalette = *palette; + const QColor mainAreaTextColor = + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0); + + widgetPalette.setColor(QPalette::All, QPalette::WindowText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors, 8, 0)); + QApplication::setPalette(widgetPalette, "QSlider"); + // return to original palette after each widget + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::Active, QPalette::ButtonText, mainAreaTextColor); + widgetPalette.setColor(QPalette::Inactive, QPalette::ButtonText, mainAreaTextColor); + const QStyleOption opt; + widgetPalette.setColor(QPalette::Disabled, QPalette::ButtonText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 6, &opt)); + QApplication::setPalette(widgetPalette, "QPushButton"); + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::Active, QPalette::ButtonText, mainAreaTextColor); + widgetPalette.setColor(QPalette::Inactive, QPalette::ButtonText, mainAreaTextColor); + QApplication::setPalette(widgetPalette, "QToolButton"); + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::Active, QPalette::ButtonText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 23, 0)); + QApplication::setPalette(widgetPalette, "QHeaderView"); + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::All, QPalette::ButtonText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 8, 0)); + QApplication::setPalette(widgetPalette, "QMenuBar"); + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::Active, QPalette::WindowText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 4, 0)); + QApplication::setPalette(widgetPalette, "QTabBar"); + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::All, QPalette::Text, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 22, 0)); + QApplication::setPalette(widgetPalette, "QTableView"); + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::All, QPalette::HighlightedText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 24, 0)); + QApplication::setPalette(widgetPalette, "QLineEdit"); + widgetPalette = *palette; + + widgetPalette.setColor(QPalette::WindowText, mainAreaTextColor); + widgetPalette.setColor(QPalette::Button, QApplication::palette().color(QPalette::Button)); + widgetPalette.setColor(QPalette::Dark, mainAreaTextColor.darker()); + widgetPalette.setColor(QPalette::Light, mainAreaTextColor.lighter()); + QApplication::setPalette(widgetPalette, "QDial"); + widgetPalette = *palette; + + widgetPalette.setBrush(QPalette::Window, QBrush()); + QApplication::setPalette(widgetPalette, "QScrollArea"); + widgetPalette = *palette; +} + +QSize QS60StylePrivate::partSize(QS60StyleEnums::SkinParts part, SkinElementFlags flags) +{ + QSize result(20, 20); + switch (part) + { + case QS60StyleEnums::SP_QgnGrafBarProgress: + result.setWidth(pixelMetric(QStyle::PM_ProgressBarChunkWidth)); + break; + case QS60StyleEnums::SP_QgnGrafTabActiveM: + case QS60StyleEnums::SP_QgnGrafTabPassiveM: + case QS60StyleEnums::SP_QgnGrafTabActiveR: + case QS60StyleEnums::SP_QgnGrafTabPassiveR: + case QS60StyleEnums::SP_QgnGrafTabPassiveL: + case QS60StyleEnums::SP_QgnGrafTabActiveL: + break; + case QS60StyleEnums::SP_QgnIndiSliderEdit: + result.scale(pixelMetric(QStyle::PM_SliderLength), + pixelMetric(QStyle::PM_SliderControlThickness), Qt::IgnoreAspectRatio); + break; + + case QS60StyleEnums::SP_QsnCpScrollHandleBottomPressed: + case QS60StyleEnums::SP_QsnCpScrollHandleTopPressed: + case QS60StyleEnums::SP_QsnCpScrollHandleMiddlePressed: + case QS60StyleEnums::SP_QsnCpScrollBgBottom: + case QS60StyleEnums::SP_QsnCpScrollBgMiddle: + case QS60StyleEnums::SP_QsnCpScrollBgTop: + case QS60StyleEnums::SP_QsnCpScrollHandleBottom: + case QS60StyleEnums::SP_QsnCpScrollHandleMiddle: + case QS60StyleEnums::SP_QsnCpScrollHandleTop: + result.setHeight(pixelMetric(QStyle::PM_ScrollBarExtent)); + result.setWidth(pixelMetric(QStyle::PM_ScrollBarExtent)); + break; + default: + // Generic frame part size gathering. + for (int i = 0; i < frameElementsCount; ++i) + { + switch (m_frameElementsData[i].center - part) { + case 8: /* CornerTl */ + case 7: /* CornerTr */ + case 6: /* CornerBl */ + case 5: /* CornerBr */ + result.setWidth(pixelMetric(PM_Custom_FrameCornerWidth)); + // Falltrough intended... + case 4: /* SideT */ + case 3: /* SideB */ + result.setHeight(pixelMetric(PM_Custom_FrameCornerHeight)); + break; + case 2: /* SideL */ + case 1: /* SideR */ + result.setWidth(pixelMetric(PM_Custom_FrameCornerWidth)); + break; + case 0: /* center */ + default: + break; + } + } + break; + } + if (flags & (QS60StylePrivate::SF_PointEast | QS60StylePrivate::SF_PointWest)) { + const int temp = result.width(); + result.setWidth(result.height()); + result.setHeight(temp); + } + return result; +} + +/*! + \class QS60Style + \brief The QS60Style class provides a look and feel suitable for applications on S60. + \since 4.6 + \ingroup appearance + + \sa QMacStyle, QWindowsStyle, QWindowsXPStyle, QWindowsVistaStyle, QPlastiqueStyle, QCleanlooksStyle, QMotifStyle +*/ + +QS60Style::~QS60Style() +{ +} + +/*! + \reimp +*/ +void QS60Style::drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ + const QS60StylePrivate::SkinElementFlags flags = (option->state & State_Enabled) ? QS60StylePrivate::SF_StateEnabled : QS60StylePrivate::SF_StateDisabled; + SubControls sub = option->subControls; + + switch (control) { +#ifndef QT_NO_SCROLLBAR + case CC_ScrollBar: + if (const QStyleOptionSlider *optionSlider = qstyleoption_cast<const QStyleOptionSlider *>(option)) { + const bool horizontal = optionSlider->orientation == Qt::Horizontal; + + const QRect scrollBarSlider = subControlRect(control, optionSlider, SC_ScrollBarSlider, widget); + const QRect grooveRect = subControlRect(control, optionSlider, SC_ScrollBarGroove, widget); + + const QS60StylePrivate::SkinElements grooveElement = + horizontal ? QS60StylePrivate::SE_ScrollBarGrooveHorizontal : QS60StylePrivate::SE_ScrollBarGrooveVertical; + QS60StylePrivate::drawSkinElement(grooveElement, painter, grooveRect, flags); + + const QStyle::SubControls subControls = optionSlider->subControls; + + // select correct slider (horizontal/vertical/pressed) + const bool sliderPressed = ((optionSlider->state & QStyle::State_Sunken) && (subControls & SC_ScrollBarSlider)); + const QS60StylePrivate::SkinElements handleElement = + horizontal ? + ( sliderPressed ? + QS60StylePrivate::SE_ScrollBarHandlePressedHorizontal : + QS60StylePrivate::SE_ScrollBarHandleHorizontal ) : + ( sliderPressed ? + QS60StylePrivate::SE_ScrollBarHandlePressedVertical : + QS60StylePrivate::SE_ScrollBarHandleVertical); + QS60StylePrivate::drawSkinElement(handleElement, painter, scrollBarSlider, flags); + } + break; +#endif // QT_NO_SCROLLBAR +#ifndef QT_NO_SLIDER + case CC_Slider: + if (const QStyleOptionSlider *optionSlider = qstyleoption_cast<const QStyleOptionSlider *>(option)) { + + // The groove is just a centered line. Maybe a qgn_graf_line_* at some point + const QRect sliderGroove = subControlRect(control, optionSlider, SC_SliderGroove, widget); + const QPoint sliderGrooveCenter = sliderGroove.center(); + const bool horizontal = optionSlider->orientation == Qt::Horizontal; + painter->save(); + if (widget) + painter->setPen(widget->palette().windowText().color()); + if (horizontal) + painter->drawLine(0, sliderGrooveCenter.y(), sliderGroove.right(), sliderGrooveCenter.y()); + else + painter->drawLine(sliderGrooveCenter.x(), 0, sliderGrooveCenter.x(), sliderGroove.bottom()); + painter->restore(); + + const QRect sliderHandle = subControlRect(control, optionSlider, SC_SliderHandle, widget); + const QS60StylePrivate::SkinElements handleElement = + horizontal ? QS60StylePrivate::SE_SliderHandleHorizontal : QS60StylePrivate::SE_SliderHandleVertical; + QS60StylePrivate::drawSkinElement(handleElement, painter, sliderHandle, flags); + + if (optionSlider->state & State_HasFocus) { + QStyleOptionFocusRect fropt; + fropt.QStyleOption::operator=(*optionSlider); + fropt.rect = subElementRect(SE_SliderFocusRect, optionSlider, widget); + drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); + } + } + break; +#endif // QT_NO_SLIDER +#ifndef QT_NO_COMBOBOX + case CC_ComboBox: + if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) { + const QRect cmbxEditField = subControlRect(CC_ComboBox, option, SC_ComboBoxEditField, widget); + const QRect cmbxFrame = subControlRect(CC_ComboBox, option, SC_ComboBoxFrame, widget); + const bool direction = cmb->direction == Qt::LeftToRight; + + // Button frame + QStyleOptionFrame buttonOption; + buttonOption.QStyleOption::operator=(*cmb); + const int maxHeight = cmbxFrame.height(); + const int maxWidth = cmbxFrame.width() - cmbxEditField.width(); + const int topLeftPoint = direction ? cmbxEditField.right()+1 : cmbxEditField.left()+1-maxWidth; + const QRect buttonRect(topLeftPoint, cmbxEditField.top(), maxWidth, maxHeight); + buttonOption.rect = buttonRect; + buttonOption.state = cmb->state & (State_Enabled | State_MouseOver); + drawPrimitive(PE_PanelButtonCommand, &buttonOption, painter, widget); + + // draw label background - label itself is drawn separately + const QS60StylePrivate::SkinElements skinElement = QS60StylePrivate::SE_FrameLineEdit; + QS60StylePrivate::drawSkinElement(skinElement, painter, cmbxEditField, flags); + + // Draw the combobox arrow + if (sub & SC_ComboBoxArrow) { + // Make rect slightly smaller + buttonOption.rect.adjust(1, 1, -1, -1); + painter->save(); + painter->setPen(option->palette.buttonText().color()); + drawPrimitive(PE_IndicatorSpinDown, &buttonOption, painter, widget); + painter->restore(); + } + + if (cmb->subControls & SC_ComboBoxEditField) { + if (cmb->state & State_HasFocus && !cmb->editable) { + QStyleOptionFocusRect focus; + focus.QStyleOption::operator=(*cmb); + focus.rect = cmbxEditField; + focus.state |= State_FocusAtBorder; + focus.backgroundColor = cmb->palette.highlight().color(); + drawPrimitive(PE_FrameFocusRect, &focus, painter, widget); + } + } + } + break; +#endif // QT_NO_COMBOBOX +#ifndef QT_NO_TOOLBUTTON + case CC_ToolButton: + if (const QStyleOptionToolButton *toolBtn = qstyleoption_cast<const QStyleOptionToolButton *>(option)) { + const State bflags = toolBtn->state; + const QRect button(subControlRect(control, toolBtn, SC_ToolButton, widget)); + QStyleOptionToolButton toolButton = *toolBtn; + + if (sub&SC_ToolButton) { + QStyleOption tool(0); + tool.palette = toolBtn->palette; + + // Check if toolbutton is in toolbar. + QToolBar *toolBar = 0; + if (widget) + toolBar = qobject_cast<QToolBar *>(widget->parentWidget()); + + if (bflags & (State_Sunken | State_On | State_Raised)) { + tool.rect = button; + tool.state = bflags; + + // todo: I'd like to move extension button next to where last button is + // however, the painter seems to want to clip the button rect even if I turn of the clipping. + if (toolBar && (qobject_cast<const QToolBarExtension *>(widget))){ + /*QList<QAction *> actionList = toolBar->actions(); + const int actionCount = actionList.count(); + const int toolbarWidth = toolBar->width(); + const int extButtonWidth = pixelMetric(PM_ToolBarExtensionExtent, option, widget); + const int toolBarButtonWidth = pixelMetric(PM_ToolBarIconSize, option, widget); + const int frame = pixelMetric(PM_ToolBarFrameWidth, option, widget); + const int margin = pixelMetric(PM_ToolBarItemMargin, option, widget); + const int border = frame + margin; + const int spacing = pixelMetric(PM_ToolBarItemSpacing, option, widget); + const int toolBarButtonArea = toolbarWidth - extButtonWidth - spacing - 2*border; + const int numberOfVisibleButtons = toolBarButtonArea / toolBarButtonWidth; + // new extension button place is after border and all the other visible buttons (with spacings) + const int newXForExtensionButton = numberOfVisibleButtons * toolBarButtonWidth + (numberOfVisibleButtons-1)*spacing + border; + painter->save(); + painter->setClipping(false); + tool.rect.translate(-newXForExtensionButton,0); + painter->restore();*/ + } + + if (toolBar){ + /*if (toolBar->orientation() == Qt::Vertical){ + // todo: I'd like to make all vertical buttons the same size, but again the painter + // prefers to use clipping for button rects, even though clipping has been set off. + painter->save(); + painter->setClipping(false); + + const int origWidth = tool.rect.width(); + const int newWidth = toolBar->width()-2*pixelMetric(PM_ToolBarFrameWidth, option, widget); + painter->translate(origWidth-newWidth,0); + tool.rect.translate(origWidth-tool.rect.width(),0); + tool.rect.setWidth(newWidth); + + if (option->state & QStyle::State_Sunken) + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_ToolBarButtonPressed, painter, tool.rect, flags); + else + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_ToolBarButton, painter, tool.rect, flags); + + }*/ + if (option->state & QStyle::State_Sunken) + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_ToolBarButtonPressed, painter, tool.rect, flags); + else + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_ToolBarButton, painter, tool.rect, flags); + /* + if (toolBar->orientation() == Qt::Vertical) + painter->restore(); + */ + } else { + drawPrimitive(PE_PanelButtonTool, &tool, painter, widget); + } + } + } + if (toolBtn->state & State_HasFocus) { + QStyleOptionFocusRect fr; + fr.QStyleOption::operator=(*toolBtn); + const int frameWidth = pixelMetric(PM_DefaultFrameWidth, option, widget); + fr.rect.adjust(frameWidth, frameWidth, -frameWidth, -frameWidth); + drawPrimitive(PE_FrameFocusRect, &fr, painter, widget); + } + + if (toolBtn->features & QStyleOptionToolButton::Arrow) { + QStyle::PrimitiveElement pe; + switch (toolBtn->arrowType) { + case Qt::LeftArrow: + pe = QStyle::PE_IndicatorArrowLeft; + break; + case Qt::RightArrow: + pe = QStyle::PE_IndicatorArrowRight; + break; + case Qt::UpArrow: + pe = QStyle::PE_IndicatorArrowUp; + break; + case Qt::DownArrow: + pe = QStyle::PE_IndicatorArrowDown; + break; + default: + break; } + toolButton.rect = button; + drawPrimitive(pe, &toolButton, painter, widget); + } + + if (toolBtn->text.length()>0 || + !toolBtn->icon.isNull()) { + const int frameWidth = pixelMetric(PM_DefaultFrameWidth, option, widget); + toolButton.rect = button.adjusted(frameWidth, frameWidth, -frameWidth, -frameWidth); + drawControl(CE_ToolButtonLabel, &toolButton, painter, widget); + } + } + break; +#endif //QT_NO_TOOLBUTTON +#ifndef QT_NO_SPINBOX + case CC_SpinBox: + if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) { + QStyleOptionSpinBox copy = *spinBox; + PrimitiveElement pe; + + if (spinBox->subControls & SC_SpinBoxUp) { + copy.subControls = SC_SpinBoxUp; + QPalette spinBoxPal = spinBox->palette; + if (!(spinBox->stepEnabled & QAbstractSpinBox::StepUpEnabled)) { + spinBoxPal.setCurrentColorGroup(QPalette::Disabled); + copy.state &= ~State_Enabled; + copy.palette = spinBoxPal; + } + + if (spinBox->activeSubControls == SC_SpinBoxUp && (spinBox->state & State_Sunken)) { + copy.state |= State_On; + copy.state |= State_Sunken; + } else { + copy.state |= State_Raised; + copy.state &= ~State_Sunken; + } + pe = (spinBox->buttonSymbols == QAbstractSpinBox::PlusMinus) ? + PE_IndicatorSpinPlus : + PE_IndicatorSpinUp; + + copy.rect = subControlRect(CC_SpinBox, spinBox, SC_SpinBoxUp, widget); + drawPrimitive(PE_PanelButtonBevel, ©, painter, widget); + copy.rect.adjust(1, 1, -1, -1); + drawPrimitive(pe, ©, painter, widget); + } + + if (spinBox->subControls & SC_SpinBoxDown) { + copy.subControls = SC_SpinBoxDown; + copy.state = spinBox->state; + QPalette spinBoxPal = spinBox->palette; + if (!(spinBox->stepEnabled & QAbstractSpinBox::StepDownEnabled)) { + spinBoxPal.setCurrentColorGroup(QPalette::Disabled); + copy.state &= ~State_Enabled; + copy.palette = spinBoxPal; + } + + if (spinBox->activeSubControls == SC_SpinBoxDown && (spinBox->state & State_Sunken)) { + copy.state |= State_On; + copy.state |= State_Sunken; + } else { + copy.state |= State_Raised; + copy.state &= ~State_Sunken; + } + pe = (spinBox->buttonSymbols == QAbstractSpinBox::PlusMinus) ? + PE_IndicatorSpinMinus : + PE_IndicatorSpinDown; + + copy.rect = subControlRect(CC_SpinBox, spinBox, SC_SpinBoxDown, widget); + drawPrimitive(PE_PanelButtonBevel, ©, painter, widget); + copy.rect.adjust(1, 1, -1, -1); + drawPrimitive(pe, ©, painter, widget); + } + } + break; +#endif //QT_NO_SPINBOX +#ifndef QT_NO_GROUPBOX + case CC_GroupBox: + if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(option)) { + // Draw frame + const QRect textRect = subControlRect(CC_GroupBox, option, SC_GroupBoxLabel, widget); + const QRect checkBoxRect = subControlRect(CC_GroupBox, option, SC_GroupBoxCheckBox, widget); + if (groupBox->subControls & QStyle::SC_GroupBoxFrame) { + QStyleOptionFrameV2 frame; + frame.QStyleOption::operator=(*groupBox); + frame.features = groupBox->features; + frame.lineWidth = groupBox->lineWidth; + frame.midLineWidth = groupBox->midLineWidth; + frame.rect = subControlRect(CC_GroupBox, option, SC_GroupBoxFrame, widget); + drawPrimitive(PE_FrameGroupBox, &frame, painter, widget); + } + + // Draw title + if ((groupBox->subControls & QStyle::SC_GroupBoxLabel) && !groupBox->text.isEmpty()) { + const QColor textColor = groupBox->textColor; + painter->save(); + + if (textColor.isValid()) + painter->setPen(textColor); + int alignment = int(groupBox->textAlignment); + if (!styleHint(QStyle::SH_UnderlineShortcut, option, widget)) + alignment |= Qt::TextHideMnemonic; + + drawItemText(painter, textRect, Qt::TextShowMnemonic | Qt::AlignHCenter | Qt::AlignVCenter | alignment, + groupBox->palette, groupBox->state & State_Enabled, groupBox->text, + textColor.isValid() ? QPalette::NoRole : QPalette::WindowText); + painter->restore(); + + if (groupBox->state & State_HasFocus) { + QStyleOptionFocusRect fropt; + fropt.QStyleOption::operator=(*groupBox); + fropt.rect = textRect; + drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); + } + } + + // Draw checkbox + if (groupBox->subControls & SC_GroupBoxCheckBox) { + QStyleOptionButton box; + box.QStyleOption::operator=(*groupBox); + box.rect = checkBoxRect; + drawPrimitive(PE_IndicatorCheckBox, &box, painter, widget); + } + } + break; +#endif //QT_NO_GROUPBOX + default: + QCommonStyle::drawComplexControl(control, option, painter, widget); + } +} + +/*! + \reimp +*/ +void QS60Style::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + Q_D(const QS60Style); + const QS60StylePrivate::SkinElementFlags flags = (option->state & State_Enabled) ? QS60StylePrivate::SF_StateEnabled : QS60StylePrivate::SF_StateDisabled; + switch (element) { + case CE_PushButton: + if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(option)) { + + drawControl(CE_PushButtonBevel, btn, painter, widget); + QStyleOptionButton subopt = *btn; + subopt.rect = subElementRect(SE_PushButtonContents, btn, widget); + + drawControl(CE_PushButtonLabel, &subopt, painter, widget); + if (btn->state & State_HasFocus) { + QStyleOptionFocusRect fropt; + fropt.QStyleOption::operator=(*btn); + fropt.rect = subElementRect(SE_PushButtonFocusRect, btn, widget); + drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); + } + } + break; + case CE_PushButtonBevel: + if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) { + const bool isDisabled = !(option->state & QStyle::State_Enabled); + const bool isFlat = button->features & QStyleOptionButton::Flat; + QS60StyleEnums::SkinParts skinPart; + QS60StylePrivate::SkinElements skinElement; + if (!isDisabled) { + const bool isPressed = (option->state & QStyle::State_Sunken) || + (option->state & QStyle::State_On); + if (isFlat) { + skinPart = + isPressed ? QS60StyleEnums::SP_QsnFrButtonTbCenterPressed : QS60StyleEnums::SP_QsnFrButtonTbCenter; + } else { + skinElement = + isPressed ? QS60StylePrivate::SE_ButtonPressed : QS60StylePrivate::SE_ButtonNormal; + } + } else { + if (isFlat) + skinPart =QS60StyleEnums::SP_QsnFrButtonCenterInactive; + else + skinElement = QS60StylePrivate::SE_ButtonInactive; + } + if (isFlat) + QS60StylePrivate::drawSkinPart(skinPart, painter, option->rect, flags); + else + QS60StylePrivate::drawSkinElement(skinElement, painter, option->rect, flags); + } + break; +#ifndef QT_NO_TOOLBUTTON + case CE_ToolButtonLabel: + if (const QStyleOptionToolButton *toolBtn = qstyleoption_cast<const QStyleOptionToolButton *>(option)) { + QStyleOptionToolButton optionToolButton = *toolBtn; + + if (!optionToolButton.icon.isNull() && (optionToolButton.state & QStyle::State_Sunken) + && (optionToolButton.state & State_Enabled)) { + + const QIcon::State state = optionToolButton.state & State_On ? QIcon::On : QIcon::Off; + const QPixmap pm(optionToolButton.icon.pixmap(optionToolButton.rect.size().boundedTo(optionToolButton.iconSize), + QIcon::Normal, state)); + optionToolButton.icon = generatedIconPixmap(QIcon::Selected, pm, &optionToolButton); + } + + QCommonStyle::drawControl(element, &optionToolButton, painter, widget); + } + break; +#endif //QT_NO_TOOLBUTTON +#ifndef QT_NO_COMBOBOX + case CE_ComboBoxLabel: + if (const QStyleOptionComboBox *comboBox = qstyleoption_cast<const QStyleOptionComboBox *>(option)) { + QStyleOption optionComboBox = *comboBox; + optionComboBox.palette.setColor(QPalette::Active, QPalette::WindowText, + optionComboBox.palette.text().color() ); + optionComboBox.palette.setColor(QPalette::Inactive, QPalette::WindowText, + optionComboBox.palette.text().color() ); + QRect editRect = subControlRect(CC_ComboBox, comboBox, SC_ComboBoxEditField, widget); + painter->save(); + painter->setClipRect(editRect); + + if (!comboBox->currentIcon.isNull()) { + QIcon::Mode mode = comboBox->state & State_Enabled ? QIcon::Normal : QIcon::Disabled; + QPixmap pixmap = comboBox->currentIcon.pixmap(comboBox->iconSize, mode); + QRect iconRect(editRect); + iconRect.setWidth(comboBox->iconSize.width() + 4); + iconRect = alignedRect(comboBox->direction, + Qt::AlignLeft | Qt::AlignVCenter, + iconRect.size(), editRect); + if (comboBox->editable) + painter->fillRect(iconRect, optionComboBox.palette.brush(QPalette::Base)); + drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); + + if (comboBox->direction == Qt::RightToLeft) + editRect.translate(-4 - comboBox->iconSize.width(), 0); + else + editRect.translate(comboBox->iconSize.width() + 4, 0); + } + if (!comboBox->currentText.isEmpty() && !comboBox->editable) { + QCommonStyle::drawItemText(painter, + editRect.adjusted(QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerWidth), 0, -1, 0), + visualAlignment(comboBox->direction, Qt::AlignLeft | Qt::AlignVCenter), + comboBox->palette, comboBox->state & State_Enabled, comboBox->currentText); + } + painter->restore(); + } + break; +#endif //QT_NO_COMBOBOX +#ifndef QT_NO_ITEMVIEWS + case CE_ItemViewItem: + if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(option)) { + QStyleOptionViewItemV4 voptAdj = *vopt; + painter->save(); + + painter->setClipRect(voptAdj.rect); + const bool isSelected = (voptAdj.state & QStyle::State_HasFocus); + + bool isVisible = false; + int scrollBarWidth = 0; + QList<QScrollBar *> scrollBars = qFindChildren<QScrollBar *>(widget); + for (int i = 0; i < scrollBars.size(); ++i) { + QScrollBar *scrollBar = scrollBars.at(i); + if (scrollBar && scrollBar->orientation() == Qt::Vertical) { + isVisible = scrollBar->isVisible(); + scrollBarWidth = scrollBar->size().width(); + break; + } + } + + int rightValue = widget ? widget->contentsRect().right() : 0; + + if (isVisible) + rightValue -= scrollBarWidth; + + if (voptAdj.rect.right() > rightValue) + voptAdj.rect.setRight(rightValue); + + const QRect iconRect = subElementRect(SE_ItemViewItemDecoration, &voptAdj, widget); + QRect textRect = subElementRect(SE_ItemViewItemText, &voptAdj, widget); + + // draw themed background for table unless background brush has been defined. + if (vopt->backgroundBrush == Qt::NoBrush) { + const QStyleOptionViewItemV4 *tableOption = qstyleoption_cast<const QStyleOptionViewItemV4 *>(option); + const QTableView *table = qobject_cast<const QTableView *>(widget); + if (table && tableOption) { + const QModelIndex index = tableOption->index; + //todo: Draw cell background only once - for the first cell. + QStyleOptionViewItemV4 voptAdj2 = voptAdj; + const QModelIndex indexFirst = table->model()->index(0,0); + const QModelIndex indexLast = table->model()->index( + table->model()->rowCount()-1,table->model()->columnCount()-1); + if (table->viewport()) + voptAdj2.rect = QRect( table->visualRect(indexFirst).topLeft(), + table->visualRect(indexLast).bottomRight()).intersect(table->viewport()->rect()); + drawPrimitive(PE_PanelItemViewItem, &voptAdj2, painter, widget); + } + } else { QCommonStyle::drawPrimitive(PE_PanelItemViewItem, option, painter, widget);} + + // draw the focus rect + if (isSelected) + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_ListHighlight, painter, option->rect, flags); + + // draw the icon + const QIcon::Mode mode = !(voptAdj.state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled; + const QIcon::State state = voptAdj.state & QStyle::State_Open ? QIcon::On : QIcon::Off; + voptAdj.icon.paint(painter, iconRect, voptAdj.decorationAlignment, mode, state); + + // Draw selection check mark. Show check mark only in multi selection modes. + if (const QListView *listView = (qobject_cast<const QListView *>(widget))) { + const bool singleSelection = + listView && + (listView->selectionMode() == QAbstractItemView::SingleSelection || + listView->selectionMode() == QAbstractItemView::NoSelection); + const QRect selectionRect = subElementRect(SE_ItemViewItemCheckIndicator, &voptAdj, widget); + if (voptAdj.state & QStyle::State_Selected && !singleSelection) { + QStyleOptionViewItemV4 option(voptAdj); + option.rect = selectionRect; + // Draw selection mark. + drawPrimitive(QStyle::PE_IndicatorViewItemCheck, &option, painter, widget); + if ( textRect.right() > selectionRect.left() ) + textRect.setRight(selectionRect.left()); + } else if (singleSelection && + voptAdj.features & QStyleOptionViewItemV2::HasCheckIndicator) { + // draw the check mark + if (selectionRect.isValid()) { + QStyleOptionViewItemV4 option(*vopt); + option.rect = selectionRect; + option.state = option.state & ~QStyle::State_HasFocus; + + switch (vopt->checkState) { + case Qt::Unchecked: + option.state |= QStyle::State_Off; + break; + case Qt::PartiallyChecked: + option.state |= QStyle::State_NoChange; + break; + case Qt::Checked: + option.state |= QStyle::State_On; + break; + } + drawPrimitive(QStyle::PE_IndicatorViewItemCheck, &option, painter, widget); + } + } + } + + // draw the text + if (!voptAdj.text.isEmpty()) { + const QStyleOptionViewItemV4 *tableOption = qstyleoption_cast<const QStyleOptionViewItemV4 *>(option); + if (isSelected) { + if (qobject_cast<const QTableView *>(widget) && tableOption) + voptAdj.palette.setColor( + QPalette::Text, QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 11, 0)); + else + voptAdj.palette.setColor( + QPalette::Text, QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 10, 0)); + } + painter->setPen(voptAdj.palette.text().color()); + d->viewItemDrawText(painter, &voptAdj, textRect); + } + painter->restore(); + } + break; +#endif // QT_NO_ITEMVIEWS +#ifndef QT_NO_TABBAR + case CE_TabBarTabShape: + if (const QStyleOptionTabV3 *optionTab = qstyleoption_cast<const QStyleOptionTabV3 *>(option)) { + QStyleOptionTabV3 optionTabAdj = *optionTab; + const bool isSelected = optionTab->state & QStyle::State_Selected; + const bool directionMirrored = (optionTab->direction == Qt::RightToLeft); + QS60StylePrivate::SkinElements skinElement; + switch (optionTab->shape) { + case QTabBar::TriangularEast: + case QTabBar::RoundedEast: + skinElement = isSelected ? QS60StylePrivate::SE_TabBarTabEastActive: + QS60StylePrivate::SE_TabBarTabEastInactive; + break; + case QTabBar::TriangularSouth: + case QTabBar::RoundedSouth: + skinElement = isSelected ? QS60StylePrivate::SE_TabBarTabSouthActive: + QS60StylePrivate::SE_TabBarTabSouthInactive; + break; + case QTabBar::TriangularWest: + case QTabBar::RoundedWest: + skinElement = isSelected ? QS60StylePrivate::SE_TabBarTabWestActive: + QS60StylePrivate::SE_TabBarTabWestInactive; + break; + case QTabBar::TriangularNorth: + case QTabBar::RoundedNorth: + default: + skinElement = isSelected ? QS60StylePrivate::SE_TabBarTabNorthActive: + QS60StylePrivate::SE_TabBarTabNorthInactive; + break; + } + if (skinElement==QS60StylePrivate::SE_TabBarTabEastInactive|| + skinElement==QS60StylePrivate::SE_TabBarTabNorthInactive|| + skinElement==QS60StylePrivate::SE_TabBarTabSouthInactive|| + skinElement==QS60StylePrivate::SE_TabBarTabWestInactive|| + skinElement==QS60StylePrivate::SE_TabBarTabEastActive|| + skinElement==QS60StylePrivate::SE_TabBarTabNorthActive|| + skinElement==QS60StylePrivate::SE_TabBarTabSouthActive|| + skinElement==QS60StylePrivate::SE_TabBarTabWestActive) { + const int borderThickness = + QS60StylePrivate::pixelMetric(QStyle::PM_DefaultFrameWidth); + const int tabOverlap = + QS60StylePrivate::pixelMetric(QStyle::PM_TabBarTabOverlap) - borderThickness; + //todo: draw navi wipe behind tabbar - must be drawn with first draw + + if (skinElement==QS60StylePrivate::SE_TabBarTabEastInactive|| + skinElement==QS60StylePrivate::SE_TabBarTabEastActive|| + skinElement==QS60StylePrivate::SE_TabBarTabWestInactive|| + skinElement==QS60StylePrivate::SE_TabBarTabWestActive){ + optionTabAdj.rect.adjust(0, 0, 0, tabOverlap); + } else { + if (directionMirrored) + optionTabAdj.rect.adjust(-tabOverlap, 0, 0, 0); + else + optionTabAdj.rect.adjust(0, 0, tabOverlap, 0); + } + } + QS60StylePrivate::drawSkinElement(skinElement, painter, optionTabAdj.rect, flags); + } + break; + case CE_TabBarTabLabel: + if (const QStyleOptionTabV3 *tab = qstyleoption_cast<const QStyleOptionTabV3 *>(option)) { + QStyleOptionTabV3 optionTab = *tab; + QRect tr = optionTab.rect; + const bool directionMirrored = (optionTab.direction == Qt::RightToLeft); + const int borderThickness = QS60StylePrivate::pixelMetric(QStyle::PM_DefaultFrameWidth); + const int tabOverlap = + QS60StylePrivate::pixelMetric(QStyle::PM_TabBarTabOverlap) - borderThickness; + const QRect windowRect = painter->window(); + + switch (tab->shape) { + case QTabBar::TriangularWest: + case QTabBar::RoundedWest: + case QTabBar::TriangularEast: + case QTabBar::RoundedEast: + tr.adjust(0, 0, 0, tabOverlap); + break; + case QTabBar::TriangularSouth: + case QTabBar::RoundedSouth: + case QTabBar::TriangularNorth: + case QTabBar::RoundedNorth: + default: + if (directionMirrored) + tr.adjust(-tabOverlap, 0, 0, 0); + else + tr.adjust(0, 0, tabOverlap, 0); + break; + } + painter->save(); + QFont f = painter->font(); + f.setPointSizeF(f.pointSizeF() * KTabFontMul); + painter->setFont(f); + + if (option->state & QStyle::State_Selected){ + optionTab.palette.setColor(QPalette::Active, QPalette::WindowText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 3, option)); + } + + const bool verticalTabs = optionTab.shape == QTabBar::RoundedEast + || optionTab.shape == QTabBar::RoundedWest + || optionTab.shape == QTabBar::TriangularEast + || optionTab.shape == QTabBar::TriangularWest; + const bool selected = optionTab.state & State_Selected; + if (verticalTabs) { + painter->save(); + int newX, newY, newRotation; + if (optionTab.shape == QTabBar::RoundedEast || optionTab.shape == QTabBar::TriangularEast) { + newX = tr.width(); + newY = tr.y(); + newRotation = 90; + } else { + newX = 0; + newY = tr.y() + tr.height(); + newRotation = -90; + } + tr.setRect(0, 0, tr.height(), tr.width()); + QTransform m; + m.translate(newX, newY); + m.rotate(newRotation); + painter->setTransform(m, true); + } + tr.adjust(0, 0, pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab, widget), + pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab, widget)); + + if (selected) { + tr.setBottom(tr.bottom() - pixelMetric(QStyle::PM_TabBarTabShiftVertical, tab, widget)); + tr.setRight(tr.right() - pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, tab, widget)); + } + + int alignment = Qt::AlignCenter | Qt::TextShowMnemonic; + if (!styleHint(SH_UnderlineShortcut, &optionTab, widget)) + alignment |= Qt::TextHideMnemonic; + if (!optionTab.icon.isNull()) { + QSize iconSize = optionTab.iconSize; + int iconExtent = pixelMetric(PM_TabBarIconSize); + if (iconSize.height() > iconExtent || iconSize.width() > iconExtent) + iconSize = QSize(iconExtent, iconExtent); + QPixmap tabIcon = optionTab.icon.pixmap(iconSize, + (optionTab.state & State_Enabled) ? QIcon::Normal : QIcon::Disabled); + if (tab->text.isEmpty()) + painter->drawPixmap(tr.center().x() - (tabIcon.height() >>1), + tr.center().y() - (tabIcon.height() >>1), + tabIcon); + else + painter->drawPixmap(tr.left() + tabOverlap, + tr.center().y() - (tabIcon.height() >>1), + tabIcon); + tr.setLeft(tr.left() + iconSize.width() + 4); + } + + QCommonStyle::drawItemText(painter, tr, alignment, optionTab.palette, tab->state & State_Enabled, tab->text, QPalette::WindowText); + if (verticalTabs) + painter->restore(); + + if (optionTab.state & State_HasFocus) { + const int OFFSET = 1 + pixelMetric(PM_DefaultFrameWidth); + const int leftBorder = optionTab.rect.left(); + const int rightBorder = optionTab.rect.right() - 1; + + QStyleOptionFocusRect fropt; + fropt.QStyleOption::operator=(*tab); + fropt.rect.setRect(leftBorder + 1 + OFFSET, optionTab.rect.y() + OFFSET, + rightBorder - leftBorder - 2*OFFSET, optionTab.rect.height() - 2*OFFSET); + drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); + } + + painter->restore(); + } + break; +#endif // QT_NO_TABBAR +#ifndef QT_NO_PROGRESSBAR + case CE_ProgressBarContents: + if (const QStyleOptionProgressBarV2 *optionProgressBar = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(option)) { + QRect progressRect = optionProgressBar->rect; + + if (optionProgressBar->minimum == optionProgressBar->maximum && optionProgressBar->minimum == 0) { + // busy indicator + QS60StylePrivate::drawSkinPart(QS60StyleEnums::SP_QgnGrafBarWait, painter, progressRect,flags); + } else { + const qreal progressFactor = (optionProgressBar->minimum == optionProgressBar->maximum) ? 1.0 + : (qreal)optionProgressBar->progress / optionProgressBar->maximum; + if (optionProgressBar->orientation == Qt::Horizontal) { + progressRect.setWidth(int(progressRect.width() * progressFactor)); + if(optionProgressBar->direction == Qt::RightToLeft) + progressRect.translate(optionProgressBar->rect.width()-progressRect.width(),0); + progressRect.adjust(1, 0, -1, 0); + } else { + progressRect.adjust(0, 1, 0, -1); + progressRect.setTop(progressRect.bottom() - int(progressRect.height() * progressFactor)); + } + + const QS60StylePrivate::SkinElements skinElement = optionProgressBar->orientation == Qt::Horizontal ? + QS60StylePrivate::SE_ProgressBarIndicatorHorizontal : QS60StylePrivate::SE_ProgressBarIndicatorVertical; + QS60StylePrivate::drawSkinElement(skinElement, painter, progressRect, flags); + } + } + break; + case CE_ProgressBarGroove: + if (const QStyleOptionProgressBarV2 *optionProgressBar = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(option)) { + const QS60StylePrivate::SkinElements skinElement = optionProgressBar->orientation == Qt::Horizontal ? + QS60StylePrivate::SE_ProgressBarGrooveHorizontal : QS60StylePrivate::SE_ProgressBarGrooveVertical; + QS60StylePrivate::drawSkinElement(skinElement, painter, option->rect, flags); + } + break; + case CE_ProgressBarLabel: + if (const QStyleOptionProgressBarV2 *progressbar = qstyleoption_cast<const QStyleOptionProgressBarV2 *>(option)) { + QStyleOptionProgressBarV2 optionProgressBar = *progressbar; + QCommonStyle::drawItemText(painter, progressbar->rect, flags | Qt::AlignCenter | Qt::TextSingleLine, optionProgressBar.palette, + progressbar->state & State_Enabled, progressbar->text, QPalette::WindowText); + } + break; +#endif // QT_NO_PROGRESSBAR +#ifndef QT_NO_MENU + case CE_MenuItem: + if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) { + QStyleOptionMenuItem optionMenuItem = *menuItem; + + bool drawSubMenuIndicator = false; + switch(menuItem->menuItemType) { + case QStyleOptionMenuItem::Scroller: + case QStyleOptionMenuItem::Separator: + return; // no separators or scrollers in S60 menus + case QStyleOptionMenuItem::SubMenu: + drawSubMenuIndicator = true; + break; + default: + break; + } + const bool enabled = optionMenuItem.state & State_Enabled; + const bool checkable = optionMenuItem.checkType != QStyleOptionMenuItem::NotCheckable; + + uint text_flags = Qt::AlignLeading | Qt::TextShowMnemonic | Qt::TextDontClip + | Qt::TextSingleLine | Qt::AlignVCenter; + if (!styleHint(SH_UnderlineShortcut, menuItem, widget)) + text_flags |= Qt::TextHideMnemonic; + + QRect iconRect = + subElementRect(SE_ItemViewItemDecoration, &optionMenuItem, widget); + QRect textRect = subElementRect(SE_ItemViewItemText, &optionMenuItem, widget); + + if ((option->state & State_Selected) && (option->state & State_Enabled)) + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_ListHighlight, painter, option->rect, flags); + + //todo: move the vertical spacing stuff into subElementRect + const int vSpacing = QS60StylePrivate::pixelMetric(QStyle::PM_LayoutVerticalSpacing); + if (checkable){ + QStyleOptionMenuItem optionCheckBox; + optionCheckBox.QStyleOption::operator=(*menuItem); + optionCheckBox.rect.setWidth(pixelMetric(PM_IndicatorWidth)); + optionCheckBox.rect.setHeight(pixelMetric(PM_IndicatorHeight)); + const int moveByX = optionCheckBox.rect.width()+vSpacing; + if (optionMenuItem.direction == Qt::LeftToRight) { + textRect.translate(moveByX,0); + iconRect.translate(moveByX, 0); + iconRect.setWidth(iconRect.width()+vSpacing); + textRect.setWidth(textRect.width()-moveByX-vSpacing); + } else { + textRect.setWidth(textRect.width()-moveByX); + iconRect.setWidth(iconRect.width()+vSpacing); + iconRect.translate(-optionCheckBox.rect.width()-vSpacing, 0); + optionCheckBox.rect.translate(textRect.width()+iconRect.width(),0); + } + drawPrimitive(PE_IndicatorMenuCheckMark, &optionCheckBox, painter, widget); + } + //draw icon and/or checkState + QPixmap pix = menuItem->icon.pixmap(pixelMetric(PM_SmallIconSize), + enabled ? QIcon::Normal : QIcon::Disabled); + const bool itemWithIcon = !pix.isNull(); + if (itemWithIcon) { + drawItemPixmap(painter, iconRect, text_flags, pix); + if (optionMenuItem.direction == Qt::LeftToRight) + textRect.translate(vSpacing,0); + else + textRect.translate(-vSpacing,0); + textRect.setWidth(textRect.width()-vSpacing); + } + + //draw indicators + if (drawSubMenuIndicator) { + QStyleOptionMenuItem arrowOptions; + arrowOptions.QStyleOption::operator=(*menuItem); + const int indicatorWidth = (pixelMetric(PM_ListViewIconSize, option, widget)>>1) + + pixelMetric(QStyle::PM_LayoutVerticalSpacing, option, widget); + if (optionMenuItem.direction == Qt::LeftToRight) + arrowOptions.rect.setLeft(textRect.right()); + arrowOptions.rect.setWidth(indicatorWidth); + //by default sub menu indicator in S60 points to east,so here icon + // direction is set to north (and south when in RightToLeft) + const QS60StylePrivate::SkinElementFlag arrowDirection = (arrowOptions.direction == Qt::LeftToRight) ? + QS60StylePrivate::SF_PointNorth : QS60StylePrivate::SF_PointSouth; + QS60StylePrivate::drawSkinPart(QS60StyleEnums::SP_QgnIndiSubMenu, painter, arrowOptions.rect, + (flags | QS60StylePrivate::SF_ColorSkinned | arrowDirection)); + } + + //draw text + if (!enabled){ + //In s60, if something becomes disabled, it is removed from menu, so no native look-alike available. + optionMenuItem.palette.setColor(QPalette::Disabled, QPalette::Text, QS60StylePrivate::lighterColor( + optionMenuItem.palette.color(QPalette::Disabled, QPalette::Text))); + painter->save(); + painter->setOpacity(0.5); + } + QCommonStyle::drawItemText(painter, textRect, text_flags, + optionMenuItem.palette, enabled, + optionMenuItem.text, QPalette::Text); + if (!enabled) + painter->restore(); + } + break; + case CE_MenuEmptyArea: + break; +#endif //QT_NO_MENU + +#ifndef QT_NO_MENUBAR + case CE_MenuBarEmptyArea: + break; +#endif //QT_NO_MENUBAR + + case CE_HeaderSection: + if ( const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) { + painter->save(); + QPen linePen = QPen(QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors, 1, header)); + const int penWidth = (header->orientation == Qt::Horizontal) ? + linePen.width()+QS60StylePrivate::pixelMetric(PM_Custom_BoldLineWidth) + : linePen.width()+QS60StylePrivate::pixelMetric(PM_Custom_ThinLineWidth); + linePen.setWidth(penWidth); + painter->setPen(linePen); + if (header->orientation == Qt::Horizontal){ + painter->drawLine(header->rect.bottomLeft(), header->rect.bottomRight()); + } else { + if ( header->direction == Qt::LeftToRight ) { + painter->drawLine(header->rect.topRight(), header->rect.bottomRight()); + } else { + painter->drawLine(header->rect.topLeft(), header->rect.bottomLeft()); + } + } + painter->restore(); + } + break; + case CE_HeaderEmptyArea: + { + QS60StylePrivate::SkinElementFlags adjFlags = flags; + QRect emptyAreaRect = option->rect; + const int frameWidth = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); + if (option->state & QStyle::State_Horizontal) { + emptyAreaRect.adjust(-frameWidth,-frameWidth,frameWidth,-frameWidth); + } else { + if ( option->direction == Qt::LeftToRight ) { + emptyAreaRect.adjust(-frameWidth,-frameWidth,0,frameWidth); + adjFlags |= QS60StylePrivate::SF_PointWest; + } else { + emptyAreaRect.adjust(frameWidth,frameWidth,0,-frameWidth); + adjFlags |= QS60StylePrivate::SF_PointEast; + } + } + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_TableHeaderItem, painter, emptyAreaRect, adjFlags); + } + break; + case CE_Header: + if ( const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) { + QS60StylePrivate::SkinElementFlags adjFlags = flags; + QRect mtyRect = header->rect; + QRect parentRect = widget->parentWidget()->rect(); + const int frameWidth = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); + if (header->orientation == Qt::Horizontal) { + mtyRect.adjust(-frameWidth,-frameWidth,frameWidth,-frameWidth); + } else { + if ( header->direction == Qt::LeftToRight ) { + mtyRect.adjust(-frameWidth,-frameWidth,0,frameWidth); + adjFlags |= QS60StylePrivate::SF_PointWest; + } else { + mtyRect.adjust(frameWidth,frameWidth,0,-frameWidth); + adjFlags |= QS60StylePrivate::SF_PointEast; + } + } + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_TableHeaderItem, painter, mtyRect, adjFlags); + + QRegion clipRegion = painter->clipRegion(); + painter->setClipRect(option->rect); + drawControl(CE_HeaderSection, header, painter, widget); + QStyleOptionHeader subopt = *header; + subopt.rect = subElementRect(SE_HeaderLabel, header, widget); + if (subopt.rect.isValid()) + drawControl(CE_HeaderLabel, &subopt, painter, widget); + if (header->sortIndicator != QStyleOptionHeader::None) { + subopt.rect = subElementRect(SE_HeaderArrow, option, widget); + drawPrimitive(PE_IndicatorHeaderArrow, &subopt, painter, widget); + } + painter->setClipRegion(clipRegion); + } + break; +#ifndef QT_NO_TOOLBAR + case CE_ToolBar: + if (const QStyleOptionToolBar *toolBar = qstyleoption_cast<const QStyleOptionToolBar *>(option)) { + const QToolBar *tbWidget = qobject_cast<const QToolBar *>(widget); + + //toolbar within a toolbar, skip + if (!tbWidget || (widget && qobject_cast<QToolBar *>(widget->parentWidget()))) + break; + + // Normally in S60 5.0+ there is no background for toolbar, but in some cases with versatile QToolBar, + // it looks a bit strange. So, lets fillRect with Button. + if (!QS60StylePrivate::isToolBarBackground()) { + QList<QAction *> actions = tbWidget->actions(); + bool justToolButtonsInToolBar = true; + for (int i = 0; i < actions.size(); ++i) { + QWidget *childWidget = tbWidget->widgetForAction(actions.at(i)); + const QToolButton *button = qobject_cast<const QToolButton *>(childWidget); + if (!button){ + justToolButtonsInToolBar = false; + } + } + + // Draw frame background + // for vertical toolbars with text only and + // for toolbars with extension buttons and + // for toolbars with widgets in them. + if (!justToolButtonsInToolBar || + (tbWidget && + (tbWidget->orientation() == Qt::Vertical) && + (tbWidget->toolButtonStyle() == Qt::ToolButtonTextOnly))) { + painter->save(); + if (widget) + painter->setBrush(widget->palette().button()); + painter->setOpacity(0.3); + painter->fillRect(toolBar->rect, painter->brush()); + painter->restore(); + } + } else { + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_ToolBar, painter, toolBar->rect, flags); + } + } + break; +#endif //QT_NO_TOOLBAR + case CE_ShapedFrame: { + const QTextEdit *txt = qobject_cast<const QTextEdit *>(widget); + if (txt) + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_Editor, painter, option->rect, flags); + } + break; + default: + QCommonStyle::drawControl(element, option, painter, widget); + } +} + +/*! + \reimp +*/ +void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + const QS60StylePrivate::SkinElementFlags flags = (option->state & State_Enabled) ? QS60StylePrivate::SF_StateEnabled : QS60StylePrivate::SF_StateDisabled; + switch (element) { +#ifndef QT_NO_LINEEDIT + case PE_PanelLineEdit: + if (const QStyleOptionFrame *lineEdit = qstyleoption_cast<const QStyleOptionFrame *>(option)) { +#ifndef QT_NO_COMBOBOX + if (widget && qobject_cast<const QComboBox *>(widget->parentWidget())) + break; +#endif + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_FrameLineEdit, + painter, option->rect, flags); + + if (lineEdit->state & State_HasFocus) + drawPrimitive(PE_FrameFocusRect, lineEdit, painter, widget); + } + break; +#endif // QT_NO_LINEEDIT + case PE_IndicatorCheckBox: + { + const QRect indicatorRect = option->rect; + // Draw checkbox indicator as color skinned graphics. + const QS60StyleEnums::SkinParts skinPart = (option->state & QStyle::State_On) ? + QS60StyleEnums::SP_QgnIndiCheckboxOn : QS60StyleEnums::SP_QgnIndiCheckboxOff; + QS60StylePrivate::drawSkinPart(skinPart, painter, indicatorRect, + (flags | QS60StylePrivate::SF_ColorSkinned)); + } + break; + case PE_IndicatorViewItemCheck: +#ifndef QT_NO_ITEMVIEWS + if (const QListView *listItem = (qobject_cast<const QListView *>(widget))) { + if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(option)) { + const bool checkBoxVisible = vopt->features & QStyleOptionViewItemV2::HasCheckIndicator; + const bool singleSelection = listItem->selectionMode() == + QAbstractItemView::SingleSelection || listItem->selectionMode() == QAbstractItemView::NoSelection; + // draw either checkbox at the beginning + if (checkBoxVisible && singleSelection) { + drawPrimitive(PE_IndicatorCheckBox, option, painter, widget); + // ... or normal "tick" selection at the end. + } else if (option->state & QStyle::State_Selected) { + QRect tickRect = option->rect; + const int frameBorderWidth = QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerWidth); + // adjust tickmark rect to exclude frame border + tickRect.adjust(0,-frameBorderWidth,0,-frameBorderWidth); + QS60StyleEnums::SkinParts skinPart = QS60StyleEnums::SP_QgnIndiMarkedAdd; + QS60StylePrivate::drawSkinPart(skinPart, painter, tickRect, + (flags | QS60StylePrivate::SF_ColorSkinned)); + } + } + } +#endif //QT_NO_ITEMVIEWS + break; + case PE_IndicatorRadioButton: { + QRect buttonRect = option->rect; + //there is empty (a. 33%) space in svg graphics for radiobutton + const qreal reduceWidth = (qreal)buttonRect.width()/3.0; + const qreal rectWidth = (qreal)option->rect.width() != 0 ? option->rect.width() : 1.0; + // Try to occupy the full area + const qreal scaler = 1 + (reduceWidth/rectWidth); + buttonRect.setWidth((int)((buttonRect.width()-reduceWidth) * scaler)); + buttonRect.setHeight((int)(buttonRect.height() * scaler)); + // move the rect up for half of the new height-gain + const int newY = (buttonRect.bottomRight().y() - option->rect.bottomRight().y()) >> 1 ; + buttonRect.adjust(0,-newY,0,-newY); + + // Draw radiobutton indicator as color skinned graphics. + QS60StyleEnums::SkinParts skinPart = (option->state & QStyle::State_On) ? + QS60StyleEnums::SP_QgnIndiRadiobuttOn : QS60StyleEnums::SP_QgnIndiRadiobuttOff; + QS60StylePrivate::drawSkinPart(skinPart, painter, buttonRect, + (flags | QS60StylePrivate::SF_ColorSkinned)); + } + break; + case PE_PanelButtonCommand: + case PE_PanelButtonTool: + case PE_PanelButtonBevel: + case PE_FrameButtonBevel: { + const bool isPressed = option->state & QStyle::State_Sunken; + const QS60StylePrivate::SkinElements skinElement = + isPressed ? QS60StylePrivate::SE_ButtonPressed : QS60StylePrivate::SE_ButtonNormal; + QS60StylePrivate::drawSkinElement(skinElement, painter, option->rect, flags); + } + break; +#ifndef QT_NO_TOOLBUTTON + case PE_IndicatorArrowDown: + case PE_IndicatorArrowLeft: + case PE_IndicatorArrowRight: + case PE_IndicatorArrowUp: { + QS60StyleEnums::SkinParts skinPart; + if (element==PE_IndicatorArrowDown) + skinPart = QS60StyleEnums::SP_QgnGrafScrollArrowDown; + else if (element==PE_IndicatorArrowLeft) + skinPart = QS60StyleEnums::SP_QgnGrafScrollArrowLeft; + else if (element==PE_IndicatorArrowRight) + skinPart = QS60StyleEnums::SP_QgnGrafScrollArrowRight; + else if (element==PE_IndicatorArrowUp) + skinPart = QS60StyleEnums::SP_QgnGrafScrollArrowUp; + + QS60StylePrivate::drawSkinPart(skinPart, painter, option->rect, flags); + } + break; +#endif //QT_NO_TOOLBUTTON +#ifndef QT_NO_SPINBOX + case PE_IndicatorSpinDown: + case PE_IndicatorSpinUp: + if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) { + QStyleOptionSpinBox optionSpinBox = *spinBox; + const QS60StyleEnums::SkinParts part = (element == PE_IndicatorSpinUp) ? + QS60StyleEnums::SP_QgnGrafScrollArrowUp : + QS60StyleEnums::SP_QgnGrafScrollArrowDown; + const int adjustment = qMin(optionSpinBox.rect.width(), optionSpinBox.rect.height())/6; + optionSpinBox.rect.translate(0, (element == PE_IndicatorSpinDown) ? adjustment : -adjustment ); + QS60StylePrivate::drawSkinPart(part, painter, optionSpinBox.rect,flags); + } +#ifndef QT_NO_COMBOBOX + else if (const QStyleOptionFrame *cmb = qstyleoption_cast<const QStyleOptionFrame *>(option)) { + // We want to draw down arrow here for comboboxes as well. + const QS60StyleEnums::SkinParts part = QS60StyleEnums::SP_QgnGrafScrollArrowDown; + QStyleOptionFrame comboBox = *cmb; + const int adjustment = qMin(comboBox.rect.width(), comboBox.rect.height())/6; + comboBox.rect.translate(0, (element == PE_IndicatorSpinDown) ? adjustment : -adjustment ); + QS60StylePrivate::drawSkinPart(part, painter, comboBox.rect,flags); + } +#endif //QT_NO_COMBOBOX + break; + case PE_IndicatorSpinMinus: + case PE_IndicatorSpinPlus: + if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) { + QStyleOptionSpinBox optionSpinBox = *spinBox; + QCommonStyle::drawPrimitive(element, &optionSpinBox, painter, widget); + } +#ifndef QT_NO_COMBOBOX + else if (const QStyleOptionFrame *cmb = qstyleoption_cast<const QStyleOptionFrame *>(option)) { + // We want to draw down arrow here for comboboxes as well. + QStyleOptionFrame comboBox = *cmb; + const int frameWidth = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); + comboBox.rect.adjust(0,frameWidth,0,-frameWidth); + QCommonStyle::drawPrimitive(element, &comboBox, painter, widget); + } +#endif //QT_NO_COMBOBOX + break; +#endif //QT_NO_SPINBOX + case PE_FrameFocusRect: +// Calendar widget and combox both do not use styled itemDelegate + if (!(widget && qobject_cast<const QCalendarWidget *>(widget->parent())) || + qobject_cast<const QComboBoxListView *>(widget)) { + // no focus selection for touch + if (option->state & State_HasFocus && !QS60StylePrivate::isTouchSupported()) { + painter->save(); + const int penWidth = QS60StylePrivate::focusRectPenWidth(); +#ifdef QT_KEYPAD_NAVIGATION + const Qt::PenStyle penStyle = widget->hasEditFocus() ? Qt::SolidLine :Qt::DotLine; + const qreal opacity = widget->hasEditFocus() ? 0.6 : 0.4; +#else + const Qt::PenStyle penStyle = Qt::SolidLine; + const qreal opacity = 0.5; +#endif + painter->setPen(QPen(option->palette.color(QPalette::Text), penWidth, penStyle)); + painter->setRenderHint(QPainter::Antialiasing); + painter->setOpacity(opacity); + // Because of Qts coordinate system, we need to tweak the rect by .5 pixels, otherwise it gets blurred. + const qreal rectAdjustment = penWidth % 2?.5:0; + // Also we try to stay inside the option->rect, with penWidth > 1. Therefore these +1/-1 + const QRectF adjustedRect = QRectF(option->rect).adjusted( + rectAdjustment + penWidth - 1, + rectAdjustment + penWidth - 1, + -rectAdjustment - penWidth + 1, + -rectAdjustment - penWidth + 1); + painter->drawRoundedRect(adjustedRect, penWidth * 1.5, penWidth * 1.5); + painter->restore(); + } + } + break; + case PE_Widget: + if (QS60StylePrivate::drawsOwnThemeBackground(widget) +#ifndef QT_NO_COMBOBOX + || qobject_cast<const QComboBoxListView *>(widget) +#endif //QT_NO_COMBOBOX +#ifndef QT_NO_MENU + || qobject_cast<const QMenu *> (widget) +#endif //QT_NO_MENU + ) { + QS60StylePrivate::SkinElements skinElement = QS60StylePrivate::SE_OptionsMenu; + QS60StylePrivate::drawSkinElement(skinElement, painter, option->rect, flags); + } + break; + case PE_FrameWindow: + case PE_FrameTabWidget: + if (const QStyleOptionTabWidgetFrame *tabFrame = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(option)) { + QStyleOptionTabWidgetFrame optionTabFrame = *tabFrame; + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_PanelBackground, painter, optionTabFrame.rect, flags); + } + break; + case PE_IndicatorHeaderArrow: + if (const QStyleOptionHeader *header = qstyleoption_cast<const QStyleOptionHeader *>(option)) { + if (header->sortIndicator & QStyleOptionHeader::SortUp) + drawPrimitive(PE_IndicatorArrowUp, header, painter, widget); + else if (header->sortIndicator & QStyleOptionHeader::SortDown) + drawPrimitive(PE_IndicatorArrowDown, header, painter, widget); + } // QStyleOptionHeader::None is not drawn => not needed + break; +#ifndef QT_NO_GROUPBOX + case PE_FrameGroupBox: + if (const QStyleOptionFrameV2 *frame = qstyleoption_cast<const QStyleOptionFrameV2 *>(option)) + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_SettingsList, painter, frame->rect, flags); + break; +#endif //QT_NO_GROUPBOX + + // Qt3 primitives are not supported + case PE_Q3CheckListController: + case PE_Q3CheckListExclusiveIndicator: + case PE_Q3CheckListIndicator: + case PE_Q3DockWindowSeparator: + case PE_Q3Separator: + Q_ASSERT(false); + break; + case PE_Frame: + if (const QStyleOptionFrameV3 *frame = qstyleoption_cast<const QStyleOptionFrameV3 *>(option)) + drawPrimitive(PE_FrameFocusRect, frame, painter, widget); + break; +#ifndef QT_NO_ITEMVIEWS + case PE_PanelItemViewItem: + case PE_PanelItemViewRow: // ### Qt 5: remove + if (qobject_cast<const QTableView *>(widget) && qstyleoption_cast<const QStyleOptionViewItemV4 *>(option)) + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_TableItem, painter, option->rect, flags); + break; +#endif //QT_NO_ITEMVIEWS + + case PE_IndicatorMenuCheckMark: + if (const QStyleOptionMenuItem *checkBox = qstyleoption_cast<const QStyleOptionMenuItem *>(option)){ + QStyleOptionMenuItem optionCheckBox = *checkBox; + if (optionCheckBox.checked) + optionCheckBox.state = (optionCheckBox.state | State_On); + drawPrimitive(PE_IndicatorCheckBox, &optionCheckBox, painter, widget); + } + break; +#ifndef QT_NO_TOOLBAR + case PE_IndicatorToolBarHandle: + // no toolbar handles in S60/AVKON UI + case PE_IndicatorToolBarSeparator: + // no separators in S60/AVKON UI + break; +#endif //QT_NO_TOOLBAR + + case PE_PanelMenuBar: + case PE_FrameMenu: + break; //disable frame in menu + + case PE_IndicatorBranch: +#if defined(Q_WS_S60) + // 3.1 AVKON UI does not have tree view component, use common style for drawing there + if (QSysInfo::s60Version() == QSysInfo::SV_S60_3_1) { +#else + if (true) { +#endif + QCommonStyle::drawPrimitive(element, option, painter, widget); + } else { + const bool rightLine = option->state & State_Item; + const bool downLine = option->state & State_Sibling; + const bool upLine = option->state & (State_Open | State_Children | State_Item | State_Sibling); + + QS60StyleEnums::SkinParts skinPart; + bool drawSkinPart = false; + if (rightLine && downLine && upLine) { + skinPart = QS60StyleEnums::SP_QgnIndiHlLineBranch; + drawSkinPart = true; + } else if (rightLine && upLine) { + skinPart = QS60StyleEnums::SP_QgnIndiHlLineEnd; + drawSkinPart = true; + } else if (upLine && downLine) { + skinPart = QS60StyleEnums::SP_QgnIndiHlLineStraight; + drawSkinPart = true; + } + + if ( drawSkinPart ) + QS60StylePrivate::drawSkinPart(skinPart, painter, option->rect, flags); + + if (option->state & State_Children) { + QS60StyleEnums::SkinParts skinPart = + (option->state & State_Open) ? QS60StyleEnums::SP_QgnIndiHlColSuper : QS60StyleEnums::SP_QgnIndiHlExpSuper; + int minDimension = qMin(option->rect.width(), option->rect.height()); + const int resizeValue = minDimension >> 1; + minDimension += resizeValue; // Adjust the icon bigger because of empty space in svg icon. + QRect iconRect(option->rect.topLeft(), QSize(minDimension, minDimension)); + int verticalMagic(0); + // magic values for positioning svg icon. + if (option->rect.width() <= option->rect.height()) + verticalMagic = 3; + iconRect.translate(3, verticalMagic - resizeValue); + QS60StylePrivate::drawSkinPart(skinPart, painter, iconRect, flags); + } + } + break; + + // todo: items are below with #ifdefs "just in case". in final version, remove all non-required cases + case PE_FrameLineEdit: + case PE_IndicatorButtonDropDown: + case PE_IndicatorDockWidgetResizeHandle: + case PE_PanelTipLabel: + case PE_PanelScrollAreaCorner: + +#ifndef QT_NO_TABBAR + case PE_IndicatorTabTear: // No tab tear in S60 +#endif // QT_NO_TABBAR + case PE_FrameDefaultButton: +#ifndef QT_NO_DOCKWIDGET + case PE_FrameDockWidget: +#endif //QT_NO_DOCKWIDGET +#ifndef QT_NO_PROGRESSBAR + case PE_IndicatorProgressChunk: +#endif //QT_NO_PROGRESSBAR +#ifndef QT_NO_TOOLBAR + case PE_PanelToolBar: +#endif //QT_NO_TOOLBAR +#ifndef QT_NO_COLUMNVIEW + case PE_IndicatorColumnViewArrow: + case PE_IndicatorItemViewItemDrop: +#endif //QT_NO_COLUMNVIEW + case PE_FrameTabBarBase: // since tabs are in S60 always in navipane, let's use common style for tab base in Qt. + default: + QCommonStyle::drawPrimitive(element, option, painter, widget); + } +} + +/*! \reimp */ +int QS60Style::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const +{ + int metricValue = QS60StylePrivate::pixelMetric(metric); + if (metricValue == KNotFound) + metricValue = QCommonStyle::pixelMetric(metric, option, widget); + + if (metric == PM_SubMenuOverlap && widget){ + const QMenu *menu = qobject_cast<const QMenu *>(widget); + if (menu && menu->activeAction() && menu->activeAction()->menu()) { + const int menuWidth = menu->activeAction()->menu()->sizeHint().width(); + metricValue = -menuWidth; + } + } + return metricValue; +} + +/*! \reimp */ +QSize QS60Style::sizeFromContents(ContentsType ct, const QStyleOption *opt, + const QSize &csz, const QWidget *widget) const +{ + QSize sz(csz); + switch (ct) { + case CT_PushButton: + sz = QCommonStyle::sizeFromContents( ct, opt, csz, widget); + if (const QAbstractButton *buttonWidget = (qobject_cast<const QAbstractButton *>(widget))) + if (buttonWidget->isCheckable()) + sz += QSize(pixelMetric(PM_IndicatorWidth) + pixelMetric(PM_CheckBoxLabelSpacing), 0); + break; + case CT_LineEdit: + if (const QStyleOptionFrame *f = qstyleoption_cast<const QStyleOptionFrame *>(opt)) + sz += QSize(2*f->lineWidth, 4*f->lineWidth); + break; + default: + sz = QCommonStyle::sizeFromContents( ct, opt, csz, widget); + break; + } + return sz; +} + +/*! \reimp */ +int QS60Style::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *widget, + QStyleHintReturn *hret) const +{ + int retValue = -1; + switch (sh) { + case SH_Table_GridLineColor: + retValue = QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors,2,0).rgb(); + break; + case SH_GroupBox_TextLabelColor: + retValue = QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors,6,0).rgb(); + break; + case SH_ScrollBar_ScrollWhenPointerLeavesControl: + retValue = true; + break; + case SH_Slider_SnapToValue: + retValue = true; + break; + case SH_Slider_StopMouseOverSlider: + retValue = true; + break; + case SH_LineEdit_PasswordCharacter: + retValue = '*'; + break; + case SH_ComboBox_PopupFrameStyle: + retValue = QFrame::NoFrame | QFrame::Plain; + break; + case SH_Dial_BackgroundRole: + retValue = QPalette::Base; + break; + case SH_ItemView_ActivateItemOnSingleClick: + retValue = true; + break; + case SH_ProgressDialog_TextLabelAlignment: + retValue = (QApplication::layoutDirection() == Qt::LeftToRight) ? + Qt::AlignLeft : + Qt::AlignRight; + break; + case SH_Menu_SubMenuPopupDelay: + retValue = 300; + break; + case SH_Menu_Scrollable: + retValue = true; + break; + case SH_Menu_SelectionWrap: + retValue = true; + break; + case SH_ItemView_ShowDecorationSelected: + retValue = true; + break; + case SH_ToolBar_Movable: + retValue = false; + break; + case SH_BlinkCursorWhenTextSelected: + retValue = true; + break; + default: + break; + } + if (retValue == -1) + retValue = QCommonStyle::styleHint(sh, opt, widget, hret); + return retValue; +} + +/*! \reimp */ +QRect QS60Style::subControlRect(ComplexControl control, const QStyleOptionComplex *option, SubControl scontrol, const QWidget *widget) const +{ + QRect ret; + switch (control) { +#ifndef QT_NO_SCROLLBAR + // This implementation of subControlRect(CC_ScrollBar..) basically just removes the SC_ScrollBarSubLine and SC_ScrollBarAddLine + case CC_ScrollBar: + if (const QStyleOptionSlider *scrollbarOption = qstyleoption_cast<const QStyleOptionSlider *>(option)) { + const QRect scrollBarRect = scrollbarOption->rect; + const bool isHorizontal = scrollbarOption->orientation == Qt::Horizontal; + const int maxlen = isHorizontal ? scrollBarRect.width() : scrollBarRect.height(); + int sliderlen; + + // calculate slider length + if (scrollbarOption->maximum != scrollbarOption->minimum) { + const uint range = scrollbarOption->maximum - scrollbarOption->minimum; + sliderlen = (qint64(scrollbarOption->pageStep) * maxlen) / (range + scrollbarOption->pageStep); + + int slidermin = pixelMetric(PM_ScrollBarSliderMin, scrollbarOption, widget); + if (sliderlen < slidermin || range > (INT_MAX>>1)) + sliderlen = slidermin; + if (sliderlen > maxlen) + sliderlen = maxlen; + } else { + sliderlen = maxlen; + } + + const int sliderstart = sliderPositionFromValue(scrollbarOption->minimum, + scrollbarOption->maximum, + scrollbarOption->sliderPosition, + maxlen - sliderlen, + scrollbarOption->upsideDown); + + switch (scontrol) { + case SC_ScrollBarSubPage: // between top/left button and slider + if (isHorizontal) + ret.setRect(0, 0, sliderstart, scrollBarRect.height()); + else + ret.setRect(0, 0, scrollBarRect.width(), sliderstart); + break; + case SC_ScrollBarAddPage: { // between bottom/right button and slider + const int addPageLength = sliderstart + sliderlen; + if (isHorizontal) + ret = scrollBarRect.adjusted(addPageLength, 0, 0, 0); + else + ret = scrollBarRect.adjusted(0, addPageLength, 0, 0); + } + break; + case SC_ScrollBarGroove: + ret = scrollBarRect; + break; + case SC_ScrollBarSlider: + if (scrollbarOption->orientation == Qt::Horizontal) + ret.setRect(sliderstart, 0, sliderlen, scrollBarRect.height()); + else + ret.setRect(0, sliderstart, scrollBarRect.width(), sliderlen); + break; + case SC_ScrollBarSubLine: // top/left button + case SC_ScrollBarAddLine: // bottom/right button + default: + break; + } + ret = visualRect(scrollbarOption->direction, scrollBarRect, ret); + } + break; +#endif // QT_NO_SCROLLBAR + case CC_SpinBox: + if (const QStyleOptionSpinBox *spinbox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) { + const int frameThickness = spinbox->frame ? pixelMetric(PM_SpinBoxFrameWidth, spinbox, widget) : 0; + const int buttonMargin = spinbox->frame ? 2 : 0; + const int buttonWidth = QS60StylePrivate::pixelMetric(QStyle::PM_ButtonIconSize) + 2*buttonMargin; + QSize buttonSize; + buttonSize.setHeight(qMax(8, spinbox->rect.height() - frameThickness)); + buttonSize.setWidth(buttonWidth); + buttonSize = buttonSize.expandedTo(QApplication::globalStrut()); + + const int y = frameThickness + spinbox->rect.y(); + const int x = spinbox->rect.x() + spinbox->rect.width() - frameThickness - 2*buttonSize.width(); + + switch (scontrol) { + case SC_SpinBoxUp: + if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) + return QRect(); + ret = QRect(x, y, buttonWidth, buttonSize.height()); + break; + case SC_SpinBoxDown: + if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) + return QRect(); + ret = QRect(x+buttonSize.width(), y, buttonWidth, buttonSize.height()); + break; + case SC_SpinBoxEditField: + if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) + ret = QRect( + frameThickness, + frameThickness, + spinbox->rect.width() - 2*frameThickness, + spinbox->rect.height() - 2*frameThickness); + else + ret = QRect( + frameThickness, + frameThickness, + x - frameThickness, + spinbox->rect.height() - 2*frameThickness); + break; + case SC_SpinBoxFrame: + ret = spinbox->rect; + break; + default: + break; + } + ret = visualRect(spinbox->direction, spinbox->rect, ret); + } + break; + case CC_ComboBox: + if (const QStyleOptionComboBox *cmb = qstyleoption_cast<const QStyleOptionComboBox *>(option)) { + ret = cmb->rect; + const int width = cmb->rect.width(); + const int height = cmb->rect.height(); + const int buttonMargin = cmb->frame ? 2 : 0; + // lets use spinbox frame here as well, as no combobox specific value available. + const int frameThickness = cmb->frame ? pixelMetric(PM_SpinBoxFrameWidth, cmb, widget) : 0; + const int buttonWidth = QS60StylePrivate::pixelMetric(QStyle::PM_ButtonIconSize); + const int xposMod = (cmb->rect.x()) + width - buttonMargin - buttonWidth; + const int ypos = cmb->rect.y(); + + QSize buttonSize; + buttonSize.setHeight(qMax(8, (cmb->rect.height()>>1) - frameThickness)); //minimum of 8 pixels + buttonSize.setWidth(buttonWidth+2*buttonMargin); + buttonSize = buttonSize.expandedTo(QApplication::globalStrut()); + switch (scontrol) { + case SC_ComboBoxArrow: + ret.setRect(xposMod, ypos + buttonMargin, buttonWidth, height - 2*buttonMargin); + break; + case SC_ComboBoxEditField: { + const int withFrameX = cmb->rect.x() + cmb->rect.width() - frameThickness - buttonSize.width(); + ret = QRect( + frameThickness, + frameThickness, + withFrameX - frameThickness, + cmb->rect.height() - 2*frameThickness); + } + break; + default: + break; + } + } + break; + case CC_GroupBox: + if (const QStyleOptionGroupBox *groupBox = qstyleoption_cast<const QStyleOptionGroupBox *>(option)) { + ret = QCommonStyle::subControlRect(control, option, scontrol, widget); + switch (scontrol) { + case SC_GroupBoxCheckBox: //fallthrough + case SC_GroupBoxLabel: { + //slightly indent text and boxes, so that dialog border does not mess with them. + const int horizontalSpacing = + QS60StylePrivate::pixelMetric(QStyle::PM_LayoutHorizontalSpacing); + ret.adjust(2,horizontalSpacing-3,0,0); + } + break; + case SC_GroupBoxFrame: { + const QRect textBox = subControlRect(control, option, SC_GroupBoxLabel, widget); + const int tbHeight = textBox.height(); + ret.translate(0, -ret.y()); + // include title to within the groupBox frame + ret.setHeight(ret.height()+tbHeight); + if (widget && ret.bottom() > widget->rect().bottom()) + ret.setBottom(widget->rect().bottom()); + } + break; + default: + break; + } + } + break; + default: + ret = QCommonStyle::subControlRect(control, option, scontrol, widget); + } + return ret; +} + +QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, const QWidget *widget) const +{ + QRect ret; + switch (element) { + case SE_LineEditContents: { + // in S60 the input text box doesn't start from line Edit's TL, but + // a bit indented. + QRect lineEditRect = opt->rect; + const int adjustment = opt->rect.height()>>2; + lineEditRect.adjust(adjustment,0,0,0); + ret = lineEditRect; + } + break; + case SE_TabBarTearIndicator: + ret = QRect(0,0,0,0); + break; + case SE_TabWidgetTabBar: + if (const QStyleOptionTabWidgetFrame *optionTab = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) { + ret = QCommonStyle::subElementRect(element, opt, widget); + + if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) { + const int tabOverlapNoBorder = + QS60StylePrivate::pixelMetric(QStyle::PM_TabBarTabOverlap); + const int tabOverlap = + tabOverlapNoBorder-QS60StylePrivate::pixelMetric(QStyle::PM_DefaultFrameWidth); + const QTabWidget *tab = qobject_cast<const QTabWidget *>(widget); + int gain = (tab) ? tabOverlap * tab->count() : 0; + switch (twf->shape) { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: { + if (widget) { + // make sure that gain does not set the rect outside of widget boundaries + if (twf->direction == Qt::RightToLeft) { + if ((ret.left() - gain) < widget->rect().left()) + gain = widget->rect().left()-ret.left(); + ret.adjust(-gain,0,0,0); + } else { + if ((ret.right() + gain) > widget->rect().right()) + gain = widget->rect().right()-ret.right(); + ret.adjust(0,0,gain,0); + } + } + break; + } + default: { + if (widget) { + if ((ret.bottom() + gain) > widget->rect().bottom()) + gain = widget->rect().bottom()-ret.bottom(); + ret.adjust(0,0,0,gain); + } + break; + } + } + } + } + break; + case SE_ItemViewItemText: + case SE_ItemViewItemDecoration: + if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(opt)) { + const QListWidget *listItem = qobject_cast<const QListWidget *>(widget); + const bool multiSelection = !listItem ? false : + listItem->selectionMode() == QAbstractItemView::MultiSelection || + listItem->selectionMode() == QAbstractItemView::ExtendedSelection || + listItem->selectionMode() == QAbstractItemView::ContiguousSelection; + ret = QCommonStyle::subElementRect(element, opt, widget); + // If both multiselect & check-state, then remove checkbox and move + // text and decoration towards the beginning + if (listItem && + multiSelection && + (vopt->features & QStyleOptionViewItemV2::HasCheckIndicator)) { + const int verticalSpacing = + QS60StylePrivate::pixelMetric(QStyle::PM_LayoutVerticalSpacing); + //const int horizontalSpacing = QS60StylePrivate::pixelMetric(QStyle::PM_LayoutHorizontalSpacing); + const int checkBoxRectWidth = subElementRect(SE_ItemViewItemCheckIndicator, opt, widget).width(); + ret.adjust(-checkBoxRectWidth-verticalSpacing,0,-checkBoxRectWidth-verticalSpacing,0); + } + } else if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) { + const bool checkable = menuItem->checkType != QStyleOptionMenuItem::NotCheckable; + const int indicatorWidth = checkable ? + pixelMetric(PM_ListViewIconSize, opt, widget) : + pixelMetric(PM_SmallIconSize, opt, widget); + ret = menuItem->rect; + + if (element == SE_ItemViewItemDecoration) { + if (menuItem->direction == Qt::RightToLeft) + ret.translate(ret.width()-indicatorWidth, 0); + ret.setWidth(indicatorWidth); + } else { + ret = menuItem->rect; + if (!menuItem->icon.isNull()) + if (menuItem->direction == Qt::LeftToRight) + ret.adjust(indicatorWidth, 0, 0, 0); + else + ret.adjust(0, 0, -indicatorWidth, 0); + + // Make room for submenu indicator + if (menuItem->menuItemType == QStyleOptionMenuItem::SubMenu){ + // submenu indicator is very small, so lets halve the rect + if (menuItem->direction == Qt::LeftToRight) + ret.adjust(0,0,-(indicatorWidth >> 1),0); + else + ret.adjust((indicatorWidth >> 1),0,0,0); + } + } + } + break; + case SE_ItemViewItemCheckIndicator: + if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(opt)) { + const QListWidget *listItem = qobject_cast<const QListWidget *>(widget); + + const bool singleSelection = listItem && + (listItem->selectionMode() == QAbstractItemView::SingleSelection || + listItem->selectionMode() == QAbstractItemView::NoSelection); + const bool checkBoxOnly = (vopt->features & QStyleOptionViewItemV2::HasCheckIndicator) && + listItem && + singleSelection; + + // Selection check mark rect. + const int indicatorWidth = QS60StylePrivate::pixelMetric(QStyle::PM_IndicatorWidth); + const int indicatorHeight = QS60StylePrivate::pixelMetric(QStyle::PM_IndicatorHeight); + const int spacing = QS60StylePrivate::pixelMetric(QStyle::PM_CheckBoxLabelSpacing); + + const int itemHeight = opt->rect.height(); + int heightOffset = 0; + if (indicatorHeight < itemHeight) + heightOffset = ((itemHeight - indicatorHeight)>>1); + if (checkBoxOnly) { + // Move rect and make it slightly smaller, so that + // a) highlight border does not cross the rect + // b) in s60 list checkbox is smaller than normal checkbox + //todo; magic three + ret.setRect(opt->rect.left()+3, opt->rect.top() + heightOffset, + indicatorWidth-3, indicatorHeight-3); + } else { + ret.setRect(opt->rect.right() - indicatorWidth - spacing, opt->rect.top() + heightOffset, + indicatorWidth, indicatorHeight); + } + } else { + ret = QCommonStyle::subElementRect(element, opt, widget); + } + break; + case SE_HeaderLabel: + ret = QCommonStyle::subElementRect(element, opt, widget); + if (qstyleoption_cast<const QStyleOptionHeader *>(opt)) { + // Subtract area needed for line + if (opt->state & State_Horizontal) + ret.setHeight(ret.height() - QS60StylePrivate::pixelMetric(PM_Custom_BoldLineWidth)); + else + ret.setWidth(ret.width() - QS60StylePrivate::pixelMetric(PM_Custom_ThinLineWidth)); + } + ret = visualRect(opt->direction, opt->rect, ret); + break; + case SE_FrameContents: + if (QS60StylePrivate::isTouchSupported()) { + return QCommonStyle::subElementRect(element, opt, widget); + } else if (const QStyleOptionFrameV2 *f = qstyleoption_cast<const QStyleOptionFrameV2 *>(opt)) { + // We shrink the frame contents by focusFrameWidth, so that we can draw the frame around it in keypad navigation mode. + const int frameWidth = QS60StylePrivate::focusRectPenWidth(); + ret = opt->rect.adjusted(frameWidth, frameWidth, -frameWidth, -frameWidth); + ret = visualRect(opt->direction, opt->rect, ret); + } + break; + default: + ret = QCommonStyle::subElementRect(element, opt, widget); + } + return ret; +} + +void QS60Style::polish(QWidget *widget) +{ + Q_D(const QS60Style); + QCommonStyle::polish(widget); + + if (!widget) + return; + + if (false +#ifndef QT_NO_SCROLLBAR + || qobject_cast<QScrollBar *>(widget) +#endif + ) { + widget->setAttribute(Qt::WA_OpaquePaintEvent, false); + } + + if (QS60StylePrivate::drawsOwnThemeBackground(widget)) { + widget->setAttribute(Qt::WA_StyledBackground); + } else if (false +#ifndef QT_NO_MENU + || qobject_cast<const QMenu *> (widget) +#endif // QT_NO_MENU + ) { + widget->setAttribute(Qt::WA_StyledBackground); + } else if (false +#ifndef QT_NO_COMBOBOX + || qobject_cast<const QComboBoxListView *>(widget) +#endif //QT_NO_COMBOBOX + ) { + widget->setAttribute(Qt::WA_StyledBackground); + } + d->setThemePalette(widget); + d->setFont(widget); +} + +void QS60Style::unpolish(QWidget *widget) +{ + if (false + #ifndef QT_NO_SCROLLBAR + || qobject_cast<QScrollBar *>(widget) + #endif + ) + widget->setAttribute(Qt::WA_OpaquePaintEvent); + + if (QS60StylePrivate::drawsOwnThemeBackground(widget)) { + widget->setAttribute(Qt::WA_StyledBackground, false); + } else if (false +#ifndef QT_NO_MENU + || qobject_cast<const QMenu *> (widget) +#endif // QT_NO_MENU + ) { + widget->setAttribute(Qt::WA_StyledBackground, false); + } else if (false +#ifndef QT_NO_COMBOBOX + || qobject_cast<const QComboBoxListView *>(widget) +#endif //QT_NO_COMBOBOX + ) { + widget->setAttribute(Qt::WA_StyledBackground, false); + } + + if (widget) + widget->setPalette(QPalette()); + + QCommonStyle::unpolish(widget); +} + +void QS60Style::polish(QApplication *application) +{ + Q_D(QS60Style); + d->m_originalPalette = application->palette(); + d->setThemePalette(application); +} + +void QS60Style::unpolish(QApplication *application) +{ + Q_UNUSED(application) + Q_D(QS60Style); + const QPalette newPalette = QApplication::style()->standardPalette(); + QApplication::setPalette(newPalette); + QApplicationPrivate::setSystemPalette(d->m_originalPalette); +} + +void QS60Style::setStyleProperty(const char *name, const QVariant &value) +{ + Q_D(QS60Style); + d->setStyleProperty_specific(name, value); +} + +QVariant QS60Style::styleProperty(const char *name) const +{ + Q_D(const QS60Style); + return d->styleProperty_specific(name); +} + +QIcon QS60Style::standardIconImplementation(StandardPixmap standardIcon, + const QStyleOption *option, const QWidget *widget) const +{ + const int iconDimension = QS60StylePrivate::pixelMetric(QStyle::PM_ToolBarIconSize); + const QRect iconSize = (!option) ? QRect(0,0,iconDimension,iconDimension) : option->rect; + QS60StyleEnums::SkinParts part; + QS60StylePrivate::SkinElementFlags adjustedFlags; + if (option) + adjustedFlags = (option->state & State_Enabled) ? + QS60StylePrivate::SF_StateEnabled : + QS60StylePrivate::SF_StateDisabled; + + switch(standardIcon) { + case QStyle::SP_MessageBoxWarning: + part = QS60StyleEnums::SP_QgnNoteWarning; + break; + case QStyle::SP_MessageBoxInformation: + part = QS60StyleEnums::SP_QgnNoteInfo; + break; + case QStyle::SP_MessageBoxCritical: + part = QS60StyleEnums::SP_QgnNoteError; + break; + case QStyle::SP_MessageBoxQuestion: + part = QS60StyleEnums::SP_QgnNoteQuery; + break; + case QStyle::SP_ArrowRight: + part = QS60StyleEnums::SP_QgnIndiNaviArrowRight; + break; + case QStyle::SP_ArrowLeft: + part = QS60StyleEnums::SP_QgnIndiNaviArrowLeft; + break; + case QStyle::SP_ArrowUp: + part = QS60StyleEnums::SP_QgnIndiNaviArrowLeft; + adjustedFlags |= QS60StylePrivate::SF_PointEast; + break; + case QStyle::SP_ArrowDown: + part = QS60StyleEnums::SP_QgnIndiNaviArrowLeft; + adjustedFlags |= QS60StylePrivate::SF_PointWest; + break; + case QStyle::SP_ArrowBack: + if (QApplication::layoutDirection() == Qt::RightToLeft) + return QS60Style::standardIcon(SP_ArrowRight, option, widget); + return QS60Style::standardIcon(SP_ArrowLeft, option, widget); + case QStyle::SP_ArrowForward: + if (QApplication::layoutDirection() == Qt::RightToLeft) + return QS60Style::standardIcon(SP_ArrowLeft, option, widget); + return QS60Style::standardIcon(SP_ArrowRight, option, widget); + case QStyle::SP_ComputerIcon: + part = QS60StyleEnums::SP_QgnPropPhoneMemcLarge; + break; + case QStyle::SP_DirClosedIcon: + part = QS60StyleEnums::SP_QgnPropFolderSmall; + break; + case QStyle::SP_DirOpenIcon: + part = QS60StyleEnums::SP_QgnPropFolderCurrent; + break; + case QStyle::SP_DirIcon: + part = QS60StyleEnums::SP_QgnPropFolderSmall; + break; + case QStyle::SP_FileDialogNewFolder: + part = QS60StyleEnums::SP_QgnPropFolderSmallNew; + break; + case QStyle::SP_FileIcon: + part = QS60StyleEnums::SP_QgnPropFileSmall; + break; + case QStyle::SP_TrashIcon: + part = QS60StyleEnums::SP_QgnNoteErased; + break; + case QStyle::SP_ToolBarHorizontalExtensionButton: + part = QS60StyleEnums::SP_QgnIndiSubMenu; + if (QApplication::layoutDirection() == Qt::RightToLeft) + adjustedFlags |= QS60StylePrivate::SF_PointSouth; + break; + case QStyle::SP_ToolBarVerticalExtensionButton: + adjustedFlags |= QS60StylePrivate::SF_PointEast; + part = QS60StyleEnums::SP_QgnIndiSubMenu; + break; + + default: + return QCommonStyle::standardIconImplementation(standardIcon, option, widget); + } + const QS60StylePrivate::SkinElementFlags flags = adjustedFlags; + const QPixmap cachedPixMap(QS60StylePrivate::cachedPart(part, iconSize.size(), flags)); + return cachedPixMap.isNull() ? + QCommonStyle::standardIconImplementation(standardIcon, option, widget) : QIcon(cachedPixMap); +} + +extern QPoint qt_s60_fill_background_offset(const QWidget *targetWidget); + +bool qt_s60_fill_background(QPainter *painter, const QRegion &rgn, const QPoint &offset, + const QBrush &brush) +{ + const QPixmap backgroundTexture(QS60StylePrivate::backgroundTexture()); + if (backgroundTexture.cacheKey() != brush.texture().cacheKey()) + return false; + + const QPaintDevice *target = painter->device(); + if (target->devType() == QInternal::Widget) { + const QWidget *widget = static_cast<const QWidget *>(target); + const QRegion translated = rgn.translated(offset); + const QVector<QRect> &rects = translated.rects(); + for (int i = 0; i < rects.size(); ++i) { + const QRect rect(rects.at(i)); + painter->drawPixmap(rect.topLeft(), backgroundTexture, + rect.translated(qt_s60_fill_background_offset(widget))); + } + } + return true; +} + +QT_END_NAMESPACE + +#endif // QT_NO_STYLE_S60 || QT_PLUGIN diff --git a/src/gui/styles/qs60style.h b/src/gui/styles/qs60style.h new file mode 100644 index 0000000..21cdd1c --- /dev/null +++ b/src/gui/styles/qs60style.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QS60STYLE_H +#define QS60STYLE_H + +#include <QtGui/qcommonstyle.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#if !defined(QT_NO_STYLE_S60) + +class QS60StylePrivate; + +class Q_GUI_EXPORT QS60Style : public QCommonStyle +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QS60Style) + +public: + QS60Style(); + ~QS60Style(); + + void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = 0) const; + void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const; + void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const; + int pixelMetric(PixelMetric metric, const QStyleOption *option = 0, const QWidget *widget = 0) const; + QSize sizeFromContents(ContentsType ct, const QStyleOption *opt, const QSize &contentsSize, const QWidget *w = 0) const; + int styleHint(StyleHint sh, const QStyleOption *opt = 0, const QWidget *w = 0, + QStyleHintReturn *shret = 0) const; + QRect subControlRect(ComplexControl control, const QStyleOptionComplex *option, SubControl scontrol, const QWidget *widget = 0) const; + QRect subElementRect(SubElement element, const QStyleOption *opt, const QWidget *widget = 0) const; + void polish(QWidget *widget); + void unpolish(QWidget *widget); + void polish(QApplication *application); + void unpolish(QApplication *application); + + void setStyleProperty(const char *name, const QVariant &value); + QVariant styleProperty(const char *name) const; + +#ifndef Q_WS_S60 + static QStringList partKeys(); + static QStringList colorListKeys(); + void setS60Theme(const QHash<QString, QPicture> &parts, + const QHash<QPair<QString , int>, QColor> &colors); + bool loadS60ThemeFromBlob(const QString &blobFile); + bool saveS60ThemeToBlob(const QString &blobFile) const; +#endif // !Q_WS_S60 + +#ifdef Q_WS_S60 +public slots: + void handleDynamicLayoutVariantSwitch(); + void handleSkinChange(); +#endif // Q_WS_S60 + +protected slots: + QIcon standardIconImplementation( + StandardPixmap standardIcon, const QStyleOption * option = 0, const QWidget * widget = 0 ) const; + +private: + Q_DISABLE_COPY(QS60Style) + friend class QStyleFactory; +}; + +#endif // QT_NO_STYLE_S60 + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QS60STYLE_H diff --git a/src/gui/styles/qs60style_p.h b/src/gui/styles/qs60style_p.h new file mode 100644 index 0000000..7240978 --- /dev/null +++ b/src/gui/styles/qs60style_p.h @@ -0,0 +1,501 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QS60STYLE_P_H +#define QS60STYLE_P_H + +#include "qs60style.h" +#include "qcommonstyle_p.h" +#include <QtCore/qhash.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +const int MAX_NON_CUSTOM_PIXELMETRICS = 92; +const int CUSTOMVALUESCOUNT = 4; +enum { + PM_Custom_FrameCornerWidth = MAX_NON_CUSTOM_PIXELMETRICS, + PM_Custom_FrameCornerHeight, + PM_Custom_BoldLineWidth, + PM_Custom_ThinLineWidth + }; +const int MAX_PIXELMETRICS = MAX_NON_CUSTOM_PIXELMETRICS + CUSTOMVALUESCOUNT; + +typedef struct { + unsigned short height; + unsigned short width; + int major_version; + int minor_version; + bool mirroring; // TODO: (nice to have) Use Qt::LayoutDirection + QString layoutName; +} layoutHeader; + +#ifdef Q_OS_SYMBIAN +NONSHARABLE_CLASS (QS60StyleEnums) +#else +class QS60StyleEnums +#endif +: public QObject +{ +#ifndef Q_WS_S60 + Q_OBJECT + Q_ENUMS(FontCategories) + Q_ENUMS(SkinParts) + Q_ENUMS(ColorLists) +#endif // !Q_WS_S60 + +public: + // S60 look-and-feel font categories + enum FontCategories { + FC_Undefined, + FC_Primary, + FC_Secondary, + FC_Title, + FC_PrimarySmall, + FC_Digital + }; + + enum SkinParts { + SP_QgnGrafBarWait, + SP_QgnGrafBarFrameCenter, + SP_QgnGrafBarFrameSideL, + SP_QgnGrafBarFrameSideR, + SP_QgnGrafBarProgress, + SP_QgnGrafScrollArrowDown, + SP_QgnGrafScrollArrowLeft, + SP_QgnGrafScrollArrowRight, + SP_QgnGrafScrollArrowUp, + SP_QgnGrafTabActiveL, + SP_QgnGrafTabActiveM, + SP_QgnGrafTabActiveR, + SP_QgnGrafTabPassiveL, + SP_QgnGrafTabPassiveM, + SP_QgnGrafTabPassiveR, + SP_QgnIndiCheckboxOff, + SP_QgnIndiCheckboxOn, + SP_QgnIndiHlColSuper, // Available in S60 release 3.2 and later. + SP_QgnIndiHlExpSuper, // Available in S60 release 3.2 and later. + SP_QgnIndiHlLineBranch, // Available in S60 release 3.2 and later. + SP_QgnIndiHlLineEnd, // Available in S60 release 3.2 and later. + SP_QgnIndiHlLineStraight, // Available in S60 release 3.2 and later. + SP_QgnIndiMarkedAdd, + SP_QgnIndiNaviArrowLeft, + SP_QgnIndiNaviArrowRight, + SP_QgnIndiRadiobuttOff, + SP_QgnIndiRadiobuttOn, + SP_QgnIndiSliderEdit, + SP_QgnIndiSubMenu, + SP_QgnNoteErased, + SP_QgnNoteError, + SP_QgnNoteInfo, + SP_QgnNoteOk, + SP_QgnNoteQuery, + SP_QgnNoteWarning, + SP_QgnPropFileSmall, + SP_QgnPropFolderCurrent, + SP_QgnPropFolderSmall, + SP_QgnPropFolderSmallNew, + SP_QgnPropPhoneMemcLarge, + SP_QsnCpScrollHandleBottomPressed, //ScrollBar handle, pressed state + SP_QsnCpScrollHandleMiddlePressed, + SP_QsnCpScrollHandleTopPressed, + SP_QsnBgScreen, + SP_QsnCpScrollBgBottom, + SP_QsnCpScrollBgMiddle, + SP_QsnCpScrollBgTop, + SP_QsnCpScrollHandleBottom, + SP_QsnCpScrollHandleMiddle, + SP_QsnCpScrollHandleTop, + SP_QsnFrButtonTbCornerTl, // Button, normal state + SP_QsnFrButtonTbCornerTr, + SP_QsnFrButtonTbCornerBl, + SP_QsnFrButtonTbCornerBr, + SP_QsnFrButtonTbSideT, + SP_QsnFrButtonTbSideB, + SP_QsnFrButtonTbSideL, + SP_QsnFrButtonTbSideR, + SP_QsnFrButtonTbCenter, + SP_QsnFrButtonTbCornerTlPressed, // Button, pressed state + SP_QsnFrButtonTbCornerTrPressed, + SP_QsnFrButtonTbCornerBlPressed, + SP_QsnFrButtonTbCornerBrPressed, + SP_QsnFrButtonTbSideTPressed, + SP_QsnFrButtonTbSideBPressed, + SP_QsnFrButtonTbSideLPressed, + SP_QsnFrButtonTbSideRPressed, + SP_QsnFrButtonTbCenterPressed, + SP_QsnFrCaleCornerTl, // calendar grid item + SP_QsnFrCaleCornerTr, + SP_QsnFrCaleCornerBl, + SP_QsnFrCaleCornerBr, + SP_QsnFrCaleGSideT, + SP_QsnFrCaleGSideB, + SP_QsnFrCaleGSideL, + SP_QsnFrCaleGSideR, + SP_QsnFrCaleCenter, + SP_QsnFrCaleHeadingCornerTl, // calendar grid header + SP_QsnFrCaleHeadingCornerTr, + SP_QsnFrCaleHeadingCornerBl, + SP_QsnFrCaleHeadingCornerBr, + SP_QsnFrCaleHeadingSideT, + SP_QsnFrCaleHeadingSideB, + SP_QsnFrCaleHeadingSideL, + SP_QsnFrCaleHeadingSideR, + SP_QsnFrCaleHeadingCenter, + SP_QsnFrInputCornerTl, // Text input field + SP_QsnFrInputCornerTr, + SP_QsnFrInputCornerBl, + SP_QsnFrInputCornerBr, + SP_QsnFrInputSideT, + SP_QsnFrInputSideB, + SP_QsnFrInputSideL, + SP_QsnFrInputSideR, + SP_QsnFrInputCenter, + SP_QsnFrListCornerTl, // List background + SP_QsnFrListCornerTr, + SP_QsnFrListCornerBl, + SP_QsnFrListCornerBr, + SP_QsnFrListSideT, + SP_QsnFrListSideB, + SP_QsnFrListSideL, + SP_QsnFrListSideR, + SP_QsnFrListCenter, + SP_QsnFrPopupCornerTl, // Option menu background + SP_QsnFrPopupCornerTr, + SP_QsnFrPopupCornerBl, + SP_QsnFrPopupCornerBr, + SP_QsnFrPopupSideT, + SP_QsnFrPopupSideB, + SP_QsnFrPopupSideL, + SP_QsnFrPopupSideR, + SP_QsnFrPopupCenter, + SP_QsnFrPopupPreviewCornerTl, // tool tip background + SP_QsnFrPopupPreviewCornerTr, + SP_QsnFrPopupPreviewCornerBl, + SP_QsnFrPopupPreviewCornerBr, + SP_QsnFrPopupPreviewSideT, + SP_QsnFrPopupPreviewSideB, + SP_QsnFrPopupPreviewSideL, + SP_QsnFrPopupPreviewSideR, + SP_QsnFrPopupPreviewCenter, + SP_QsnFrSetOptCornerTl, // Settings list + SP_QsnFrSetOptCornerTr, + SP_QsnFrSetOptCornerBl, + SP_QsnFrSetOptCornerBr, + SP_QsnFrSetOptSideT, + SP_QsnFrSetOptSideB, + SP_QsnFrSetOptSideL, + SP_QsnFrSetOptSideR, + SP_QsnFrSetOptCenter, + SP_QsnFrPopupSubCornerTl, // Toolbar background + SP_QsnFrPopupSubCornerTr, + SP_QsnFrPopupSubCornerBl, + SP_QsnFrPopupSubCornerBr, + SP_QsnFrPopupSubSideT, + SP_QsnFrPopupSubSideB, + SP_QsnFrPopupSubSideL, + SP_QsnFrPopupSubSideR, + SP_QsnFrPopupSubCenter, + SP_QsnFrSctrlButtonCornerTl, // Toolbar button + SP_QsnFrSctrlButtonCornerTr, + SP_QsnFrSctrlButtonCornerBl, + SP_QsnFrSctrlButtonCornerBr, + SP_QsnFrSctrlButtonSideT, + SP_QsnFrSctrlButtonSideB, + SP_QsnFrSctrlButtonSideL, + SP_QsnFrSctrlButtonSideR, + SP_QsnFrSctrlButtonCenter, + SP_QsnFrSctrlButtonCornerTlPressed, // Toolbar button, pressed + SP_QsnFrSctrlButtonCornerTrPressed, + SP_QsnFrSctrlButtonCornerBlPressed, + SP_QsnFrSctrlButtonCornerBrPressed, + SP_QsnFrSctrlButtonSideTPressed, + SP_QsnFrSctrlButtonSideBPressed, + SP_QsnFrSctrlButtonSideLPressed, + SP_QsnFrSctrlButtonSideRPressed, + SP_QsnFrSctrlButtonCenterPressed, + SP_QsnFrButtonCornerTlInactive, // Inactive button + SP_QsnFrButtonCornerTrInactive, + SP_QsnFrButtonCornerBlInactive, + SP_QsnFrButtonCornerBrInactive, + SP_QsnFrButtonSideTInactive, + SP_QsnFrButtonSideBInactive, + SP_QsnFrButtonSideLInactive, + SP_QsnFrButtonSideRInactive, + SP_QsnFrButtonCenterInactive, + SP_QsnFrNotepadCornerTl, + SP_QsnFrNotepadCornerTr, + SP_QsnFrNotepadCornerBl, + SP_QsnFrNotepadCornerBr, + SP_QsnFrNotepadSideT, + SP_QsnFrNotepadSideB, + SP_QsnFrNotepadSideL, + SP_QsnFrNotepadSideR, + SP_QsnFrNotepadCenter + }; + + enum ColorLists { + CL_QsnHighlightColors, + CL_QsnIconColors, + CL_QsnLineColors, + CL_QsnOtherColors, + CL_QsnParentColors, + CL_QsnTextColors + }; +}; + +// Private class +#ifdef Q_OS_SYMBIAN +NONSHARABLE_CLASS (QS60StylePrivate) +#else +class QS60StylePrivate +#endif +: public QCommonStylePrivate +{ + Q_DECLARE_PUBLIC(QS60Style) + +public: + QS60StylePrivate(); + ~QS60StylePrivate(); + + enum SkinElements { + SE_ButtonNormal, + SE_ButtonPressed, + SE_FrameLineEdit, + SE_ProgressBarGrooveHorizontal, + SE_ProgressBarIndicatorHorizontal, + SE_ProgressBarGrooveVertical, + SE_ProgressBarIndicatorVertical, + SE_ScrollBarGrooveHorizontal, + SE_ScrollBarGrooveVertical, + SE_ScrollBarHandleHorizontal, + SE_ScrollBarHandleVertical, + SE_SliderHandleHorizontal, + SE_SliderHandleVertical, + SE_TabBarTabEastActive, + SE_TabBarTabEastInactive, + SE_TabBarTabNorthActive, + SE_TabBarTabNorthInactive, + SE_TabBarTabSouthActive, + SE_TabBarTabSouthInactive, + SE_TabBarTabWestActive, + SE_TabBarTabWestInactive, + SE_ListHighlight, + SE_OptionsMenu, + SE_SettingsList, + SE_TableItem, + SE_TableHeaderItem, + SE_ToolTip, //own graphic available on 3.2+ releases, + SE_ToolBar, + SE_ToolBarButton, + SE_ToolBarButtonPressed, + SE_PanelBackground, + SE_ScrollBarHandlePressedHorizontal, //only for 5.0+ + SE_ScrollBarHandlePressedVertical, + SE_ButtonInactive, + SE_Editor, + }; + + enum SkinFrameElements { + SF_ButtonNormal, + SF_ButtonPressed, + SF_FrameLineEdit, + SF_ListHighlight, + SF_OptionsMenu, + SF_SettingsList, + SF_TableItem, + SF_TableHeaderItem, + SF_ToolTip, + SF_ToolBar, + SF_ToolBarButton, + SF_ToolBarButtonPressed, + SF_PanelBackground, + SF_ButtonInactive, + SF_Editor, + }; + + enum SkinElementFlag { + SF_PointNorth = 0x0001, // North = the default + SF_PointEast = 0x0002, + SF_PointSouth = 0x0004, + SF_PointWest = 0x0008, + + SF_StateEnabled = 0x0010, // Enabled = the default + SF_StateDisabled = 0x0020, + SF_ColorSkinned = 0x0040, + }; + + enum CacheClearReason { + CC_UndefinedChange = 0, + CC_LayoutChange, + CC_ThemeChange + }; + + Q_DECLARE_FLAGS(SkinElementFlags, SkinElementFlag) + + // draws skin element + static void drawSkinElement(SkinElements element, QPainter *painter, + const QRect &rect, SkinElementFlags flags = KDefaultSkinElementFlags); + // draws a specific skin part + static void drawSkinPart(QS60StyleEnums::SkinParts part, QPainter *painter, + const QRect &rect, SkinElementFlags flags = KDefaultSkinElementFlags); + // sets style property + void setStyleProperty(const char *name, const QVariant &value); + // sets specific style property + void setStyleProperty_specific(const char *name, const QVariant &value); + // gets style property + QVariant styleProperty(const char *name) const; + // gets specific style property + QVariant styleProperty_specific(const char *name) const; + // gets pixel metrics value + static short pixelMetric(int metric); + // gets color. 'index' is NOT 0-based. + // It corresponds to the enum key 1-based numbers of TAknsQsnXYZColorsIndex, not the values. + static QColor s60Color(QS60StyleEnums::ColorLists list, + int index, const QStyleOption *option); + // gets state specific color + static QColor stateColor(const QColor &color, const QStyleOption *option); + // gets lighter color than base color + static QColor lighterColor(const QColor &baseColor); + //deduces if the given widget should have separately themeable background + static bool drawsOwnThemeBackground(const QWidget *widget); + + QFont s60Font(QS60StyleEnums::FontCategories fontCategory, + int pointSize = -1) const; + // clears all style caches (fonts, colors, pixmaps) + void clearCaches(CacheClearReason reason = CC_UndefinedChange); + + // themed main background oprations + void setBackgroundTexture(QApplication *application) const; + static void deleteBackground(); + + static bool isTouchSupported(); + static bool isToolBarBackground(); + + // calculates average color based on button skin graphics (minus borders). + QColor colorFromFrameGraphics(SkinFrameElements frame) const; + + //set theme palette for application + void setThemePalette(QApplication *application) const; + //set theme palette for style option + void setThemePalette(QStyleOption *option) const; + //access to theme palette + static QPalette* themePalette(); + + static int focusRectPenWidth(); + + static const layoutHeader m_layoutHeaders[]; + static const short data[][MAX_PIXELMETRICS]; + + void setCurrentLayout(int layoutIndex); + void setActiveLayout(); + // Pointer + static short const *m_pmPointer; + // number of layouts supported by the style + static const int m_numberOfLayouts; + + mutable QHash<QPair<QS60StyleEnums::FontCategories , int>, QFont> m_mappedFontsCache; + mutable QHash<SkinFrameElements, QColor> m_colorCache; + + // Has one entry per SkinFrameElements + static const struct frameElementCenter { + SkinElements element; + QS60StyleEnums::SkinParts center; + } m_frameElementsData[]; + + static QPixmap frame(SkinFrameElements frame, const QSize &size, + SkinElementFlags flags = KDefaultSkinElementFlags); + static QPixmap backgroundTexture(); + +private: + static void drawPart(QS60StyleEnums::SkinParts part, QPainter *painter, + const QRect &rect, SkinElementFlags flags = KDefaultSkinElementFlags); + static void drawRow(QS60StyleEnums::SkinParts start, QS60StyleEnums::SkinParts middle, + QS60StyleEnums::SkinParts end, Qt::Orientation orientation, QPainter *painter, + const QRect &rect, SkinElementFlags flags = KDefaultSkinElementFlags); + static void drawFrame(SkinFrameElements frame, QPainter *painter, + const QRect &rect, SkinElementFlags flags = KDefaultSkinElementFlags); + + static QPixmap cachedPart(QS60StyleEnums::SkinParts part, const QSize &size, + SkinElementFlags flags = KDefaultSkinElementFlags); + static QPixmap cachedFrame(SkinFrameElements frame, const QSize &size, + SkinElementFlags flags = KDefaultSkinElementFlags); + + static void refreshUI(); + + // set S60 font for widget + void setFont(QWidget *widget) const; + void setThemePalette(QWidget *widget) const; + void setThemePalette(QPalette *palette) const; + void setThemePaletteHash(QPalette *palette) const; + static void storeThemePalette(QPalette *palette); + static void deleteThemePalette(); + + static QSize partSize(QS60StyleEnums::SkinParts part, + SkinElementFlags flags = KDefaultSkinElementFlags); + static QPixmap part(QS60StyleEnums::SkinParts part, const QSize &size, + SkinElementFlags flags = KDefaultSkinElementFlags); + + static QFont s60Font_specific(QS60StyleEnums::FontCategories fontCategory, int pointSize); + + static QSize screenSize(); + + // Contains background texture. + static QPixmap *m_background; + const static SkinElementFlags KDefaultSkinElementFlags; + // defined theme palette + static QPalette *m_themePalette; + QPalette m_originalPalette; +}; + +QT_END_NAMESPACE + +#endif // QS60STYLE_P_H diff --git a/src/gui/styles/qs60style_s60.cpp b/src/gui/styles/qs60style_s60.cpp new file mode 100644 index 0000000..1f02efa --- /dev/null +++ b/src/gui/styles/qs60style_s60.cpp @@ -0,0 +1,1364 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qs60style.h" +#include "qs60style_p.h" +#include "qpainter.h" +#include "qstyleoption.h" +#include "qstyle.h" +#include "private/qwindowsurface_s60_p.h" +#include "private/qt_s60_p.h" +#include "private/qcore_symbian_p.h" +#include "qapplication.h" + +#include <w32std.h> +#include <aknsconstants.h> +#include <aknconsts.h> +#include <aknsitemid.h> +#include <aknsutils.h> +#include <aknsdrawutils.h> +#include <aknsskininstance.h> +#include <aknsbasicbackgroundcontrolcontext.h> +#include <avkon.mbg> +#include <AknFontAccess.h> +#include <AknLayoutFont.h> +#include <aknutils.h> + +#if !defined(QT_NO_STYLE_S60) || defined(QT_PLUGIN) + +QT_BEGIN_NAMESPACE + +enum TDrawType { + EDrawIcon, + EDrawBackground, + ENoDraw +}; + +enum TSupportRelease { + ES60_None = 0x0000, //indicates that the commonstyle should draw the graphics + ES60_3_1 = 0x0001, + ES60_3_2 = 0x0002, + ES60_5_0 = 0x0004, + ES60_5_1 = 0x0008, + ES60_5_2 = 0x0010, + // Add all new releases here + ES60_AllReleases = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1 | ES60_5_2 +}; + +typedef struct { + const TAknsItemID &skinID; + TDrawType drawType; + int supportInfo; + int newMajorSkinId; + int newMinorSkinId; +} partMapEntry; + +class QS60StyleModeSpecifics +{ +public: + static QPixmap skinnedGraphics(QS60StyleEnums::SkinParts stylepart, + const QSize &size, QS60StylePrivate::SkinElementFlags flags); + static QPixmap skinnedGraphics(QS60StylePrivate::SkinFrameElements frameElement, const QSize &size, QS60StylePrivate::SkinElementFlags flags); + static QPixmap colorSkinnedGraphics(const QS60StyleEnums::SkinParts &stylepart, + const QSize &size, QS60StylePrivate::SkinElementFlags flags); + static QColor colorValue(const TAknsItemID &colorGroup, int colorIndex); + static QPixmap fromFbsBitmap(CFbsBitmap *icon, CFbsBitmap *mask, QS60StylePrivate::SkinElementFlags flags, QImage::Format format); + static bool disabledPartGraphic(QS60StyleEnums::SkinParts &part); + static bool disabledFrameGraphic(QS60StylePrivate::SkinFrameElements &frame); + static QPixmap generateMissingThemeGraphic(QS60StyleEnums::SkinParts &part, const QSize &size, QS60StylePrivate::SkinElementFlags flags); + +private: + static QPixmap createSkinnedGraphicsL(QS60StyleEnums::SkinParts part, + const QSize &size, QS60StylePrivate::SkinElementFlags flags); + static QPixmap createSkinnedGraphicsL(QS60StylePrivate::SkinFrameElements frameElement, const QSize &size, QS60StylePrivate::SkinElementFlags flags); + static QPixmap colorSkinnedGraphicsL(const QS60StyleEnums::SkinParts &stylepart, + const QSize &size, QS60StylePrivate::SkinElementFlags flags); + static void frameIdAndCenterId(QS60StylePrivate::SkinFrameElements frameElement, TAknsItemID &frameId, TAknsItemID ¢erId); + static TRect innerRectFromElement(QS60StylePrivate::SkinFrameElements frameElement, const TRect &outerRect); + static void checkAndUnCompressBitmapL(CFbsBitmap*& aOriginalBitmap); + static void checkAndUnCompressBitmap(CFbsBitmap*& aOriginalBitmap); + static void unCompressBitmapL(const TRect& aTrgRect, CFbsBitmap* aTrgBitmap, CFbsBitmap* aSrcBitmap); + static void colorGroupAndIndex(QS60StyleEnums::SkinParts skinID, + TAknsItemID &colorGroup, int colorIndex); + static void fallbackInfo(const QS60StyleEnums::SkinParts &stylepart, TDes& fallbackFileName, TInt& fallbackIndex); + static bool checkSupport(const int supportedRelease); + static TAknsItemID checkAndUpdateReleaseSpecificGraphics(int part); + // Array to match the skin ID, fallback graphics and Qt widget graphics. + static const partMapEntry m_partMap[]; +}; + +const partMapEntry QS60StyleModeSpecifics::m_partMap[] = { + /* SP_QgnGrafBarWait */ {KAknsIIDQgnGrafBarWaitAnim, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafBarFrameCenter */ {KAknsIIDQgnGrafBarFrameCenter, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafBarFrameSideL */ {KAknsIIDQgnGrafBarFrameSideL, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafBarFrameSideR */ {KAknsIIDQgnGrafBarFrameSideR, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafBarProgress */ {KAknsIIDQgnGrafBarProgress, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafScrollArrowDown */ {KAknsIIDQgnGrafScrollArrowDown, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafScrollArrowLeft */ {KAknsIIDQgnGrafScrollArrowLeft, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafScrollArrowRight */ {KAknsIIDQgnGrafScrollArrowRight, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafScrollArrowUp */ {KAknsIIDQgnGrafScrollArrowUp, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafTabActiveL */ {KAknsIIDQgnGrafTabActiveL, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafTabActiveM */ {KAknsIIDQgnGrafTabActiveM, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafTabActiveR */ {KAknsIIDQgnGrafTabActiveR, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafTabPassiveL */ {KAknsIIDQgnGrafTabPassiveL, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafTabPassiveM */ {KAknsIIDQgnGrafTabPassiveM, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnGrafTabPassiveR */ {KAknsIIDQgnGrafTabPassiveR, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiCheckboxOff */ {KAknsIIDQgnIndiCheckboxOff, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiCheckboxOn */ {KAknsIIDQgnIndiCheckboxOn, EDrawIcon, ES60_AllReleases, -1,-1}, + // Following 5 items (SP_QgnIndiHlColSuper - SP_QgnIndiHlLineStraight) are available starting from S60 release 3.2. + // In 3.1 CommonStyle drawing is used for these QTreeView elements, since no similar icons in AVKON UI. + /* SP_QgnIndiHlColSuper */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d5 /* KAknsIIDQgnIndiHlColSuper */}, + /* SP_QgnIndiHlExpSuper */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d6 /* KAknsIIDQgnIndiHlExpSuper */}, + /* SP_QgnIndiHlLineBranch */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d7 /* KAknsIIDQgnIndiHlLineBranch */}, + /* SP_QgnIndiHlLineEnd */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d8 /* KAknsIIDQgnIndiHlLineEnd */}, + /* SP_QgnIndiHlLineStraight */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x17d9 /* KAknsIIDQgnIndiHlLineStraight */}, + /* SP_QgnIndiMarkedAdd */ {KAknsIIDQgnIndiMarkedAdd, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiNaviArrowLeft */ {KAknsIIDQgnGrafScrollArrowLeft, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiNaviArrowRight */ {KAknsIIDQgnGrafScrollArrowRight, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiRadiobuttOff */ {KAknsIIDQgnIndiRadiobuttOff, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiRadiobuttOn */ {KAknsIIDQgnIndiRadiobuttOn, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiSliderEdit */ {KAknsIIDQgnIndiSliderEdit, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnIndiSubMenu */ {KAknsIIDQgnIndiSubmenu, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnNoteErased */ {KAknsIIDQgnNoteErased, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnNoteError */ {KAknsIIDQgnNoteError, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnNoteInfo */ {KAknsIIDQgnNoteInfo, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnNoteOk */ {KAknsIIDQgnNoteOk, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnNoteQuery */ {KAknsIIDQgnNoteQuery, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnNoteWarning */ {KAknsIIDQgnNoteWarning, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnPropFileSmall */ {KAknsIIDQgnPropFileSmall, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnPropFolderCurrent */ {KAknsIIDQgnPropFolderCurrent, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnPropFolderSmall */ {KAknsIIDQgnPropFolderSmall, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnPropFolderSmallNew */ {KAknsIIDQgnPropFolderSmallNew, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QgnPropPhoneMemcLarge */ {KAknsIIDQgnPropPhoneMemcLarge, EDrawIcon, ES60_AllReleases, -1,-1}, + + // 3.1 & 3.2 do not have pressed state for scrollbar, so use normal scrollbar graphics instead. + /* SP_QsnCpScrollHandleBottomPressed*/ {KAknsIIDQsnCpScrollHandleBottom, EDrawIcon, ES60_3_1 | ES60_3_2, EAknsMajorGeneric, 0x20f8}, /*KAknsIIDQsnCpScrollHandleBottomPressed*/ + /* SP_QsnCpScrollHandleMiddlePressed*/ {KAknsIIDQsnCpScrollHandleMiddle, EDrawIcon, ES60_3_1 | ES60_3_2, EAknsMajorGeneric, 0x20f9}, /*KAknsIIDQsnCpScrollHandleMiddlePressed*/ + /* SP_QsnCpScrollHandleTopPressed*/ {KAknsIIDQsnCpScrollHandleTop, EDrawIcon, ES60_3_1 | ES60_3_2, EAknsMajorGeneric, 0x20fa}, /*KAknsIIDQsnCpScrollHandleTopPressed*/ + + /* SP_QsnBgScreen */ {KAknsIIDQsnBgScreen, EDrawBackground, ES60_AllReleases, -1,-1}, + + /* SP_QsnCpScrollBgBottom */ {KAknsIIDQsnCpScrollBgBottom, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QsnCpScrollBgMiddle */ {KAknsIIDQsnCpScrollBgMiddle, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QsnCpScrollBgTop */ {KAknsIIDQsnCpScrollBgTop, EDrawIcon, ES60_AllReleases, -1,-1}, + + /* SP_QsnCpScrollHandleBottom */ {KAknsIIDQsnCpScrollHandleBottom, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QsnCpScrollHandleMiddle */ {KAknsIIDQsnCpScrollHandleMiddle, EDrawIcon, ES60_AllReleases, -1,-1}, + /* SP_QsnCpScrollHandleTop */ {KAknsIIDQsnCpScrollHandleTop, EDrawIcon, ES60_AllReleases, -1,-1}, + + /* SP_QsnFrButtonTbCornerTl */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, //todo: use "normal button" from 5.0 onwards + /* SP_QsnFrButtonTbCornerTr */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbCornerBl */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbCornerBr */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbSideT */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbSideB */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbSideL */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbSideR */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbCenter */ {KAknsIIDQsnFrButtonTbCenter, EDrawIcon, ES60_AllReleases, -1,-1}, + + /* SP_QsnFrButtonTbCornerTlPressed */{KAknsIIDQsnFrButtonTbCornerTlPressed, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbCornerTrPressed */{KAknsIIDQsnFrButtonTbCornerTrPressed, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbCornerBlPressed */{KAknsIIDQsnFrButtonTbCornerBlPressed, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbCornerBrPressed */{KAknsIIDQsnFrButtonTbCornerBrPressed, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbSideTPressed */ {KAknsIIDQsnFrButtonTbSideTPressed, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbSideBPressed */ {KAknsIIDQsnFrButtonTbSideBPressed, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbSideLPressed */ {KAknsIIDQsnFrButtonTbSideLPressed, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbSideRPressed */ {KAknsIIDQsnFrButtonTbSideRPressed, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrButtonTbCenterPressed */ {KAknsIIDQsnFrButtonTbCenterPressed, EDrawIcon, ES60_AllReleases, -1,-1}, + + /* SP_QsnFrCaleCornerTl */ {KAknsIIDQsnFrCaleCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleCornerTr */ {KAknsIIDQsnFrCaleCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleCornerBl */ {KAknsIIDQsnFrCaleCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleCornerBr */ {KAknsIIDQsnFrCaleCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleGSideT */ {KAknsIIDQsnFrCaleSideT, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleGSideB */ {KAknsIIDQsnFrCaleSideB, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleGSideL */ {KAknsIIDQsnFrCaleSideL, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleGSideR */ {KAknsIIDQsnFrCaleSideR, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleCenter */ {KAknsIIDQsnFrCaleCenter, ENoDraw, ES60_AllReleases, -1,-1}, + + /* SP_QsnFrCaleHeadingCornerTl */ {KAknsIIDQsnFrCaleHeadingCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleHeadingCornerTr */ {KAknsIIDQsnFrCaleHeadingCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleHeadingCornerBl */ {KAknsIIDQsnFrCaleHeadingCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleHeadingCornerBr */ {KAknsIIDQsnFrCaleHeadingCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleHeadingSideT */ {KAknsIIDQsnFrCaleHeadingSideT, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleHeadingSideB */ {KAknsIIDQsnFrCaleHeadingSideB, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleHeadingSideL */ {KAknsIIDQsnFrCaleHeadingSideL, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleHeadingSideR */ {KAknsIIDQsnFrCaleHeadingSideR, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrCaleHeadingCenter */ {KAknsIIDQsnFrCaleHeadingCenter, ENoDraw, ES60_AllReleases, -1,-1}, + + /* SP_QsnFrInputCornerTl */ {KAknsIIDQsnFrInputCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrInputCornerTr */ {KAknsIIDQsnFrInputCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrInputCornerBl */ {KAknsIIDQsnFrInputCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrInputCornerBr */ {KAknsIIDQsnFrInputCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrInputSideT */ {KAknsIIDQsnFrInputSideT, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrInputSideB */ {KAknsIIDQsnFrInputSideB, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrInputSideL */ {KAknsIIDQsnFrInputSideL, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrInputSideR */ {KAknsIIDQsnFrInputSideR, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrInputCenter */ {KAknsIIDQsnFrInputCenter, ENoDraw, ES60_AllReleases, -1,-1}, + + /* SP_QsnFrListCornerTl */ {KAknsIIDQsnFrListCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrListCornerTr */ {KAknsIIDQsnFrListCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrListCornerBl */ {KAknsIIDQsnFrListCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrListCornerBr */ {KAknsIIDQsnFrListCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrListSideT */ {KAknsIIDQsnFrListSideT, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrListSideB */ {KAknsIIDQsnFrListSideB, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrListSideL */ {KAknsIIDQsnFrListSideL, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrListSideR */ {KAknsIIDQsnFrListSideR, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrListCenter */ {KAknsIIDQsnFrListCenter, ENoDraw, ES60_AllReleases, -1,-1}, + + /* SP_QsnFrPopupCornerTl */ {KAknsIIDQsnFrPopupCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupCornerTr */ {KAknsIIDQsnFrPopupCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupCornerBl */ {KAknsIIDQsnFrPopupCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupCornerBr */ {KAknsIIDQsnFrPopupCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupSideT */ {KAknsIIDQsnFrPopupSideT, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupSideB */ {KAknsIIDQsnFrPopupSideB, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupSideL */ {KAknsIIDQsnFrPopupSideL, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupSideR */ {KAknsIIDQsnFrPopupSideR, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrPopupCenter */ {KAknsIIDQsnFrPopupCenter, ENoDraw, ES60_AllReleases, -1,-1}, + + // ToolTip graphics different in 3.1 vs. 3.2+. + /* SP_QsnFrPopupPreviewCornerTl */ {KAknsIIDQsnFrPopupCornerTl, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c5}, /* KAknsIIDQsnFrPopupPreviewCornerTl */ + /* SP_QsnFrPopupPreviewCornerTr */ {KAknsIIDQsnFrPopupCornerTr, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c6}, + /* SP_QsnFrPopupPreviewCornerBl */ {KAknsIIDQsnFrPopupCornerBl, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c3}, + /* SP_QsnFrPopupPreviewCornerBr */ {KAknsIIDQsnFrPopupCornerBr, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c4}, + /* SP_QsnFrPopupPreviewSideT */ {KAknsIIDQsnFrPopupSideT, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19ca}, + /* SP_QsnFrPopupPreviewSideB */ {KAknsIIDQsnFrPopupSideB, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c7}, + /* SP_QsnFrPopupPreviewSideL */ {KAknsIIDQsnFrPopupSideL, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c8}, + /* SP_QsnFrPopupPreviewSideR */ {KAknsIIDQsnFrPopupSideR, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c9}, + /* SP_QsnFrPopupPreviewCenter */ {KAknsIIDQsnFrPopupCenter, ENoDraw, ES60_3_1, EAknsMajorSkin, 0x19c2}, + + /* SP_QsnFrSetOptCornerTl */ {KAknsIIDQsnFrSetOptCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrSetOptCornerTr */ {KAknsIIDQsnFrSetOptCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrSetOptCornerBl */ {KAknsIIDQsnFrSetOptCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrSetOptCornerBr */ {KAknsIIDQsnFrSetOptCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrSetOptSideT */ {KAknsIIDQsnFrSetOptSideT, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrSetOptSideB */ {KAknsIIDQsnFrSetOptSideB, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrSetOptSideL */ {KAknsIIDQsnFrSetOptSideL, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrSetOptSideR */ {KAknsIIDQsnFrSetOptSideR, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrSetOptCenter */ {KAknsIIDQsnFrSetOptCenter, ENoDraw, ES60_AllReleases, -1,-1}, + + // No toolbar frame for 5.0+ releases. + /* SP_QsnFrPopupSubCornerTl */ {KAknsIIDQsnFrPopupSubCornerTl, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubCornerTr */ {KAknsIIDQsnFrPopupSubCornerTr, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubCornerBl */ {KAknsIIDQsnFrPopupSubCornerBl, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubCornerBr */ {KAknsIIDQsnFrPopupSubCornerBr, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubSideT */ {KAknsIIDQsnFrPopupSubSideT, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubSideB */ {KAknsIIDQsnFrPopupSubSideB, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubSideL */ {KAknsIIDQsnFrPopupSubSideL, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubSideR */ {KAknsIIDQsnFrPopupSubSideR, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + /* SP_QsnFrPopupSubCenter */ {KAknsIIDQsnFrPopupCenterSubmenu, ENoDraw, ES60_3_1 | ES60_3_2, -1,-1}, + + // Toolbar graphics is different in 3.1/3.2 vs. 5.0 + /* SP_QsnFrSctrlButtonCornerTl */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2301}, /* KAknsIIDQgnFrSctrlButtonCornerTl*/ + /* SP_QsnFrSctrlButtonCornerTr */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2302}, + /* SP_QsnFrSctrlButtonCornerBl */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2303}, + /* SP_QsnFrSctrlButtonCornerBr */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2304}, + /* SP_QsnFrSctrlButtonSideT */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2305}, + /* SP_QsnFrSctrlButtonSideB */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2306}, + /* SP_QsnFrSctrlButtonSideL */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2307}, + /* SP_QsnFrSctrlButtonSideR */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2308}, + /* SP_QsnFrSctrlButtonCenter */ {KAknsIIDQsnFrButtonTbCenter, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2309}, /*KAknsIIDQgnFrSctrlButtonCenter*/ + + // No pressed state for toolbar button in 3.1/3.2. + /* SP_QsnFrSctrlButtonCornerTlPressed */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2621}, /*KAknsIIDQsnFrSctrlButtonCornerTlPressed*/ + /* SP_QsnFrSctrlButtonCornerTrPressed */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2622}, + /* SP_QsnFrSctrlButtonCornerBlPressed */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2623}, + /* SP_QsnFrSctrlButtonCornerBrPressed */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2624}, + /* SP_QsnFrSctrlButtonSideTPressed */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2625}, + /* SP_QsnFrSctrlButtonSideBPressed */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2626}, + /* SP_QsnFrSctrlButtonSideLPressed */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2627}, + /* SP_QsnFrSctrlButtonSideRPressed */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2628}, + /* SP_QsnFrSctrlButtonCenterPressed */ {KAknsIIDQsnFrButtonTbCenter, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x2629}, + + // No inactive button graphics in 3.1/3.2 + /* SP_QsnFrButtonCornerTlInactive */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b1}, /*KAknsIIDQsnFrButtonCornerTlInactive*/ + /* SP_QsnFrButtonCornerTrInactive */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b2}, + /* SP_QsnFrButtonCornerBlInactive */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b3}, + /* SP_QsnFrButtonCornerTrInactive */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b4}, + /* SP_QsnFrButtonSideTInactive */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b5}, + /* SP_QsnFrButtonSideBInactive */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b6}, + /* SP_QsnFrButtonSideLInactive */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b7}, + /* SP_QsnFrButtonSideRInactive */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b8}, + /* SP_QsnFrButtonCenterInactive */ {KAknsIIDQsnFrButtonTbCenter, EDrawIcon, ES60_3_1 | ES60_3_2, EAknsMajorSkin, 0x21b9}, + + /*SP_QsnFrNotepadCornerTl */ {KAknsIIDQsnFrNotepadCornerTl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrNotepadCornerTr */ {KAknsIIDQsnFrNotepadCornerTr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrNotepadCornerBl */ {KAknsIIDQsnFrNotepadCornerBl, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrNotepadCornerBr */ {KAknsIIDQsnFrNotepadCornerBr, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrNotepadSideT */ {KAknsIIDQsnFrNotepadSideT, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrNotepadSideB */ {KAknsIIDQsnFrNotepadSideB, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrNotepadSideL */ {KAknsIIDQsnFrNotepadSideL, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrNotepadSideR */ {KAknsIIDQsnFrNotepadSideR, ENoDraw, ES60_AllReleases, -1,-1}, + /* SP_QsnFrNotepadCenter */ {KAknsIIDQsnFrNotepadCenter, EDrawIcon, ES60_AllReleases, -1,-1} + +}; + +QPixmap QS60StyleModeSpecifics::skinnedGraphics( + QS60StyleEnums::SkinParts stylepart, const QSize &size, + QS60StylePrivate::SkinElementFlags flags) +{ + QPixmap themedImage; + TRAPD( error, { + const QPixmap skinnedImage = createSkinnedGraphicsL(stylepart, size, flags); + themedImage = skinnedImage; + }); + if (error) + return themedImage = QPixmap(); + return themedImage; +} + +QPixmap QS60StyleModeSpecifics::skinnedGraphics( + QS60StylePrivate::SkinFrameElements frame, const QSize &size, QS60StylePrivate::SkinElementFlags flags) +{ + QPixmap themedImage; + TRAPD( error, { + const QPixmap skinnedImage = createSkinnedGraphicsL(frame, size, flags); + themedImage = skinnedImage; + }); + if (error) + return themedImage = QPixmap(); + return themedImage; +} + +QPixmap QS60StyleModeSpecifics::colorSkinnedGraphics( + const QS60StyleEnums::SkinParts &stylepart, + const QSize &size, QS60StylePrivate::SkinElementFlags flags) +{ + QPixmap colorGraphics; + TRAPD(error, colorGraphics = colorSkinnedGraphicsL(stylepart, size, flags)); + return error ? QPixmap() : colorGraphics; +} + +void QS60StyleModeSpecifics::fallbackInfo(const QS60StyleEnums::SkinParts &stylepart, TDes& fallbackFileName, TInt& fallbackIndex) +{ + switch(stylepart) { + case QS60StyleEnums::SP_QgnGrafBarWait: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_bar_wait_1; + break; + case QS60StyleEnums::SP_QgnGrafBarFrameCenter: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_bar_frame_center; + break; + case QS60StyleEnums::SP_QgnGrafBarFrameSideL: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_bar_frame_side_l; + break; + case QS60StyleEnums::SP_QgnGrafBarFrameSideR: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_bar_frame_side_r; + break; + case QS60StyleEnums::SP_QgnGrafBarProgress: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_bar_progress; + break; + case QS60StyleEnums::SP_QgnGrafTabActiveL: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_tab_active_l; + break; + case QS60StyleEnums::SP_QgnGrafTabActiveM: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_tab_active_m; + break; + case QS60StyleEnums::SP_QgnGrafTabActiveR: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_tab_active_r; + break; + case QS60StyleEnums::SP_QgnGrafTabPassiveL: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_tab_passive_l; + break; + case QS60StyleEnums::SP_QgnGrafTabPassiveM: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_tab_passive_m; + break; + case QS60StyleEnums::SP_QgnGrafTabPassiveR: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_graf_tab_passive_r; + break; + case QS60StyleEnums::SP_QgnIndiCheckboxOff: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_checkbox_off; + break; + case QS60StyleEnums::SP_QgnIndiCheckboxOn: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_checkbox_on; + break; + case QS60StyleEnums::SP_QgnIndiHlColSuper: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = 0x4456; /* EMbmAvkonQgn_indi_hl_col_super */ + break; + case QS60StyleEnums::SP_QgnIndiHlExpSuper: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = 0x4458; /* EMbmAvkonQgn_indi_hl_exp_super */ + break; + case QS60StyleEnums::SP_QgnIndiHlLineBranch: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = 0x445A; /* EMbmAvkonQgn_indi_hl_line_branch */ + break; + case QS60StyleEnums::SP_QgnIndiHlLineEnd: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = 0x445C; /* EMbmAvkonQgn_indi_hl_line_end */ + break; + case QS60StyleEnums::SP_QgnIndiHlLineStraight: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = 0x445E; /* EMbmAvkonQgn_indi_hl_line_straight */ + break; + case QS60StyleEnums::SP_QgnIndiMarkedAdd: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_marked_add; + break; + case QS60StyleEnums::SP_QgnIndiNaviArrowLeft: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_navi_arrow_left; + break; + case QS60StyleEnums::SP_QgnIndiNaviArrowRight: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_navi_arrow_right; + break; + case QS60StyleEnums::SP_QgnIndiRadiobuttOff: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_radiobutt_off; + break; + case QS60StyleEnums::SP_QgnIndiRadiobuttOn: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_radiobutt_on; + break; + case QS60StyleEnums::SP_QgnIndiSliderEdit: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_slider_edit; + break; + case QS60StyleEnums::SP_QgnIndiSubMenu: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_indi_submenu; + break; + case QS60StyleEnums::SP_QgnNoteErased: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_note_erased; + break; + case QS60StyleEnums::SP_QgnNoteError: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_note_error; + break; + case QS60StyleEnums::SP_QgnNoteInfo: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_note_info; + break; + case QS60StyleEnums::SP_QgnNoteOk: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_note_ok; + break; + case QS60StyleEnums::SP_QgnNoteQuery: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_note_query; + break; + case QS60StyleEnums::SP_QgnNoteWarning: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_note_warning; + break; + case QS60StyleEnums::SP_QgnPropFileSmall: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_prop_file_small; + break; + case QS60StyleEnums::SP_QgnPropFolderCurrent: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_prop_folder_current; + break; + case QS60StyleEnums::SP_QgnPropFolderSmall: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_prop_folder_small; + break; + case QS60StyleEnums::SP_QgnPropFolderSmallNew: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_prop_folder_small_new; + break; + case QS60StyleEnums::SP_QgnPropPhoneMemcLarge: + fallbackFileName = KAvkonBitmapFile(); + fallbackIndex = EMbmAvkonQgn_prop_phone_memc_large; + break; + default: + fallbackFileName = KNullDesC(); + fallbackIndex = -1; + break; + } +} + +QPixmap QS60StyleModeSpecifics::colorSkinnedGraphicsL( + const QS60StyleEnums::SkinParts &stylepart, + const QSize &size, QS60StylePrivate::SkinElementFlags flags) +{ + const int stylepartIndex = (int)stylepart; + const TAknsItemID skinId = m_partMap[stylepartIndex].skinID; + + TInt fallbackGraphicID = -1; + HBufC* iconFile = HBufC::NewLC( KMaxFileName ); + TPtr fileNamePtr = iconFile->Des(); + fallbackInfo(stylepart, fileNamePtr, fallbackGraphicID); + + TAknsItemID colorGroup = KAknsIIDQsnIconColors; + int colorIndex = 0; + colorGroupAndIndex(stylepart, colorGroup, colorIndex); + + const bool rotatedBy90or270 = + (flags & (QS60StylePrivate::SF_PointEast | QS60StylePrivate::SF_PointWest)); + const TSize targetSize = + rotatedBy90or270?TSize(size.height(), size.width()):TSize(size.width(), size.height()); + CFbsBitmap *icon = 0; + CFbsBitmap *iconMask = 0; + const TInt fallbackGraphicsMaskID = + fallbackGraphicID == KErrNotFound?KErrNotFound:fallbackGraphicID+1; //masks are auto-generated as next in mif files + MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance(); + AknsUtils::CreateColorIconLC( + skinInstance, skinId, colorGroup, colorIndex, icon, iconMask, fileNamePtr, fallbackGraphicID , fallbackGraphicsMaskID, KRgbBlack); + User::LeaveIfError(AknIconUtils::SetSize(icon, targetSize, EAspectRatioNotPreserved)); + User::LeaveIfError(AknIconUtils::SetSize(iconMask, targetSize, EAspectRatioNotPreserved)); + QPixmap result = fromFbsBitmap(icon, iconMask, flags, qt_TDisplayMode2Format(icon->DisplayMode())); + CleanupStack::PopAndDestroy(3); //icon, iconMask, iconFile + return result; +} + +QColor QS60StyleModeSpecifics::colorValue(const TAknsItemID &colorGroup, int colorIndex) +{ + TRgb skinnedColor; + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + AknsUtils::GetCachedColor(skin, skinnedColor, colorGroup, colorIndex); + return QColor(skinnedColor.Red(),skinnedColor.Green(),skinnedColor.Blue()); +} + +QPixmap QS60StyleModeSpecifics::fromFbsBitmap(CFbsBitmap *icon, CFbsBitmap *mask, QS60StylePrivate::SkinElementFlags flags, QImage::Format format) +{ + Q_ASSERT(icon); + const TSize iconSize = icon->SizeInPixels(); + const int iconBytesPerLine = CFbsBitmap::ScanLineLength(iconSize.iWidth, icon->DisplayMode()); + const int iconBytesCount = iconBytesPerLine * iconSize.iHeight; + + QImage iconImage(qt_TSize2QSize(iconSize), format); + if (iconImage.isNull()) + return QPixmap(); + + checkAndUnCompressBitmap(icon); + if (!icon) //checkAndUnCompressBitmap might set icon to NULL + return QPixmap(); + + icon->LockHeap(); + const uchar *const iconBytes = (uchar*)icon->DataAddress(); + // The icon data needs to be copied, since the color format will be + // automatically converted to Format_ARGB32 when setAlphaChannel is called. + memcpy(iconImage.bits(), iconBytes, iconBytesCount); + icon->UnlockHeap(); + if (mask) { + checkAndUnCompressBitmap(mask); + if (mask) { //checkAndUnCompressBitmap might set mask to NULL + const TSize maskSize = icon->SizeInPixels(); + const int maskBytesPerLine = CFbsBitmap::ScanLineLength(maskSize.iWidth, mask->DisplayMode()); + mask->LockHeap(); + const uchar *const maskBytes = (uchar *)mask->DataAddress(); + // Since no other bitmap should be locked, we can just "borrow" the mask data for setAlphaChannel + const QImage maskImage(maskBytes, maskSize.iWidth, maskSize.iHeight, maskBytesPerLine, QImage::Format_Indexed8); + if (!maskImage.isNull()) + iconImage.setAlphaChannel(maskImage); + mask->UnlockHeap(); + } + } + + QTransform imageTransform; + if (flags & QS60StylePrivate::SF_PointEast) { + imageTransform.rotate(90); + } else if (flags & QS60StylePrivate::SF_PointSouth) { + imageTransform.rotate(180); + iconImage = iconImage.transformed(imageTransform); + } else if (flags & QS60StylePrivate::SF_PointWest) { + imageTransform.rotate(270); + } + if (imageTransform.isRotating()) + iconImage = iconImage.transformed(imageTransform); + + return QPixmap::fromImage(iconImage); +} + +bool QS60StylePrivate::isTouchSupported() +{ + return bool(AknLayoutUtils::PenEnabled()); +} + +bool QS60StylePrivate::isToolBarBackground() +{ + return (QSysInfo::s60Version() == QSysInfo::SV_S60_3_1 || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2); +} + +QPoint qt_s60_fill_background_offset(const QWidget *targetWidget) +{ + CCoeControl *control = targetWidget->effectiveWinId(); + TPoint globalPos = control ? control->PositionRelativeToScreen() : TPoint(0,0); + return QPoint(globalPos.iX, globalPos.iY); +} + +QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsL( + QS60StyleEnums::SkinParts part, + const QSize &size, QS60StylePrivate::SkinElementFlags flags) +{ + if (!size.isValid()) + return QPixmap(); + + // Check release support and change part, if necessary. + const TAknsItemID skinId = checkAndUpdateReleaseSpecificGraphics((int)part); + const int stylepartIndex = (int)part; + const TDrawType drawType = m_partMap[stylepartIndex].drawType; + Q_ASSERT(drawType != ENoDraw); + const bool rotatedBy90or270 = + (flags & (QS60StylePrivate::SF_PointEast | QS60StylePrivate::SF_PointWest)); + const TSize targetSize = + rotatedBy90or270 ? TSize(size.height(), size.width()) : qt_QSize2TSize(size); + + MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance(); + + QPixmap result; + + switch (drawType) { + case EDrawIcon: { + TInt fallbackGraphicID = -1; + HBufC* iconFile = HBufC::NewLC( KMaxFileName ); + TPtr fileNamePtr = iconFile->Des(); + fallbackInfo(part, fileNamePtr, fallbackGraphicID); + // todo: could we instead use AknIconUtils::AvkonIconFileName(); to avoid allocating each time? + + CFbsBitmap *icon = 0; + CFbsBitmap *iconMask = 0; + const TInt fallbackGraphicsMaskID = + fallbackGraphicID == KErrNotFound?KErrNotFound:fallbackGraphicID+1; //masks are auto-generated as next in mif files + // QS60WindowSurface::unlockBitmapHeap(); + AknsUtils::CreateIconLC(skinInstance, skinId, icon, iconMask, fileNamePtr, fallbackGraphicID , fallbackGraphicsMaskID); + User::LeaveIfError(AknIconUtils::SetSize(icon, targetSize, EAspectRatioNotPreserved)); + User::LeaveIfError(AknIconUtils::SetSize(iconMask, targetSize, EAspectRatioNotPreserved)); + result = fromFbsBitmap(icon, iconMask, flags, qt_TDisplayMode2Format(icon->DisplayMode())); + CleanupStack::PopAndDestroy(3); // iconMask, icon, iconFile + // QS60WindowSurface::lockBitmapHeap(); + break; + } + case EDrawBackground: { + // QS60WindowSurface::unlockBitmapHeap(); + CFbsBitmap *background = new (ELeave) CFbsBitmap(); //offscreen + CleanupStack::PushL(background); + User::LeaveIfError(background->Create(targetSize, EColor16MA)); + + CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL(background); + CleanupStack::PushL(dev); + CFbsBitGc* gc = NULL; + User::LeaveIfError(dev->CreateContext(gc)); + CleanupStack::PushL(gc); + + CAknsBasicBackgroundControlContext* bgContext = CAknsBasicBackgroundControlContext::NewL( + skinId, + targetSize, + EFalse); + CleanupStack::PushL(bgContext); + + const TBool drawn = AknsDrawUtils::DrawBackground( + skinInstance, + bgContext, + NULL, + *gc, + TPoint(), + targetSize, + KAknsDrawParamDefault | KAknsDrawParamRGBOnly); + + if (drawn) + result = fromFbsBitmap(background, NULL, flags, QImage::Format_RGB32); + + CleanupStack::PopAndDestroy(4, background); //background, dev, gc, bgContext + // QS60WindowSurface::lockBitmapHeap(); + break; + } + } + + return result; +} + +QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsL(QS60StylePrivate::SkinFrameElements frameElement, + const QSize &size, QS60StylePrivate::SkinElementFlags flags) +{ + if (!size.isValid()) + return QPixmap(); + + const bool rotatedBy90or270 = + (flags & (QS60StylePrivate::SF_PointEast | QS60StylePrivate::SF_PointWest)); + const TSize targetSize = + rotatedBy90or270 ? TSize(size.height(), size.width()) : qt_QSize2TSize(size); + + MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance(); + QPixmap result; + +// QS60WindowSurface::unlockBitmapHeap(); + static const bool canDoEColor16MAP = !(QSysInfo::s60Version() == QSysInfo::SV_S60_3_1 || QSysInfo::s60Version() == QSysInfo::SV_S60_3_2); + static const TDisplayMode displayMode = canDoEColor16MAP ? TDisplayMode(13) : EColor16MA; // 13 = EColor16MAP + static const TInt drawParam = canDoEColor16MAP ? KAknsDrawParamDefault : KAknsDrawParamNoClearUnderImage|KAknsDrawParamRGBOnly; + + CFbsBitmap *frame = new (ELeave) CFbsBitmap(); //offscreen + CleanupStack::PushL(frame); + User::LeaveIfError(frame->Create(targetSize, displayMode)); + + CFbsBitmapDevice* bitmapDev = CFbsBitmapDevice::NewL(frame); + CleanupStack::PushL(bitmapDev); + CFbsBitGc* bitmapGc = NULL; + User::LeaveIfError(bitmapDev->CreateContext(bitmapGc)); + CleanupStack::PushL(bitmapGc); + + frame->LockHeap(); + memset(frame->DataAddress(), 0, frame->SizeInPixels().iWidth * frame->SizeInPixels().iHeight * 4); // 4: argb bytes + frame->UnlockHeap(); + + const TRect outerRect(TPoint(0, 0), targetSize); + const TRect innerRect = innerRectFromElement(frameElement, outerRect); + + TAknsItemID frameSkinID, centerSkinID; + frameSkinID = centerSkinID = checkAndUpdateReleaseSpecificGraphics(QS60StylePrivate::m_frameElementsData[frameElement].center); + frameIdAndCenterId(frameElement, frameSkinID, centerSkinID); + const TBool drawn = AknsDrawUtils::DrawFrame( skinInstance, + *bitmapGc, outerRect, innerRect, + frameSkinID, centerSkinID, + drawParam ); + + if (canDoEColor16MAP) { + if (drawn) + result = fromFbsBitmap(frame, NULL, flags, QImage::Format_ARGB32_Premultiplied); + } else { + TDisplayMode maskDepth = EGray2; + // Query the skin item for possible frame graphics mask details. + if (skinInstance) { + CAknsMaskedBitmapItemData* skinMaskedBmp = static_cast<CAknsMaskedBitmapItemData*>( + skinInstance->GetCachedItemData(frameSkinID,EAknsITMaskedBitmap)); + if (skinMaskedBmp && skinMaskedBmp->Mask()) + maskDepth = skinMaskedBmp->Mask()->DisplayMode(); + } + if (maskDepth != ENone) { + CFbsBitmap *frameMask = new (ELeave) CFbsBitmap(); //offscreen + CleanupStack::PushL(frameMask); + User::LeaveIfError(frameMask->Create(targetSize, maskDepth)); + + CFbsBitmapDevice* maskBitmapDevice = CFbsBitmapDevice::NewL(frameMask); + CleanupStack::PushL(maskBitmapDevice); + CFbsBitGc* maskBitGc = NULL; + User::LeaveIfError(maskBitmapDevice->CreateContext(maskBitGc)); + CleanupStack::PushL(maskBitGc); + + if (drawn) { + //ensure that the mask is really transparent + maskBitGc->Activate( maskBitmapDevice ); + maskBitGc->SetPenStyle(CGraphicsContext::ENullPen); + maskBitGc->SetBrushStyle(CGraphicsContext::ESolidBrush); + maskBitGc->SetBrushColor(KRgbWhite); + maskBitGc->Clear(); + maskBitGc->SetBrushStyle(CGraphicsContext::ENullBrush); + + AknsDrawUtils::DrawFrame(skinInstance, + *maskBitGc, outerRect, innerRect, + frameSkinID, centerSkinID, + KAknsSDMAlphaOnly |KAknsDrawParamNoClearUnderImage); + result = fromFbsBitmap(frame, frameMask, flags, QImage::Format_ARGB32); + } + CleanupStack::PopAndDestroy(3, frameMask); + } + } + CleanupStack::PopAndDestroy(3, frame); //frame, bitmapDev, bitmapGc + return result; +} + +void QS60StyleModeSpecifics::frameIdAndCenterId(QS60StylePrivate::SkinFrameElements frameElement, TAknsItemID &frameId, TAknsItemID ¢erId) +{ +// There are some major mix-ups in skin declarations for some frames. +// First, the frames are not declared in sequence. +// Second, the parts use different major than the frame-master. + + switch(frameElement) { + case QS60StylePrivate::SF_ToolTip: + if (QSysInfo::s60Version()!=QSysInfo::SV_S60_3_1) { + centerId.Set(EAknsMajorGeneric, 0x19c2); + frameId.Set(EAknsMajorSkin, 0x5300); + } else { + centerId.Set(KAknsIIDQsnFrPopupCenter); + frameId.iMinor = centerId.iMinor - 9; + } + break; + case QS60StylePrivate::SF_ToolBar: + if (QSysInfo::s60Version()==QSysInfo::SV_S60_3_1 || QSysInfo::s60Version()==QSysInfo::SV_S60_3_2) { + centerId.Set(KAknsIIDQsnFrPopupCenterSubmenu); + frameId.Set(KAknsIIDQsnFrPopupSub); + } + break; + case QS60StylePrivate::SF_PanelBackground: + // remove center piece for panel graphics, so that only border is drawn + centerId.Set(KAknsIIDNone); + frameId.Set(KAknsIIDQsnFrSetOpt); + break; + default: + // center should be correct here + frameId.iMinor = centerId.iMinor - 9; + break; + } +} + +TRect QS60StyleModeSpecifics::innerRectFromElement(QS60StylePrivate::SkinFrameElements frameElement, const TRect &outerRect) +{ + TInt widthShrink = QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerWidth); + TInt heightShrink = QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerHeight); + switch(frameElement) { + case QS60StylePrivate::SF_PanelBackground: + // panel should have slightly slimmer border to enable thin line of background graphics between closest component + widthShrink = widthShrink-2; + heightShrink = heightShrink-2; + break; + case QS60StylePrivate::SF_ToolTip: + widthShrink = widthShrink>>1; + heightShrink = heightShrink>>1; + break; + default: + break; + } + TRect innerRect(outerRect); + innerRect.Shrink(widthShrink, heightShrink); + return innerRect; +} + +bool QS60StyleModeSpecifics::checkSupport(const int supportedRelease) +{ + const QSysInfo::S60Version currentRelease = QSysInfo::s60Version(); + return ( (currentRelease == QSysInfo::SV_S60_3_1 && supportedRelease & ES60_3_1) || + (currentRelease == QSysInfo::SV_S60_3_2 && supportedRelease & ES60_3_2) || + (currentRelease == QSysInfo::SV_S60_5_0 && supportedRelease & ES60_5_0)); +} + +TAknsItemID QS60StyleModeSpecifics::checkAndUpdateReleaseSpecificGraphics(int part) +{ + TAknsItemID newSkinId; + if (!checkSupport(m_partMap[(int)part].supportInfo)) + newSkinId.Set(m_partMap[(int)part].newMajorSkinId, m_partMap[(int)part].newMinorSkinId); + else + newSkinId.Set(m_partMap[(int)part].skinID); + return newSkinId; +} + +void QS60StyleModeSpecifics::checkAndUnCompressBitmap(CFbsBitmap*& aOriginalBitmap) +{ + TRAPD(error, checkAndUnCompressBitmapL(aOriginalBitmap)); + if (error) + aOriginalBitmap = NULL; +} + +void QS60StyleModeSpecifics::checkAndUnCompressBitmapL(CFbsBitmap*& aOriginalBitmap) +{ + if (aOriginalBitmap->IsCompressedInRAM()) { + const TSize iconSize(aOriginalBitmap->SizeInPixels().iWidth, + aOriginalBitmap->SizeInPixels().iHeight); + CFbsBitmap* uncompressedBitmap = new (ELeave) CFbsBitmap(); + CleanupStack::PushL(uncompressedBitmap); + User::LeaveIfError(uncompressedBitmap->Create(iconSize, + aOriginalBitmap->DisplayMode())); + unCompressBitmapL(iconSize, uncompressedBitmap, aOriginalBitmap); + CleanupStack::Pop(uncompressedBitmap); + User::LeaveIfError(aOriginalBitmap->Duplicate( + uncompressedBitmap->Handle())); + delete uncompressedBitmap; + } +} + +QFont QS60StylePrivate::s60Font_specific( + QS60StyleEnums::FontCategories fontCategory, int pointSize) +{ + TAknFontCategory aknFontCategory = EAknFontCategoryUndefined; + switch (fontCategory) { + case QS60StyleEnums::FC_Primary: + aknFontCategory = EAknFontCategoryPrimary; + break; + case QS60StyleEnums::FC_Secondary: + aknFontCategory = EAknFontCategorySecondary; + break; + case QS60StyleEnums::FC_Title: + aknFontCategory = EAknFontCategoryTitle; + break; + case QS60StyleEnums::FC_PrimarySmall: + aknFontCategory = EAknFontCategoryPrimarySmall; + break; + case QS60StyleEnums::FC_Digital: + aknFontCategory = EAknFontCategoryDigital; + break; + case QS60StyleEnums::FC_Undefined: + default: + break; + } + + // Create AVKON font according the given parameters + CWsScreenDevice* dev = CCoeEnv::Static()->ScreenDevice(); + TAknFontSpecification spec(aknFontCategory, TFontSpec(), NULL); + if (pointSize > 0) { + const TInt pixelSize = dev->VerticalTwipsToPixels(pointSize * KTwipsPerPoint); + spec.SetTextPaneHeight(pixelSize + 4); // TODO: Is 4 a reasonable top+bottom margin? + } + + QFont result; + TRAPD( error, { + const CAknLayoutFont* aknFont = + AknFontAccess::CreateLayoutFontFromSpecificationL(*dev, spec); + + result = qt_TFontSpec2QFontL(aknFont->DoFontSpecInTwips()); + if (result.pointSize() != pointSize) + result.setPointSize(pointSize); // Correct the font size returned by CreateLayoutFontFromSpecificationL() + + delete aknFont; + }); + if (error) result = QFont(); + return result; +} + +void QS60StylePrivate::setActiveLayout() +{ + const QSize activeScreenSize(screenSize()); + int activeLayoutIndex = -1; + const bool mirrored = !QApplication::isLeftToRight(); + const short screenHeight = (short)activeScreenSize.height(); + const short screenWidth = (short)activeScreenSize.width(); + for (int i=0; i<m_numberOfLayouts; i++) { + if (screenHeight==m_layoutHeaders[i].height && + screenWidth==m_layoutHeaders[i].width && + mirrored==m_layoutHeaders[i].mirroring) { + activeLayoutIndex = i; + break; + } + } + + //not found, lets try without mirroring info + if (activeLayoutIndex==-1){ + for (int i=0; i<m_numberOfLayouts; i++) { + if (screenHeight==m_layoutHeaders[i].height && + screenWidth==m_layoutHeaders[i].width) { + activeLayoutIndex = i; + break; + } + } + } + + //not found, lets try with either of dimensions + if (activeLayoutIndex==-1){ + const QSysInfo::S60Version currentRelease = QSysInfo::s60Version(); + const bool landscape = screenHeight < screenWidth; + + activeLayoutIndex = (currentRelease == QSysInfo::SV_S60_3_1 || currentRelease == QSysInfo::SV_S60_3_2) ? 0 : 4; + activeLayoutIndex += (!landscape) ? 2 : 0; + activeLayoutIndex += (!mirrored) ? 1 : 0; + } + + m_pmPointer = data[activeLayoutIndex]; +} + +QS60StylePrivate::QS60StylePrivate() +{ + // No need to set active layout, if dynamic metrics API is available + setActiveLayout(); +} + +void QS60StylePrivate::setStyleProperty_specific(const char *name, const QVariant &value) +{ + if (name == QLatin1String("foo")) { + // BaR + } else { + setStyleProperty(name, value); + } +} + +QVariant QS60StylePrivate::styleProperty_specific(const char *name) const +{ + if (name == QLatin1String("foo")) + return QLatin1String("Bar"); + else + return styleProperty(name); +} + +QColor QS60StylePrivate::s60Color(QS60StyleEnums::ColorLists list, + int index, const QStyleOption *option) +{ + static const TAknsItemID *idMap[] = { + &KAknsIIDQsnHighlightColors, + &KAknsIIDQsnIconColors, + &KAknsIIDQsnLineColors, + &KAknsIIDQsnOtherColors, + &KAknsIIDQsnParentColors, + &KAknsIIDQsnTextColors + }; + Q_ASSERT((int)list <= (int)sizeof(idMap)/sizeof(idMap[0])); + const QColor color = QS60StyleModeSpecifics::colorValue(*idMap[(int) list], index - 1); + return option ? QS60StylePrivate::stateColor(color, option) : color; +} + +// In some cases, the AVKON UI themegraphic is already in 'disabled state'. +// If so, return true for these parts. +bool QS60StyleModeSpecifics::disabledPartGraphic(QS60StyleEnums::SkinParts &part) +{ + bool disabledGraphic = false; + switch(part){ + // inactive button graphics are available from 5.0 onwards + case QS60StyleEnums::SP_QsnFrButtonCornerTlInactive: + case QS60StyleEnums::SP_QsnFrButtonCornerTrInactive: + case QS60StyleEnums::SP_QsnFrButtonCornerBlInactive: + case QS60StyleEnums::SP_QsnFrButtonCornerBrInactive: + case QS60StyleEnums::SP_QsnFrButtonSideTInactive: + case QS60StyleEnums::SP_QsnFrButtonSideBInactive: + case QS60StyleEnums::SP_QsnFrButtonSideLInactive: + case QS60StyleEnums::SP_QsnFrButtonSideRInactive: + case QS60StyleEnums::SP_QsnFrButtonCenterInactive: + if (!(QSysInfo::s60Version()==QSysInfo::SV_S60_3_1 || + QSysInfo::s60Version()==QSysInfo::SV_S60_3_2)) + disabledGraphic = true; + break; + default: + break; + } + return disabledGraphic; +} + +// In some cases, the AVKON UI themegraphic is already in 'disabled state'. +// If so, return true for these frames. +bool QS60StyleModeSpecifics::disabledFrameGraphic(QS60StylePrivate::SkinFrameElements &frame) +{ + bool disabledGraphic = false; + switch(frame){ + // inactive button graphics are available from 5.0 onwards + case QS60StylePrivate::SF_ButtonInactive: + if (!(QSysInfo::s60Version()==QSysInfo::SV_S60_3_1 || + QSysInfo::s60Version()==QSysInfo::SV_S60_3_2)) + disabledGraphic = true; + break; + default: + break; + } + return disabledGraphic; +} + +QPixmap QS60StyleModeSpecifics::generateMissingThemeGraphic(QS60StyleEnums::SkinParts &part, + const QSize &size, QS60StylePrivate::SkinElementFlags flags) +{ + if (!QS60StylePrivate::isTouchSupported()) + return QPixmap(); + + QS60StyleEnums::SkinParts updatedPart = part; + switch(part){ + // AVKON UI has a abnormal handling for scrollbar graphics. It is possible that the root + // skin does not contain mandatory graphics for scrollbar pressed states. Therefore, AVKON UI + // creates dynamically these graphics by modifying the normal state scrollbar graphics slightly. + // S60Style needs to work similarly. Therefore if skingraphics call provides to be a miss + // (i.e. result is not valid), style needs to draw normal graphics instead and apply some + // modifications (similar to generatedIconPixmap()) to the result. + case QS60StyleEnums::SP_QsnCpScrollHandleBottomPressed: + updatedPart = QS60StyleEnums::SP_QsnCpScrollHandleBottom; + break; + case QS60StyleEnums::SP_QsnCpScrollHandleMiddlePressed: + updatedPart = QS60StyleEnums::SP_QsnCpScrollHandleMiddle; + break; + case QS60StyleEnums::SP_QsnCpScrollHandleTopPressed: + updatedPart = QS60StyleEnums::SP_QsnCpScrollHandleTop; + break; + default: + break; + } + if (part==updatedPart) { + return QPixmap(); + } else { + QPixmap result = skinnedGraphics(updatedPart, size, flags); + QStyleOption opt; + QPalette *themePalette = QS60StylePrivate::themePalette(); + if (themePalette) + opt.palette = *themePalette; + + // For now, always generate new icon based on "selected". In the future possibly, expand + // this to consist other possibilities as well. + result = QApplication::style()->generatedIconPixmap(QIcon::Selected, result, &opt); + return result; + } +} + +QPixmap QS60StylePrivate::part(QS60StyleEnums::SkinParts part, + const QSize &size, SkinElementFlags flags) +{ + QS60WindowSurface::unlockBitmapHeap(); + QPixmap result = (flags & SF_ColorSkinned)? + QS60StyleModeSpecifics::colorSkinnedGraphics(part, size, flags) + : QS60StyleModeSpecifics::skinnedGraphics(part, size, flags); + QS60WindowSurface::lockBitmapHeap(); + + if (flags & SF_StateDisabled && !QS60StyleModeSpecifics::disabledPartGraphic(part)) { + QStyleOption opt; + QPalette *themePalette = QS60StylePrivate::themePalette(); + if (themePalette) + opt.palette = *themePalette; + result = QApplication::style()->generatedIconPixmap(QIcon::Disabled, result, &opt); + } + + if (!result) + result = QS60StyleModeSpecifics::generateMissingThemeGraphic(part, size, flags); + + return result; +} + +QPixmap QS60StylePrivate::frame(SkinFrameElements frame, const QSize &size, SkinElementFlags flags) +{ + QS60WindowSurface::unlockBitmapHeap(); + QPixmap result = QS60StyleModeSpecifics::skinnedGraphics(frame, size, flags); + QS60WindowSurface::lockBitmapHeap(); + + if (flags & SF_StateDisabled && !QS60StyleModeSpecifics::disabledFrameGraphic(frame)) { + QStyleOption opt; + QPalette *themePalette = QS60StylePrivate::themePalette(); + if (themePalette) + opt.palette = *themePalette; + result = QApplication::style()->generatedIconPixmap(QIcon::Disabled, result, &opt); + } + return result; +} + +QPixmap QS60StylePrivate::backgroundTexture() +{ + if (!m_background) { + QPixmap background = part(QS60StyleEnums::SP_QsnBgScreen, + QSize(S60->screenWidthInPixels, S60->screenHeightInPixels), SkinElementFlags()); + m_background = new QPixmap(background); + } + return *m_background; +} + +// If the public SDK returns compressed images, please let us also uncompress those! +void QS60StyleModeSpecifics::unCompressBitmapL(const TRect& aTrgRect, CFbsBitmap* aTrgBitmap, CFbsBitmap* aSrcBitmap) +{ + if (!aSrcBitmap) + User::Leave(KErrArgument); + if (!aTrgBitmap) + User::Leave(KErrArgument); + + // Note! aSrcBitmap->IsCompressedInRAM() is always ETrue, since this method is called only if that applies! + ASSERT(aSrcBitmap->IsCompressedInRAM()); + + TDisplayMode displayMode = aSrcBitmap->DisplayMode(); + + if (displayMode != aTrgBitmap->DisplayMode()) + User::Leave(KErrArgument); + + const TSize trgSize = aTrgBitmap->SizeInPixels(); + const TSize srcSize = aSrcBitmap->SizeInPixels(); + + // calculate the valid drawing area + TRect drawRect = aTrgRect; + drawRect.Intersection(TRect(TPoint(0, 0), trgSize)); + + if (drawRect.IsEmpty()) + return; + + CFbsBitmap* realSource = new (ELeave) CFbsBitmap(); + CleanupStack::PushL(realSource); + User::LeaveIfError(realSource->Create(srcSize, displayMode)); + CFbsBitmapDevice* dev = CFbsBitmapDevice::NewL(realSource); + CleanupStack::PushL(dev); + CFbsBitGc* gc = NULL; + User::LeaveIfError(dev->CreateContext(gc)); + CleanupStack::PushL(gc); + gc->BitBlt(TPoint(0, 0), aSrcBitmap); + CleanupStack::PopAndDestroy(2); // dev, gc + + // Heap lock for FBServ large chunk is only needed with large bitmaps. + if (realSource->IsLargeBitmap() || aTrgBitmap->IsLargeBitmap()) { + aTrgBitmap->LockHeapLC(ETrue); // fbsheaplock + } else { + CleanupStack::PushL((TAny*) NULL); + } + + TUint32* srcAddress = realSource->DataAddress(); + TUint32* trgAddress = aTrgBitmap->DataAddress(); + + const TInt xSkip = (srcSize.iWidth << 8) / aTrgRect.Width(); + const TInt ySkip = (srcSize.iHeight << 8) / aTrgRect.Height(); + + const TInt drawWidth = drawRect.Width(); + const TInt drawHeight = drawRect.Height(); + + const TRect offsetRect(aTrgRect.iTl, drawRect.iTl); + const TInt yPosOffset = ySkip * offsetRect.Height(); + const TInt xPosOffset = xSkip * offsetRect.Width(); + + if ((displayMode == EGray256) || (displayMode == EColor256)) { + const TInt srcScanLen8 = CFbsBitmap::ScanLineLength(srcSize.iWidth, + displayMode); + const TInt trgScanLen8 = CFbsBitmap::ScanLineLength(trgSize.iWidth, + displayMode); + + TUint8* trgAddress8 = reinterpret_cast<TUint8*> (trgAddress); + + TInt yPos = yPosOffset; + // skip left and top margins in the beginning + trgAddress8 += trgScanLen8 * drawRect.iTl.iY + drawRect.iTl.iX; + + for (TInt y = 0; y < drawHeight; y++) { + const TUint8* srcAddress8 = reinterpret_cast<const TUint8*> (srcAddress) + + (srcScanLen8 * (yPos >> 8)); + + TInt xPos = xPosOffset; + for (TInt x = 0; x < drawWidth; x++) { + *(trgAddress8++) = srcAddress8[xPos >> 8]; + xPos += xSkip; + } + + yPos += ySkip; + + trgAddress8 += trgScanLen8 - drawWidth; + } + } else if (displayMode == EColor4K || displayMode == EColor64K) { + const TInt srcScanLen16 = CFbsBitmap::ScanLineLength(srcSize.iWidth, + displayMode) >>1; + const TInt trgScanLen16 = CFbsBitmap::ScanLineLength(trgSize.iWidth, + displayMode) >>1; + + TUint16* trgAddress16 = reinterpret_cast<TUint16*> (trgAddress); + + TInt yPos = yPosOffset; + // skip left and top margins in the beginning + trgAddress16 += trgScanLen16 * drawRect.iTl.iY + drawRect.iTl.iX; + + for (TInt y = 0; y < drawHeight; y++) { + const TUint16* srcAddress16 = reinterpret_cast<const TUint16*> (srcAddress) + + (srcScanLen16 * (yPos >> 8)); + + TInt xPos = xPosOffset; + for (TInt x = 0; x < drawWidth; x++) { + *(trgAddress16++) = srcAddress16[xPos >> 8]; + xPos += xSkip; + } + + yPos += ySkip; + + trgAddress16 += trgScanLen16 - drawWidth; + } + } else if (displayMode == EColor16MU || displayMode == EColor16MA) { + const TInt srcScanLen32 = CFbsBitmap::ScanLineLength(srcSize.iWidth, + displayMode) >>2; + const TInt trgScanLen32 = CFbsBitmap::ScanLineLength(trgSize.iWidth, + displayMode) >>2; + + TUint32* trgAddress32 = reinterpret_cast<TUint32*> (trgAddress); + + TInt yPos = yPosOffset; + // skip left and top margins in the beginning + trgAddress32 += trgScanLen32 * drawRect.iTl.iY + drawRect.iTl.iX; + + for (TInt y = 0; y < drawHeight; y++) { + const TUint32* srcAddress32 = reinterpret_cast<const TUint32*> (srcAddress) + + (srcScanLen32 * (yPos >> 8)); + + TInt xPos = xPosOffset; + for (TInt x = 0; x < drawWidth; x++) { + *(trgAddress32++) = srcAddress32[xPos >> 8]; + xPos += xSkip; + } + + yPos += ySkip; + + trgAddress32 += trgScanLen32 - drawWidth; + } + } else { User::Leave(KErrUnknown);} + + CleanupStack::PopAndDestroy(2); // fbsheaplock, realSource +} + +QSize QS60StylePrivate::screenSize() +{ + const TSize screenSize = QS60Data::screenDevice()->SizeInPixels(); + return QSize(screenSize.iWidth, screenSize.iHeight); +} + +void QS60StyleModeSpecifics::colorGroupAndIndex( + QS60StyleEnums::SkinParts skinID, TAknsItemID &colorGroup, int colorIndex) +{ + switch(skinID) { + case QS60StyleEnums::SP_QgnIndiSubMenu: + colorGroup = KAknsIIDQsnIconColors; + colorIndex = EAknsCIQsnIconColorsCG1; + break; + case QS60StyleEnums::SP_QgnIndiRadiobuttOff: + case QS60StyleEnums::SP_QgnIndiRadiobuttOn: + case QS60StyleEnums::SP_QgnIndiCheckboxOff: + case QS60StyleEnums::SP_QgnIndiCheckboxOn: + colorGroup = KAknsIIDQsnIconColors; + colorIndex = EAknsCIQsnIconColorsCG14; + break; + default: + break; + } +} + +/*! + Constructs a QS60Style object. +*/ +QS60Style::QS60Style() + : QCommonStyle(*new QS60StylePrivate) +{ +} + +void QS60Style::handleDynamicLayoutVariantSwitch() +{ + Q_D(QS60Style); + d->clearCaches(QS60StylePrivate::CC_LayoutChange); + d->setActiveLayout(); + d->refreshUI(); + d->setBackgroundTexture(qApp); + foreach (QWidget *widget, QApplication::allWidgets()) + widget->ensurePolished(); +} + +void QS60Style::handleSkinChange() +{ + Q_D(QS60Style); + d->clearCaches(QS60StylePrivate::CC_ThemeChange); + d->setThemePalette(qApp); + foreach (QWidget *topLevelWidget, QApplication::allWidgets()){ + QEvent e(QEvent::StyleChange); + QApplication::sendEvent(topLevelWidget, &e); + d->setThemePalette(topLevelWidget); + topLevelWidget->ensurePolished(); + } +} + +QT_END_NAMESPACE + +#endif // QT_NO_STYLE_S60 || QT_PLUGIN diff --git a/src/gui/styles/qs60style_simulated.cpp b/src/gui/styles/qs60style_simulated.cpp new file mode 100644 index 0000000..a94d73e --- /dev/null +++ b/src/gui/styles/qs60style_simulated.cpp @@ -0,0 +1,439 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qs60style.h" +#include "qs60style_p.h" +#include "qfile.h" +#include "qhash.h" +#include "qapplication.h" +#include "qpainter.h" +#include "qpicture.h" +#include "qstyleoption.h" +#include "qtransform.h" +#include "qlayout.h" +#include "qpixmapcache.h" +#include "qmetaobject.h" +#include "qdebug.h" +#include "qbuffer.h" + +#if !defined(QT_NO_STYLE_S60) || defined(QT_PLUGIN) + +QT_BEGIN_NAMESPACE + +static const quint32 blobVersion = 1; +static const int pictureSize = 256; + +bool saveThemeToBlob(const QString &themeBlob, + const QHash<QString, QPicture> &partPictures, + const QHash<QPair<QString, int>, QColor> &colors) +{ + QFile blob(themeBlob); + if (!blob.open(QIODevice::WriteOnly)) { + qWarning() << __FUNCTION__": Could not create blob: " << themeBlob; + return false; + } + + QByteArray data; + QBuffer dataBuffer(&data); + dataBuffer.open(QIODevice::WriteOnly); + QDataStream dataOut(&dataBuffer); + + const int colorsCount = colors.count(); + dataOut << colorsCount; + const QList<QPair<QString, int> > colorKeys = colors.keys(); + for (int i = 0; i < colorsCount; ++i) { + const QPair<QString, int> &key = colorKeys.at(i); + dataOut << key; + const QColor color = colors.value(key); + dataOut << color; + } + + const int picturesCount = partPictures.count(); + dataOut << picturesCount; + foreach (const QString &key, partPictures.keys()) { + const QPicture picture = partPictures.value(key); + dataOut << key; + dataOut << picture; + } + + QDataStream blobOut(&blob); + blobOut << blobVersion; + blobOut << qCompress(data); + return blobOut.status() == QDataStream::Ok; +} + +bool loadThemeFromBlob(const QString &themeBlob, + QHash<QString, QPicture> &partPictures, + QHash<QPair<QString, int>, QColor> &colors) +{ + QFile blob(themeBlob); + if (!blob.open(QIODevice::ReadOnly)) { + qWarning() << __FUNCTION__": Could not read blob: " << themeBlob; + return false; + } + QDataStream blobIn(&blob); + + quint32 version; + blobIn >> version; + + if (version != blobVersion) { + qWarning() << __FUNCTION__": Invalid blob version: " << version << " ...expected: " << blobVersion; + return false; + } + + QByteArray data; + blobIn >> data; + data = qUncompress(data); + QBuffer dataBuffer(&data); + dataBuffer.open(QIODevice::ReadOnly); + QDataStream dataIn(&dataBuffer); + + int colorsCount; + dataIn >> colorsCount; + for (int i = 0; i < colorsCount; ++i) { + QPair<QString, int> key; + dataIn >> key; + QColor value; + dataIn >> value; + colors.insert(key, value); + } + + int picturesCount; + dataIn >> picturesCount; + for (int i = 0; i < picturesCount; ++i) { + QString key; + dataIn >> key; + QPicture value; + dataIn >> value; + value.setBoundingRect(QRect(0, 0, pictureSize, pictureSize)); // Bug? The forced bounding rect was not deserialized. + partPictures.insert(key, value); + } + + if (dataIn.status() != QDataStream::Ok) { + qWarning() << __FUNCTION__": Invalid data blob: " << themeBlob; + return false; + } + return true; +} + +class QS60StyleModeSpecifics +{ +public: + static QPixmap skinnedGraphics(QS60StyleEnums::SkinParts stylepart, + const QSize &size, QS60StylePrivate::SkinElementFlags flags); + static QHash<QString, QPicture> m_partPictures; + static QHash<QPair<QString , int>, QColor> m_colors; +}; +QHash<QString, QPicture> QS60StyleModeSpecifics::m_partPictures; +QHash<QPair<QString , int>, QColor> QS60StyleModeSpecifics::m_colors; + +QS60StylePrivate::QS60StylePrivate() +{ + setCurrentLayout(0); +} + +QColor QS60StylePrivate::s60Color(QS60StyleEnums::ColorLists list, + int index, const QStyleOption *option) +{ + const QString listKey = QS60Style::colorListKeys().at(list); + return QS60StylePrivate::stateColor( + QS60StyleModeSpecifics::m_colors.value(QPair<QString, int>(listKey, index)), + option + ); +} + +QPixmap QS60StylePrivate::part(QS60StyleEnums::SkinParts part, const QSize &size, + QS60StylePrivate::SkinElementFlags flags) +{ + const QString partKey = QS60Style::partKeys().at(part); + const QPicture partPicture = QS60StyleModeSpecifics::m_partPictures.value(partKey); + QSize partSize(partPicture.boundingRect().size()); + if (flags & (SF_PointEast | SF_PointWest)) { + const int temp = partSize.width(); + partSize.setWidth(partSize.height()); + partSize.setHeight(temp); + } + const qreal scaleX = size.width() / (qreal)partSize.width(); + const qreal scaleY = size.height() / (qreal)partSize.height(); + + QImage partImage(size, QImage::Format_ARGB32); + partImage.fill(Qt::transparent); + QPainter resultPainter(&partImage); + QTransform t; + + if (flags & SF_PointEast) + t.translate(size.width(), 0); + else if (flags & SF_PointSouth) + t.translate(size.width(), size.height()); + else if (flags & SF_PointWest) + t.translate(0, size.height()); + + t.scale(scaleX, scaleY); + + if (flags & SF_PointEast) + t.rotate(90); + else if (flags & SF_PointSouth) + t.rotate(180); + else if (flags & SF_PointWest) + t.rotate(270); + + resultPainter.setTransform(t, true); + const_cast<QPicture *>(&partPicture)->play(&resultPainter); + resultPainter.end(); + + QPixmap result = QPixmap::fromImage(partImage); + if (flags & SF_StateDisabled) { + QStyleOption opt; + QPalette *themePalette = QS60StylePrivate::themePalette(); + if (themePalette) + opt.palette = *themePalette; + result = QApplication::style()->generatedIconPixmap(QIcon::Disabled, result, &opt); + } + + return result; +} + +QPixmap QS60StylePrivate::frame(SkinFrameElements frame, const QSize &size, + SkinElementFlags flags) +{ + const QS60StyleEnums::SkinParts center = m_frameElementsData[frame].center; + const QS60StyleEnums::SkinParts topLeft = QS60StyleEnums::SkinParts(center - 8); + const QS60StyleEnums::SkinParts topRight = QS60StyleEnums::SkinParts(center - 7); + const QS60StyleEnums::SkinParts bottomLeft = QS60StyleEnums::SkinParts(center - 6); + const QS60StyleEnums::SkinParts bottomRight = QS60StyleEnums::SkinParts(center - 5); + const QS60StyleEnums::SkinParts top = QS60StyleEnums::SkinParts(center - 4); + const QS60StyleEnums::SkinParts bottom = QS60StyleEnums::SkinParts(center - 3); + const QS60StyleEnums::SkinParts left = QS60StyleEnums::SkinParts(center - 2); + const QS60StyleEnums::SkinParts right = QS60StyleEnums::SkinParts(center - 1); + + // The size of topLeft defines all other sizes + const QSize cornerSize(partSize(topLeft)); + // if frame is so small that corners would cover it completely, draw only center piece + const bool drawOnlyCenter = + 2 * cornerSize.width() + 1 >= size.width() || 2 * cornerSize.height() + 1 >= size.height(); + + const int cornerWidth = cornerSize.width(); + const int cornerHeight = cornerSize.height(); + const int rectWidth = size.width(); + const int rectHeight = size.height(); + const QRect rect(QPoint(), size); + + const QRect topLeftRect = QRect(rect.topLeft(), cornerSize); + const QRect topRect = rect.adjusted(cornerWidth, 0, -cornerWidth, -(rectHeight - cornerHeight)); + const QRect topRightRect = topLeftRect.translated(rectWidth - cornerWidth, 0); + const QRect rightRect = rect.adjusted(rectWidth - cornerWidth, cornerHeight, 0, -cornerHeight); + const QRect bottomRightRect = topRightRect.translated(0, rectHeight - cornerHeight); + const QRect bottomRect = topRect.translated(0, rectHeight - cornerHeight); + const QRect bottomLeftRect = topLeftRect.translated(0, rectHeight - cornerHeight); + const QRect leftRect = rightRect.translated(cornerWidth - rectWidth, 0); + const QRect centerRect = drawOnlyCenter ? rect : rect.adjusted(cornerWidth, cornerWidth, -cornerWidth, -cornerWidth); + + QImage result(size, QImage::Format_ARGB32); + result.fill(Qt::transparent); + QPainter painter(&result); + +#if 0 + painter.save(); + painter.setOpacity(.3); + painter.fillRect(topLeftRect, Qt::red); + painter.fillRect(topRect, Qt::green); + painter.fillRect(topRightRect, Qt::blue); + painter.fillRect(rightRect, Qt::green); + painter.fillRect(bottomRightRect, Qt::red); + painter.fillRect(bottomRect, Qt::blue); + painter.fillRect(bottomLeftRect, Qt::green); + painter.fillRect(leftRect, Qt::blue); + painter.fillRect(centerRect, Qt::red); + painter.restore(); +#else + drawPart(topLeft, &painter, topLeftRect, flags); + drawPart(top, &painter, topRect, flags); + drawPart(topRight, &painter, topRightRect, flags); + drawPart(right, &painter, rightRect, flags); + drawPart(bottomRight, &painter, bottomRightRect, flags); + drawPart(bottom, &painter, bottomRect, flags); + drawPart(bottomLeft, &painter, bottomLeftRect, flags); + drawPart(left, &painter, leftRect, flags); + drawPart(center, &painter, centerRect, flags); +#endif + + return QPixmap::fromImage(result); +} + +void QS60StylePrivate::setStyleProperty_specific(const char *name, const QVariant &value) +{ + setStyleProperty(name, value); +} + +QVariant QS60StylePrivate::styleProperty_specific(const char *name) const +{ + return styleProperty(name); +} + +QPixmap QS60StylePrivate::backgroundTexture() +{ + if (!m_background) { + const QSize size = QApplication::desktop()->screen()->size(); + QPixmap background = part(QS60StyleEnums::SP_QsnBgScreen, size); + m_background = new QPixmap(background); + } + return *m_background; +} + + +bool QS60StylePrivate::isTouchSupported() +{ +#ifdef QT_KEYPAD_NAVIGATION + return !QApplication::keypadNavigationEnabled(); +#else + return true; +#endif +} + +bool QS60StylePrivate::isToolBarBackground() +{ + return true; +} + +QFont QS60StylePrivate::s60Font_specific(QS60StyleEnums::FontCategories fontCategory, int pointSize) +{ + QFont result; + result.setPointSize(pointSize); + switch (fontCategory) { + case QS60StyleEnums::FC_Primary: + result.setBold(true); + break; + case QS60StyleEnums::FC_Secondary: + case QS60StyleEnums::FC_Title: + case QS60StyleEnums::FC_PrimarySmall: + case QS60StyleEnums::FC_Digital: + case QS60StyleEnums::FC_Undefined: + default: + break; + } + return result; +} + +/*! + Constructs a QS60Style object. +*/ +QS60Style::QS60Style() + : QCommonStyle(*new QS60StylePrivate) +{ + // Assume, that the resource system has a ':/s60Stylethemes/Default.blob' + loadS60ThemeFromBlob(QString::fromLatin1(":/s60Stylethemes/Default.blob")); +} + +Q_GLOBAL_STATIC_WITH_INITIALIZER(QStringList, enumPartKeys, { + const int enumIndex = QS60StyleEnums::staticMetaObject.indexOfEnumerator("SkinParts"); + Q_ASSERT(enumIndex >= 0); + const QMetaEnum metaEnum = QS60StyleEnums::staticMetaObject.enumerator(enumIndex); + for (int i = 0; i < metaEnum.keyCount(); ++i) { + const QString enumKey = QString::fromLatin1(metaEnum.key(i)); + QString partKey; + // Following loop does following conversions: "SP_QgnNoteInfo" to "qgn_note_info"... + for (int charPosition = 3; charPosition < enumKey.length(); charPosition++) { + if (charPosition > 3 && enumKey[charPosition].isUpper()) + partKey.append(QChar::fromLatin1('_')); + partKey.append(enumKey[charPosition].toLower()); + } + x->append(partKey); + } +}) + +QStringList QS60Style::partKeys() +{ + return *enumPartKeys(); +} + +Q_GLOBAL_STATIC_WITH_INITIALIZER(QStringList, enumColorListKeys, { + const int enumIndex = QS60StyleEnums::staticMetaObject.indexOfEnumerator("ColorLists"); + Q_ASSERT(enumIndex >= 0); + const QMetaEnum metaEnum = QS60StyleEnums::staticMetaObject.enumerator(enumIndex); + for (int i = 0; i < metaEnum.keyCount(); i++) { + const QString enumKey = QString::fromLatin1(metaEnum.key(i)); + // Following line does following conversions: CL_QsnTextColors to "text"... + x->append(enumKey.mid(6, enumKey.length() - 12).toLower()); + } +}) + +QStringList QS60Style::colorListKeys() +{ + return *enumColorListKeys(); +} + +void QS60Style::setS60Theme(const QHash<QString, QPicture> &parts, + const QHash<QPair<QString , int>, QColor> &colors) +{ + Q_D(QS60Style); + QS60StyleModeSpecifics::m_partPictures = parts; + QS60StyleModeSpecifics::m_colors = colors; + d->clearCaches(QS60StylePrivate::CC_ThemeChange); + d->setBackgroundTexture(qApp); + d->setThemePalette(qApp); +} + +bool QS60Style::loadS60ThemeFromBlob(const QString &blobFile) +{ + QHash<QString, QPicture> partPictures; + QHash<QPair<QString, int>, QColor> colors; + + if (!loadThemeFromBlob(blobFile, partPictures, colors)) + return false; + setS60Theme(partPictures, colors); + return true; +} + +bool QS60Style::saveS60ThemeToBlob(const QString &blobFile) const +{ + return saveThemeToBlob(blobFile, + QS60StyleModeSpecifics::m_partPictures, QS60StyleModeSpecifics::m_colors); +} + +QPoint qt_s60_fill_background_offset(const QWidget *targetWidget) +{ + Q_UNUSED(targetWidget) + return QPoint(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_STYLE_S60 || QT_PLUGIN diff --git a/src/gui/styles/qstyle_s60_simulated.qrc b/src/gui/styles/qstyle_s60_simulated.qrc new file mode 100644 index 0000000..72aab9e --- /dev/null +++ b/src/gui/styles/qstyle_s60_simulated.qrc @@ -0,0 +1,6 @@ +<!DOCTYPE RCC> +<RCC version="1.0"> + <qresource prefix="/trolltech/styles/s60style"> + <file>images/s60themes.dat</file> + </qresource> +</RCC> diff --git a/src/gui/styles/qstylefactory.cpp b/src/gui/styles/qstylefactory.cpp index 70717db..42cd6dc 100644 --- a/src/gui/styles/qstylefactory.cpp +++ b/src/gui/styles/qstylefactory.cpp @@ -69,6 +69,9 @@ #ifndef QT_NO_STYLE_WINDOWSMOBILE #include "qwindowsmobilestyle.h" #endif +#ifndef QT_NO_STYLE_S60 +#include "qs60style.h" +#endif QT_BEGIN_NAMESPACE @@ -154,6 +157,11 @@ QStyle *QStyleFactory::create(const QString& key) ret = new QCDEStyle; else #endif +#ifndef QT_NO_STYLE_S60 + if (style == QLatin1String("s60")) + ret = new QS60Style; + else +#endif #ifndef QT_NO_STYLE_PLASTIQUE if (style == QLatin1String("plastique")) ret = new QPlastiqueStyle; @@ -233,6 +241,10 @@ QStringList QStyleFactory::keys() if (!list.contains(QLatin1String("CDE"))) list << QLatin1String("CDE"); #endif +#ifndef QT_NO_STYLE_S60 + if (!list.contains(QLatin1String("S60"))) + list << QLatin1String("S60"); +#endif #ifndef QT_NO_STYLE_PLASTIQUE if (!list.contains(QLatin1String("Plastique"))) list << QLatin1String("Plastique"); diff --git a/src/gui/styles/qstylesheetstyle_default.cpp b/src/gui/styles/qstylesheetstyle_default.cpp index 742cfe1..74e23b8 100644 --- a/src/gui/styles/qstylesheetstyle_default.cpp +++ b/src/gui/styles/qstylesheetstyle_default.cpp @@ -154,11 +154,12 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const Value value; Pseudo pseudo; AttributeSelector attr; - + // pixmap based style doesn't support any features bool styleIsPixmapBased = baseStyle()->inherits("QMacStyle") || baseStyle()->inherits("QWindowsXPStyle") - || baseStyle()->inherits("QGtkStyle"); + || baseStyle()->inherits("QGtkStyle") + || baseStyle()->inherits("QS60Style"); /*QLineEdit { @@ -212,7 +213,7 @@ StyleSheet QStyleSheetStyle::getDefaultStyleSheet() const ADD_BASIC_SELECTOR; ADD_SELECTOR; - + SET_PROPERTY(QLatin1String("padding-top"), PaddingTop); ADD_VALUE(Value::Identifier, QString::fromLatin1("2px")); ADD_DECLARATION; diff --git a/src/gui/styles/styles.pri b/src/gui/styles/styles.pri index 376f834..050d81d 100644 --- a/src/gui/styles/styles.pri +++ b/src/gui/styles/styles.pri @@ -155,3 +155,19 @@ contains( styles, windowsmobile ) { DEFINES += QT_NO_STYLE_WINDOWSMOBILE } +contains( styles, s60 ) { + HEADERS += \ + styles/qs60style.h \ + styles/qs60style_p.h + SOURCES += styles/qs60style.cpp + symbian { + SOURCES += styles/qs60style_s60.cpp + # TODO: fix the following LIBS hack. Line 1 is for armv5, 2 for winscw + LIBS += aknicon aknskins aknskinsrv fontutils + LIBS += -laknicon -laknskins -laknskinsrv -lfontutils + } else { + SOURCES += styles/qs60style_simulated.cpp + } +} else { + DEFINES += QT_NO_STYLE_S60 +} diff --git a/src/gui/text/qabstractfontengine_p.h b/src/gui/text/qabstractfontengine_p.h index 4752de5..59b54bd 100644 --- a/src/gui/text/qabstractfontengine_p.h +++ b/src/gui/text/qabstractfontengine_p.h @@ -91,7 +91,7 @@ public: virtual Type type() const { return Proxy; } virtual const char *name() const { return "proxy engine"; } -#if !defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC) +#if !defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC) && !defined(Q_WS_S60) virtual void draw(QPaintEngine *, qreal, qreal, const QTextItemInt &); #endif diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp index 38621c1..0bd2d9a 100644 --- a/src/gui/text/qcssparser.cpp +++ b/src/gui/text/qcssparser.cpp @@ -48,6 +48,7 @@ #include <qfontmetrics.h> #include <qbrush.h> #include <qimagereader.h> +#include "private/qfunctions_p.h" #ifndef QT_NO_CSSPARSER @@ -378,12 +379,12 @@ static const QCssKnownValue styleFeatures[NumKnownStyleFeatures - 1] = { { "none", StyleFeature_None } }; -static bool operator<(const QString &name, const QCssKnownValue &prop) +Q_STATIC_GLOBAL_OPERATOR bool operator<(const QString &name, const QCssKnownValue &prop) { return QString::compare(name, QLatin1String(prop.name), Qt::CaseInsensitive) < 0; } -static bool operator<(const QCssKnownValue &prop, const QString &name) +Q_STATIC_GLOBAL_OPERATOR bool operator<(const QCssKnownValue &prop, const QString &name) { return QString::compare(QLatin1String(prop.name), name, Qt::CaseInsensitive) < 0; } diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index c5096bf..930e8af 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -72,6 +72,9 @@ #include "qfontengine_qpf_p.h" #endif #endif +#ifdef Q_WS_S60 +#include "qt_s60_p.h" +#endif #include <QMutexLocker> @@ -169,6 +172,8 @@ Q_GUI_EXPORT int qt_defaultDpiX() if (!subScreens.isEmpty()) screen = subScreens.at(0); dpi = qRound(screen->width() / (screen->physicalWidth() / qreal(25.4))); +#elif defined(Q_WS_S60) + dpi = S60->defaultDpiX; #endif // Q_WS_X11 return dpi; @@ -195,6 +200,8 @@ Q_GUI_EXPORT int qt_defaultDpiY() if (!subScreens.isEmpty()) screen = subScreens.at(0); dpi = qRound(screen->height() / (screen->physicalHeight() / qreal(25.4))); +#elif defined(Q_WS_S60) + dpi = S60->defaultDpiY; #endif // Q_WS_X11 return dpi; @@ -788,7 +795,12 @@ QFont::QFont(const QString &family, int pointSize, int weight, bool italic) resolve_mask = QFont::FamilyResolved; if (pointSize <= 0) { +#ifdef Q_WS_S60 + // TODO: What should the default QFont pointSize for Q_WS_S60 be? + pointSize = 7; +#else pointSize = 12; +#endif } else { resolve_mask |= QFont::SizeResolved; } diff --git a/src/gui/text/qfont_s60.cpp b/src/gui/text/qfont_s60.cpp new file mode 100644 index 0000000..533e51f --- /dev/null +++ b/src/gui/text/qfont_s60.cpp @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfont.h" +#include "qt_s60_p.h" +#include <private/qwindowsurface_s60_p.h> +#include "qmutex.h" + +QT_BEGIN_NAMESPACE + +#if 1 +#ifdef QT_NO_FREETYPE +Q_GLOBAL_STATIC(QMutex, lastResortFamilyMutex); +#endif // QT_NO_FREETYPE + +QString QFont::lastResortFamily() const +{ +#ifdef QT_NO_FREETYPE + QMutexLocker locker(lastResortFamilyMutex()); + static QString family; + if (family.isEmpty()) { + QS60WindowSurface::unlockBitmapHeap(); + CFont *font; + const TInt err = S60->screenDevice()->GetNearestFontInTwips(font, TFontSpec()); + Q_ASSERT(err == KErrNone); + const TFontSpec spec = font->FontSpecInTwips(); + family = QString((const QChar *)spec.iTypeface.iName.Ptr(), spec.iTypeface.iName.Length()); + S60->screenDevice()->ReleaseFont(font); + QS60WindowSurface::lockBitmapHeap(); + } + return family; +#else + // For the FreeType case we just hard code the face name, since otherwise on + // East Asian systems we may get a name for a stroke based (non-ttf) font. + + // TODO: Get the type face name in a proper way + + const bool isJapaneseOrChineseSystem = + User::Language() == ELangJapanese || User::Language() == ELangPrcChinese; + + return QLatin1String(isJapaneseOrChineseSystem?"Heisei Kaku Gothic S60":"Series 60 Sans"); +#endif // QT_NO_FREETYPE +} +#else // 0 +QString QFont::lastResortFamily() const +{ + return QLatin1String("Series 60 Sans"); +} +#endif // 0 + +QString QFont::defaultFamily() const +{ + return lastResortFamily(); +} + +QT_END_NAMESPACE diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 5fb294f..9426fef 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -56,6 +56,11 @@ #include <stdlib.h> #include <limits.h> +#if (defined(Q_WS_QWS) || defined(Q_WS_S60)) && !defined(QT_NO_FREETYPE) +# include <ft2build.h> +# include FT_TRUETYPE_TABLES_H +#endif + // #define QFONTDATABASE_DEBUG #ifdef QFONTDATABASE_DEBUG # define FD_DEBUG qDebug @@ -76,6 +81,8 @@ QT_BEGIN_NAMESPACE +#define SMOOTH_SCALABLE 0xffff + extern int qt_defaultDpiY(); // in qfont.cpp Q_GUI_EXPORT bool qt_enable_test_font = false; @@ -141,10 +148,10 @@ struct QtFontSize QtFontEncoding *encodingID(int id, uint xpoint = 0, uint xres = 0, uint yres = 0, uint avgwidth = 0, bool add = false); #endif // Q_WS_X11 -#ifdef Q_WS_QWS +#if defined(Q_WS_QWS) || defined(Q_WS_S60) QByteArray fileName; int fileIndex; -#endif +#endif // defined(Q_WS_QWS) || defined(Q_WS_S60) }; @@ -215,12 +222,12 @@ struct QtFontStyle delete [] weightName; delete [] setwidthName; #endif -#if defined(Q_WS_X11) || defined(Q_WS_QWS) +#if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_S60) while (count--) { #ifdef Q_WS_X11 free(pixelSizes[count].encodings); #endif -#ifdef Q_WS_QWS +#if defined(Q_WS_QWS) || defined(Q_WS_S60) pixelSizes[count].fileName.~QByteArray(); #endif } @@ -238,7 +245,7 @@ struct QtFontStyle const char *weightName; const char *setwidthName; #endif // Q_WS_X11 -#ifdef Q_WS_QWS +#if defined(Q_WS_QWS) || defined(Q_WS_S60) bool antialiased; #endif @@ -276,7 +283,7 @@ QtFontSize *QtFontStyle::pixelSize(unsigned short size, bool add) pixelSizes[count].count = 0; pixelSizes[count].encodings = 0; #endif -#ifdef Q_WS_QWS +#if defined(Q_WS_QWS) || defined(Q_WS_S60) new (&pixelSizes[count].fileName) QByteArray; pixelSizes[count].fileIndex = 0; #endif @@ -358,7 +365,7 @@ struct QtFontFamily fixedPitchComputed(false), #endif name(n), count(0), foundries(0) -#if defined(Q_WS_QWS) +#if defined(Q_WS_QWS) || defined(Q_WS_S60) && !defined(QT_NO_FREETYPE) , bogusWritingSystems(false) #endif { @@ -388,7 +395,7 @@ struct QtFontFamily #endif QString name; -#ifdef Q_WS_X11 +#if defined(Q_WS_X11) || defined(Q_WS_S60) && !defined(QT_NO_FREETYPE) QByteArray fontFilename; int fontFileIndex; #endif @@ -398,7 +405,7 @@ struct QtFontFamily int count; QtFontFoundry **foundries; -#ifdef Q_WS_QWS +#if defined(Q_WS_QWS) || defined(Q_WS_S60) && !defined(QT_NO_FREETYPE) bool bogusWritingSystems; QStringList fallbackFamilies; #endif @@ -442,7 +449,7 @@ QtFontFoundry *QtFontFamily::foundry(const QString &f, bool create) // ### copied to tools/makeqpf/qpf2.cpp -#if (defined(Q_WS_QWS) && !defined(QT_NO_FREETYPE)) || defined(Q_WS_WIN) || defined(Q_WS_MAC) +#if (defined(Q_WS_QWS) && !defined(QT_NO_FREETYPE)) || defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_WS_S60) // see the Unicode subset bitfields in the MSDN docs static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { // Any, @@ -563,6 +570,15 @@ static QList<QFontDatabase::WritingSystem> determineWritingSystemsFromTrueTypeBi } #endif +#if defined(Q_WS_S60) && defined(QT_NO_FREETYPE) +// class with virtual destructor, derived in qfontdatabase_s60.cpp +class QFontDatabaseS60Store +{ +public: + virtual ~QFontDatabaseS60Store() {}; +}; +#endif + class QFontDatabasePrivate { public: @@ -571,6 +587,9 @@ public: #if defined(Q_WS_QWS) , stream(0) #endif +#if defined(Q_WS_S60) && defined(QT_NO_FREETYPE) + , s60Store(0) +#endif { } ~QFontDatabasePrivate() { free(); @@ -582,6 +601,12 @@ public: ::free(families); families = 0; count = 0; +#if defined(Q_WS_S60) && defined(QT_NO_FREETYPE) + if (s60Store) { + delete s60Store; + s60Store = 0; + } +#endif // don't clear the memory fonts! } @@ -609,17 +634,22 @@ public: #if defined(Q_WS_QWS) bool loadFromCache(const QString &fontPath); + void addQPF2File(const QByteArray &file); +#endif // Q_WS_QWS +#if defined(Q_WS_QWS) || defined(Q_WS_S60) && !defined(QT_NO_FREETYPE) void addFont(const QString &familyname, const char *foundryname, int weight, bool italic, int pixelSize, const QByteArray &file, int fileIndex, bool antialiased, const QList<QFontDatabase::WritingSystem> &writingSystems = QList<QFontDatabase::WritingSystem>()); - void addQPF2File(const QByteArray &file); #ifndef QT_NO_FREETYPE QStringList addTTFile(const QByteArray &file, const QByteArray &fontData = QByteArray()); +#endif // QT_NO_FREETYPE #endif - +#if defined(Q_WS_QWS) QDataStream *stream; QStringList fallbackFamilies; +#elif defined(Q_WS_S60) && defined(QT_NO_FREETYPE) + const QFontDatabaseS60Store *s60Store; #endif }; @@ -665,6 +695,118 @@ QtFontFamily *QFontDatabasePrivate::family(const QString &f, bool create) return families[pos]; } +#if defined(Q_WS_QWS) || defined(Q_WS_S60) && !defined(QT_NO_FREETYPE) +void QFontDatabasePrivate::addFont(const QString &familyname, const char *foundryname, int weight, bool italic, int pixelSize, + const QByteArray &file, int fileIndex, bool antialiased, + const QList<QFontDatabase::WritingSystem> &writingSystems) +{ +// qDebug() << "Adding font" << familyname << weight << italic << pixelSize << file << fileIndex << antialiased; + QtFontStyle::Key styleKey; + styleKey.style = italic ? QFont::StyleItalic : QFont::StyleNormal; + styleKey.weight = weight; + styleKey.stretch = 100; + QtFontFamily *f = family(familyname, true); + + if (writingSystems.isEmpty()) { + for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) { + f->writingSystems[ws] = QtFontFamily::Supported; + } + f->bogusWritingSystems = true; + } else { + for (int i = 0; i < writingSystems.count(); ++i) { + f->writingSystems[writingSystems.at(i)] = QtFontFamily::Supported; + } + } + + QtFontFoundry *foundry = f->foundry(QString::fromLatin1(foundryname), true); + QtFontStyle *style = foundry->style(styleKey, true); + style->smoothScalable = (pixelSize == 0); + style->antialiased = antialiased; + QtFontSize *size = style->pixelSize(pixelSize?pixelSize:SMOOTH_SCALABLE, true); + size->fileName = file; + size->fileIndex = fileIndex; + +#if defined(Q_WS_QWS) + if (stream) { + *stream << familyname << foundry->name << weight << quint8(italic) << pixelSize + << file << fileIndex << quint8(antialiased); + *stream << quint8(writingSystems.count()); + for (int i = 0; i < writingSystems.count(); ++i) + *stream << quint8(writingSystems.at(i)); + } +#else // ..in case of defined(Q_WS_S60) && !defined(QT_NO_FREETYPE) + f->fontFilename = file; + f->fontFileIndex = fileIndex; +#endif +} +#endif + +#if (defined(Q_WS_QWS) || defined(Q_WS_S60)) && !defined(QT_NO_FREETYPE) +QStringList QFontDatabasePrivate::addTTFile(const QByteArray &file, const QByteArray &fontData) +{ + QStringList families; + extern FT_Library qt_getFreetype(); + FT_Library library = qt_getFreetype(); + + int index = 0; + int numFaces = 0; + do { + FT_Face face; + FT_Error error; + if (!fontData.isEmpty()) { + error = FT_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face); + } else { + error = FT_New_Face(library, file, index, &face); + } + if (error != FT_Err_Ok) { + qDebug() << "FT_New_Face failed with index" << index << ":" << hex << error; + break; + } + numFaces = face->num_faces; + + int weight = QFont::Normal; + bool italic = face->style_flags & FT_STYLE_FLAG_ITALIC; + + if (face->style_flags & FT_STYLE_FLAG_BOLD) + weight = QFont::Bold; + + QList<QFontDatabase::WritingSystem> writingSystems; + // detect symbol fonts + for (int i = 0; i < face->num_charmaps; ++i) { + FT_CharMap cm = face->charmaps[i]; + if (cm->encoding == ft_encoding_adobe_custom + || cm->encoding == ft_encoding_symbol) { + writingSystems.append(QFontDatabase::Symbol); + break; + } + } + if (writingSystems.isEmpty()) { + TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2); + if (os2) { + quint32 unicodeRange[4] = { + os2->ulUnicodeRange1, os2->ulUnicodeRange2, os2->ulUnicodeRange3, os2->ulUnicodeRange4 + }; + quint32 codePageRange[2] = { + os2->ulCodePageRange1, os2->ulCodePageRange2 + }; + + writingSystems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + //for (int i = 0; i < writingSystems.count(); ++i) + // qDebug() << QFontDatabase::writingSystemName(writingSystems.at(i)); + } + } + + QString family = QString::fromAscii(face->family_name); + families.append(family); + addFont(family, /*foundry*/ "", weight, italic, + /*pixelsize*/ 0, file, index, /*antialias*/ true, writingSystems); + + FT_Done_Face(face); + ++index; + } while (index < numFaces); + return families; +} +#endif static const int scriptForWritingSystem[] = { QUnicodeTables::Common, // Any @@ -814,7 +956,7 @@ static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDe #endif #endif -#if defined(Q_WS_X11) || defined(Q_WS_WIN) +#if defined(Q_WS_X11) || defined(Q_WS_WIN) || defined(Q_WS_S60) static void getEngineData(const QFontPrivate *d, const QFontCache::Key &key) { // look for the requested font in the engine data cache @@ -866,8 +1008,6 @@ QMutex *qt_fontdatabase_mutex() return fontDatabaseMutex(); } -#define SMOOTH_SCALABLE 0xffff - QT_BEGIN_INCLUDE_NAMESPACE #if defined(Q_WS_X11) # include "qfontdatabase_x11.cpp" @@ -877,6 +1017,8 @@ QT_BEGIN_INCLUDE_NAMESPACE # include "qfontdatabase_win.cpp" #elif defined(Q_WS_QWS) # include "qfontdatabase_qws.cpp" +#elif defined(Q_WS_S60) +# include "qfontdatabase_s60.cpp" #endif QT_END_INCLUDE_NAMESPACE @@ -2254,7 +2396,16 @@ QString QFontDatabase::writingSystemSample(WritingSystem writingSystem) sample += QChar(0xac2f); break; case Vietnamese: + { + static const char vietnameseUtf8[] = { + char(0xef), char(0xbb), char(0xbf), char(0xe1), char(0xbb), char(0x97), + char(0xe1), char(0xbb), char(0x99), + char(0xe1), char(0xbb), char(0x91), + char(0xe1), char(0xbb), char(0x93), + }; + sample += QString::fromUtf8(vietnameseUtf8, sizeof(vietnameseUtf8)); break; + } case Ogham: sample += QChar(0x1681); sample += QChar(0x1682); diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h index eadb6ba..c169e29 100644 --- a/src/gui/text/qfontdatabase.h +++ b/src/gui/text/qfontdatabase.h @@ -151,7 +151,7 @@ public: private: static void createDatabase(); static void parseFontName(const QString &name, QString &foundry, QString &family); -#if defined(Q_WS_QWS) +#if defined(Q_WS_QWS) || defined(Q_WS_S60) static QFontEngine *findFont(int script, const QFontPrivate *fp, const QFontDef &request); #endif static void load(const QFontPrivate *d, int script); @@ -165,6 +165,7 @@ private: friend class QFontDialogPrivate; friend class QFontEngineMultiXLFD; friend class QFontEngineMultiQWS; + friend class QFontEngineMultiS60; QFontDatabasePrivate *d; }; diff --git a/src/gui/text/qfontdatabase_qws.cpp b/src/gui/text/qfontdatabase_qws.cpp index eb8a0cf..33b0728 100644 --- a/src/gui/text/qfontdatabase_qws.cpp +++ b/src/gui/text/qfontdatabase_qws.cpp @@ -50,7 +50,6 @@ #include <ft2build.h> #include FT_FREETYPE_H -#include FT_TRUETYPE_TABLES_H #endif #include "qfontengine_qpf_p.h" @@ -81,44 +80,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, const quint8 DatabaseVersion = 4; -void QFontDatabasePrivate::addFont(const QString &familyname, const char *foundryname, int weight, bool italic, int pixelSize, - const QByteArray &file, int fileIndex, bool antialiased, - const QList<QFontDatabase::WritingSystem> &writingSystems) -{ -// qDebug() << "Adding font" << familyname << weight << italic << pixelSize << file << fileIndex << antialiased; - QtFontStyle::Key styleKey; - styleKey.style = italic ? QFont::StyleItalic : QFont::StyleNormal; - styleKey.weight = weight; - styleKey.stretch = 100; - QtFontFamily *f = family(familyname, true); - - if (writingSystems.isEmpty()) { - for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) { - f->writingSystems[ws] = QtFontFamily::Supported; - } - f->bogusWritingSystems = true; - } else { - for (int i = 0; i < writingSystems.count(); ++i) { - f->writingSystems[writingSystems.at(i)] = QtFontFamily::Supported; - } - } - - QtFontFoundry *foundry = f->foundry(QString::fromLatin1(foundryname), true); - QtFontStyle *style = foundry->style(styleKey, true); - style->smoothScalable = (pixelSize == 0); - style->antialiased = antialiased; - QtFontSize *size = style->pixelSize(pixelSize?pixelSize:SMOOTH_SCALABLE, true); - size->fileName = file; - size->fileIndex = fileIndex; - - if (stream) { - *stream << familyname << foundry->name << weight << quint8(italic) << pixelSize - << file << fileIndex << quint8(antialiased); - *stream << quint8(writingSystems.count()); - for (int i = 0; i < writingSystems.count(); ++i) - *stream << quint8(writingSystems.at(i)); - } -} +// QFontDatabasePrivate::addFont() went into qfontdatabase.cpp #ifndef QT_NO_QWS_QPF2 void QFontDatabasePrivate::addQPF2File(const QByteArray &file) @@ -178,74 +140,9 @@ void QFontDatabasePrivate::addQPF2File(const QByteArray &file) ::close(f); #endif } -#endif - -#ifndef QT_NO_FREETYPE -QStringList QFontDatabasePrivate::addTTFile(const QByteArray &file, const QByteArray &fontData) -{ - QStringList families; - extern FT_Library qt_getFreetype(); - FT_Library library = qt_getFreetype(); - - int index = 0; - int numFaces = 0; - do { - FT_Face face; - FT_Error error; - if (!fontData.isEmpty()) { - error = FT_New_Memory_Face(library, (const FT_Byte *)fontData.constData(), fontData.size(), index, &face); - } else { - error = FT_New_Face(library, file, index, &face); - } - if (error != FT_Err_Ok) { - qDebug() << "FT_New_Face failed with index" << index << ":" << hex << error; - break; - } - numFaces = face->num_faces; - - int weight = QFont::Normal; - bool italic = face->style_flags & FT_STYLE_FLAG_ITALIC; - - if (face->style_flags & FT_STYLE_FLAG_BOLD) - weight = QFont::Bold; - - QList<QFontDatabase::WritingSystem> writingSystems; - // detect symbol fonts - for (int i = 0; i < face->num_charmaps; ++i) { - FT_CharMap cm = face->charmaps[i]; - if (cm->encoding == ft_encoding_adobe_custom - || cm->encoding == ft_encoding_symbol) { - writingSystems.append(QFontDatabase::Symbol); - break; - } - } - if (writingSystems.isEmpty()) { - TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, ft_sfnt_os2); - if (os2) { - quint32 unicodeRange[4] = { - os2->ulUnicodeRange1, os2->ulUnicodeRange2, os2->ulUnicodeRange3, os2->ulUnicodeRange4 - }; - quint32 codePageRange[2] = { - os2->ulCodePageRange1, os2->ulCodePageRange2 - }; - - writingSystems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); - //for (int i = 0; i < writingSystems.count(); ++i) - // qDebug() << QFontDatabase::writingSystemName(writingSystems.at(i)); - } - } +#endif // QT_NO_QWS_QPF2 - QString family = QString::fromAscii(face->family_name); - families.append(family); - addFont(family, /*foundry*/ "", weight, italic, - /*pixelsize*/ 0, file, index, /*antialias*/ true, writingSystems); - - FT_Done_Face(face); - ++index; - } while (index < numFaces); - return families; -} -#endif +// QFontDatabasePrivate::addTTFile() went into qfontdatabase.cpp static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt); diff --git a/src/gui/text/qfontdatabase_s60.cpp b/src/gui/text/qfontdatabase_s60.cpp new file mode 100644 index 0000000..416c3d1 --- /dev/null +++ b/src/gui/text/qfontdatabase_s60.cpp @@ -0,0 +1,414 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <private/qapplication_p.h> +#include "qdir.h" +#include "qfont_p.h" +#include "qfontengine_s60_p.h" +#include "qabstractfileengine.h" +#include "qdesktopservices.h" +#include "qt_s60_p.h" +#include "qendian.h" +#include <private/qwindowsurface_s60_p.h> +#include <private/qcore_symbian_p.h> +#if defined(QT_NO_FREETYPE) +#include <OPENFONT.H> +#endif + +QT_BEGIN_NAMESPACE + +QFileInfoList alternativeFilePaths(const QString &path, const QStringList &nameFilters, + QDir::Filters filters = QDir::NoFilter, QDir::SortFlags sort = QDir::NoSort, + bool uniqueFileNames = true) +{ + QFileInfoList result; + + // Prepare a 'soft to hard' drive list: W:, X: ... A:, Z: + QStringList driveStrings; + foreach (const QFileInfo &drive, QDir::drives()) + driveStrings.append(drive.absolutePath()); + driveStrings.sort(); + const QString zDriveString("Z:/"); + driveStrings.removeAll(zDriveString); + driveStrings.prepend(zDriveString); + + QStringList uniqueFileNameList; + for (int i = driveStrings.count() - 1; i >= 0; --i) { + const QDir dirOnDrive(driveStrings.at(i) + path); + const QFileInfoList entriesOnDrive = dirOnDrive.entryInfoList(nameFilters, filters, sort); + if (uniqueFileNames) { + foreach(const QFileInfo &entry, entriesOnDrive) { + if (!uniqueFileNameList.contains(entry.fileName())) { + uniqueFileNameList.append(entry.fileName()); + result.append(entry); + } + } + } else { + result.append(entriesOnDrive); + } + } + return result; +} + +#if defined(QT_NO_FREETYPE) +class QFontDatabaseS60StoreImplementation : public QFontDatabaseS60Store +{ +public: + QFontDatabaseS60StoreImplementation(); + ~QFontDatabaseS60StoreImplementation(); + + const QFontEngineS60Extensions *extension(const QString &typeface) const; + +private: + RHeap* m_heap; + CFontStore *m_store; + COpenFontRasterizer *m_rasterizer; + mutable QHash<QString, const QFontEngineS60Extensions *> m_extensions; +}; + +QFontDatabaseS60StoreImplementation::QFontDatabaseS60StoreImplementation() +{ + m_heap = User::ChunkHeap(NULL, 0x1000, 0x100000); + m_store = CFontStore::NewL(m_heap); + m_rasterizer = COpenFontRasterizer::NewL(TUid::Uid(0x101F7F5E)); + m_store->InstallRasterizerL(m_rasterizer); + + QStringList filters; + filters.append(QString::fromLatin1("*.ttf")); + filters.append(QString::fromLatin1("*.ccc")); + const QFileInfoList fontFiles = alternativeFilePaths(QString::fromLatin1("resource\\Fonts"), filters); + foreach (const QFileInfo &fontFileInfo, fontFiles) { + const QString fontFile = QDir::toNativeSeparators(fontFileInfo.absoluteFilePath()); + m_store->AddFileL(qt_QString2TPtrC(fontFile)); + } +} +QFontDatabaseS60StoreImplementation::~QFontDatabaseS60StoreImplementation() +{ + qDeleteAll(m_extensions); + delete m_rasterizer; + delete m_store; + m_heap->Close(); +} + +const QFontEngineS60Extensions *QFontDatabaseS60StoreImplementation::extension(const QString &typeface) const +{ + if (!m_extensions.contains(typeface)) { + CFont* font = NULL; + TFontSpec spec(qt_QString2TPtrC(typeface), 1); + spec.iHeight = 1; + const TInt err = m_store->GetNearestFontToDesignHeightInPixels(font, spec); + Q_ASSERT(err == KErrNone && font); + CBitmapFont *bitmapFont = static_cast<CBitmapFont*>(font); + m_extensions.insert(typeface, new QFontEngineS60Extensions(bitmapFont->OpenFont())); + } + return m_extensions.value(typeface); +} +#else +class QFontEngineFTS60 : public QFontEngineFT +{ +public: + QFontEngineFTS60(const QFontDef &fd); +}; + +QFontEngineFTS60::QFontEngineFTS60(const QFontDef &fd) + : QFontEngineFT(fd) +{ + default_hint_style = HintFull; +} +#endif // defined(QT_NO_FREETYPE) + +/* + QFontEngineS60::pixelsToPoints, QFontEngineS60::pointsToPixels, QFontEngineMultiS60::QFontEngineMultiS60 + and QFontEngineMultiS60::QFontEngineMultiS60 should be in qfontengine_s60.cpp. But since also the + Freetype based font rendering need them, they are here. +*/ +qreal QFontEngineS60::pixelsToPoints(qreal pixels, Qt::Orientation orientation) +{ + return (orientation == Qt::Horizontal? + S60->screenDevice()->HorizontalPixelsToTwips(pixels) + :S60->screenDevice()->VerticalPixelsToTwips(pixels)) / KTwipsPerPoint; +} + +qreal QFontEngineS60::pointsToPixels(qreal points, Qt::Orientation orientation) +{ + const int twips = points * KTwipsPerPoint; + return orientation == Qt::Horizontal? + S60->screenDevice()->HorizontalTwipsToPixels(twips) + :S60->screenDevice()->VerticalTwipsToPixels(twips); +} + +QFontEngineMultiS60::QFontEngineMultiS60(QFontEngine *first, int script, const QStringList &fallbackFamilies) + : QFontEngineMulti(fallbackFamilies.size() + 1) + , m_script(script) + , m_fallbackFamilies(fallbackFamilies) +{ + engines[0] = first; + first->ref.ref(); + fontDef = engines[0]->fontDef; +} + +void QFontEngineMultiS60::loadEngine(int at) +{ + Q_ASSERT(at < engines.size()); + Q_ASSERT(engines.at(at) == 0); + + QFontDef request = fontDef; + request.styleStrategy |= QFont::NoFontMerging; + request.family = m_fallbackFamilies.at(at-1); + engines[at] = QFontDatabase::findFont(m_script, + /*fontprivate*/0, + request); + Q_ASSERT(engines[at]); +} + +static void initializeDb() +{ + QFontDatabasePrivate *db = privateDb(); + if(!db || db->count) + return; + +#if defined(QT_NO_FREETYPE) + if (!db->s60Store) + db->s60Store = new QFontDatabaseS60StoreImplementation; + + QS60WindowSurface::unlockBitmapHeap(); + const int numTypeFaces = QS60Data::screenDevice()->NumTypefaces(); + const QFontDatabaseS60StoreImplementation *store = dynamic_cast<const QFontDatabaseS60StoreImplementation*>(db->s60Store); + Q_ASSERT(store); + for (int i = 0; i < numTypeFaces; i++) { + TTypefaceSupport typefaceSupport; + QS60Data::screenDevice()->TypefaceSupport(typefaceSupport, i); + CFont *font; // We have to get a font instance in order to know all the details + TFontSpec fontSpec(typefaceSupport.iTypeface.iName, 11); + QS60Data::screenDevice()->GetNearestFontInPixels(font, fontSpec); + if (font->TypeUid() == KCFbsFontUid) { + TOpenFontFaceAttrib faceAttrib; + const CFbsFont *cfbsFont = dynamic_cast<const CFbsFont *>(font); + Q_ASSERT(cfbsFont); + cfbsFont->GetFaceAttrib(faceAttrib); + + QtFontStyle::Key styleKey; + styleKey.style = faceAttrib.IsItalic()?QFont::StyleItalic:QFont::StyleNormal; + styleKey.weight = faceAttrib.IsBold()?QFont::Bold:QFont::Normal; + + QString familyName((const QChar *)typefaceSupport.iTypeface.iName.Ptr(), typefaceSupport.iTypeface.iName.Length()); + QtFontFamily *family = db->family(familyName, true); + family->fixedPitch = faceAttrib.IsMonoWidth(); + QtFontFoundry *foundry = family->foundry(QString(), true); + QtFontStyle *style = foundry->style(styleKey, true); + style->smoothScalable = typefaceSupport.iIsScalable; + style->pixelSize(0, true); + + const QFontEngineS60Extensions *extension = store->extension(familyName); + const QByteArray os2Table = extension->getSfntTable(MAKE_TAG('O', 'S', '/', '2')); + const unsigned char* data = reinterpret_cast<const unsigned char*>(os2Table.constData()); + const unsigned char* ulUnicodeRange = data + 42; + quint32 unicodeRange[4] = { + qFromBigEndian<quint32>(ulUnicodeRange), + qFromBigEndian<quint32>(ulUnicodeRange + 4), + qFromBigEndian<quint32>(ulUnicodeRange + 8), + qFromBigEndian<quint32>(ulUnicodeRange + 12) + }; + const unsigned char* ulCodePageRange = data + 78; + quint32 codePageRange[2] = { + qFromBigEndian<quint32>(ulCodePageRange), + qFromBigEndian<quint32>(ulCodePageRange + 4) + }; + const QList<QFontDatabase::WritingSystem> writingSystems = + determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + foreach (const QFontDatabase::WritingSystem system, writingSystems) + family->writingSystems[system] = QtFontFamily::Supported; + } + QS60Data::screenDevice()->ReleaseFont(font); + } + QS60WindowSurface::lockBitmapHeap(); +#else // defined(QT_NO_FREETYPE) + QDir dir(QDesktopServices::storageLocation(QDesktopServices::FontsLocation)); + dir.setNameFilters(QStringList() << QLatin1String("*.ttf") + << QLatin1String("*.ttc") << QLatin1String("*.pfa") + << QLatin1String("*.pfb")); + for (int i = 0; i < int(dir.count()); ++i) { + const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i])); + db->addTTFile(file); + } +#endif // defined(QT_NO_FREETYPE) +} + +static inline void load(const QString &family = QString(), int script = -1) +{ + Q_UNUSED(family) + Q_UNUSED(script) + initializeDb(); +} + +static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt) +{ + Q_UNUSED(fnt); +} + +bool QFontDatabase::supportsThreadedFontRendering() +{ + return false; +} + +static +QFontDef cleanedFontDef(const QFontDef &req) +{ + QFontDef result = req; + if (result.pixelSize <= 0) { + result.pixelSize = QFontEngineS60::pointsToPixels(qMax(qreal(1.0), result.pointSize)); + result.pointSize = 0; + } + return result; +} + +QFontEngine *QFontDatabase::findFont(int script, const QFontPrivate *, const QFontDef &req) +{ + const QFontCache::Key key(cleanedFontDef(req), script); + + if (!privateDb()->count) + initializeDb(); + + QFontEngine *fe = QFontCache::instance()->findEngine(key); + if (!fe) { + // Making sure that fe->fontDef.family will be an existing font. + initializeDb(); + QFontDatabasePrivate *db = privateDb(); + QtFontDesc desc; + QList<int> blacklistedFamilies; + match(script, req, req.family, QString(), -1, &desc, blacklistedFamilies); + if (!desc.family) // falling back to application font + desc.family = db->family(QApplication::font().defaultFamily()); + Q_ASSERT(desc.family); + + // Making sure that desc.family supports the requested script + QtFontDesc mappedDesc; + bool supportsScript = false; + do { + match(script, req, QString(), QString(), -1, &mappedDesc, blacklistedFamilies); + if (mappedDesc.family == desc.family) { + supportsScript = true; + break; + } + blacklistedFamilies.append(mappedDesc.familyIndex); + } while (mappedDesc.family); + if (!supportsScript) { + blacklistedFamilies.clear(); + match(script, req, QString(), QString(), -1, &mappedDesc, blacklistedFamilies); + if (mappedDesc.family) + desc = mappedDesc; + } + + const QString fontFamily = desc.family->name; + QFontDef request = req; + request.family = fontFamily; +#if defined(QT_NO_FREETYPE) + const QFontDatabaseS60StoreImplementation *store = dynamic_cast<const QFontDatabaseS60StoreImplementation*>(db->s60Store); + Q_ASSERT(store); + const QFontEngineS60Extensions *extension = store->extension(fontFamily); + fe = new QFontEngineS60(request, extension); +#else + QFontEngine::FaceId faceId; + const QtFontFamily * const reqQtFontFamily = db->family(fontFamily); + faceId.filename = reqQtFontFamily->fontFilename; + faceId.index = reqQtFontFamily->fontFileIndex; + + QFontEngineFTS60 *fte = new QFontEngineFTS60(cleanedFontDef(request)); + if (fte->init(faceId, true, QFontEngineFT::Format_A8)) + fe = fte; + else + delete fte; +#endif + + Q_ASSERT(fe); + if (script == QUnicodeTables::Common + && !(req.styleStrategy & QFont::NoFontMerging) + && !fe->symbol) { + + QStringList commonFonts; + for (int ws = 1; ws < QFontDatabase::WritingSystemsCount; ++ws) { + if (scriptForWritingSystem[ws] != script) + continue; + for (int i = 0; i < db->count; ++i) { + if (db->families[i]->writingSystems[ws] & QtFontFamily::Supported) + commonFonts.append(db->families[i]->name); + } + } + + // Hack: Prioritize .ccc fonts + const QString niceEastAsianFont(QLatin1String("Sans MT 936_S60")); + if (commonFonts.removeAll(niceEastAsianFont) > 0) + commonFonts.prepend(niceEastAsianFont); + + fe = new QFontEngineMultiS60(fe, script, commonFonts); + } + } + fe->ref.ref(); + QFontCache::instance()->insertEngine(key, fe); + return fe; +} + +void QFontDatabase::load(const QFontPrivate *d, int script) +{ + QFontEngine *fe = 0; + QFontDef req = d->request; + + if (!d->engineData) { + const QFontCache::Key key(cleanedFontDef(req), script); + getEngineData(d, key); + } + + // the cached engineData could have already loaded the engine we want + if (d->engineData->engines[script]) + fe = d->engineData->engines[script]; + + if (!fe) { + if (qt_enable_test_font && req.family == QLatin1String("__Qt__Box__Engine__")) { + fe = new QTestFontEngine(req.pixelSize); + fe->fontDef = req; + } else { + fe = findFont(script, d, req); + } + d->engineData->engines[script] = fe; + } +} + +QT_END_NAMESPACE diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index d7a9c23..c2c23ee 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -819,7 +819,7 @@ QFontEngineGlyphCache *QFontEngine::glyphCache(QFontEngineGlyphCache::Type key, return 0; } -#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_QWS) +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_S60) static inline QFixed kerning(int left, int right, const QFontEngine::KernPair *pairs, int numPairs) { uint left_right = (left << 16) + right; @@ -1110,6 +1110,18 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode) return 0; } +Q_GLOBAL_STATIC_WITH_INITIALIZER(QVector<QRgb>, qt_grayPalette, { + x->resize(256); + QRgb *it = x->data(); + for (int i = 0; i < x->size(); ++i, ++it) + *it = 0xff000000 | i | (i<<8) | (i<<16); +}); + +const QVector<QRgb> &QFontEngine::grayPalette() +{ + return *qt_grayPalette(); +} + // ------------------------------------------------------------------ // The box font engine // ------------------------------------------------------------------ diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h index 284904b..649d78b 100644 --- a/src/gui/text/qfontengine_ft_p.h +++ b/src/gui/text/qfontengine_ft_p.h @@ -255,7 +255,7 @@ public: QGlyphSet *loadTransformedGlyphSet(const QTransform &matrix); bool loadGlyphs(QGlyphSet *gs, glyph_t *glyphs, int num_glyphs, GlyphFormat format = Format_Render); -#if defined(Q_WS_QWS) +#if defined(Q_WS_QWS) || defined(Q_WS_S60) virtual void draw(QPaintEngine * /*p*/, qreal /*x*/, qreal /*y*/, const QTextItemInt & /*si*/) {} #endif diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index dc18991..a5aa097 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -113,6 +113,10 @@ public: QPF1, QPF2, Proxy, + + // S60 types + S60FontEngine, // Cannot be simply called "S60". Reason is qt_s60Data.h + TestFontEngine = 0x1000 }; @@ -164,7 +168,7 @@ public: virtual void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const {} virtual void doKerning(QGlyphLayout *, QTextEngine::ShaperFlags) const; -#if !defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC) +#if !defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC) && !defined(Q_WS_S60) virtual void draw(QPaintEngine *p, qreal x, qreal y, const QTextItemInt &si) = 0; #endif virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, @@ -231,7 +235,7 @@ public: bool symbol; mutable HB_FontRec hbFont; mutable HB_Face hbFace; -#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_QWS) +#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_WS_S60) struct KernPair { uint left_right; QFixed adjust; @@ -247,6 +251,9 @@ public: int glyphFormat; +protected: + static const QVector<QRgb> &grayPalette(); + private: /// remove old entries from the glyph cache. Helper method for the setGlyphCache ones. void expireGlyphCache(); @@ -322,7 +329,7 @@ public: virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const; virtual void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const; -#if !defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC) +#if !defined(Q_WS_X11) && !defined(Q_WS_WIN) && !defined(Q_WS_MAC) && !defined(Q_WS_S60) void draw(QPaintEngine *p, qreal x, qreal y, const QTextItemInt &si); #endif virtual void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags); @@ -614,4 +621,8 @@ QT_END_NAMESPACE # include "private/qfontengine_win_p.h" #endif +#if defined(Q_WS_S60) && !defined(QT_NO_FREETYPE) +# include "private/qfontengine_ft_p.h" +#endif + #endif // QFONTENGINE_P_H diff --git a/src/gui/text/qfontengine_s60.cpp b/src/gui/text/qfontengine_s60.cpp new file mode 100644 index 0000000..2e1abb2 --- /dev/null +++ b/src/gui/text/qfontengine_s60.cpp @@ -0,0 +1,326 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfontengine_s60_p.h" +#include "qtextengine_p.h" +#include "qglobal.h" +#include <private/qapplication_p.h> +#include <private/qwindowsurface_s60_p.h> +#include "qimage.h" +#include "qt_s60_p.h" + +#include <e32base.h> +#include <e32std.h> +#include <EIKENV.H> +#include <GDI.H> + +QT_BEGIN_NAMESPACE + +static const int maxFontSizeInPixels = 60; + +QFontEngineS60Extensions::QFontEngineS60Extensions(COpenFont *font) + : m_font(font) + , m_cmap(0) + , m_symbolCMap(false) +{ + TAny *shapingExtension = NULL; + m_font->ExtendedInterface(KUidOpenFontShapingExtension, shapingExtension); + m_shapingExtension = static_cast<MOpenFontShapingExtension*>(shapingExtension); + TAny *trueTypeExtension = NULL; + m_font->ExtendedInterface(KUidOpenFontTrueTypeExtension, trueTypeExtension); + m_trueTypeExtension = static_cast<MOpenFontTrueTypeExtension*>(trueTypeExtension); + Q_ASSERT(m_shapingExtension && m_trueTypeExtension); +} + +QByteArray QFontEngineS60Extensions::getSfntTable(uint tag) const +{ + Q_ASSERT(m_trueTypeExtension->HasTrueTypeTable(tag)); + TInt error = KErrNone; + TInt tableByteLength = 0; + TAny *table = m_trueTypeExtension->GetTrueTypeTable(error, tag, &tableByteLength); + QByteArray result(static_cast<const char*>(table), tableByteLength); + m_trueTypeExtension->ReleaseTrueTypeTable(table); + return result; +} + +const unsigned char *QFontEngineS60Extensions::cmap() const +{ + if (!m_cmap) { + m_cmapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p')); + int size = 0; + m_cmap = QFontEngineS60::getCMap(reinterpret_cast<const uchar *>(m_cmapTable.constData()), m_cmapTable.size(), &m_symbolCMap, &size); + } + return m_cmap; +} + +QPainterPath QFontEngineS60Extensions::glyphOutline(glyph_t glyph) const +{ + QPainterPath result; + QPolygonF polygon; + TInt glyphIndex = glyph; + TInt pointNumber = 0; + TInt x, y; + while (m_shapingExtension->GlyphPointInFontUnits(glyphIndex, pointNumber++, x, y)) { + const QPointF point(qreal(x) / 0xffff, qreal(y) / 0xffff); + if (polygon.contains(point)) { + result.addPolygon(polygon); + result.closeSubpath(); + polygon.clear(); + } else { + polygon.append(point); + } + } + return result; +} + +// duplicated from qfontengine_xyz.cpp +static inline unsigned int getChar(const QChar *str, int &i, const int len) +{ + unsigned int uc = str[i].unicode(); + if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) { + uint low = str[i+1].unicode(); + if (low >= 0xdc00 && low < 0xe000) { + uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000; + ++i; + } + } + return uc; +} + +QFontEngineS60::QFontEngineS60(const QFontDef &request, const QFontEngineS60Extensions *extensions) + : m_extensions(extensions) +{ + QFontEngine::fontDef = request; + m_fontSizeInPixels = (request.pixelSize >= 0)? + request.pixelSize:pointsToPixels(request.pointSize); + QS60WindowSurface::unlockBitmapHeap(); + m_textRenderBitmap = new (ELeave) CFbsBitmap(); + const TSize bitmapSize(1, 1); // It is just a dummy bitmap that I need to keep the font alive (or maybe not) + User::LeaveIfError(m_textRenderBitmap->Create(bitmapSize, EGray256)); + m_textRenderBitmapDevice = CFbsBitmapDevice::NewL(m_textRenderBitmap); + User::LeaveIfError(m_textRenderBitmapDevice->CreateContext(m_textRenderBitmapGc)); + cache_cost = sizeof(QFontEngineS60) + bitmapSize.iHeight * bitmapSize.iWidth * 4; + + TFontSpec fontSpec(qt_QString2TPtrC(request.family), m_fontSizeInPixels); + fontSpec.iFontStyle.SetBitmapType(EAntiAliasedGlyphBitmap); + fontSpec.iFontStyle.SetPosture(request.style == QFont::StyleNormal?EPostureUpright:EPostureItalic); + fontSpec.iFontStyle.SetStrokeWeight(request.weight > QFont::Normal?EStrokeWeightBold:EStrokeWeightNormal); + const TInt errorCode = m_textRenderBitmapDevice->GetNearestFontInPixels(m_font, fontSpec); + Q_ASSERT(errorCode == 0); + m_textRenderBitmapGc->UseFont(m_font); + QS60WindowSurface::lockBitmapHeap(); +} + +QFontEngineS60::~QFontEngineS60() +{ + QS60WindowSurface::unlockBitmapHeap(); + m_textRenderBitmapGc->DiscardFont(); + delete m_textRenderBitmapGc; + m_textRenderBitmapGc = NULL; + m_textRenderBitmapDevice->ReleaseFont(m_font); + delete m_textRenderBitmapDevice; + m_textRenderBitmapDevice = NULL; + delete m_textRenderBitmap; + m_textRenderBitmap = NULL; + QS60WindowSurface::lockBitmapHeap(); +} + +bool QFontEngineS60::stringToCMap(const QChar *characters, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const +{ + if (*nglyphs < len) { + *nglyphs = len; + return false; + } + + HB_Glyph *g = glyphs->glyphs; + const unsigned char* cmap = m_extensions->cmap(); + for (int i = 0; i < len; ++i) { + const unsigned int uc = getChar(characters, i, len); + *g++ = QFontEngine::getTrueTypeGlyphIndex(cmap, uc); + } + + glyphs->numGlyphs = g - glyphs->glyphs; + *nglyphs = glyphs->numGlyphs; + + if (flags & QTextEngine::GlyphIndicesOnly) + return true; + + recalcAdvances(glyphs, flags); + return true; +} + +void QFontEngineS60::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const +{ + Q_UNUSED(flags); + for (int i = 0; i < glyphs->numGlyphs; i++) { + const glyph_metrics_t bbox = boundingBox_const(glyphs->glyphs[i]); + glyphs->advances_x[i] = glyphs->offsets[i].x = bbox.xoff; + glyphs->advances_y[i] = glyphs->offsets[i].y = bbox.yoff; + } +} + +QImage QFontEngineS60::alphaMapForGlyph(glyph_t glyph) +{ + TOpenFontCharMetrics metrics; + const TUint8 *glyphBitmapBytes; + TSize glyphBitmapSize; + getCharacterData(glyph, metrics, glyphBitmapBytes, glyphBitmapSize); + QImage result(glyphBitmapBytes, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight, glyphBitmapSize.iWidth, QImage::Format_Indexed8); + result.setColorTable(grayPalette()); + + // The above setColorTable() call detached the image data anyway, so why not shape tha data a bit, while we can. + // CFont::GetCharacterData() returns 8-bit data that obviously was 4-bit data before, and converted to 8-bit incorrectly. + // The data values are 0x00, 0x10 ... 0xe0, 0xf0. So, a real opaque 0xff is never reached, which we get punished + // for every time we want to blit this glyph in the raster paint engine. + // "Fix" is to convert all 0xf0 to 0xff. Is fine, quality wise, and I assume faster than correcting all values. + // Blitting is however, evidentially faster now. + const int bpl = result.bytesPerLine(); + for (int row = 0; row < result.height(); ++row) { + uchar *scanLine = result.scanLine(row); + for (int column = 0; column < bpl; ++column) { + if (*scanLine == 0xf0) + *scanLine = 0xff; + scanLine++; + } + } + + return result; +} + +glyph_metrics_t QFontEngineS60::boundingBox(const QGlyphLayout &glyphs) +{ + if (glyphs.numGlyphs == 0) + return glyph_metrics_t(); + + QFixed w = 0; + for (int i = 0; i < glyphs.numGlyphs; ++i) + w += glyphs.effectiveAdvance(i); + + return glyph_metrics_t(0, -ascent(), w, ascent()+descent()+1, w, 0); +} + +glyph_metrics_t QFontEngineS60::boundingBox_const(glyph_t glyph) const +{ + TOpenFontCharMetrics metrics; + const TUint8 *glyphBitmapBytes; + TSize glyphBitmapSize; + getCharacterData(glyph, metrics, glyphBitmapBytes, glyphBitmapSize); + TRect glyphBounds; + metrics.GetHorizBounds(glyphBounds); + const glyph_metrics_t result( + glyphBounds.iTl.iX, + glyphBounds.iTl.iY, + glyphBounds.Width(), + glyphBounds.Height(), + metrics.HorizAdvance(), + 0 + ); + return result; +} + +glyph_metrics_t QFontEngineS60::boundingBox(glyph_t glyph) +{ + return boundingBox_const(glyph); +} + +QFixed QFontEngineS60::ascent() const +{ + return m_font->FontMaxAscent(); +} + +QFixed QFontEngineS60::descent() const +{ + return m_font->FontMaxDescent(); +} + +QFixed QFontEngineS60::leading() const +{ + return 0; +} + +qreal QFontEngineS60::maxCharWidth() const +{ + return m_font->MaxCharWidthInPixels(); +} + +const char *QFontEngineS60::name() const +{ + return "QFontEngineS60"; +} + +bool QFontEngineS60::canRender(const QChar *string, int len) +{ + const unsigned char *cmap = m_extensions->cmap(); + for (int i = 0; i < len; ++i) { + const unsigned int uc = getChar(string, i, len); + if (QFontEngine::getTrueTypeGlyphIndex(cmap, uc) == 0) + return false; + } + return true; +} + +QByteArray QFontEngineS60::getSfntTable(uint tag) const +{ + return m_extensions->getSfntTable(tag); +} + +QFontEngine::Type QFontEngineS60::type() const +{ + return QFontEngine::S60FontEngine; +} + +void QFontEngineS60::getCharacterData(glyph_t glyph, TOpenFontCharMetrics& metrics, const TUint8*& bitmap, TSize& bitmapSize) const +{ + // Setting the most significant bit tells GetCharacterData + // that 'code' is a Glyph ID, rather than a UTF-16 value + const TUint specialCode = (TUint)glyph | 0x80000000; + + const CFont::TCharacterDataAvailability availability = + m_font->GetCharacterData(specialCode, metrics, bitmap, bitmapSize); + const glyph_t fallbackGlyph = '?'; + if (availability != CFont::EAllCharacterData) { + const CFont::TCharacterDataAvailability fallbackAvailability = + m_font->GetCharacterData(fallbackGlyph, metrics, bitmap, bitmapSize); + Q_ASSERT(fallbackAvailability == CFont::EAllCharacterData); + } +} + +QT_END_NAMESPACE diff --git a/src/gui/text/qfontengine_s60_p.h b/src/gui/text/qfontengine_s60_p.h new file mode 100644 index 0000000..2998de8 --- /dev/null +++ b/src/gui/text/qfontengine_s60_p.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFONTENGINE_S60_P_H +#define QFONTENGINE_S60_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qconfig.h" +#include "qfontengine_p.h" +#include "qsize.h" +#include <OPENFONT.H> + +class CFbsBitmap; +class CFbsBitmapDevice; +class CFbsBitGc; +class CFont; + +QT_BEGIN_NAMESPACE + +// ..gives us access to truetype tables, UTF-16<->GlyphID mapping, and glyph outlines +class QFontEngineS60Extensions +{ +public: + QFontEngineS60Extensions(COpenFont *font); + + QByteArray getSfntTable(uint tag) const; + const unsigned char *cmap() const; + QPainterPath glyphOutline(glyph_t glyph) const; + +private: + COpenFont *m_font; + const MOpenFontShapingExtension *m_shapingExtension; + mutable MOpenFontTrueTypeExtension *m_trueTypeExtension; + mutable const unsigned char *m_cmap; + mutable bool m_symbolCMap; + mutable QByteArray m_cmapTable; +}; + +class QFontEngineS60 : public QFontEngine +{ +public: + QFontEngineS60(const QFontDef &fontDef, const QFontEngineS60Extensions *extensions); + ~QFontEngineS60(); + + bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const; + void recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const; + + QImage alphaMapForGlyph(glyph_t glyph); + + glyph_metrics_t boundingBox(const QGlyphLayout &glyphs); + glyph_metrics_t boundingBox_const(glyph_t glyph) const; // Const correctnes quirk. + glyph_metrics_t boundingBox(glyph_t glyph); + + QFixed ascent() const; + QFixed descent() const; + QFixed leading() const; + qreal maxCharWidth() const; + qreal minLeftBearing() const { return 0; } + qreal minRightBearing() const { return 0; } + + QByteArray getSfntTable(uint tag) const; + + static qreal pixelsToPoints(qreal pixels, Qt::Orientation orientation = Qt::Horizontal); + static qreal pointsToPixels(qreal points, Qt::Orientation orientation = Qt::Horizontal); + + const char *name() const; + + bool canRender(const QChar *string, int len); + + Type type() const; + +private: + friend class QFontPrivate; + + QFixed glyphAdvance(HB_Glyph glyph) const; + void getCharacterData(glyph_t glyph, TOpenFontCharMetrics& metrics, const TUint8*& bitmap, TSize& bitmapSize) const; + + CFbsBitmap *m_textRenderBitmap; + CFbsBitmapDevice *m_textRenderBitmapDevice; + CFbsBitGc *m_textRenderBitmapGc; + CFont* m_font; + const QFontEngineS60Extensions *m_extensions; + qreal m_fontSizeInPixels; +}; + +class QFontEngineMultiS60 : public QFontEngineMulti +{ +public: + QFontEngineMultiS60(QFontEngine *first, int script, const QStringList &fallbackFamilies); + void loadEngine(int at); + + int m_script; + QStringList m_fallbackFamilies; +}; + +QT_END_NAMESPACE + +#endif // QFONTENGINE_S60_P_H diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index f3d025c..69e1ee4 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -1611,6 +1611,9 @@ void QTextControlPrivate::mouseMoveEvent(Qt::MouseButtons buttons, const QPointF if (cursor.position() != oldCursorPos) emit q->cursorPositionChanged(); _q_updateCurrentCharFormatAndSelection(); + if (QInputContext *ic = inputContext()) { + ic->update(); + } } else { //emit q->visibilityRequest(QRectF(mousePos, QSizeF(1, 1))); if (cursor.position() != oldCursorPos) @@ -1813,13 +1816,18 @@ bool QTextControlPrivate::dropEvent(const QMimeData *mimeData, const QPointF &po void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) { + Q_Q(QTextControl); if (!(interactionFlags & Qt::TextEditable) || cursor.isNull()) { e->ignore(); return; } - cursor.beginEditBlock(); + bool isGettingInput = !e->commitString().isEmpty() || !e->preeditString().isEmpty() + || e->replacementLength() > 0; - cursor.removeSelectedText(); + if (isGettingInput) { + cursor.beginEditBlock(); + cursor.removeSelectedText(); + } // insert commit string if (!e->commitString().isEmpty() || e->replacementLength()) { @@ -1829,6 +1837,18 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) c.insertText(e->commitString()); } + for (int i = 0; i < e->attributes().size(); ++i) { + const QInputMethodEvent::Attribute &a = e->attributes().at(i); + if (a.type == QInputMethodEvent::Selection) { + QTextCursor oldCursor = cursor; + int blockStart = a.start + cursor.block().position(); + cursor.setPosition(blockStart, QTextCursor::MoveAnchor); + cursor.setPosition(blockStart + a.length, QTextCursor::KeepAnchor); + q->ensureCursorVisible(); + repaintOldAndNewSelection(oldCursor); + } + } + QTextBlock block = cursor.block(); QTextLayout *layout = block.layout(); layout->setPreeditArea(cursor.position() - block.position(), e->preeditString()); @@ -1852,7 +1872,9 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) } } layout->setAdditionalFormats(overrides); - cursor.endEditBlock(); + + if (isGettingInput) + cursor.endEditBlock(); } QVariant QTextControl::inputMethodQuery(Qt::InputMethodQuery property) const @@ -1865,11 +1887,15 @@ QVariant QTextControl::inputMethodQuery(Qt::InputMethodQuery property) const case Qt::ImFont: return QVariant(d->cursor.charFormat().font()); case Qt::ImCursorPosition: - return QVariant(d->cursor.selectionEnd() - block.position()); + return QVariant(d->cursor.position() - block.position()); case Qt::ImSurroundingText: return QVariant(block.text()); case Qt::ImCurrentSelection: return QVariant(d->cursor.selectedText()); + case Qt::ImMaximumTextLength: + return QVariant(); // No limit. + case Qt::ImAnchorPosition: + return QVariant(qBound(0, d->cursor.anchor() - block.position(), block.length())); default: return QVariant(); } diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index fc33d43..e4d24ff 100644 --- a/src/gui/text/text.pri +++ b/src/gui/text/text.pri @@ -106,9 +106,27 @@ embedded { DEFINES += QT_NO_FONTCONFIG } +symbian { + SOURCES += \ + text/qfont_s60.cpp + contains(QT_CONFIG, freetype) { + SOURCES += \ + text/qfontengine_ft.cpp + HEADERS += \ + text/qfontengine_ft_p.h + DEFINES += \ + QT_NO_FONTCONFIG + } else { + SOURCES += \ + text/qfontengine_s60.cpp + HEADERS += \ + text/qfontengine_s60_p.h + LIBS += -lfntstr -lecom + } +} + contains(QT_CONFIG, freetype) { SOURCES += \ - ../3rdparty/freetype/builds/unix/ftsystem.c \ ../3rdparty/freetype/src/base/ftbase.c \ ../3rdparty/freetype/src/base/ftbbox.c \ ../3rdparty/freetype/src/base/ftdebug.c \ @@ -152,10 +170,19 @@ contains(QT_CONFIG, freetype) { ../3rdparty/freetype/src/autofit/afloader.c\ ../3rdparty/freetype/src/autofit/autofit.c + symbian { + SOURCES += \ + ../3rdparty/freetype/src/base/ftsystem.c + } else { + SOURCES += \ + ../3rdparty/freetype/builds/unix/ftsystem.c + INCLUDEPATH += \ + ../3rdparty/freetype/builds/unix + } + INCLUDEPATH += \ ../3rdparty/freetype/src \ - ../3rdparty/freetype/include \ - ../3rdparty/freetype/builds/unix + ../3rdparty/freetype/include DEFINES += FT2_BUILD_LIBRARY FT_CONFIG_OPTION_SYSTEM_ZLIB diff --git a/src/gui/util/qcompleter.cpp b/src/gui/util/qcompleter.cpp index faa4e7b..8410a69 100644 --- a/src/gui/util/qcompleter.cpp +++ b/src/gui/util/qcompleter.cpp @@ -482,7 +482,7 @@ QMatchData QCompletionEngine::filterHistory() for (int i = 0; i < source->rowCount(); i++) { QString str = source->index(i, c->column).data().toString(); if (str.startsWith(c->prefix, c->cs) -#if !defined(Q_OS_WIN) || defined(Q_OS_WINCE) +#if (!defined(Q_OS_WIN) || defined(Q_OS_WINCE)) && !defined(Q_OS_SYMBIAN) && (!dirModel || QDir::toNativeSeparators(str) != QDir::separator()) #endif ) @@ -987,7 +987,7 @@ void QCompleter::setModel(QAbstractItemModel *model) delete oldModel; #ifndef QT_NO_DIRMODEL if (qobject_cast<QDirModel *>(model)) { -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#if (defined(Q_OS_WIN) && !defined(Q_OS_WINCE)) || defined(Q_OS_SYMBIAN) setCaseSensitivity(Qt::CaseInsensitive); #else setCaseSensitivity(Qt::CaseSensitive); @@ -1620,7 +1620,7 @@ QString QCompleter::pathFromIndex(const QModelIndex& index) const idx = parent.sibling(parent.row(), index.column()); } while (idx.isValid()); -#if !defined(Q_OS_WIN) || defined(Q_OS_WINCE) +#if (!defined(Q_OS_WIN) || defined(Q_OS_WINCE)) && !defined(Q_OS_SYMBIAN) if (list.count() == 1) // only the separator or some other text return list[0]; list[0].clear() ; // the join below will provide the separator @@ -1654,7 +1654,10 @@ QStringList QCompleter::splitPath(const QString& path) const QString pathCopy = QDir::toNativeSeparators(path); QString sep = QDir::separator(); -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#if defined(Q_OS_SYMBIAN) + if (pathCopy == QLatin1String("\\")) + return QStringList(pathCopy); +#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE) if (pathCopy == QLatin1String("\\") || pathCopy == QLatin1String("\\\\")) return QStringList(pathCopy); QString doubleSlash(QLatin1String("\\\\")); @@ -1667,7 +1670,9 @@ QStringList QCompleter::splitPath(const QString& path) const QRegExp re(QLatin1String("[") + QRegExp::escape(sep) + QLatin1String("]")); QStringList parts = pathCopy.split(re); -#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) +#if defined(Q_OS_SYMBIAN) + // Do nothing +#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE) if (!doubleSlash.isEmpty()) parts[0].prepend(doubleSlash); #else diff --git a/src/gui/util/qdesktopservices.cpp b/src/gui/util/qdesktopservices.cpp index 84aa16e..b84b63f 100644 --- a/src/gui/util/qdesktopservices.cpp +++ b/src/gui/util/qdesktopservices.cpp @@ -53,6 +53,8 @@ #include "qdesktopservices_win.cpp" #elif defined(Q_WS_MAC) #include "qdesktopservices_mac.cpp" +#elif defined(Q_WS_S60) +#include "qdesktopservices_s60.cpp" #endif #include <qhash.h> @@ -285,6 +287,11 @@ void QDesktopServices::unsetUrlHandler(const QString &scheme) \note The storage location returned can be a directory that does not exist; i.e., it may need to be created by the system or the user. + + \note On Symbian OS, DataLocation and ApplicationsLocation always point to appropriate + folder on same drive with executable. FontsLocation always points to folder on ROM drive. + Rest of the standard locations point to folder on same drive with executable, except + that if executable is in ROM the folder from C drive is returned. \note On Mac OS X, DataLocation does not include QCoreApplication::organizationName. Use code like this to add it: diff --git a/src/gui/util/qdesktopservices_s60.cpp b/src/gui/util/qdesktopservices_s60.cpp new file mode 100644 index 0000000..a30e2ed --- /dev/null +++ b/src/gui/util/qdesktopservices_s60.cpp @@ -0,0 +1,389 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// This flag changes the implementation to use S60 CDcoumentHandler +// instead of apparch when opening the files +#undef USE_DOCUMENTHANDLER + +#include <qcoreapplication.h> +#include <qdir.h> +#include <qurl.h> +#include <private/qcore_symbian_p.h> + +#include <miutset.h> // KUidMsgTypeSMTP +#include <txtrich.h> // CRichText +#include <f32file.h> // TDriveUnit etc +#include <eikenv.h> // CEikonEnv +#include <apgcli.h> // RApaLsSession +#include <apgtask.h> // TApaTaskList, TApaTask +#include <sendui.h> // CSendUi +#include <cmessagedata.h> // CMessageData +#include <pathinfo.h> // PathInfo +#ifdef USE_DOCUMENTHANDLER +#include <documenthandler.h> // CDocumentHandler +#endif + +QT_BEGIN_NAMESPACE + +_LIT(KSysBin, "\\Sys\\Bin\\"); +_LIT(KTempDir, "\\System\\Temp\\"); +_LIT(KBrowserPrefix, "4 " ); +_LIT(KFontsDir, "z:\\resource\\Fonts\\"); +const TUid KUidBrowser = { 0x10008D39 }; + +static void handleMailtoSchemeL(const QUrl &url) +{ + QString recipient = url.path(); + QString subject = url.queryItemValue("subject"); + QString body = url.queryItemValue("body"); + QString to = url.queryItemValue("to"); + QString cc = url.queryItemValue("cc"); + QString bcc = url.queryItemValue("bcc"); + + // these fields might have comma separated addresses + QStringList recipients = recipient.split(","); + QStringList tos = to.split(","); + QStringList ccs = cc.split(","); + QStringList bccs = bcc.split(","); + + + CSendUi* sendUi = CSendUi::NewLC(); + + // Construct symbian sendUI data holder + CMessageData* messageData = CMessageData::NewLC(); + + // Subject + TPtrC subj( qt_QString2TPtrC(subject) ); + messageData->SetSubjectL( &subj ); + + // Body + CParaFormatLayer* paraFormat = CParaFormatLayer::NewL(); + CleanupStack::PushL( paraFormat ); + CCharFormatLayer* charFormat = CCharFormatLayer::NewL(); + CleanupStack::PushL( charFormat ); + CRichText* bodyRichText = CRichText::NewL( paraFormat, charFormat ); + CleanupStack::PushL( bodyRichText ); + + TPtrC bodyPtr( qt_QString2TPtrC(body) ); + if( bodyPtr.Length() ) + { + bodyRichText->InsertL( 0, bodyPtr ); + } + else + { + bodyRichText->InsertL( 0, KNullDesC ); + } + + messageData->SetBodyTextL( bodyRichText ); + + // To + foreach(QString item, recipients) + messageData->AppendToAddressL(qt_QString2TPtrC(item)); + + foreach(QString item, tos) + messageData->AppendToAddressL(qt_QString2TPtrC(item)); + + // Cc + foreach(QString item, ccs) + messageData->AppendCcAddressL(qt_QString2TPtrC(item)); + + // Bcc + foreach(QString item, bccs) + messageData->AppendBccAddressL(qt_QString2TPtrC(item)); + + sendUi->CreateAndSendMessageL( KUidMsgTypeSMTP, messageData ); + CleanupStack::PopAndDestroy( 5 ); // bodyRichText, charFormat, paraFormat, messageData, sendUi +} + +static bool handleMailtoScheme(const QUrl &url) +{ + TRAPD(err, handleMailtoSchemeL(url)); + return err ? false : true; +} + +static void handleOtherSchemesL(const TDesC& aUrl) +{ + // Other schemes are at the moment passed to WEB browser + HBufC* buf16 = HBufC::NewLC( aUrl.Length() + KBrowserPrefix.iTypeLength ); + buf16->Des().Copy( KBrowserPrefix ); // Prefix used to launch correct browser view + buf16->Des().Append( aUrl ); + + TApaTaskList taskList( CEikonEnv::Static()->WsSession() ); + TApaTask task = taskList.FindApp( KUidBrowser ); + if ( task.Exists() ) + { + // Switch to existing browser instance + HBufC8* param8 = HBufC8::NewLC( buf16->Length() ); + param8->Des().Append( buf16->Des() ); + task.SendMessage( TUid::Uid( 0 ), *param8 ); // Uid is not used + CleanupStack::PopAndDestroy( param8 ); + } + else + { + // Start a new browser instance + RApaLsSession appArcSession; + User::LeaveIfError( appArcSession.Connect() ); + CleanupClosePushL<RApaLsSession>( appArcSession ); + TThreadId id; + appArcSession.StartDocument( *buf16, KUidBrowser , id ); + CleanupStack::PopAndDestroy(); // appArcSession + } + + CleanupStack::PopAndDestroy( buf16 ); +} + +static bool handleOtherSchemes(const QUrl &url) +{ + TRAPD( err, handleOtherSchemesL(qt_QString2TPtrC(url.toEncoded()))); + return err ? false : true; +} + +static TDriveUnit exeDrive() +{ + RProcess me; + TFileName processFileName = me.FileName(); + TDriveUnit drive(processFileName); + return drive; +} + +static TDriveUnit writableExeDrive() +{ + TDriveUnit drive = exeDrive(); + if( drive.operator TInt() == EDriveZ ) + return TDriveUnit( EDriveC ); + return drive; +} + +static TPtrC writableDataRoot() +{ + TDriveUnit drive = exeDrive(); + switch( drive.operator TInt() ){ + case EDriveC: + return PathInfo::PhoneMemoryRootPath(); + break; + case EDriveE: + return PathInfo::MemoryCardRootPath(); + break; + case EDriveZ: + // It is not possible to write on ROM drive -> + // return phone mem root path instead + return PathInfo::PhoneMemoryRootPath(); + break; + default: + // TODO: Should we return drive root similar to MemoryCardRootPath + return PathInfo::PhoneMemoryRootPath(); + break; + } +} + +static void openDocumentL(const TDesC& aUrl) +{ +#ifndef USE_DOCUMENTHANDLER + // Start app associated to file MIME type by using RApaLsSession + // Apparc base method cannot be used to open app in embedded mode, + // but seems to be most stable way at the moment + RApaLsSession appArcSession; + User::LeaveIfError( appArcSession.Connect() ); + CleanupClosePushL<RApaLsSession>( appArcSession ); + TThreadId id; + // ESwitchFiles means do not start another instance + // Leaves if file does not exist, leave is trapped in openDocument and false returned to user. + User::LeaveIfError( appArcSession.StartDocument( aUrl, id, + RApaLsSession::ESwitchFiles ) ); // ELaunchNewApp + CleanupStack::PopAndDestroy(); // appArcSession +#else + // This is an alternative way to launch app associated to MIME type + // CDocumentHandler would support opening apps in embedded mode, + // but our Qt application window group seems to always get switched on top of embedded one + // -> Cannot use menus etc of embedded app -> used + + CDocumentHandler* docHandler = CDocumentHandler::NewLC(); + TDataType temp; + //Standalone file opening fails for some file-types at least in S60 3.1 emulator + //For example .txt file fails with KErrAlreadyInUse and music files with KERN-EXEC 0 + //Workaround is to use OpenFileEmbeddedL + //docHandler->OpenFileL(aUrl, temp); + + // Opening file with CDocumentHandler will leave if file does not exist + // Leave is trapped in openDocument and false returned to user. + docHandler->OpenFileEmbeddedL(aUrl, temp); + CleanupStack::PopAndDestroy(docHandler); +#endif +} + +#ifdef USE_SCHEMEHANDLER +// The schemehandler component only exist in private SDK. This implementation +// exist here just for convenience in case that we need to use it later on +// The schemehandle based implementation is not yet tested. + +// The biggest advantage of schemehandler is that it can handle +// wide range of schemes and is extensible by plugins +static bool handleUrl(const QUrl &url) +{ + if (!url.isValid()) + return false; + + TRAPD( err, handleUrlL(qt_QString2TPtrC(url.toString()))); + return err ? false : true; +} + +static void handleUrlL(const TDesC& aUrl) +{ + CSchemeHandler* schemeHandler = CSchemeHandler::NewL( aUrl ); + CleanupStack::PushL( schemeHandler ); + schemeHandler->HandleUrlStandaloneL(); // Process the Url in standalone mode + CleanupStack::PopAndDestroy(); +} +static bool launchWebBrowser(const QUrl &url) +{ + return handleUrl(url); +} + +static bool openDocument(const QUrl &file) +{ + return handleUrl(url); +} +#endif + +static bool launchWebBrowser(const QUrl &url) +{ + if (!url.isValid()) + return false; + + if (url.scheme() == QLatin1String("mailto")) { + return handleMailtoScheme(url); + } + return handleOtherSchemes( url ); +} + +static bool openDocument(const QUrl &file) +{ + if (!file.isValid()) + return false; + + QString filePath = file.toLocalFile(); + filePath = QDir::toNativeSeparators(filePath); + TRAPD(err, openDocumentL(qt_QString2TPtrC(filePath))); + return err ? false : true; +} + +QString QDesktopServices::storageLocation(StandardLocation type) +{ + TFileName path; + + switch (type) { + case DesktopLocation: + qWarning("QDesktopServices::storageLocation %d not implemented", type); + break; + case DocumentsLocation: + path.Append(writableDataRoot()); + break; + case FontsLocation: + path.Append(KFontsDir); + break; + case ApplicationsLocation: + path.Append(exeDrive().Name()); + path.Append(KSysBin); + break; + case MusicLocation: + path.Append(writableDataRoot()); + path.Append(PathInfo::SoundsPath()); + break; + case MoviesLocation: + path.Append(writableDataRoot()); + path.Append(PathInfo::VideosPath()); + break; + case PicturesLocation: + path.Append(writableDataRoot()); + path.Append(PathInfo::ImagesPath()); + break; + case TempLocation: + path.Append(writableExeDrive().Name()); + path.Append(KTempDir); + //return QDir::tempPath(); break; + break; + case HomeLocation: + path.Append(writableDataRoot()); + //return QDir::homePath(); break; + break; + case DataLocation: + CEikonEnv::Static()->FsSession().PrivatePath( path ); + // TODO: Should we actually return phone mem if data is on ROM? + path.Insert( 0, exeDrive().Name() ); + break; + default: + break; + } + + // Convert to cross-platform format and clean the path + QString nativePath = QString::fromUtf16(path.Ptr(), path.Length()); + QString qtPath = QDir::fromNativeSeparators(nativePath); + qtPath = QDir::cleanPath(qtPath); + + // Note: The storage location returned can be a directory that does not exist; + // i.e., it may need to be created by the system or the user. + return qtPath; +} + +typedef QString (*LocalizerFunc)(QString&); + +static QString defaultLocalizedDirectoryName(QString&) +{ + return QString(); +} + +QString QDesktopServices::displayName(StandardLocation type) +{ + static LocalizerFunc ptrLocalizerFunc = NULL; + + if (!ptrLocalizerFunc) { + ptrLocalizerFunc = reinterpret_cast<LocalizerFunc> + (qt_resolveS60PluginFunc(S60Plugin_LocalizedDirectoryName)); + if (!ptrLocalizerFunc) + ptrLocalizerFunc = &defaultLocalizedDirectoryName; + } + + QString rawPath = storageLocation(type); + return ptrLocalizerFunc(rawPath); +} + + +QT_END_NAMESPACE diff --git a/src/gui/util/util.pri b/src/gui/util/util.pri index e628229..69c53ae 100644 --- a/src/gui/util/util.pri +++ b/src/gui/util/util.pri @@ -35,6 +35,11 @@ embedded { util/qsystemtrayicon_qws.cpp } +symbian { + # QDesktopServices uses CSendUi which is located on app layer + INCLUDEPATH += $$APP_LAYER_SYSTEMINCLUDE +} + !embedded:!x11:mac { OBJECTIVE_SOURCES += util/qsystemtrayicon_mac.mm } diff --git a/src/gui/widgets/qabstractslider.cpp b/src/gui/widgets/qabstractslider.cpp index 8028fdc..abe592d 100644 --- a/src/gui/widgets/qabstractslider.cpp +++ b/src/gui/widgets/qabstractslider.cpp @@ -687,8 +687,9 @@ void QAbstractSlider::wheelEvent(QWheelEvent * e) Q_D(QAbstractSlider); e->ignore(); if (e->orientation() != d->orientation && !rect().contains(e->pos())) + { return; - + } static qreal offset = 0; static QAbstractSlider *offset_owner = 0; if (offset_owner != this){ diff --git a/src/gui/widgets/qabstractspinbox.cpp b/src/gui/widgets/qabstractspinbox.cpp index 347f89a..2bf1cda 100644 --- a/src/gui/widgets/qabstractspinbox.cpp +++ b/src/gui/widgets/qabstractspinbox.cpp @@ -659,7 +659,6 @@ void QAbstractSpinBox::setLineEdit(QLineEdit *lineEdit) d->edit->setParent(this); d->edit->setFrame(false); - d->edit->setAttribute(Qt::WA_InputMethodEnabled, false); d->edit->setFocusProxy(this); d->edit->setAcceptDrops(false); @@ -690,6 +689,18 @@ void QAbstractSpinBox::interpretText() d->interpret(EmitIfChanged); } +/* + Reimplemented in 4.6, so be careful. + */ +/*! + \reimp +*/ +QVariant QAbstractSpinBox::inputMethodQuery(Qt::InputMethodQuery query) const +{ + Q_D(const QAbstractSpinBox); + return d->edit->inputMethodQuery(query); +} + /*! \reimp */ diff --git a/src/gui/widgets/qabstractspinbox.h b/src/gui/widgets/qabstractspinbox.h index 4e7fc3f..aa8905f 100644 --- a/src/gui/widgets/qabstractspinbox.h +++ b/src/gui/widgets/qabstractspinbox.h @@ -122,6 +122,8 @@ public: void interpretText(); bool event(QEvent *event); + QVariant inputMethodQuery(Qt::InputMethodQuery) const; + virtual QValidator::State validate(QString &input, int &pos) const; virtual void fixup(QString &input) const; diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index a5a98d4..16e2f39 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -640,6 +640,7 @@ bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e) case Qt::Key_Escape: #ifdef QT_KEYPAD_NAVIGATION case Qt::Key_Back: + case Qt::Key_Context2: // TODO: aportale, KEYPAD_NAVIGATION_HACK when softkey support is there #endif combo->hidePopup(); return true; @@ -2431,6 +2432,10 @@ void QComboBox::showPopup() container->setUpdatesEnabled(updatesEnabled); container->update(); +#ifdef QT_KEYPAD_NAVIGATION + if (QApplication::keypadNavigationEnabled()) + view()->setEditFocus(true); +#endif } /*! diff --git a/src/gui/widgets/qdatetimeedit.cpp b/src/gui/widgets/qdatetimeedit.cpp index 83bec68..4d34691 100644 --- a/src/gui/widgets/qdatetimeedit.cpp +++ b/src/gui/widgets/qdatetimeedit.cpp @@ -2390,6 +2390,7 @@ void QDateTimeEditPrivate::init(const QVariant &var) q->setCalendarPopup(true); #endif updateTimeSpec(); + q->setInputMethodHints(Qt::ImhPreferNumbers); setLayoutItemMargins(QStyle::SE_DateTimeEditLayoutItem); } diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index b76d019..a95d2f2 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -97,8 +97,7 @@ extern void qt_mac_secure_keyboard(bool); //qapplication_mac.cpp static inline bool shouldEnableInputMethod(QLineEdit *lineedit) { - const QLineEdit::EchoMode mode = lineedit->echoMode(); - return !lineedit->isReadOnly() && (mode == QLineEdit::Normal || mode == QLineEdit::PasswordEchoOnEdit); + return !lineedit->isReadOnly(); } /*! @@ -544,7 +543,13 @@ void QLineEdit::setEchoMode(EchoMode mode) Q_D(QLineEdit); if (mode == (EchoMode)d->echoMode) return; - setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this)); + Qt::InputMethodHints imHints = inputMethodHints(); + if (mode == Password) { + imHints |= Qt::ImhHiddenText; + } else { + imHints &= ~Qt::ImhHiddenText; + } + setInputMethodHints(imHints); d->echoMode = mode; d->passwordEchoEditing = false; d->updateTextLayout(); @@ -1768,6 +1773,13 @@ void QLineEdit::mouseReleaseEvent(QMouseEvent* e) } } #endif + + if (e->button() == Qt::LeftButton && qApp->autoSipEnabled() + && (!d->clickCausedFocus || qApp->autoSipOnMouseFocus())) { + QEvent event(QEvent::RequestSoftwareInputPanel); + QApplication::sendEvent(this, &event); + } + d->clickCausedFocus = 0; } /*! \reimp @@ -2262,8 +2274,16 @@ void QLineEdit::inputMethodEvent(QInputMethodEvent *e) } #endif - int priorState = d->undoState; - d->removeSelectedText(); + int priorState = 0; + bool isGettingInput = !e->commitString().isEmpty() || !e->preeditString().isEmpty() + || e->replacementLength() > 0; + bool cursorPositionChanged = false; + + if (isGettingInput) { + // If any text is being input, remove selected text. + priorState = d->undoState; + d->removeSelectedText(); + } int c = d->cursor; // cursor position after insertion of commit string if (e->replacementStart() <= 0) @@ -2277,11 +2297,30 @@ void QLineEdit::inputMethodEvent(QInputMethodEvent *e) d->selend = d->selstart + e->replacementLength(); d->removeSelectedText(); } - if (!e->commitString().isEmpty()) + if (!e->commitString().isEmpty()) { d->insert(e->commitString()); + cursorPositionChanged = true; + } d->cursor = qMin(c, d->text.length()); + for (int i = 0; i < e->attributes().size(); ++i) { + const QInputMethodEvent::Attribute &a = e->attributes().at(i); + if (a.type == QInputMethodEvent::Selection) { + d->cursor = qBound(0, a.start + a.length, d->text.length()); + if (a.length) { + d->selstart = qMax(0, qMin(a.start, d->text.length())); + d->selend = d->cursor; + if (d->selend < d->selstart) { + qSwap(d->selstart, d->selend); + } + } else { + d->selstart = d->selend = 0; + } + cursorPositionChanged = true; + } + } + d->textLayout.setPreeditArea(d->cursor, e->preeditString()); d->preeditCursor = e->preeditString().length(); d->hideCursor = false; @@ -2305,9 +2344,12 @@ void QLineEdit::inputMethodEvent(QInputMethodEvent *e) d->textLayout.setAdditionalFormats(formats); d->updateTextLayout(); update(); - if (!e->commitString().isEmpty()) + if (cursorPositionChanged) d->emitCursorPositionChanged(); - d->finishChange(priorState); + + if (isGettingInput) + d->finishChange(priorState); + #ifndef QT_NO_COMPLETER if (!e->commitString().isEmpty()) d->complete(Qt::Key_unknown); @@ -2325,11 +2367,20 @@ QVariant QLineEdit::inputMethodQuery(Qt::InputMethodQuery property) const case Qt::ImFont: return font(); case Qt::ImCursorPosition: - return QVariant((d->selend - d->selstart == 0) ? d->cursor : d->selend); + return QVariant(d->cursor); case Qt::ImSurroundingText: return QVariant(d->text); case Qt::ImCurrentSelection: return QVariant(selectedText()); + case Qt::ImMaximumTextLength: + return QVariant(maxLength()); + case Qt::ImAnchorPosition: + if (d->selstart == d->selend) + return QVariant(d->cursor); + else if (d->selstart == d->cursor) + return QVariant(d->selend); + else + return QVariant(d->selstart); default: return QVariant(); } @@ -2348,6 +2399,8 @@ void QLineEdit::focusInEvent(QFocusEvent *e) d->moveCursor(d->nextMaskBlank(0)); else if (!d->hasSelectedText()) selectAll(); + } else if (e->reason() == Qt::MouseFocusReason) { + d->clickCausedFocus = 1; } #ifdef QT_KEYPAD_NAVIGATION if (!QApplication::keypadNavigationEnabled() || (hasEditFocus() && e->reason() == Qt::PopupFocusReason)) @@ -2926,6 +2979,7 @@ void QLineEditPrivate::moveCursor(int pos, bool mark) selDirty = false; emit q->selectionChanged(); } + q->updateMicroFocus(); emitCursorPositionChanged(); } diff --git a/src/gui/widgets/qlineedit_p.h b/src/gui/widgets/qlineedit_p.h index 532528b..3db903f 100644 --- a/src/gui/widgets/qlineedit_p.h +++ b/src/gui/widgets/qlineedit_p.h @@ -76,7 +76,8 @@ public: : cursor(0), preeditCursor(0), cursorTimer(0), frame(1), cursorVisible(0), hideCursor(false), separator(0), readOnly(0), dragEnabled(0), contextMenuEnabled(1), echoMode(0), textDirty(0), - selDirty(0), validInput(1), alignment(Qt::AlignLeading | Qt::AlignVCenter), ascent(0), + selDirty(0), validInput(1), clickCausedFocus(0), + alignment(Qt::AlignLeading | Qt::AlignVCenter), ascent(0), maxLength(32767), hscroll(0), vscroll(0), lastCursorPos(-1), maskData(0), modifiedState(0), undoState(0), selstart(0), selend(0), userInput(false), emitingEditingFinished(false), passwordEchoEditing(false) @@ -110,6 +111,7 @@ public: uint textDirty : 1; uint selDirty : 1; uint validInput : 1; + uint clickCausedFocus : 1; uint alignment; int ascent; int maxLength; diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp index 7396a9d..6be0f19 100644 --- a/src/gui/widgets/qmenu.cpp +++ b/src/gui/widgets/qmenu.cpp @@ -1794,6 +1794,22 @@ void QMenu::popup(const QPoint &p, QAction *atAction) QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(p)); const int desktopFrame = style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, this); bool adjustToDesktop = !window()->testAttribute(Qt::WA_DontShowOnScreen); +#ifdef QT_KEYPAD_NAVIGATION + if (!atAction && QApplication::keypadNavigationEnabled()) { + // Try to have one item activated + if (d->defaultAction && d->defaultAction->isEnabled()) { + atAction = d->defaultAction; + // TODO: This works for first level menus, not yet sub menus + } else { + foreach (QAction *action, d->actionList) + if (action->isEnabled()) { + atAction = action; + break; + } + } + d->currentAction = atAction; + } +#endif if (d->ncols > 1) { pos.setY(screen.top()+desktopFrame); } else if (atAction) { @@ -2571,6 +2587,7 @@ void QMenu::keyPressEvent(QKeyEvent *e) case Qt::Key_Escape: #ifdef QT_KEYPAD_NAVIGATION case Qt::Key_Back: + case Qt::Key_Context2: // TODO: aportale, remove KEYPAD_NAVIGATION_HACK when softkey support is there #endif key_consumed = true; if (d->tornoff) { @@ -2848,6 +2865,16 @@ void QMenu::actionEvent(QActionEvent *e) d->wce_menu->syncAction(e->action()); #endif +#ifdef Q_OS_SYMBIAN + if (!d->symbian_menu) + d->symbian_menu = new QMenuPrivate::QSymbianMenuPrivate; + if (e->type() == QEvent::ActionAdded) + d->symbian_menu->addAction(e->action(), d->symbian_menu->findAction(e->before())); + else if (e->type() == QEvent::ActionRemoved) + d->symbian_menu->removeAction(e->action()); + else if (e->type() == QEvent::ActionChanged) + d->symbian_menu->syncAction(e->action()); +#endif if (isVisible()) { d->updateActions(); resize(sizeHint()); diff --git a/src/gui/widgets/qmenu.h b/src/gui/widgets/qmenu.h index 867baee..bf1c39f 100644 --- a/src/gui/widgets/qmenu.h +++ b/src/gui/widgets/qmenu.h @@ -52,11 +52,19 @@ #endif QT_BEGIN_HEADER +#ifdef Q_OS_SYMBIAN + class CEikMenuPane; +#endif QT_BEGIN_NAMESPACE QT_MODULE(Gui) +#ifdef Q_OS_SYMBIAN + IMPORT_C void qt_symbian_show_toplevel(CEikMenuPane* menuPane); + IMPORT_C void qt_symbian_show_submenu(CEikMenuPane* menuPane, int id); +#endif + #ifndef QT_NO_MENU class QMenuPrivate; @@ -145,7 +153,6 @@ public: HMENU wceMenu(bool create = false); #endif - bool separatorsCollapsible() const; void setSeparatorsCollapsible(bool collapse); diff --git a/src/gui/widgets/qmenu_p.h b/src/gui/widgets/qmenu_p.h index 74367c4..aafc945 100644 --- a/src/gui/widgets/qmenu_p.h +++ b/src/gui/widgets/qmenu_p.h @@ -61,6 +61,9 @@ #include "QtCore/qbasictimer.h" #include "private/qwidget_p.h" +#ifdef Q_OS_SYMBIAN +class CEikMenuPane; +#endif QT_BEGIN_NAMESPACE #ifndef QT_NO_MENU @@ -120,6 +123,15 @@ struct QWceMenuAction { QWceMenuAction() : menuHandle(0), command(0) {} }; #endif +#ifdef Q_OS_SYMBIAN +struct QSymbianMenuAction { + uint command; + int parent; + CEikMenuPane* menuPane; + QPointer<QAction> action; + QSymbianMenuAction() : command(0) {} +}; +#endif class QMenuPrivate : public QWidgetPrivate { @@ -135,6 +147,9 @@ public: #if defined(Q_OS_WINCE) && !defined(QT_NO_MENUBAR) ,wce_menu(0) #endif +#ifdef Q_OS_SYMBIAN + ,symbian_menu(0) +#endif #ifdef QT3_SUPPORT ,emitHighlighted(false) #endif @@ -148,6 +163,10 @@ public: #if defined(Q_OS_WINCE) && !defined(QT_NO_MENUBAR) delete wce_menu; #endif +#ifdef Q_OS_SYMBIAN + delete symbian_menu; +#endif + } void init(); @@ -318,7 +337,28 @@ public: HMENU wceMenu(bool create = false); QAction* wceCommands(uint command); #endif - +#if defined(Q_OS_SYMBIAN) + struct QSymbianMenuPrivate { + QList<QSymbianMenuAction*> actionItems; + QSymbianMenuPrivate(); + ~QSymbianMenuPrivate(); + void addAction(QAction *, QSymbianMenuAction* =0); + void addAction(QSymbianMenuAction *, QSymbianMenuAction* =0); + void syncAction(QSymbianMenuAction *); + inline void syncAction(QAction *a) { syncAction(findAction(a)); } + void removeAction(QSymbianMenuAction *); + void rebuild(bool reCreate = false); + inline void removeAction(QAction *a) { removeAction(findAction(a)); } + inline QSymbianMenuAction *findAction(QAction *a) { + for(int i = 0; i < actionItems.size(); i++) { + QSymbianMenuAction *act = actionItems[i]; + if(a == act->action) + return act; + } + return 0; + } + } *symbian_menu; +#endif QPointer<QWidget> noReplayFor; }; diff --git a/src/gui/widgets/qmenu_symbian.cpp b/src/gui/widgets/qmenu_symbian.cpp new file mode 100644 index 0000000..48c2cf6 --- /dev/null +++ b/src/gui/widgets/qmenu_symbian.cpp @@ -0,0 +1,398 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmenu.h" +#include "qapplication.h" +#include "qmainwindow.h" +#include "qtoolbar.h" +#include "qevent.h" +#include "qstyle.h" +#include "qdebug.h" +#include "qwidgetaction.h" +#include <eikmenub.h> +#include <eikmenup.h> +#include <private/qapplication_p.h> +#include <private/qmenu_p.h> +#include <private/qmenubar_p.h> +#include <qt_s60_p.h> +#include <eikaufty.h> +#include <eikbtgpc.h> +#include <QtCore/qlibrary.h> +#include <avkon.rsg> + +#ifndef QT_NO_MENUBAR + +QT_BEGIN_NAMESPACE + +// ### FIX/Document this, we need some safe range of menu id's for Qt that don't clash with AIW ones +typedef QMultiHash<QWidget *, QMenuBarPrivate *> MenuBarHash; +Q_GLOBAL_STATIC(MenuBarHash, menubars) + +#define QT_FIRST_MENU_ITEM 32000 + +struct SymbianMenuItem +{ + int id; + CEikMenuPaneItem::SData menuItemData; + QList<SymbianMenuItem*> children; + QAction* action; +}; + +static QList<SymbianMenuItem*> symbianMenus; +static QList<QMenuBar*> nativeMenuBars; +static uint qt_symbian_menu_static_cmd_id = QT_FIRST_MENU_ITEM; + +bool menuExists() +{ + QWidget *w = qApp->activeWindow(); + QMenuBarPrivate *mb = menubars()->value(w); + if ((!mb) && !menubars()->count()) + return false; + return true; +} + +// ### FIX THIS, copy/paste of original (faulty) stripped text implementation. +// Implementation should be removed from QAction implementation to some generic place +static QString qt_strippedText_copy_from_qaction(QString s) +{ + s.remove(QString::fromLatin1("...")); + int i = 0; + while (i < s.size()) { + ++i; + if (s.at(i-1) != QLatin1Char('&')) + continue; + if (i < s.size() && s.at(i) == QLatin1Char('&')) + ++i; + s.remove(i-1,1); + } + return s.trimmed(); +}; + +static SymbianMenuItem* qt_symbian_find_menu(int id, const QList<SymbianMenuItem*> &parent) +{ + int index=0; + while (index < parent.count()) { + SymbianMenuItem* temp = parent[index]; + if (temp->menuItemData.iCascadeId == id) + return temp; + else if (temp->menuItemData.iCascadeId != 0) { + SymbianMenuItem* result = qt_symbian_find_menu( id, temp->children); + if (result) + return result; + } + index++; + } + return 0; +} + +static SymbianMenuItem* qt_symbian_find_menu_item(int id, const QList<SymbianMenuItem*> &parent) +{ + int index=0; + while (index < parent.count()) { + SymbianMenuItem* temp = parent[index]; + if (temp->menuItemData.iCascadeId != 0) { + SymbianMenuItem* result = qt_symbian_find_menu_item( id, temp->children); + if (result) + return result; + } + else if (temp->menuItemData.iCommandId == id) + return temp; + index++; + + } + return 0; +} + +static void qt_symbian_insert_action(QSymbianMenuAction* action, QList<SymbianMenuItem*>* parent) +{ + if (action->action->isVisible()) { + if (action->action->isSeparator()) + return; + +// ### FIX THIS, the qt_strippedText2 doesn't work perfectly for stripping & marks. Same bug is in QAction +// New really working method is needed in a place where the implementation isn't copy/pasted + QString text = qt_strippedText_copy_from_qaction(action->action->text()); + HBufC* menuItemText = qt_QString2HBufCNewL(text); + + if (action->action->menu()) { + SymbianMenuItem* menuItem = new SymbianMenuItem(); + menuItem->menuItemData.iCascadeId = action->command; + menuItem->menuItemData.iCommandId = action->command; + menuItem->menuItemData.iFlags = 0; + menuItem->menuItemData.iText = *menuItemText; + menuItem->action = action->action; + if (action->action->menu()->actions().size() == 0 || !action->action->isEnabled() ) + menuItem->menuItemData.iFlags |= EEikMenuItemDimmed; + parent->append(menuItem); + + if (action->action->menu()->actions().size() > 0) { + for (int c2= 0; c2 < action->action->menu()->actions().size(); ++c2) { + QSymbianMenuAction *symbianAction2 = new QSymbianMenuAction; + symbianAction2->action = action->action->menu()->actions().at(c2); + QMenu * menu = symbianAction2->action->menu(); + symbianAction2->command = qt_symbian_menu_static_cmd_id++; + qt_symbian_insert_action(symbianAction2, &(menuItem->children)); + } + } + + } else { + SymbianMenuItem* menuItem = new SymbianMenuItem(); + menuItem->menuItemData.iCascadeId = 0; + menuItem->menuItemData.iCommandId = action->command; + menuItem->menuItemData.iFlags = 0; + menuItem->menuItemData.iText = *menuItemText; + menuItem->action = action->action; + if (!action->action->isEnabled()){ + menuItem->menuItemData.iFlags += EEikMenuItemDimmed; + } + + if (action->action->isCheckable()) { + if (action->action->isChecked()) + menuItem->menuItemData.iFlags += EEikMenuItemCheckBox | EEikMenuItemSymbolOn; + else + menuItem->menuItemData.iFlags += EEikMenuItemCheckBox; + } + parent->append(menuItem); + } + delete menuItemText; + } +} + +void deleteAll(QList<SymbianMenuItem*> *items) +{ + while (!items->isEmpty()) { + SymbianMenuItem* temp = items->takeFirst(); + deleteAll(&temp->children); + delete temp; + } +} + +static void setSoftkeys() +{ + CEikButtonGroupContainer* cba = CEikonEnv::Static()->AppUiFactory()->Cba(); + if (cba){ + if (menuExists()) + cba->SetCommandSetL(R_AVKON_SOFTKEYS_OPTIONS_EXIT); + else + cba->SetCommandSetL(R_AVKON_SOFTKEYS_EXIT); + } +} + +static void rebuildMenu() +{ + QMenuBarPrivate *mb = 0; + setSoftkeys(); + QWidget *w = qApp->activeWindow(); + if (w) + { + mb = menubars()->value(w); + qt_symbian_menu_static_cmd_id = QT_FIRST_MENU_ITEM; + deleteAll( &symbianMenus ); + if (!mb) + return; + mb->symbian_menubar->rebuild(); + } + } + +Q_GUI_EXPORT void qt_symbian_show_toplevel( CEikMenuPane* menuPane) +{ + if (!menuExists()) + return; + rebuildMenu(); + for (int i = 0; i < symbianMenus.count(); ++i) + menuPane->AddMenuItemL(symbianMenus.at(i)->menuItemData); +} + +Q_GUI_EXPORT void qt_symbian_show_submenu( CEikMenuPane* menuPane, int id) +{ + SymbianMenuItem* menu = qt_symbian_find_menu(id, symbianMenus); + if (menu) { + for (int i = 0; i < menu->children.count(); ++i) + menuPane->AddMenuItemL(menu->children.at(i)->menuItemData); + } +} + +void QMenuBarPrivate::symbianCommands(int command) +{ + int size = nativeMenuBars.size(); + for (int i = 0; i < nativeMenuBars.size(); ++i) { + SymbianMenuItem* menu = qt_symbian_find_menu_item(command, symbianMenus); + if (!menu) + continue; + + emit nativeMenuBars.at(i)->triggered(menu->action); + menu->action->activate(QAction::Trigger); + break; + } +} + +void QMenuBarPrivate::symbianCreateMenuBar(QWidget *parent) +{ + Q_Q(QMenuBar); + if (parent && parent->isWindow()){ + menubars()->insert(q->window(), this); + symbian_menubar = new QSymbianMenuBarPrivate(this); + nativeMenuBars.append(q); + } +} + +void QMenuBarPrivate::symbianDestroyMenuBar() +{ + Q_Q(QMenuBar); + int index = nativeMenuBars.indexOf(q); + nativeMenuBars.removeAt(index); + menubars()->remove(q->window(), this); + rebuildMenu(); + if (symbian_menubar) + delete symbian_menubar; + symbian_menubar = 0; +} + +QMenuBarPrivate::QSymbianMenuBarPrivate::QSymbianMenuBarPrivate(QMenuBarPrivate *menubar) +{ + d = menubar; +} + +QMenuBarPrivate::QSymbianMenuBarPrivate::~QSymbianMenuBarPrivate() +{ + deleteAll( &symbianMenus ); + symbianMenus.clear(); + d = 0; + rebuild(); +} + +QMenuPrivate::QSymbianMenuPrivate::QSymbianMenuPrivate() +{ +} + +QMenuPrivate::QSymbianMenuPrivate::~QSymbianMenuPrivate() +{ + +} + +void QMenuPrivate::QSymbianMenuPrivate::addAction(QAction *a, QSymbianMenuAction *before) +{ + QSymbianMenuAction *action = new QSymbianMenuAction; + action->action = a; + action->command = qt_symbian_menu_static_cmd_id++; + addAction(action, before); +} + +void QMenuPrivate::QSymbianMenuPrivate::addAction(QSymbianMenuAction *action, QSymbianMenuAction *before) +{ + if (!action) + return; + int before_index = actionItems.indexOf(before); + if (before_index < 0) { + before = 0; + before_index = actionItems.size(); + } + actionItems.insert(before_index, action); +} + + +void QMenuPrivate::QSymbianMenuPrivate::syncAction(QSymbianMenuAction *) +{ + rebuild(); +} + +void QMenuPrivate::QSymbianMenuPrivate::removeAction(QSymbianMenuAction *action) +{ + actionItems.removeAll(action); + delete action; + action = 0; + rebuild(); +} + +void QMenuPrivate::QSymbianMenuPrivate::rebuild(bool) +{ +} + +void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QAction *a, QSymbianMenuAction *before) +{ + QSymbianMenuAction *action = new QSymbianMenuAction; + action->action = a; + action->command = qt_symbian_menu_static_cmd_id++; + addAction(action, before); +} + +void QMenuBarPrivate::QSymbianMenuBarPrivate::addAction(QSymbianMenuAction *action, QSymbianMenuAction *before) +{ + if (!action) + return; + int before_index = actionItems.indexOf(before); + if (before_index < 0) { + before = 0; + before_index = actionItems.size(); + } + actionItems.insert(before_index, action); +} + +void QMenuBarPrivate::QSymbianMenuBarPrivate::syncAction(QSymbianMenuAction*) +{ + rebuild(); +} + +void QMenuBarPrivate::QSymbianMenuBarPrivate::removeAction(QSymbianMenuAction *action) +{ + actionItems.removeAll(action); + delete action; + rebuild(); +} + +void QMenuBarPrivate::QSymbianMenuBarPrivate::rebuild() +{ + setSoftkeys(); + qt_symbian_menu_static_cmd_id = QT_FIRST_MENU_ITEM; + deleteAll( &symbianMenus ); + if (!d) + return; + for (int i = 0; i < d->actions.size(); ++i) { + QSymbianMenuAction *symbianActionTopLevel = new QSymbianMenuAction; + symbianActionTopLevel->action = d->actions.at(i); + symbianActionTopLevel->parent = 0; + symbianActionTopLevel->command = qt_symbian_menu_static_cmd_id++; + qt_symbian_insert_action(symbianActionTopLevel, &symbianMenus); + } +} + +QT_END_NAMESPACE + +#endif //QT_NO_MENUBAR diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp index c63da64..fb8a69b 100644 --- a/src/gui/widgets/qmenubar.cpp +++ b/src/gui/widgets/qmenubar.cpp @@ -732,6 +732,12 @@ void QMenuBarPrivate::init() q->hide(); } #endif +#ifdef Q_OS_SYMBIAN + symbianCreateMenuBar(q->parentWidget()); + if(symbian_menubar) + q->hide(); +#endif + q->setBackgroundRole(QPalette::Button); oldWindow = oldParent = 0; #ifdef QT3_SUPPORT @@ -781,6 +787,10 @@ QMenuBar::~QMenuBar() if (qt_wince_is_mobile()) d->wceDestroyMenuBar(); #endif +#ifdef Q_OS_SYMBIAN + Q_D(QMenuBar); + d->symbianDestroyMenuBar(); +#endif } /*! @@ -1035,6 +1045,12 @@ void QMenuBar::setVisible(bool visible) if(d->wce_menubar) return; #endif +#ifdef Q_OS_SYMBIAN + Q_D(QMenuBar); + if(d->symbian_menubar) + return; +#endif + QWidget::setVisible(visible); } @@ -1292,6 +1308,17 @@ void QMenuBar::actionEvent(QActionEvent *e) d->wce_menubar->syncAction(e->action()); } #endif +#ifdef Q_OS_SYMBIAN + if(d->symbian_menubar) { + if(e->type() == QEvent::ActionAdded) + d->symbian_menubar->addAction(e->action(), d->symbian_menubar->findAction(e->before())); + else if(e->type() == QEvent::ActionRemoved) + d->symbian_menubar->removeAction(e->action()); + else if(e->type() == QEvent::ActionChanged) + d->symbian_menubar->syncAction(e->action()); + } +#endif + if(e->type() == QEvent::ActionAdded) { connect(e->action(), SIGNAL(triggered()), this, SLOT(_q_actionTriggered())); connect(e->action(), SIGNAL(hovered()), this, SLOT(_q_actionHovered())); @@ -1378,6 +1405,11 @@ void QMenuBarPrivate::handleReparent() if (qt_wince_is_mobile() && wce_menubar) wce_menubar->rebuild(); #endif +#ifdef Q_OS_SYMBIAN + if (symbian_menubar) + symbian_menubar->rebuild(); +#endif + } #ifdef QT3_SUPPORT @@ -1616,6 +1648,8 @@ QSize QMenuBar::minimumSizeHint() const const bool as_gui_menubar = !d->mac_menubar; #elif defined (Q_OS_WINCE) const bool as_gui_menubar = !d->wce_menubar; +#elif defined (Q_OS_SYMBIAN) + const bool as_gui_menubar = !d->symbian_menubar; #else const bool as_gui_menubar = true; #endif @@ -1676,6 +1710,8 @@ QSize QMenuBar::sizeHint() const const bool as_gui_menubar = !d->mac_menubar; #elif defined (Q_OS_WINCE) const bool as_gui_menubar = !d->wce_menubar; +#elif defined (Q_OS_SYMBIAN) + const bool as_gui_menubar = !d->symbian_menubar; #else const bool as_gui_menubar = true; #endif @@ -1739,6 +1775,8 @@ int QMenuBar::heightForWidth(int) const const bool as_gui_menubar = !d->mac_menubar; #elif defined (Q_OS_WINCE) const bool as_gui_menubar = !d->wce_menubar; +#elif defined (Q_OS_SYMBIAN) + const bool as_gui_menubar = !d->symbian_menubar; #else const bool as_gui_menubar = true; #endif diff --git a/src/gui/widgets/qmenubar_p.h b/src/gui/widgets/qmenubar_p.h index 223346b..7993acd 100644 --- a/src/gui/widgets/qmenubar_p.h +++ b/src/gui/widgets/qmenubar_p.h @@ -61,6 +61,13 @@ #include "qguifunctions_wince.h" #endif +#ifndef QT_NO_MENUBAR +#ifdef Q_OS_SYMBIAN +class CCoeControl; +class CEikMenuBar; +#endif +#endif + QT_BEGIN_NAMESPACE #ifndef QT_NO_MENUBAR @@ -78,7 +85,11 @@ public: #ifdef Q_OS_WINCE , wce_menubar(0), wceClassicMenu(false) #endif - { } +#ifdef Q_OS_SYMBIAN + , symbian_menubar(0) +#endif + + { } ~QMenuBarPrivate() { #ifdef Q_WS_MAC @@ -87,6 +98,9 @@ public: #ifdef Q_OS_WINCE delete wce_menubar; #endif +#ifdef Q_OS_SYMBIAN + delete symbian_menubar; +#endif } void init(); @@ -220,6 +234,34 @@ public: void wceRefresh(); bool wceEmitSignals(QList<QWceMenuAction*> actions, uint command); #endif +#ifdef Q_OS_SYMBIAN + void symbianCreateMenuBar(QWidget *); + void symbianDestroyMenuBar(); + struct QSymbianMenuBarPrivate { + QList<QSymbianMenuAction*> actionItems; + QMenuBarPrivate *d; + QSymbianMenuBarPrivate(QMenuBarPrivate *menubar); + ~QSymbianMenuBarPrivate(); + void addAction(QAction *, QSymbianMenuAction* =0); + void addAction(QSymbianMenuAction *, QSymbianMenuAction* =0); + void syncAction(QSymbianMenuAction *); + inline void syncAction(QAction *a) { syncAction(findAction(a)); } + void removeAction(QSymbianMenuAction *); + void rebuild(); + inline void removeAction(QAction *a) { removeAction(findAction(a)); } + inline QSymbianMenuAction *findAction(QAction *a) { + for(int i = 0; i < actionItems.size(); i++) { + QSymbianMenuAction *act = actionItems[i]; + if(a == act->action) + return act; + } + return 0; + } + + } *symbian_menubar; + static void symbianCommands(int command); + +#endif }; #endif diff --git a/src/gui/widgets/qplaintextedit.cpp b/src/gui/widgets/qplaintextedit.cpp index e563fa1..3d2c4f5 100644 --- a/src/gui/widgets/qplaintextedit.cpp +++ b/src/gui/widgets/qplaintextedit.cpp @@ -72,6 +72,11 @@ QT_BEGIN_NAMESPACE +static inline bool shouldEnableInputMethod(QPlainTextEdit *plaintextedit) +{ + return !plaintextedit->isReadOnly(); +} + class QPlainTextDocumentLayoutPrivate : public QAbstractTextDocumentLayoutPrivate { Q_DECLARE_PUBLIC(QPlainTextDocumentLayout) @@ -705,7 +710,8 @@ QPlainTextEditPrivate::QPlainTextEditPrivate() tabChangesFocus(false), lineWrap(QPlainTextEdit::WidgetWidth), wordWrap(QTextOption::WrapAtWordBoundaryOrAnywhere), - topLine(0), pageUpDownLastCursorYIsValid(false) + clickCausedFocus(0),topLine(0), + pageUpDownLastCursorYIsValid(false) { showCursorOnInitialShow = true; backgroundVisible = false; @@ -1905,6 +1911,13 @@ void QPlainTextEdit::mouseReleaseEvent(QMouseEvent *e) d->autoScrollTimer.stop(); d->ensureCursorVisible(); } + + if (e->button() == Qt::LeftButton && qApp->autoSipEnabled() + && (!d->clickCausedFocus || qApp->autoSipOnMouseFocus())) { + QEvent event(QEvent::RequestSoftwareInputPanel); + QApplication::sendEvent(this, &event); + } + d->clickCausedFocus = 0; } /*! \reimp @@ -2038,6 +2051,9 @@ QVariant QPlainTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const void QPlainTextEdit::focusInEvent(QFocusEvent *e) { Q_D(QPlainTextEdit); + if (e->reason() == Qt::MouseFocusReason) { + d->clickCausedFocus = 1; + } QAbstractScrollArea::focusInEvent(e); d->sendControlEvent(e); } @@ -2304,7 +2320,7 @@ void QPlainTextEdit::setReadOnly(bool ro) } else { flags = Qt::TextEditorInteraction; } - setAttribute(Qt::WA_InputMethodEnabled, !ro); + setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this)); d->control->setTextInteractionFlags(flags); } diff --git a/src/gui/widgets/qplaintextedit_p.h b/src/gui/widgets/qplaintextedit_p.h index 0739d53..56a3aa9 100644 --- a/src/gui/widgets/qplaintextedit_p.h +++ b/src/gui/widgets/qplaintextedit_p.h @@ -91,7 +91,10 @@ public: return r; } inline QRectF cursorRect() { return cursorRect(textCursor()); } - void ensureCursorVisible() { textEdit->ensureCursorVisible(); } + void ensureCursorVisible() { + textEdit->ensureCursorVisible(); + emit microFocusChanged(); + } QPlainTextEdit *textEdit; @@ -148,6 +151,7 @@ public: uint backgroundVisible : 1; uint centerOnScroll : 1; uint inDrag : 1; + uint clickCausedFocus : 1; int topLine; diff --git a/src/gui/widgets/qspinbox.cpp b/src/gui/widgets/qspinbox.cpp index c691eaf..295bf48 100644 --- a/src/gui/widgets/qspinbox.cpp +++ b/src/gui/widgets/qspinbox.cpp @@ -77,6 +77,8 @@ public: QChar thousand; inline void init() { + Q_Q(QSpinBox); + q->setInputMethodHints(Qt::ImhDigitsOnly); setLayoutItemMargins(QStyle::SE_SpinBoxLayoutItem); } }; @@ -97,6 +99,11 @@ public: // variables int decimals; QChar delimiter, thousand; + + inline void init() { + Q_Q(QDoubleSpinBox); + q->setInputMethodHints(Qt::ImhFormattedNumbersOnly); + } }; @@ -592,6 +599,8 @@ void QSpinBox::fixup(QString &input) const QDoubleSpinBox::QDoubleSpinBox(QWidget *parent) : QAbstractSpinBox(*new QDoubleSpinBoxPrivate(parent), parent) { + Q_D(QDoubleSpinBox); + d->init(); } /*! diff --git a/src/gui/widgets/qtextedit.cpp b/src/gui/widgets/qtextedit.cpp index 1c4df93..c1ec5c2 100644 --- a/src/gui/widgets/qtextedit.cpp +++ b/src/gui/widgets/qtextedit.cpp @@ -74,6 +74,10 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_TEXTEDIT +static inline bool shouldEnableInputMethod(QTextEdit *textedit) +{ + return !textedit->isReadOnly(); +} class QTextEditControl : public QTextControl { @@ -104,7 +108,7 @@ public: QTextEditPrivate::QTextEditPrivate() : control(0), autoFormatting(QTextEdit::AutoNone), tabChangesFocus(false), - lineWrap(QTextEdit::WidgetWidth), lineWrapColumnOrWidth(0), + lineWrap(QTextEdit::WidgetWidth), lineWrapColumnOrWidth(0), clickCausedFocus(0), wordWrap(QTextOption::WrapAtWordBoundaryOrAnywhere), textFormat(Qt::AutoText) { ignoreAutomaticScrollbarAdjustment = false; @@ -1559,6 +1563,12 @@ void QTextEdit::mouseReleaseEvent(QMouseEvent *e) d->autoScrollTimer.stop(); ensureCursorVisible(); } + if (e->button() == Qt::LeftButton && qApp->autoSipEnabled() + && (!d->clickCausedFocus || qApp->autoSipOnMouseFocus())) { + QEvent event(QEvent::RequestSoftwareInputPanel); + QApplication::sendEvent(this, &event); + } + d->clickCausedFocus = 0; } /*! \reimp @@ -1694,6 +1704,9 @@ QVariant QTextEdit::inputMethodQuery(Qt::InputMethodQuery property) const void QTextEdit::focusInEvent(QFocusEvent *e) { Q_D(QTextEdit); + if (e->reason() == Qt::MouseFocusReason) { + d->clickCausedFocus = 1; + } QAbstractScrollArea::focusInEvent(e); d->sendControlEvent(e); } @@ -2058,7 +2071,7 @@ void QTextEdit::setReadOnly(bool ro) } else { flags = Qt::TextEditorInteraction; } - setAttribute(Qt::WA_InputMethodEnabled, !ro); + setAttribute(Qt::WA_InputMethodEnabled, shouldEnableInputMethod(this)); d->control->setTextInteractionFlags(flags); } diff --git a/src/gui/widgets/qtextedit_p.h b/src/gui/widgets/qtextedit_p.h index 3c37868..594174a 100644 --- a/src/gui/widgets/qtextedit_p.h +++ b/src/gui/widgets/qtextedit_p.h @@ -123,6 +123,7 @@ public: uint preferRichText : 1; uint showCursorOnInitialShow : 1; uint inDrag : 1; + uint clickCausedFocus : 1; // Qt3 COMPAT only, for setText Qt::TextFormat textFormat; diff --git a/src/gui/widgets/widgets.pri b/src/gui/widgets/widgets.pri index 86dc453..fc57944 100644 --- a/src/gui/widgets/widgets.pri +++ b/src/gui/widgets/widgets.pri @@ -160,3 +160,7 @@ wince*: { RC_FILE = widgets/qmenu_wince.rc !static: QMAKE_WRITE_DEFAULT_RC = 1 } + +symbian*: { + SOURCES += widgets/qmenu_symbian.cpp +} diff --git a/src/network/access/qnetworkcookie.cpp b/src/network/access/qnetworkcookie.cpp index 67df526..e31621c 100644 --- a/src/network/access/qnetworkcookie.cpp +++ b/src/network/access/qnetworkcookie.cpp @@ -97,6 +97,43 @@ QT_BEGIN_NAMESPACE /*! Create a new QNetworkCookie object, initializing the cookie name + and its value to empty QByteArray + + A cookie is only valid if it has a name. However, the value is + opaque to the application and being empty may have significance to + the remote server. +*/ +QNetworkCookie::QNetworkCookie() + : d(new QNetworkCookiePrivate) +{ + qRegisterMetaType<QNetworkCookie>(); + qRegisterMetaType<QList<QNetworkCookie> >(); + + d->name = QByteArray(); + d->value = QByteArray(); +} + +/*! + Create a new QNetworkCookie object, initializing the cookie name + to \a name and its value to empty QByteArray. + + A cookie is only valid if it has a name. However, the value is + opaque to the application and being empty may have significance to + the remote server. +*/ +QNetworkCookie::QNetworkCookie( const QByteArray &name ) + : d(new QNetworkCookiePrivate) +{ + qRegisterMetaType<QNetworkCookie>(); + qRegisterMetaType<QList<QNetworkCookie> >(); + + d->name = name; + d->value = QByteArray(); +} + + +/*! + Create a new QNetworkCookie object, initializing the cookie name to \a name and its value to \a value. A cookie is only valid if it has a name. However, the value is diff --git a/src/network/access/qnetworkcookie.h b/src/network/access/qnetworkcookie.h index e8dfab0..9112635 100644 --- a/src/network/access/qnetworkcookie.h +++ b/src/network/access/qnetworkcookie.h @@ -67,7 +67,9 @@ public: Full }; - QNetworkCookie(const QByteArray &name = QByteArray(), const QByteArray &value = QByteArray()); + QNetworkCookie(); + QNetworkCookie(const QByteArray &name ); + QNetworkCookie(const QByteArray &name, const QByteArray &value ); QNetworkCookie(const QNetworkCookie &other); ~QNetworkCookie(); QNetworkCookie &operator=(const QNetworkCookie &other); diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index 56b793d..4f9ea52 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -238,6 +238,18 @@ public: }; /*! + Constructs a QNetworkRequest object with empty QUrl. + + \sa url(), setUrl() +*/ +QNetworkRequest::QNetworkRequest() + : d(new QNetworkRequestPrivate) +{ + d->url = QUrl(); +} + + +/*! Constructs a QNetworkRequest object with \a url as the URL to be requested. diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h index 6f34bce..4c4159d 100644 --- a/src/network/access/qnetworkrequest.h +++ b/src/network/access/qnetworkrequest.h @@ -86,7 +86,9 @@ public: AlwaysCache }; - explicit QNetworkRequest(const QUrl &url = QUrl()); + + explicit QNetworkRequest(); + explicit QNetworkRequest(const QUrl &url); QNetworkRequest(const QNetworkRequest &other); ~QNetworkRequest(); QNetworkRequest &operator=(const QNetworkRequest &other); diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index 8aa6ff4..bf07aab 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -20,7 +20,8 @@ SOURCES += kernel/qauthenticator.cpp \ kernel/qnetworkproxy.cpp \ kernel/qnetworkinterface.cpp -unix:SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp +symbian: SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_symbian.cpp +unix:!symbian:SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp win32:SOURCES += kernel/qhostinfo_win.cpp kernel/qnetworkinterface_win.cpp mac:LIBS+= -framework SystemConfiguration diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp index f987520..3271deb 100644 --- a/src/network/kernel/qhostinfo_unix.cpp +++ b/src/network/kernel/qhostinfo_unix.cpp @@ -148,7 +148,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) if (address.setAddress(hostName)) { // Reverse lookup // Reverse lookups using getnameinfo are broken on darwin, use gethostbyaddr instead. -#if !defined (QT_NO_GETADDRINFO) && !defined (Q_OS_DARWIN) +#if !defined (QT_NO_GETADDRINFO) && !defined (Q_OS_DARWIN) && !defined (Q_OS_SYMBIAN) sockaddr_in sa4; #ifndef QT_NO_IPV6 sockaddr_in6 sa6; diff --git a/src/network/kernel/qnetworkinterface.cpp b/src/network/kernel/qnetworkinterface.cpp index 960999e..ff3624e 100644 --- a/src/network/kernel/qnetworkinterface.cpp +++ b/src/network/kernel/qnetworkinterface.cpp @@ -604,8 +604,13 @@ QDebug operator<<(QDebug debug, const QNetworkInterface &networkInterface) << ", hardware address = " << networkInterface.hardwareAddress() << ", flags = "; flagsDebug(debug, networkInterface.flags()); +#if defined(Q_CC_RVCT) + // RVCT gets confused with << networkInterface.addressEntries(), reason unknown. + debug.nospace() << ")\n"; +#else debug.nospace() << ", entries = " << networkInterface.addressEntries() << ")\n"; +#endif return debug.space(); } #endif diff --git a/src/network/kernel/qnetworkinterface_symbian.cpp b/src/network/kernel/qnetworkinterface_symbian.cpp new file mode 100644 index 0000000..59f1c02 --- /dev/null +++ b/src/network/kernel/qnetworkinterface_symbian.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +//#define QNETWORKINTERFACE_DEBUG + +//#include "qset.h" +#include "qnetworkinterface.h" +#include "qnetworkinterface_p.h" +//#include <private/qnativesocketengine_p.h> +//#include "qalgorithms.h" + + +#ifndef QT_NO_NETWORKINTERFACE + +#include <in_sock.h> +#include <in_iface.h> +#include <es_sock.h> + +//#include <sys/types.h> +//#include <sys/socket.h> +//#include <errno.h> +//#include <net/if.h> +//#include <qplatformdefs.h> + +QT_BEGIN_NAMESPACE + + +static QNetworkInterface::InterfaceFlags convertFlags( const TSoInetInterfaceInfo& aInfo ) +{ + QNetworkInterface::InterfaceFlags flags = 0; + flags |= (aInfo.iState == EIfUp) ? QNetworkInterface::IsUp : QNetworkInterface::InterfaceFlag(0); + // We do not have separate flag for running in Symbian OS + flags |= (aInfo.iState == EIfUp) ? QNetworkInterface::IsRunning : QNetworkInterface::InterfaceFlag(0); + flags |= (aInfo.iFeatures&KIfCanBroadcast) ? QNetworkInterface::CanBroadcast : QNetworkInterface::InterfaceFlag(0); + flags |= (aInfo.iFeatures&KIfIsLoopback) ? QNetworkInterface::IsLoopBack : QNetworkInterface::InterfaceFlag(0); + flags |= (aInfo.iFeatures&KIfIsPointToPoint) ? QNetworkInterface::IsPointToPoint : QNetworkInterface::InterfaceFlag(0); + flags |= (aInfo.iFeatures&KIfCanMulticast) ? QNetworkInterface::CanMulticast : QNetworkInterface::InterfaceFlag(0); + return flags; +} + +QString qstringFromDesc( const TDesC& aData ) +{ + return QString::fromUtf16(aData.Ptr(), aData.Length()); +} + +static QList<QNetworkInterfacePrivate *> interfaceListing() +{ + TInt err( KErrNone ); + QList<QNetworkInterfacePrivate *> interfaces; + + // Connect to Native socket server + RSocketServ socketServ; + err = socketServ.Connect(); + if( err ) + return interfaces; + + // Open dummy socket for interface queries + RSocket socket; + err = socket.Open( socketServ, _L("udp")); + if( err ) + { + socketServ.Close(); + return interfaces; + } + + // Ask socket to start enumerating interfaces + err = socket.SetOpt( KSoInetEnumInterfaces, KSolInetIfCtrl ); + if( err ) + { + socket.Close(); + socketServ.Close(); + return interfaces; + } + + int ifindex = 0; + TPckgBuf<TSoInetInterfaceInfo> infoPckg; + TSoInetInterfaceInfo &info = infoPckg(); + while( socket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, infoPckg) == KErrNone ) + { + // Do not include IPv6 addresses because netmask and broadcast address cannot be determined correctly + if( info.iName != KNullDesC && info.iAddress.IsV4Mapped() ) + { + TName address; + QNetworkAddressEntry entry; + QNetworkInterfacePrivate *iface = 0; + + iface = new QNetworkInterfacePrivate; + iface->index = ifindex++; + interfaces << iface; + iface->name = qstringFromDesc( info.iName ); + iface->flags = convertFlags( info ); + + if( /*info.iFeatures&KIfHasHardwareAddr &&*/ info.iHwAddr.Family() != KAFUnspec ) + { + for ( TInt i = sizeof(SSockAddr); i < sizeof(SSockAddr) + info.iHwAddr.GetUserLen(); i++ ) + { + address.AppendNumFixedWidth(info.iHwAddr[i], EHex, 2); + if( ( i + 1) < sizeof(SSockAddr) + info.iHwAddr.GetUserLen() ) + address.Append( _L(":") ); + } + address.UpperCase(); + iface->hardwareAddress = qstringFromDesc( address ); + } + + // Get the address of the interface + info.iAddress.Output(address); + entry.setIp( QHostAddress( qstringFromDesc( address ) ) ); + + // Get the interface netmask + // TODO: For some reason netmask is always 0.0.0.0 + //info.iNetMask.Output(address); + //entry.setNetmask( QHostAddress( qstringFromDesc( address ) ) ); + + // Workaround: Let Symbian determine netmask based on IP address class + // TODO: works only for IPv4 + TInetAddr netmask; + netmask.NetMask( info.iAddress ); + netmask.Output(address); + entry.setNetmask( QHostAddress( qstringFromDesc( address ) ) ); + + // Get the interface broadcast address + if (iface->flags & QNetworkInterface::CanBroadcast) + { + // For some reason broadcast address is always 0.0.0.0 + // info.iBrdAddr.Output(address); + // entry.setBroadcast( QHostAddress( qstringFromDesc( address ) ) ); + + // Workaround: Let Symbian determine broadcast address based on IP address + // TODO: works only for IPv4 + TInetAddr broadcast; + broadcast.NetBroadcast( info.iAddress ); + broadcast.Output(address); + entry.setBroadcast( QHostAddress( qstringFromDesc( address ) ) ); + } + + // Add new entry to interface address entries + iface->addressEntries << entry; + +#if defined(QNETWORKINTERFACE_DEBUG) + qDebug("\n Found network interface %s, interface flags:\n\ + IsUp = %d, IsRunning = %d, CanBroadcast = %d,\n\ + IsLoopBack = %d, IsPointToPoint = %d, CanMulticast = %d, \n\ + ip = %s, netmask = %s, broadcast = %s,\n\ + hwaddress = %s", + iface->name.toLatin1().constData(), + iface->flags & QNetworkInterface::IsUp, iface->flags & QNetworkInterface::IsRunning, iface->flags & QNetworkInterface::CanBroadcast, + iface->flags & QNetworkInterface::IsLoopBack, iface->flags & QNetworkInterface::IsPointToPoint, iface->flags & QNetworkInterface::CanMulticast, + entry.ip().toString().toLatin1().constData(), entry.netmask().toString().toLatin1().constData(), entry.broadcast().toString().toLatin1().constData(), + iface->hardwareAddress.toLatin1().constData()); +#endif + } + } + socket.Close(); + socketServ.Close(); + return interfaces; +} + +QList<QNetworkInterfacePrivate *> QNetworkInterfaceManager::scan() +{ + return interfaceListing(); +} + +QT_END_NAMESPACE + +#endif // QT_NO_NETWORKINTERFACE diff --git a/src/network/network.pro b/src/network/network.pro index d476b56..59cffd0 100644 --- a/src/network/network.pro +++ b/src/network/network.pro @@ -3,6 +3,13 @@ TARGET = QtNetwork QPRO_PWD = $$PWD DEFINES += QT_BUILD_NETWORK_LIB QT_NO_USING_NAMESPACE +#DEFINES += QLOCALSERVER_DEBUG QLOCALSOCKET_DEBUG +#DEFINES += QNETWORKDISKCACHE_DEBUG +#DEFINES += QSSLSOCKET_DEBUG +#DEFINES += QHOSTINFO_DEBUG +#DEFINES += QABSTRACTSOCKET_DEBUG QNATIVESOCKETENGINE_DEBUG +#DEFINES += QTCPSOCKETENGINE_DEBUG QTCPSOCKET_DEBUG QTCPSERVER_DEBUG QSSLSOCKET_DEBUG +#DEFINES += QUDPSOCKET_DEBUG QUDPSERVER_DEBUG QT = core win32-msvc*|win32-icc:QMAKE_LFLAGS += /BASE:0x64000000 @@ -15,3 +22,10 @@ include(socket/socket.pri) include(ssl/ssl.pri) QMAKE_LIBS += $$QMAKE_LIBS_NETWORK + + +symbian { + TARGET.UID3=0x2001B2DE + LIBS += -lesock -linsock +} + diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 4bb12e6..b6f91e4 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -1051,8 +1051,9 @@ void QAbstractSocketPrivate::_q_abortConnectionAttempt() #if defined(QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocketPrivate::_q_abortConnectionAttempt() (timed out)"); #endif - if (socketEngine) + if (socketEngine) { socketEngine->setWriteNotificationEnabled(false); + } connectTimer->stop(); if (addresses.isEmpty()) { diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp index d6b1507..35701a7 100644 --- a/src/network/socket/qlocalserver.cpp +++ b/src/network/socket/qlocalserver.cpp @@ -276,6 +276,10 @@ QLocalSocket *QLocalServer::nextPendingConnection() if (d->pendingConnections.isEmpty()) return 0; QLocalSocket *nextSocket = d->pendingConnections.dequeue(); +#ifdef Q_OS_SYMBIAN + if(!d->socketNotifier) + return nextSocket; +#endif #ifndef Q_OS_WIN d->socketNotifier->setEnabled(d->pendingConnections.size() <= d->maxPendingConnections); diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp index e7d2252..d3ccb69 100644 --- a/src/network/socket/qlocalserver_unix.cpp +++ b/src/network/socket/qlocalserver_unix.cpp @@ -106,6 +106,24 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName) ::memcpy(addr.sun_path, fullServerName.toLatin1().data(), fullServerName.toLatin1().size() + 1); +#ifdef Q_OS_SYMBIAN + // In SYMBIAN OS it can currently happen that accept is called twice, + // once from waitForNewConnection and once via QSocketNotfier activity + // + // As an workaround, we set the socket to non blocking so possible + // subsequent call to accept will not block in any case + // + // This change can be removed once more generic fix to select thread + // syncronization problem is implemented. + int flags = fcntl(listenSocket, F_GETFL, 0); + if (-1 == flags + || -1 == (fcntl(listenSocket, F_SETFL, flags | O_NONBLOCK))) { + setError(QLatin1String("QLocalServer::listen")); + closeServer(); + return false; + } +#endif + // bind if(-1 == qBind(listenSocket, (sockaddr *)&addr, sizeof(sockaddr_un))) { setError(QLatin1String("QLocalServer::listen")); diff --git a/src/network/socket/qlocalsocket_unix.cpp b/src/network/socket/qlocalsocket_unix.cpp index 38643f1..9e3cbde 100644 --- a/src/network/socket/qlocalsocket_unix.cpp +++ b/src/network/socket/qlocalsocket_unix.cpp @@ -237,7 +237,7 @@ void QLocalSocket::connectToServer(const QString &name, OpenMode openMode) QLatin1String("QLocalSocket::connectToServer")); return; } - +#ifndef Q_OS_SYMBIAN // set non blocking so we can try to connect and it wont wait int flags = fcntl(d->connectingSocket, F_GETFL, 0); if (-1 == flags @@ -246,6 +246,7 @@ void QLocalSocket::connectToServer(const QString &name, OpenMode openMode) QLatin1String("QLocalSocket::connectToServer")); return; } +#endif // _q_connectToSocket does the actual connecting d->connectingName = name; @@ -282,7 +283,7 @@ void QLocalSocketPrivate::_q_connectToSocket() } ::memcpy(name.sun_path, connectingPathName.toLatin1().data(), connectingPathName.toLatin1().size() + 1); - if (-1 == qConnect(connectingSocket, (struct sockaddr *)&name, sizeof(name))) { + if (-1 == qConnect(connectingSocket, (struct sockaddr *)&name, sizeof(name)) && errno != EISCONN) { QString function = QLatin1String("QLocalSocket::connectToServer"); switch (errno) { @@ -300,6 +301,7 @@ void QLocalSocketPrivate::_q_connectToSocket() case ETIMEDOUT: errorOccurred(QLocalSocket::SocketTimeoutError, function); break; + case EINPROGRESS: case EAGAIN: // Try again later, all of the sockets listening are full if (!delayConnect) { @@ -514,9 +516,9 @@ bool QLocalSocket::waitForConnected(int msec) if (state() != ConnectingState) return (state() == ConnectedState); - fd_set readfds; - FD_ZERO(&readfds); - FD_SET(d->connectingSocket, &readfds); + fd_set fds; + FD_ZERO(&fds); + FD_SET(d->connectingSocket, &fds); timeval timeout; timeout.tv_sec = msec / 1000; @@ -532,7 +534,14 @@ bool QLocalSocket::waitForConnected(int msec) timer.start(); while (state() == ConnectingState && (-1 == msec || timer.elapsed() < msec)) { - result = ::select(d->connectingSocket + 1, &readfds, 0, 0, &timeout); +#ifdef Q_OS_SYMBIAN + // On Symbian, ready-to-write is signaled when non-blocking socket + // connect is finised. Is ready-to-read really used on other + // UNIX paltforms when using non-blocking AF_UNIX socket? + result = ::select(d->connectingSocket + 1, 0, &fds, 0, &timeout); +#else + result = ::select(d->connectingSocket + 1, &fds, 0, 0, &timeout); +#endif if (-1 == result && errno != EINTR) { d->errorOccurred( QLocalSocket::UnknownSocketError, QLatin1String("QLocalSocket::waitForConnected")); diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp index b25b887..6b2e194 100644 --- a/src/network/socket/qnativesocketengine.cpp +++ b/src/network/socket/qnativesocketengine.cpp @@ -381,11 +381,13 @@ bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAb return false; } + // Make sure we receive out-of-band data + // On Symbian OS this works only with native IP stack, not with WinSock if (socketType == QAbstractSocket::TcpSocket && !setOption(ReceiveOutOfBandData, 1)) { qWarning("QNativeSocketEngine::initialize unable to inline out-of-band data"); - } + } // Set the send and receive buffer sizes to a magic size, found // most optimal for our platforms. @@ -1086,10 +1088,13 @@ protected: bool QExceptionNotifier::event(QEvent *e) { if (e->type() == QEvent::SockAct) { - engine->exceptionNotification(); + if (engine->state() == QAbstractSocket::ConnectingState) + engine->connectionNotification(); + else + engine->exceptionNotification(); return true; } - return QSocketNotifier::event(e); + return QSocketNotifier::event(e); } void QNativeSocketEngine::setReadNotificationEnabled(bool enable) diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index eb031d3..95ffba5 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -52,7 +52,6 @@ // // We mean it. // - #include "QtNetwork/qhostaddress.h" #include "private/qabstractsocketengine_p.h" #ifndef Q_OS_WIN @@ -61,8 +60,14 @@ # include <winsock2.h> #endif +#ifdef Q_OS_SYMBIAN +#include <private/qeventdispatcher_symbian_p.h> +#include<unistd.h> +#endif + QT_BEGIN_NAMESPACE + #ifndef Q_OS_WIN // Almost always the same. If not, specify in qplatformdefs.h. #if !defined(QT_SOCKOPTLEN_T) @@ -78,14 +83,144 @@ static inline int qt_socket_accept(int s, struct sockaddr *addr, QT_SOCKLEN_T *a // UnixWare 7 redefines listen -> _listen static inline int qt_socket_listen(int s, int backlog) -{ return ::listen(s, backlog); } +{ + return ::listen(s, backlog); +} #if defined(listen) # undef listen #endif +static inline int qt_socket_connect(int s, const struct sockaddr * addrptr, socklen_t namelen) +{ + return ::connect(s, addrptr, namelen); +} +#if defined(connect) +# undef connect +#endif + +static inline int qt_socket_bind(int s, const struct sockaddr * addrptr, socklen_t namelen) +{ + return ::bind(s, addrptr, namelen); +} +#if defined(bind) +# undef bind +#endif + +static inline int qt_socket_write(int socket, const char *data, qint64 len) +{ + return ::write(socket, data, len); +} +#if defined(write) +# undef write +#endif + +static inline int qt_socket_read(int socket, char *data, qint64 len) +{ + return ::read(socket, data, len); +} +#if defined(read) +# undef read +#endif + +static inline int qt_socket_recv(int socket, void *data, size_t length, int flags) +{ + return ::recv(socket, data, length, flags); +} +#if defined(recv) +# undef recv +#endif + +static inline int qt_socket_recvfrom(int socket, void *data, size_t length, + int flags, struct sockaddr *address, + socklen_t *address_length) +{ + return ::recvfrom(socket, data, length, flags, address, address_length); +} +#if defined(recvfrom) +# undef recvfrom +#endif + +static inline int qt_socket_sendto(int socket, const void *data, size_t length, + int flags, const struct sockaddr *dest_addr, + socklen_t dest_length) +{ + return ::sendto(socket, data, length, flags, dest_addr, dest_length); +} +#if defined(sendto) +# undef sendto +#endif +static inline int qt_socket_close(int socket) +{ + return ::close(socket); +} +#if defined(close) +# undef close +#endif + +static inline int qt_socket_fcntl(int socket, int command, int option) +{ + return ::fcntl(socket, command, option); +} +#if defined(fcntl) +# undef fcntl +#endif + +static inline int qt_socket_ioctl(int socket, int command, char *option) +{ + return ::ioctl(socket, command, option); +} +#if defined(ioctl) +# undef ioctl +#endif + +static inline int qt_socket_getsockname(int socket, struct sockaddr *address, socklen_t *address_len) +{ + return ::getsockname(socket, address, address_len); +} +#if defined(getsockname) +# undef getsockname +#endif + +static inline int qt_socket_getpeername(int socket, struct sockaddr *address, socklen_t *address_len) +{ + return ::getpeername(socket, address, address_len); +} +#if defined(getpeername) +# undef getpeername +#endif + +static inline int qt_socket_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) +{ + return ::select(nfds, readfds, writefds, exceptfds, timeout); +} + +#if defined(select) +# undef select +#endif + +static inline int qt_socket_getsockopt(int socket, int level, int optname, void *optval, socklen_t *optlen) +{ + return ::getsockopt(socket, level, optname, optval, optlen); +} + +#if defined(getsockopt) +# undef getsockopt +#endif + +static inline int qt_socket_setsockopt(int socket, int level, int optname, void *optval, socklen_t optlen) +{ + return ::setsockopt(socket, level, optname, optval, optlen); +} + +#if defined(setsockopt) +# undef setsockopt +#endif + // UnixWare 7 redefines socket -> _socket static inline int qt_socket_socket(int domain, int type, int protocol) -{ return ::socket(domain, type, protocol); } +{ + return ::socket(domain, type, protocol); +} #if defined(socket) # undef socket #endif @@ -212,6 +347,12 @@ public: int socketDescriptor; +#if !defined(QT_NO_IPV6) + struct sockaddr_storage aa; +#else + struct sockaddr_in aa; +#endif + QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; #ifdef Q_OS_WIN diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index 75b5a64..5136978 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -40,7 +40,6 @@ ****************************************************************************/ //#define QNATIVESOCKETENGINE_DEBUG - #include "qnativesocketengine_p.h" #include "qiodevice.h" #include "qhostaddress.h" @@ -59,6 +58,10 @@ #include <arpa/inet.h> #endif +#ifdef Q_OS_SYMBIAN +#include <private/qeventdispatcher_symbian_p.h> +#endif + #if defined QNATIVESOCKETENGINE_DEBUG #include <qstring.h> #include <ctype.h> @@ -100,6 +103,7 @@ static QByteArray qt_prettyDebug(const char *data, int len, int maxSize) static void qt_ignore_sigpipe() { +#ifndef Q_NO_POSIX_SIGNALS // Set to ignore SIGPIPE once only. static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0); if (atom.testAndSetRelaxed(0, 1)) { @@ -108,6 +112,10 @@ static void qt_ignore_sigpipe() noaction.sa_handler = SIG_IGN; ::sigaction(SIGPIPE, &noaction, 0); } +#else + // Posix signals are not supported by the underlying platform + // so we don't need to ignore sigpipe signal explicitly +#endif } /* @@ -126,7 +134,7 @@ static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *po *addr = tmpAddress; #ifndef QT_NO_IPV6IFNAME char scopeid[IFNAMSIZ]; - if (::if_indextoname(s->a6.sin6_scope_id, scopeid) > 0) { + if (::if_indextoname(s->a6.sin6_scope_id, scopeid)) { addr->setScopeId(QLatin1String(scopeid)); } else #endif @@ -187,7 +195,8 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc } // Ensure that the socket is closed on exec*(). - ::fcntl(socket, F_SETFD, FD_CLOEXEC); + qt_socket_fcntl(socket, F_SETFD, FD_CLOEXEC); + socketDescriptor = socket; return true; } @@ -225,8 +234,9 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co int v = -1; QT_SOCKOPTLEN_T len = sizeof(v); - if (getsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, &len) != -1) + if (qt_socket_getsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, &len) != -1) return v; + return -1; } @@ -253,14 +263,14 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt break; case QNativeSocketEngine::NonBlockingSocketOption: { // Make the socket nonblocking. - int flags = ::fcntl(socketDescriptor, F_GETFL, 0); + int flags = qt_socket_fcntl(socketDescriptor, F_GETFL, 0); if (flags == -1) { #ifdef QNATIVESOCKETENGINE_DEBUG perror("QNativeSocketEnginePrivate::setOption(): fcntl(F_GETFL) failed"); #endif return false; } - if (::fcntl(socketDescriptor, F_SETFL, flags | O_NONBLOCK) == -1) { + if (qt_socket_fcntl(socketDescriptor, F_SETFL, flags | O_NONBLOCK) == -1) { #ifdef QNATIVESOCKETENGINE_DEBUG perror("QNativeSocketEnginePrivate::setOption(): fcntl(F_SETFL) failed"); #endif @@ -270,7 +280,9 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt return true; } case QNativeSocketEngine::AddressReusable: -#ifdef SO_REUSEPORT +#ifdef Q_OS_SYMBIAN + n = SO_REUSEADDR; +#elif SO_REUSEPORT n = SO_REUSEPORT; #else n = SO_REUSEADDR; @@ -283,11 +295,16 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt break; } - return ::setsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, sizeof(v)) == 0; + return qt_socket_setsockopt(socketDescriptor, SOL_SOCKET, n, (char *) &v, sizeof(v)) == 0; + } bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 port) { +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug("QNativeSocketEnginePrivate::nativeConnect() : %d ", socketDescriptor); +#endif + struct sockaddr_in sockAddrIPv4; struct sockaddr *sockAddrPtr = 0; QT_SOCKLEN_T sockAddrSize = 0; @@ -326,7 +343,8 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 // unreachable } - int connectResult = QT_SOCKET_CONNECT(socketDescriptor, sockAddrPtr, sockAddrSize); + int connectResult = qt_socket_connect(socketDescriptor, sockAddrPtr, sockAddrSize); + if (connectResult == -1) { switch (errno) { case EISCONN: @@ -429,7 +447,8 @@ bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 // unreachable } - int bindResult = QT_SOCKET_BIND(socketDescriptor, sockAddrPtr, sockAddrSize); + int bindResult = qt_socket_bind(socketDescriptor, sockAddrPtr, sockAddrSize); + if (bindResult < 0) { switch(errno) { case EADDRINUSE: @@ -497,8 +516,15 @@ int QNativeSocketEnginePrivate::nativeAccept() #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeAccept() == %i", acceptedDescriptor); #endif - // Ensure that the socket is closed on exec*() - ::fcntl(acceptedDescriptor, F_SETFD, FD_CLOEXEC); + + //check if we have vaild descriptor at all + if(acceptedDescriptor > 0) { + // Ensure that the socket is closed on exec*() + qt_socket_fcntl(acceptedDescriptor, F_SETFD, FD_CLOEXEC); + } else { + qWarning("QNativeSocketEnginePrivate::nativeAccept() - acceptedDescriptor <= 0"); + } + return acceptedDescriptor; } @@ -528,7 +554,7 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const ssize_t readBytes; do { char c; - readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, &storage.a, &storageSize); + readBytes = qt_socket_recvfrom(socketDescriptor, &c, 1, MSG_PEEK, &storage.a, &storageSize); } while (readBytes == -1 && errno == EINTR); // If there's no error, or if our buffer was too small, there must be a @@ -542,16 +568,25 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const return result; } +#ifdef Q_OS_SYMBIAN +qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const +{ + size_t nbytes = 0; + qt_socket_ioctl(socketDescriptor, E32IONREAD, (char *) &nbytes); + return qint64(nbytes-28); +} +#else qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const { QVarLengthArray<char, 8192> udpMessagePeekBuffer(8192); - ssize_t recvResult = -1; + ssize_t recvResult = -1; + for (;;) { // the data written to udpMessagePeekBuffer is discarded, so // this function is still reentrant although it might not look // so. - recvResult = ::recv(socketDescriptor, udpMessagePeekBuffer.data(), - udpMessagePeekBuffer.size(), MSG_PEEK); + recvResult = qt_socket_recv(socketDescriptor, udpMessagePeekBuffer.data(), + udpMessagePeekBuffer.size(), MSG_PEEK); if (recvResult == -1 && errno == EINTR) continue; @@ -560,14 +595,14 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const udpMessagePeekBuffer.resize(udpMessagePeekBuffer.size() * 2); } - + #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativePendingDatagramSize() == %i", recvResult); #endif return qint64(recvResult); } - +#endif qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, QHostAddress *address, quint16 *port) { @@ -579,7 +614,7 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS ssize_t recvFromResult = 0; do { char c; - recvFromResult = ::recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1, + recvFromResult = qt_socket_recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1, 0, &aa.a, &sz); } while (recvFromResult == -1 && errno == EINTR); @@ -630,10 +665,9 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l // ignore the SIGPIPE signal qt_ignore_sigpipe(); - ssize_t sentBytes; do { - sentBytes = ::sendto(socketDescriptor, data, len, + sentBytes = qt_socket_sendto(socketDescriptor, data, len, 0, sockAddrPtr, sockAddrSize); } while (sentBytes == -1 && errno == EINTR); @@ -671,7 +705,7 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() // Determine local address memset(&sa, 0, sizeof(sa)); - if (::getsockname(socketDescriptor, &sa.a, &sockAddrSize) == 0) { + if (qt_socket_getsockname(socketDescriptor, &sa.a, &sockAddrSize) == 0) { qt_socket_getPortAndAddress(&sa, &localPort, &localAddress); // Determine protocol family @@ -695,13 +729,13 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() } // Determine the remote address - if (!::getpeername(socketDescriptor, &sa.a, &sockAddrSize)) + if (!qt_socket_getpeername(socketDescriptor, &sa.a, &sockAddrSize)) qt_socket_getPortAndAddress(&sa, &peerPort, &peerAddress); // Determine the socket type (UDP/TCP) int value = 0; QT_SOCKOPTLEN_T valueSize = sizeof(int); - if (::getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, &value, &valueSize) == 0) { + if (qt_socket_getsockopt(socketDescriptor, SOL_SOCKET, SO_TYPE, &value, &valueSize) == 0) { if (value == SOCK_STREAM) socketType = QAbstractSocket::TcpSocket; else if (value == SOCK_DGRAM) @@ -732,7 +766,7 @@ void QNativeSocketEnginePrivate::nativeClose() #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEngine::nativeClose()"); #endif - ::close(socketDescriptor); + qt_socket_close(socketDescriptor); } qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) @@ -746,7 +780,7 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) // of an interrupting signal. ssize_t writtenBytes; do { - writtenBytes = ::write(socketDescriptor, data, len); + writtenBytes = qt_socket_write(socketDescriptor, data, len); } while (writtenBytes < 0 && errno == EINTR); if (writtenBytes < 0) { @@ -788,7 +822,7 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) ssize_t r = 0; do { - r = ::read(socketDescriptor, data, maxSize); + r = qt_socket_read(socketDescriptor, data, maxSize); } while (r == -1 && errno == EINTR); if (r < 0) { @@ -806,6 +840,9 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) case EIO: setError(QAbstractSocket::NetworkError, ReadErrorString); break; +#ifdef Q_OS_SYMBIAN + case EPIPE: +#endif case ECONNRESET: r = 0; break; @@ -833,18 +870,48 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; +#ifdef Q_OS_SYMBIAN + fd_set fdexec; + FD_ZERO(&fdexec); + FD_SET(socketDescriptor, &fdexec); +#endif + QTime timer; timer.start(); int retval; do { if (selectForRead) - retval = select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv); +#ifndef Q_OS_SYMBIAN + retval = qt_socket_select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv); +#else + retval = qt_socket_select(socketDescriptor + 1, &fds, 0, &fdexec, timeout < 0 ? 0 : &tv); +#endif else - retval = select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv); +#ifndef Q_OS_SYMBIAN + retval = qt_socket_select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv); +#else + retval = qt_socket_select(socketDescriptor + 1, 0, &fds, &fdexec, timeout < 0 ? 0 : &tv); +#endif + + +#ifdef Q_OS_SYMBIAN + bool selectForExec = false; + if(retval != 0) { + if(retval < 0) { + qWarning("nativeSelect(....) returned < 0 for socket %d", socketDescriptor); + } + selectForExec = FD_ISSET(socketDescriptor, &fdexec); + } + if(selectForExec) { + qWarning("nativeSelect (selectForRead %d, retVal %d, errno %d) Unexpected expectfds ready in fd %d", + selectForRead, retval, errno, socketDescriptor); + } +#endif - if (retval != -1 || errno != EINTR) + if (retval != -1 || errno != EINTR) { break; + } if (timeout > 0) { // recalculate the timeout @@ -875,6 +942,12 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c FD_ZERO(&fdwrite); if (checkWrite) FD_SET(socketDescriptor, &fdwrite); + +#ifdef Q_OS_SYMBIAN + fd_set fdexec; + FD_ZERO(&fdexec); + FD_SET(socketDescriptor, &fdexec); +#endif struct timeval tv; tv.tv_sec = timeout / 1000; @@ -885,9 +958,33 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c int ret; do { - ret = select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv); - if (ret != -1 || errno != EINTR) +#ifndef Q_OS_SYMBIAN + ret = qt_socket_select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv); +#else + ret = qt_socket_select(socketDescriptor + 1, &fdread, &fdwrite, &fdexec, timeout < 0 ? 0 : &tv); + bool selectForExec = false; + if(ret != 0) { + if(ret < 0) { + qWarning("nativeSelect(....) returned < 0 for socket %d", socketDescriptor); + } + selectForExec = FD_ISSET(socketDescriptor, &fdexec); + } + if(selectForExec) { + qWarning("nativeSelect (checkRead %d, checkWrite %d, ret %d, errno %d): Unexpected expectfds ready in fd %d", + checkRead, checkWrite, ret, errno, socketDescriptor); + if (checkRead) + FD_SET(socketDescriptor, &fdread); + if (checkWrite) + FD_SET(socketDescriptor, &fdwrite); + + if ((ret == -1) && ( errno == ECONNREFUSED || errno == EPIPE )) + ret = 1; + + } +#endif + if (ret != -1 || errno != EINTR) { break; + } if (timeout > 0) { // recalculate the timeout @@ -904,9 +1001,9 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c } while (true); if (ret <= 0) return ret; - *selectForRead = FD_ISSET(socketDescriptor, &fdread); *selectForWrite = FD_ISSET(socketDescriptor, &fdwrite); + return ret; } diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp index c41e32d..b6b0e89 100644 --- a/src/network/socket/qsocks5socketengine.cpp +++ b/src/network/socket/qsocks5socketengine.cpp @@ -59,7 +59,11 @@ QT_BEGIN_NAMESPACE +#ifdef Q_OS_SYMBIAN +static const int MaxWriteBufferSize = 4*1024; +#else static const int MaxWriteBufferSize = 128*1024; +#endif //#define QSOCKS5SOCKETLAYER_DEBUG diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp index 820404d..e46cb4c 100644 --- a/src/network/socket/qudpsocket.cpp +++ b/src/network/socket/qudpsocket.cpp @@ -91,6 +91,13 @@ This enum describes the different flags you can pass to modify the behavior of QUdpSocket::bind(). + + \note On Symbian OS bind flags behaviour depends on process capabilties. + If process has NetworkControl capability, the bind attempt with + ReuseAddressHint will always succeed even the address and port is already + bound by another socket with any flags. If process does not have + NetworkControl capability, the bind attempt to address and port already + bound by another socket will always fail. \value ShareAddress Allow other services to bind to the same address and port. This is useful when multiple processes share @@ -346,6 +353,9 @@ qint64 QUdpSocket::pendingDatagramSize() const as even if they are sent successfully, they are likely to be fragmented by the IP layer before arriving at their final destination. + + \warning In S60 5.0 and earlier versions, the writeDatagram return + value is not reliable for large datagrams. \warning Calling this function on a connected UDP socket may result in an error and no packet being sent. If you are using a @@ -365,6 +375,16 @@ qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddre return -1; qint64 sent = d->socketEngine->writeDatagram(data, size, address, port); +#ifdef Q_OS_SYMBIAN + if( QSysInfo::s60Version() <= QSysInfo::SV_S60_5_0 ) { + // This is evil hack, but for some reason native RSocket::SendTo returns 0, + // for large datagrams (such as 600 bytes). Based on comments from Open C team + // this should happen only in platforms <= S60 5.0. + // As an workaround, we just set sent = size + if( sent == 0 ) + sent = size; + } +#endif d->cachedSocketDescriptor = d->socketEngine->socketDescriptor(); if (sent >= 0) { diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri index b1fe64a..dad43d2 100644 --- a/src/network/socket/socket.pri +++ b/src/network/socket/socket.pri @@ -42,5 +42,3 @@ wince*: { DEFINES += QT_LOCALSOCKET_TCP } - - diff --git a/src/network/ssl/qsslerror.cpp b/src/network/ssl/qsslerror.cpp index daa6533..3096fee 100644 --- a/src/network/ssl/qsslerror.cpp +++ b/src/network/ssl/qsslerror.cpp @@ -110,6 +110,23 @@ public: \sa QSslCertificate */ + +// RVCT compiler in debug build does not like about default values in const- +// So as an workaround we define all constructor overloads here explicitly +QSslError::QSslError() + : d(new QSslErrorPrivate) +{ + d->error = QSslError::NoError; + d->certificate = QSslCertificate(); +} + +QSslError::QSslError(SslError error) + : d(new QSslErrorPrivate) +{ + d->error = error; + d->certificate = QSslCertificate(); +} + QSslError::QSslError(SslError error, const QSslCertificate &certificate) : d(new QSslErrorPrivate) { diff --git a/src/network/ssl/qsslerror.h b/src/network/ssl/qsslerror.h index c120215..50cc142 100644 --- a/src/network/ssl/qsslerror.h +++ b/src/network/ssl/qsslerror.h @@ -86,8 +86,14 @@ public: UnspecifiedError = -1 }; - QSslError(SslError error = NoError, const QSslCertificate &certificate = QSslCertificate()); + // RVCT compiler in debug build does not like about default values in const- + // So as an workaround we define all constructor overloads here explicitly + QSslError(); + QSslError(SslError error); + QSslError(SslError error, const QSslCertificate &certificate); + QSslError(const QSslError &other); + ~QSslError(); QSslError &operator=(const QSslError &other); bool operator==(const QSslError &other) const; diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h index b3be42a..968fdc0 100644 --- a/src/network/ssl/qsslsocket_openssl_p.h +++ b/src/network/ssl/qsslsocket_openssl_p.h @@ -77,6 +77,10 @@ #include <openssl/x509.h> #include <openssl/x509v3.h> #include <openssl/x509_vfy.h> +#ifdef Q_OS_SYMBIAN +#include <openssl/dsa.h> +#include <openssl/rsa.h> +#endif QT_BEGIN_NAMESPACE diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp index 42c09f5..0723822 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols.cpp +++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp @@ -231,10 +231,16 @@ DEFINEFUNC3(DSA *, d2i_DSAPrivateKey, DSA **a, a, unsigned char **b, b, long c, DEFINEFUNC(void, OPENSSL_add_all_algorithms_noconf, void, DUMMYARG, return, DUMMYARG) DEFINEFUNC(void, OPENSSL_add_all_algorithms_conf, void, DUMMYARG, return, DUMMYARG) +#ifdef Q_OS_SYMBIAN +#define RESOLVEFUNC(func, ordinal, lib) \ + if (!(_q_##func = _q_PTR_##func(lib->resolve(#ordinal)))) \ + qWarning("QSslSocket: cannot resolve "#func); +#else #define RESOLVEFUNC(func) \ if (!(_q_##func = _q_PTR_##func(libs.first->resolve(#func))) \ && !(_q_##func = _q_PTR_##func(libs.second->resolve(#func)))) \ qWarning("QSslSocket: cannot resolve "#func); +#endif #if !defined QT_LINKED_OPENSSL @@ -335,7 +341,24 @@ static QPair<QLibrary*, QLibrary*> loadOpenSsl() pair.first = ssleay32; pair.second = libeay32; return pair; +# elif defined(Q_OS_SYMBIAN) + QLibrary *libssl = new QLibrary(QLatin1String("libssl")); + if (!libssl->load()) { + // Cannot find ssleay32.dll + delete libssl; + return pair; + } + QLibrary *libcrypto = new QLibrary(QLatin1String("libcrypto")); + if (!libcrypto->load()) { + delete libcrypto; + delete libssl; + return pair; + } + + pair.first = libssl; + pair.second = libcrypto; + return pair; # elif defined(Q_OS_UNIX) QLibrary *&libssl = pair.first; QLibrary *&libcrypto = pair.second; @@ -437,6 +460,127 @@ bool q_resolveOpenSslSymbols() // failed to load them return false; +#ifdef Q_OS_SYMBIAN +#ifdef SSLEAY_MACROS + RESOLVEFUNC(ASN1_dup, 125, libs.second ) +#endif + RESOLVEFUNC(ASN1_STRING_data, 71, libs.second ) + RESOLVEFUNC(ASN1_STRING_length, 76, libs.second ) + RESOLVEFUNC(BIO_ctrl, 184, libs.second ) + RESOLVEFUNC(BIO_free, 209, libs.second ) + RESOLVEFUNC(BIO_new, 222, libs.second ) + RESOLVEFUNC(BIO_new_mem_buf, 230, libs.second ) + RESOLVEFUNC(BIO_read, 244, libs.second ) + RESOLVEFUNC(BIO_s_mem, 251, libs.second ) + RESOLVEFUNC(BIO_write, 269, libs.second ) + RESOLVEFUNC(BN_num_bits, 387, libs.second ) + RESOLVEFUNC(CRYPTO_free, 469, libs.second ) + RESOLVEFUNC(CRYPTO_num_locks, 500, libs.second ) + RESOLVEFUNC(CRYPTO_set_id_callback, 513, libs.second ) + RESOLVEFUNC(CRYPTO_set_locking_callback, 516, libs.second ) + RESOLVEFUNC(DSA_free, 594, libs.second ) + RESOLVEFUNC(ERR_error_string, 744, libs.second ) + RESOLVEFUNC(ERR_get_error, 749, libs.second ) + RESOLVEFUNC(EVP_des_ede3_cbc, 919, libs.second ) + RESOLVEFUNC(EVP_PKEY_assign, 859, libs.second ) + RESOLVEFUNC(EVP_PKEY_free, 867, libs.second ) + RESOLVEFUNC(EVP_PKEY_get1_DSA, 869, libs.second ) + RESOLVEFUNC(EVP_PKEY_get1_RSA, 870, libs.second ) + RESOLVEFUNC(EVP_PKEY_new, 876, libs.second ) + RESOLVEFUNC(EVP_PKEY_type, 882, libs.second ) + RESOLVEFUNC(OBJ_nid2sn, 1036, libs.second ) + RESOLVEFUNC(OBJ_obj2nid, 1037, libs.second ) +#ifdef SSLEAY_MACROS // ### verify + RESOLVEFUNC(PEM_ASN1_read_bio, 1180, libs.second ) +#else + RESOLVEFUNC(PEM_read_bio_DSAPrivateKey, 1219, libs.second ) + RESOLVEFUNC(PEM_read_bio_RSAPrivateKey, 1228, libs.second ) + RESOLVEFUNC(PEM_write_bio_DSAPrivateKey, 1260, libs.second ) + RESOLVEFUNC(PEM_write_bio_RSAPrivateKey, 1271, libs.second ) +#endif + RESOLVEFUNC(PEM_read_bio_DSA_PUBKEY, 1220, libs.second ) + RESOLVEFUNC(PEM_read_bio_RSA_PUBKEY, 1230, libs.second ) + RESOLVEFUNC(PEM_write_bio_DSA_PUBKEY, 1261, libs.second ) + RESOLVEFUNC(PEM_write_bio_RSA_PUBKEY, 1273, libs.second ) + RESOLVEFUNC(RAND_seed, 1426, libs.second ) + RESOLVEFUNC(RAND_status, 1429, libs.second ) + RESOLVEFUNC(RSA_free, 1450, libs.second ) + RESOLVEFUNC(sk_free, 2571, libs.second ) + RESOLVEFUNC(sk_num, 2576, libs.second ) + RESOLVEFUNC(sk_value, 2585, libs.second ) + RESOLVEFUNC(SSL_CIPHER_description, 11, libs.first ) + RESOLVEFUNC(SSL_CTX_check_private_key, 21, libs.first ) + RESOLVEFUNC(SSL_CTX_ctrl, 22, libs.first ) + RESOLVEFUNC(SSL_CTX_free, 24, libs.first ) + RESOLVEFUNC(SSL_CTX_new, 35, libs.first ) + RESOLVEFUNC(SSL_CTX_set_cipher_list, 40, libs.first ) + RESOLVEFUNC(SSL_CTX_set_default_verify_paths, 44, libs.first ) + RESOLVEFUNC(SSL_CTX_set_verify, 56, libs.first ) + RESOLVEFUNC(SSL_CTX_set_verify_depth, 57, libs.first ) + RESOLVEFUNC(SSL_CTX_use_certificate, 64, libs.first ) + RESOLVEFUNC(SSL_CTX_use_certificate_file, 67, libs.first ) + RESOLVEFUNC(SSL_CTX_use_PrivateKey, 58, libs.first ) + RESOLVEFUNC(SSL_CTX_use_RSAPrivateKey, 61, libs.first ) + RESOLVEFUNC(SSL_CTX_use_PrivateKey_file, 60, libs.first ) + RESOLVEFUNC(SSL_accept, 82, libs.first ) + RESOLVEFUNC(SSL_clear, 92, libs.first ) + RESOLVEFUNC(SSL_connect, 93, libs.first ) + RESOLVEFUNC(SSL_free, 99, libs.first ) + RESOLVEFUNC(SSL_get_ciphers, 104, libs.first ) + RESOLVEFUNC(SSL_get_current_cipher, 106, libs.first ) + RESOLVEFUNC(SSL_get_error, 110, libs.first ) + RESOLVEFUNC(SSL_get_peer_cert_chain, 117, libs.first ) + RESOLVEFUNC(SSL_get_peer_certificate, 118, libs.first ) + RESOLVEFUNC(SSL_get_verify_result, 132, libs.first ) + RESOLVEFUNC(SSL_library_init, 137, libs.first ) + RESOLVEFUNC(SSL_load_error_strings, 139, libs.first ) + RESOLVEFUNC(SSL_new, 140, libs.first ) + RESOLVEFUNC(SSL_read, 143, libs.first ) + RESOLVEFUNC(SSL_set_accept_state, 148, libs.first ) + RESOLVEFUNC(SSL_set_bio, 149, libs.first ) + RESOLVEFUNC(SSL_set_connect_state, 152, libs.first ) + RESOLVEFUNC(SSL_shutdown, 173, libs.first ) + RESOLVEFUNC(SSL_write, 188, libs.first ) + RESOLVEFUNC(SSLv2_client_method, 192, libs.first ) + RESOLVEFUNC(SSLv3_client_method, 195, libs.first ) + RESOLVEFUNC(SSLv23_client_method, 189, libs.first ) + RESOLVEFUNC(TLSv1_client_method, 198, libs.first ) + RESOLVEFUNC(SSLv2_server_method, 194, libs.first ) + RESOLVEFUNC(SSLv3_server_method, 197, libs.first ) + RESOLVEFUNC(SSLv23_server_method, 191, libs.first ) + RESOLVEFUNC(TLSv1_server_method, 200, libs.first ) + RESOLVEFUNC(X509_NAME_oneline, 1830, libs.second ) + RESOLVEFUNC(X509_PUBKEY_get, 1844, libs.second ) + RESOLVEFUNC(X509_STORE_free, 1939, libs.second ) + RESOLVEFUNC(X509_STORE_new, 1942, libs.second ) + RESOLVEFUNC(X509_STORE_add_cert, 1936, libs.second ) + RESOLVEFUNC(X509_STORE_CTX_free, 1907, libs.second ) + RESOLVEFUNC(X509_STORE_CTX_init, 1919, libs.second ) + RESOLVEFUNC(X509_STORE_CTX_new, 1920, libs.second ) + RESOLVEFUNC(X509_STORE_CTX_set_purpose, 1931, libs.second ) + RESOLVEFUNC(X509_cmp, 1992, libs.second ) +#ifndef SSLEAY_MACROS + RESOLVEFUNC(X509_dup, 1997, libs.second ) +#endif + RESOLVEFUNC(X509_EXTENSION_get_object, 1785, libs.second ) + RESOLVEFUNC(X509_free, 2001, libs.second ) + RESOLVEFUNC(X509_get_ext, 2012, libs.second ) + RESOLVEFUNC(X509_get_ext_count, 2016, libs.second ) + RESOLVEFUNC(X509_get_ext_d2i, 2017, libs.second ) + RESOLVEFUNC(X509_get_issuer_name, 2018, libs.second ) + RESOLVEFUNC(X509_get_subject_name, 2022, libs.second ) + RESOLVEFUNC(X509_verify_cert, 2069, libs.second ) + RESOLVEFUNC(d2i_X509, 2309, libs.second ) + RESOLVEFUNC(i2d_X509, 2489, libs.second ) +#ifdef SSLEAY_MACROS + RESOLVEFUNC(i2d_DSAPrivateKey, 2395, libs.second ) + RESOLVEFUNC(i2d_RSAPrivateKey, 2476, libs.second ) + RESOLVEFUNC(d2i_DSAPrivateKey, 2220, libs.second ) + RESOLVEFUNC(d2i_RSAPrivateKey, 2296, libs.second ) +#endif + RESOLVEFUNC(OPENSSL_add_all_algorithms_noconf, 1153, libs.second ) + RESOLVEFUNC(OPENSSL_add_all_algorithms_conf, 1152, libs.second ) +#else // Q_OS_SYMBIAN #ifdef SSLEAY_MACROS RESOLVEFUNC(ASN1_dup) #endif @@ -556,6 +700,7 @@ bool q_resolveOpenSslSymbols() #endif RESOLVEFUNC(OPENSSL_add_all_algorithms_noconf) RESOLVEFUNC(OPENSSL_add_all_algorithms_conf) +#endif // Q_OS_SYMBIAN symbolsResolved = true; delete libs.first; delete libs.second; diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri index 196e19d..5427370 100644 --- a/src/network/ssl/ssl.pri +++ b/src/network/ssl/ssl.pri @@ -1,6 +1,16 @@ # OpenSSL support; compile in QSslSocket. contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) { - include($$QT_SOURCE_TREE/config.tests/unix/openssl/openssl.pri) + + +symbian { + TRY_INCLUDEPATHS = $${EPOCROOT}epoc32/include $${EPOCROOT}epoc32/include/stdapis $${EPOCROOT}epoc32/include/stdapis/sys $$OS_LAYER_LIBC_SYSTEMINCLUDE + for(p, TRY_INCLUDEPATHS) { + pp = $$join(p, "", "", "/openssl") + exists($$pp):INCLUDEPATH *= $$pp + } +} else { + include($$QT_SOURCE_TREE/config.tests/unix/openssl/openssl.pri) +} HEADERS += ssl/qssl.h \ ssl/qsslcertificate.h \ diff --git a/src/phonon/phonon.pro b/src/phonon/phonon.pro index ec7e46a..b38adb8 100644 --- a/src/phonon/phonon.pro +++ b/src/phonon/phonon.pro @@ -113,3 +113,18 @@ contains(QT_CONFIG, dbus) { } contains(QT_CONFIG, reduce_exports): CONFIG += hide_symbols + +symbian: { + # Phonon depends on numeric_limits. Enabling STL support in Qt + # would bring in link dependencies, and we don't need that for + # numeric_limits, hence we here merely ensure we bring in the necessary + # header. + INCLUDEPATH *= $${EPOCROOT}epoc32/include/stdapis/stlport \ + $$OS_LAYER_STDCPP_SYSTEMINCLUDE + + # Without this setting, code using numeric_limits will fail + # for winscw, although armv5 works fine no matter what. + QMAKE_CXXFLAGS.CW *= $$STLLIB_USAGE_CW_FLAGS + + TARGET.UID3 = 0x2001E624 +} diff --git a/src/plugins/codecs/cn/cn.pro b/src/plugins/codecs/cn/cn.pro index a7b8b60..b0a8a91 100644 --- a/src/plugins/codecs/cn/cn.pro +++ b/src/plugins/codecs/cn/cn.pro @@ -12,3 +12,5 @@ SOURCES = qgb18030codec.cpp \ target.path += $$[QT_INSTALL_PLUGINS]/codecs INSTALLS += target + +symbian:TARGET.UID3=0x2001E615 diff --git a/src/plugins/codecs/jp/jp.pro b/src/plugins/codecs/jp/jp.pro index 8626912..6480e43 100644 --- a/src/plugins/codecs/jp/jp.pro +++ b/src/plugins/codecs/jp/jp.pro @@ -23,3 +23,5 @@ unix { target.path += $$[QT_INSTALL_PLUGINS]/codecs INSTALLS += target + +symbian:TARGET.UID3=0x2001E614 diff --git a/src/plugins/codecs/kr/kr.pro b/src/plugins/codecs/kr/kr.pro index 9199e33..1cc28d8 100644 --- a/src/plugins/codecs/kr/kr.pro +++ b/src/plugins/codecs/kr/kr.pro @@ -16,3 +16,5 @@ wince*: { target.path += $$[QT_INSTALL_PLUGINS]/codecs INSTALLS += target + +symbian:TARGET.UID3=0x2001B2E5 diff --git a/src/plugins/codecs/tw/tw.pro b/src/plugins/codecs/tw/tw.pro index 8039f4b..2ebb94f 100644 --- a/src/plugins/codecs/tw/tw.pro +++ b/src/plugins/codecs/tw/tw.pro @@ -12,3 +12,5 @@ SOURCES = qbig5codec.cpp \ target.path += $$[QT_INSTALL_PLUGINS]/codecs INSTALLS += target + +symbian:TARGET.UID3=0x2001B2E4 diff --git a/src/plugins/iconengines/svgiconengine/svgiconengine.pro b/src/plugins/iconengines/svgiconengine/svgiconengine.pro index 2e105ee..5c5a31e 100644 --- a/src/plugins/iconengines/svgiconengine/svgiconengine.pro +++ b/src/plugins/iconengines/svgiconengine/svgiconengine.pro @@ -9,3 +9,5 @@ QT += xml svg QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/iconengines target.path += $$[QT_INSTALL_PLUGINS]/iconengines INSTALLS += target + +symbian:TARGET.UID3=0x2001B2E3 diff --git a/src/plugins/imageformats/gif/gif.pro b/src/plugins/imageformats/gif/gif.pro index 74586b2..8a5c51a 100644 --- a/src/plugins/imageformats/gif/gif.pro +++ b/src/plugins/imageformats/gif/gif.pro @@ -8,3 +8,5 @@ SOURCES += main.cpp \ QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/imageformats target.path += $$[QT_INSTALL_PLUGINS]/imageformats INSTALLS += target + +symbian:TARGET.UID3=0x2001E61A diff --git a/src/plugins/imageformats/ico/ico.pro b/src/plugins/imageformats/ico/ico.pro index 73665cd..eadff41 100644 --- a/src/plugins/imageformats/ico/ico.pro +++ b/src/plugins/imageformats/ico/ico.pro @@ -10,3 +10,5 @@ SOURCES += main.cpp \ QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/imageformats target.path += $$[QT_INSTALL_PLUGINS]/imageformats INSTALLS += target + +symbian:TARGET.UID3=0x2001E616 diff --git a/src/plugins/imageformats/jpeg/jpeg.pro b/src/plugins/imageformats/jpeg/jpeg.pro index f310902..e2e1a66 100644 --- a/src/plugins/imageformats/jpeg/jpeg.pro +++ b/src/plugins/imageformats/jpeg/jpeg.pro @@ -71,3 +71,5 @@ contains(QT_CONFIG, system-jpeg) { QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/imageformats target.path += $$[QT_INSTALL_PLUGINS]/imageformats INSTALLS += target + +symbian:TARGET.UID3=0x2001E61B diff --git a/src/plugins/imageformats/mng/mng.pro b/src/plugins/imageformats/mng/mng.pro index f0943f5..35cb47a 100644 --- a/src/plugins/imageformats/mng/mng.pro +++ b/src/plugins/imageformats/mng/mng.pro @@ -47,3 +47,5 @@ contains(QT_CONFIG, system-zlib) { QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/imageformats target.path += $$[QT_INSTALL_PLUGINS]/imageformats INSTALLS += target + +symbian:TARGET.UID3=0x2001E619 diff --git a/src/plugins/imageformats/svg/svg.pro b/src/plugins/imageformats/svg/svg.pro index 747d556..bcf4c21 100644 --- a/src/plugins/imageformats/svg/svg.pro +++ b/src/plugins/imageformats/svg/svg.pro @@ -9,3 +9,5 @@ QT += xml svg QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/imageformats target.path += $$[QT_INSTALL_PLUGINS]/imageformats INSTALLS += target + +symbian:TARGET.UID3=0x2001E618 diff --git a/src/plugins/imageformats/tiff/tiff.pro b/src/plugins/imageformats/tiff/tiff.pro index 8930cf3..312f99c 100644 --- a/src/plugins/imageformats/tiff/tiff.pro +++ b/src/plugins/imageformats/tiff/tiff.pro @@ -56,6 +56,9 @@ contains(QT_CONFIG, system-tiff) { wince*: { SOURCES += ../../../corelib/kernel/qfunctions_wince.cpp } + symbian*: { + SOURCES += ../../../3rdparty/libtiff/port/lfind.c + } } contains(QT_CONFIG, system-zlib) { @@ -68,3 +71,5 @@ contains(QT_CONFIG, system-zlib) { QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/imageformats target.path += $$[QT_INSTALL_PLUGINS]/imageformats INSTALLS += target + +symbian:TARGET.UID3=0x2001E617 diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index cf4edf1..c08056e 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -10,3 +10,4 @@ unix { embedded:SUBDIRS *= gfxdrivers decorations mousedrivers kbddrivers !win32:!embedded:!mac:SUBDIRS *= inputmethods contains(QT_CONFIG, phonon): SUBDIRS *= phonon +symbian:SUBDIRS = imageformats codecs iconengines s60 sqldrivers diff --git a/src/plugins/qpluginbase.pri b/src/plugins/qpluginbase.pri index ae39021..47ad4a1 100644 --- a/src/plugins/qpluginbase.pri +++ b/src/plugins/qpluginbase.pri @@ -13,3 +13,8 @@ contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols include(../qt_targets.pri) wince*:LIBS += $$QMAKE_LIBS_GUI + +symbian: { + TARGET.EPOCALLOWDLLDATA=1 + TARGET.CAPABILITY = All -Tcb +} diff --git a/src/plugins/s60/3_1/3_1.pro b/src/plugins/s60/3_1/3_1.pro new file mode 100644 index 0000000..568a33c --- /dev/null +++ b/src/plugins/s60/3_1/3_1.pro @@ -0,0 +1,8 @@ +include(../s60pluginbase.pri) + +TARGET = qts60plugin_3_1 + +SOURCES += ../src/qlocale_3_1.cpp \ + ../src/qdesktopservices_3_1.cpp + +TARGET.UID3=0x2001E620 diff --git a/src/plugins/s60/3_2/3_2.pro b/src/plugins/s60/3_2/3_2.pro new file mode 100644 index 0000000..97409d3 --- /dev/null +++ b/src/plugins/s60/3_2/3_2.pro @@ -0,0 +1,15 @@ +include(../s60pluginbase.pri) + +TARGET = qts60plugin_3_2 + +contains(S60_VERSION, 3.1) { + SOURCES += ../src/qlocale_3_1.cpp \ + ../src/qdesktopservices_3_1.cpp +} else { + SOURCES += ../src/qlocale_3_2.cpp \ + ../src/qdesktopservices_3_2.cpp + LIBS += -ldirectorylocalizer + INCLUDEPATH += $$APP_LAYER_SYSTEMINCLUDE +} + +TARGET.UID3=0x2001E621 diff --git a/src/plugins/s60/5_0/5_0.pro b/src/plugins/s60/5_0/5_0.pro new file mode 100644 index 0000000..878a466 --- /dev/null +++ b/src/plugins/s60/5_0/5_0.pro @@ -0,0 +1,15 @@ +include(../s60pluginbase.pri) + +TARGET = qts60plugin_5_0 + +contains(S60_VERSION, 3.1) { + SOURCES += ../src/qlocale_3_1.cpp \ + ../src/qdesktopservices_3_1.cpp +} else { + SOURCES += ../src/qlocale_3_2.cpp \ + ../src/qdesktopservices_3_2.cpp + LIBS += -ldirectorylocalizer + INCLUDEPATH += $$APP_LAYER_SYSTEMINCLUDE +} + +TARGET.UID3=0x2001E622 diff --git a/src/plugins/s60/bwins/qts60pluginu.def b/src/plugins/s60/bwins/qts60pluginu.def new file mode 100644 index 0000000..549f71f --- /dev/null +++ b/src/plugins/s60/bwins/qts60pluginu.def @@ -0,0 +1,7 @@ +EXPORTS + ?defaultFormatL@@YAXAAVTTime@@AAVTDes16@@ABVTDesC16@@ABVTLocale@@@Z @ 1 NONAME ; void defaultFormatL(class TTime &, class TDes16 &, class TDesC16 const &, class TLocale const &) + ?defaultGetTimeFormatSpec@@YA?AVTPtrC16@@AAVTExtendedLocale@@@Z @ 2 NONAME ; class TPtrC16 defaultGetTimeFormatSpec(class TExtendedLocale &) + ?defaultGetLongDateFormatSpec@@YA?AVTPtrC16@@AAVTExtendedLocale@@@Z @ 3 NONAME ; class TPtrC16 defaultGetLongDateFormatSpec(class TExtendedLocale &) + ?defaultGetShortDateFormatSpec@@YA?AVTPtrC16@@AAVTExtendedLocale@@@Z @ 4 NONAME ; class TPtrC16 defaultGetShortDateFormatSpec(class TExtendedLocale &) + ?localizedDirectoryName@@YA?AVQString@@AAV1@@Z @ 5 NONAME ; class QString localizedDirectoryName(class QString &) + diff --git a/src/plugins/s60/eabi/qts60pluginu.def b/src/plugins/s60/eabi/qts60pluginu.def new file mode 100644 index 0000000..a433a5d --- /dev/null +++ b/src/plugins/s60/eabi/qts60pluginu.def @@ -0,0 +1,7 @@ +EXPORTS + _Z14defaultFormatLR5TTimeR6TDes16RK7TDesC16RK7TLocale @ 1 NONAME + _Z24defaultGetTimeFormatSpecR15TExtendedLocale @ 2 NONAME + _Z28defaultGetLongDateFormatSpecR15TExtendedLocale @ 3 NONAME + _Z29defaultGetShortDateFormatSpecR15TExtendedLocale @ 4 NONAME + _Z22localizedDirectoryNameR7QString @ 5 NONAME + diff --git a/src/plugins/s60/s60.pro b/src/plugins/s60/s60.pro new file mode 100644 index 0000000..8ae639c --- /dev/null +++ b/src/plugins/s60/s60.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs + +symbian:SUBDIRS = 3_1 3_2 5_0 diff --git a/src/plugins/s60/s60pluginbase.pri b/src/plugins/s60/s60pluginbase.pri new file mode 100644 index 0000000..62100f9 --- /dev/null +++ b/src/plugins/s60/s60pluginbase.pri @@ -0,0 +1,15 @@ +# Note: These version based 'plugins' are not an actual Qt plugins, +# they are just regular runtime loaded libraries +include(../../qpluginbase.pri) + +CONFIG -= plugin +MMP_RULES -= EXPORTUNFROZEN + +defBlock = \ + "$${LITERAL_HASH}ifdef WINSCW" \ + "DEFFILE ../bwins/qts60plugin.def" \ + "$${LITERAL_HASH}else" \ + "DEFFILE ../eabi/qts60plugin.def" \ + "$${LITERAL_HASH}endif" + +MMP_RULES += defBlock
\ No newline at end of file diff --git a/src/plugins/s60/src/qdesktopservices_3_1.cpp b/src/plugins/s60/src/qdesktopservices_3_1.cpp new file mode 100644 index 0000000..0551a74 --- /dev/null +++ b/src/plugins/s60/src/qdesktopservices_3_1.cpp @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qglobal.h> +#include <qstring.h> + +EXPORT_C QString localizedDirectoryName(QString&) +{ + qWarning("QDesktopServices::displayName() not implemented for this platform version"); + return QString(); +} + diff --git a/src/plugins/s60/src/qdesktopservices_3_2.cpp b/src/plugins/s60/src/qdesktopservices_3_2.cpp new file mode 100644 index 0000000..7695f00 --- /dev/null +++ b/src/plugins/s60/src/qdesktopservices_3_2.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <private/qcore_symbian_p.h> +#include <qstring.h> +#include <qdir.h> + +#include <e32base.h> // CBase -> Required by cdirectorylocalizer.h +#include <cdirectorylocalizer.h> // CDirectoryLocalizer + +EXPORT_C QString localizedDirectoryName(QString& rawPath) +{ + QString ret; + + TRAPD(err, + CDirectoryLocalizer* localizer = CDirectoryLocalizer::NewL(); + CleanupStack::PushL(localizer); + localizer->SetFullPath(qt_QString2TPtrC(QDir::toNativeSeparators(rawPath))); + if(localizer->IsLocalized()){ + TPtrC locName(localizer->LocalizedName()); + ret = qt_TDesC2QStringL(locName); + } + CleanupStack::PopAndDestroy(localizer); + ) + + if (err != KErrNone) + ret = QString(); + + return ret; +} + diff --git a/src/plugins/s60/src/qlocale_3_1.cpp b/src/plugins/s60/src/qlocale_3_1.cpp new file mode 100644 index 0000000..b2e6a5d --- /dev/null +++ b/src/plugins/s60/src/qlocale_3_1.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <e32std.h> + +EXPORT_C void defaultFormatL(TTime&, TDes& des, const TDesC&, const TLocale&) +{ + des.Zero(); +} + +EXPORT_C TPtrC defaultGetTimeFormatSpec(TExtendedLocale&) +{ + return TPtrC(KNullDesC); +} + +EXPORT_C TPtrC defaultGetLongDateFormatSpec(TExtendedLocale&) +{ + return TPtrC(KNullDesC); +} + +EXPORT_C TPtrC defaultGetShortDateFormatSpec(TExtendedLocale&) +{ + return TPtrC(KNullDesC); +} diff --git a/src/plugins/s60/src/qlocale_3_2.cpp b/src/plugins/s60/src/qlocale_3_2.cpp new file mode 100644 index 0000000..ab3040b --- /dev/null +++ b/src/plugins/s60/src/qlocale_3_2.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <e32std.h> +#include <e32base.h> + +EXPORT_C TPtrC defaultGetLongDateFormatSpec(TExtendedLocale& locale) +{ + return locale.GetLongDateFormatSpec(); +} + +EXPORT_C TPtrC defaultGetShortDateFormatSpec(TExtendedLocale& locale) +{ + return locale.GetShortDateFormatSpec(); +} + +EXPORT_C TPtrC defaultGetTimeFormatSpec(TExtendedLocale& locale) +{ + return locale.GetTimeFormatSpec(); +} + +EXPORT_C void defaultFormatL(TTime& time, TDes& des, const TDesC& format, const TLocale& locale) +{ + time.FormatL(des, format, locale); +} diff --git a/src/plugins/sqldrivers/sqldrivers.pro b/src/plugins/sqldrivers/sqldrivers.pro index 39c58d4..2bd5f2c 100644 --- a/src/plugins/sqldrivers/sqldrivers.pro +++ b/src/plugins/sqldrivers/sqldrivers.pro @@ -9,3 +9,7 @@ contains(sql-plugins, db2) : SUBDIRS += db2 contains(sql-plugins, sqlite) : SUBDIRS += sqlite contains(sql-plugins, sqlite2) : SUBDIRS += sqlite2 contains(sql-plugins, ibase) : SUBDIRS += ibase + +contains(S60_VERSION, 3.1)|contains(S60_VERSION, 3.2)|contains(S60_VERSION, 5.0) { + symbian:contains(CONFIG, system-sqlite): SUBDIRS += sqlite_symbian + } diff --git a/src/plugins/sqldrivers/sqlite_symbian/SQLite3_v9.2.zip b/src/plugins/sqldrivers/sqlite_symbian/SQLite3_v9.2.zip Binary files differnew file mode 100644 index 0000000..923cca4 --- /dev/null +++ b/src/plugins/sqldrivers/sqlite_symbian/SQLite3_v9.2.zip diff --git a/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pro b/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pro new file mode 100644 index 0000000..0574341 --- /dev/null +++ b/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pro @@ -0,0 +1,6 @@ +# Use subdirs template to suppress generation of unnecessary files +TEMPLATE = subdirs + +# We just want to extract the zip file containing sqlite binaries for Symbian +BLD_INF_RULES.prj_exports += ":zip SQLite3_v9.2.zip" + diff --git a/src/qbase.pri b/src/qbase.pri index f7c8a95..d52120a 100644 --- a/src/qbase.pri +++ b/src/qbase.pri @@ -94,6 +94,12 @@ win32 { INCLUDEPATH += tmp !static: DEFINES+=QT_MAKEDLL } +symbian { + !static { + DEFINES+=QT_MAKEDLL + TARGET.CAPABILITY = All -Tcb + } +} win32-borland:INCLUDEPATH += kernel aix-g++* { @@ -115,7 +121,7 @@ embedded:DEPENDPATH += ;$$EMBEDDED_H #install directives include(qt_install.pri) -unix { +unix:!symbian { CONFIG += create_libtool create_pc explicitlib QMAKE_LIBTOOL_LIBDIR = $$[QT_INSTALL_LIBS] QMAKE_PRL_LIBDIR = $$[QT_INSTALL_LIBS] diff --git a/src/s60installs/qt.iby b/src/s60installs/qt.iby new file mode 100644 index 0000000..dc702f9 --- /dev/null +++ b/src/s60installs/qt.iby @@ -0,0 +1,94 @@ +#ifndef QT_IBY +#define QT_IBY + +#include <bldvariant.hrh> + +// Dependancies for more than one module +#include <base.iby> +#include <openenv.iby> // QtCore, QtGui, QtNetwork, QtOpenGL, QSvgIconEngine, +#include <cone.iby> // QtGui, QtOpenGL + +// QtGui dependancies +#include <bafl.iby> +#include <store.iby> +#include <fntstore.iby> +#include <ecom.iby> +#include <fontutils.iby> +#include <fepbase.iby> +#include <fbserv.iby> +#include <bitgdi.iby> +#include <gdi.iby> +#include <wserv.iby> +#include <apparc.iby> +#include <uikon.iby> +#include <etext.iby> +#include <emime.iby> +#include <eikstd.iby> +#include <mmf.iby> +#include <avkon.iby> +#include <commonui.iby> +#include <platformenv.iby> +#include <senduiservices.iby> +#include <aknicon.iby> +#include <aknskins.iby> + +// QtNetwork dependancies +#include <esock_core.iby> +#include <insock.iby> + +// QtOpenGL dependancies +///@todo Problem here as we need libegl.dll and libglesv2.dll but they may come from a variety of places +/// depending on the platform we're on + +#warning("qt.iby: hack - BINARY_SELECTION_ORDER really needs to be at the baseport/device level as it depends on the device type"); +BINARY_SELECTION_ORDER ARMV6,ARMV5 // hack - this really needs to be at the baseport/device level as it depends on the device type + +file=ABI_DIR\BUILD_DIR\QtCore.dll SHARED_LIB_DIR\QtCore.dll PAGED +file=ABI_DIR\BUILD_DIR\QtGui.dll SHARED_LIB_DIR\QtGui.dll PAGED +file=ABI_DIR\BUILD_DIR\QtOpenGL.dll SHARED_LIB_DIR\QtOpenGL.dll PAGED +file=ABI_DIR\BUILD_DIR\QtSvg.dll SHARED_LIB_DIR\QtSvg.dll PAGED +file=ABI_DIR\BUILD_DIR\QtXml.dll SHARED_LIB_DIR\QtXml.dll PAGED +file=ABI_DIR\BUILD_DIR\QtNetwork.dll SHARED_LIB_DIR\QtNetwork.dll PAGED +file=ABI_DIR\BUILD_DIR\QtScript.dll SHARED_LIB_DIR\QtScript.dll PAGED +file=ABI_DIR\BUILD_DIR\QtTest.dll SHARED_LIB_DIR\QtTest.dll PAGED + +// imageformats +file=ABI_DIR\BUILD_DIR\qgif.dll SHARED_LIB_DIR\qgif.dll PAGED +file=ABI_DIR\BUILD_DIR\qico.dll SHARED_LIB_DIR\qico.dll PAGED +file=ABI_DIR\BUILD_DIR\qjpeg.dll SHARED_LIB_DIR\qjpeg.dll PAGED +file=ABI_DIR\BUILD_DIR\qmng.dll SHARED_LIB_DIR\qmng.dll PAGED +file=ABI_DIR\BUILD_DIR\qsvg.dll SHARED_LIB_DIR\qsvg.dll PAGED +file=ABI_DIR\BUILD_DIR\qtiff.dll SHARED_LIB_DIR\qtiff.dll PAGED + +// codecs +file=ABI_DIR\BUILD_DIR\qcncodecs.dll SHARED_LIB_DIR\qcncodecs.dll PAGED +file=ABI_DIR\BUILD_DIR\qjpcodecs.dll SHARED_LIB_DIR\qjpcodecs.dll PAGED +file=ABI_DIR\BUILD_DIR\qkrcodecs.dll SHARED_LIB_DIR\qkrcodecs.dll PAGED +file=ABI_DIR\BUILD_DIR\qtwcodecs.dll SHARED_LIB_DIR\qtwcodecs.dll PAGED + +// iconengines +file=ABI_DIR\BUILD_DIR\qsvgicon.dll SHARED_LIB_DIR\qsvgicon.dll PAGED + +S60_APP_RESOURCE(s60main) + +// imageformats stubs +data=\epoc32\winscw\c\resource\qt\plugins\imageformats\qgif.qtplugin resource\qt\plugins\imageformats\qgif.qtplugin +data=\epoc32\winscw\c\resource\qt\plugins\imageformats\qico.qtplugin resource\qt\plugins\imageformats\qico.qtplugin +data=\epoc32\winscw\c\resource\qt\plugins\imageformats\qjpeg.qtplugin resource\qt\plugins\imageformats\qjpeg.qtplugin +data=\epoc32\winscw\c\resource\qt\plugins\imageformats\qmng.qtplugin resource\qt\plugins\imageformats\qmng.qtplugin +data=\epoc32\winscw\c\resource\qt\plugins\imageformats\qsvg.qtplugin resource\qt\plugins\imageformats\qsvg.qtplugin +data=\epoc32\winscw\c\resource\qt\plugins\imageformats\qtiff.qtplugin resource\qt\plugins\imageformats\qtiff.qtplugin + +// codecs stubs +data=\epoc32\winscw\c\resource\qt\plugins\codecs\qcncodecs.qtplugin resource\qt\plugins\codecs\qcncodecs.qtplugin +data=\epoc32\winscw\c\resource\qt\plugins\codecs\qjpcodecs.qtplugin resource\qt\plugins\codecs\qjpcodecs.qtplugin +data=\epoc32\winscw\c\resource\qt\plugins\codecs\qkrcodecs.qtplugin resource\qt\plugins\codecs\qkrcodecs.qtplugin +data=\epoc32\winscw\c\resource\qt\plugins\codecs\qtwcodecs.qtplugin resource\qt\plugins\codecs\qtwcodecs.qtplugin + +// iconengines stubs +data=\epoc32\winscw\c\resource\qt\plugins\iconengines\qsvgicon.qtplugin resource\qt\plugins\iconengines\qsvgicon.qtplugin + +// Stub sis file +data=ZSYSTEM\install\qt.sis System\Install\qt.sis + +#endif // __QT_IBY__ diff --git a/src/s60installs/qt_libs.pro b/src/s60installs/qt_libs.pro new file mode 100644 index 0000000..9aadfc0 --- /dev/null +++ b/src/s60installs/qt_libs.pro @@ -0,0 +1,75 @@ +# Use subdirs template to suppress generation of unnecessary files +TEMPLATE = subdirs + +symbian: { + load(data_caging_paths) + + SUBDIRS= + TARGET = "QtLibs pre-release" + TARGET.UID3 = 0x2001E61C + VERSION=$${QT_MAJOR_VERSION}.$${QT_MINOR_VERSION}.$${QT_PATCH_VERSION} + + qtresources.sources = $${EPOCROOT}$$HW_ZDIR$$APP_RESOURCE_DIR/s60main.rsc + qtresources.path = $$APP_RESOURCE_DIR + + qtlibraries.sources = \ + QtCore.dll \ + QtXml.dll \ + QtGui.dll \ + QtNetwork.dll \ + QtScript.dll \ + QtTest.dll \ + QtSql.dll \ + qts60plugin_3_1.dll \ + qts60plugin_3_2.dll \ + qts60plugin_5_0.dll + + + # TODO: This should be conditional in PKG file, see commented code below + # However we don't yet have such mechanism in place + contains(S60_VERSION, 3.1)|contains(S60_VERSION, 3.2)|contains(S60_VERSION, 5.0) { + contains(CONFIG, system-sqlite): qtlibraries.sources += sqlite3.dll + } + + #; EXISTS statement does not resolve !. Lets check the most common drives + #IF NOT EXISTS("c:\sys\bin\sqlite3.dll") AND NOT EXISTS("e:\sys\bin\sqlite3.dll") AND NOT EXISTS("z:\sys\bin\sqlite3.dll") + #"\Epoc32\release\armv5\UREL\sqlite3.dll"-"!:\sys\bin\sqlite3.dll" + #ENDIF + + qtlibraries.path = /sys/bin + qtlibraries.depends = "(0x20013851), 1, 5, 1, {\"PIPS Installer\"}" + contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) { + qtlibraries.depends += "(0x200110CB), 1, 5, 1, {\"Open C LIBSSL Common\"}" + } + contains(QT_CONFIG, stl) { + qtlibraries.depends += "(0x2000F866), 1, 0, 0, {\"Standard C++ Library Common\"}" + } + + !contains(QT_CONFIG, no-jpeg): imageformats_plugins.sources += qjpeg.dll + !contains(QT_CONFIG, no-gif): imageformats_plugins.sources += qgif.dll + !contains(QT_CONFIG, no-mng): imageformats_plugins.sources += qmng.dll + !contains(QT_CONFIG, no-tiff): imageformats_plugins.sources += qtiff.dll + !contains(QT_CONFIG, no-ico): imageformats_plugins.sources += qico.dll + imageformats_plugins.path = $$QT_PLUGINS_BASE_DIR/imageformats + + codecs_plugins.sources = qcncodecs.dll qjpcodecs.dll qtwcodecs.dll qkrcodecs.dll + codecs_plugins.path = $$QT_PLUGINS_BASE_DIR/codecs + + DEPLOYMENT += qtresources qtlibraries imageformats_plugins codecs_plugins + + contains(QT_CONFIG, svg): { + qtlibraries.sources += QtSvg.dll + imageformats_plugins.sources += qsvg.dll + iconengines_plugins.sources = qsvgicon.dll + iconengines_plugins.path = $$QT_PLUGINS_BASE_DIR/iconengines + DEPLOYMENT += iconengines_plugins + } + + contains(QT_CONFIG, phonon): { + qtlibraries.sources += Phonon.dll + } + + BLD_INF_RULES.prj_exports += "qt.iby $$CORE_MW_LAYER_IBY_EXPORT_PATH(qt.iby)" + BLD_INF_RULES.prj_exports += "qtvggraphicssystem.iby $$CORE_MW_LAYER_IBY_EXPORT_PATH(qtvggraphicssystem.iby)" + BLD_INF_RULES.prj_exports += "qtdemoapps.iby $$CORE_APP_LAYER_IBY_EXPORT_PATH(qtdemoapps.iby)" +} diff --git a/src/s60installs/qtdemoapps.iby b/src/s60installs/qtdemoapps.iby new file mode 100644 index 0000000..d888135 --- /dev/null +++ b/src/s60installs/qtdemoapps.iby @@ -0,0 +1,15 @@ +#ifndef QTDEMOAPPS_IBY +#define QTDEMOAPPS_IBY + +// A subset of Qt demo & example applications + +// Note that star requires OpenVG and the Qt OpenVG paint engine +S60_APP_EXE(star) +S60_APP_RESOURCE(star) +data=\epoc32\data\Z\private\10003a3f\import\Apps\star_reg.rsc \private\10003a3f\import\apps\star_reg.rsc + +S60_APP_EXE(wiggly) +S60_APP_RESOURCE(wiggly) +data=\epoc32\data\Z\private\10003a3f\import\Apps\wiggly_reg.rsc \private\10003a3f\import\apps\wiggly_reg.rsc + +#endif // QTDEMOAPPS_IBY diff --git a/src/s60installs/qtvggraphicssystem.iby b/src/s60installs/qtvggraphicssystem.iby new file mode 100644 index 0000000..6aec404 --- /dev/null +++ b/src/s60installs/qtvggraphicssystem.iby @@ -0,0 +1,9 @@ +#ifndef QTVGGRAPHICSSYSTEM_IBY +#define QTVGGRAPHICSSYSTEM_IBY + +#include <qt.iby> + +file=ABI_DIR\BUILD_DIR\qvggraphicssystem.dll qvggraphicssystem.dll +data=\epoc32\winscw\c\resource\qt\plugins\graphicssystems\qvggraphicssystem.qtplugin resource\qt\plugins\graphicssystems\qvggraphicssystem.qtplugin + +#endif // QTVGGRAPHICSSYSTEM_IBY diff --git a/src/s60main/qts60main.cpp b/src/s60main/qts60main.cpp new file mode 100644 index 0000000..965c02b --- /dev/null +++ b/src/s60main/qts60main.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// INCLUDE FILES +#include <eikstart.h> +#include "qts60mainapplication.h" + +/** + * factory function to create the QtS60Main application class + */ +LOCAL_C CApaApplication* NewApplication() + { + return new CQtS60MainApplication; + } + +/** + * A normal Symbian OS executable provides an E32Main() function which is + * called by the operating system to start the program. + */ +GLDEF_C TInt E32Main() + { + return EikStart::RunApplication( NewApplication ); + } + diff --git a/src/s60main/qts60main_mcrt0.cpp b/src/s60main/qts60main_mcrt0.cpp new file mode 100644 index 0000000..b7bf1a3 --- /dev/null +++ b/src/s60main/qts60main_mcrt0.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// MCRT0.CPP +// +// © Portions copyright (c) 2005-2006 Nokia Corporation. All rights reserved. +// Copyright (c) Symbian Software Ltd 1997-2004. All rights reserved. +// + +// EPOC32 version of crt0.c for C programs which always want multi-threaded support + +#include <e32std.h> +#include <e32base.h> +#include "estlib.h" + +#ifdef __ARMCC__ +__asm int CallMain(int argc, char *argv[], char *envp[]) +{ + import main + code32 + b main +} +#define CALLMAIN(argc, argv, envp) CallMain(argc, argv, envp) +#else +extern "C" int main (int argc, char *argv[], char *envp[]); +#define CALLMAIN(argc, argv, envp) main(argc, argv, envp) +#endif + +// Dummy function to handle GCCE toolchain problem +extern "C" GLDEF_C int __GccGlueInit() +{ + return 0; +} + +extern "C" IMPORT_C void exit (int ret); + +GLDEF_C TInt QtMainWrapper() +{ + int argc=0; + char **argv=0; + char **envp=0; + // get args & environment + __crt0(argc,argv,envp); + CleanupArrayDelete<char*>::PushL(argv); + CleanupArrayDelete<char*>::PushL(envp); + //Call user(application)'s main + int ret = CALLMAIN(argc,argv,envp); + CleanupStack::PopAndDestroy(2,argv); + return ret; +} + + +#ifdef __GCC32__ + +/* stub function inserted into main() by GCC */ +extern "C" void __gccmain (void) {} + +/* Default GCC entrypoint */ +extern "C" TInt _mainCRTStartup (void) +{ + extern TInt _E32Startup(); + return _E32Startup(); +} + +#endif /* __GCC32__ */ + +#ifdef __EABI__ + +// standard entrypoint for C runtime, expected by some linkers +// Symbian OS does not currently use this function +extern "C" void __main() {} +#endif diff --git a/src/s60main/qts60mainapplication.cpp b/src/s60main/qts60mainapplication.cpp new file mode 100644 index 0000000..680243f --- /dev/null +++ b/src/s60main/qts60mainapplication.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// INCLUDE FILES +#include "qts60maindocument.h" +#include "qts60mainapplication.h" +#include <bautils.h> +#include <coemain.h> + +// ============================ MEMBER FUNCTIONS =============================== + + +_LIT( KQtWrapperResourceFile,"\\resource\\apps\\s60main.rsc" ); + +// ----------------------------------------------------------------------------- +// CQtS60MainApplication::CreateDocumentL() +// Creates CApaDocument object +// ----------------------------------------------------------------------------- +// +CApaDocument* CQtS60MainApplication::CreateDocumentL() + { + // Create an QtS60Main document, and return a pointer to it + return (static_cast<CApaDocument*>( CQtS60MainDocument::NewL( *this ) ) ); + } + +// ----------------------------------------------------------------------------- +// CQtS60MainApplication::AppDllUid() +// Returns application UID +// ----------------------------------------------------------------------------- +// +TUid CQtS60MainApplication::AppDllUid() const + { + // Return the UID for the QtS60Main application + return ProcessUid(); + } + +// ----------------------------------------------------------------------------- +// CQtS60MainApplication::ResourceFileName() +// Returns application resource filename +// ----------------------------------------------------------------------------- +// +TFileName CQtS60MainApplication::ResourceFileName() const + { + TFindFile finder(iCoeEnv->FsSession()); + TInt err = finder.FindByDir(KQtWrapperResourceFile, KNullDesC); + if (err == KErrNone) + return finder.File(); + return KNullDesC(); + } + + +// End of File + diff --git a/src/s60main/qts60mainapplication.h b/src/s60main/qts60mainapplication.h new file mode 100644 index 0000000..70b6909 --- /dev/null +++ b/src/s60main/qts60mainapplication.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef __QtS60MainAPPLICATION_H__ +#define __QtS60MainAPPLICATION_H__ + +// INCLUDES +#include <aknapp.h> + +// CLASS DECLARATION + +static TUid ProcessUid() + { + RProcess me; + TSecureId securId = me.SecureId(); + me.Close(); + return securId.operator TUid(); + } + +/** +* CQtS60MainApplication application class. +* Provides factory to create concrete document object. +* An instance of CQtS60MainApplication is the application part of the +* AVKON application framework for the QtS60Main example application. +*/ +class CQtS60MainApplication : public CAknApplication + { + public: // Functions from base classes + + /** + * From CApaApplication, AppDllUid. + * @return Application's UID (KUidQtS60MainApp). + */ + TUid AppDllUid() const; + + /** + * From CApaApplication, ResourceFileName + * @return Application's resource filename (KUidQtS60MainApp). + */ + TFileName ResourceFileName() const; + + protected: // Functions from base classes + + /** + * From CApaApplication, CreateDocumentL. + * Creates CQtS60MainDocument document object. The returned + * pointer in not owned by the CQtS60MainApplication object. + * @return A pointer to the created document object. + */ + CApaDocument* CreateDocumentL(); + }; + +#endif // __QtS60MainAPPLICATION_H__ + +// End of File + diff --git a/src/s60main/qts60mainappui.cpp b/src/s60main/qts60mainappui.cpp new file mode 100644 index 0000000..47312af --- /dev/null +++ b/src/s60main/qts60mainappui.cpp @@ -0,0 +1,201 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// INCLUDE FILES +#include <avkon.hrh> +#include <eikmenub.h> +#include <eikmenup.h> +#include <barsread.h> +#include <s60main.rsg> +#include <avkon.rsg> + +#include "qts60mainappui.h" +#include <QtGui/qapplication.h> +#include <QtGui/qmenu.h> +#include <QtGui/private/qt_s60_p.h> + +// ============================ MEMBER FUNCTIONS =============================== + + +// ----------------------------------------------------------------------------- +// CQtS60MainAppUi::ConstructL() +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CQtS60MainAppUi::ConstructL() +{ + // Initialise app UI with standard value. + // ENoAppResourceFile and ENonStandardResourceFile makes UI to work without + // resource files in most SDKs. S60 3rd FP1 public seems to require resource file + // even these flags are defined + BaseConstructL(CAknAppUi::EAknEnableSkin); + + // Create async callback to call Qt main, + // this is required to give S60 app FW to finish starting correctly + TCallBack callBack( OpenCMainStaticCallBack, this ); + iAsyncCallBack = new(ELeave) CAsyncCallBack( callBack, CActive::EPriorityIdle ); + iAsyncCallBack->Call(); +} + +// ----------------------------------------------------------------------------- +// CQtS60MainAppUi::CQtS60MainAppUi() +// C++ default constructor can NOT contain any code, that might leave. +// ----------------------------------------------------------------------------- +// +CQtS60MainAppUi::CQtS60MainAppUi() +{ + // No implementation required +} + +// ----------------------------------------------------------------------------- +// CQtS60MainAppUi::~CQtS60MainAppUi() +// Destructor. +// ----------------------------------------------------------------------------- +// +CQtS60MainAppUi::~CQtS60MainAppUi() +{ + delete iAsyncCallBack; +} + +// ----------------------------------------------------------------------------- +// CQtS60MainAppUi::HandleCommandL() +// Takes care of command handling. +// ----------------------------------------------------------------------------- +// +void CQtS60MainAppUi::HandleCommandL( TInt aCommand ) +{ + if (qApp) + qApp->symbianHandleCommand(aCommand); +} + +// ----------------------------------------------------------------------------- +// CQtS60MainAppUi::HandleResourceChangeL() +// Takes care of event handling. +// ----------------------------------------------------------------------------- +// +void CQtS60MainAppUi::HandleResourceChangeL(TInt aType) +{ + CAknAppUi::HandleResourceChangeL(aType); + + if (qApp) + qApp->symbianResourceChange(aType); +} + +void CQtS60MainAppUi::HandleWsEventL(const TWsEvent& aEvent, CCoeControl *control) +{ + int result = 0; + if (qApp) + result = qApp->s60ProcessEvent(const_cast<TWsEvent*>(&aEvent)); + + if (result <= 0) + CAknAppUi::HandleWsEventL(aEvent, control); +} + + +// ----------------------------------------------------------------------------- +// Called by the framework when the application status pane +// size is changed. Passes the new client rectangle to the +// AppView +// ----------------------------------------------------------------------------- +// +void CQtS60MainAppUi::HandleStatusPaneSizeChange() +{ + HandleResourceChangeL(KInternalStatusPaneChange); + HandleStackedControlsResourceChange(KInternalStatusPaneChange); +} + +// ----------------------------------------------------------------------------- +// Called asynchronously from ConstructL() - passes call to nan static method +// ----------------------------------------------------------------------------- +// +TInt CQtS60MainAppUi::OpenCMainStaticCallBack( TAny* aObject ) +{ + CQtS60MainAppUi* myObj = static_cast<CQtS60MainAppUi*>( aObject ); + myObj->OpenCMainCallBack(); + return 0; +} + +#include "qtS60main_mcrt0.cpp" + +// ----------------------------------------------------------------------------- +// Invokes Qt main, the Qt main will block and when we return from there +// application should be closed. -> Call Exit(); +// ----------------------------------------------------------------------------- +// +void CQtS60MainAppUi::OpenCMainCallBack() +{ + TInt ret = QtMainWrapper(); + Exit(); +} + +void CQtS60MainAppUi::DynInitMenuBarL(TInt, CEikMenuBar *) +{ +} + +void CQtS60MainAppUi::DynInitMenuPaneL(TInt aResourceId, CEikMenuPane *aMenuPane) +{ + if (aResourceId == R_QT_WRAPPERAPP_MENU){ + if (aMenuPane->NumberOfItemsInPane() <= 1) + qt_symbian_show_toplevel(aMenuPane); + + } + else if( aResourceId != R_AVKON_MENUPANE_FEP_DEFAULT && aResourceId != R_AVKON_MENUPANE_EDITTEXT_DEFAULT && aResourceId != R_AVKON_MENUPANE_LANGUAGE_DEFAULT ){ + qt_symbian_show_submenu(aMenuPane, aResourceId); + } +} + +void CQtS60MainAppUi::RestoreMenuL(CCoeControl* aMenuWindow,TInt aMenuId,TMenuType aMenuType) +{ + if ((aMenuId==R_QT_WRAPPERAPP_MENUBAR) || (aMenuId == R_AVKON_MENUPANE_FEP_DEFAULT)) { + TResourceReader reader; + iCoeEnv->CreateResourceReaderLC(reader,aMenuId); + aMenuWindow->ConstructFromResourceL(reader); + CleanupStack::PopAndDestroy(); + } + + if (aMenuType==EMenuPane) + DynInitMenuPaneL(aMenuId,(CEikMenuPane*)aMenuWindow); + else + DynInitMenuBarL(aMenuId,(CEikMenuBar*)aMenuWindow); + } + +// End of File + diff --git a/src/s60main/qts60mainappui.h b/src/s60main/qts60mainappui.h new file mode 100644 index 0000000..6bdeb2e --- /dev/null +++ b/src/s60main/qts60mainappui.h @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef __QtS60MainAPPUI_H__ +#define __QtS60MainAPPUI_H__ + +// INCLUDES +#include <aknappui.h> + +// FORWARD DECLARATIONS + +// CLASS DECLARATION +/** +* CQtS60MainAppUi application UI class. +* Interacts with the user through the UI and request message processing +* from the handler class +*/ +class CQtS60MainAppUi : public CAknAppUi + { + public: // Constructors and destructor + + /** + * ConstructL. + * 2nd phase constructor. + */ + void ConstructL(); + + /** + * CQtS60MainAppUi. + * C++ default constructor. This needs to be public due to + * the way the framework constructs the AppUi + */ + CQtS60MainAppUi(); + + /** + * ~CQtS60MainAppUi. + * Virtual Destructor. + */ + virtual ~CQtS60MainAppUi(); + + protected: + void RestoreMenuL(CCoeControl* aMenuWindow,TInt aMenuId,TMenuType aMenuType); + void DynInitMenuBarL(TInt aResourceId, CEikMenuBar *aMenuBar); + void DynInitMenuPaneL(TInt aResourceId, CEikMenuPane *aMenuPane); + + private: // Functions from base classes + + /** + * From CEikAppUi, HandleCommandL. + * Takes care of command handling. + * @param aCommand Command to be handled. + */ + void HandleCommandL( TInt aCommand ); + + /** + * From CAknAppUi, HandleResourceChangeL + * Handles resource change events such as layout switches in global level. + * @param aType event type. + */ + void HandleResourceChangeL(TInt aType); + + /** + * HandleStatusPaneSizeChange. + * Called by the framework when the application status pane + * size is changed. + */ + void HandleStatusPaneSizeChange(); + + /** + * Static callback method for invoking Qt main. + * Called asynchronously from ConstructL() - passes call to non static method. + */ + static TInt OpenCMainStaticCallBack( TAny* aObject ); + + /** + * Callback method for invoking Qt main. + * Called from static OpenCMainStaticCallBack. + */ + void OpenCMainCallBack(); + + protected: + void HandleWsEventL(const TWsEvent& aEvent, CCoeControl* aDestination); + + + private: // Data + + /** + * Async callback object to call Qt main + * Owned by CQtS60MainAppUi + */ + CAsyncCallBack* iAsyncCallBack; + + }; + +#endif // __QtS60MainAPPUI_H__ + +// End of File + diff --git a/src/s60main/qts60maindocument.cpp b/src/s60main/qts60maindocument.cpp new file mode 100644 index 0000000..b4a2e66 --- /dev/null +++ b/src/s60main/qts60maindocument.cpp @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// INCLUDE FILES +#include "qts60mainappui.h" +#include "qts60maindocument.h" + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CQtS60MainDocument::NewL() +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CQtS60MainDocument* CQtS60MainDocument::NewL( CEikApplication& aApp ) + { + CQtS60MainDocument* self = NewLC( aApp ); + CleanupStack::Pop( self ); + return self; + } + +// ----------------------------------------------------------------------------- +// CQtS60MainDocument::NewLC() +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CQtS60MainDocument* CQtS60MainDocument::NewLC( CEikApplication& aApp ) + { + CQtS60MainDocument* self = new ( ELeave ) CQtS60MainDocument( aApp ); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + +// ----------------------------------------------------------------------------- +// CQtS60MainDocument::ConstructL() +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CQtS60MainDocument::ConstructL() + { + // No implementation required + } + +// ----------------------------------------------------------------------------- +// CQtS60MainDocument::CQtS60MainDocument() +// C++ default constructor can NOT contain any code, that might leave. +// ----------------------------------------------------------------------------- +// +CQtS60MainDocument::CQtS60MainDocument( CEikApplication& aApp ) + : CAknDocument( aApp ) + { + // No implementation required + } + +// --------------------------------------------------------------------------- +// CQtS60MainDocument::~CQtS60MainDocument() +// Destructor. +// --------------------------------------------------------------------------- +// +CQtS60MainDocument::~CQtS60MainDocument() + { + // No implementation required + } + +// --------------------------------------------------------------------------- +// CQtS60MainDocument::CreateAppUiL() +// Constructs CreateAppUi. +// --------------------------------------------------------------------------- +// +CEikAppUi* CQtS60MainDocument::CreateAppUiL() + { + // Create the application user interface, and return a pointer to it; + // the framework takes ownership of this object + return ( static_cast <CEikAppUi*> ( new ( ELeave )CQtS60MainAppUi ) ); + } + +// End of File + diff --git a/src/s60main/qts60maindocument.h b/src/s60main/qts60maindocument.h new file mode 100644 index 0000000..a95e620 --- /dev/null +++ b/src/s60main/qts60maindocument.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef __QTS60MAINDOCUMENT_H__ +#define __QTS60MAINDOCUMENT_H__ + +// INCLUDES +#include <akndoc.h> + +// FORWARD DECLARATIONS +class CQtS60MainAppUi; +class CEikApplication; + + +// CLASS DECLARATION + +/** +* CQtS60MainDocument application class. +* An instance of class CQtS60MainDocument is the Document part of the +* AVKON application framework for the QtS60Main application. +*/ +class CQtS60MainDocument : public CAknDocument + { + public: // Constructors and destructor + + /** + * NewL. + * Two-phased constructor. + * Construct a CQtS60MainDocument for the AVKON application aApp + * using two phase construction, and return a pointer + * to the created object. + * @param aApp Application creating this document. + * @return A pointer to the created instance of CQtS60MainDocument. + */ + static CQtS60MainDocument* NewL( CEikApplication& aApp ); + + /** + * NewLC. + * Two-phased constructor. + * Construct a CQtS60MainDocument for the AVKON application aApp + * using two phase construction, and return a pointer + * to the created object. + * @param aApp Application creating this document. + * @return A pointer to the created instance of CQtS60MainDocument. + */ + static CQtS60MainDocument* NewLC( CEikApplication& aApp ); + + /** + * ~CQtS60MainDocument + * Virtual Destructor. + */ + virtual ~CQtS60MainDocument(); + + public: // Functions from base classes + + /** + * CreateAppUiL + * From CEikDocument, CreateAppUiL. + * Create a CQtS60MainAppUi object and return a pointer to it. + * The object returned is owned by the Uikon framework. + * @return Pointer to created instance of AppUi. + */ + CEikAppUi* CreateAppUiL(); + + private: // Constructors + + /** + * ConstructL + * 2nd phase constructor. + */ + void ConstructL(); + + /** + * CQtS60MainDocument. + * C++ default constructor. + * @param aApp Application creating this document. + */ + CQtS60MainDocument( CEikApplication& aApp ); + + }; + +#endif // __QTS60MAINDOCUMENT_H__ + +// End of File + diff --git a/src/s60main/s60main.pro b/src/s60main/s60main.pro new file mode 100644 index 0000000..f74943f --- /dev/null +++ b/src/s60main/s60main.pro @@ -0,0 +1,55 @@ +# Additional Qt project file for qtmain lib on Symbian +TEMPLATE = lib +TARGET = qtmain +DESTDIR = $$QMAKE_LIBDIR_QT +QT = + +CONFIG += staticlib warn_on +CONFIG -= qt shared + +symbian { + # Note: UID only needed for ensuring that no filename generation conflicts occur + TARGET.UID3 = 0x2001E61F + CONFIG += png zlib + CONFIG -= jpeg + INCLUDEPATH += tmp $$QMAKE_INCDIR_QT/QtCore $$MW_LAYER_SYSTEMINCLUDE + SOURCES = qts60main.cpp \ + qts60mainapplication.cpp \ + qts60mainappui.cpp \ + qts60maindocument.cpp + + HEADERS = qts60mainapplication.h \ + qts60mainappui.h \ + qts60maindocument.h + + # This block serves the minimalistic resource file for S60 3.1 platforms. + # Note there is no way to ifdef S60 version in mmp file, that is why the resource + # file is always compiled for WINSCW + minimalAppResource31 = \ + "START RESOURCE s60main.rss" \ + "HEADER" \ + "TARGETPATH resource\apps" \ + "END" + MMP_RULES += minimalAppResource31 + + # s60main needs to be built in ARM mode for GCCE to work. + MMP_RULES+="ALWAYS_BUILD_AS_ARM" + + # staticlib should not have any lib depencies in s60 + # This seems not to work, some hard coded libs are still added as dependency + LIBS = +} else { + error("$$_FILE_ is intended only for Symbian!") +} + +symbian-abld: { + # abld build commands generated resources after the static library is built, and + # we have dependency to resource from static lib -> resources need to be generated + # explicitly before library + rsgFix2.commands = "-$(DEL_FILE) $(EPOCROOT)Epoc32\Data\z\resource\apps\s60main.rsc >NUL 2>&1" + rsgFix.commands = "-$(ABLD) resource $(PLATFORM) $(CFG) 2>NUL" + QMAKE_EXTRA_TARGETS += rsgFix rsgFix2 + PRE_TARGETDEPS += rsgFix rsgFix2 +} + +include(../qbase.pri) diff --git a/src/s60main/s60main.rss b/src/s60main/s60main.rss new file mode 100644 index 0000000..6e8004c --- /dev/null +++ b/src/s60main/s60main.rss @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Even S60 application have ENoAppResourceFile and ENonStandardResourceFile +// flags set, the S60 3rd Edition FP1 emulator requires applications to have +// very minimalistic application resource file, otherwise apps refures to start +// This file serves the minimalistic resource file for S60 3.1 platforms. + +// RESOURCE IDENTIFIER +NAME QTMA // 4 letter ID + +// INCLUDES +//#include <eikon.rh> +#include <appinfo.rh> +#include <eikon.rh> +#include <avkon.rsg> +#include <avkon.rh> +#include <avkon.mbg> + +// RESOURCE DEFINITIONS +RESOURCE RSS_SIGNATURE + { + } + +RESOURCE TBUF r_default_document_name + { + buf="QTMA"; + } + +RESOURCE EIK_APP_INFO + { + menubar = r_qt_wrapperapp_menubar; + cba = R_AVKON_SOFTKEYS_EXIT; + } + +RESOURCE MENU_BAR r_qt_wrapperapp_menubar + { + titles = + { + MENU_TITLE { menu_pane = r_qt_wrapperapp_menu; } + }; + } + +RESOURCE MENU_PANE r_qt_wrapperapp_menu + { + } +// End of File + diff --git a/src/script/qscriptengine_p.cpp b/src/script/qscriptengine_p.cpp index a2e58de..27b8101 100644 --- a/src/script/qscriptengine_p.cpp +++ b/src/script/qscriptengine_p.cpp @@ -1706,6 +1706,8 @@ QScriptEnginePrivate::QScriptEnginePrivate() m_maxCallDepth = 640; #elif defined(QT_ARCH_ARM) || defined(QT_ARCH_ARMV6) m_maxCallDepth = 360; +#elif defined(Q_OS_SYMBIAN) + m_maxCallDepth = 128; //stack size limitation of 80k, has headroom for other stack vars. #else m_maxCallDepth = 512; #endif diff --git a/src/script/qscriptvalueimplfwd_p.h b/src/script/qscriptvalueimplfwd_p.h index 059842e..9c811bf 100644 --- a/src/script/qscriptvalueimplfwd_p.h +++ b/src/script/qscriptvalueimplfwd_p.h @@ -77,7 +77,7 @@ class QScriptEnginePrivate; namespace QScript { class Member; -}; +} class QScriptValueImpl { @@ -88,6 +88,17 @@ public: StringTypeHint }; + QScript::Type m_type; + union { + bool m_bool_value; + int m_int_value; + qsreal m_number_value; + void *m_ptr_value; + QScriptObject *m_object_value; + QScriptNameIdImpl *m_string_value; + QString *m_lazy_string_value; + }; + inline QScriptValueImpl(); inline QScriptValueImpl(QScriptValue::SpecialValue val); inline QScriptValueImpl(bool val); @@ -218,16 +229,6 @@ public: bool detectedCycle() const; - QScript::Type m_type; - union { - bool m_bool_value; - int m_int_value; - qsreal m_number_value; - void *m_ptr_value; - QScriptObject *m_object_value; - QScriptNameIdImpl *m_string_value; - QString *m_lazy_string_value; - }; }; QT_END_NAMESPACE diff --git a/src/script/script.pro b/src/script/script.pro index 9aa9bc2..4792527 100644 --- a/src/script/script.pro +++ b/src/script/script.pro @@ -10,3 +10,5 @@ unix:QMAKE_PKGCONFIG_REQUIRES = QtCore include(../qbase.pri) include(script.pri) + +symbian:TARGET.UID3=0x2001B2E1 diff --git a/src/scripttools/scripttools.pro b/src/scripttools/scripttools.pro index faf0936a..5878db2 100644 --- a/src/scripttools/scripttools.pro +++ b/src/scripttools/scripttools.pro @@ -10,3 +10,5 @@ unix:QMAKE_PKGCONFIG_REQUIRES = QtCore QtGui QtScript include(../qbase.pri) include(debugging/debugging.pri) + +symbian:TARGET.UID3=0x2001E625 diff --git a/src/sql/kernel/qsqlfield.cpp b/src/sql/kernel/qsqlfield.cpp index 8a808b6..4c1f1f4 100644 --- a/src/sql/kernel/qsqlfield.cpp +++ b/src/sql/kernel/qsqlfield.cpp @@ -159,11 +159,20 @@ public: \sa setRequiredStatus() setLength() setPrecision() setDefaultValue() setGenerated() setReadOnly() */ +QSqlField::QSqlField() +{ + d = new QSqlFieldPrivate(QString(), QVariant::Invalid); +} + +QSqlField::QSqlField(const QString& fieldName) +{ + d = new QSqlFieldPrivate(fieldName, QVariant::Invalid); +} + QSqlField::QSqlField(const QString& fieldName, QVariant::Type type) { d = new QSqlFieldPrivate(fieldName, type); } - /*! Constructs a copy of \a other. */ diff --git a/src/sql/kernel/qsqlfield.h b/src/sql/kernel/qsqlfield.h index 58b3616..a5bd8c4 100644 --- a/src/sql/kernel/qsqlfield.h +++ b/src/sql/kernel/qsqlfield.h @@ -58,9 +58,9 @@ class Q_SQL_EXPORT QSqlField public: enum RequiredStatus { Unknown = -1, Optional = 0, Required = 1 }; - QSqlField(const QString& fieldName = QString(), - QVariant::Type type = QVariant::Invalid); - + QSqlField(); + QSqlField(const QString& fieldName); + QSqlField(const QString& fieldName, QVariant::Type type); QSqlField(const QSqlField& other); QSqlField& operator=(const QSqlField& other); bool operator==(const QSqlField& other) const; diff --git a/src/sql/kernel/qsqlresult.cpp b/src/sql/kernel/qsqlresult.cpp index 180bfc7..cffc570 100644 --- a/src/sql/kernel/qsqlresult.cpp +++ b/src/sql/kernel/qsqlresult.cpp @@ -52,7 +52,9 @@ QT_BEGIN_NAMESPACE struct QHolder { - QHolder(const QString& hldr = QString(), int index = -1): holderName(hldr), holderPos(index) {} + QHolder(): holderName(QString()), holderPos(-1) {} + QHolder(const QString& hldr): holderName(hldr), holderPos(-1) {} + QHolder(const QString& hldr, int index): holderName(hldr), holderPos(index) {} bool operator==(const QHolder& h) const { return h.holderPos == holderPos && h.holderName == holderName; } bool operator!=(const QHolder& h) const { return h.holderPos != holderPos || h.holderName != holderName; } QString holderName; diff --git a/src/sql/sql.pro b/src/sql/sql.pro index 3cca4e0..60be748 100644 --- a/src/sql/sql.pro +++ b/src/sql/sql.pro @@ -17,3 +17,11 @@ include(kernel/kernel.pri) include(drivers/drivers.pri) include(models/models.pri) +symbian: { + TARGET.UID3=0x2001E61D + + # Workaroud for problems with paging this dll + MMP_RULES -= PAGED + MMP_RULES *= UNPAGED +} + diff --git a/src/src.pro b/src/src.pro index f40c6ad..f131e4f 100644 --- a/src/src.pro +++ b/src/src.pro @@ -5,6 +5,11 @@ unset(SRC_SUBDIRS) win32:SRC_SUBDIRS += src_winmain wince*:{ SRC_SUBDIRS += src_corelib src_xml src_gui src_sql src_network src_script src_testlib +} symbian { + SRC_SUBDIRS += src_s60main src_corelib src_xml src_gui src_network src_sql src_script src_testlib + contains(QT_CONFIG, svg): SRC_SUBDIRS += src_svg + SRC_SUBDIRS += src_plugins + SRC_SUBDIRS += $$QT_SOURCE_TREE/src/s60installs/qt_libs.pro } else { SRC_SUBDIRS += src_tools_bootstrap src_tools_moc src_tools_rcc src_tools_uic src_corelib src_xml src_network src_gui src_sql src_script src_testlib contains(QT_CONFIG, qt3support): SRC_SUBDIRS += src_qt3support @@ -18,9 +23,12 @@ win32:{ !wince*: SRC_SUBDIRS += src_tools_idc } +# TODO the following line should be between opengl and webkit when the 'symbian' block is removed +contains(QT_CONFIG, phonon): SRC_SUBDIRS += src_phonon + +!symbian { contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles2): SRC_SUBDIRS += src_opengl contains(QT_CONFIG, xmlpatterns): SRC_SUBDIRS += src_xmlpatterns -contains(QT_CONFIG, phonon): SRC_SUBDIRS += src_phonon contains(QT_CONFIG, svg): SRC_SUBDIRS += src_svg contains(QT_CONFIG, webkit) { #exists($$QT_SOURCE_TREE/src/3rdparty/webkit/JavaScriptCore/JavaScriptCore.pro): SRC_SUBDIRS += src_javascriptcore @@ -28,7 +36,10 @@ contains(QT_CONFIG, webkit) { } contains(QT_CONFIG, scripttools): SRC_SUBDIRS += src_scripttools SRC_SUBDIRS += src_plugins +} +src_s60main.subdir = $$QT_SOURCE_TREE/src/s60main +src_s60main.target = sub-s60main src_winmain.subdir = $$QT_SOURCE_TREE/src/winmain src_winmain.target = sub-winmain src_tools_bootstrap.subdir = $$QT_SOURCE_TREE/src/tools/bootstrap @@ -81,7 +92,7 @@ src_webkit.subdir = $$QT_SOURCE_TREE/src/3rdparty/webkit/WebCore src_webkit.target = sub-webkit #CONFIG += ordered -!wince*:!ordered { +!wince*:!symbian:!ordered { src_tools_moc.depends = src_tools_bootstrap src_tools_rcc.depends = src_tools_bootstrap src_tools_uic.depends = src_tools_bootstrap @@ -115,6 +126,7 @@ src_webkit.target = sub-webkit } } +!symbian { # This creates a sub-src rule sub_src_target.CONFIG = recursive sub_src_target.recurse = $$SRC_SUBDIRS @@ -163,6 +175,7 @@ for(subname, SRC_SUBDIRS) { debug.depends = $$EXTRA_DEBUG_TARGETS release.depends = $$EXTRA_RELEASE_TARGETS QMAKE_EXTRA_TARGETS += debug release +} SUBDIRS += $$SRC_SUBDIRS diff --git a/src/svg/svg.pro b/src/svg/svg.pro index aef0786..662940a 100644 --- a/src/svg/svg.pro +++ b/src/svg/svg.pro @@ -40,6 +40,8 @@ SOURCES += \ INCLUDEPATH += ../3rdparty/harfbuzz/src +symbian:TARGET.UID3=0x2001B2E2 + #zlib support contains(QT_CONFIG, zlib) { INCLUDEPATH += ../3rdparty/zlib diff --git a/src/testlib/3rdparty/cycle_p.h b/src/testlib/3rdparty/cycle_p.h index b4b6876..547fdc1 100644 --- a/src/testlib/3rdparty/cycle_p.h +++ b/src/testlib/3rdparty/cycle_p.h @@ -491,4 +491,21 @@ INLINE_ELAPSED(inline) #define HAVE_TICK_COUNTER #endif +/*----------------------------------------------------------------*/ +/* Symbian */ +#if defined(__SYMBIAN32__) && !defined(HAVE_TICK_COUNTER) +#include <e32std.h> + +typedef TUint32 CycleCounterTicks; + +static inline CycleCounterTicks getticks(void) +{ + return User::FastCounter(); +} + +INLINE_ELAPSED(inline) + +#define HAVE_TICK_COUNTER +#endif + #endif // QBENCHLIB_CYCLE_H diff --git a/src/testlib/qbenchmark.cpp b/src/testlib/qbenchmark.cpp index 7687fec..64594c1 100644 --- a/src/testlib/qbenchmark.cpp +++ b/src/testlib/qbenchmark.cpp @@ -219,6 +219,7 @@ void QTest::setIterationCountHint(int count) { QBenchmarkTestMethodData::current->adjustIterationCount(count); } + /*! \internal */ void QTest::setIterationCount(int count) diff --git a/src/testlib/qplaintestlogger.cpp b/src/testlib/qplaintestlogger.cpp index 6f10d72..c408c1c 100644 --- a/src/testlib/qplaintestlogger.cpp +++ b/src/testlib/qplaintestlogger.cpp @@ -54,6 +54,10 @@ #include "windows.h" #endif +#if defined(Q_OS_SYMBIAN) +#include <e32debug.h> +#endif + #ifdef Q_OS_WINCE #include <QtCore/QString> #endif @@ -159,6 +163,12 @@ namespace QTest { // OutputDebugString is not threadsafe OutputDebugStringA(str); LeaveCriticalSection(&outputCriticalSection); +#elif defined(Q_OS_SYMBIAN) + TPtrC8 ptr(reinterpret_cast<const TUint8*>(str)); + HBufC* hbuffer = HBufC::NewL(ptr.Length()); + hbuffer->Des().Copy(ptr); + RDebug::Print(_L("[QTestLib Message] %S"), hbuffer); + delete hbuffer; #endif QAbstractTestLogger::outputString(str); } diff --git a/src/testlib/qtest.h b/src/testlib/qtest.h index 6ea38f7..15319ce 100644 --- a/src/testlib/qtest.h +++ b/src/testlib/qtest.h @@ -226,10 +226,17 @@ int main(int argc, char *argv[]) \ #include <QtTest/qtest_gui.h> +#ifdef QT_KEYPAD_NAVIGATION +# define QTEST_DISABLE_KEYPAD_NAVIGATION QApplication::setKeypadNavigationEnabled(false); +#else +# define QTEST_DISABLE_KEYPAD_NAVIGATION +#endif + #define QTEST_MAIN(TestObject) \ int main(int argc, char *argv[]) \ { \ QApplication app(argc, argv); \ + QTEST_DISABLE_KEYPAD_NAVIGATION \ TestObject tc; \ return QTest::qExec(&tc, argc, argv); \ } diff --git a/src/testlib/qtest_global.h b/src/testlib/qtest_global.h index d6b0655..ba7da2a 100644 --- a/src/testlib/qtest_global.h +++ b/src/testlib/qtest_global.h @@ -52,7 +52,7 @@ QT_MODULE(Test) #ifdef QTEST_EMBED # define Q_TESTLIB_EXPORT -#elif !defined(QT_SHARED) +#elif !defined(QT_SHARED) && !(defined(Q_OS_SYMBIAN) && defined(Q_CC_RVCT)) # define Q_TESTLIB_EXPORT #else # ifdef QTESTLIB_MAKEDLL @@ -62,10 +62,11 @@ QT_MODULE(Test) # endif #endif -#if (defined (Q_CC_MSVC) && _MSC_VER < 1310) || defined (Q_CC_SUN) || defined (Q_CC_XLC) || (defined (Q_CC_GNU) && (__GNUC__ - 0 < 3)) +#if (defined (Q_CC_MSVC) && _MSC_VER < 1310) || defined (Q_CC_SUN) || defined (Q_CC_XLC) || (defined (Q_CC_GNU) && (__GNUC__ - 0 < 3)) || defined (Q_CC_NOKIAX86) # define QTEST_NO_SPECIALIZATIONS #endif + #if (defined Q_CC_HPACC) && (defined __ia64) # ifdef Q_TESTLIB_EXPORT # undef Q_TESTLIB_EXPORT diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index b5200dc..b676012 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -300,10 +300,15 @@ QT_BEGIN_NAMESPACE the \a TestClass, and executes all tests in the order they were defined. Use this macro to build stand-alone executables. + \bold {Note:} On platforms that have keypad navigation enabled by default (eg: Symbian), + this macro will forcfully disable it to simplify the usage of key events when writing + autotests. If you wish to write a test case that uses keypad navigation, you should + enable it either in the \c {initTestCase()} or \c {init()} functions of your test case. + Example: \snippet doc/src/snippets/code/src_qtestlib_qtestcase.cpp 11 - \sa QTEST_APPLESS_MAIN(), QTest::qExec() + \sa QTEST_APPLESS_MAIN(), QTest::qExec(), QApplication::setKeypadNavigationEnabled() */ /*! \macro QTEST_APPLESS_MAIN(TestClass) @@ -1279,7 +1284,7 @@ static void qInvokeTestMethods(QObject *testObject) QTEST_ASSERT(metaObject); QTestLog::startLogging(); - + QTestResult::setCurrentTestFunction("initTestCase"); QTestResult::setCurrentTestLocation(QTestResult::DataFunc); QTestTable::globalTestTable(); @@ -1399,6 +1404,11 @@ int QTest::qExec(QObject *testObject, int argc, char **argv) } #endif +#ifdef Q_OS_SYMBIAN +//### FIX THIS temporary hack to delay execution of symbian os tests. Used to get emulator to stable state before running testcase + qSleep(3000); +#endif + QTestResult::reset(); QTEST_ASSERT(testObject); diff --git a/src/testlib/qtestcase.h b/src/testlib/qtestcase.h index 4e5deff..b104e93 100644 --- a/src/testlib/qtestcase.h +++ b/src/testlib/qtestcase.h @@ -119,11 +119,22 @@ class QTestData; namespace QTest { - template <typename T> +#ifndef Q_CC_NOKIAX86 + template <typename T> inline char *toString(const T &) { return 0; } +#else + // Nokia X86 compiler bug: + // does not export template specializations if parent template is inline + template <typename T> + Q_TESTLIB_EXPORT char *toString(const T &) + { + return 0; + } +#endif + Q_TESTLIB_EXPORT char *toHexRepresentation(const char *ba, int length); Q_TESTLIB_EXPORT char *toString(const char *); @@ -168,6 +179,7 @@ namespace QTest } Q_TESTLIB_EXPORT QTestData &newRow(const char *dataTag); +#ifndef Q_CC_NOKIAX86 template <typename T> inline bool qCompare(T const &t1, T const &t2, const char *actual, const char *expected, const char *file, int line) @@ -177,6 +189,20 @@ namespace QTest : compare_helper(false, "Compared values are not the same", toString<T>(t1), toString<T>(t2), actual, expected, file, line); } +#else + // Nokia X86 compiler bug: + // does not export template specializations if parent template is inline + template <typename T> + Q_TESTLIB_EXPORT bool qCompare(T const &t1, T const &t2, const char *actual, const char *expected, + const char *file, int line) + { + return (t1 == t2) + ? compare_helper(true, "COMPARE()", file, line) + : compare_helper(false, "Compared values are not the same", + toString<T>(t1), toString<T>(t2), actual, expected, file, line); + } +#endif + template <> Q_TESTLIB_EXPORT bool qCompare<float>(float const &t1, float const &t2, @@ -233,7 +259,7 @@ namespace QTest return qCompare<qreal>(qreal(t1), t2, actual, expected, file, line); } -#elif defined(QT_COORD_TYPE) || defined(QT_ARCH_ARM) || defined(QT_NO_FPU) || defined(QT_ARCH_WINDOWSCE) +#elif defined(QT_COORD_TYPE) || defined(QT_ARCH_ARM) || defined(QT_NO_FPU) || defined(QT_ARCH_WINDOWSCE) || defined(QT_ARCH_SYMBIAN) template <> inline bool qCompare<qreal, double>(qreal const &t1, double const &t2, const char *actual, const char *expected, const char *file, int line) @@ -289,6 +315,28 @@ namespace QTest return compare_string_helper(t1, t2, actual, expected, file, line); } #else /* QTEST_NO_SPECIALIZATIONS */ + +// In Synmbian we have QTEST_NO_SPECIALIZATIONS defined, but still float related specialization +// Should be uses. If QTEST_NO_SPECIALIZATIONS is enabled we get ambiguous overload errors +#if defined(QT_ARCH_SYMBIAN) + template <typename T1, typename T2> + bool qCompare(T1 const &, T2 const &, const char *, const char *, const char *, int); + + template <> + inline bool qCompare<qreal, double>(qreal const &t1, double const &t2, const char *actual, + const char *expected, const char *file, int line) + { + return qCompare<float>(float(t1), float(t2), actual, expected, file, line); + } + + template <> + inline bool qCompare<double, qreal>(double const &t1, qreal const &t2, const char *actual, + const char *expected, const char *file, int line) + { + return qCompare<float>(float(t1), float(t2), actual, expected, file, line); + } +#endif + inline bool qCompare(const char *t1, const char *t2, const char *actual, const char *expected, const char *file, int line) { @@ -322,13 +370,24 @@ namespace QTest return compare_string_helper(t1, t2, actual, expected, file, line); } + // NokiaX86 and RVCT do not like implicitly comparing bool with int +#ifndef QTEST_NO_SPECIALIZATIONS + template <> +#endif + inline bool qCompare(bool const &t1, int const &t2, + const char *actual, const char *expected, const char *file, int line) + { + return qCompare<int>(int(t1), t2, actual, expected, file, line); + } + + template <class T> inline bool qTest(const T& actual, const char *elementName, const char *actualStr, const char *expected, const char *file, int line) { return qCompare(actual, *static_cast<const T *>(QTest::qElementData(elementName, qMetaTypeId<T>())), actualStr, expected, file, line); - } + } } #undef QTEST_COMPARE_DECL diff --git a/src/testlib/testlib.pro b/src/testlib/testlib.pro index 90bd92d..de42b6d 100644 --- a/src/testlib/testlib.pro +++ b/src/testlib/testlib.pro @@ -25,3 +25,5 @@ mac { include(../qbase.pri) QMAKE_TARGET_PRODUCT = QTestLib QMAKE_TARGET_DESCRIPTION = Qt Unit Testing Library + +symbian:TARGET.UID3=0x2001B2DF diff --git a/src/tools/bootstrap/bootstrap.pri b/src/tools/bootstrap/bootstrap.pri index 1cf103b..4726653 100644 --- a/src/tools/bootstrap/bootstrap.pri +++ b/src/tools/bootstrap/bootstrap.pri @@ -55,7 +55,7 @@ hpux-acc*|hpuxi-acc* { unix:LIBS += -lz # win32:LIBS += libz.lib } -win32:LIBS += -luser32 +win32:!win32-mwc:LIBS += -luser32 mac { CONFIG -= incremental diff --git a/src/tools/moc/preprocessor.cpp b/src/tools/moc/preprocessor.cpp index 45cbbfd..d1703c8 100644 --- a/src/tools/moc/preprocessor.cpp +++ b/src/tools/moc/preprocessor.cpp @@ -515,7 +515,12 @@ void Preprocessor::substituteMacro(const MacroName ¯o, Symbols &substituted, Symbols saveSymbols = symbols; int saveIndex = index; - symbols = macros.value(macro).symbols; + // This is a workaround for a compiler bug that did not like the QHash::value function that + // simply did: "return T();" This code should essentially do the same thing but declares the + // default instance outside and calls the other QHash::value() implementation that returns + // 'dummy' as the default value now. + Macro dummy; + symbols = macros.value(macro, dummy).symbols; index = 0; safeset += macro; diff --git a/src/xml/sax/qxml.cpp b/src/xml/sax/qxml.cpp index ade0339..ba68636 100644 --- a/src/xml/sax/qxml.cpp +++ b/src/xml/sax/qxml.cpp @@ -302,7 +302,9 @@ private: // used for parsing of entity references struct XmlRef { - XmlRef(const QString &_name = QString(), const QString &_value = QString()) + XmlRef() + : index(0) {} + XmlRef(const QString &_name, const QString &_value) : name(_name), value(_value), index(0) {} bool isEmpty() const { return index == value.length(); } QChar next() { return value.at(index++); } diff --git a/src/xml/xml.pro b/src/xml/xml.pro index 0c7133c..8d1bf68 100644 --- a/src/xml/xml.pro +++ b/src/xml/xml.pro @@ -18,3 +18,5 @@ win32-borland { include(dom/dom.pri) include(sax/sax.pri) include(stream/stream.pri) + +symbian:TARGET.UID3=0x2001B2E0 diff --git a/src/xmlpatterns/data/qabstractfloatcasters.cpp b/src/xmlpatterns/data/qabstractfloatcasters.cpp index bf53fa4..95ac17a 100644 --- a/src/xmlpatterns/data/qabstractfloatcasters.cpp +++ b/src/xmlpatterns/data/qabstractfloatcasters.cpp @@ -63,9 +63,19 @@ template <const bool isDouble> Item BooleanToAbstractFloatCaster<isDouble>::castFrom(const Item &from, const QExplicitlySharedDataPointer<DynamicContext> &context) const { +#if defined(Q_CC_RVCT) + // RVCT doesn't like using template parameter in trinary operator when the trinary operator result is + // passed directly into another constructor. + bool tempDouble = isDouble; + if(from.template as<AtomicValue>()->evaluateEBV(context)) + return tempDouble ? toItem(CommonValues::DoubleOne) : toItem(CommonValues::FloatOne); + else + return tempDouble ? toItem(CommonValues::DoubleZero) : toItem(CommonValues::FloatZero); +#else if(from.template as<AtomicValue>()->evaluateEBV(context)) return isDouble ? toItem(CommonValues::DoubleOne) : toItem(CommonValues::FloatOne); else return isDouble ? toItem(CommonValues::DoubleZero) : toItem(CommonValues::FloatZero); +#endif } diff --git a/src/xmlpatterns/data/qschemanumeric.cpp b/src/xmlpatterns/data/qschemanumeric.cpp index 4f42db9..a23bb6d 100644 --- a/src/xmlpatterns/data/qschemanumeric.cpp +++ b/src/xmlpatterns/data/qschemanumeric.cpp @@ -51,8 +51,7 @@ #include "qschemanumeric_p.h" /** - * @file - * @short Contains class Numeric. This file was originally called qnumeric.cpp, + * @file Contains class Numeric. This file was originally called qnumeric.cpp, * but was renamed to stay consistent with qschemanumeric_p.h */ diff --git a/src/xmlpatterns/functions/qcomparingaggregator.cpp b/src/xmlpatterns/functions/qcomparingaggregator.cpp index a87e659..4c3f1b6 100644 --- a/src/xmlpatterns/functions/qcomparingaggregator.cpp +++ b/src/xmlpatterns/functions/qcomparingaggregator.cpp @@ -203,8 +203,13 @@ ComparingAggregator<oper, result>::typeCheck(const StaticContext::Ptr &context, if(!m_operands.first()->staticType()->cardinality().allowsMany()) return m_operands.first(); - + +#if defined(Q_CC_RVCT) + // explicit scope needed in RVCT + ComparingAggregator<oper, result>::prepareComparison(fetchComparator(t1, t1, context)); +#else prepareComparison(fetchComparator(t1, t1, context)); +#endif return me; } diff --git a/src/xmlpatterns/functions/qsequencefns_p.h b/src/xmlpatterns/functions/qsequencefns_p.h index 3f79a5f..1c67d89 100644 --- a/src/xmlpatterns/functions/qsequencefns_p.h +++ b/src/xmlpatterns/functions/qsequencefns_p.h @@ -146,13 +146,28 @@ namespace QPatternist */ virtual Expression::Ptr compress(const StaticContext::Ptr &context) { +#if defined(Q_CC_RVCT) && !defined(QT_NO_DEBUG) + // RVCT doesn't like using template parameter in trinary operator when the trinary operator result is + // passed directly into another constructor. + bool tempAssert = (Id == IDExistsFN || Id == IDEmptyFN); + Q_ASSERT(tempAssert); +#else Q_ASSERT(Id == IDExistsFN || Id == IDEmptyFN); +#endif + const Expression::Ptr me(FunctionCall::compress(context)); if(me != this) return me; +#if defined(Q_CC_RVCT) + // RVCT doesn't like using template parameter in trinary operator when the trinary operator result is + // passed directly into another constructor. + Expression::ID tempId = Id; + const Cardinality myCard((tempId == IDExistsFN) ? Cardinality::oneOrMore() : Cardinality::empty()); +#else const Cardinality myCard((Id == IDExistsFN) ? Cardinality::oneOrMore() : Cardinality::empty()); +#endif const Cardinality card(m_operands.first()->staticType()->cardinality()); if(myCard.isMatch(card)) |