diff options
Diffstat (limited to 'src')
261 files changed, 18291 insertions, 526 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/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..f8d5450 100644 --- a/src/corelib/arch/generic/qatomic_generic_unix.cpp +++ b/src/corelib/arch/generic/qatomic_generic_unix.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#if !defined(Q_OS_SYMBIAN) || (defined(Q_OS_SYMBIAN) && !defined(Q_CC_RVCT)) + #include "qplatformdefs.h" #include <QtCore/qatomic.h> @@ -116,3 +118,4 @@ void *QBasicAtomicPointer_fetchAndAddOrdered(void * volatile *_q_value, qptrdiff pthread_mutex_unlock(&qAtomicMutex); return returnValue; } +#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..902b320 --- /dev/null +++ b/src/corelib/arch/qatomic_symbian.h @@ -0,0 +1,26 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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 ac26b4f..c795ea6 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 extern "C" { long __cdecl _InterlockedIncrement(volatile long *); @@ -313,7 +313,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 @@ -321,8 +321,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..bcb0bd4 --- /dev/null +++ b/src/corelib/arch/symbian/qatomic_symbian.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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.h b/src/corelib/concurrent/qtconcurrentiteratekernel.h index 01c54a7..38d2824 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> diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro index f99d57f..469225e 100644 --- a/src/corelib/corelib.pro +++ b/src/corelib/corelib.pro @@ -26,3 +26,5 @@ QMAKE_LIBS += $$QMAKE_LIBS_CORE QMAKE_DYNAMIC_LIST_FILE = $$PWD/QtCore.dynlist contains(DEFINES,QT_EVAL):include(eval.pri) + +symbian:TARGET.UID3=0x2001B2DC
\ No newline at end of file diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 8324d05..dd1dbd2 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,14 @@ # 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 <e32debug.h> +#endif + QT_BEGIN_NAMESPACE @@ -1024,6 +1030,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) @@ -1079,7 +1099,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 */ /*! @@ -1108,7 +1128,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 */ /*! @@ -1686,6 +1738,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> @@ -1835,7 +1960,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) { @@ -1847,7 +1972,7 @@ static void mac_default_handler(const char *msg) fprintf(stderr, msg); } } -#endif // Q_CC_MWERKS +#endif // Q_CC_MWERKS && Q_OS_MACX @@ -1981,12 +2106,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); @@ -2013,7 +2149,9 @@ 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) + 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 @@ -2282,7 +2420,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); @@ -2311,7 +2449,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..7d8b321 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,7 +1394,8 @@ public: ImFont, ImCursorPosition, ImSurroundingText, - ImCurrentSelection + ImCurrentSelection, + ImMaximumTextLength }; enum ToolButtonStyle { @@ -1485,6 +1490,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; 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 6d75c59..0d82c2a 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -61,7 +61,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(); @@ -146,7 +146,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); @@ -783,6 +783,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 @@ -798,7 +800,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)) @@ -845,7 +847,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('\\'); @@ -869,7 +871,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('/'); @@ -1811,10 +1813,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 @@ -1914,7 +1916,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() */ @@ -2065,7 +2068,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(); @@ -2134,7 +2137,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 d7da800..af10c31 100644 --- a/src/corelib/io/qfile.cpp +++ b/src/corelib/io/qfile.cpp @@ -785,6 +785,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..883b70f --- /dev/null +++ b/src/corelib/io/qfilesystemwatcher_symbian.cpp @@ -0,0 +1,252 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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..b34418a --- /dev/null +++ b/src/corelib/io/qfilesystemwatcher_symbian_p.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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 0d88b06..4747bcc 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 @@ -379,10 +399,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) @@ -406,7 +455,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) { @@ -438,7 +491,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; @@ -459,7 +516,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) @@ -473,6 +534,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(); @@ -480,18 +551,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; @@ -500,28 +579,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; } @@ -554,6 +666,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) { @@ -674,20 +812,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) @@ -831,10 +1096,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 @@ -870,6 +1139,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 522be20..a57c00e 100644 --- a/src/corelib/io/qfsfileengine_win.cpp +++ b/src/corelib/io/qfsfileengine_win.cpp @@ -1452,7 +1452,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; @@ -1555,7 +1555,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 c739054..fe3ceff 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -1031,6 +1031,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. @@ -1069,6 +1078,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..ae7f51a --- /dev/null +++ b/src/corelib/io/qprocess_symbian.cpp @@ -0,0 +1,1003 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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 4856353..3aea508 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -467,6 +467,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..19c1510 --- /dev/null +++ b/src/corelib/kernel/qcore_symbian_p.cpp @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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..a7d2ce4 --- /dev/null +++ b/src/corelib/kernel/qcore_symbian_p.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. +** +** $TROLLTECH_DUAL_EMBEDDED_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 a23b2dd..12b80f6 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); @@ -313,10 +318,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 +456,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 +621,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 +969,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 +1486,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 +1714,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 +1729,32 @@ QString QCoreApplication::applicationDirPath() QCoreApplicationPrivate *d = self->d_func(); if (d->cachedApplicationDirPath == QString()) +#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 +1808,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 +2113,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 +2124,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 +2162,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 +2264,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 +2461,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 +2475,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 +2489,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 +2498,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/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp new file mode 100644 index 0000000..b38a6c6 --- /dev/null +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -0,0 +1,843 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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_ZERO_TIMERS_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; +}; + +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(SymbianTimerInfo *timerInfo) + : CActive(TIMER_PRIORITY), + 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 (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(); + // We complete it after the processEvents is done. + } +} + +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; +} + +QCompleteZeroTimersActiveObject::QCompleteZeroTimersActiveObject(QEventDispatcherSymbian *dispatcher) + : CActive(COMPLETE_ZERO_TIMERS_PRIORITY), + m_dispatcher(dispatcher) +{ + CActiveScheduler::Add(this); + iStatus = KRequestPending; + SetActive(); + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); +} + +QCompleteZeroTimersActiveObject::~QCompleteZeroTimersActiveObject() +{ + Cancel(); +} + +bool QCompleteZeroTimersActiveObject::ref() +{ + return (++m_refCount != 0); +} + +bool QCompleteZeroTimersActiveObject::deref() +{ + return (--m_refCount != 0); +} + +void QCompleteZeroTimersActiveObject::DoCancel() +{ + if (iStatus.Int() & KRequestPending) { + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); + } +} + +void QCompleteZeroTimersActiveObject::RunL() +{ + m_dispatcher->completeZeroTimers(); + + iStatus = KRequestPending; + SetActive(); + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); +} + +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 + + + // 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); + 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, 0, &timeout); + if(ret != 0) FD_SET(i.key()->socket(), &readfds); + } else if(i.key()->type() == QSocketNotifier::Write) { + ret = ::select(maxfd, 0, &onefds, 0, &timeout); + if(ret != 0) FD_SET(i.key()->socket(), &writefds); + } else { // must be exception fds then + ret = ::select(maxfd, 0, 0, &onefds, &timeout); + if(ret != 0) FD_SET(i.key()->socket(), &exceptionfds); + } + + } // 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(); + } + + Q_ASSERT(!m_AOStatuses.contains(notifier)); + + QSelectMutexGrabber lock(m_pipeEnds[1], &m_mutex); + + 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; + 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()); + } + } + + return maxfd; +} + +void QSelectThread::updateActivatedNotifiers(QSocketNotifier::Type type, fd_set *fds) +{ + Q_D(QThread); + + 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); + } + } + + 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) + : CActive(CActive::EPriorityStandard), + m_dispatcher(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() +{ + 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_completeZeroTimersAO(0), + m_interrupt(false), + m_wakeUpDone(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); + // We already might have posted events, wakeup once to process them + wakeUp(); +} + +void QEventDispatcherSymbian::closingDown() +{ + if (m_selectThread.isRunning()) { + m_selectThread.stop(); + } +/* + We do have bug in AO cancel mechanism, unfortunately it was too late + to fix it for Garden release. This has to be fixed after Garden, see task: 246600 + delete m_wakeUpAO; + if (m_activeScheduler) { + CActiveScheduler::Install(NULL); + delete m_activeScheduler; + } + */ +} + +bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags flags ) +{ + Q_D(QAbstractEventDispatcher); + + 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() > 500) { + 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; + }; + + // Complete zero timers so that we get them next time. + completeZeroTimers(); + + 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; +} + +void QEventDispatcherSymbian::completeZeroTimers() +{ + for (QHash<int, SymbianTimerInfoPtr>::iterator i = m_timerList.begin(); i != m_timerList.end(); ++i) { + if ((*i)->interval == 0 && (*i)->timerAO->iStatus.Int() & KRequestPending) { + TRequestStatus *status = &(*i)->timerAO->iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); + } + } + + // We do this because we want to return from processEvents. This is because + // each invocation of processEvents should only run each zero timer 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(timer.data()); + m_timerList.insert(timerId, timer); + + if (interval == 0) { + if (!m_completeZeroTimersAO) { + m_completeZeroTimersAO = new (ELeave) QCompleteZeroTimersActiveObject(this); + } + m_completeZeroTimersAO->ref(); + } + + timer->timerAO->Start(); +} + +bool QEventDispatcherSymbian::unregisterTimer ( int timerId ) +{ + if (!m_timerList.contains(timerId)) { + return false; + } + + SymbianTimerInfoPtr timerInfo = m_timerList.take(timerId); + if (timerInfo->interval == 0) { + if (!m_completeZeroTimersAO->deref()) { + delete m_completeZeroTimersAO; + m_completeZeroTimersAO = 0; + } + } + + 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..b5ce868 --- /dev/null +++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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 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 CActive +{ +public: + QTimerActiveObject(SymbianTimerInfo *timerInfo); + ~QTimerActiveObject(); + + void Start(); + +protected: + void DoCancel(); + void RunL(); + +private: + SymbianTimerInfo *m_timerInfo; + RTimer m_rTimer; +}; + +class QCompleteZeroTimersActiveObject : public CActive +{ +public: + QCompleteZeroTimersActiveObject(QEventDispatcherSymbian *dispatcher); + ~QCompleteZeroTimersActiveObject(); + + bool ref(); + bool deref(); + +protected: + void DoCancel(); + void RunL(); + +private: + int m_refCount; + QEventDispatcherSymbian *m_dispatcher; +}; + +class QSocketActiveObject : public CActive +{ +public: + QSocketActiveObject(QEventDispatcherSymbian *dispatcher, QSocketNotifier *notifier); + ~QSocketActiveObject(); + + void deleteLater(); + +protected: + void DoCancel(); + void RunL(); + +private: + QEventDispatcherSymbian *m_dispatcher; + 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 completeZeroTimers(); + + 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; + QCompleteZeroTimersActiveObject *m_completeZeroTimersAO; + + volatile bool m_interrupt; + QAtomicInt m_wakeUpDone; + + bool m_noSocketEvents; + QList<QSocketActiveObject *> m_deferredSocketEvents; + + RProcess m_processHandle; +}; + +#define DEBUG_REQUEST_COMPLETE + +#ifdef DEBUG_REQUEST_COMPLETE +// 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 you define DEBUG_REQUEST_COMPLETE, 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/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp index 6aa3b56..ce38b73 100644 --- a/src/corelib/kernel/qeventdispatcher_unix.cpp +++ b/src/corelib/kernel/qeventdispatcher_unix.cpp @@ -54,7 +54,7 @@ #include <stdio.h> #include <stdlib.h> -#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED) +#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED) && !defined(Q_OS_SYMBIAN) # include <sys/times.h> #endif @@ -65,7 +65,7 @@ Q_CORE_EXPORT bool qt_disable_lowpriority_timers=false; /***************************************************************************** UNIX signal handling *****************************************************************************/ - +#if !defined(Q_OS_SYMBIAN) static sig_atomic_t signal_received; static sig_atomic_t signals_fired[NSIG]; @@ -74,7 +74,7 @@ static void signalHandler(int sig) signals_fired[sig] = 1; signal_received = 1; } - +#endif static void initThreadPipeFD(int fd) { @@ -134,6 +134,7 @@ int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, int nsel; do { +#if !defined(Q_OS_SYMBIAN) if (mainThread) { while (signal_received) { signal_received = 0; @@ -145,7 +146,7 @@ int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, } } } - +#endif // Process timers and socket notifiers - the common UNIX stuff int highest = 0; if (! (flags & QEventLoop::ExcludeSocketNotifiers) && (sn_highest >= 0)) { @@ -257,7 +258,7 @@ int QEventDispatcherUNIXPrivate::doSelect(QEventLoop::ProcessEventsFlags flags, QTimerInfoList::QTimerInfoList() { -#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) +#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) && !defined(Q_OS_SYMBIAN) useMonotonicTimers = false; # if (_POSIX_MONOTONIC_CLOCK == 0) @@ -298,7 +299,7 @@ timeval QTimerInfoList::updateCurrentTime() return currentTime; } -#if (_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED) +#if ((_POSIX_MONOTONIC_CLOCK-0 <= 0) || defined(QT_BOOTSTRAPPED)) && !defined(Q_OS_SYMBIAN) /* Returns true if the real time clock has changed by more than 10% @@ -374,7 +375,11 @@ void QTimerInfoList::repairTimersIfNeeded() void QTimerInfoList::getTime(timeval &t) { timespec ts; +#if !defined(Q_OS_SYMBIAN) clock_gettime(CLOCK_MONOTONIC, &ts); +#else + clock_gettime(CLOCK_REALTIME, &ts); +#endif t.tv_sec = ts.tv_sec; t.tv_usec = ts.tv_nsec / 1000; } @@ -939,7 +944,7 @@ void QEventDispatcherUNIX::flush() - +#if !defined(Q_OS_SYMBIAN) void QCoreApplication::watchUnixSignal(int sig, bool watch) { if (sig < NSIG) { @@ -953,5 +958,10 @@ void QCoreApplication::watchUnixSignal(int sig, bool watch) sigaction(sig, &sa, 0); } } +#else +void QCoreApplication::watchUnixSignal(int, bool) +{ +} +#endif QT_END_NAMESPACE diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 05015c0..f5d3f78 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -1402,8 +1402,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 9853079..2b0e0af 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..afb161c --- /dev/null +++ b/src/corelib/kernel/qsharedmemory_symbian.cpp @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_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 487c653..c4395d9 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> - -QT_BEGIN_NAMESPACE - -#ifndef QT_NO_SHAREDMEMORY - #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> +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_SHAREDMEMORY + 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 81d4f10..05a9347 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..0c138c4 --- /dev/null +++ b/src/corelib/kernel/qsystemsemaphore_symbian.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_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 b4427c0..006c635 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/kernel/qvariant.h b/src/corelib/kernel/qvariant.h index d7b7e3c..870aba2 100644 --- a/src/corelib/kernel/qvariant.h +++ b/src/corelib/kernel/qvariant.h @@ -571,7 +571,12 @@ template<typename T> T qvariant_cast(const QVariant &v) if (qvariant_cast_helper(v, QVariant::Type(vid), &t)) return t; } +#ifdef Q_CC_NOKIAX86 + T t; + return t; +#else return T(); +#endif } template<typename T> 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..f07fad8 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); +#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..aad55bc 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) +#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,14 @@ void QThreadPrivate::finish(void *arg) QThreadStorageData::finish((void **)data); d->thread_id = 0; +#ifdef Q_OS_SYMBIAN + d->data->symbian_thread_handle.Close(); +#endif d->thread_done.wakeAll(); +#ifdef Q_OS_SYMBIAN + if (lockAnyway) +#endif + d->mutex.unlock(); } @@ -268,6 +316,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 +403,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 +486,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 +501,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 +515,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 +523,20 @@ void QThread::terminate() } else { d->terminated = true; } +#else + if (!d->running) + return; + if (!d->terminationEnabled) { + d->terminatePending = true; + return; + } + + d->data->symbian_thread_handle.Terminate(KErrNone); + + d->terminated = true; +#endif + + } bool QThread::wait(unsigned long time) @@ -489,11 +561,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 7232626..9063ae4 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 a18b531..3328716 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -914,7 +914,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; @@ -984,7 +985,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 559ba81..4267562 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -78,6 +78,11 @@ QT_END_NAMESPACE #include <qdebug.h> #include <time.h> +#if defined(Q_OS_SYMBIAN) +#include <e32std.h> +#include "private/qcore_symbian_p.h" +#endif + #if defined(Q_OS_LINUX) && !defined(__UCLIBC__) # include <fenv.h> #endif @@ -123,6 +128,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 */ @@ -1270,6 +1282,792 @@ QVariant QSystemLocale::query(QueryType type, QVariant in = QVariant()) const } return QVariant(); } +#elif defined(Q_OS_SYMBIAN) + +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(); +} #elif defined(Q_OS_UNIX) 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 f1b35ee..b8c3f3d 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(); } @@ -248,7 +254,7 @@ namespace QtSharedPointer { if (o && !o->strongref) o = 0; if (o) { - verifyReconstruction(actual); + Basic<T>::verifyReconstruction(actual); o->weakref.ref(); o->strongref.ref(); } @@ -276,15 +282,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; } @@ -300,7 +306,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; } @@ -338,12 +344,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..45e92bf 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -101,4 +101,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..b0aa7b6 100644 --- a/src/gui/dialogs/qdialog.cpp +++ b/src/gui/dialogs/qdialog.cpp @@ -64,6 +64,8 @@ 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 #ifndef SPI_GETSNAPTODEFBUTTON @@ -486,7 +488,14 @@ int QDialog::exec() #endif //QT_NO_MENUBAR #endif //Q_OS_WINCE_WM +#if !defined(Q_WS_S60) show(); +#else + if (qobject_cast<QFileDialog *>(this)) + showFullScreen(); + else + show(); +#endif #ifdef Q_WS_MAC d->mac_nativeDialogModalHelp(); diff --git a/src/gui/dialogs/qfiledialog.cpp b/src/gui/dialogs/qfiledialog.cpp index d786f3e..7056575 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 @@ -2081,7 +2084,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); @@ -3194,7 +3197,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("\\\\")); @@ -3206,7 +3212,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); @@ -3218,7 +3228,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 dc24390..bbd4af3 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(QAbstractItemModel *model, QObject *parent = 0) : QCompleter(model, parent), proxyModel(0), sourceModel(0) { -#ifdef Q_OS_WIN +#ifdef 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 012d3a1..b202629 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); } @@ -1585,12 +1597,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); } diff --git a/src/gui/dialogs/qmessagebox.cpp b/src/gui/dialogs/qmessagebox.cpp index 456b480..9702fd1 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/gui.pro b/src/gui/gui.pro index f224e67..d3b7388 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,4 @@ QMAKE_DYNAMIC_LIST_FILE = $$PWD/QtGui.dynlist DEFINES += Q_INTERNAL_QAPP_SRC +symbian:TARGET.UID3=0x2001B2DD
\ 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 efb8260..82be1b9 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_s60.cpp b/src/gui/image/qpixmap_s60.cpp new file mode 100644 index 0000000..6246592 --- /dev/null +++ b/src/gui/image/qpixmap_s60.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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(); + } + + QImage::Format format = qt_TDisplayMode2Format( displayMode ); + int bytesPerLine = CFbsBitmap::ScanLineLength(temporary->SizeInPixels().iWidth,displayMode); + temporary->LockHeap(); + QImage image = QImage((uchar*)temporary->DataAddress(), srcRect.Width(), srcRect.Height(), bytesPerLine, format); + QPixmap pixmap = QPixmap::fromImage(image.copy()); + temporary->UnlockHeap(); + CBase::Delete(temporary); + return pixmap; + +} +QT_END_NAMESPACE diff --git a/src/gui/image/qpixmapcache.cpp b/src/gui/image/qpixmapcache.cpp index eedb6a3..4f1f0f0 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..7f0a482 --- /dev/null +++ b/src/gui/inputmethod/qcoefepinputcontext_p.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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(); + + // 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; + bool m_isEditing; + bool m_inDestruction; + int m_cursorVisibility; + int m_inlinePosition; + QPoint m_mousePressPos; + 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..b9ea4c7 --- /dev/null +++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp @@ -0,0 +1,577 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_NO_IM + +#include "qcoefepinputcontext_p.h" +#include <qapplication.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_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->SetCurrentInputMode( EAknEditorTextInputMode ); + m_fepState->SetPermittedInputModes( EAknEditorAllInputModes ); + m_fepState->SetLocalLanguage(ELangEnglish); + m_fepState->SetDefaultLanguage(ELangEnglish); + m_fepState->SetDefaultCase( EAknEditorLowerCase ); + m_fepState->SetCurrentCase( 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. + CCoeEnv::Static()->InputCapabilitiesChanged(); + QApplication::processEvents(); + + if (m_fepState) + delete m_fepState; +} + +void QCoeFepInputContext::reset() +{ + CCoeEnv::Static()->Fep()->CancelTransaction(); +} + +void QCoeFepInputContext::update() +{ + // For pre-5.0 SDKs, we don't do any work. + 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); +} + +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) +{ + // For pre-5.0 SDKs, we don't do any work. + if (QSysInfo::s60Version() != QSysInfo::SV_S60_5_0) { + return false; + } + + if (event->type() == QEvent::MouseButtonPress) { + const QMouseEvent *mEvent = static_cast<const QMouseEvent *>(event); + m_mousePressPos = mEvent->globalPos(); + } else if (event->type() == QEvent::MouseButtonRelease) { + // Notify S60 that we want the virtual keyboard to show up. + const QMouseEvent *mEvent = static_cast<const QMouseEvent *>(event); + + if (mEvent->modifiers() == Qt::NoModifier + && mEvent->button() == Qt::LeftButton + && focusWidget() // Not set if prior MouseButtonPress was not on this widget + && focusWidget()->rect().contains(focusWidget()->mapFromGlobal(mEvent->globalPos())) + && (m_mousePressPos - mEvent->globalPos()).manhattanLength() < QApplication::startDragDistance()) { + + QSymbianControl *sControl; + sControl = focusWidget()->effectiveWinId()->MopGetObject(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); + } + + // Although it is tempting to let the click through by returning false, we have to return + // true because the event might have caused focus switches, which may in turn delete + // widgets. + 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(TCoeInputCapabilities::EAllText, 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::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; + + TCharFormat cFormat; + TInt numChars = 0; + TInt charPos = 0; + 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; + } + } + + 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; + 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 = w->inputMethodQuery(Qt::ImCursorPosition).toInt() + aCursorSelection.iCursorPos + 1; + + QList<QInputMethodEvent::Attribute> attributes; + attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, pos, 1, QVariant()); + QInputMethodEvent event(m_preeditString, attributes); + // ### FIXME Sets preeditcursor and not cursor. Probably needs new API. + //sendEvent(event); +} + +void QCoeFepInputContext::GetCursorSelectionForFep(TCursorSelection& aCursorSelection) const +{ + QWidget *w = focusWidget(); + if (!w) + return; + + QVariant cursorVar = w->inputMethodQuery(Qt::ImCursorPosition); + int cursor = cursorVar.toInt() + m_preeditString.size(); + int anchor = cursor - w->inputMethodQuery(Qt::ImCurrentSelection).toString().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..3d6d303 100644 --- a/src/gui/inputmethod/qinputcontext.cpp +++ b/src/gui/inputmethod/qinputcontext.cpp @@ -209,9 +209,9 @@ 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 QKeyEvent and QMouseEvent. + 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 @@ -459,6 +459,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 for XIM, 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..b84c52b 100644 --- a/src/gui/inputmethod/qinputcontext.h +++ b/src/gui/inputmethod/qinputcontext.h @@ -76,6 +76,10 @@ class QFont; class QPopupMenu; class QInputContextPrivate; +#ifdef Q_WS_S60 +class TWsEvent; +#endif + class Q_GUI_EXPORT QInputContext : public QObject { @@ -105,6 +109,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/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp index 55b3a03..6c2d109 100644 --- a/src/gui/itemviews/qabstractitemview.cpp +++ b/src/gui/itemviews/qabstractitemview.cpp @@ -2006,6 +2006,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 dc63b25..d373163 100644 --- a/src/gui/itemviews/qheaderview.cpp +++ b/src/gui/itemviews/qheaderview.cpp @@ -3558,7 +3558,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 bf9b5c5..147f523 100644 --- a/src/gui/itemviews/qitemdelegate.cpp +++ b/src/gui/itemviews/qitemdelegate.cpp @@ -1320,7 +1320,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 be0971b..4dc54a1 100644 --- a/src/gui/itemviews/qstyleditemdelegate.cpp +++ b/src/gui/itemviews/qstyleditemdelegate.cpp @@ -321,7 +321,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 d0b1790..d65a352 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 @@ -430,7 +433,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; @@ -446,7 +454,11 @@ QString* QApplicationPrivate::styleOverride = 0; 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 @@ -1319,6 +1331,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) @@ -3709,6 +3723,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; @@ -4750,8 +4771,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. */ /*! @@ -4934,6 +4955,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..807d347 100644 --- a/src/gui/kernel/qapplication.h +++ b/src/gui/kernel/qapplication.h @@ -84,6 +84,10 @@ class QApplicationPrivate; #endif #define qApp (static_cast<QApplication *>(QCoreApplication::instance())) +#if defined(Q_WS_S60) +class TWsEvent; +#endif + class Q_GUI_EXPORT QApplication : public QCoreApplication { Q_OBJECT @@ -223,6 +227,10 @@ 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); +#endif #if defined(Q_WS_QWS) virtual bool qwsEventFilter(QWSEvent *); int qwsProcessEvent(QWSEvent*); @@ -239,7 +247,6 @@ public: void winFocus(QWidget *, bool); static void winMouseButtonUp(); #endif - #ifndef QT_NO_SESSIONMANAGER // session management bool isSessionRestored() const; diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 7487f0a..553efbe 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -233,7 +233,6 @@ public: void createEventDispatcher(); QString appName() const; - static void dispatchEnterLeave(QWidget *enter, QWidget *leave); //modality @@ -420,6 +419,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 +431,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..b021b1c --- /dev/null +++ b/src/gui/kernel/qapplication_s60.cpp @@ -0,0 +1,1071 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_LICENSE$ +** +****************************************************************************/ + +#include "qapplication_p.h" +#include "qsessionmanager.h" +#include "qevent.h" +#include "qeventdispatcher_s60_p.h" +#include "qwidget.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 "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*); + +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) + 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); + //### possible bug, within manhattan lenght if the target is slipped outside .... + 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 = true; +} + +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) + { + // 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 || 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->mapFrom(qwidget, widgetPos), globalPos, + button, QApplicationPrivate::mouse_buttons, mapToQtModifiers(pEvent.iModifiers)); + events.append(Event(alienWidget,mEventEnter)); + } + S60->lastCursorPos = globalPos; + S60->lastPointerEventPos = widgetPos; + S60->lastPointerEventTarget = alienWidget; + + QMouseEvent mEvent(type, alienWidget->mapFrom(qwidget, widgetPos), 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 = 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(); + QPaintEngine *engine = surface->paintDevice()->paintEngine(); + if (!engine) + return; + if (engine->type() == QPaintEngine::Raster) { + QS60WindowSurface *s60Surface = static_cast<QS60WindowSurface *>(qwidget->windowSurface()); + CFbsBitmap *bitmap = s60Surface->symbianBitmap(); + SystemGc().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: + { +#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 + if (qwidget->isFullScreen()) { + SetExtentToWholeScreen(); + } else if (qwidget->isMaximized()) { + TRect r = static_cast<CEikAppUi*>(S60->appUi())->ClientRect(); + SetExtent(r.iTl, r.Size()); + } + break; + } +#ifndef QT_NO_STYLE_S60 + case KAknsMessageSkinChange: + if (QS60Style *s60Style = qobject_cast<QS60Style*>(QApplication::style())) + s60Style->handleSkinChange(); + break; +#endif + default: + break; + } + + CCoeControl::HandleResourceChange(resourceType); + +} + +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(); ; + switch(mode) { + case EColor256: + S60->screenDepth = 8; + break; + case EColor4K: + S60->screenDepth = 12; + break; + case EColor64K: + S60->screenDepth = 16; + break; + case EColor16M: + case EColor16MU: + case EColor16MA: + S60->screenDepth = 32; + break; + default: + qFatal("Unsupported screen depth"); + break; + } + + + 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); + + 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()) { + 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); + 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()); + 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 (QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control)) + { + // Qt::Enter will be generated in HandlePointerL + return 1; + } + break; + case EEventPointerExit: + if (QWidgetPrivate::mapper && QWidgetPrivate::mapper->contains(control)) + { + 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(); + return 0; // Propagate to CONE + default: + break; + } + + if (!QWidgetPrivate::mapper || !QWidgetPrivate::mapper->contains(control)) + return -1; + + return 0; +} + +bool QApplication::s60EventFilter(TWsEvent *aEvent) +{ + return false; +} + +#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..1ba1dfe --- /dev/null +++ b/src/gui/kernel/qclipboard_s60.cpp @@ -0,0 +1,252 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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 + +QT_USE_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() +{ +} + +#endif // QT_NO_CLIPBOARD + +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..0670b6f --- /dev/null +++ b/src/gui/kernel/qcursor_s60.cpp @@ -0,0 +1,29 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_LICENSE$ +** +****************************************************************************/ + +#include <private/qcursor_p.h> +#include <qcursor.h> +#include <qt_s60_p.h> + +#ifdef QT_NO_CURSOR + +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..029892e --- /dev/null +++ b/src/gui/kernel/qdesktopwidget_s60.cpp @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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; +}; + +int QDesktopWidgetPrivate::screenCount = 1; +int QDesktopWidgetPrivate::primaryScreen = 0; + +QDesktopWidgetPrivate::QDesktopWidgetPrivate() +{ +} + +QDesktopWidgetPrivate::~QDesktopWidgetPrivate() +{ +} + +void QDesktopWidgetPrivate::init(QDesktopWidget *that) +{ + TInt screenCount=0; + TInt result=0; + + result = HAL::Get(0, HALData::EDisplayNumberOfScreens, screenCount); + QDesktopWidgetPrivate::screenCount = screenCount; + if( result != KErrNone) + { + // ### What to do if no screens found? + } +} + +void QDesktopWidgetPrivate::cleanup() +{ +} + + +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 *) +{ +} + +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..5b888f7 --- /dev/null +++ b/src/gui/kernel/qdnd_s60.cpp @@ -0,0 +1,370 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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 + +QT_USE_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(); +} + + +#endif // QT_NO_DRAGANDDROP + + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h index 449730d..2724315 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) diff --git a/src/gui/kernel/qeventdispatcher_s60.cpp b/src/gui/kernel/qeventdispatcher_s60.cpp new file mode 100644 index 0000000..862f4ef --- /dev/null +++ b/src/gui/kernel/qeventdispatcher_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. +** +** $TROLLTECH_DUAL_EMBEDDED_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..fec8773 --- /dev/null +++ b/src/gui/kernel/qeventdispatcher_s60_p.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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..96dfa03 --- /dev/null +++ b/src/gui/kernel/qkeymapper_s60.cpp @@ -0,0 +1,220 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_LICENSE$ +** +****************************************************************************/ + +#include "private/qkeymapper_p.h" +#include <e32keys.h> + +QT_BEGIN_NAMESPACE + +QT_USE_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..3ab5230 --- /dev/null +++ b/src/gui/kernel/qsound_s60.cpp @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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 + +QT_USE_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..6261e4b --- /dev/null +++ b/src/gui/kernel/qt_s60_p.h @@ -0,0 +1,248 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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; } + +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 EColor256: + // TODO: is the correct? + 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: + case EColor16MA: + format = QImage::Format_RGB32; + break; +#ifdef __S60_50__ + case EColor16MAP: + format = QImage::Format_ARGB32; + break; +#endif + default: + qFatal("Screen format not supported"); + 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 071e1bd..7eaebbb 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" @@ -389,6 +393,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 @@ -1252,7 +1257,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; @@ -2039,6 +2044,13 @@ static inline void fillRegion(QPainter *painter, const QRegion &rgn, const QPoin painter->setClipRegion(translated); painter->drawTiledPixmap(rect, brush.texture(), rect.topLeft()); #endif +#if defined(Q_WS_S60) && !defined(QT_NO_STYLE_S60) + } if (!brush.isOpaque()) { + // QS60Style knows it's background and does not store its texture in a palette + // Defined in qs60style.cpp + extern void qt_s60_fill_background(QPainter *painter, const QRegion &rgn, const QPoint &offset); + qt_s60_fill_background(painter, rgn, offset); +#endif } else { const QVector<QRect> &rects = rgn.rects(); for (int i = 0; i < rects.size(); ++i) @@ -2060,6 +2072,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()) @@ -2594,7 +2607,7 @@ bool QWidget::isMaximized() const */ Qt::WindowStates QWidget::windowState() const { - return (Qt::WindowStates)data->window_state; + return Qt::WindowStates(data->window_state); } /*!\internal @@ -2606,7 +2619,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); } @@ -6719,7 +6732,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 @@ -6736,7 +6749,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 @@ -7306,7 +7319,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 @@ -10285,7 +10298,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..8ecf758 100644 --- a/src/gui/kernel/qwidget.h +++ b/src/gui/kernel/qwidget.h @@ -744,6 +744,9 @@ private: friend bool isWidgetOpaque(const QWidget *); friend class QGLWidgetPrivate; #endif +#ifdef Q_WS_S60 + friend class QSymbianControl; +#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 423e833..ec64b6e 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -90,6 +90,12 @@ class QWSManager; #if defined(Q_WS_MAC) class QCoreGraphicsPaintEnginePrivate; #endif +#if defined(Q_WS_S60) +class RDrawableWindow; +class CCoeControl; +class CAknTitlePane; +class CAknContextPane; +#endif class QPaintEngine; class QPixmap; class QWidgetBackingStore; @@ -142,6 +148,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 @@ -364,7 +374,7 @@ public: void x11UpdateIsOpaque(); #endif -#if defined (Q_WS_WIN) +#if defined (Q_WS_WIN) || defined (Q_WS_S60) void reparentChildren(); #endif @@ -594,7 +604,7 @@ public: uint isGLWidget : 1; #endif -#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) #ifdef Q_WS_MAC void setWSGeometry(bool dontShow=false, const QRect &oldRect = QRect()); #else @@ -622,7 +632,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 @@ -667,6 +677,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..116dc35 --- /dev/null +++ b/src/gui/kernel/qwidget_s60.cpp @@ -0,0 +1,942 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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) + 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); + } + + 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() +{ + +} + +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 level) +{ + +} + +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); + } +} 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..8f1d762 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,12 @@ embedded { painting/qpaintdevice_qws.cpp } +symbian { + SOURCES += \ + painting/qpaintdevice_s60.cpp \ + painting/qregion_s60.cpp +} + x11|embedded { contains(QT_CONFIG,qtopia) { DEFINES += QT_NO_CUPS QT_NO_LPR @@ -367,3 +374,8 @@ win32:contains(QT_CONFIG, direct3d) { SOURCES += painting/qwindowsurface_d3d.cpp } +symbian { + HEADERS += painting/qwindowsurface_s60_p.h + SOURCES += painting/qwindowsurface_s60.cpp +} + diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp index fbac811a..b533409 100644 --- a/src/gui/painting/qbackingstore.cpp +++ b/src/gui/painting/qbackingstore.cpp @@ -61,6 +61,11 @@ #include <private/qwsmanager_p.h> #endif +#ifdef Q_WS_S60 +#include <unistd.h> // For usleep +#include <qt_s60_p.h> +#endif + QT_BEGIN_NAMESPACE extern QRegion qt_dirtyRegion(QWidget *); 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..ec1b765 --- /dev/null +++ b/src/gui/painting/qpaintdevice_s60.cpp @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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 ba1e27c..19b2574 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) @@ -3163,7 +3165,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; @@ -3196,7 +3198,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; @@ -3216,7 +3218,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) { @@ -4172,8 +4174,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..4504118 --- /dev/null +++ b/src/gui/painting/qregion_s60.cpp @@ -0,0 +1,22 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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..b262cb2 --- /dev/null +++ b/src/gui/painting/qwindowsurface_s60.cpp @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_LICENSE$ +** +****************************************************************************/ + +#include <qglobal.h> // for Q_WS_WIN define (non-PCH) + +#include <QtGui/qpaintdevice.h> +#include <QtGui/qwidget.h> +#include "qwindowsurface_s60_p.h" +#include "qt_s60_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; + + TSize size(0, 0); + TDisplayMode mode = S60->screenDevice()->DisplayMode(); + + // We create empty CFbsBitmap here -> it will be resized in setGeometry + d_ptr->bitmap = new (ELeave) CFbsBitmap; + User::LeaveIfError( d_ptr->bitmap->Create( size, 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 &) +{ + if(!d_ptr->bitmap) + return; + + Q_ASSERT(!QS60WindowSurfacePrivate::lockedSurface); + QS60WindowSurfacePrivate::lockedSurface = this; + lockBitmapHeap(); +} + +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; + + TRect nativeRect(qt_QRect2TRect(rect)); + User::LeaveIfError(d_ptr->bitmap->Resize(nativeRect.Size())); + + updatePaintDeviceOnBitmap(); + + QWindowSurface::setGeometry(rect); +} + +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(); + 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..a238f5b --- /dev/null +++ b/src/gui/painting/qwindowsurface_s60_p.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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" + +QT_BEGIN_NAMESPACE + +struct QS60WindowSurfacePrivate; +class CFbsBitmap; + +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..58dcb98 --- /dev/null +++ b/src/gui/styles/qs60style.cpp @@ -0,0 +1,2451 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include "qs60style_p.h" +#include "qapplication.h" +#include "qpainter.h" +#include "qstyleoption.h" +#include "qresizeevent" +#include "qpixmapcache" +#include "qlistview.h" +#include "qcalendarwidget.h" +#include "qtabbar.h" +#include "qlistwidget.h" +#include "qmenu.h" +#include "qpushbutton.h" +#include "qmenubar.h" +#include "qtablewidget.h" +#include "private/qcombobox_p.h" +#include "private/qwidget_p.h" +#include "qscrollbar.h" +#include "qlist.h" +#include "qtableview.h" +#include "qheaderview.h" +#include "qtreeview.h" +#include "qdialog.h" +#include "qmessagebox.h" +#include "qerrormessage.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"; + +#if defined(QT_S60STYLE_LAYOUTDATA_SIMULATED) +const layoutHeader QS60StylePrivate::m_layoutHeaders[] = { +// *** generated layout data *** +{240,320,1,12,true,QLatin1String("QVGA Landscape Mirrored")}, +{240,320,1,12,false,QLatin1String("QVGA Landscape")}, +{320,240,1,12,true,QLatin1String("QVGA Portrait Mirrored")}, +{320,240,1,12,false,QLatin1String("QVGA Portrait")}, +{360,640,1,12,true,QLatin1String("NHD Landscape Mirrored")}, +{360,640,1,12,false,QLatin1String("NHD Landscape")}, +{640,360,1,12,true,QLatin1String("NHD Portrait Mirrored")}, +{640,360,1,12,false,QLatin1String("NHD Portrait")}, +{352,800,1,9,true,QLatin1String("E90 Landscape Mirrored")}, +{352,800,1,9,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,4,-909,0,0,-909,-909,-909,-909,-909,-909,37,21,51,27,51,4,4,5,3,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,5,-909,0,0,-909,-909,-909,-909,-909,-909,37,21,51,27,51,4,4,5,3,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,4,-909,0,0,-909,-909,-909,-909,-909,-909,37,21,65,27,65,4,4,5,3,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,5,-909,0,0,-909,-909,-909,-909,-909,-909,37,21,65,27,65,4,4,5,3,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,5,-909,0,0,-909,-909,-909,-909,-909,-909,87,27,77,35,77,5,5,6,3,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,7,-909,0,0,-909,-909,-909,-909,-909,-909,87,27,77,35,77,5,5,6,3,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,5,-909,0,0,-909,-909,-909,-909,-909,-909,87,27,98,35,98,5,5,6,3,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,7,-909,0,0,-909,-909,-909,-909,-909,-909,87,27,98,35,98,5,5,6,3,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,16,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,34,7,0,2,2,3,0,1,1,-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,16,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,34,7,0,3,2,2,0,1,1,-909,2,-909,-909,-909,-909,7,7,3,1} + +// *** End of generated data *** +}; + +const short *QS60StylePrivate::m_pmPointer = QS60StylePrivate::data[0]; +#endif // defined(QT_S60STYLE_LAYOUTDATA_SIMULATED) + +bool QS60StylePrivate::m_backgroundValid = false; + +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} +}; +static const int frameElementsCount = + int(sizeof(QS60StylePrivate::m_frameElementsData)/sizeof(QS60StylePrivate::m_frameElementsData[0])); + +const int KNotFound = -1; + +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() / 2 - 1, startRect.width())); + endRect = startRect.translated(rect.width() - startRect.width(), 0); + middleRect.adjust(startRect.width(), 0, -startRect.width(), 0); + } else { + startRect.setHeight(qMin(rect.height() / 2 - 1, startRect.height())); + endRect = startRect.translated(0, rect.height() - startRect.height()); + middleRect.adjust(0, startRect.height(), 0, -startRect.height()); + } + +#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 SkinElementFlags=%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() +{ + foreach (QWidget *topLevelWidget, QApplication::allWidgets()) { + topLevelWidget->updateGeometry(); + QCoreApplication::postEvent(topLevelWidget, new QResizeEvent(topLevelWidget->size(), topLevelWidget->size())); + } +} + +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; + default: + break; + } +} + +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_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; +} + + +void QS60StylePrivate::drawSkinPart(QS60StyleEnums::SkinParts part, + QPainter *painter, const QRect &rect, SkinElementFlags flags) +{ + drawPart(part, painter, rect, flags); +} + +void QS60StylePrivate::setStyleProperty(const char *name, const QVariant &value) +{ + if (name == propertyKeyCurrentlayout) { +#if !defined(QT_WS_S60) || defined(QT_S60STYLE_LAYOUTDATA_SIMULATED) + 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(); + return; +#else + qFatal("Cannot set static layout. Dynamic layouts are used!"); +#endif + } +} + +// 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 we need to guesstimate +// this 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); + const int rows = frameImage.numBytes()/(sizeof(QRgb)*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); + } + +} + +int QS60StylePrivate::focusRectPenWidth() +{ + return pixelMetric(QS60Style::PM_DefaultFrameWidth); +} + +void QS60StylePrivate::setThemePalette(QWidget *widget) const +{ + QPalette widgetPalette = QPalette(Qt::white); + + // basic colors + widgetPalette.setColor(QPalette::WindowText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0)); + widgetPalette.setColor(QPalette::ButtonText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0)); + widgetPalette.setColor(QPalette::Text, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0)); + widgetPalette.setColor(QPalette::ToolTipText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 55, 0)); + widgetPalette.setColor(QPalette::BrightText, widgetPalette.color(QPalette::WindowText).lighter()); + widgetPalette.setColor(QPalette::HighlightedText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 10, 0)); + widgetPalette.setColor(QPalette::Link, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnHighlightColors, 3, 0)); + widgetPalette.setColor(QPalette::LinkVisited, widgetPalette.color(QPalette::Link).darker()); + widgetPalette.setColor(QPalette::Highlight, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnHighlightColors, 2, 0)); + // set these as transparent so that styled full screen theme background is visible + widgetPalette.setColor(QPalette::AlternateBase, Qt::transparent); + widgetPalette.setColor(QPalette::Window, Qt::transparent); + widgetPalette.setColor(QPalette::Base, Qt::transparent); + // set button and tooltipbase based on pixel colors + QColor buttonColor = colorFromFrameGraphics(QS60StylePrivate::SF_ButtonNormal); + widgetPalette.setColor(QPalette::Button, buttonColor ); + widgetPalette.setColor(QPalette::Light, widgetPalette.color(QPalette::Button).lighter()); + widgetPalette.setColor(QPalette::Dark, widgetPalette.color(QPalette::Button).darker()); + widgetPalette.setColor(QPalette::Midlight, widgetPalette.color(QPalette::Button).lighter(125)); + widgetPalette.setColor(QPalette::Mid, widgetPalette.color(QPalette::Button).darker(150)); + widgetPalette.setColor(QPalette::Shadow, Qt::black); + QColor toolTipColor = colorFromFrameGraphics(QS60StylePrivate::SF_ToolTip); + widgetPalette.setColor(QPalette::ToolTipBase, toolTipColor ); + + // widget specific colors + if (QSlider *slider = qobject_cast<QSlider *>(widget)){ + widgetPalette.setColor(QPalette::All, QPalette::WindowText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors, 8, 0)); + } else if (QPushButton *button = qobject_cast<QPushButton *>(widget)){ + widgetPalette.setColor(QPalette::Active, QPalette::ButtonText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0)); + widgetPalette.setColor(QPalette::Inactive, QPalette::ButtonText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 6, 0)); + } else if (QHeaderView *table = qobject_cast<QHeaderView *>(widget)){ + widgetPalette.setColor(QPalette::Active, QPalette::ButtonText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 23, 0)); + } else if (QMenuBar *menuBar = qobject_cast<QMenuBar *>(widget)){ + widgetPalette.setColor(QPalette::All, QPalette::ButtonText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 8, 0)); + } else if (QTabBar *tabBar = qobject_cast<QTabBar *>(widget)){ + widgetPalette.setColor(QPalette::Active, QPalette::WindowText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 4, 0)); + } else if (QTableView *table = qobject_cast<QTableView *>(widget)){ + widgetPalette.setColor(QPalette::All, QPalette::Text, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 22, 0)); + } + + if (widget) + widget->setPalette(widgetPalette); +} + +void QS60Style::polish(QWidget *widget) +{ + Q_D(const QS60Style); + QCommonStyle::polish(widget); + + if (QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(widget)){ + scrollArea->viewport()->setAutoFillBackground(false); + } + + if (false +#ifndef QT_NO_SCROLLBAR + || qobject_cast<QScrollBar *>(widget) +#endif + ) { + widget->setAttribute(Qt::WA_OpaquePaintEvent, false); + } + if (QS60StylePrivate::isSkinnableDialog(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); + } + + if (widget){ + d->setThemePalette(widget); + } + +} + +void QS60Style::unpolish(QWidget *widget) +{ + if (QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(widget)){ + scrollArea->viewport()->setAutoFillBackground(true); + } + + if (false +#ifndef QT_NO_SCROLLBAR + || qobject_cast<QScrollBar *>(widget) +#endif + ) { + widget->setAttribute(Qt::WA_OpaquePaintEvent); + } + if (QS60StylePrivate::isSkinnableDialog(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); +} + +QVariant QS60StylePrivate::styleProperty(const char *name) const +{ + if (name == propertyKeyLayouts) { +#if !defined(QT_WS_S60) || defined(QT_S60STYLE_LAYOUTDATA_SIMULATED) + static QStringList layouts; + if (layouts.isEmpty()) + for (int i = 0; i < QS60StylePrivate::m_numberOfLayouts; i++) + layouts.append(QS60StylePrivate::m_layoutHeaders[i].layoutName); + return layouts; +#else + qFatal("Cannot return list of 'canned' static layouts. Dynamic layouts are used!"); +#endif + } + return QVariant(); +} + +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; +} + +//todo: you could pass a reason to clear cache here, so that we could +// deduce whether or not the specific cache needs to be cleared +void QS60StylePrivate::clearCaches() +{ + m_colorCache.clear(); + m_mappedFontsCache.clear(); + QPixmapCache::clear(); + m_backgroundValid = false; +} + +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::isSkinnableDialog(const QWidget *widget) +{ + return (qobject_cast<const QMessageBox *> (widget) || + qobject_cast<const QErrorMessage *> (widget)); +} + +#if !defined(QT_WS_S60) || defined(QT_S60STYLE_LAYOUTDATA_SIMULATED) +void QS60StylePrivate::setCurrentLayout(int index) +{ + m_pmPointer = data[index]; +} +#endif + +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; +} + +/*! + \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 +*/ + +/*! + Constructs a QS60Style object. +*/ +QS60Style::QS60Style() + : QCommonStyle(*new QS60StylePrivate) +{ +} + +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 QS60StylePrivate::SkinElements handleElement = + horizontal ? QS60StylePrivate::SE_ScrollBarHandleHorizontal : 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 + //todo: why calc rect here for button? Is there no suitable SE_xxx for that? + 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); + // todo: we could draw qgn_prop_set_button skin item here + + // draw label background - label itself is drawn separately + const QS60StylePrivate::SkinElements skinElement = QS60StylePrivate::SE_FrameLineEdit; + QS60StylePrivate::drawSkinElement(skinElement, painter, cmbxEditField, flags); + + if (sub & SC_ComboBoxArrow) { + const int iconRectWidth = buttonOption.rect.width()>>1; + const int nudgeWidth =iconRectWidth>>1; + + // Draw the little arrow + const QRect arrowRect(((buttonOption.rect.left()+buttonOption.rect.right())>>1) - nudgeWidth, + buttonOption.rect.center().y()-(buttonOption.rect.height()>>2)+nudgeWidth, iconRectWidth, iconRectWidth); + + 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 label = *toolBtn; + + if (sub&SC_ToolButton) { + QStyleOption tool(0); + tool.palette = toolBtn->palette; + if (bflags & (State_Sunken | State_On | State_Raised)) { + tool.rect = button; + tool.state = bflags; + 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; } + label.rect = button; + drawPrimitive(pe, &label, painter, widget); + } + + if (toolBtn->text.length()>0 || + !toolBtn->icon.isNull()) { + const int frameWidth = pixelMetric(PM_DefaultFrameWidth, option, widget); + label.rect = button.adjusted(frameWidth, frameWidth, -frameWidth, -frameWidth); + drawControl(CE_ToolButtonLabel, &label, 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; + + // Let the base class draw the wole thing except the qDrawWinPanel 'frame' with Windows95-look + copy.frame = false; + QCommonStyle::drawComplexControl(control, ©, 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 + + //todo: remove non-used complex widgets in final version + case CC_TitleBar: +#ifdef QT3_SUPPORT + case CC_Q3ListView: +#endif //QT3_SUPPORT +#ifndef QT_NO_DIAL + case CC_Dial: +#endif //QT_NO_DIAL +#ifndef QT_NO_WORKSPACE + case CC_MdiControls: +#endif //QT_NO_WORKSPACE + 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_PushButtonBevel: + { + 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; + case CE_PushButtonLabel: + if (const QStyleOptionButton *button = qstyleoption_cast<const QStyleOptionButton *>(option)) { + QStyleOptionButton optionButton = *button; + int margins = 2*QS60StylePrivate::pixelMetric(QStyle::PM_ButtonMargin); + // make sure that margins do not take too much space from button + if (margins > optionButton.rect.height()/3) // TODO: (?) Remove this when s60Fonts are set by polish(QWidget*) + margins = optionButton.rect.height()/3; + const QFont suggestedFont = d->s60Font( + QS60StyleEnums::FC_Primary, painter->font().pointSizeF()); + painter->save(); + painter->setFont(suggestedFont); + QCommonStyle::drawControl(element, &optionButton, painter, widget); + painter->restore(); + } + break; + case CE_CheckBoxLabel: + if (const QStyleOptionButton *checkBox = qstyleoption_cast<const QStyleOptionButton *>(option)) { + QStyleOptionButton optionCheckBox = *checkBox; + QCommonStyle::drawControl(element, &optionCheckBox, painter, widget); + } + break; + case CE_RadioButtonLabel: + if (const QStyleOptionButton *radioButton = qstyleoption_cast<const QStyleOptionButton *>(option)) { + QStyleOptionButton optionRadioButton = *radioButton; + QCommonStyle::drawControl(element, &optionRadioButton, painter, widget); + } + break; +#ifndef QT_NO_TOOLBUTTON + case CE_ToolButtonLabel: + if (const QStyleOptionToolButton *toolBtn = qstyleoption_cast<const QStyleOptionToolButton *>(option)) { + QStyleOptionToolButton optionToolButton = *toolBtn; + QCommonStyle::drawControl(element, &optionToolButton, painter, widget); + } + break; +#endif //QT_NO_TOOLBUTTON + case CE_HeaderLabel: + if (const QStyleOptionHeader *headerLabel = qstyleoption_cast<const QStyleOptionHeader *>(option)) { + QStyleOptionHeader optionHeaderLabel = *headerLabel; + // Adjust font according S60 Look-and-Feel + const QFont suggestedFont = d->s60Font( + QS60StyleEnums::FC_Secondary, painter->font().pointSizeF()); + painter->save(); + painter->setFont(suggestedFont); + QCommonStyle::drawControl(element, &optionHeaderLabel, painter, widget); + painter->restore(); + } + break; +#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 the background + const QStyleOptionViewItemV4 *tableOption = qstyleoption_cast<const QStyleOptionViewItemV4 *>(option); + const QTableView *table = qobject_cast<const QTableView *>(widget); + if (table && tableOption) { + const QModelIndex indexCurrent = tableOption->index; + // Draw cell background only once - for the first cell + //todo: calc area based on viewport only so that 1000x1000 table doesn't get ridiculously big background + //todo: try to do this only once. For some reason, if I try to + //if ( indexCurrent.column() == 2 && indexCurrent.row() == 2 ) { + QStyleOptionViewItemV4 voptAdj2 = voptAdj2; + const QModelIndex index = table->model()->index(0,0); + const QModelIndex indexLast = table->model()->index( + table->model()->rowCount()-1,table->model()->columnCount()-1); + voptAdj2.rect = QRect( table->visualRect(index).topLeft(), table->visualRect(indexLast).bottomRight()); + drawPrimitive(PE_PanelItemViewItem, &voptAdj2, 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); + 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 + //QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_TableHeaderItem, painter, windowRect, flags); + + 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() * 0.72); + painter->setFont(f); + + if (option->state & QStyle::State_Selected){ + optionTab.palette.setColor(QPalette::Active, QPalette::WindowText, + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 3, option)); + } + + bool verticalTabs = optionTab.shape == QTabBar::RoundedEast + || optionTab.shape == QTabBar::RoundedWest + || optionTab.shape == QTabBar::TriangularEast + || optionTab.shape == QTabBar::TriangularWest; + bool selected = optionTab.state & State_Selected; + if (verticalTabs) { + painter->save(); + int newX, newY, newRot; + if (optionTab.shape == QTabBar::RoundedEast || optionTab.shape == QTabBar::TriangularEast) { + newX = tr.width(); + newY = tr.y(); + newRot = 90; + } else { + newX = 0; + newY = tr.y() + tr.height(); + newRot = -90; + } + tr.setRect(0, 0, tr.height(), tr.width()); + QTransform m; + m.translate(newX, newY); + m.rotate(newRot); + 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 x1 = optionTab.rect.left(); + const int x2 = optionTab.rect.right() - 1; + + QStyleOptionFocusRect fropt; + fropt.QStyleOption::operator=(*tab); + fropt.rect.setRect(x1 + 1 + OFFSET, optionTab.rect.y() + OFFSET, + x2 - x1 - 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; + 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_MENUBAR + case CE_MenuBarItem: + if (const QStyleOptionMenuItem *menuBarItem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) { + QStyleOptionMenuItem optionMenuBarItem = *menuBarItem; + QCommonStyle::drawControl(element, &optionMenuBarItem, painter, widget); + } + break; +#endif //QT_NO_MENUBAR +#ifndef QT_NO_MENU + case CE_MenuItem: + if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) { + QStyleOptionMenuItem optionMenuItem = *menuItem; + 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); + 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; + } + + 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); + QStyleOptionMenuItem optionCheckBox; + if (checkable){ + QRect checkBoxRect = optionMenuItem.rect; + checkBoxRect.setWidth(pixelMetric(PM_IndicatorWidth)); + checkBoxRect.setHeight(pixelMetric(PM_IndicatorHeight)); + optionCheckBox.QStyleOption::operator=(*menuItem); + optionCheckBox.rect = checkBoxRect; + const int moveByX = checkBoxRect.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); + painter->restore(); + } else { + QCommonStyle::drawItemText(painter, textRect, text_flags, + optionMenuItem.palette, enabled, + optionMenuItem.text, QPalette::Text); + } + } + break; +#endif //QT_NO_MENU + + //todo: remove non-used widgets in final version + case CE_MenuEmptyArea: +#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 mtyRect = option->rect; + if (option->state & QStyle::State_Horizontal) { + mtyRect.adjust(-2,-2,2,-2); + } else { + if ( option->direction == Qt::LeftToRight ) { + mtyRect.adjust(-2,-2,0,2); + adjFlags |= QS60StylePrivate::SF_PointWest; + } else { + mtyRect.adjust(2,2,0,-2); + adjFlags |= QS60StylePrivate::SF_PointEast; + } + } + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_TableHeaderItem, painter, mtyRect, 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(); + if (header->orientation == Qt::Horizontal) { + mtyRect.adjust(-2,-2,2,-2); + } else { + if ( header->direction == Qt::LeftToRight ) { + mtyRect.adjust(-2,-2,0,2); + adjFlags |= QS60StylePrivate::SF_PointWest; + } else { + mtyRect.adjust(2,2,0,-2); + adjFlags |= QS60StylePrivate::SF_PointEast; + } + } + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_TableHeaderItem, painter, mtyRect, adjFlags); + QCommonStyle::drawControl(element, header, painter, widget); + } + break; + case CE_ShapedFrame: + case CE_MenuVMargin: + case CE_MenuHMargin: +#ifndef QT_NO_MENU + case CE_MenuScroller: + case CE_MenuTearoff: +#endif //QT_NO_MENU + + case CE_PushButton: + case CE_CheckBox: + case CE_RadioButton: +#ifndef QT_NO_TABBAR + case CE_TabBarTab: +#endif //QT_NO_TABBAR +#ifndef QT_NO_PROGRESSBAR + case CE_ProgressBar: +#endif // QT_NO_PROGRESSBAR + case CE_Q3DockWindowEmptyArea: +#ifndef QT_NO_SIZEGRIP + case CE_SizeGrip: +#endif //QT_NO_SIZEGRIP + case CE_Splitter: +#ifndef QT_NO_RUBBERBAND + case CE_RubberBand: +#endif //QT_NO_RUBBERBAND +#ifndef QT_NO_DOCKWIDGET + case CE_DockWidgetTitle: +#endif //QT_NO_DOCKWIDGET + case CE_ScrollBarAddLine: + case CE_ScrollBarSubLine: + case CE_ScrollBarAddPage: + case CE_ScrollBarSubPage: + case CE_ScrollBarSlider: + case CE_ScrollBarFirst: + case CE_ScrollBarLast: + case CE_FocusFrame: +#ifndef QT_NO_TOOLBAR + case CE_ToolBar: +#endif //QT_NO_TOOLBAR +#ifndef QT_NO_TOOLBOX + case CE_ToolBoxTab: + case CE_ToolBoxTabShape: + case CE_ToolBoxTabLabel: +#endif //QT_NO_TOOLBOX + case CE_ColumnViewGrip: + 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: + 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) { + QS60StyleEnums::SkinParts skinPart = QS60StyleEnums::SP_QgnIndiMarkedAdd; + QS60StylePrivate::drawSkinPart(skinPart, painter, option->rect, + (flags | QS60StylePrivate::SF_ColorSkinned)); + } + } + } + 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: + { + if (option->rect.width() <= 1 || option->rect.height() <= 1) + break; + QRect r = option->rect; + int size = qMin(r.height(), r.width()); + int border = size/5; + int sqsize = 2*(size>>1); + QImage image(sqsize, sqsize, QImage::Format_ARGB32); + image.fill(Qt::transparent); + QPainter imagePainter(&image); + + QPolygon a; + int halfsqsize = sqsize>>1; + int borderlessSqSize = sqsize - border; + switch (element) { + case PE_IndicatorArrowUp: + a.setPoints(3, border, halfsqsize, halfsqsize, border, borderlessSqSize, halfsqsize); + break; + case PE_IndicatorArrowDown: + a.setPoints(3, border, halfsqsize, halfsqsize, borderlessSqSize, borderlessSqSize, halfsqsize); + break; + case PE_IndicatorArrowRight: + a.setPoints(3, borderlessSqSize, halfsqsize, halfsqsize, border, halfsqsize, borderlessSqSize); + break; + case PE_IndicatorArrowLeft: + a.setPoints(3, border, halfsqsize, halfsqsize, border, halfsqsize, borderlessSqSize); + break; + default: + break; + } + + int bsx = 0; + int bsy = 0; + + if (option->state & State_Sunken) { + bsx = pixelMetric(PM_ButtonShiftHorizontal); + bsy = pixelMetric(PM_ButtonShiftVertical); + } + + QRect bounds = a.boundingRect(); + int sx = halfsqsize - bounds.center().x() - 1; + int sy = halfsqsize - bounds.center().y() - 1; + QPalette themeColor = option->palette; + imagePainter.translate(sx + bsx, sy + bsy); + imagePainter.setPen(themeColor.buttonText().color()); + + if (!(option->state & State_Enabled)) { + imagePainter.translate(1, 1); + imagePainter.setPen(themeColor.light().color()); + imagePainter.drawPolygon(a); + imagePainter.translate(-1, -1); + imagePainter.setPen(themeColor.mid().color()); + } + imagePainter.drawPolygon(a); + imagePainter.end(); + int xOffset = r.x() + ((r.width() - size)>>1); + int yOffset = r.y() + ((r.height() - size)>>1); + + painter->drawImage(xOffset, yOffset, image); + } + break; +#endif //QT_NO_TOOLBUTTON +#ifndef QT_NO_SPINBOX + case PE_IndicatorSpinDown: + case PE_IndicatorSpinUp: + case PE_IndicatorSpinMinus: + case PE_IndicatorSpinPlus: + { + if (const QStyleOptionSpinBox *spinBox = qstyleoption_cast<const QStyleOptionSpinBox *>(option)) { + QStyleOptionSpinBox optionSpinBox = *spinBox; + if (element==PE_IndicatorSpinDown || element==PE_IndicatorSpinUp) + optionSpinBox.rect.adjust(2,2,-2,-2); + QCommonStyle::drawPrimitive(element, &optionSpinBox, painter, widget); + } else if (const QStyleOptionFrame *cmb = qstyleoption_cast<const QStyleOptionFrame *>(option)) { + // We want to draw down arrow here for comboboxes as well. + QStyleOptionFrame comboBox = *cmb; + comboBox.rect.adjust(0,2,0,-2); + QCommonStyle::drawPrimitive(element, &comboBox, painter, widget); + } + } + break; +#endif //QT_NO_SPINBOX + case PE_FrameFocusRect: + 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::isSkinnableDialog(widget) || + qobject_cast<const QComboBoxListView *>(widget) || + qobject_cast<const QMenu *> (widget)) { + 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; + + const QColor baseColor(QS60StylePrivate::lighterColor( + QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors, 3, option))); + const QPalette tabPalette(baseColor); + optionTabFrame.palette = tabPalette; + QCommonStyle::drawPrimitive(element, &optionTabFrame, painter, widget); + } + } + 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; + + case PE_PanelMenuBar: + case PE_FrameMenu: + break; //disable frame in menu + + // todo: items are below with #ifdefs "just in case". in final version, remove all non-required cases + case PE_FrameLineEdit: + case PE_IndicatorBranch: + 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: + case PE_IndicatorToolBarHandle: + case PE_IndicatorToolBarSeparator: +#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 - sets the default colors +*/ +void QS60Style::drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette & palette, bool enabled, const QString &text, QPalette::ColorRole textRole) const +{ + QPalette override = palette; + QCommonStyle::drawItemText(painter, rectangle, alignment, override, enabled, text, textRole); +} + +/*! + \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 int widgetWidth = widget->width(); + 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_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: { + QColor lineColor = QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors,2,0); + retValue = lineColor.rgb(); + } + break; + case SH_GroupBox_TextLabelColor: { + QColor groupBoxTxtColor = QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnTextColors,6,0); + retValue = groupBoxTxtColor.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; + 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_ScrollBarSubLine: // top/left button + case SC_ScrollBarAddLine: // bottom/right button + break; + 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; + 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 = 2; //spinbox->frame ? /*QS60StylePrivate::pixelMetric(QStyle::PM_ButtonMargin)*/2 : 0; + const int buttonWidth = + QS60StylePrivate::pixelMetric(QStyle::PM_ButtonIconSize) + 2*buttonMargin; + //todo: buttonMargin commented out as WAY too big in pixel metrics + QSize buttonSize; + buttonSize.setHeight(qMax(8, spinbox->rect.height()/2 - 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 - 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, y + buttonSize.height(), 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(); + //todo: buttonMargin commented out as WAY too big in pixel metrics + const int buttonMargin = cmb->frame ? /*QS60StylePrivate::pixelMetric(QStyle::PM_ButtonMargin)*/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); + 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); + const int bottomMargin = QS60StylePrivate::pixelMetric(QStyle::PM_LayoutBottomMargin); + 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. + // todo: Should we NOT do this for combo boxes and spin boxes? + QRect lineEditRect = opt->rect; + 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 bool subMenu = menuItem->menuItemType == QStyleOptionMenuItem::SubMenu; + int indicatorWidth = checkable ? + pixelMetric(PM_ListViewIconSize, opt, widget) : + pixelMetric(PM_SmallIconSize, opt, widget); + ret = menuItem->rect; + const int verticalSpacing = + QS60StylePrivate::pixelMetric(QStyle::PM_LayoutVerticalSpacing); + + 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 + indicatorWidth = indicatorWidth >> 1; + if (menuItem->direction == Qt::LeftToRight) + ret.adjust(0,0,-indicatorWidth,0); + else + ret.adjust(indicatorWidth,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 + 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); + } + } + } + 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::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; + 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); +} + +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..253eb61 --- /dev/null +++ b/src/gui/styles/qs60style.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_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; + void drawItemText(QPainter *painter, const QRect &rectangle, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) 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 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); +#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..c11d89a --- /dev/null +++ b/src/gui/styles/qs60style_p.h @@ -0,0 +1,368 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_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_QgnGrafBarFrameCenter, + SP_QgnGrafBarFrameSideL, + SP_QgnGrafBarFrameSideR, + SP_QgnGrafBarProgress, + SP_QgnGrafTabActiveL, + SP_QgnGrafTabActiveM, + SP_QgnGrafTabActiveR, + SP_QgnGrafTabPassiveL, + SP_QgnGrafTabPassiveM, + SP_QgnGrafTabPassiveR, + SP_QgnIndiCheckboxOff, + SP_QgnIndiCheckboxOn, + 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_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 + }; + + 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 + }; + + enum SkinFrameElements { + SF_ButtonNormal, + SF_ButtonPressed, + SF_FrameLineEdit, + SF_ListHighlight, + SF_OptionsMenu, + SF_SettingsList, + SF_TableItem, + SF_TableHeaderItem, + SF_ToolTip + }; + + 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, + }; + 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); + static QColor lighterColor(const QColor &baseColor); + static bool isSkinnableDialog(const QWidget *widget); + // gets layout + static const QHash<QStyle::PixelMetric, int> &s60StyleLayout(); + + QFont s60Font(QS60StyleEnums::FontCategories fontCategory, + int pointSize = -1) const; + void clearCaches(); + static QPixmap backgroundTexture(); + + static bool isTouchSupported(); + // calculates average color based on button skin graphics (minus borders). + QColor colorFromFrameGraphics(QS60StylePrivate::SkinFrameElements frame) const; + void setThemePalette(QWidget *widget) const; + + static int focusRectPenWidth(); + +#if defined(QT_S60STYLE_LAYOUTDATA_SIMULATED) + 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; +#endif // defined(QT_S60STYLE_LAYOUTDATA_SIMULATED) + + mutable QHash<QPair<QS60StyleEnums::FontCategories , int>, QFont> m_mappedFontsCache; + mutable QHash<QS60StylePrivate::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); + +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 QSize partSize(QS60StyleEnums::SkinParts part, + SkinElementFlags flags = KDefaultSkinElementFlags); + static QPixmap part(QS60StyleEnums::SkinParts part, const QSize &size, + 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 QFont s60Font_specific(QS60StyleEnums::FontCategories fontCategory, int pointSize); + + static void refreshUI(); + + static QSize screenSize(); + + static bool m_backgroundValid; + const static SkinElementFlags KDefaultSkinElementFlags; +}; + +QT_END_NAMESPACE + +#endif // QS60STYLE_P_H diff --git a/src/gui/styles/qs60style_simulated.cpp b/src/gui/styles/qs60style_simulated.cpp new file mode 100644 index 0000000..68f0b70 --- /dev/null +++ b/src/gui/styles/qs60style_simulated.cpp @@ -0,0 +1,269 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_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" + +#if !defined(QT_NO_STYLE_S60) || defined(QT_PLUGIN) + +QT_BEGIN_NAMESPACE + +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); +} + +QS60StylePrivate::~QS60StylePrivate() +{ +} + +short QS60StylePrivate::pixelMetric(int metric) +{ + Q_ASSERT(metric < MAX_PIXELMETRICS); + const short returnValue = m_pmPointer[metric]; + if (returnValue==-909) + return -1; + return returnValue; +} + +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) { + // TODO: fix this + QStyleOption opt; +// opt.palette = q->standardPalette(); + 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); + 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); +} + +bool QS60StylePrivate::isTouchSupported() +{ +#ifdef QT_KEYPAD_NAVIGATION + return !QApplication::keypadNavigationEnabled(); +#else + return true; +#endif +} + +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; +} + +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) +{ + QS60StyleModeSpecifics::m_partPictures = parts; + QS60StyleModeSpecifics::m_colors = colors; +} + +QT_END_NAMESPACE + +#endif // QT_NO_STYLE_S60 || QT_PLUGIN diff --git a/src/gui/styles/qs60style_symbian.cpp b/src/gui/styles/qs60style_symbian.cpp new file mode 100644 index 0000000..a1e7800 --- /dev/null +++ b/src/gui/styles/qs60style_symbian.cpp @@ -0,0 +1,980 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_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_3_1 = 0x0001, + ES60_3_2 = 0x0002, + ES60_5_0 = 0x0004, + // Add all new releases here + ES60_AllReleases = ES60_3_1 | ES60_3_2 | ES60_5_0 +}; + +typedef struct { + const TAknsItemID &skinID; + TDrawType drawType; + int supportInfo; + int fallbackGraphicID; + 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); + +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 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 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_QgnGrafBarFrameCenter */ {KAknsIIDQgnGrafBarFrameCenter, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_graf_bar_frame_center ,-1,-1}, + /* SP_QgnGrafBarFrameSideL */ {KAknsIIDQgnGrafBarFrameSideL, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_graf_bar_frame_side_l ,-1,-1}, + /* SP_QgnGrafBarFrameSideR */ {KAknsIIDQgnGrafBarFrameSideR, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_graf_bar_frame_side_r ,-1,-1}, + /* SP_QgnGrafBarProgress */ {KAknsIIDQgnGrafBarProgress, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_graf_bar_progress ,-1,-1}, + /* SP_QgnGrafTabActiveL */ {KAknsIIDQgnGrafTabActiveL, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_graf_tab_active_l ,-1,-1}, + /* SP_QgnGrafTabActiveM */ {KAknsIIDQgnGrafTabActiveM, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_graf_tab_active_m ,-1,-1}, + /* SP_QgnGrafTabActiveR */ {KAknsIIDQgnGrafTabActiveR, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_graf_tab_active_r ,-1,-1}, + /* SP_QgnGrafTabPassiveL */ {KAknsIIDQgnGrafTabPassiveL, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_graf_tab_passive_l ,-1,-1}, + /* SP_QgnGrafTabPassiveM */ {KAknsIIDQgnGrafTabPassiveM, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_graf_tab_passive_m ,-1,-1}, + /* SP_QgnGrafTabPassiveR */ {KAknsIIDQgnGrafTabPassiveR, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_graf_tab_passive_r ,-1,-1}, + /* SP_QgnIndiCheckboxOff */ {KAknsIIDQgnIndiCheckboxOff, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_indi_checkbox_off ,-1,-1}, + /* SP_QgnIndiCheckboxOn */ {KAknsIIDQgnIndiCheckboxOn, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_indi_checkbox_on ,-1,-1}, + /* SP_QgnIndiMarkedAdd */ {KAknsIIDQgnIndiMarkedAdd, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_indi_marked_add ,-1,-1}, + /* SP_QgnIndiNaviArrowLeft */ {KAknsIIDQgnGrafScrollArrowLeft, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_indi_navi_arrow_left ,-1,-1}, + /* SP_QgnIndiNaviArrowRight */ {KAknsIIDQgnGrafScrollArrowRight, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_indi_navi_arrow_right ,-1,-1}, + /* SP_QgnIndiRadiobuttOff */ {KAknsIIDQgnIndiRadiobuttOff, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_indi_radiobutt_off ,-1,-1}, + /* SP_QgnIndiRadiobuttOn */ {KAknsIIDQgnIndiRadiobuttOn, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_indi_radiobutt_on ,-1,-1}, + /* SP_QgnIndiSliderEdit */ {KAknsIIDQgnIndiSliderEdit, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_indi_slider_edit ,-1,-1}, + /* SP_QgnIndiSubMenu */ {KAknsIIDQgnIndiSubmenu, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_indi_submenu ,-1,-1}, + /* SP_QgnNoteErased */ {KAknsIIDQgnNoteErased, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_note_erased ,-1,-1}, + /* SP_QgnNoteError */ {KAknsIIDQgnNoteError, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_note_error ,-1,-1}, + /* SP_QgnNoteInfo */ {KAknsIIDQgnNoteInfo, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_note_info ,-1,-1}, + /* SP_QgnNoteOk */ {KAknsIIDQgnNoteOk, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_note_ok ,-1,-1}, + /* SP_QgnNoteQuery */ {KAknsIIDQgnNoteQuery, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_note_query ,-1,-1}, + /* SP_QgnNoteWarning */ {KAknsIIDQgnNoteWarning, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_note_warning ,-1,-1}, + /* SP_QgnPropFileSmall */ {KAknsIIDQgnPropFileSmall, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_prop_file_small ,-1,-1}, + /* SP_QgnPropFolderCurrent */ {KAknsIIDQgnPropFolderCurrent, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_prop_folder_current ,-1,-1}, + /* SP_QgnPropFolderSmall */ {KAknsIIDQgnPropFolderSmall, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_prop_folder_small ,-1,-1}, + /* SP_QgnPropFolderSmallNew */ {KAknsIIDQgnPropFolderSmallNew, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_prop_folder_small_new ,-1,-1}, + /* SP_QgnPropPhoneMemcLarge */ {KAknsIIDQgnPropPhoneMemcLarge, EDrawIcon, ES60_AllReleases, EMbmAvkonQgn_prop_phone_memc_large ,-1,-1}, + +// No fallback graphics for screen elements (it is guaranteed that the root skin contains these). + /* SP_QsnBgScreen */ {KAknsIIDQsnBgScreen, EDrawBackground, ES60_AllReleases, -1,-1,-1}, + + /* SP_QsnCpScrollBgBottom */ {KAknsIIDQsnCpScrollBgBottom, EDrawIcon, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnCpScrollBgMiddle */ {KAknsIIDQsnCpScrollBgMiddle, EDrawIcon, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnCpScrollBgTop */ {KAknsIIDQsnCpScrollBgTop, EDrawIcon, ES60_AllReleases, -1,-1,-1}, + + /* SP_QsnCpScrollHandleBottom */ {KAknsIIDQsnCpScrollHandleBottom, EDrawIcon, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnCpScrollHandleMiddle */ {KAknsIIDQsnCpScrollHandleMiddle, EDrawIcon, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnCpScrollHandleTop */ {KAknsIIDQsnCpScrollHandleTop, EDrawIcon, ES60_AllReleases, -1,-1,-1}, + + /* SP_QsnFrButtonTbCornerTl */ {KAknsIIDQsnFrButtonTbCornerTl, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrButtonTbCornerTr */ {KAknsIIDQsnFrButtonTbCornerTr, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrButtonTbCornerBl */ {KAknsIIDQsnFrButtonTbCornerBl, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrButtonTbCornerBr */ {KAknsIIDQsnFrButtonTbCornerBr, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrButtonTbSideT */ {KAknsIIDQsnFrButtonTbSideT, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrButtonTbSideB */ {KAknsIIDQsnFrButtonTbSideB, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrButtonTbSideL */ {KAknsIIDQsnFrButtonTbSideL, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrButtonTbSideR */ {KAknsIIDQsnFrButtonTbSideR, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrButtonTbCenter */ {KAknsIIDQsnFrButtonTbCenter, ENoDraw, ES60_AllReleases, -1,-1,-1}, + + /* SP_QsnFrButtonTbCornerTlPressed */{KAknsIIDQsnFrButtonTbCornerTlPressed, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrButtonTbCornerTrPressed */{KAknsIIDQsnFrButtonTbCornerTrPressed, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrButtonTbCornerBlPressed */{KAknsIIDQsnFrButtonTbCornerBlPressed, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrButtonTbCornerBrPressed */{KAknsIIDQsnFrButtonTbCornerBrPressed, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrButtonTbSideTPressed */ {KAknsIIDQsnFrButtonTbSideTPressed, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrButtonTbSideBPressed */ {KAknsIIDQsnFrButtonTbSideBPressed, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrButtonTbSideLPressed */ {KAknsIIDQsnFrButtonTbSideLPressed, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrButtonTbSideRPressed */ {KAknsIIDQsnFrButtonTbSideRPressed, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrButtonTbCenterPressed */ {KAknsIIDQsnFrButtonTbCenterPressed, ENoDraw, ES60_AllReleases, -1,-1,-1}, + + /* SP_QsnFrCaleCornerTl */ {KAknsIIDQsnFrCaleCornerTl, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrCaleCornerTr */ {KAknsIIDQsnFrCaleCornerTr, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrCaleCornerBl */ {KAknsIIDQsnFrCaleCornerBl, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrCaleCornerBr */ {KAknsIIDQsnFrCaleCornerBr, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrCaleGSideT */ {KAknsIIDQsnFrCaleSideT, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrCaleGSideB */ {KAknsIIDQsnFrCaleSideB, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrCaleGSideL */ {KAknsIIDQsnFrCaleSideL, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrCaleGSideR */ {KAknsIIDQsnFrCaleSideR, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrCaleCenter */ {KAknsIIDQsnFrCaleCenter, ENoDraw, ES60_AllReleases, -1,-1,-1}, + + /* SP_QsnFrCaleHeadingCornerTl */ {KAknsIIDQsnFrCaleHeadingCornerTl, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrCaleHeadingCornerTr */ {KAknsIIDQsnFrCaleHeadingCornerTr, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrCaleHeadingCornerBl */ {KAknsIIDQsnFrCaleHeadingCornerBl, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrCaleHeadingCornerBr */ {KAknsIIDQsnFrCaleHeadingCornerBr, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrCaleHeadingSideT */ {KAknsIIDQsnFrCaleHeadingSideT, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrCaleHeadingSideB */ {KAknsIIDQsnFrCaleHeadingSideB, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrCaleHeadingSideL */ {KAknsIIDQsnFrCaleHeadingSideL, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrCaleHeadingSideR */ {KAknsIIDQsnFrCaleHeadingSideR, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrCaleHeadingCenter */ {KAknsIIDQsnFrCaleHeadingCenter, ENoDraw, ES60_AllReleases, -1,-1,-1}, + + /* SP_QsnFrInputCornerTl */ {KAknsIIDQsnFrInputCornerTl, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrInputCornerTr */ {KAknsIIDQsnFrInputCornerTr, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrInputCornerBl */ {KAknsIIDQsnFrInputCornerBl, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrInputCornerBr */ {KAknsIIDQsnFrInputCornerBr, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrInputSideT */ {KAknsIIDQsnFrInputSideT, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrInputSideB */ {KAknsIIDQsnFrInputSideB, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrInputSideL */ {KAknsIIDQsnFrInputSideL, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrInputSideR */ {KAknsIIDQsnFrInputSideR, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrInputCenter */ {KAknsIIDQsnFrInputCenter, ENoDraw, ES60_AllReleases, -1,-1,-1}, + + /* SP_QsnFrListCornerTl */ {KAknsIIDQsnFrListCornerTl, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrListCornerTr */ {KAknsIIDQsnFrListCornerTr, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrListCornerBl */ {KAknsIIDQsnFrListCornerBl, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrListCornerBr */ {KAknsIIDQsnFrListCornerBr, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrListSideT */ {KAknsIIDQsnFrListSideT, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrListSideB */ {KAknsIIDQsnFrListSideB, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrListSideL */ {KAknsIIDQsnFrListSideL, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrListSideR */ {KAknsIIDQsnFrListSideR, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrListCenter */ {KAknsIIDQsnFrListCenter, ENoDraw, ES60_AllReleases, -1,-1,-1}, + + /* SP_QsnFrPopupCornerTl */ {KAknsIIDQsnFrPopupCornerTl, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrPopupCornerTr */ {KAknsIIDQsnFrPopupCornerTr, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrPopupCornerBl */ {KAknsIIDQsnFrPopupCornerBl, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrPopupCornerBr */ {KAknsIIDQsnFrPopupCornerBr, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrPopupSideT */ {KAknsIIDQsnFrPopupSideT, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrPopupSideB */ {KAknsIIDQsnFrPopupSideB, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrPopupSideL */ {KAknsIIDQsnFrPopupSideL, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrPopupSideR */ {KAknsIIDQsnFrPopupSideR, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrPopupCenter */ {KAknsIIDQsnFrPopupCenter, ENoDraw, ES60_AllReleases, -1,-1,-1}, + + + /* SP_QsnFrPopupPreviewCornerTl */ {KAknsIIDQsnFrPopupCornerTl, ENoDraw, ES60_3_1, -1, EAknsMajorSkin, 0x19c5}, + /* SP_QsnFrPopupPreviewCornerTr */ {KAknsIIDQsnFrPopupCornerTr, ENoDraw, ES60_3_1, -1, EAknsMajorSkin, 0x19c6}, + /* SP_QsnFrPopupPreviewCornerBl */ {KAknsIIDQsnFrPopupCornerBl, ENoDraw, ES60_3_1, -1, EAknsMajorSkin, 0x19c3}, + /* SP_QsnFrPopupPreviewCornerBr */ {KAknsIIDQsnFrPopupCornerBr, ENoDraw, ES60_3_1, -1, EAknsMajorSkin, 0x19c4}, + /* SP_QsnFrPopupPreviewSideT */ {KAknsIIDQsnFrPopupSideT, ENoDraw, ES60_3_1, -1, EAknsMajorSkin, 0x19ca}, + /* SP_QsnFrPopupPreviewSideB */ {KAknsIIDQsnFrPopupSideB, ENoDraw, ES60_3_1, -1, EAknsMajorSkin, 0x19c7}, + /* SP_QsnFrPopupPreviewSideL */ {KAknsIIDQsnFrPopupSideL, ENoDraw, ES60_3_1, -1, EAknsMajorSkin, 0x19c8}, + /* SP_QsnFrPopupPreviewSideR */ {KAknsIIDQsnFrPopupSideR, ENoDraw, ES60_3_1, -1, EAknsMajorSkin, 0x19c9}, + /* SP_QsnFrPopupPreviewCenter */ {KAknsIIDQsnFrPopupCenter, ENoDraw, ES60_3_1, -1, EAknsMajorSkin, 0x19c2}, + + /* SP_QsnFrSetOptCornerTl */ {KAknsIIDQsnFrSetOptCornerTl, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrSetOptCornerTr */ {KAknsIIDQsnFrSetOptCornerTr, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrSetOptCornerBl */ {KAknsIIDQsnFrSetOptCornerBl, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrSetOptCornerBr */ {KAknsIIDQsnFrSetOptCornerBr, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrSetOptSideT */ {KAknsIIDQsnFrSetOptSideT, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrSetOptSideB */ {KAknsIIDQsnFrSetOptSideB, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrSetOptSideL */ {KAknsIIDQsnFrSetOptSideL, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrSetOptSideR */ {KAknsIIDQsnFrSetOptSideR, ENoDraw, ES60_AllReleases, -1,-1,-1}, + /* SP_QsnFrSetOptCenter */ {KAknsIIDQsnFrSetOptCenter, ENoDraw, ES60_AllReleases, -1,-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; +} + +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; + const TInt fallbackGraphicID = m_partMap[stylepartIndex].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, KAvkonBitmapFile, 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(2); //icon, iconMask + 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); +} + +QPixmap QS60StylePrivate::backgroundTexture() +{ + static QPixmap result; + // Poor mans caching. + Making sure that there is always only one background image in memory at a time + +/* + TODO: 1) Hold the background QPixmap as pointer in a static class member. + Also add a deleteBackground() function and call that in ~QS60StylePrivate() + 2) Don't cache the background at all as soon as we have native pixmap support +*/ + + if (!m_backgroundValid) { + result = QPixmap(); + result = part(QS60StyleEnums::SP_QsnBgScreen, + QSize(S60->screenWidthInPixels, S60->screenHeightInPixels), SkinElementFlags()); + m_backgroundValid = true; + } + return result; +} + +bool QS60StylePrivate::isTouchSupported() +{ + return bool(AknLayoutUtils::PenEnabled()); +} + +void qt_s60_fill_background(QPainter *painter, const QRegion &rgn, const QPoint &offset) +{ + const QPixmap backgroundTexture(QS60StylePrivate::backgroundTexture()); + const QPaintDevice *target = painter->device(); + if (target->devType() == QInternal::Widget) { + const QWidget *widget = static_cast<const QWidget *>(target); + const CCoeControl *control = widget->effectiveWinId(); + const TPoint globalPos = control ? control->PositionRelativeToScreen() : TPoint(0,0); + 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(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 TInt fallbackGraphicID = m_partMap[stylepartIndex].fallbackGraphicID; + const bool rotatedBy90or270 = + (flags & (QS60StylePrivate::SF_PointEast | QS60StylePrivate::SF_PointWest)); + TSize targetSize = + rotatedBy90or270 ? TSize(size.height(), size.width()) : qt_QSize2TSize(size); + + MAknsSkinInstance* skinInstance = AknsUtils::SkinInstance(); + + QPixmap result; + + switch (drawType) { + case EDrawIcon: + { + 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, KAvkonBitmapFile, 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(2); // iconMask, icon +// QS60WindowSurface::lockBitmapHeap(); + break; + } + case EDrawBackground: + { +// QS60WindowSurface::unlockBitmapHeap(); + CFbsBitmap *background = new (ELeave) CFbsBitmap(); //offscreen + CleanupStack::PushL(background); + User::LeaveIfError(background->Create(targetSize, EColor16MA)); + + // todo: push background into CleanupStack + 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; // TODO: Let fromFbsBitmap return a QPixmap +} + +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)); + 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); + TRect innerRect = outerRect; + innerRect.Shrink( + QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerWidth), + QS60StylePrivate::pixelMetric(PM_Custom_FrameCornerHeight) + ); + + 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; // TODO: Let fromFbsBitmap return a QPixmap +} + +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_5_0 || QSysInfo::s60Version()==QSysInfo::SV_S60_3_2) { + centerId.Set(EAknsMajorSkin, 0x5300); + frameId.Set(EAknsMajorGeneric, 0x19c2); + } else { + centerId.Set(KAknsIIDQsnFrPopupCenter); + frameId.iMinor = centerId.iMinor - 9; + } + break; + default: + // center should be correct here + frameId.iMinor = centerId.iMinor - 9; + break; + } +} + +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) +{ + enum 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; +} + +#ifdef QT_S60STYLE_LAYOUTDATA_SIMULATED +void QS60StylePrivate::setActiveLayout() +{ + //todo: how to find layouts that are of same size (QVGA1 vs. QVGA2) + const QSize activeScreenSize(screenSize()); + int activeLayoutIndex = 0; + 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; + } + } + m_pmPointer = data[activeLayoutIndex]; +} +#endif // QT_S60STYLE_LAYOUTDATA_SIMULATED + +QS60StylePrivate::QS60StylePrivate() +{ +#ifdef QT_S60STYLE_LAYOUTDATA_SIMULATED + // No need to set active layout, if dynamic metrics API is available + setActiveLayout(); +#endif // QT_S60STYLE_LAYOUTDATA_SIMULATED +} + +QS60StylePrivate::~QS60StylePrivate() +{ + m_backgroundValid = false; +} + +short QS60StylePrivate::pixelMetric(int metric) +{ +#ifdef QT_S60STYLE_LAYOUTDATA_SIMULATED + Q_ASSERT(metric < MAX_PIXELMETRICS); + const short returnValue = m_pmPointer[metric]; + if (returnValue==-909) + return -1; + return returnValue; +#else + //todo - call the pixelmetrics API directly + return 0; +#endif // QT_S60STYLE_LAYOUTDATA_SIMULATED +} + +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) { + // TODO: fix this + QStyleOption opt; +// opt.palette = q->standardPalette(); + result = QApplication::style()->generatedIconPixmap(QIcon::Disabled, result, &opt); + } + 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) { + // TODO: fix this + QStyleOption opt; +// opt.palette = q->standardPalette(); + result = QApplication::style()->generatedIconPixmap(QIcon::Disabled, result, &opt); + } + return result; +} + +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; +} + +// 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); + + TSize trgSize = aTrgBitmap->SizeInPixels(); + 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(); + + TRect offsetRect(aTrgRect.iTl, drawRect.iTl); + const TInt yPosOffset = ySkip * offsetRect.Height(); + const TInt xPosOffset = xSkip * offsetRect.Width(); + + if ((displayMode == EGray256) || (displayMode == EColor256)) { + TInt srcScanLen8 = CFbsBitmap::ScanLineLength(srcSize.iWidth, + displayMode); + 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++) { + TUint8* srcAddress8 = reinterpret_cast<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) { + TInt srcScanLen16 = CFbsBitmap::ScanLineLength(srcSize.iWidth, + displayMode) >>1; + 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++) { + TUint16* srcAddress16 = reinterpret_cast<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) { + TInt srcScanLen32 = CFbsBitmap::ScanLineLength(srcSize.iWidth, + displayMode) >>2; + 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++) { + TUint32* srcAddress32 = reinterpret_cast<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() +{ + TSize mySize = QS60Data::screenDevice()->SizeInPixels(); + return QSize(mySize.iWidth, mySize.iHeight); +} + +void QS60StyleModeSpecifics::colorGroupAndIndex( + QS60StyleEnums::SkinParts skinID, TAknsItemID &colorGroup, int colorIndex) +{ + switch(skinID) { + case QS60StyleEnums::SP_QgnIndiRadiobuttOff: + case QS60StyleEnums::SP_QgnIndiRadiobuttOn: + case QS60StyleEnums::SP_QgnIndiCheckboxOff: + case QS60StyleEnums::SP_QgnIndiCheckboxOn: + colorGroup = KAknsIIDQsnIconColors; + colorIndex = EAknsCIQsnIconColorsCG1; + break; + default: + break; + } +} + +void QS60Style::handleDynamicLayoutVariantSwitch() +{ + Q_D(QS60Style); + d->clearCaches(); +#ifdef QT_S60STYLE_LAYOUTDATA_SIMULATED + d->setActiveLayout(); +#endif // QT_S60STYLE_LAYOUTDATA_SIMULATED + d->refreshUI(); + foreach (QWidget *widget, QApplication::allWidgets()) + d->setThemePalette(widget); +} + +void QS60Style::handleSkinChange() +{ + Q_D(QS60Style); + d->clearCaches(); + foreach (QWidget *topLevelWidget, QApplication::allWidgets()){ + d->setThemePalette(topLevelWidget); + topLevelWidget->update(); + } +} + +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..9aa170e 100644 --- a/src/gui/styles/styles.pri +++ b/src/gui/styles/styles.pri @@ -155,3 +155,20 @@ contains( styles, windowsmobile ) { DEFINES += QT_NO_STYLE_WINDOWSMOBILE } +contains( styles, s60 ) { + HEADERS += \ + styles/qs60style.h \ + styles/qs60style_p.h + SOURCES += styles/qs60style.cpp + DEFINES += QT_S60STYLE_LAYOUTDATA_SIMULATED + symbian { + SOURCES += styles/qs60style_symbian.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 db1e781..dac01c7 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 @@ -382,12 +383,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 43f5b1e..0e4b378 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,9 @@ 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) + const TReal inchWidth = (TReal)S60->screenWidthInTwips / KTwipsPerInch; + dpi = S60->screenWidthInPixels / inchWidth; #endif // Q_WS_X11 return dpi; @@ -195,6 +201,9 @@ 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) + const TReal inchHeight = (TReal)S60->screenHeightInTwips / KTwipsPerInch; + dpi = S60->screenHeightInPixels / inchHeight; #endif // Q_WS_X11 return dpi; @@ -788,7 +797,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..2606091 --- /dev/null +++ b/src/gui/text/qfont_s60.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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 c3fc9f5..1345d21 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..0b4567c --- /dev/null +++ b/src/gui/text/qfontdatabase_s60.cpp @@ -0,0 +1,348 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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 + +#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); + QDir dir(QDesktopServices::storageLocation(QDesktopServices::FontsLocation)); + dir.setNameFilters(QStringList() << QLatin1String("*.ttf") << QLatin1String("*.ccc")); + for (int i = 0; i < int(dir.count()); ++i) { + const QString fontFile = QDir::toNativeSeparators(dir.absoluteFilePath(dir[i])); + 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 47fe5c2..5a8977d 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -780,7 +780,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; @@ -1071,6 +1071,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 176c728..7382b39 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..0c6d5b9 --- /dev/null +++ b/src/gui/text/qfontengine_s60.cpp @@ -0,0 +1,307 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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> + +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) +{ + glyph_metrics_t overall; + // initialize with line height, we get the same behaviour on all platforms + overall.y = -ascent(); + overall.height = ascent() + descent() + 1; + + QFixed ymax = 0; + QFixed xmax = 0; + for (int i = 0; i < glyphs.numGlyphs; i++) { + const glyph_metrics_t glyphBounds = boundingBox_const(glyphs.glyphs[i]); + QFixed x = overall.xoff + glyphs.offsets[i].x + glyphBounds.x; + QFixed y = overall.yoff + glyphs.offsets[i].y - glyphBounds.y; + overall.x = qMin(overall.x, x); + overall.y = qMin(overall.y, y); + xmax = qMax(xmax, x + glyphBounds.width); + ymax = qMax(ymax, y + glyphBounds.height); + overall.xoff += glyphBounds.xoff; + } + overall.height = qMax(overall.height, ymax - overall.y); + overall.width = xmax - overall.x; + + return overall; +} + +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(), + metrics.VertAdvance() + ); + 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..0b20c74 --- /dev/null +++ b/src/gui/text/qfontengine_s60_p.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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> + +QT_BEGIN_NAMESPACE + +class CFbsBitmap; +class CFbsBitmapDevice; +class CFbsBitGc; +class CFont; + +// ..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..c74af23 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -1870,6 +1870,8 @@ QVariant QTextControl::inputMethodQuery(Qt::InputMethodQuery property) const return QVariant(block.text()); case Qt::ImCurrentSelection: return QVariant(d->cursor.selectedText()); + case Qt::ImMaximumTextLength: + return QVariant(); // No limit. 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 a622385..e6bc80a 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..a32a91c --- /dev/null +++ b/src/gui/util/qdesktopservices_s60.cpp @@ -0,0 +1,359 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index 09a51fe..e9884bb 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; @@ -2421,6 +2422,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/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp index b03df9e..8b553f9 100644 --- a/src/gui/widgets/qlineedit.cpp +++ b/src/gui/widgets/qlineedit.cpp @@ -2330,6 +2330,8 @@ QVariant QLineEdit::inputMethodQuery(Qt::InputMethodQuery property) const return QVariant(d->text); case Qt::ImCurrentSelection: return QVariant(selectedText()); + case Qt::ImMaximumTextLength: + return QVariant(maxLength()); default: return QVariant(); } @@ -2926,6 +2928,7 @@ void QLineEditPrivate::moveCursor(int pos, bool mark) selDirty = false; emit q->selectionChanged(); } + q->updateMicroFocus(); emitCursorPositionChanged(); } 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..1e544f7 100644 --- a/src/gui/widgets/qmenu.h +++ b/src/gui/widgets/qmenu.h @@ -57,6 +57,12 @@ QT_BEGIN_NAMESPACE QT_MODULE(Gui) +#ifdef Q_OS_SYMBIAN + class CEikMenuPane; + 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 +151,6 @@ public: HMENU wceMenu(bool create = false); #endif - bool separatorsCollapsible() const; void setSeparatorsCollapsible(bool collapse); @@ -177,6 +182,9 @@ protected: #ifdef Q_OS_WINCE QAction* wceCommands(uint command); #endif +#ifdef Q_OS_SYMBIAN + void symbianCommands(int command); +#endif private Q_SLOTS: void internalSetSloppyAction(); diff --git a/src/gui/widgets/qmenu_p.h b/src/gui/widgets/qmenu_p.h index e3c4890..61cc3db 100644 --- a/src/gui/widgets/qmenu_p.h +++ b/src/gui/widgets/qmenu_p.h @@ -120,6 +120,16 @@ struct QWceMenuAction { QWceMenuAction() : menuHandle(0), command(0) {} }; #endif +#ifdef Q_OS_SYMBIAN +class CEikMenuPane; +struct QSymbianMenuAction { + uint command; + int parent; + CEikMenuPane* menuPane; + QPointer<QAction> action; + QSymbianMenuAction() : command(0) {} +}; +#endif class QMenuPrivate : public QWidgetPrivate { @@ -135,6 +145,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 +161,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 +335,29 @@ 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; + bool symbianCommands(int command); +#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..a50c5c0 --- /dev/null +++ b/src/gui/widgets/qmenu_symbian.cpp @@ -0,0 +1,370 @@ +/**************************************************************************** +** +** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** +** $TROLLTECH_DUAL_EMBEDDED_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 +#define QT_FIRST_MENU_ITEM 32000 +static QMenuBarPrivate *s60_menubar=0; + +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; + +// ### 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 (s60_menubar) + cba->SetCommandSetL(R_AVKON_SOFTKEYS_OPTIONS_EXIT); + else + cba->SetCommandSetL(R_AVKON_SOFTKEYS_EXIT); + } +} + +static void rebuildMenu() +{ + qt_symbian_menu_static_cmd_id = QT_FIRST_MENU_ITEM; + deleteAll( &symbianMenus ); + if (!s60_menubar) + return; + for (int i = 0; i < s60_menubar->actions.size(); ++i) { + QSymbianMenuAction *symbianActionTopLevel = new QSymbianMenuAction; + symbianActionTopLevel->action = s60_menubar->actions.at(i); + symbianActionTopLevel->parent = 0; + symbianActionTopLevel->command = qt_symbian_menu_static_cmd_id++; + qt_symbian_insert_action(symbianActionTopLevel, &symbianMenus); + } + + return; + } + +Q_GUI_EXPORT void qt_symbian_show_toplevel( CEikMenuPane* menuPane) +{ + if (!s60_menubar) + 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 QMenu::symbianCommands(int command) +{ + Q_D(QMenu); + d->symbianCommands(command); +} + +void QMenuBar::symbianCommands(int command) +{ + int size = nativeMenuBars.size(); + for (int i = 0; i < nativeMenuBars.size(); ++i) { + bool result = nativeMenuBars.at(i)->d_func()->symbianCommands(command); + if (result) + return; + } +} + +bool QMenuBarPrivate::symbianCommands(int command) +{ + SymbianMenuItem* menu = qt_symbian_find_menu_item(command, symbianMenus); + if (!menu) + return false; + + emit q_func()->triggered(menu->action); + menu->action->activate(QAction::Trigger); + return true; +} + +bool QMenuPrivate::symbianCommands(int command) +{ + SymbianMenuItem* menu = qt_symbian_find_menu_item(command, symbianMenus); + if (!menu) + return false; + + emit q_func()->triggered(menu->action); + menu->action->activate(QAction::Trigger); + return true; +} + +void QMenuBarPrivate::symbianCreateMenuBar(QWidget *parent) +{ + Q_Q(QMenuBar); + if (parent && parent->isWindow()){ + symbian_menubar = new QSymbianMenuBarPrivate(this); + nativeMenuBars.append(q); + } +} + +void QMenuBarPrivate::symbianDestroyMenuBar() +{ + Q_Q(QMenuBar); + int index = nativeMenuBars.indexOf(q); + nativeMenuBars.removeAt(index); + if (symbian_menubar) + delete symbian_menubar; + symbian_menubar = 0; +} + +QMenuBarPrivate::QSymbianMenuBarPrivate::QSymbianMenuBarPrivate(QMenuBarPrivate *menubar) +{ + d = menubar; + s60_menubar = menubar; +} + +QMenuBarPrivate::QSymbianMenuBarPrivate::~QSymbianMenuBarPrivate() +{ + deleteAll( &symbianMenus ); + symbianMenus.clear(); + d = 0; + s60_menubar = 0; +} + +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(); + if (!s60_menubar) + return; + + rebuildMenu(); + } +#endif //QT_NO_MENUBAR diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp index ccf37db..b92f48b 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 } /*! @@ -1292,6 +1302,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 +1399,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 diff --git a/src/gui/widgets/qmenubar.h b/src/gui/widgets/qmenubar.h index 42f0c0c..36c983b 100644 --- a/src/gui/widgets/qmenubar.h +++ b/src/gui/widgets/qmenubar.h @@ -118,6 +118,10 @@ public: static void wceRefresh(); #endif +#ifdef Q_OS_SYMBIAN + static void symbianCommands(int command); +#endif + public Q_SLOTS: virtual void setVisible(bool visible); diff --git a/src/gui/widgets/qmenubar_p.h b/src/gui/widgets/qmenubar_p.h index 223346b..f617d80 100644 --- a/src/gui/widgets/qmenubar_p.h +++ b/src/gui/widgets/qmenubar_p.h @@ -65,6 +65,10 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_MENUBAR class QMenuBarExtension; +#ifdef Q_OS_SYMBIAN +class CCoeControl; +class CEikMenuBar; +#endif class QMenuBarPrivate : public QWidgetPrivate { Q_DECLARE_PUBLIC(QMenuBar) @@ -78,7 +82,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 +95,9 @@ public: #ifdef Q_OS_WINCE delete wce_menubar; #endif +#ifdef Q_OS_SYMBIAN + delete symbian_menubar; +#endif } void init(); @@ -220,6 +231,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; + bool symbianCommands(int command); + +#endif }; #endif 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 01a743b..c8d6097 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 670745b..a339388 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..82c673f --- /dev/null +++ b/src/network/kernel/qnetworkinterface_symbian.cpp @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_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 f9750f2..8ae247c 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -991,6 +991,7 @@ void QAbstractSocketPrivate::_q_connectToNextAddress() // Wait for a write notification that will eventually call // _q_testConnection(). socketEngine->setWriteNotificationEnabled(true); + socketEngine->setExceptionNotificationEnabled(true); break; } while (state != QAbstractSocket::ConnectedState); } @@ -1049,8 +1050,10 @@ void QAbstractSocketPrivate::_q_abortConnectionAttempt() #if defined(QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocketPrivate::_q_abortConnectionAttempt() (timed out)"); #endif - if (socketEngine) + if (socketEngine) { socketEngine->setWriteNotificationEnabled(false); + socketEngine->setExceptionNotificationEnabled(false); + } connectTimer->stop(); if (addresses.isEmpty()) { 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..2471043 100644 --- a/src/network/socket/qlocalsocket_unix.cpp +++ b/src/network/socket/qlocalsocket_unix.cpp @@ -282,7 +282,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 +300,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 +515,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 +533,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 3366f2d..515ad84 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -52,15 +52,22 @@ // // We mean it. // - #include "QtNetwork/qhostaddress.h" #include "private/qabstractsocketengine_p.h" #ifndef Q_OS_WIN #include "qplatformdefs.h" +#else +#include <Winsock2.h> // sockaddr_storage, sockaddr_in +#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) @@ -76,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 @@ -177,6 +314,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 cc372a6..5584c6a 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 } /* @@ -127,7 +135,7 @@ static inline void qt_socket_getPortAndAddress(struct sockaddr *sa, quint16 *por *addr = tmpAddress; #ifndef QT_NO_IPV6IFNAME char scopeid[IFNAMSIZ]; - if (::if_indextoname(sa6->sin6_scope_id, scopeid) > 0) { + if (::if_indextoname(sa6->sin6_scope_id, scopeid)) { addr->setScopeId(QLatin1String(scopeid)); } else #endif @@ -189,7 +197,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; } @@ -227,8 +236,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; } @@ -255,14 +265,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 @@ -272,7 +282,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; @@ -285,11 +297,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; @@ -328,7 +345,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: @@ -431,7 +449,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: @@ -500,7 +519,8 @@ int QNativeSocketEnginePrivate::nativeAccept() qDebug("QNativeSocketEnginePrivate::nativeAccept() == %i", acceptedDescriptor); #endif // Ensure that the socket is closed on exec*() - ::fcntl(acceptedDescriptor, F_SETFD, FD_CLOEXEC); + qt_socket_fcntl(acceptedDescriptor, F_SETFD, FD_CLOEXEC); + return acceptedDescriptor; } @@ -540,7 +560,7 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const ssize_t readBytes; do { char c; - readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, storagePtr, &storageSize); + readBytes = qt_socket_recvfrom(socketDescriptor, &c, 1, MSG_PEEK, storagePtr, &storageSize); } while (readBytes == -1 && errno == EINTR); // If there's no error, or if our buffer was too small, there must be a @@ -554,16 +574,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; @@ -572,14 +601,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) { @@ -595,7 +624,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, (struct sockaddr *)&aa, &sz); } while (recvFromResult == -1 && errno == EINTR); @@ -646,10 +675,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); @@ -692,7 +720,7 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() // Determine local address memset(&sa, 0, sizeof(sa)); - if (::getsockname(socketDescriptor, sockAddrPtr, &sockAddrSize) == 0) { + if (qt_socket_getsockname(socketDescriptor, sockAddrPtr, &sockAddrSize) == 0) { qt_socket_getPortAndAddress(sockAddrPtr, &localPort, &localAddress); // Determine protocol family @@ -716,13 +744,13 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() } // Determine the remote address - if (!::getpeername(socketDescriptor, sockAddrPtr, &sockAddrSize)) + if (!qt_socket_getpeername(socketDescriptor, sockAddrPtr, &sockAddrSize)) qt_socket_getPortAndAddress(sockAddrPtr, &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) @@ -753,7 +781,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) @@ -767,7 +795,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) { @@ -809,7 +837,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) { @@ -827,6 +855,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; @@ -860,12 +891,15 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co int retval; do { if (selectForRead) - retval = select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv); + //retval = ::select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv); + retval = qt_socket_select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv); else - retval = select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv); + //retval = ::select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv); + retval = qt_socket_select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv); - if (retval != -1 || errno != EINTR) + if (retval != -1 || errno != EINTR) { break; + } if (timeout > 0) { // recalculate the timeout @@ -906,9 +940,13 @@ 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) + + ret = qt_socket_select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv); + //ret = ::select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv); + + if (ret != -1 || errno != EINTR) { break; + } if (timeout > 0) { // recalculate the timeout @@ -925,9 +963,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/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/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..d772fae 100644 --- a/src/plugins/qpluginbase.pri +++ b/src/plugins/qpluginbase.pri @@ -13,3 +13,12 @@ contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols include(../qt_targets.pri) wince*:LIBS += $$QMAKE_LIBS_GUI + +symbian: { + TARGET.EPOCALLOWDLLDATA=1 + contains(QT_EDITION, OpenSource) { + TARGET.CAPABILITY = LocalServices NetworkServices ReadUserData UserEnvironment WriteUserData + } else { + 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..1b7edbd --- /dev/null +++ b/src/plugins/s60/src/qdesktopservices_3_1.cpp @@ -0,0 +1,20 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_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..e563c14 --- /dev/null +++ b/src/plugins/s60/src/qdesktopservices_3_2.cpp @@ -0,0 +1,37 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include <private/qcore_symbian_p.h> +#include <cdirectorylocalizer.h> // CDirectoryLocalizer +#include <qstring.h> +#include <qdir.h> + +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..95cf244 --- /dev/null +++ b/src/plugins/s60/src/qlocale_3_1.cpp @@ -0,0 +1,32 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_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..027eefc --- /dev/null +++ b/src/plugins/s60/src/qlocale_3_2.cpp @@ -0,0 +1,32 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include <e32std.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..ab96b1b --- /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..bacf23b --- /dev/null +++ b/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pro @@ -0,0 +1,8 @@ +# Use subdirs template to suppress generation of unnecessary files +TEMPLATE = subdirs + +# We just want to extract the zip file containing sqlite binaries for Symbian +!exists($${EPOCROOT}epoc32/release/armv5/urel/sqlite3.dll): { + BLD_INF_RULES.prj_exports += ":zip SQLite3_v9.2.zip" +} + diff --git a/src/qbase.pri b/src/qbase.pri index f7c8a95..5ec63fb 100644 --- a/src/qbase.pri +++ b/src/qbase.pri @@ -94,6 +94,16 @@ win32 { INCLUDEPATH += tmp !static: DEFINES+=QT_MAKEDLL } +symbian { + !static { + DEFINES+=QT_MAKEDLL + contains(QT_EDITION, OpenSource) { + TARGET.CAPABILITY = LocalServices NetworkServices ReadUserData UserEnvironment WriteUserData + } else { + TARGET.CAPABILITY = All -Tcb + } + } +} win32-borland:INCLUDEPATH += kernel aix-g++* { @@ -115,7 +125,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_libs.pro b/src/s60installs/qt_libs.pro new file mode 100644 index 0000000..546c5b6 --- /dev/null +++ b/src/s60installs/qt_libs.pro @@ -0,0 +1,74 @@ +# Use subdirs template to suppress generation of unnecessary files +TEMPLATE = subdirs + +symbian: { + load(data_caging_paths) + + SUBDIRS= + TARGET = "QtLibs pre-release" + contains(QT_EDITION, OpenSource) { + # Can't use UID in protected range for self signed packages. + TARGET.UID3 = 0xE001E61C + } else { + 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 = "(0x20009a80), 1, 5, 0, {\"Symbian OS PIPS\"}" + contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) { + qtlibraries.depends += "(0x200110CB), 1, 5, 0, {\"Open C LIBSSL Common\"}" + qtlibraries.depends += "(0x10281f34), 1, 5, 0, {\"Open C LIBSSL\"}" + qtlibraries.depends += "(0x2001B28B), 1, 5, 0, {\"OpenC LIBZ Support Files\"}" + } + 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 + } +} diff --git a/src/s60main/qts60main.cpp b/src/s60main/qts60main.cpp new file mode 100644 index 0000000..1d19cc6 --- /dev/null +++ b/src/s60main/qts60main.cpp @@ -0,0 +1,32 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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..10a784a --- /dev/null +++ b/src/s60main/qts60main_mcrt0.cpp @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_3RDPARTY_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..807b5af --- /dev/null +++ b/src/s60main/qts60mainapplication.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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..318f83b --- /dev/null +++ b/src/s60main/qts60mainapplication.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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..016d49b --- /dev/null +++ b/src/s60main/qts60mainappui.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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/qmenubar.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 ) +{ + switch (aCommand) { + case EEikCmdExit: + case EAknSoftkeyBack: + case EAknSoftkeyExit: + if (qApp) + qApp->exit(); + break; + default: + // For now assume all unknown menu items are Qt menu items + QMenuBar::symbianCommands(aCommand); + break; + } +} + +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..3addb0c --- /dev/null +++ b/src/s60main/qts60mainappui.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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 ); + + /** + * 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..9ab426d --- /dev/null +++ b/src/s60main/qts60maindocument.cpp @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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..4979e7f --- /dev/null +++ b/src/s60main/qts60maindocument.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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. +** +** $TROLLTECH_DUAL_EMBEDDED_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..569f59e --- /dev/null +++ b/src/s60main/s60main.rss @@ -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. +** +** $TROLLTECH_DUAL_EMBEDDED_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/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..f089dd7 100644 --- a/src/sql/sql.pro +++ b/src/sql/sql.pro @@ -17,3 +17,5 @@ include(kernel/kernel.pri) include(drivers/drivers.pri) include(models/models.pri) +symbian:TARGET.UID3=0x2001E61D + diff --git a/src/src.pro b/src/src.pro index f40c6ad..2a5595f 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,6 +23,7 @@ win32:{ !wince*: SRC_SUBDIRS += src_tools_idc } +!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 @@ -28,7 +34,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 +90,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 +124,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 +173,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_global.h b/src/testlib/qtest_global.h index d6b0655..ebfdae1 100644 --- a/src/testlib/qtest_global.h +++ b/src/testlib/qtest_global.h @@ -62,9 +62,10 @@ 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 +#endif + #if (defined Q_CC_HPACC) && (defined __ia64) # ifdef Q_TESTLIB_EXPORT diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index b5200dc..27ba6da 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -1279,7 +1279,7 @@ static void qInvokeTestMethods(QObject *testObject) QTEST_ASSERT(metaObject); QTestLog::startLogging(); - + QTestResult::setCurrentTestFunction("initTestCase"); QTestResult::setCurrentTestLocation(QTestResult::DataFunc); QTestTable::globalTestTable(); @@ -1399,6 +1399,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/qtestnetworkservers.h b/src/testlib/qtestnetworkservers.h new file mode 100644 index 0000000..4b11f27 --- /dev/null +++ b/src/testlib/qtestnetworkservers.h @@ -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. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QT_TESTNETWORKSERVERS_H +#define QT_TESTNETWORKSERVERS_H + +#if defined(Q_OS_SYMBIAN) && !defined(Q_CC_NOKIAX86) +#define FTP_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define FTP_TEST_SERVER_IP_1 "10.215.7.68" +#define FTPPROXY_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define PROXY_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define SOCKS5PROXY_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define HTTPPROXY_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define HTTP_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define HTTPS_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define NTLM_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define UDP_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define TCP_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define SSH_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define ECHO_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define DAYTIME_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define WILDCARD_TEST_SERVER_NAME_1 "netiks.wildcard.dev.troll.no" +#define WILDCARD_TEST_SERVER_NAME_2 "netiks.*.troll.no" +#define DOMAIN_TEST_SERVER_NAME_1 ".troll.no" +#define DOMAIN_TEST_SERVER_NAME_2 "troll.no" +#define INTERN_TEST_SERVER_NAME_1 "intern.nokia.troll.no" +#define HOSTLOOKUP_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define HOSTLOOKUP_TEST_SERVER_IP "10.215.7.68" +#else +#define FTP_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define FTP_TEST_SERVER_IP_1 "10.215.7.68" +#define FTPPROXY_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define PROXY_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define SOCKS5PROXY_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define HTTPPROXY_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define HTTP_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define HTTPS_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define NTLM_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define UDP_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define TCP_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define SSH_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define ECHO_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define DAYTIME_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define WILDCARD_TEST_SERVER_NAME_1 "aspiriniks.wildcard.dev.europe.nokia.com" +#define WILDCARD_TEST_SERVER_NAME_2 "netiks.*.troll.no" +#define INTERN_TEST_SERVER_NAME_1 "intern.nokia.troll.no" +#define DOMAIN_TEST_SERVER_NAME_1 ".europe.nokia.com" +#define DOMAIN_TEST_SERVER_NAME_2 "europe.nokia.com" +#define HOSTLOOKUP_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define HOSTLOOKUP_TEST_SERVER_IP "10.215.7.68" +#endif + +#define FTPS_TEST_SERVER_NAME_1 "aspiriniks.troll.no" +#define FOO_TEST_SERVER_NAME_1 HOSTWILLNEVEREXIST_TEST_SERVER_NAME_1 +#define LOCALHOST_TEST_SERVER_NAME_1 "localhost" +#define HTTP_TEST_SERVER_NAME_4 "www.ietf.org" +#define NONEXISTING_TEST_SERVER_NAME_1 "this-host-will-never-exist.troll.no" +#define NONEXISTING_TEST_SERVER_NAME_2 "fluke-nosuchhost.troll.no" +#define NOSUCH_TEST_SERVER_NAME_1 "nosuchserver.troll.no" +#define IMAP_TEST_SERVER_NAME_1 "fluke.troll.no" +#define IMAP_TEST_SERVER_NAME_2 "imap.troll.no" +#define IMAP_TEST_SERVER_NAME_3 "imap.trolltech.com" +#define IMAPS_TEST_SERVER_NAME_1 "fluke.troll.no" +#define HOSTNOTFOUND_TEST_SERVER_NAME_1 "hostnotfoundhostnotfound.troll.no" +#define TIMEOUT_TEST_SERVER_NAME_1 "cisco.com" +#define UMA_TEST_SERVER_NAME_1 "fluke.troll.no" +#define HOSTWILLNEVEREXIST_TEST_SERVER_NAME_1 "this-host-will-never-exist.troll.no" + +#define QBYTEARRAY_DEBUG(ba, maxsize)\ + printf( "ByteArray content (%d/%d bytes):\n", ba.size() <= maxsize ? ba.size() : maxsize , ba.size() ); \ + printf( "===========================================================================\n" ); \ + printf( ba.mid( 0, ba.size() <= maxsize ? ba.size() : maxsize ).constData() ); \ + printf( "\n==========================================================================\n" ); + + +static const char *IFNAME = "Lab"; + +#endif // QT_TESTNETWORKSERVERS_H 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 c78d4ba..b94d3fa 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)) |