summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorQt Continuous Integration System <qt-info@nokia.com>2011-06-22 20:44:56 +1000
committerQt Continuous Integration System <qt-info@nokia.com>2011-06-22 20:44:56 +1000
commit078a68ffc84a745830535f1eb0e19ab8a190f542 (patch)
treeda6310c113b1be22c440a3548849d1ea28aa4d18 /src
parente4cce8849bf45be9a111072e3fca7bdf67364e8a (diff)
parentaf3bb0f146ec357ae6daf752a5f8bbdb074cde20 (diff)
Merge branch 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-1 into master-integration
* 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-1: trivial: fix typo in comment changelog docu update for QNX 6.5 get rid of anacronysm massive improvements for the QNX screen driver massive improvements for the QNX mouse driver massive improvements for the QNX keyboard driver disable the Embedded Linux data directory permissions check for QNX skip two subtests that are known to fail on QNX implement POSIX IPC based QLock, QWSLock and QWSSharedMemory backends implement POSIX IPC based QSystemSemaphore and QSharedMemory backends add a configure-time check for an IPC support make QProcess really work on QNX make the kernel attempt to emulate an instruction with a misaligned access use RoundRobin scheduler by default on QNX a major refactoring of the mkspecs tree for QNX buildfix for qmake
Diffstat (limited to 'src')
-rw-r--r--src/corelib/global/qglobal.h12
-rw-r--r--src/corelib/io/qprocess.cpp10
-rw-r--r--src/corelib/io/qprocess_p.h8
-rw-r--r--src/corelib/io/qprocess_unix.cpp183
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp22
-rw-r--r--src/corelib/kernel/qsharedmemory.cpp5
-rw-r--r--src/corelib/kernel/qsharedmemory_p.h4
-rw-r--r--src/corelib/kernel/qsharedmemory_unix.cpp143
-rw-r--r--src/corelib/kernel/qsystemsemaphore.cpp7
-rw-r--r--src/corelib/kernel/qsystemsemaphore_p.h9
-rw-r--r--src/corelib/kernel/qsystemsemaphore_unix.cpp124
-rw-r--r--src/corelib/thread/qthread_unix.cpp5
-rw-r--r--src/gui/embedded/embedded.pri2
-rw-r--r--src/gui/embedded/qkbdqnx_qws.cpp257
-rw-r--r--src/gui/embedded/qlock.cpp128
-rw-r--r--src/gui/embedded/qmouselinuxinput_qws.cpp18
-rw-r--r--src/gui/embedded/qmouseqnx_qws.cpp96
-rw-r--r--src/gui/embedded/qmouseqnx_qws.h2
-rw-r--r--src/gui/embedded/qscreen_qws.h3
-rw-r--r--src/gui/embedded/qscreenqnx_qws.cpp409
-rw-r--r--src/gui/embedded/qscreenqnx_qws.h1
-rw-r--r--src/gui/embedded/qwslock.cpp67
-rw-r--r--src/gui/embedded/qwslock_p.h8
-rw-r--r--src/gui/embedded/qwssharedmemory.cpp89
-rw-r--r--src/gui/embedded/qwssharedmemory_p.h5
-rw-r--r--src/gui/kernel/qapplication_qws.cpp2
-rw-r--r--src/gui/painting/qwindowsurface_qws.cpp8
-rw-r--r--src/gui/text/qfontdatabase_qws.cpp5
-rw-r--r--src/qt3support/other/q3process_unix.cpp18
29 files changed, 1283 insertions, 367 deletions
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index 32b3e6bb3d..1f5f5375cd 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 70a70c27d8..4b689c5369 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 9adb331a13..f24a7bcf33 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 07e3087acc..725e4c50d8 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 7694a0f979..dd46bc5603 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, &param) == 0 && sched_policy != SCHED_RR) {
+ sched_policy = SCHED_RR;
+ pthread_setschedparam(0, sched_policy, &param);
+ }
+#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 288227933c..371974cae9 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 21b8612438..780e52e50f 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 e991ce9e09..a086acde7e 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 98ee6f4231..ae30348253 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 3e5f737667..d84d4163f7 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 704afaf1e4..e060eb2e8d 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 839a396ac1..765969efd9 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 31f0bc6d50..836c116053 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 5a8118d9d9..ad76446f51 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 ac154313cf..eaad15c40c 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 efcf6d4267..19a9a99fec 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 a9647c0fff..d0b892eeab 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 2a5eef2daa..54deaf3796 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 2ecc6e7155..5ff90f94f4 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 4afe087cdb..d34e7326a5 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 38c0ac9475..6f6d18a4be 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 c14f50b1ae..f9ea0002f4 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 d020b22cb4..71a4cca9c4 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 a677626678..853de615dc 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 f3ce24101b..42ef6c8cef 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 abee361c0b..3b6a0757dd 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 7e8cf9bbb1..3789a33110 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 c83e9297d9..313000f84c 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 af024bcadf..426d10f03e 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;