diff options
55 files changed, 1782 insertions, 770 deletions
diff --git a/config.tests/unix/ipc_posix/ipc.cpp b/config.tests/unix/ipc_posix/ipc.cpp new file mode 100644 index 0000000..fde8a99 --- /dev/null +++ b/config.tests/unix/ipc_posix/ipc.cpp @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the config.tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/mman.h> +#include <semaphore.h> +#include <fcntl.h> + +int main(int, char **) +{ + sem_t *semaphore = sem_open("test", O_CREAT | O_EXCL, 0666, 0); + if (semaphore != SEM_FAILED) + sem_close(semaphore); + + shm_open("test", O_RDWR | O_CREAT | O_EXCL, 0666); + shm_unlink("test"); + + return 0; +} diff --git a/config.tests/unix/ipc_posix/ipc_posix.pro b/config.tests/unix/ipc_posix/ipc_posix.pro new file mode 100644 index 0000000..1b6de02 --- /dev/null +++ b/config.tests/unix/ipc_posix/ipc_posix.pro @@ -0,0 +1,3 @@ +SOURCES = ipc.cpp +CONFIG -= qt dylib +mac:CONFIG -= app_bundle diff --git a/config.tests/unix/ipc_sysv/ipc.cpp b/config.tests/unix/ipc_sysv/ipc.cpp new file mode 100644 index 0000000..7f04552 --- /dev/null +++ b/config.tests/unix/ipc_sysv/ipc.cpp @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the config.tests of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/sem.h> +#include <sys/shm.h> +#include <fcntl.h> + +int main(int, char **) +{ + key_t unix_key = ftok("test", 'Q'); + int semaphore = semget(unix_key, 1, 0666 | IPC_CREAT | IPC_EXCL); + if (semaphore != -1) + semctl(semaphore, 0, IPC_RMID, 0); + + shmget(unix_key, 0, 0666 | IPC_CREAT | IPC_EXCL); + shmctl(0, 0, static_cast<struct shmid_ds *>(0)); + + return 0; +} diff --git a/config.tests/unix/ipc_sysv/ipc_sysv.pro b/config.tests/unix/ipc_sysv/ipc_sysv.pro new file mode 100644 index 0000000..1b6de02 --- /dev/null +++ b/config.tests/unix/ipc_sysv/ipc_sysv.pro @@ -0,0 +1,3 @@ +SOURCES = ipc.cpp +CONFIG -= qt dylib +mac:CONFIG -= app_bundle @@ -5112,6 +5112,19 @@ if [ "$XPLATFORM_SYMBIAN" = "yes" ]; then fi fi +# check IPC support +if ! "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/unix/ipc_sysv "ipc_sysv" $L_FLAGS $I_FLAGS $l_FLAGS ; then + # SYSV IPC is not supported - check POSIX IPC + if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/unix/ipc_posix "ipc_posix" $L_FLAGS $I_FLAGS $l_FLAGS ; then + QCONFIG_FLAGS="$QCONFIG_FLAGS QT_POSIX_IPC" + else + QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_SYSTEMSEMAPHORE QT_NO_SHAREDMEMORY" + if [ "$PLATFORM_QWS" = "yes" ]; then + QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_SEMAPHORE QT_NO_QWS_MULTIPROCESS QT_NO_QWS_SHARE_FONTS" + fi + fi +fi + # detect zlib if [ "$CFG_ZLIB" = "no" ]; then # Note: Qt no longer support builds without zlib diff --git a/dist/changes-4.8.0 b/dist/changes-4.8.0 index 1703633..02205b3 100644 --- a/dist/changes-4.8.0 +++ b/dist/changes-4.8.0 @@ -99,6 +99,8 @@ Qt for Mac OS X Qt for Embedded Linux --------------------- + - Added support for QNX 6.5 with multi-process support, and much improved mouse, + keyboard and screen drivers. Qt for Windows CE diff --git a/doc/src/platforms/platform-notes-rtos.qdoc b/doc/src/platforms/platform-notes-rtos.qdoc index 62d5add..0b1265b 100644 --- a/doc/src/platforms/platform-notes-rtos.qdoc +++ b/doc/src/platforms/platform-notes-rtos.qdoc @@ -160,7 +160,7 @@ X11 embedded server is not recommended due to missing support for X11 extensions, resulting in poor rendering quality. - Qt for QNX contains experimental screen and input drivers based on QNX's + Qt for QNX contains screen and input drivers based on QNX's \c devi-hid and \c io-display. For more information, check the class documentation for QQnxScreen, QWSQnxKeyboardHandler and QQnxMouseHandler. See the \l{Porting Qt for Embedded Linux to a New Architecture} document for information @@ -170,7 +170,7 @@ \section1 Supported Versions - Qt has been tested on QNX 6.4 on i386 and PowerPC targets with QNX's default + Qt has been tested on QNX 6.5 on i386, ARM/ARM-v7 and PowerPC targets with QNX's default gcc compiler. \section1 Limitations @@ -179,16 +179,12 @@ \table \header \o Function \o Notes - \row \o QProcess - \o Not available - QNX doesn't support mixing threads and processes. - \row \o QSharedMemory - \o Not available - QNX doesn't support SYSV style shared memory. - \row \o QSystemSemaphore - \o Not available - QNX doesn't support SYSV style system semaphores. - \row \o QWS Multi Process - \o QT_NO_QWS_MULTIPROCESS is always on due to missing shared memory support. \row \o Phonon \o There is no standard audio backend, which could be integrated into Phonon. + \row \o QtMultimedia + \o There is no standard backend, which could be integrated into QtMultimedia. + \row \o QtDBus + \o The the QtDBus library is not available on QNX. \row \o Qt3Support \o The Qt3Support library is not available on QNX. \endtable @@ -203,24 +199,25 @@ i386 QNX target: \code - configure -xplatform unsupported/qws/qnx-i386-g++ -embedded i386 -no-gfx-linuxfb -no-mouse-linuxtp -no-kbd-tty -no-qt3support -qt-gfx-qnx -qt-mouse-qnx -qt-kbd-qnx -no-exceptions + configure -xplatform unsupported/qws/qnx-i386-g++ -embedded x86 -no-gfx-linuxfb -no-mouse-linuxtp -no-kbd-tty -no-qt3support -qt-mouse-qnx -qt-kbd-qnx -qt-gfx-qnx -depths 16,24,32,generic -no-exceptions \endcode \list \o \c{-xplatform unsupported/qws/qnx-i386-g++} - selects the i386-g++ mkspec for QNX - \o \c{-embedded i386} - builds the embedded version of Qt and sets the architecture to i386 + \o \c{-embedded x86} - builds the embedded version of Qt and sets the architecture to i386 \o \c{-no-gfx-linuxfb}, \c{-no-mouse-linuxtp} and \c{-no-kbd-tty} are Linux specific and won't work on QNX \o \c{-no-qt3support} - required since the Qt3 support classes are not supported on QNX \o \c{-no-exceptions} - reduces the size of the library by disabling exception support - \o \c{-qt-gfx-qnx} - enables the experimental \c{io-graphics} based display driver - \o \c{-qt-mouse-qnx} - enables the experimental \c{devi-hig} based mouse driver - \o \c{-qt-kbd-qnx} - enables the experimental \c{devi-hig} based keyboard driver + \o \c{-qt-mouse-qnx} - enables the \c{devi-hid} based mouse driver + \o \c{-qt-kbd-qnx} - enables the \c{devi-hid} based keyboard driver + \o \c{-qt-gfx-qnx} - enables the \c{io-graphics} based screen driver + \o \c{-depths 16,24,32,generic} - enables all modes supported by the QNX screen driver \endlist \section1 General Notes \list - \o To enable the experimental QNX display and input drivers, \c{io-display} needs to be + \o To enable the QNX screen and input drivers, \c{io-display} needs to be up and running. The \c devi-hid based Qt input drivers require \c devi-hid to run in resource mode without Photon support. To enable a standard mouse and keyboard combination, run \c devi-hid as follows: \c{/usr/photon/bin/devi-hid -Pr kbd mouse}. @@ -235,8 +232,8 @@ with a newer version, or disable the TIFF plugin entierly by appending \c{QT_CONFIG += no-tiff} to \c{.qmake.cache} after configuring Qt. - \o Some of the tools, examples and demos do not compile due to dependencies on QProcess - or other classes that are not available on QNX. + \o Some of the tools, examples and demos do not compile due to dependencies on classes + that are not available on QNX. \endlist \section1 Platform Regressions @@ -244,6 +241,14 @@ Qt for QNX's behavior is mostly identical with \l{Qt for Embedded Linux}. However, some regressions were spotted in QDateTime computation around year 0 and year 1970, which have been tracked back to faulty time zone data on some QNX versions. + + QString::localeAwareCompare() only works for C locale. + + QTranslator's default locale-based fallback mechanism doesn't work. + + QSystemSemaphore: Due to POSIX semaphores limitations, the semaphore operations aren't + automatically undone when the process terminates. This potentially may lead to unexpected + lock-ups in applications which does use the SysV semaphores behavior. */ /*! diff --git a/mkspecs/common/qnx/qmake.conf b/mkspecs/common/qnx/qmake.conf new file mode 100644 index 0000000..d241b61 --- /dev/null +++ b/mkspecs/common/qnx/qmake.conf @@ -0,0 +1,33 @@ +# +# qmake configuration common for qnx-g++ without X11 +# + +include(../gcc-base-unix.conf) +include(../g++-unix.conf) +include(../linux.conf) +include(../qws.conf) + +CONFIG += qnx +QT -= network + +QMAKE_COMPILER_DEFINES += __QNXNTO__ + +# modifications to linux.conf and qws.conf +QMAKE_LIBS = +QMAKE_LIBS_DYNLOAD = +QMAKE_LIBS_NIS = +QMAKE_LIBS_EGL = -lEGL +QMAKE_LIBS_OPENGL = $$QMAKE_LIBS_EGL -lGLESv1_CM -lGLESv2 +QMAKE_LIBS_OPENGL_QT = $$QMAKE_LIBS_OPENGL +QMAKE_LIBS_OPENGL_ES1 = $$QMAKE_LIBS_EGL -lGLESv1_CM +QMAKE_LIBS_OPENGL_ES2 = $$QMAKE_LIBS_EGL -lGLESv2 +QMAKE_LIBS_OPENVG = $$QMAKE_LIBS_EGL -lOpenVG +QMAKE_LIBS_THREAD = + +QMAKE_LIBS_CORE = +QMAKE_LIBS_NETWORK += -lsocket +QMAKE_LIBS_GUI += -lsocket + +# QNX doesn't have install +QMAKE_INSTALL_FILE = +QMAKE_INSTALL_PROGRAM = diff --git a/mkspecs/common/qnx/qplatformdefs.h b/mkspecs/common/qnx/qplatformdefs.h new file mode 100644 index 0000000..bf7a0a0 --- /dev/null +++ b/mkspecs/common/qnx/qplatformdefs.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the qmake spec of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPLATFORMDEFS_H +#define QPLATFORMDEFS_H + +// Get Qt defines/settings +#include <qglobal.h> + +// Set any POSIX/XOPEN defines at the top of this file to turn on specific APIs + +#include <unistd.h> + +// We are hot - unistd.h should have turned on the specific APIs we requested + +#include <pthread.h> +#include <dirent.h> +#include <fcntl.h> +#include <grp.h> +#include <pwd.h> +#include <signal.h> + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/ipc.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <netinet/in.h> +#ifndef QT_NO_IPV6IFNAME +#include <net/if.h> +#endif + +// for htonl +#include <arpa/inet.h> + +#define QT_USE_XOPEN_LFS_EXTENSIONS +#define QT_NO_READDIR64 +#include "../posix/qplatformdefs.h" + +#include <stdlib.h> + +#define QT_SNPRINTF ::snprintf +#define QT_VSNPRINTF ::vsnprintf + + +#include <sys/neutrino.h> + +#if !defined(_NTO_VERSION) || _NTO_VERSION < 650 +// pre-6.5 versions of QNX doesn't have getpagesize() +inline int getpagesize() +{ + return ::sysconf(_SC_PAGESIZE); +} + +// pre-6.5 versions of QNX doesn't have strtof() +inline float strtof(const char *b, char **e) +{ + return float(strtod(b, e)); +} +#endif + +#define QT_QWS_TEMP_DIR QString::fromLocal8Bit(qgetenv("TMPDIR").constData()) + +#endif // QPLATFORMDEFS_H diff --git a/mkspecs/unsupported/qnx-g++/qmake.conf b/mkspecs/unsupported/qnx-g++/qmake.conf index 83c4a26..e354b2c 100644 --- a/mkspecs/unsupported/qnx-g++/qmake.conf +++ b/mkspecs/unsupported/qnx-g++/qmake.conf @@ -4,58 +4,16 @@ # Written for QNX RTOS v6 with X11 # -MAKEFILE_GENERATOR = UNIX -TARGET_PLATFORM = unix -TEMPLATE = app -CONFIG += qt warn_on release link_prl -QT += core gui +include(../../common/qnx/qmake.conf) -include(../common/gcc-base-unix.conf) -include(../common/g++-unix.conf) -include(../common/unix.conf) - -QMAKE_CFLAGS_THREAD = -D_REENTRANT -QMAKE_CXXFLAGS_THREAD = $$QMAKE_CLFAGS_THREAD -QMAKE_COMPILER_DEFINES += __QNXNTO__ - -QMAKE_INCDIR = -QMAKE_LIBDIR = QMAKE_INCDIR_X11 = /opt/X11R6/include QMAKE_LIBDIR_X11 = /opt/X11R6/lib -QMAKE_INCDIR_QT = $$[QT_INSTALL_HEADERS] -QMAKE_LIBDIR_QT = $$[QT_INSTALL_LIBS] QMAKE_INCDIR_OPENGL = /opt/X11R6/include QMAKE_LIBDIR_OPENGL = /opt/X11R6/lib -#QMAKE_LIBS = -lunix -QMAKE_LIBS = -QMAKE_LIBS_DYNLOAD = QMAKE_LIBS_X11 = -lXext -lX11 -lm -lsocket QMAKE_LIBS_X11SM = -lSM -lICE QMAKE_LIBS_OPENGL = -lGL QMAKE_LIBS_OPENGL_QT = -lGL -QMAKE_LIBS_THREAD = -QMAKE_LIBS_NETWORK = -lsocket - -QMAKE_MOC = $$[QT_INSTALL_BINS]/moc -QMAKE_UIC = $$[QT_INSTALL_BINS]/uic - -QMAKE_AR = ar cqs -QMAKE_RANLIB = - -QMAKE_TAR = tar -cf -QMAKE_GZIP = gzip -9f -QMAKE_COPY = cp -f -QMAKE_COPY_FILE = $(COPY) -QMAKE_COPY_DIR = $(COPY) -r -QMAKE_MOVE = mv -f -QMAKE_DEL_FILE = rm -f -QMAKE_DEL_DIR = rmdir -QMAKE_CHK_DIR_EXISTS = test -d -QMAKE_MKDIR = mkdir -p -QMAKE_STRIP = strip -QMAKE_STRIPFLAGS_LIB += --strip-unneeded -QMAKE_CHK_DIR_EXISTS = test -d -QMAKE_MKDIR = mkdir -p load(qt_config) diff --git a/mkspecs/unsupported/qnx-g++/qplatformdefs.h b/mkspecs/unsupported/qnx-g++/qplatformdefs.h index 8b50f92..34c1525 100644 --- a/mkspecs/unsupported/qnx-g++/qplatformdefs.h +++ b/mkspecs/unsupported/qnx-g++/qplatformdefs.h @@ -39,68 +39,4 @@ ** ****************************************************************************/ -#ifndef QPLATFORMDEFS_H -#define QPLATFORMDEFS_H - -// Get Qt defines/settings - -#include "qglobal.h" - -// Set any POSIX/XOPEN defines at the top of this file to turn on specific APIs - -#include <unistd.h> - - -// We are hot - unistd.h should have turned on the specific APIs we requested - - -#include <pthread.h> -#include <dirent.h> -#include <fcntl.h> -#include <grp.h> -#include <pwd.h> -#include <signal.h> - -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/ipc.h> -#include <sys/time.h> -// QNX doesn't have the System V <sys/shm.h> header. This is not a standard -// POSIX header, it's only documented in the Single UNIX Specification. -// The preferred POSIX compliant way to share memory is to use the functions -// in <sys/mman.h> that comply with the POSIX Real Time Interface (1003.1b). -#include <sys/mman.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <netinet/in.h> -#ifndef QT_NO_IPV6IFNAME -#include <net/if.h> -#endif - -// for htonl -#include <arpa/inet.h> - -#define QT_USE_XOPEN_LFS_EXTENSIONS -#include "../../common/posix/qplatformdefs.h" - -#define QT_SNPRINTF ::snprintf -#define QT_VSNPRINTF ::vsnprintf - -// QNX6 doesn't have getpagesize() -inline int getpagesize() -{ - return ::sysconf(_SC_PAGESIZE); -} - -#include <stdlib.h> - -// QNX6 doesn't have strtof - use strtod instead -inline float strtof(const char *b, char **e) -{ - return float(strtod(b, e)); -} - -#define QT_QWS_TEMP_DIR QString::fromLatin1(qgetenv("TMP")) - -#endif // QPLATFORMDEFS_H +#include "../../common/qnx/qplatformdefs.h" diff --git a/mkspecs/unsupported/qws/qnx-641/qmake.conf b/mkspecs/unsupported/qws/qnx-641/qmake.conf index 441f408..304ac67 100644 --- a/mkspecs/unsupported/qws/qnx-641/qmake.conf +++ b/mkspecs/unsupported/qws/qnx-641/qmake.conf @@ -59,7 +59,7 @@ QMAKE_PCH_OUTPUT_EXT = .gch QMAKE_LFLAGS_BSYMBOLIC_FUNC = -Wl,-Bsymbolic-functions QMAKE_LFLAGS_DYNAMIC_LIST = -Wl,--dynamic-list, -include(../../common/unix.conf) +include(../../../common/unix.conf) QMAKE_CFLAGS_THREAD = -D_REENTRANT QMAKE_CXXFLAGS_THREAD = $$QMAKE_CFLAGS_THREAD diff --git a/mkspecs/unsupported/qws/qnx-641/qplatformdefs.h b/mkspecs/unsupported/qws/qnx-641/qplatformdefs.h index 0c71265..ea04d0f 100644 --- a/mkspecs/unsupported/qws/qnx-641/qplatformdefs.h +++ b/mkspecs/unsupported/qws/qnx-641/qplatformdefs.h @@ -39,4 +39,4 @@ ** ****************************************************************************/ -#include "../../qnx-g++/qplatformdefs.h" +#include "../../../common/qnx/qplatformdefs.h" diff --git a/mkspecs/unsupported/qws/qnx-arm-g++/qmake.conf b/mkspecs/unsupported/qws/qnx-arm-g++/qmake.conf new file mode 100644 index 0000000..b9f946e --- /dev/null +++ b/mkspecs/unsupported/qws/qnx-arm-g++/qmake.conf @@ -0,0 +1,32 @@ +# +# qmake configuration for qnx-arm-g++ +# +# Written for QNX RTOS v6 +# + +include(../../../common/qnx/qmake.conf) + +# modifications to gcc-base.conf and g++-base.conf + +#Bug in arm compiler for QNX +QMAKE_CFLAGS_RELEASE = -O1 +QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO = -O1 -g + +QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE +QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO + +QMAKE_CC = ntoarm-gcc +QMAKE_CXX = ntoarm-g++ + +QMAKE_LINK = ntoarm-g++ +QMAKE_LINK_SHLIB = $$QMAKE_LINK +QMAKE_LINK_C = ntoarm-gcc +QMAKE_LINK_C_SHLIB = $$QMAKE_LINK_C + +# modifications to linux.conf +QMAKE_AR = ntoarm-ar cqs +QMAKE_STRIP = ntoarm-strip +QMAKE_RANLIB = ntoarm-ranlib +QMAKE_OBJCOPY = ntoarm-objcopy + +load(qt_config) diff --git a/mkspecs/unsupported/qws/qnx-arm-g++/qplatformdefs.h b/mkspecs/unsupported/qws/qnx-arm-g++/qplatformdefs.h new file mode 100644 index 0000000..5817a53 --- /dev/null +++ b/mkspecs/unsupported/qws/qnx-arm-g++/qplatformdefs.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the qmake spec of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../../../common/qnx/qplatformdefs.h" diff --git a/mkspecs/unsupported/qws/qnx-armv7-g++/qmake.conf b/mkspecs/unsupported/qws/qnx-armv7-g++/qmake.conf new file mode 100644 index 0000000..c6763d5 --- /dev/null +++ b/mkspecs/unsupported/qws/qnx-armv7-g++/qmake.conf @@ -0,0 +1,32 @@ +# +# qmake configuration for qnx-armv7-g++ +# +# Written for QNX RTOS v6 +# + +include(../../../common/qnx/qmake.conf) + +# modifications to gcc-base.conf and g++-base.conf + +# note: on the NVidia Tegra 2 and on the Marvell Dovecott, '-mfpu=neon' should be removed +QMAKE_CFLAGS_RELEASE = -O3 -march=armv7-a -mfpu=neon -mfloat-abi=softfp +QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO = -O3 -g -march=armv7-a -mfpu=neon -mfloat-abi=softfp + +QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE +QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO + +QMAKE_CC = ntoarmv7-gcc +QMAKE_CXX = ntoarmv7-g++ + +QMAKE_LINK = ntoarmv7-g++ +QMAKE_LINK_SHLIB = $$QMAKE_LINK +QMAKE_LINK_C = ntoarmv7-gcc +QMAKE_LINK_C_SHLIB = $$QMAKE_LINK_C + +# modifications to linux.conf +QMAKE_AR = ntoarmv7-ar cqs +QMAKE_STRIP = ntoarmv7-strip +QMAKE_RANLIB = ntoarmv7-ranlib +QMAKE_OBJCOPY = ntoarmv7-objcopy + +load(qt_config) diff --git a/mkspecs/unsupported/qws/qnx-armv7-g++/qplatformdefs.h b/mkspecs/unsupported/qws/qnx-armv7-g++/qplatformdefs.h new file mode 100644 index 0000000..5817a53 --- /dev/null +++ b/mkspecs/unsupported/qws/qnx-armv7-g++/qplatformdefs.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the qmake spec of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "../../../common/qnx/qplatformdefs.h" diff --git a/mkspecs/unsupported/qws/qnx-generic-g++/qmake.conf b/mkspecs/unsupported/qws/qnx-generic-g++/qmake.conf index bb760b2..f5e7045 100644 --- a/mkspecs/unsupported/qws/qnx-generic-g++/qmake.conf +++ b/mkspecs/unsupported/qws/qnx-generic-g++/qmake.conf @@ -1,102 +1,24 @@ # -# qmake configuration for qnx-g++ +# qmake configuration for qnx-generic-g++ # # Written for QNX RTOS v6 # -MAKEFILE_GENERATOR = UNIX -TARGET_PLATFORM = unix -TEMPLATE = app -CONFIG += qt warn_on release link_prl -QT += core gui +include(../../../common/qnx/qmake.conf) -# -# qmake configuration for common gcc -# - -QMAKE_CC = ntox86-gcc-3.3.5 -QMAKE_CFLAGS += -pipe -QMAKE_CFLAGS_DEPS += -M -QMAKE_CFLAGS_WARN_ON += -Wall -W -QMAKE_CFLAGS_WARN_OFF += -w -QMAKE_CFLAGS_RELEASE += -O2 -QMAKE_CFLAGS_DEBUG += -g -QMAKE_CFLAGS_SHLIB += -fPIC -QMAKE_CFLAGS_STATIC_LIB += -fPIC -QMAKE_CFLAGS_YACC += -Wno-unused -Wno-parentheses -QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden -QMAKE_CFLAGS_PRECOMPILE += -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} -QMAKE_CFLAGS_USE_PRECOMPILE += -include ${QMAKE_PCH_OUTPUT_BASE} -QMAKE_COMPILER_DEFINES += __QNXNTO__ - -QMAKE_CXX = ntox86-g++-3.3.5 -QMAKE_CXXFLAGS += $$QMAKE_CFLAGS -QMAKE_CXXFLAGS_DEPS += $$QMAKE_CFLAGS_DEPS -QMAKE_CXXFLAGS_WARN_ON += $$QMAKE_CFLAGS_WARN_ON -QMAKE_CXXFLAGS_WARN_OFF += $$QMAKE_CFLAGS_WARN_OFF -QMAKE_CXXFLAGS_RELEASE += $$QMAKE_CFLAGS_RELEASE -QMAKE_CXXFLAGS_DEBUG += $$QMAKE_CFLAGS_DEBUG -QMAKE_CXXFLAGS_SHLIB += $$QMAKE_CFLAGS_SHLIB -QMAKE_CXXFLAGS_STATIC_LIB += $$QMAKE_CFLAGS_STATIC_LIB -QMAKE_CXXFLAGS_YACC += $$QMAKE_CFLAGS_YACC -QMAKE_CXXFLAGS_HIDESYMS += $$QMAKE_CFLAGS_HIDESYMS -fvisibility-inlines-hidden -QMAKE_CXXFLAGS_PRECOMPILE += -x c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} -QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE - -QMAKE_LINK = ntox86-gcc-3.3.5 -QMAKE_LINK_SHLIB = ntox86-gcc-3.3.5 -QMAKE_LFLAGS += -Wl,--no-undefined -QMAKE_LFLAGS_RELEASE += -QMAKE_LFLAGS_DEBUG += -QMAKE_LFLAGS_APP += -QMAKE_LFLAGS_SHLIB += -shared -QMAKE_LFLAGS_PLUGIN += $$QMAKE_LFLAGS_SHLIB -QMAKE_LFLAGS_SONAME += -Wl,-soname, -QMAKE_LFLAGS_THREAD += -QMAKE_LFLAGS_RPATH = -Wl,-rpath, - -QMAKE_PCH_OUTPUT_EXT = .gch - -# -Bsymbolic-functions (ld) support -QMAKE_LFLAGS_BSYMBOLIC_FUNC = -Wl,-Bsymbolic-functions -QMAKE_LFLAGS_DYNAMIC_LIST = -Wl,--dynamic-list, - -include(../../common/unix.conf) - -QMAKE_CFLAGS_THREAD = -D_REENTRANT -QMAKE_CXXFLAGS_THREAD = $$QMAKE_CLFAGS_THREAD - -QMAKE_INCDIR = -QMAKE_LIBDIR = -QMAKE_INCDIR_QT = $$[QT_INSTALL_HEADERS] -QMAKE_LIBDIR_QT = $$[QT_INSTALL_LIBS] - -#QMAKE_LIBS = -lunix -QMAKE_LIBS = -QMAKE_LIBS_DYNLOAD = -QMAKE_LIBS_THREAD = -QMAKE_LIBS_NETWORK += -lsocket -QMAKE_LIBS_GUI += -lsocket - -QMAKE_MOC = $$[QT_INSTALL_BINS]/moc -QMAKE_UIC = $$[QT_INSTALL_BINS]/uic +# derived from g++-base.conf +#QMAKE_CC = gcc +#QMAKE_CXX = g++ -QMAKE_AR = ar cqs -QMAKE_RANLIB = +#QMAKE_LINK = g++ +#QMAKE_LINK_SHLIB = g++ +#QMAKE_LINK_C = gcc +#QMAKE_LINK_C_SHLIB = gcc -QMAKE_TAR = tar -cf -QMAKE_GZIP = gzip -9f +# derived from linux.conf +#QMAKE_AR = ar cqs +#QMAKE_OBJCOPY = objcopy +#QMAKE_RANLIB = +#QMAKE_STRIP = strip -QMAKE_COPY = cp -f -QMAKE_COPY_FILE = $(COPY) -QMAKE_COPY_DIR = $(COPY) -r -QMAKE_MOVE = mv -f -QMAKE_DEL_FILE = rm -f -QMAKE_DEL_DIR = rmdir -QMAKE_CHK_DIR_EXISTS = test -d -QMAKE_MKDIR = mkdir -p -QMAKE_STRIP = strip -QMAKE_STRIPFLAGS_LIB += --strip-unneeded -QMAKE_CHK_DIR_EXISTS = test -d -QMAKE_MKDIR = mkdir -p load(qt_config) diff --git a/mkspecs/unsupported/qws/qnx-generic-g++/qplatformdefs.h b/mkspecs/unsupported/qws/qnx-generic-g++/qplatformdefs.h index 0c71265..ea04d0f 100644 --- a/mkspecs/unsupported/qws/qnx-generic-g++/qplatformdefs.h +++ b/mkspecs/unsupported/qws/qnx-generic-g++/qplatformdefs.h @@ -39,4 +39,4 @@ ** ****************************************************************************/ -#include "../../qnx-g++/qplatformdefs.h" +#include "../../../common/qnx/qplatformdefs.h" diff --git a/mkspecs/unsupported/qws/qnx-i386-g++/qmake.conf b/mkspecs/unsupported/qws/qnx-i386-g++/qmake.conf index b43c391..6940bd8 100644 --- a/mkspecs/unsupported/qws/qnx-i386-g++/qmake.conf +++ b/mkspecs/unsupported/qws/qnx-i386-g++/qmake.conf @@ -1,98 +1,24 @@ # -# qmake configuration for qnx-g++ +# qmake configuration for qnx-i386-g++ # # Written for QNX RTOS v6 # -MAKEFILE_GENERATOR = UNIX -TARGET_PLATFORM = unix -TEMPLATE = app -CONFIG += qt warn_on release link_prl -QT += core gui +include(../../../common/qnx/qmake.conf) -QMAKE_CC = ntox86-gcc-4.2.4 -QMAKE_CFLAGS += -pipe -QMAKE_CFLAGS_DEPS += -M -QMAKE_CFLAGS_WARN_ON += -Wall -W -QMAKE_CFLAGS_WARN_OFF += -w -QMAKE_CFLAGS_RELEASE += -O2 -QMAKE_CFLAGS_DEBUG += -g -QMAKE_CFLAGS_SHLIB += -fPIC -QMAKE_CFLAGS_STATIC_LIB += -fPIC -QMAKE_CFLAGS_YACC += -Wno-unused -Wno-parentheses -QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden -QMAKE_CFLAGS_PRECOMPILE += -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} -QMAKE_CFLAGS_USE_PRECOMPILE += -include ${QMAKE_PCH_OUTPUT_BASE} -QMAKE_COMPILER_DEFINES += __QNXNTO__ +# modifications to g++-base.conf +QMAKE_CC = ntox86-gcc +QMAKE_CXX = ntox86-g++ -QMAKE_CXX = ntox86-g++-4.2.4 -QMAKE_CXXFLAGS += $$QMAKE_CFLAGS -QMAKE_CXXFLAGS_DEPS += $$QMAKE_CFLAGS_DEPS -QMAKE_CXXFLAGS_WARN_ON += $$QMAKE_CFLAGS_WARN_ON -QMAKE_CXXFLAGS_WARN_OFF += $$QMAKE_CFLAGS_WARN_OFF -QMAKE_CXXFLAGS_RELEASE += $$QMAKE_CFLAGS_RELEASE -QMAKE_CXXFLAGS_DEBUG += $$QMAKE_CFLAGS_DEBUG -QMAKE_CXXFLAGS_SHLIB += $$QMAKE_CFLAGS_SHLIB -QMAKE_CXXFLAGS_STATIC_LIB += $$QMAKE_CFLAGS_STATIC_LIB -QMAKE_CXXFLAGS_YACC += $$QMAKE_CFLAGS_YACC -QMAKE_CXXFLAGS_HIDESYMS += $$QMAKE_CFLAGS_HIDESYMS -fvisibility-inlines-hidden -QMAKE_CXXFLAGS_PRECOMPILE += -x c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} -QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE +QMAKE_LINK = ntox86-g++ +QMAKE_LINK_SHLIB = $$QMAKE_LINK +QMAKE_LINK_C = ntox86-gcc +QMAKE_LINK_C_SHLIB = $$QMAKE_LINK_C -QMAKE_LINK = ntox86-g++-4.2.4 -QMAKE_LINK_SHLIB = ntox86-g++-4.2.4 -QMAKE_LFLAGS += -Wl,--no-undefined -QMAKE_LFLAGS_RELEASE += -QMAKE_LFLAGS_DEBUG += -QMAKE_LFLAGS_APP += -QMAKE_LFLAGS_SHLIB += -shared -QMAKE_LFLAGS_PLUGIN += $$QMAKE_LFLAGS_SHLIB -QMAKE_LFLAGS_SONAME += -Wl,-soname, -QMAKE_LFLAGS_THREAD += -QMAKE_LFLAGS_RPATH = -Wl,-rpath, +# modifications to linux.conf +QMAKE_AR = ntox86-ar cqs +QMAKE_OBJCOPY = ntox86-objcopy +QMAKE_RANLIB = ntox86-ranlib +QMAKE_STRIP = ntox86-strip -QMAKE_PCH_OUTPUT_EXT = .gch - -# -Bsymbolic-functions (ld) support -QMAKE_LFLAGS_BSYMBOLIC_FUNC = -Wl,-Bsymbolic-functions -QMAKE_LFLAGS_DYNAMIC_LIST = -Wl,--dynamic-list, - -include(../../../common/unix.conf) - -QMAKE_CFLAGS_THREAD = -D_REENTRANT -QMAKE_CXXFLAGS_THREAD = $$QMAKE_CFLAGS_THREAD - -QMAKE_INCDIR = -QMAKE_LIBDIR = -QMAKE_INCDIR_QT = $$[QT_INSTALL_HEADERS] -QMAKE_LIBDIR_QT = $$[QT_INSTALL_LIBS] - -#QMAKE_LIBS = -lunix -QMAKE_LIBS = -QMAKE_LIBS_DYNLOAD = -QMAKE_LIBS_THREAD = -QMAKE_LIBS_NETWORK += -lsocket -QMAKE_LIBS_GUI += -lsocket - -QMAKE_MOC = $$[QT_INSTALL_BINS]/moc -QMAKE_UIC = $$[QT_INSTALL_BINS]/uic - -QMAKE_AR = ar cqs -QMAKE_RANLIB = - -QMAKE_TAR = tar -cf -QMAKE_GZIP = gzip -9f - -QMAKE_COPY = cp -f -QMAKE_COPY_FILE = $(COPY) -QMAKE_COPY_DIR = $(COPY) -r -QMAKE_MOVE = mv -f -QMAKE_DEL_FILE = rm -f -QMAKE_DEL_DIR = rmdir -QMAKE_CHK_DIR_EXISTS = test -d -QMAKE_MKDIR = mkdir -p -QMAKE_STRIP = strip -QMAKE_STRIPFLAGS_LIB += --strip-unneeded -QMAKE_CHK_DIR_EXISTS = test -d -QMAKE_MKDIR = mkdir -p load(qt_config) diff --git a/mkspecs/unsupported/qws/qnx-i386-g++/qplatformdefs.h b/mkspecs/unsupported/qws/qnx-i386-g++/qplatformdefs.h index 0c71265..ea04d0f 100644 --- a/mkspecs/unsupported/qws/qnx-i386-g++/qplatformdefs.h +++ b/mkspecs/unsupported/qws/qnx-i386-g++/qplatformdefs.h @@ -39,4 +39,4 @@ ** ****************************************************************************/ -#include "../../qnx-g++/qplatformdefs.h" +#include "../../../common/qnx/qplatformdefs.h" diff --git a/mkspecs/unsupported/qws/qnx-ppc-g++/qmake.conf b/mkspecs/unsupported/qws/qnx-ppc-g++/qmake.conf index 29a2952..cb4d391 100644 --- a/mkspecs/unsupported/qws/qnx-ppc-g++/qmake.conf +++ b/mkspecs/unsupported/qws/qnx-ppc-g++/qmake.conf @@ -1,98 +1,24 @@ # -# qmake configuration for qnx-g++ +# qmake configuration for qnx-ppc-g++ # # Written for QNX RTOS v6 # -MAKEFILE_GENERATOR = UNIX -TARGET_PLATFORM = unix -TEMPLATE = app -CONFIG += qt warn_on release link_prl -QT += core gui +include(../../../common/qnx/qmake.conf) -QMAKE_CC = ntoppc-gcc-4.3.3 -QMAKE_CFLAGS += -pipe -QMAKE_CFLAGS_DEPS += -M -QMAKE_CFLAGS_WARN_ON += -Wall -W -QMAKE_CFLAGS_WARN_OFF += -w -QMAKE_CFLAGS_RELEASE += -O2 -QMAKE_CFLAGS_DEBUG += -g -QMAKE_CFLAGS_SHLIB += -fPIC -QMAKE_CFLAGS_STATIC_LIB += -fPIC -QMAKE_CFLAGS_YACC += -Wno-unused -Wno-parentheses -QMAKE_CFLAGS_HIDESYMS += -fvisibility=hidden -QMAKE_CFLAGS_PRECOMPILE += -x c-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} -QMAKE_CFLAGS_USE_PRECOMPILE += -include ${QMAKE_PCH_OUTPUT_BASE} -QMAKE_COMPILER_DEFINES += __QNXNTO__ +# modifications to g++-base.conf +QMAKE_CC = ntoppc-gcc +QMAKE_CXX = ntoppc-g++ -QMAKE_CXX = ntoppc-g++-4.3.3 -QMAKE_CXXFLAGS += $$QMAKE_CFLAGS -QMAKE_CXXFLAGS_DEPS += $$QMAKE_CFLAGS_DEPS -QMAKE_CXXFLAGS_WARN_ON += $$QMAKE_CFLAGS_WARN_ON -QMAKE_CXXFLAGS_WARN_OFF += $$QMAKE_CFLAGS_WARN_OFF -QMAKE_CXXFLAGS_RELEASE += $$QMAKE_CFLAGS_RELEASE -QMAKE_CXXFLAGS_DEBUG += $$QMAKE_CFLAGS_DEBUG -QMAKE_CXXFLAGS_SHLIB += $$QMAKE_CFLAGS_SHLIB -QMAKE_CXXFLAGS_STATIC_LIB += $$QMAKE_CFLAGS_STATIC_LIB -QMAKE_CXXFLAGS_YACC += $$QMAKE_CFLAGS_YACC -QMAKE_CXXFLAGS_HIDESYMS += $$QMAKE_CFLAGS_HIDESYMS -fvisibility-inlines-hidden -QMAKE_CXXFLAGS_PRECOMPILE += -x c++-header -c ${QMAKE_PCH_INPUT} -o ${QMAKE_PCH_OUTPUT} -QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE +QMAKE_LINK = ntoppc-g++ +QMAKE_LINK_SHLIB = $$QMAKE_LINK +QMAKE_LINK_C = ntoppc-gcc +QMAKE_LINK_C_SHLIB = $$QMAKE_LINK_C -QMAKE_LINK = ntoppc-g++-4.3.3 -QMAKE_LINK_SHLIB = ntoppc-g++-4.3.3 -QMAKE_LFLAGS += -Wl,--no-undefined -QMAKE_LFLAGS_RELEASE += -QMAKE_LFLAGS_DEBUG += -QMAKE_LFLAGS_APP += -QMAKE_LFLAGS_SHLIB += -shared -QMAKE_LFLAGS_PLUGIN += $$QMAKE_LFLAGS_SHLIB -QMAKE_LFLAGS_SONAME += -Wl,-soname, -QMAKE_LFLAGS_THREAD += -QMAKE_LFLAGS_RPATH = -Wl,-rpath, +# modifications to linux.conf +QMAKE_AR = ntoppc-ar cqs +QMAKE_STRIP = ntoppc-strip +QMAKE_RANLIB = ntoppc-ranlib +QMAKE_OBJCOPY = ntoppc-objcopy -QMAKE_PCH_OUTPUT_EXT = .gch - -# -Bsymbolic-functions (ld) support -QMAKE_LFLAGS_BSYMBOLIC_FUNC = -Wl,-Bsymbolic-functions -QMAKE_LFLAGS_DYNAMIC_LIST = -Wl,--dynamic-list, - -include(../../common/unix.conf) - -QMAKE_CFLAGS_THREAD = -D_REENTRANT -QMAKE_CXXFLAGS_THREAD = $$QMAKE_CLFAGS_THREAD - -QMAKE_INCDIR = -QMAKE_LIBDIR = -QMAKE_INCDIR_QT = $$[QT_INSTALL_HEADERS] -QMAKE_LIBDIR_QT = $$[QT_INSTALL_LIBS] - -#QMAKE_LIBS = -lunix -QMAKE_LIBS = -QMAKE_LIBS_DYNLOAD = -QMAKE_LIBS_THREAD = -QMAKE_LIBS_NETWORK += -lsocket -QMAKE_LIBS_GUI += -lsocket - -QMAKE_MOC = $$[QT_INSTALL_BINS]/moc -QMAKE_UIC = $$[QT_INSTALL_BINS]/uic - -QMAKE_AR = ar cqs -QMAKE_RANLIB = - -QMAKE_TAR = tar -cf -QMAKE_GZIP = gzip -9f - -QMAKE_COPY = cp -f -QMAKE_COPY_FILE = $(COPY) -QMAKE_COPY_DIR = $(COPY) -r -QMAKE_MOVE = mv -f -QMAKE_DEL_FILE = rm -f -QMAKE_DEL_DIR = rmdir -QMAKE_CHK_DIR_EXISTS = test -d -QMAKE_MKDIR = mkdir -p -QMAKE_STRIP = strip -QMAKE_STRIPFLAGS_LIB += --strip-unneeded -QMAKE_CHK_DIR_EXISTS = test -d -QMAKE_MKDIR = mkdir -p load(qt_config) diff --git a/mkspecs/unsupported/qws/qnx-ppc-g++/qplatformdefs.h b/mkspecs/unsupported/qws/qnx-ppc-g++/qplatformdefs.h index 0c71265..ea04d0f 100644 --- a/mkspecs/unsupported/qws/qnx-ppc-g++/qplatformdefs.h +++ b/mkspecs/unsupported/qws/qnx-ppc-g++/qplatformdefs.h @@ -39,4 +39,4 @@ ** ****************************************************************************/ -#include "../../qnx-g++/qplatformdefs.h" +#include "../../../common/qnx/qplatformdefs.h" diff --git a/qmake/qmake.pri b/qmake/qmake.pri index d6c5f09..87735d6 100644 --- a/qmake/qmake.pri +++ b/qmake/qmake.pri @@ -146,7 +146,7 @@ bootstrap { #Qt code qnx { CFLAGS += -fhonor-std - LFLAGS += -lcpp + LFLAGS += -lcpp -lm } DEFINES *= QT_NO_QOBJECT } else { diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 32b3e6b..1f5f537 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -173,7 +173,6 @@ namespace QT_NAMESPACE {} RELIANT - Reliant UNIX DYNIX - DYNIX/ptx QNX - QNX - QNX6 - QNX RTP 6.1 LYNX - LynxOS BSD4 - Any BSD 4.4 system UNIX - Any UNIX BSD/SYSV system @@ -2746,17 +2745,6 @@ QT_LICENSED_MODULE(DBus) # define QT_NO_CONCURRENT_FILTER #endif -#ifdef Q_OS_QNX -// QNX doesn't have SYSV style shared memory. Multiprocess QWS apps, -// shared fonts and QSystemSemaphore + QSharedMemory are not available -# define QT_NO_QWS_MULTIPROCESS -# define QT_NO_QWS_SHARE_FONTS -# define QT_NO_SYSTEMSEMAPHORE -# define QT_NO_SHAREDMEMORY -// QNX currently doesn't support forking in a thread, so disable QProcess -# define QT_NO_PROCESS -#endif - #if defined (__ELF__) # if defined (Q_OS_LINUX) || defined (Q_OS_SOLARIS) || defined (Q_OS_FREEBSD) || defined (Q_OS_OPENBSD) || defined (Q_OS_IRIX) # define Q_OF_ELF diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 70a70c2..4b689c5 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -751,12 +751,16 @@ QProcessPrivate::QProcessPrivate() sequenceNumber = 0; exitCode = 0; exitStatus = QProcess::NormalExit; +#ifndef Q_OS_QNX startupSocketNotifier = 0; +#endif deathNotifier = 0; notifier = 0; pipeWriter = 0; +#ifndef Q_OS_QNX childStartedPipe[0] = INVALID_Q_PIPE; childStartedPipe[1] = INVALID_Q_PIPE; +#endif deathPipe[0] = INVALID_Q_PIPE; deathPipe[1] = INVALID_Q_PIPE; exitCode = 0; @@ -825,11 +829,13 @@ void QProcessPrivate::cleanup() qDeleteInEventHandler(stdinChannel.notifier); stdinChannel.notifier = 0; } +#ifndef Q_OS_QNX if (startupSocketNotifier) { startupSocketNotifier->setEnabled(false); qDeleteInEventHandler(startupSocketNotifier); startupSocketNotifier = 0; } +#endif if (deathNotifier) { deathNotifier->setEnabled(false); qDeleteInEventHandler(deathNotifier); @@ -842,7 +848,9 @@ void QProcessPrivate::cleanup() destroyPipe(stdoutChannel.pipe); destroyPipe(stderrChannel.pipe); destroyPipe(stdinChannel.pipe); +#ifndef Q_OS_QNX destroyPipe(childStartedPipe); +#endif destroyPipe(deathPipe); #ifdef Q_OS_UNIX serial = 0; @@ -1077,8 +1085,10 @@ bool QProcessPrivate::_q_startupNotification() qDebug("QProcessPrivate::startupNotification()"); #endif +#ifndef Q_OS_QNX if (startupSocketNotifier) startupSocketNotifier->setEnabled(false); +#endif if (processStarted()) { q->setProcessState(QProcess::Running); emit q->started(); diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h index 9adb331..f24a7bc 100644 --- a/src/corelib/io/qprocess_p.h +++ b/src/corelib/io/qprocess_p.h @@ -288,11 +288,15 @@ public: QRingBuffer errorReadBuffer; QRingBuffer writeBuffer; +#ifndef Q_OS_QNX Q_PIPE childStartedPipe[2]; +#endif Q_PIPE deathPipe[2]; void destroyPipe(Q_PIPE pipe[2]); +#ifndef Q_OS_QNX QSocketNotifier *startupSocketNotifier; +#endif QSocketNotifier *deathNotifier; // the wonderful windows notifier @@ -301,8 +305,10 @@ public: QWinEventNotifier *processFinishedNotifier; void startProcess(); -#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) +#if defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) && !defined(Q_OS_QNX) void execChild(const char *workingDirectory, char **path, char **argv, char **envp); +#elif defined(Q_OS_QNX) + pid_t spawnChild(const char *workingDirectory, char **argv, char **envp); #endif bool processStarted(); void terminateProcess(); diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp index 07e3087..725e4c5 100644 --- a/src/corelib/io/qprocess_unix.cpp +++ b/src/corelib/io/qprocess_unix.cpp @@ -105,6 +105,10 @@ QT_END_NAMESPACE #include <errno.h> #include <stdlib.h> #include <string.h> +#ifdef Q_OS_QNX +# include <spawn.h> +#endif + QT_BEGIN_NAMESPACE @@ -521,16 +525,6 @@ static char **_q_dupEnvironment(const QProcessEnvironmentPrivate::Hash &environm return envp; } -// under QNX RTOS we have to use vfork() when multithreading -inline pid_t qt_fork() -{ -#if defined(Q_OS_QNX) - return vfork(); -#else - return fork(); -#endif -} - #ifdef Q_OS_MAC Q_GLOBAL_STATIC(QMutex, cfbundleMutex); #endif @@ -550,15 +544,18 @@ void QProcessPrivate::startProcess() !createChannel(stdoutChannel) || !createChannel(stderrChannel)) return; +#if !defined(Q_OS_QNX) qt_create_pipe(childStartedPipe); +#endif qt_create_pipe(deathPipe); if (threadData->eventDispatcher) { +#if !defined(Q_OS_QNX) startupSocketNotifier = new QSocketNotifier(childStartedPipe[0], QSocketNotifier::Read, q); QObject::connect(startupSocketNotifier, SIGNAL(activated(int)), q, SLOT(_q_startupNotification())); - +#endif deathNotifier = new QSocketNotifier(deathPipe[0], QSocketNotifier::Read, q); QObject::connect(deathNotifier, SIGNAL(activated(int)), @@ -650,7 +647,11 @@ void QProcessPrivate::startProcess() // Start the process manager, and fork off the child process. processManager()->lock(); - pid_t childPid = qt_fork(); +#if defined(Q_OS_QNX) + pid_t childPid = spawnChild(workingDirPtr, argv, envp); +#else + pid_t childPid = fork(); +#endif int lastForkErrno = errno; if (childPid != 0) { // Clean up duplicated memory. @@ -668,7 +669,7 @@ void QProcessPrivate::startProcess() if (childPid < 0) { // Cleanup, report error and return #if defined (QPROCESS_DEBUG) - qDebug("qt_fork failed: %s", qPrintable(qt_error_string(lastForkErrno))); + qDebug("fork() failed: %s", qPrintable(qt_error_string(lastForkErrno))); #endif processManager()->unlock(); q->setProcessState(QProcess::NotRunning); @@ -679,11 +680,13 @@ void QProcessPrivate::startProcess() return; } +#if !defined(Q_OS_QNX) // Start the child. if (childPid == 0) { execChild(workingDirPtr, path, argv, envp); ::_exit(-1); } +#endif // Register the child. In the mean time, we can get a SIGCHLD, so we need // to keep the lock held to avoid a race to catch the child. @@ -694,14 +697,15 @@ void QProcessPrivate::startProcess() // parent // close the ends we don't use and make all pipes non-blocking ::fcntl(deathPipe[0], F_SETFL, ::fcntl(deathPipe[0], F_GETFL) | O_NONBLOCK); +#if !defined(Q_OS_QNX) qt_safe_close(childStartedPipe[1]); childStartedPipe[1] = -1; +#endif if (stdinChannel.pipe[0] != -1) { qt_safe_close(stdinChannel.pipe[0]); stdinChannel.pipe[0] = -1; } - if (stdinChannel.pipe[1] != -1) ::fcntl(stdinChannel.pipe[1], F_SETFL, ::fcntl(stdinChannel.pipe[1], F_GETFL) | O_NONBLOCK); @@ -709,7 +713,6 @@ void QProcessPrivate::startProcess() qt_safe_close(stdoutChannel.pipe[1]); stdoutChannel.pipe[1] = -1; } - if (stdoutChannel.pipe[0] != -1) ::fcntl(stdoutChannel.pipe[0], F_SETFL, ::fcntl(stdoutChannel.pipe[0], F_GETFL) | O_NONBLOCK); @@ -721,6 +724,7 @@ void QProcessPrivate::startProcess() ::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK); } +#if !defined(Q_OS_QNX) void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv, char **envp) { ::signal(SIGPIPE, SIG_DFL); // reset the signal that we ignored @@ -728,17 +732,17 @@ void QProcessPrivate::execChild(const char *workingDir, char **path, char **argv Q_Q(QProcess); // copy the stdin socket (without closing on exec) - qt_safe_dup2(stdinChannel.pipe[0], fileno(stdin), 0); + qt_safe_dup2(stdinChannel.pipe[0], QT_FILENO(stdin), 0); // copy the stdout and stderr if asked to if (processChannelMode != QProcess::ForwardedChannels) { - qt_safe_dup2(stdoutChannel.pipe[1], fileno(stdout), 0); + qt_safe_dup2(stdoutChannel.pipe[1], QT_FILENO(stdout), 0); // merge stdout and stderr if asked to if (processChannelMode == QProcess::MergedChannels) { - qt_safe_dup2(fileno(stdout), fileno(stderr), 0); + qt_safe_dup2(QT_FILENO(stdout), QT_FILENO(stderr), 0); } else { - qt_safe_dup2(stderrChannel.pipe[1], fileno(stderr), 0); + qt_safe_dup2(stderrChannel.pipe[1], QT_FILENO(stderr), 0); } } @@ -807,6 +811,87 @@ bool QProcessPrivate::processStarted() return i <= 0; } +#else // Q_OS_QNX + +static pid_t doSpawn(int fd_count, int fd_map[], char **argv, char **envp, bool spawn_detached) +{ + // A multi threaded QNX Process can't fork so we call spawn() instead. + + struct inheritance inherit; + memset(&inherit, 0, sizeof(inherit)); + inherit.flags |= SPAWN_SETSID; + inherit.flags |= SPAWN_CHECK_SCRIPT; + if (spawn_detached) + inherit.flags |= SPAWN_NOZOMBIE; + inherit.flags |= SPAWN_SETSIGDEF; + sigaddset(&inherit.sigdefault, SIGPIPE); // reset the signal that we ignored + + pid_t childPid; + EINTR_LOOP(childPid, ::spawn(argv[0], fd_count, fd_map, &inherit, argv, envp)); + if (childPid == -1) { + inherit.flags |= SPAWN_SEARCH_PATH; + EINTR_LOOP(childPid, ::spawn(argv[0], fd_count, fd_map, &inherit, argv, envp)); + } + + return childPid; +} + +pid_t QProcessPrivate::spawnChild(const char *workingDir, char **argv, char **envp) +{ + Q_Q(QProcess); + + const int fd_count = 3; + int fd_map[fd_count]; + switch (processChannelMode) { + case QProcess::ForwardedChannels: + fd_map[0] = stdinChannel.pipe[0]; + fd_map[1] = QT_FILENO(stdout); + fd_map[2] = QT_FILENO(stderr); + break; + case QProcess::MergedChannels: + fd_map[0] = stdinChannel.pipe[0]; + fd_map[1] = stdoutChannel.pipe[1]; + fd_map[2] = stdoutChannel.pipe[1]; + break; + case QProcess::SeparateChannels: + fd_map[0] = stdinChannel.pipe[0]; + fd_map[1] = stdoutChannel.pipe[1]; + fd_map[2] = stderrChannel.pipe[1]; + break; + } + + // enter the working directory + char *oldWorkingDir = 0; + char buff[PATH_MAX + 1]; + if (workingDir) { + oldWorkingDir = QT_GETCWD(buff, PATH_MAX + 1); + QT_CHDIR(workingDir); + } + + pid_t childPid = doSpawn(fd_count, fd_map, argv, envp, false); + + if (oldWorkingDir) + QT_CHDIR(oldWorkingDir); + + if (childPid != -1) { + q->setProcessState(QProcess::Running); + QMetaObject::invokeMethod(q, "_q_startupNotification", Qt::QueuedConnection); + } + + return childPid; +} + +bool QProcessPrivate::processStarted() +{ + return processState == QProcess::Running; +} + +bool QProcessPrivate::waitForStarted(int /*msecs*/) +{ + return processStarted(); +} +#endif // Q_OS_QNX + qint64 QProcessPrivate::bytesAvailableFromStdout() const { int nbytes = 0; @@ -924,6 +1009,7 @@ static int qt_timeout_value(int msecs, int elapsed) return timeout < 0 ? 0 : timeout; } +#if !defined(Q_OS_QNX) bool QProcessPrivate::waitForStarted(int msecs) { Q_Q(QProcess); @@ -951,6 +1037,7 @@ bool QProcessPrivate::waitForStarted(int msecs) #endif return startedEmitted; } +#endif // Q_OS_QNX bool QProcessPrivate::waitForReadyRead(int msecs) { @@ -972,8 +1059,10 @@ bool QProcessPrivate::waitForReadyRead(int msecs) int nfds = deathPipe[0]; FD_SET(deathPipe[0], &fdread); +#if !defined(Q_OS_QNX) if (processState == QProcess::Starting) add_fd(nfds, childStartedPipe[0], &fdread); +#endif if (stdoutChannel.pipe[0] != -1) add_fd(nfds, stdoutChannel.pipe[0], &fdread); @@ -994,10 +1083,12 @@ bool QProcessPrivate::waitForReadyRead(int msecs) return false; } +#if !defined(Q_OS_QNX) if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) { if (!_q_startupNotification()) return false; } +#endif bool readyReadEmitted = false; if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread)) { @@ -1044,8 +1135,10 @@ bool QProcessPrivate::waitForBytesWritten(int msecs) int nfds = deathPipe[0]; FD_SET(deathPipe[0], &fdread); +#if !defined(Q_OS_QNX) if (processState == QProcess::Starting) add_fd(nfds, childStartedPipe[0], &fdread); +#endif if (stdoutChannel.pipe[0] != -1) add_fd(nfds, stdoutChannel.pipe[0], &fdread); @@ -1068,10 +1161,12 @@ bool QProcessPrivate::waitForBytesWritten(int msecs) return false; } +#if !defined(Q_OS_QNX) if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) { if (!_q_startupNotification()) return false; } +#endif if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite)) return _q_canWrite(); @@ -1109,8 +1204,10 @@ bool QProcessPrivate::waitForFinished(int msecs) FD_ZERO(&fdread); FD_ZERO(&fdwrite); +#if !defined(Q_OS_QNX) if (processState == QProcess::Starting) add_fd(nfds, childStartedPipe[0], &fdread); +#endif if (stdoutChannel.pipe[0] != -1) add_fd(nfds, stdoutChannel.pipe[0], &fdread); @@ -1134,10 +1231,12 @@ bool QProcessPrivate::waitForFinished(int msecs) return false; } +#if !defined(Q_OS_QNX) if (childStartedPipe[0] != -1 && FD_ISSET(childStartedPipe[0], &fdread)) { if (!_q_startupNotification()) return false; } +#endif if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite)) _q_canWrite(); @@ -1199,6 +1298,47 @@ void QProcessPrivate::_q_notified() { } +#if defined(Q_OS_QNX) +bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid) +{ + QByteArray encodedWorkingDirectory = QFile::encodeName(workingDirectory); + + // enter the working directory + char *oldWorkingDir = 0; + char buff[PATH_MAX + 1]; + if (!encodedWorkingDirectory.isEmpty()) { + oldWorkingDir = QT_GETCWD(buff, PATH_MAX + 1); + QT_CHDIR(encodedWorkingDirectory.constData()); + } + + const int fd_count = 3; + int fd_map[fd_count] = { QT_FILENO(stdin), QT_FILENO(stdout), QT_FILENO(stderr) }; + + QList<QByteArray> enc_args; + enc_args.append(QFile::encodeName(program)); + for (int i = 0; i < arguments.size(); ++i) + enc_args.append(arguments.at(i).toLocal8Bit()); + + const int argc = enc_args.size(); + QScopedArrayPointer<char*> raw_argv(new char*[argc + 1]); + for (int i = 0; i < argc; ++i) + raw_argv[i] = const_cast<char *>(enc_args.at(i).data()); + raw_argv[argc] = 0; + + char **envp = 0; // inherit environment + + pid_t childPid = doSpawn(fd_count, fd_map, raw_argv.data(), envp, true); + if (pid && childPid != -1) + *pid = childPid; + + if (oldWorkingDir) + QT_CHDIR(oldWorkingDir); + + return childPid != -1; +} + +#else + bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid) { processManager()->start(); @@ -1212,7 +1352,7 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a int pidPipe[2]; qt_safe_pipe(pidPipe); - pid_t childPid = qt_fork(); + pid_t childPid = fork(); if (childPid == 0) { struct sigaction noaction; memset(&noaction, 0, sizeof(noaction)); @@ -1224,7 +1364,7 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a qt_safe_close(startedPipe[0]); qt_safe_close(pidPipe[0]); - pid_t doubleForkPid = qt_fork(); + pid_t doubleForkPid = fork(); if (doubleForkPid == 0) { qt_safe_close(pidPipe[1]); @@ -1312,6 +1452,7 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a qt_safe_close(pidPipe[0]); return success; } +#endif // Q_OS_QNX void QProcessPrivate::initializeProcessManager() { diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp index 7694a0f..dd46bc5 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -98,6 +98,12 @@ # include <taskLib.h> #endif +#ifdef Q_OS_QNX +# include <sys/neutrino.h> +# include <pthread.h> +# include <sched.h> +#endif + QT_BEGIN_NAMESPACE class QMutexUnlocker @@ -353,6 +359,22 @@ QCoreApplicationPrivate::QCoreApplicationPrivate(int &aargc, char **aargv, uint qt_application_thread_id = QThread::currentThreadId(); #endif +#ifdef Q_OS_QNX + // make the kernel attempt to emulate an instruction with a misaligned access + // if the attempt fails, it faults with a SIGBUS + int tv = -1; + ThreadCtl(_NTO_TCTL_ALIGN_FAULT, &tv); + + // without Round Robin drawn intensive apps will hog the cpu + // and make the system appear frozen + int sched_policy; + sched_param param; + if (pthread_getschedparam(0, &sched_policy, ¶m) == 0 && sched_policy != SCHED_RR) { + sched_policy = SCHED_RR; + pthread_setschedparam(0, sched_policy, ¶m); + } +#endif + // note: this call to QThread::currentThread() may end up setting theMainThread! if (QThread::currentThread() != theMainThread) qWarning("WARNING: QApplication was not created in the main() thread."); diff --git a/src/corelib/kernel/qsharedmemory.cpp b/src/corelib/kernel/qsharedmemory.cpp index 2882279..371974c 100644 --- a/src/corelib/kernel/qsharedmemory.cpp +++ b/src/corelib/kernel/qsharedmemory.cpp @@ -80,6 +80,8 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key, return result; #elif defined(Q_OS_SYMBIAN) return result.left(KMaxKernelName); +#elif defined(QT_POSIX_IPC) + return QLatin1Char('/') + result; #else return QDir::tempPath() + QLatin1Char('/') + result; #endif @@ -117,6 +119,9 @@ QSharedMemoryPrivate::makePlatformSafeKey(const QString &key, process crashes without running the QSharedMemory destructor, the shared memory segment survives the crash. + \o QNX: Due to possible race conditions in the POSIX IPC implementation, create() + should be called prior to any attach() calls (even across multiple threads). + \o HP-UX: Only one attach to a shared memory segment is allowed per process. This means that QSharedMemory should not be used across multiple threads in the same process in HP-UX. diff --git a/src/corelib/kernel/qsharedmemory_p.h b/src/corelib/kernel/qsharedmemory_p.h index 21b8612..780e52e 100644 --- a/src/corelib/kernel/qsharedmemory_p.h +++ b/src/corelib/kernel/qsharedmemory_p.h @@ -135,6 +135,8 @@ public: const QString &prefix = QLatin1String("qipc_sharedmemory_")); #ifdef Q_OS_WIN HANDLE handle(); +#elif defined(QT_POSIX_IPC) + int handle(); #else key_t handle(); #endif @@ -166,6 +168,8 @@ private: HANDLE hand; #elif defined(Q_OS_SYMBIAN) RChunk chunk; +#elif defined(QT_POSIX_IPC) + int hand; #else key_t unix_key; #endif diff --git a/src/corelib/kernel/qsharedmemory_unix.cpp b/src/corelib/kernel/qsharedmemory_unix.cpp index e991ce9..a086acd 100644 --- a/src/corelib/kernel/qsharedmemory_unix.cpp +++ b/src/corelib/kernel/qsharedmemory_unix.cpp @@ -50,8 +50,12 @@ #ifndef QT_NO_SHAREDMEMORY #include <sys/types.h> #include <sys/ipc.h> +#ifndef QT_POSIX_IPC #include <sys/shm.h> +#else +#include <sys/mman.h> #include <sys/stat.h> +#endif #include <fcntl.h> #include <unistd.h> #endif // QT_NO_SHAREDMEMORY @@ -70,7 +74,11 @@ QSharedMemoryPrivate::QSharedMemoryPrivate() #ifndef QT_NO_SYSTEMSEMAPHORE systemSemaphore(QString()), lockedByMe(false), #endif +#ifndef QT_POSIX_IPC unix_key(0) +#else + hand(0) +#endif { } @@ -91,12 +99,18 @@ void QSharedMemoryPrivate::setErrorString(const QString &function) errorString = QSharedMemory::tr("%1: doesn't exist").arg(function); error = QSharedMemory::NotFound; break; + case EAGAIN: case EMFILE: + case ENFILE: case ENOMEM: case ENOSPC: errorString = QSharedMemory::tr("%1: out of resources").arg(function); error = QSharedMemory::OutOfResources; break; + case EOVERFLOW: + errorString = QSharedMemory::tr("%1: invalid size").arg(function); + error = QSharedMemory::InvalidSize; + break; default: errorString = QSharedMemory::tr("%1: unknown error %2").arg(function).arg(errno); error = QSharedMemory::UnknownError; @@ -112,6 +126,7 @@ void QSharedMemoryPrivate::setErrorString(const QString &function) If not already made create the handle used for accessing the shared memory. */ +#ifndef QT_POSIX_IPC key_t QSharedMemoryPrivate::handle() { // already made @@ -140,6 +155,20 @@ key_t QSharedMemoryPrivate::handle() } return unix_key; } +#else +int QSharedMemoryPrivate::handle() +{ + // don't allow making handles on empty keys + QString safeKey = makePlatformSafeKey(key); + if (safeKey.isEmpty()) { + errorString = QSharedMemory::tr("%1: key is empty").arg(QLatin1String("QSharedMemory::handle")); + error = QSharedMemory::KeyError; + return 0; + } + + return 1; +} +#endif // QT_POSIX_IPC #endif // QT_NO_SHAREDMEMORY @@ -155,6 +184,7 @@ key_t QSharedMemoryPrivate::handle() */ int QSharedMemoryPrivate::createUnixKeyFile(const QString &fileName) { +#ifndef QT_POSIX_IPC if (QFile::exists(fileName)) return 0; @@ -168,6 +198,11 @@ int QSharedMemoryPrivate::createUnixKeyFile(const QString &fileName) qt_safe_close(fd); } return 1; +#else + Q_UNUSED(fileName); + // nothing to do + return -1; +#endif } #endif // QT_NO_SHAREDMEMORY && QT_NO_SYSTEMSEMAPHORE @@ -175,11 +210,17 @@ int QSharedMemoryPrivate::createUnixKeyFile(const QString &fileName) void QSharedMemoryPrivate::cleanHandle() { +#ifndef QT_POSIX_IPC unix_key = 0; +#else + qt_safe_close(hand); + hand = 0; +#endif } bool QSharedMemoryPrivate::create(int size) { +#ifndef QT_POSIX_IPC // build file if needed int built = createUnixKeyFile(nativeKey); if (built == -1) { @@ -211,12 +252,46 @@ bool QSharedMemoryPrivate::create(int size) QFile::remove(nativeKey); return false; } +#else + if (!handle()) + return false; + + QByteArray shmName = QFile::encodeName(makePlatformSafeKey(key)); + + int fd; + EINTR_LOOP(fd, shm_open(shmName.constData(), O_RDWR | O_CREAT | O_EXCL, 0666)); + if (fd == -1) { + QString function = QLatin1String("QSharedMemory::create"); + switch (errno) { + case ENAMETOOLONG: + case EINVAL: + errorString = QSharedMemory::tr("%1: bad name").arg(function); + error = QSharedMemory::KeyError; + break; + default: + setErrorString(function); + } + return false; + } + + // the size may only be set once; ignore errors + int ret; + EINTR_LOOP(ret, ftruncate(fd, size)); + if (ret == -1) { + setErrorString(QLatin1String("QSharedMemory::create (ftruncate)")); + qt_safe_close(fd); + return false; + } + + qt_safe_close(fd); +#endif // QT_POSIX_IPC return true; } bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode) { +#ifndef QT_POSIX_IPC // grab the shared memory segment id int id = shmget(unix_key, 0, (mode == QSharedMemory::ReadOnly ? 0444 : 0660)); if (-1 == id) { @@ -240,12 +315,55 @@ bool QSharedMemoryPrivate::attach(QSharedMemory::AccessMode mode) setErrorString(QLatin1String("QSharedMemory::attach (shmctl)")); return false; } +#else + QByteArray shmName = QFile::encodeName(makePlatformSafeKey(key)); + + int oflag = (mode == QSharedMemory::ReadOnly ? O_RDONLY : O_RDWR); + mode_t omode = (mode == QSharedMemory::ReadOnly ? 0444 : 0660); + + EINTR_LOOP(hand, shm_open(shmName.constData(), oflag, omode)); + if (hand == -1) { + QString function = QLatin1String("QSharedMemory::attach (shm_open)"); + switch (errno) { + case ENAMETOOLONG: + case EINVAL: + errorString = QSharedMemory::tr("%1: bad name").arg(function); + error = QSharedMemory::KeyError; + break; + default: + setErrorString(function); + } + hand = 0; + return false; + } + + // grab the size + QT_STATBUF st; + if (QT_FSTAT(hand, &st) == -1) { + setErrorString(QLatin1String("QSharedMemory::attach (fstat)")); + cleanHandle(); + return false; + } + size = st.st_size; + + // grab the memory + int mprot = (mode == QSharedMemory::ReadOnly ? PROT_READ : PROT_READ | PROT_WRITE); + memory = mmap(0, size, mprot, MAP_SHARED, hand, 0); + if (memory == MAP_FAILED || !memory) { + setErrorString(QLatin1String("QSharedMemory::attach (mmap)")); + cleanHandle(); + memory = 0; + size = 0; + return false; + } +#endif // QT_POSIX_IPC return true; } bool QSharedMemoryPrivate::detach() { +#ifndef QT_POSIX_IPC // detach from the memory segment if (-1 == shmdt(memory)) { QString function = QLatin1String("QSharedMemory::detach"); @@ -292,6 +410,31 @@ bool QSharedMemoryPrivate::detach() if (!QFile::remove(nativeKey)) return false; } +#else + // detach from the memory segment + if (munmap(memory, size) == -1) { + setErrorString(QLatin1String("QSharedMemory::detach (munmap)")); + return false; + } + memory = 0; + size = 0; + + // get the number of current attachments + int shm_nattch = 0; + QT_STATBUF st; + if (QT_FSTAT(hand, &st) == 0) { + // subtract 2 from linkcount: one for our own open and one for the dir entry + shm_nattch = st.st_nlink - 2; + } + cleanHandle(); + // if there are no attachments then unlink the shared memory + if (shm_nattch == 0) { + QByteArray shmName = QFile::encodeName(makePlatformSafeKey(key)); + if (shm_unlink(shmName.constData()) == -1 && errno != ENOENT) + setErrorString(QLatin1String("QSharedMemory::detach (shm_unlink)")); + } +#endif // QT_POSIX_IPC + return true; } diff --git a/src/corelib/kernel/qsystemsemaphore.cpp b/src/corelib/kernel/qsystemsemaphore.cpp index 98ee6f4..ae30348 100644 --- a/src/corelib/kernel/qsystemsemaphore.cpp +++ b/src/corelib/kernel/qsystemsemaphore.cpp @@ -151,6 +151,11 @@ QT_BEGIN_NAMESPACE creates a new semaphore for that key and sets its resource count to \a initialValue. + In QNX, if the \a mode is \l {QSystemSemaphore::} {Create} and the + system already has a semaphore identified by \a key, that semaphore + will be deleted and the new one will be created for that key with + a resource count set to \a initialValue. + 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 @@ -234,7 +239,7 @@ void QSystemSemaphore::setKey(const QString &key, int initialValue, AccessMode m return; d->error = NoError; d->errorString = QString(); -#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) && !defined(QT_POSIX_IPC) // 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 3e5f737..d84d416 100644 --- a/src/corelib/kernel/qsystemsemaphore_p.h +++ b/src/corelib/kernel/qsystemsemaphore_p.h @@ -61,6 +61,9 @@ #ifndef Q_OS_WINCE # include <sys/types.h> #endif +#ifdef QT_POSIX_IPC +# include <semaphore.h> +#endif #ifdef Q_OS_SYMBIAN class RSemaphore; @@ -84,6 +87,9 @@ public: #elif defined(Q_OS_SYMBIAN) int handle(QSystemSemaphore::AccessMode mode = QSystemSemaphore::Open); void setErrorString(const QString &function,int err = 0); +#elif defined(QT_POSIX_IPC) + bool handle(QSystemSemaphore::AccessMode mode = QSystemSemaphore::Open); + void setErrorString(const QString &function); #else key_t handle(QSystemSemaphore::AccessMode mode = QSystemSemaphore::Open); void setErrorString(const QString &function); @@ -99,6 +105,9 @@ public: HANDLE semaphoreLock; #elif defined(Q_OS_SYMBIAN) RSemaphore semaphore; +#elif defined(QT_POSIX_IPC) + sem_t *semaphore; + bool createdSemaphore; #else key_t unix_key; int semaphore; diff --git a/src/corelib/kernel/qsystemsemaphore_unix.cpp b/src/corelib/kernel/qsystemsemaphore_unix.cpp index 704afaf..e060eb2 100644 --- a/src/corelib/kernel/qsystemsemaphore_unix.cpp +++ b/src/corelib/kernel/qsystemsemaphore_unix.cpp @@ -50,7 +50,9 @@ #include <sys/types.h> #include <sys/ipc.h> +#ifndef QT_POSIX_IPC #include <sys/sem.h> +#endif #include <fcntl.h> #include <errno.h> @@ -67,7 +69,11 @@ QT_BEGIN_NAMESPACE QSystemSemaphorePrivate::QSystemSemaphorePrivate() : +#ifndef QT_POSIX_IPC unix_key(-1), semaphore(-1), createdFile(false), +#else + semaphore(SEM_FAILED), +#endif createdSemaphore(false), error(QSystemSemaphore::NoError) { } @@ -90,10 +96,18 @@ void QSystemSemaphorePrivate::setErrorString(const QString &function) error = QSystemSemaphore::NotFound; break; case ERANGE: + case ENOMEM: case ENOSPC: + case EMFILE: + case ENFILE: + case EOVERFLOW: errorString = QCoreApplication::translate("QSystemSemaphore", "%1: out of resources").arg(function); error = QSystemSemaphore::OutOfResources; break; + case ENAMETOOLONG: + errorString = QCoreApplication::translate("QSystemSemaphore", "%1: name error").arg(function); + error = QSystemSemaphore::KeyError; + break; default: errorString = QCoreApplication::translate("QSystemSemaphore", "%1: unknown error %2").arg(function).arg(errno); error = QSystemSemaphore::UnknownError; @@ -109,6 +123,7 @@ void QSystemSemaphorePrivate::setErrorString(const QString &function) Initialise the semaphore */ +#ifndef QT_POSIX_IPC key_t QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode) { if (-1 != unix_key) @@ -170,6 +185,54 @@ key_t QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode) return unix_key; } +#else +bool QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode) +{ + if (semaphore != SEM_FAILED) + return true; // we already have a semaphore + + if (fileName.isEmpty()) { + errorString = QCoreApplication::tr("%1: key is empty", "QSystemSemaphore").arg(QLatin1String("QSystemSemaphore::handle")); + error = QSystemSemaphore::KeyError; + return false; + } + + QByteArray semName = QFile::encodeName(fileName); + + // Always try with O_EXCL so we know whether we created the semaphore. + int oflag = O_CREAT | O_EXCL; + for (int tryNum = 0, maxTries = 1; tryNum < maxTries; ++tryNum) { + do { + semaphore = sem_open(semName.constData(), oflag, 0666, initialValue); + } while (semaphore == SEM_FAILED && errno == EINTR); + if (semaphore == SEM_FAILED && errno == EEXIST) { + if (mode == QSystemSemaphore::Create) { + if (sem_unlink(semName.constData()) == -1 && errno != ENOENT) { + setErrorString(QLatin1String("QSystemSemaphore::handle (sem_unlink)")); + return false; + } + // Race condition: the semaphore might be recreated before + // we call sem_open again, so we'll retry several times. + maxTries = 3; + } else { + // Race condition: if it no longer exists at the next sem_open + // call, we won't realize we created it, so we'll leak it later. + oflag &= ~O_EXCL; + maxTries = 2; + } + } else { + break; + } + } + if (semaphore == SEM_FAILED) { + setErrorString(QLatin1String("QSystemSemaphore::handle")); + return false; + } + + createdSemaphore = (oflag & O_EXCL) != 0; + return true; +} +#endif // QT_POSIX_IPC /*! \internal @@ -178,6 +241,7 @@ key_t QSystemSemaphorePrivate::handle(QSystemSemaphore::AccessMode mode) */ void QSystemSemaphorePrivate::cleanHandle() { +#ifndef QT_POSIX_IPC unix_key = -1; // remove the file if we made it @@ -198,6 +262,27 @@ void QSystemSemaphorePrivate::cleanHandle() } createdSemaphore = false; } +#else + if (semaphore != SEM_FAILED) { + if (sem_close(semaphore) == -1) { + setErrorString(QLatin1String("QSystemSemaphore::cleanHandle (sem_close)")); +#ifdef QSYSTEMSEMAPHORE_DEBUG + qDebug() << QLatin1String("QSystemSemaphore::cleanHandle sem_close failed."); +#endif + } + semaphore = SEM_FAILED; + } + + if (createdSemaphore) { + if (sem_unlink(QFile::encodeName(fileName).constData()) == -1 && errno != ENOENT) { + setErrorString(QLatin1String("QSystemSemaphore::cleanHandle (sem_unlink)")); +#ifdef QSYSTEMSEMAPHORE_DEBUG + qDebug() << QLatin1String("QSystemSemaphore::cleanHandle sem_unlink failed."); +#endif + } + createdSemaphore = false; + } +#endif // QT_POSIX_IPC } /*! @@ -205,6 +290,7 @@ void QSystemSemaphorePrivate::cleanHandle() */ bool QSystemSemaphorePrivate::modifySemaphore(int count) { +#ifndef QT_POSIX_IPC if (-1 == handle()) return false; @@ -229,6 +315,44 @@ bool QSystemSemaphorePrivate::modifySemaphore(int count) #endif return false; } +#else + if (!handle()) + return false; + + if (count > 0) { + int cnt = count; + do { + if (sem_post(semaphore) == -1) { + setErrorString(QLatin1String("QSystemSemaphore::modifySemaphore (sem_post)")); +#ifdef QSYSTEMSEMAPHORE_DEBUG + qDebug() << QLatin1String("QSystemSemaphore::modify sem_post failed") << count << errno; +#endif + // rollback changes to preserve the SysV semaphore behavior + for ( ; cnt < count; ++cnt) { + register int res; + EINTR_LOOP(res, sem_wait(semaphore)); + } + return false; + } + --cnt; + } while (cnt > 0); + } else { + register int res; + EINTR_LOOP(res, sem_wait(semaphore)); + if (res == -1) { + // If the semaphore was removed be nice and create it and then modifySemaphore again + if (errno == EINVAL || errno == EIDRM) { + semaphore = SEM_FAILED; + return modifySemaphore(count); + } + setErrorString(QLatin1String("QSystemSemaphore::modifySemaphore (sem_wait)")); +#ifdef QSYSTEMSEMAPHORE_DEBUG + qDebug() << QLatin1String("QSystemSemaphore::modify sem_wait failed") << count << errno; +#endif + return false; + } + } +#endif // QT_POSIX_IPC return true; } diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 839a396..765969e 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -479,6 +479,11 @@ void QThread::usleep(unsigned long usecs) // sched_priority is OUT only static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority) { +#ifdef Q_OS_QNX + // without Round Robin drawn intensive apps will hog the cpu + // and make the system appear frozen + *sched_policy = SCHED_RR; +#endif #ifdef SCHED_IDLE if (priority == QThread::IdlePriority) { *sched_policy = SCHED_IDLE; diff --git a/src/gui/embedded/embedded.pri b/src/gui/embedded/embedded.pri index 31f0bc6..836c116 100644 --- a/src/gui/embedded/embedded.pri +++ b/src/gui/embedded/embedded.pri @@ -117,7 +117,7 @@ embedded { contains( gfx-drivers, qnx ) { HEADERS += embedded/qscreenqnx_qws.h SOURCES += embedded/qscreenqnx_qws.cpp - LIBS += -lgf + LIBS_PRIVATE += -lgf } contains( gfx-drivers, integrityfb ) { diff --git a/src/gui/embedded/qkbdqnx_qws.cpp b/src/gui/embedded/qkbdqnx_qws.cpp index 5a8118d..ad76446 100644 --- a/src/gui/embedded/qkbdqnx_qws.cpp +++ b/src/gui/embedded/qkbdqnx_qws.cpp @@ -40,16 +40,16 @@ ****************************************************************************/ #include "qkbdqnx_qws.h" -#include "QtCore/qsocketnotifier.h" + +#include "qplatformdefs.h" +#include "qsocketnotifier.h" +#include "private/qcore_unix_p.h" #include "QtCore/qdebug.h" #include <sys/dcmd_input.h> -#include <photon/keycodes.h> - -#include "qplatformdefs.h" +#include <sys/keycodes.h> #include <errno.h> - QT_BEGIN_NAMESPACE /*! @@ -72,7 +72,7 @@ QT_BEGIN_NAMESPACE Example invocation from command line: \c{/usr/photon/bin/devi-hid -Pr kbd mouse} Note that after running \c{devi-hid}, you will not be able to use the local - shell anymore. It is suggested to run the command in a shell scrip, that launches + shell anymore. It is suggested to run the command in a shell script, that launches a Qt application after invocation of \c{devi-hid}. To make \l{Qt for Embedded Linux} explicitly choose the qnx keyboard @@ -100,15 +100,13 @@ QWSQnxKeyboardHandler::QWSQnxKeyboardHandler(const QString &device) QT_OPEN_RDONLY); if (keyboardFD == -1) { qErrnoWarning(errno, "QWSQnxKeyboardHandler: Unable to open device"); - return; - } - - // create a socket notifier so we'll wake up whenever keyboard input is detected. - QSocketNotifier *notifier = new QSocketNotifier(keyboardFD, QSocketNotifier::Read, this); - connect(notifier, SIGNAL(activated(int)), SLOT(socketActivated())); - - qDebug() << "QWSQnxKeyboardHandler: connected."; + } else { + // create a socket notifier so we'll wake up whenever keyboard input is detected. + QSocketNotifier *notifier = new QSocketNotifier(keyboardFD, QSocketNotifier::Read, this); + connect(notifier, SIGNAL(activated(int)), SLOT(socketActivated())); + qDebug("QWSQnxKeyboardHandler: connected."); + } } /*! @@ -116,7 +114,16 @@ QWSQnxKeyboardHandler::QWSQnxKeyboardHandler(const QString &device) */ QWSQnxKeyboardHandler::~QWSQnxKeyboardHandler() { - QT_CLOSE(keyboardFD); + if (keyboardFD != -1) + QT_CLOSE(keyboardFD); +} + +// similar to PhKeyToMb +static inline bool key_sym_displayable(unsigned long sym) +{ + if (sym >= 0xF000) + return sym >= 0xF100 && (sizeof(wchar_t) > 2 || sym < 0x10000); + return (sym & ~0x9F) != 0; // exclude 0...0x1F and 0x80...0x9F } /*! \internal @@ -136,6 +143,11 @@ void QWSQnxKeyboardHandler::socketActivated() // the bytes read must be the size of a keyboard packet Q_ASSERT(bytesRead == sizeof(_keyboard_packet)); + if (packet.data.flags & KEY_SYM_VALID_EX) + packet.data.flags |= KEY_SYM_VALID; + else if (!(packet.data.flags & (KEY_SYM_VALID | KEY_CAP_VALID))) + return; + #if 0 qDebug() << "keyboard got scancode" << hex << packet.data.modifiers @@ -145,86 +157,157 @@ void QWSQnxKeyboardHandler::socketActivated() << packet.data.key_scan; #endif - // QNX is nice enough to translate the raw keyboard data into a QNX data structure + // QNX is nice enough to translate the raw keyboard data into generic format for us. // Now we just have to translate it into a format Qt understands. - // figure out whether it's a press - bool isPress = packet.data.key_cap & KEY_DOWN; - // figure out whether the key is still pressed and the key event is repeated - bool isRepeat = packet.data.key_cap & KEY_REPEAT; - - Qt::Key key = Qt::Key_unknown; - int unicode = 0xffff; - - // TODO - this switch is not complete! - switch (packet.data.key_scan) { - case KEYCODE_SPACE: key = Qt::Key_Space; unicode = 0x20; break; - case KEYCODE_F1: key = Qt::Key_F1; break; - case KEYCODE_F2: key = Qt::Key_F2; break; - case KEYCODE_F3: key = Qt::Key_F3; break; - case KEYCODE_F4: key = Qt::Key_F4; break; - case KEYCODE_F5: key = Qt::Key_F5; break; - case KEYCODE_F6: key = Qt::Key_F6; break; - case KEYCODE_F7: key = Qt::Key_F7; break; - case KEYCODE_F8: key = Qt::Key_F8; break; - case KEYCODE_F9: key = Qt::Key_F9; break; - case KEYCODE_F10: key = Qt::Key_F10; break; - case KEYCODE_F11: key = Qt::Key_F11; break; - case KEYCODE_F12: key = Qt::Key_F12; break; - case KEYCODE_BACKSPACE: key = Qt::Key_Backspace; break; - case KEYCODE_TAB: key = Qt::Key_Tab; break; - case KEYCODE_RETURN: key = Qt::Key_Return; break; - case KEYCODE_KP_ENTER: key = Qt::Key_Enter; break; - case KEYCODE_UP: - case KEYCODE_KP_UP: - key = Qt::Key_Up; break; - case KEYCODE_DOWN: - case KEYCODE_KP_DOWN: - key = Qt::Key_Down; break; - case KEYCODE_LEFT: - case KEYCODE_KP_LEFT: - key = Qt::Key_Left; break; - case KEYCODE_RIGHT: - case KEYCODE_KP_RIGHT: - key = Qt::Key_Right; break; - case KEYCODE_HOME: - case KEYCODE_KP_HOME: - key = Qt::Key_Home; break; - case KEYCODE_END: - case KEYCODE_KP_END: - key = Qt::Key_End; break; - case KEYCODE_PG_UP: - case KEYCODE_KP_PG_UP: - key = Qt::Key_PageUp; break; - case KEYCODE_PG_DOWN: - case KEYCODE_KP_PG_DOWN: - key = Qt::Key_PageDown; break; - case KEYCODE_INSERT: - case KEYCODE_KP_INSERT: - key = Qt::Key_Insert; break; - case KEYCODE_DELETE: - case KEYCODE_KP_DELETE: - key = Qt::Key_Delete; break; - case KEYCODE_ESCAPE: - key = Qt::Key_Escape; break; - default: // none of the above, try the key_scan directly - unicode = packet.data.key_scan; - break; - } - // figure out the modifiers that are currently pressed Qt::KeyboardModifiers modifiers = Qt::NoModifier; - if (packet.data.flags & KEYMOD_SHIFT) + if (packet.data.modifiers & KEYMOD_SHIFT) modifiers |= Qt::ShiftModifier; - if (packet.data.flags & KEYMOD_CTRL) + if (packet.data.modifiers & KEYMOD_CTRL) modifiers |= Qt::ControlModifier; - if (packet.data.flags & KEYMOD_ALT) + if (packet.data.modifiers & KEYMOD_ALT) modifiers |= Qt::AltModifier; + if (packet.data.modifiers & KEYMOD_NUM_LOCK) + modifiers |= Qt::KeypadModifier; +#if 0 + // special case for AltGr + if (packet.data.modifiers & KEYMOD_ALTGR) + key = Qt::Key_AltGr; +#endif + + // figure out whether it's a press + bool isPress = packet.data.flags & KEY_DOWN; + // figure out whether the key is still pressed and the key event is repeated + bool isRepeat = packet.data.flags & KEY_REPEAT; + + int key = Qt::Key_unknown; + int unicode = 0; + + if (((packet.data.flags & KEY_SYM_VALID) && key_sym_displayable(unicode = packet.data.key_sym)) + || ((packet.data.flags & KEY_CAP_VALID) && key_sym_displayable(unicode = packet.data.key_cap))) { + if (unicode <= 0x0ff) { + if (unicode >= 'a' && unicode <= 'z') + key = Qt::Key_A + unicode - 'a'; + else + key = unicode; + } + // Ctrl<something> or Alt<something> is not a displayable character + if (modifiers & (Qt::ControlModifier | Qt::AltModifier)) + unicode = 0; + } else { + unicode = 0; + + unsigned long sym = 0; + if (packet.data.flags & KEY_SYM_VALID) + sym = packet.data.key_sym; + else if (packet.data.flags & KEY_CAP_VALID) + sym = packet.data.key_cap; - // if the unicode value is not ascii, we ignore it. - // TODO - do a complete mapping between all QNX scan codes and Qt codes - if (unicode != 0xffff && !isascii(unicode)) - return; // unprintable character + switch (sym) { + case KEYCODE_ESCAPE: key = Qt::Key_Escape; unicode = 27; break; + case KEYCODE_TAB: key = Qt::Key_Tab; unicode = 9; break; + case KEYCODE_BACK_TAB: key = Qt::Key_Backtab; break; + case KEYCODE_BACKSPACE: key = Qt::Key_Backspace; unicode = 127; break; + case KEYCODE_RETURN: key = Qt::Key_Return; break; + case KEYCODE_KP_ENTER: key = Qt::Key_Enter; break; + case KEYCODE_INSERT: + case KEYCODE_KP_INSERT: + key = Qt::Key_Insert; break; + case KEYCODE_KP_DELETE: + if (modifiers & Qt::KeypadModifier) { + key = Qt::Key_Comma; + break; + } + // fall through + case KEYCODE_DELETE: + key = Qt::Key_Delete; break; + case KEYCODE_PAUSE: + case KEYCODE_BREAK: + if (modifiers & (Qt::ControlModifier | Qt::AltModifier)) + return; // sometimes occurs at the middle of a key sequence + key = Qt::Key_Pause; break; + case KEYCODE_PRINT: + if (modifiers & (Qt::ControlModifier | Qt::AltModifier)) + return; // sometimes occurs at the middle of a key sequence + key = Qt::Key_Print; break; + case KEYCODE_SYSREQ: + key = Qt::Key_SysReq; break; + case KEYCODE_HOME: + case KEYCODE_KP_HOME: + key = Qt::Key_Home; break; + case KEYCODE_END: + case KEYCODE_KP_END: + key = Qt::Key_End; break; + case KEYCODE_LEFT: + case KEYCODE_KP_LEFT: + key = Qt::Key_Left; break; + case KEYCODE_UP: + case KEYCODE_KP_UP: + key = Qt::Key_Up; break; + case KEYCODE_RIGHT: + case KEYCODE_KP_RIGHT: + key = Qt::Key_Right; break; + case KEYCODE_DOWN: + case KEYCODE_KP_DOWN: + key = Qt::Key_Down; break; + case KEYCODE_PG_UP: + case KEYCODE_KP_PG_UP: + key = Qt::Key_PageUp; break; + case KEYCODE_PG_DOWN: + case KEYCODE_KP_PG_DOWN: + key = Qt::Key_PageDown; break; + + case KEYCODE_LEFT_SHIFT: + case KEYCODE_RIGHT_SHIFT: + key = Qt::Key_Shift; break; + case KEYCODE_LEFT_CTRL: + case KEYCODE_RIGHT_CTRL: + key = Qt::Key_Control; break; + case KEYCODE_LEFT_ALT: + case KEYCODE_RIGHT_ALT: + key = Qt::Key_Alt; break; + case KEYCODE_CAPS_LOCK: + key = Qt::Key_CapsLock; break; + case KEYCODE_NUM_LOCK: + key = Qt::Key_NumLock; break; + case KEYCODE_SCROLL_LOCK: + key = Qt::Key_ScrollLock; break; + + case KEYCODE_F1: + case KEYCODE_F2: + case KEYCODE_F3: + case KEYCODE_F4: + case KEYCODE_F5: + case KEYCODE_F6: + case KEYCODE_F7: + case KEYCODE_F8: + case KEYCODE_F9: + case KEYCODE_F10: + case KEYCODE_F11: + case KEYCODE_F12: + key = Qt::Key_F1 + sym - KEYCODE_F1; break; + + case KEYCODE_MENU: key = Qt::Key_Menu; break; + case KEYCODE_LEFT_HYPER: key = Qt::Key_Hyper_L; break; + case KEYCODE_RIGHT_HYPER: key = Qt::Key_Hyper_R; break; + + case KEYCODE_KP_PLUS: key = Qt::Key_Plus; break; + case KEYCODE_KP_MINUS: key = Qt::Key_Minus; break; + case KEYCODE_KP_MULTIPLY: key = Qt::Key_multiply; break; + case KEYCODE_KP_DIVIDE: key = Qt::Key_Slash; break; + case KEYCODE_KP_FIVE: + if (!(modifiers & Qt::KeypadModifier)) + key = Qt::Key_5; + break; + + default: // none of the above + break; + } + } + + if (key == Qt::Key_unknown && unicode == 0) + return; // call processKeyEvent. This is where all the magic happens to insert a // key event into Qt's event loop. diff --git a/src/gui/embedded/qlock.cpp b/src/gui/embedded/qlock.cpp index ac15431..eaad15c 100644 --- a/src/gui/embedded/qlock.cpp +++ b/src/gui/embedded/qlock.cpp @@ -41,7 +41,6 @@ #include "qlock_p.h" - #ifdef QT_NO_QWS_MULTIPROCESS QT_BEGIN_NAMESPACE @@ -83,7 +82,7 @@ QT_END_NAMESPACE #else // QT_NO_QWS_MULTIPROCESS #if defined(Q_OS_DARWIN) -# define Q_NO_SEMAPHORE +# define QT_NO_SEMAPHORE #endif #include "qwssignalhandler_p.h" @@ -91,11 +90,13 @@ QT_END_NAMESPACE #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> -#if defined(Q_NO_SEMAPHORE) +#if defined(QT_NO_SEMAPHORE) # include <sys/stat.h> # include <sys/file.h> -#else +#elif !defined(QT_POSIX_IPC) # include <sys/sem.h> +#else +# include <semaphore.h> #endif #include <string.h> #include <errno.h> @@ -109,17 +110,24 @@ QT_BEGIN_NAMESPACE class QLockData { public: -#ifdef Q_NO_SEMAPHORE +#if defined(QT_NO_SEMAPHORE) || defined(QT_POSIX_IPC) QByteArray file; -#endif // Q_NO_SEMAPHORE +#endif +#if !defined(QT_POSIX_IPC) int id; +#else + sem_t *id; // Read mode resource counter + sem_t *rsem; // Read mode lock + sem_t *wsem; // Write mode lock +#endif int count; bool owned; }; + /*! \class QLock - \brief The QLock class is a wrapper for a System V shared semaphore. + \brief The QLock class is a wrapper for a system shared semaphore. \ingroup qws @@ -148,7 +156,7 @@ QLock::QLock(const QString &filename, char id, bool create) { data = new QLockData; data->count = 0; -#ifdef Q_NO_SEMAPHORE +#if defined(QT_NO_SEMAPHORE) data->file = filename.toLocal8Bit() + id; for (int x = 0; x < 2; ++x) { data->id = QT_OPEN(data->file.constData(), O_RDWR | (x ? O_CREAT : 0), S_IRWXU); @@ -157,7 +165,7 @@ QLock::QLock(const QString &filename, char id, bool create) break; } } -#else +#elif !defined(QT_POSIX_IPC) key_t semkey = ftok(filename.toLocal8Bit().constData(), id); data->id = semget(semkey, 0, 0); data->owned = create; @@ -170,6 +178,28 @@ QLock::QLock(const QString &filename, char id, bool create) arg.val = MAX_LOCKS; semctl(data->id, 0, SETVAL, arg); } +#else + data->file = filename.toLocal8Bit() + id; + data->owned = create; + + char ids[3] = { 'c', 'r', 'w' }; + sem_t **sems[3] = { &data->id, &data->rsem, &data->wsem }; + unsigned short initialValues[3] = { MAX_LOCKS, 1, 1 }; + for (int i = 0; i < 3; ++i) { + QByteArray file = data->file + ids[i]; + do { + *sems[i] = sem_open(file.constData(), 0, 0666, 0); + } while (*sems[i] == SEM_FAILED && errno == EINTR); + if (create) { + if (*sems[i] != SEM_FAILED) { + sem_close(*sems[i]); + sem_unlink(file.constData()); + } + do { + *sems[i] = sem_open(file.constData(), O_CREAT, 0666, initialValues[i]); + } while (*sems[i] == SEM_FAILED && errno == EINTR); + } + } #endif if (!isValid()) { qWarning("QLock::QLock: Cannot %s semaphore %s '%c' (%d, %s)", @@ -193,17 +223,32 @@ QLock::~QLock() while (locked()) unlock(); -#ifdef Q_NO_SEMAPHORE + +#if defined(QT_NO_SEMAPHORE) if (isValid()) QT_CLOSE(data->id); +#elif defined(QT_POSIX_IPC) + if (data->id != SEM_FAILED) + sem_close(data->id); + if (data->rsem != SEM_FAILED) + sem_close(data->rsem); + if (data->wsem != SEM_FAILED) + sem_close(data->wsem); #endif + if (data->owned) { -#ifdef Q_NO_SEMAPHORE +#if defined(QT_NO_SEMAPHORE) unlink(data->file.constData()); -#else +#elif !defined(QT_POSIX_IPC) qt_semun semval; semval.val = 0; semctl(data->id, 0, IPC_RMID, semval); +#else + char ids[3] = { 'c', 'r', 'w' }; + for (int i = 0; i < 3; ++i) { + QByteArray file = data->file + ids[i]; + sem_unlink(file.constData()); + } #endif } delete data; @@ -216,7 +261,11 @@ QLock::~QLock() */ bool QLock::isValid() const { +#if !defined(QT_POSIX_IPC) return data && data->id != -1; +#else + return data && data->id != SEM_FAILED && data->rsem != SEM_FAILED && data->wsem != SEM_FAILED; +#endif } /*! @@ -232,21 +281,48 @@ bool QLock::isValid() const */ void QLock::lock(Type t) { + if (!isValid()) + return; + if (!data->count) { type = t; int rv; -#ifdef Q_NO_SEMAPHORE +#if defined(QT_NO_SEMAPHORE) int op = type == Write ? LOCK_EX : LOCK_SH; EINTR_LOOP(rv, flock(data->id, op)); -#else +#elif !defined(QT_POSIX_IPC) sembuf sops; sops.sem_num = 0; sops.sem_op = type == Write ? -MAX_LOCKS : -1; sops.sem_flg = SEM_UNDO; EINTR_LOOP(rv, semop(data->id, &sops, 1)); +#else + if (type == Write) { + EINTR_LOOP(rv, sem_wait(data->rsem)); + if (rv != -1) { + EINTR_LOOP(rv, sem_wait(data->wsem)); + if (rv == -1) + sem_post(data->rsem); + } + } else { + EINTR_LOOP(rv, sem_wait(data->wsem)); + if (rv != -1) { + EINTR_LOOP(rv, sem_trywait(data->rsem)); + if (rv != -1 || errno == EAGAIN) { + EINTR_LOOP(rv, sem_wait(data->id)); + if (rv == -1) { + int semval; + sem_getvalue(data->id, &semval); + if (semval == MAX_LOCKS) + sem_post(data->rsem); + } + } + rv = sem_post(data->wsem); + } + } #endif if (rv == -1) { qDebug("QLock::lock(): %s", strerror(errno)); @@ -265,19 +341,37 @@ void QLock::lock(Type t) */ void QLock::unlock() { - if (data->count) { + if (!isValid()) + return; + + if (data->count > 0) { data->count--; if (!data->count) { int rv; -#ifdef Q_NO_SEMAPHORE +#if defined(QT_NO_SEMAPHORE) EINTR_LOOP(rv, flock(data->id, LOCK_UN)); -#else +#elif !defined(QT_POSIX_IPC) sembuf sops; sops.sem_num = 0; sops.sem_op = type == Write ? MAX_LOCKS : 1; sops.sem_flg = SEM_UNDO; EINTR_LOOP(rv, semop(data->id, &sops, 1)); +#else + if (type == Write) { + sem_post(data->wsem); + rv = sem_post(data->rsem); + } else { + EINTR_LOOP(rv, sem_wait(data->wsem)); + if (rv != -1) { + sem_post(data->id); + int semval; + sem_getvalue(data->id, &semval); + if (semval == MAX_LOCKS) + sem_post(data->rsem); + rv = sem_post(data->wsem); + } + } #endif if (rv == -1) qDebug("QLock::unlock(): %s", strerror(errno)); diff --git a/src/gui/embedded/qmouselinuxinput_qws.cpp b/src/gui/embedded/qmouselinuxinput_qws.cpp index efcf6d4..19a9a99 100644 --- a/src/gui/embedded/qmouselinuxinput_qws.cpp +++ b/src/gui/embedded/qmouselinuxinput_qws.cpp @@ -135,19 +135,21 @@ void QWSLinuxInputMousePrivate::readMouseData() int n = 0; forever { - n = QT_READ(m_fd, reinterpret_cast<char *>(buffer) + n, sizeof(buffer) - n); - - if (n == 0) { + int bytesRead = QT_READ(m_fd, reinterpret_cast<char *>(buffer) + n, sizeof(buffer) - n); + if (bytesRead == 0) { qWarning("Got EOF from the input device."); return; - } else if (n < 0 && (errno != EINTR && errno != EAGAIN)) { - qWarning("Could not read from input device: %s", strerror(errno)); - return; - } else if (n % sizeof(buffer[0]) == 0) { + } + if (bytesRead == -1) { + if (errno != EAGAIN) + qWarning("Could not read from input device: %s", strerror(errno)); break; } - } + n += bytesRead; + if (n % sizeof(buffer[0]) == 0) + break; + } n /= sizeof(buffer[0]); for (int i = 0; i < n; ++i) { diff --git a/src/gui/embedded/qmouseqnx_qws.cpp b/src/gui/embedded/qmouseqnx_qws.cpp index a9647c0..d0b892e 100644 --- a/src/gui/embedded/qmouseqnx_qws.cpp +++ b/src/gui/embedded/qmouseqnx_qws.cpp @@ -39,14 +39,13 @@ ** ****************************************************************************/ -#include "qplatformdefs.h" #include "qmouseqnx_qws.h" +#include "qplatformdefs.h" #include "qsocketnotifier.h" -#include "qdebug.h" +#include "private/qcore_unix_p.h" #include <sys/dcmd_input.h> - #include <errno.h> QT_BEGIN_NAMESPACE @@ -92,22 +91,28 @@ QT_BEGIN_NAMESPACE \sa QMouseDriverFactory */ -QQnxMouseHandler::QQnxMouseHandler(const QString & /*driver*/, const QString &device) +QQnxMouseHandler::QQnxMouseHandler(const QString & driver, const QString &device) + : QObject(), QWSMouseHandler(driver, device), mouseButtons(Qt::NoButton) { // open the mouse device with O_NONBLOCK so reading won't block when there's no data mouseFD = QT_OPEN(device.isEmpty() ? "/dev/devi/mouse0" : device.toLatin1().constData(), - QT_OPEN_RDONLY | O_NONBLOCK); + QT_OPEN_RDONLY | O_NONBLOCK); if (mouseFD == -1) { qErrnoWarning(errno, "QQnxMouseHandler: Unable to open mouse device"); - return; + } else { + struct _pointer_info data; + if (devctl(mouseFD, _POINTERGETINFO, &data, sizeof(data), NULL) == EOK) + absolutePositioning = (data.flags & _POINTER_FLAG_ABSOLUTE); + else + absolutePositioning = !device.isEmpty() && device.contains(QLatin1String("touch")); + + // register a socket notifier on the file descriptor so we'll wake up whenever + // there's a mouse move waiting for us. + mouseNotifier = new QSocketNotifier(mouseFD, QSocketNotifier::Read, this); + connect(mouseNotifier, SIGNAL(activated(int)), SLOT(socketActivated())); + + qDebug("QQnxMouseHandler: connected."); } - - // register a socket notifier on the file descriptor so we'll wake up whenever - // there's a mouse move waiting for us. - mouseNotifier = new QSocketNotifier(mouseFD, QSocketNotifier::Read, this); - connect(mouseNotifier, SIGNAL(activated(int)), SLOT(socketActivated())); - - qDebug() << "QQnxMouseHandler: connected."; } /*! @@ -115,7 +120,8 @@ QQnxMouseHandler::QQnxMouseHandler(const QString & /*driver*/, const QString &de */ QQnxMouseHandler::~QQnxMouseHandler() { - QT_CLOSE(mouseFD); + if (mouseFD != -1) + QT_CLOSE(mouseFD); } /*! \reimp */ @@ -140,39 +146,45 @@ void QQnxMouseHandler::suspend() */ void QQnxMouseHandler::socketActivated() { + QPoint queuedPos = mousePos; + // _mouse_packet is a QNX structure. devi-hid is nice enough to translate // the raw byte data from mouse devices into generic format for us. - _mouse_packet packet; + struct _mouse_packet buffer[32]; + int n = 0; - int iteration = 0; - - // read mouse events in batches of 10. Since we're getting quite a lot - // of mouse events, it's better to do them in batches than to return to the - // event loop every time. - do { - int bytesRead = QT_READ(mouseFD, &packet, sizeof(packet)); + forever { + int bytesRead = QT_READ(mouseFD, reinterpret_cast<char *>(buffer) + n, sizeof(buffer) - n); if (bytesRead == -1) { // EAGAIN means that there are no more mouse events to read if (errno != EAGAIN) - qErrnoWarning(errno, "QQnxMouseHandler: Unable to read from socket"); - return; + qErrnoWarning(errno, "QQnxMouseHandler: Could not read from input device"); + break; } - // bytes read should always be equal to the size of a packet. - Q_ASSERT(bytesRead == sizeof(packet)); + n += bytesRead; + if (n % sizeof(buffer[0]) == 0) + break; + } + n /= sizeof(buffer[0]); - // translate the coordinates from the QNX data structure to Qt coordinates - // note the swapped y axis - QPoint pos = mousePos; - pos += QPoint(packet.dx, -packet.dy); + for (int i = 0; i < n; ++i) { + const struct _mouse_packet &packet = buffer[i]; - // QNX only tells us relative mouse movements, not absolute ones, so limit the - // cursor position manually to the screen - limitToScreen(pos); + // translate the coordinates from the QNX data structure to the Qt coordinates + if (absolutePositioning) { + queuedPos = QPoint(packet.dx, packet.dy); + } else { + // note the swapped y axis + queuedPos += QPoint(packet.dx, -packet.dy); + + // QNX only tells us relative mouse movements, not absolute ones, so + // limit the cursor position manually to the screen + limitToScreen(queuedPos); + } // translate the QNX mouse button bitmask to Qt buttons int buttons = Qt::NoButton; - if (packet.hdr.buttons & _POINTER_BUTTON_LEFT) buttons |= Qt::LeftButton; if (packet.hdr.buttons & _POINTER_BUTTON_MIDDLE) @@ -180,11 +192,17 @@ void QQnxMouseHandler::socketActivated() if (packet.hdr.buttons & _POINTER_BUTTON_RIGHT) buttons |= Qt::RightButton; - // call mouseChanged() - this does all the magic to actually move the on-screen - // mouse cursor. - mouseChanged(pos, buttons, 0); - } while (++iteration < 11); + if (buttons != mouseButtons) { + // send the MouseEvent to avoid missing any clicks + mouseChanged(queuedPos, buttons, 0); + // mousePos updated by the mouseChanged() + queuedPos = mousePos; + mouseButtons = buttons; + } + } + + if (queuedPos != mousePos) + mouseChanged(queuedPos, mouseButtons, 0); } QT_END_NAMESPACE - diff --git a/src/gui/embedded/qmouseqnx_qws.h b/src/gui/embedded/qmouseqnx_qws.h index 2a5eef2..54deaf3 100644 --- a/src/gui/embedded/qmouseqnx_qws.h +++ b/src/gui/embedded/qmouseqnx_qws.h @@ -70,6 +70,8 @@ private Q_SLOTS: private: QSocketNotifier *mouseNotifier; int mouseFD; + int mouseButtons; + bool absolutePositioning; }; QT_END_NAMESPACE diff --git a/src/gui/embedded/qscreen_qws.h b/src/gui/embedded/qscreen_qws.h index 2ecc6e7..5ff90f9 100644 --- a/src/gui/embedded/qscreen_qws.h +++ b/src/gui/embedded/qscreen_qws.h @@ -44,7 +44,7 @@ #include <QtCore/qnamespace.h> #include <QtCore/qpoint.h> -#include <QtCore/qlist.h> +#include <QtCore/qstringlist.h> #include <QtGui/qrgb.h> #include <QtCore/qrect.h> #include <QtGui/qimage.h> @@ -357,6 +357,7 @@ private: friend class QVNCScreen; friend class QLinuxFbScreen; friend class QVFbScreen; + friend class QQnxScreen; friend class QProxyScreen; friend class QIntfbScreen; #endif diff --git a/src/gui/embedded/qscreenqnx_qws.cpp b/src/gui/embedded/qscreenqnx_qws.cpp index 4afe087..d34e732 100644 --- a/src/gui/embedded/qscreenqnx_qws.cpp +++ b/src/gui/embedded/qscreenqnx_qws.cpp @@ -40,7 +40,9 @@ ****************************************************************************/ #include "qscreenqnx_qws.h" -#include "qdebug.h" + +#include <qapplication.h> +#include <qregexp.h> #include <gf/gf.h> @@ -52,6 +54,10 @@ struct QQnxScreenContext inline QQnxScreenContext() : device(0), display(0), layer(0), hwSurface(0), memSurface(0), context(0) {} + inline ~QQnxScreenContext() + { cleanup(); } + + void cleanup(); gf_dev_t device; gf_dev_info_t deviceInfo; @@ -64,6 +70,35 @@ struct QQnxScreenContext gf_context_t context; }; +void QQnxScreenContext::cleanup() +{ + if (context) { + gf_context_free(context); + context = 0; + } + if (memSurface) { + gf_surface_free(memSurface); + memSurface = 0; + } + if (hwSurface) { + gf_surface_free(hwSurface); + hwSurface = 0; + } + if (layer) { + gf_layer_detach(layer); + layer = 0; + } + if (display) { + gf_display_detach(display); + display = 0; + } + if (device) { + gf_dev_detach(device); + device = 0; + } +} + + /*! \class QQnxScreen \preliminary @@ -117,19 +152,23 @@ QQnxScreen::~QQnxScreen() delete d; } -/*! \reimp +/*! + \reimp */ bool QQnxScreen::initDevice() { - // implement this if you have multiple processes that want to access the display - // (not required if QT_NO_QWS_MULTIPROCESS is set) +#ifndef QT_NO_QWS_CURSOR + QScreenCursor::initSoftwareCursor(); +#endif + return true; } -/*! \internal - Attaches to the named device \a name. +/*! + \internal + Attaches to the named device \a name. */ -static bool attachDevice(QQnxScreenContext * const d, const char *name) +static inline bool attachDevice(QQnxScreenContext * const d, const char *name) { int ret = gf_dev_attach(&d->device, name, &d->deviceInfo); if (ret != GF_ERR_OK) { @@ -139,193 +178,231 @@ static bool attachDevice(QQnxScreenContext * const d, const char *name) return true; } -/*! \internal - Attaches to the display at index \a displayIndex. - */ -static bool attachDisplay(QQnxScreenContext * const d, int displayIndex) +/*! + \internal + Attaches to the display at index \a displayIndex. +*/ +static inline bool attachDisplay(QQnxScreenContext * const d, int displayIndex) { int ret = gf_display_attach(&d->display, d->device, displayIndex, &d->displayInfo); if (ret != GF_ERR_OK) { - qWarning("QQnxScreen: gf_display_attach(%d) failed with error code %d", - displayIndex, ret); + qWarning("QQnxScreen: gf_display_attach(%d) failed with error code %d", displayIndex, ret); return false; } return true; } -/*! \internal - Attaches to the layer \a layerIndex. - */ -static bool attachLayer(QQnxScreenContext * const d, int layerIndex) +/*! + \internal + Attaches to the layer \a layerIndex. +*/ +static inline bool attachLayer(QQnxScreenContext * const d, int layerIndex) { - int ret = gf_layer_attach(&d->layer, d->display, layerIndex, 0); + unsigned flags = QApplication::type() != QApplication::GuiServer ? GF_LAYER_ATTACH_PASSIVE : 0; + int ret = gf_layer_attach(&d->layer, d->display, layerIndex, flags); if (ret != GF_ERR_OK) { - qWarning("QQnxScreen: gf_layer_attach(%d) failed with error code %d", layerIndex, - ret); + qWarning("QQnxScreen: gf_layer_attach(%d) failed with error code %d", layerIndex, ret); return false; } - gf_layer_enable(d->layer); return true; } -/*! \internal - Creates a new hardware surface (usually on the Gfx card memory) with the dimensions \a w * \a h. - */ -static bool createHwSurface(QQnxScreenContext * const d, int w, int h) +/*! + \internal + Creates a new hardware surface (usually on the Gfx card memory) with the dimensions \a w * \a h. +*/ +static inline bool createHwSurface(QQnxScreenContext * const d, int w, int h) { int ret = gf_surface_create_layer(&d->hwSurface, &d->layer, 1, 0, - w, h, GF_FORMAT_ARGB8888, 0, 0); + w, h, d->displayInfo.format, 0, 0); if (ret != GF_ERR_OK) { - qWarning("QQnxScreen: gf_surface_create_layer(%dx%d) failed with error code %d", - w, h, ret); + qWarning("QQnxScreen: gf_surface_create_layer(%dx%d) failed with error code %d", w, h, ret); return false; } gf_layer_set_surfaces(d->layer, &d->hwSurface, 1); + gf_layer_enable(d->layer); + ret = gf_layer_update(d->layer, 0); if (ret != GF_ERR_OK) { qWarning("QQnxScreen: gf_layer_update() failed with error code %d\n", ret); return false; } - return true; -} - -/*! \internal - Creates an in-memory, linear accessible surface of dimensions \a w * \a h. - This is the main surface that QWS blits to. - */ -static bool createMemSurface(QQnxScreenContext * const d, int w, int h) -{ - // Note: gf_surface_attach() could also be used, so we'll create the buffer - // and let the surface point to it. Here, we use surface_create instead. - - int ret = gf_surface_create(&d->memSurface, d->device, w, h, - GF_FORMAT_ARGB8888, 0, - GF_SURFACE_CREATE_CPU_FAST_ACCESS | GF_SURFACE_CREATE_CPU_LINEAR_ACCESSIBLE - | GF_SURFACE_PHYS_CONTIG | GF_SURFACE_CREATE_SHAREABLE); + ret = gf_context_create(&d->context); if (ret != GF_ERR_OK) { - qWarning("QQnxScreen: gf_surface_create(%dx%d) failed with error code %d", - w, h, ret); + qWarning("QQnxScreen: gf_context_create() failed with error code %d", ret); return false; } - gf_surface_get_info(d->memSurface, &d->memSurfaceInfo); - - if (d->memSurfaceInfo.sid == unsigned(GF_SID_INVALID)) { - qWarning("QQnxScreen: gf_surface_get_info() failed."); + ret = gf_context_set_surface(d->context, d->hwSurface); + if (ret != GF_ERR_OK) { + qWarning("QQnxScreen: gf_context_set_surface() failed with error code %d", ret); return false; } return true; } -/* \internal - Creates a QNX gf context and sets our memory surface on it. - */ -static bool createContext(QQnxScreenContext * const d) +/*! + \internal + Creates an in-memory, linear accessible surface of dimensions \a w * \a h. + This is the main surface that QWS blits to. +*/ +static inline bool createMemSurface(QQnxScreenContext * const d, int w, int h) { - int ret = gf_context_create(&d->context); +#ifndef QT_NO_QWS_MULTIPROCESS + if (QApplication::type() != QApplication::GuiServer) { + unsigned sidlist[64]; + int n = gf_surface_sidlist(d->device, sidlist); // undocumented API + for (int i = 0; i < n; ++i) { + int ret = gf_surface_attach_by_sid(&d->memSurface, d->device, sidlist[i]); + if (ret == GF_ERR_OK) { + gf_surface_get_info(d->memSurface, &d->memSurfaceInfo); + if (d->memSurfaceInfo.sid != unsigned(GF_SID_INVALID)) { + // can we use the surface's vaddr? + unsigned flags = GF_SURFACE_CPU_LINEAR_READABLE | GF_SURFACE_CPU_LINEAR_WRITEABLE; + if ((d->memSurfaceInfo.flags & flags) == flags) + return true; + } + + gf_surface_free(d->memSurface); + d->memSurface = 0; + } + } + qWarning("QQnxScreen: cannot attach to an usable surface; create a new one."); + } +#endif + int ret = gf_surface_create(&d->memSurface, d->device, w, h, d->displayInfo.format, 0, + GF_SURFACE_CREATE_CPU_FAST_ACCESS | GF_SURFACE_CREATE_CPU_LINEAR_ACCESSIBLE + | GF_SURFACE_CREATE_PHYS_CONTIG | GF_SURFACE_CREATE_SHAREABLE); if (ret != GF_ERR_OK) { - qWarning("QQnxScreen: gf_context_create() failed with error code %d", ret); + qWarning("QQnxScreen: gf_surface_create(%dx%d) failed with error code %d", + w, h, ret); return false; } - ret = gf_context_set_surface(d->context, d->memSurface); - if (ret != GF_ERR_OK) { - qWarning("QQnxScreen: gf_context_set_surface() failed with error code %d", ret); + gf_surface_get_info(d->memSurface, &d->memSurfaceInfo); + + if (d->memSurfaceInfo.sid == unsigned(GF_SID_INVALID)) { + qWarning("QQnxScreen: gf_surface_get_info() failed."); return false; } return true; } -/*! \reimp - Connects to QNX's io-display based device based on the \a displaySpec parameters - from the \c{QWS_DISPLAY} environment variable. See the QQnxScreen class documentation - for possible parameters. +/*! + \reimp + Connects to QNX's io-display based device based on the \a displaySpec parameters + from the \c{QWS_DISPLAY} environment variable. See the QQnxScreen class documentation + for possible parameters. - \sa QQnxScreen - */ + \sa QQnxScreen +*/ bool QQnxScreen::connect(const QString &displaySpec) { const QStringList params = displaySpec.split(QLatin1Char(':'), QString::SkipEmptyParts); - bool isOk = false; - QRegExp deviceRegExp(QLatin1String("^device=(.+)$")); - if (params.indexOf(deviceRegExp) != -1) { - isOk = attachDevice(d, deviceRegExp.cap(1).toLocal8Bit().constData()); - } else { - // no device specified - attach to device 0 (the default) - isOk = attachDevice(d, GF_DEVICE_INDEX(0)); + // default to device 0 + int deviceIndex = 0; + if (!params.isEmpty()) { + QRegExp deviceRegExp(QLatin1String("^device=(.+)$")); + if (params.indexOf(deviceRegExp) != -1) + deviceIndex = deviceRegExp.cap(1).toInt(); } - if (!isOk) + if (!attachDevice(d, GF_DEVICE_INDEX(deviceIndex))) return false; qDebug("QQnxScreen: Attached to Device, number of displays: %d", d->deviceInfo.ndisplays); - // default to display 0 - int displayIndex = 0; - QRegExp displayRegexp(QLatin1String("^display=(\\d+)$")); - if (params.indexOf(displayRegexp) != -1) { - displayIndex = displayRegexp.cap(1).toInt(); + // default to display id passed to constructor + int displayIndex = displayId; + if (!params.isEmpty()) { + QRegExp displayRegexp(QLatin1String("^display=(\\d+)$")); + if (params.indexOf(displayRegexp) != -1) + displayIndex = displayRegexp.cap(1).toInt(); } if (!attachDisplay(d, displayIndex)) return false; qDebug("QQnxScreen: Attached to Display %d, resolution %dx%d, refresh %d Hz", - displayIndex, d->displayInfo.xres, d->displayInfo.yres, - d->displayInfo.refresh); - + displayIndex, d->displayInfo.xres, d->displayInfo.yres, d->displayInfo.refresh); // default to main_layer_index from the displayInfo struct - int layerIndex = 0; - QRegExp layerRegexp(QLatin1String("^layer=(\\d+)$")); - if (params.indexOf(layerRegexp) != -1) { - layerIndex = layerRegexp.cap(1).toInt(); - } else { - layerIndex = d->displayInfo.main_layer_index; + int layerIndex = d->displayInfo.main_layer_index; + if (!params.isEmpty()) { + QRegExp layerRegexp(QLatin1String("^layer=(\\d+)$")); + if (params.indexOf(layerRegexp) != -1) + layerIndex = layerRegexp.cap(1).toInt(); } if (!attachLayer(d, layerIndex)) return false; + // determine the pixel format and the pixel type + switch (d->displayInfo.format) { +#if defined(QT_QWS_DEPTH_32) || defined(QT_QWS_DEPTH_GENERIC) + case GF_FORMAT_ARGB8888: + pixeltype = QScreen::BGRPixel; + // fall through + case GF_FORMAT_BGRA8888: + setPixelFormat(QImage::Format_ARGB32); + break; +#endif +#if defined(QT_QWS_DEPTH_24) + case GF_FORMAT_BGR888: + pixeltype = QScreen::BGRPixel; + setPixelFormat(QImage::Format_RGB888); + break; +#endif +#if defined(QT_QWS_DEPTH_16) || defined(QT_QWS_DEPTH_GENERIC) + case GF_FORMAT_PACK_RGB565: + case GF_FORMAT_PKLE_RGB565: + case GF_FORMAT_PKBE_RGB565: +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + setFrameBufferLittleEndian((d->displayInfo.format & GF_FORMAT_PKLE) == GF_FORMAT_PKLE); +#endif + setPixelFormat(QImage::Format_RGB16); + break; +#endif + default: + return false; + } + // tell QWSDisplay the width and height of the display w = dw = d->displayInfo.xres; h = dh = d->displayInfo.yres; - - // we only support 32 bit displays for now. - QScreen::d = 32; + QScreen::d = (d->displayInfo.format & GF_FORMAT_BPP); // colour depth // assume 72 dpi as default, to calculate the physical dimensions if not specified const int defaultDpi = 72; - - // Handle display physical size spec. - QRegExp mmWidthRegexp(QLatin1String("^mmWidth=(\\d+)$")); - if (params.indexOf(mmWidthRegexp) == -1) { - physWidth = qRound(dw * 25.4 / defaultDpi); - } else { - physWidth = mmWidthRegexp.cap(1).toInt(); + // Handle display physical size + physWidth = qRound(dw * 25.4 / defaultDpi); + physHeight = qRound(dh * 25.4 / defaultDpi); + if (!params.isEmpty()) { + QRegExp mmWidthRegexp(QLatin1String("^mmWidth=(\\d+)$")); + if (params.indexOf(mmWidthRegexp) != -1) + physWidth = mmWidthRegexp.cap(1).toInt(); + + QRegExp mmHeightRegexp(QLatin1String("^mmHeight=(\\d+)$")); + if (params.indexOf(mmHeightRegexp) != -1) + physHeight = mmHeightRegexp.cap(1).toInt(); } - QRegExp mmHeightRegexp(QLatin1String("^mmHeight=(\\d+)$")); - if (params.indexOf(mmHeightRegexp) == -1) { - physHeight = qRound(dh * 25.4 / defaultDpi); - } else { - physHeight = mmHeightRegexp.cap(1).toInt(); + if (QApplication::type() == QApplication::GuiServer) { + // create a hardware surface with our dimensions. In the old days, it was possible + // to get a pointer directly to the hw surface, so we could blit directly. Now, we + // have to use one indirection more, because it's not guaranteed that the hw surface + // is mappable into our process. + if (!createHwSurface(d, w, h)) + return false; } - // create a hardware surface with our dimensions. In the old days, it was possible - // to get a pointer directly to the hw surface, so we could blit directly. Now, we - // have to use one indirection more, because it's not guaranteed that the hw surface - // is mappable into our process. - if (!createHwSurface(d, w, h)) - return false; - // create an in-memory linear surface that is used by QWS. QWS will blit directly in here. if (!createMemSurface(d, w, h)) return false; @@ -338,72 +415,84 @@ bool QQnxScreen::connect(const QString &displaySpec) // the overall size of the in-memory buffer is linestep * height size = mapsize = lstep * h; - // create a QNX drawing context - if (!createContext(d)) - return false; - - // we're always using a software cursor for now. Initialize it here. - QScreenCursor::initSoftwareCursor(); - // done, the driver should be connected to the display now. return true; } -/*! \reimp - */ +/*! + \reimp +*/ void QQnxScreen::disconnect() { - if (d->context) - gf_context_free(d->context); - - if (d->memSurface) - gf_surface_free(d->memSurface); - - if (d->hwSurface) - gf_surface_free(d->hwSurface); - - if (d->layer) - gf_layer_detach(d->layer); - - if (d->display) - gf_display_detach(d->display); - - if (d->device) - gf_dev_detach(d->device); - - d->memSurface = 0; - d->hwSurface = 0; - d->context = 0; - d->layer = 0; - d->display = 0; - d->device = 0; + d->cleanup(); } -/*! \reimp - */ +/*! + \reimp +*/ void QQnxScreen::shutdownDevice() { } - -/*! \reimp - QQnxScreen doesn't support setting the mode, use io-display instead. - */ +/*! + \reimp + QQnxScreen doesn't support setting the mode, use io-display instead. +*/ void QQnxScreen::setMode(int,int,int) { qWarning("QQnxScreen: Unable to change mode, use io-display instead."); } -/*! \reimp - */ +/*! + \reimp +*/ bool QQnxScreen::supportsDepth(int depth) const { - // only 32-bit for the moment - return depth == 32; + gf_modeinfo_t displayMode; + for (int i = 0; gf_display_query_mode(d->display, i, &displayMode) == GF_ERR_OK; ++i) { + switch (displayMode.primary_format) { +#if defined(QT_QWS_DEPTH_32) || defined(QT_QWS_DEPTH_GENERIC) + case GF_FORMAT_ARGB8888: + case GF_FORMAT_BGRA8888: + if (depth == 32) + return true; + break; +#endif +#if defined(QT_QWS_DEPTH_24) + case GF_FORMAT_BGR888: + if (depth == 24) + return true; + break; +#endif +#if defined(QT_QWS_DEPTH_16) || defined(QT_QWS_DEPTH_GENERIC) + case GF_FORMAT_PACK_RGB565: + case GF_FORMAT_PKLE_RGB565: + case GF_FORMAT_PKBE_RGB565: + if (depth == 16) + return true; + break; +#endif + default: + break; + } + } + + return false; } -/*! \reimp - */ +/*! + \reimp +*/ +void QQnxScreen::blank(bool on) +{ + int ret = gf_display_set_dpms(d->display, on ? GF_DPMS_OFF : GF_DPMS_ON); + if (ret != GF_ERR_OK) + qWarning("QQnxScreen: gf_display_set_dpms() failed with error code %d", ret); +} + +/*! + \reimp +*/ void QQnxScreen::exposeRegion(QRegion r, int changing) { // here is where the actual magic happens. QWS will call exposeRegion whenever @@ -414,6 +503,10 @@ void QQnxScreen::exposeRegion(QRegion r, int changing) QScreen::exposeRegion(r, changing); // now our in-memory surface should be up to date with the latest changes. + + if (!d->hwSurface) + return; + // the code below copies the region from the in-memory surface to the hardware. // just get the bounding rectangle of the region. Most screen updates are rectangular @@ -432,16 +525,14 @@ void QQnxScreen::exposeRegion(QRegion r, int changing) // blit the changed region from the memory surface to the hardware surface ret = gf_draw_blit2(d->context, d->memSurface, d->hwSurface, - br.x(), br.y(), br.right(), br.bottom(), br.x(), br.y()); - if (ret != GF_ERR_OK) { + br.x(), br.y(), br.right(), br.bottom(), br.x(), br.y()); + if (ret != GF_ERR_OK) qWarning("QQnxScreen: gf_draw_blit2() failed with error code %d", ret); - } // flush all drawing commands (in our case, a single blit) ret = gf_draw_flush(d->context); - if (ret != GF_ERR_OK) { + if (ret != GF_ERR_OK) qWarning("QQnxScreen: gf_draw_flush() failed with error code %d", ret); - } // tell QNX that we're done drawing. gf_draw_end(d->context); diff --git a/src/gui/embedded/qscreenqnx_qws.h b/src/gui/embedded/qscreenqnx_qws.h index 38c0ac9..6f6d18a 100644 --- a/src/gui/embedded/qscreenqnx_qws.h +++ b/src/gui/embedded/qscreenqnx_qws.h @@ -66,6 +66,7 @@ public: void shutdownDevice(); void setMode(int,int,int); bool supportsDepth(int) const; + void blank(bool on); void exposeRegion(QRegion r, int changing); diff --git a/src/gui/embedded/qwslock.cpp b/src/gui/embedded/qwslock.cpp index c14f50b..f9ea000 100644 --- a/src/gui/embedded/qwslock.cpp +++ b/src/gui/embedded/qwslock.cpp @@ -45,12 +45,15 @@ #include "qwssignalhandler_p.h" +#include <stdint.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> +#ifndef QT_POSIX_IPC #include <sys/sem.h> +#endif #include <sys/time.h> #include <time.h> #ifdef Q_OS_LINUX @@ -66,6 +69,12 @@ QT_BEGIN_NAMESPACE #error QWSLock currently requires semaphores #endif +#ifdef QT_POSIX_IPC +#include <QtCore/QAtomicInt> + +static QBasicAtomicInt localUniqueId = Q_BASIC_ATOMIC_INITIALIZER(1); +#endif + QWSLock::QWSLock(int id) : semId(id) { static unsigned short initialValues[3] = { 1, 1, 0 }; @@ -74,6 +83,7 @@ QWSLock::QWSLock(int id) : semId(id) QWSSignalHandler::instance()->addWSLock(this); #endif +#ifndef QT_POSIX_IPC if (semId == -1) { semId = semget(IPC_PRIVATE, 3, IPC_CREAT | 0666); if (semId == -1) { @@ -88,6 +98,30 @@ QWSLock::QWSLock(int id) : semId(id) qFatal("Unable to initialize semaphores"); } } +#else + sems[0] = sems[1] = sems[2] = SEM_FAILED; + owned = false; + + if (semId == -1) { + // ### generate really unique IDs + semId = (getpid() << 16) + (localUniqueId.fetchAndAddRelaxed(1) % ushort(-1)); + owned = true; + } + + QByteArray pfx = "/qwslock_" + QByteArray::number(semId, 16) + '_'; + QByteArray keys[3] = { pfx + "BackingStore", pfx + "Communication", pfx + "RegionEvent" }; + for (int i = 0; i < 3; ++i) { + if (owned) + sem_unlink(keys[i].constData()); + do { + sems[i] = sem_open(keys[i].constData(), (owned ? O_CREAT : 0), 0666, initialValues[i]); + } while (sems[i] == SEM_FAILED && errno == EINTR); + if (sems[i] == SEM_FAILED) { + perror("QWSLock::QWSLock"); + qFatal("Unable to %s semaphore", (owned ? "create" : "open")); + } + } +#endif lockCount[0] = lockCount[1] = 0; } @@ -99,10 +133,27 @@ QWSLock::~QWSLock() #endif if (semId != -1) { +#ifndef QT_POSIX_IPC qt_semun semval; semval.val = 0; semctl(semId, 0, IPC_RMID, semval); semId = -1; +#else + // emulate the SEM_UNDO behavior for the BackingStore lock + while (hasLock(BackingStore)) + unlock(BackingStore); + + QByteArray pfx = "/qwslock_" + QByteArray::number(semId, 16) + '_'; + QByteArray keys[3] = { pfx + "BackingStore", pfx + "Communication", pfx + "RegionEvent" }; + for (int i = 0; i < 3; ++i) { + if (sems[i] != SEM_FAILED) { + sem_close(sems[i]); + sems[i] = SEM_FAILED; + } + if (owned) + sem_unlink(keys[i].constData()); + } +#endif } } @@ -110,6 +161,7 @@ bool QWSLock::up(unsigned short semNum) { int ret; +#ifndef QT_POSIX_IPC sembuf sops = { semNum, 1, 0 }; // As the BackingStore lock is a mutex, and only one process may own // the lock, it's safe to use SEM_UNDO. On the other hand, the @@ -119,6 +171,9 @@ bool QWSLock::up(unsigned short semNum) sops.sem_flg |= SEM_UNDO; EINTR_LOOP(ret, semop(semId, &sops, 1)); +#else + ret = sem_post(sems[semNum]); +#endif if (ret == -1) { qDebug("QWSLock::up(): %s", strerror(errno)); return false; @@ -131,6 +186,7 @@ bool QWSLock::down(unsigned short semNum, int) { int ret; +#ifndef QT_POSIX_IPC sembuf sops = { semNum, -1, 0 }; // As the BackingStore lock is a mutex, and only one process may own // the lock, it's safe to use SEM_UNDO. On the other hand, the @@ -140,6 +196,9 @@ bool QWSLock::down(unsigned short semNum, int) sops.sem_flg |= SEM_UNDO; EINTR_LOOP(ret, semop(semId, &sops, 1)); +#else + EINTR_LOOP(ret, sem_wait(sems[semNum])); +#endif if (ret == -1) { qDebug("QWSLock::down(): %s", strerror(errno)); return false; @@ -150,7 +209,13 @@ bool QWSLock::down(unsigned short semNum, int) int QWSLock::getValue(unsigned short semNum) const { - int ret = semctl(semId, semNum, GETVAL, 0); + int ret; +#ifndef QT_POSIX_IPC + ret = semctl(semId, semNum, GETVAL, 0); +#else + if (sem_getvalue(sems[semNum], &ret) == -1) + ret = -1; +#endif if (ret == -1) qDebug("QWSLock::getValue(): %s", strerror(errno)); return ret; diff --git a/src/gui/embedded/qwslock_p.h b/src/gui/embedded/qwslock_p.h index d020b22..71a4cca 100644 --- a/src/gui/embedded/qwslock_p.h +++ b/src/gui/embedded/qwslock_p.h @@ -57,6 +57,10 @@ #ifndef QT_NO_QWS_MULTIPROCESS +#ifdef QT_POSIX_IPC +# include <semaphore.h> +#endif + QT_BEGIN_NAMESPACE class QWSLock @@ -80,6 +84,10 @@ private: int semId; int lockCount[2]; +#ifdef QT_POSIX_IPC + sem_t *sems[3]; + bool owned; +#endif }; QT_END_NAMESPACE diff --git a/src/gui/embedded/qwssharedmemory.cpp b/src/gui/embedded/qwssharedmemory.cpp index a677626..853de61 100644 --- a/src/gui/embedded/qwssharedmemory.cpp +++ b/src/gui/embedded/qwssharedmemory.cpp @@ -45,14 +45,37 @@ #include <sys/types.h> #include <sys/ipc.h> +#ifndef QT_POSIX_IPC #include <sys/shm.h> +#else +#include <sys/mman.h> +#include <sys/stat.h> +#endif +#include <fcntl.h> +#include <unistd.h> + +#include <private/qcore_unix_p.h> //#define QT_SHM_DEBUG QT_BEGIN_NAMESPACE +#ifdef QT_POSIX_IPC +#include <QtCore/QAtomicInt> + +static QBasicAtomicInt localUniqueId = Q_BASIC_ATOMIC_INITIALIZER(1); + +static inline QByteArray makeKey(int id) +{ + return "/qwsshm_" + QByteArray::number(id, 16); +} +#endif + QWSSharedMemory::QWSSharedMemory() : shmId(-1), shmBase(0), shmSize(0) +#ifdef QT_POSIX_IPC + , hand(-1) +#endif { } @@ -66,19 +89,47 @@ bool QWSSharedMemory::create(int size) if (shmId != -1) detach(); +#ifndef QT_POSIX_IPC shmId = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600); +#else + // ### generate really unique IDs + shmId = (getpid() << 16) + (localUniqueId.fetchAndAddRelaxed(1) % ushort(-1)); + QByteArray shmName = makeKey(shmId); + EINTR_LOOP(hand, shm_open(shmName.constData(), O_RDWR | O_CREAT, 0660)); + if (hand != -1) { + // the size may only be set once; ignore errors + int ret; + EINTR_LOOP(ret, ftruncate(hand, size)); + if (ret == -1) + shmId = -1; + } else { + shmId = -1; + } +#endif if (shmId == -1) { #ifdef QT_SHM_DEBUG perror("QWSSharedMemory::create():"); qWarning("Error allocating shared memory of size %d", size); #endif + detach(); return false; } + +#ifndef QT_POSIX_IPC shmBase = shmat(shmId, 0, 0); // On Linux, it is possible to attach a shared memory segment even if it // is already marked to be deleted. However, POSIX.1-2001 does not specify // this behaviour and many other implementations do not support it. shmctl(shmId, IPC_RMID, 0); +#else + // grab the size + QT_STATBUF st; + if (QT_FSTAT(hand, &st) != -1) { + shmSize = st.st_size; + // grab the memory + shmBase = mmap(0, shmSize, PROT_READ | PROT_WRITE, MAP_SHARED, hand, 0); + } +#endif if (shmBase == (void*)-1 || !shmBase) { #ifdef QT_SHM_DEBUG perror("QWSSharedMemory::create():"); @@ -102,7 +153,21 @@ bool QWSSharedMemory::attach(int id) return false; shmId = id; +#ifndef QT_POSIX_IPC shmBase = shmat(shmId, 0, 0); +#else + QByteArray shmName = makeKey(shmId); + EINTR_LOOP(hand, shm_open(shmName.constData(), O_RDWR, 0660)); + if (hand != -1) { + // grab the size + QT_STATBUF st; + if (QT_FSTAT(hand, &st) != -1) { + shmSize = st.st_size; + // grab the memory + shmBase = mmap(0, shmSize, PROT_READ | PROT_WRITE, MAP_SHARED, hand, 0); + } + } +#endif if (shmBase == (void*)-1 || !shmBase) { #ifdef QT_SHM_DEBUG perror("QWSSharedMemory::attach():"); @@ -117,8 +182,28 @@ bool QWSSharedMemory::attach(int id) void QWSSharedMemory::detach() { +#ifndef QT_POSIX_IPC if (shmBase && shmBase != (void*)-1) shmdt(shmBase); +#else + if (shmBase && shmBase != (void*)-1) + munmap(shmBase, shmSize); + if (hand > 0) { + // get the number of current attachments + int shm_nattch = 0; + QT_STATBUF st; + if (QT_FSTAT(hand, &st) == 0) { + // subtract 2 from linkcount: one for our own open and one for the dir entry + shm_nattch = st.st_nlink - 2; + } + qt_safe_close(hand); + // if there are no attachments then unlink the shared memory + if (shm_nattch == 0) { + QByteArray shmName = makeKey(shmId); + shm_unlink(shmName.constData()); + } + } +#endif shmBase = 0; shmSize = 0; shmId = -1; @@ -129,11 +214,13 @@ int QWSSharedMemory::size() const if (shmId == -1) return 0; +#ifndef QT_POSIX_IPC if (!shmSize) { struct shmid_ds shm; shmctl(shmId, IPC_STAT, &shm); - const_cast<QWSSharedMemory *>(this)->shmSize = shm.shm_segsz; + shmSize = shm.shm_segsz; } +#endif return shmSize; } diff --git a/src/gui/embedded/qwssharedmemory_p.h b/src/gui/embedded/qwssharedmemory_p.h index f3ce241..42ef6c8 100644 --- a/src/gui/embedded/qwssharedmemory_p.h +++ b/src/gui/embedded/qwssharedmemory_p.h @@ -77,7 +77,10 @@ public: private: int shmId; void *shmBase; - int shmSize; + mutable int shmSize; +#ifdef QT_POSIX_IPC + int hand; +#endif }; #endif // QT_NO_QWS_MULTIPROCESS diff --git a/src/gui/kernel/qapplication_qws.cpp b/src/gui/kernel/qapplication_qws.cpp index abee361..3b6a075 100644 --- a/src/gui/kernel/qapplication_qws.cpp +++ b/src/gui/kernel/qapplication_qws.cpp @@ -209,7 +209,7 @@ QString qws_dataDir() if (!S_ISDIR(buf.st_mode)) qFatal("%s is not a directory", dataDir.constData()); -#if !defined(Q_OS_INTEGRITY) && !defined(Q_OS_VXWORKS) +#if !defined(Q_OS_INTEGRITY) && !defined(Q_OS_VXWORKS) && !defined(Q_OS_QNX) if (buf.st_uid != getuid()) qFatal("Qt for Embedded Linux data directory is not owned by user %d", getuid()); diff --git a/src/gui/painting/qwindowsurface_qws.cpp b/src/gui/painting/qwindowsurface_qws.cpp index 7e8cf9b..3789a33 100644 --- a/src/gui/painting/qwindowsurface_qws.cpp +++ b/src/gui/painting/qwindowsurface_qws.cpp @@ -1065,10 +1065,12 @@ bool QWSSharedMemSurface::setMemory(int memId) return true; mem.detach(); - if (!mem.attach(memId)) { + + if (memId != -1 && !mem.attach(memId)) { +#ifndef QT_NO_DEBUG perror("QWSSharedMemSurface: attaching to shared memory"); - qCritical("QWSSharedMemSurface: Error attaching to" - " shared memory 0x%x", memId); + qCritical("QWSSharedMemSurface: Error attaching to shared memory 0x%x", memId); +#endif return false; } diff --git a/src/gui/text/qfontdatabase_qws.cpp b/src/gui/text/qfontdatabase_qws.cpp index c83e929..313000f 100644 --- a/src/gui/text/qfontdatabase_qws.cpp +++ b/src/gui/text/qfontdatabase_qws.cpp @@ -75,6 +75,11 @@ #include <qresource.h> #endif +#ifdef Q_OS_QNX +// ### using QFontEngineQPF leads to artifacts on QNX +# define QT_NO_QWS_SHARE_FONTS +#endif + QT_BEGIN_NAMESPACE #ifndef QT_NO_LIBRARY diff --git a/src/qt3support/other/q3process_unix.cpp b/src/qt3support/other/q3process_unix.cpp index af024bc..426d10f 100644 --- a/src/qt3support/other/q3process_unix.cpp +++ b/src/qt3support/other/q3process_unix.cpp @@ -213,7 +213,7 @@ static void q3process_cleanup() Q3ProcessPrivate::procManager = 0; } -#ifdef Q_OS_QNX6 +#ifdef Q_OS_QNX #define BAILOUT qt_safe_close(tmpSocket);qt_safe_close(socketFD[1]);return -1; int qnx6SocketPairReplacement (int socketFD[2]) { int tmpSocket; @@ -270,7 +270,7 @@ Q3ProcessManager::Q3ProcessManager() : sn(0) // The SIGCHLD handler writes to a socket to tell the manager that // something happened. This is done to get the processing in sync with the // event reporting. -#ifndef Q_OS_QNX6 +#ifndef Q_OS_QNX if ( ::socketpair( AF_UNIX, SOCK_STREAM, 0, sigchldFd ) ) { #else if ( qnx6SocketPairReplacement (sigchldFd) ) { @@ -670,14 +670,14 @@ bool Q3Process::start( QStringList *env ) int sStderr[2]; // open sockets for piping -#ifndef Q_OS_QNX6 +#ifndef Q_OS_QNX if ( (comms & Stdin) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdin ) == -1 ) { #else if ( (comms & Stdin) && qnx6SocketPairReplacement(sStdin) == -1 ) { #endif return false; } -#ifndef Q_OS_QNX6 +#ifndef Q_OS_QNX if ( (comms & Stderr) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStderr ) == -1 ) { #else if ( (comms & Stderr) && qnx6SocketPairReplacement(sStderr) == -1 ) { @@ -688,7 +688,7 @@ bool Q3Process::start( QStringList *env ) } return false; } -#ifndef Q_OS_QNX6 +#ifndef Q_OS_QNX if ( (comms & Stdout) && ::socketpair( AF_UNIX, SOCK_STREAM, 0, sStdout ) == -1 ) { #else if ( (comms & Stdout) && qnx6SocketPairReplacement(sStdout) == -1 ) { @@ -782,11 +782,7 @@ bool Q3Process::start( QStringList *env ) ::fcntl( fd[1], F_SETFD, FD_CLOEXEC ); // close on exec shows success if ( env == 0 ) { // inherit environment and start process -#ifndef Q_OS_QNX4 ::execvp( arglist[0], (char*const*)arglist ); // ### cast not nice -#else - ::execvp( arglist[0], (char const*const*)arglist ); // ### cast not nice -#endif } else { // start process with environment settins as specified in env // construct the environment for exec int numEntries = env->count(); @@ -843,11 +839,7 @@ bool Q3Process::start( QStringList *env ) } } } -#ifndef Q_OS_QNX4 ::execve( arglist[0], (char*const*)arglist, (char*const*)envlist ); // ### casts not nice -#else - ::execve( arglist[0], (char const*const*)arglist,(char const*const*)envlist ); // ### casts not nice -#endif } if ( fd[1] ) { char buf = 0; diff --git a/tests/auto/qlocalsocket/tst_qlocalsocket.cpp b/tests/auto/qlocalsocket/tst_qlocalsocket.cpp index 3dc5e73..feb2552 100644 --- a/tests/auto/qlocalsocket/tst_qlocalsocket.cpp +++ b/tests/auto/qlocalsocket/tst_qlocalsocket.cpp @@ -893,8 +893,8 @@ void tst_QLocalSocket::removeServer() QLocalServer server, server2; QVERIFY(QLocalServer::removeServer("cleanuptest")); QVERIFY(server.listen("cleanuptest")); -#ifndef Q_OS_WIN - // on Windows, there can be several sockets listening on the same pipe +#if !defined(Q_OS_WIN) && !defined(Q_OS_QNX) + // on Windows and QNX, there can be several sockets listening on the same pipe // on Unix, there can only be one socket instance QVERIFY(! server2.listen("cleanuptest")); #endif diff --git a/tests/auto/qpluginloader/tst_qpluginloader.cpp b/tests/auto/qpluginloader/tst_qpluginloader.cpp index 76dbd48..d2d92a5 100644 --- a/tests/auto/qpluginloader/tst_qpluginloader.cpp +++ b/tests/auto/qpluginloader/tst_qpluginloader.cpp @@ -219,7 +219,7 @@ void tst_QPluginLoader::errorString() QVERIFY(loader.errorString() != unknown); } -#if !defined Q_OS_WIN && !defined Q_OS_MAC && !defined Q_OS_HPUX && !defined Q_OS_SYMBIAN +#if !defined Q_OS_WIN && !defined Q_OS_MAC && !defined Q_OS_HPUX && !defined Q_OS_SYMBIAN && !defined Q_OS_QNX { QPluginLoader loader( sys_qualifiedLibraryName("almostplugin")); //a plugin with unresolved symbols loader.setLoadHints(QLibrary::ResolveAllSymbolsHint); |