Index: trunk/src/corelib/io/io.pri
===================================================================
--- trunk/src/corelib/io/io.pri	(revision 615)
+++ trunk/src/corelib/io/io.pri	(revision 616)
@@ -69,7 +69,6 @@
 
         SOURCES += io/qfsfileengine_iterator_os2.cpp
-        # @todo later
-#        SOURCES += io/qfilesystemwatcher_os2.cpp
-#        HEADERS += io/qfilesystemwatcher_os2_p.h
+        SOURCES += io/qfilesystemwatcher_os2.cpp
+        HEADERS += io/qfilesystemwatcher_os2_p.h
 } else:unix {
         SOURCES += io/qfsfileengine_unix.cpp
Index: trunk/src/corelib/io/qfilesystemwatcher.cpp
===================================================================
--- trunk/src/corelib/io/qfilesystemwatcher.cpp	(revision 615)
+++ trunk/src/corelib/io/qfilesystemwatcher.cpp	(revision 616)
@@ -55,4 +55,6 @@
 #if defined(Q_OS_WIN)
 #  include "qfilesystemwatcher_win_p.h"
+#elif defined(Q_OS_OS2)
+#  include "qfilesystemwatcher_os2_p.h"
 #elif defined(Q_OS_LINUX)
 #  include "qfilesystemwatcher_inotify_p.h"
@@ -298,4 +300,10 @@
 #if defined(Q_OS_WIN)
     return new QWindowsFileSystemWatcherEngine;
+#elif defined(Q_OS_OS2) && 0 // @todo: temporarily disabled
+    QOS2FileSystemWatcherEngine *engine = new QOS2FileSystemWatcherEngine();
+    if (engine->isOk())
+        return engine;
+    delete engine;
+    return 0;
 #elif defined(Q_OS_LINUX)
     QFileSystemWatcherEngine *eng = QInotifyFileSystemWatcherEngine::create();
Index: trunk/src/corelib/io/qfilesystemwatcher_os2.cpp
===================================================================
--- trunk/src/corelib/io/qfilesystemwatcher_os2.cpp	(revision 616)
+++ trunk/src/corelib/io/qfilesystemwatcher_os2.cpp	(revision 616)
@@ -0,0 +1,322 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Copyright (C) 2009 netlabs.org. OS/2 parts.
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qfilesystemwatcher.h"
+#include "qfilesystemwatcher_os2_p.h"
+
+#ifndef QT_NO_FILESYSTEMWATCHER
+
+#include "qdir.h"
+#include "qfileinfo.h"
+
+#include "qdebug.h"
+
+// OS/2 has the Dos*ChangeNotify API for file system change notifications but
+// this API may be only used once (i.e. by a single process on the system,
+// all other attempt will return the "access denied" error) and this process
+// is normally the Workplace Shell so there is no way for other applications
+// to use this handy API. In order to overcome this limitation, XWorkplace
+// (which is a Workplace Shell extension which lives in the same process)
+// takes over the WPS change notification function and extends it by sinking
+// all changes to a named pipe. This pipe is utilized by this class to get
+// notifications about file and directory changes.
+//
+// Note that when XWorkplace is not installed or when its "Enable folder auto-
+// refresh" feature is disabled, the notification pipe will not be available and
+// we will fall back to the polling filesystem watcher implementation.
+
+// Notification server pipe name (taken from xworkplace/src/filesys/refresh.c)
+#define PIPE_CHANGENOTIFY       "\\PIPE\\XNOTIFY"
+
+// Taken from xworkplace/include/filesys/refresh.c
+#pragma pack(1)
+typedef struct _CNINFO {      /* CHANGENOTIFYINFO */
+    ULONG   oNextEntryOffset;
+    CHAR    bAction;
+    USHORT  cbName;
+    CHAR    szName[1];
+} CNINFO;
+typedef CNINFO *PCNINFO;
+#pragma pack()
+
+#define  RCNF_FILE_ADDED        0x0001
+#define  RCNF_FILE_DELETED      0x0002
+#define  RCNF_DIR_ADDED         0x0003
+#define  RCNF_DIR_DELETED       0x0004
+#define  RCNF_MOVED_IN          0x0005
+#define  RCNF_MOVED_OUT         0x0006
+#define  RCNF_CHANGED           0x0007
+#define  RCNF_OLDNAME           0x0008
+#define  RCNF_NEWNAME           0x0009
+#define  RCNF_DEVICE_ATTACHED   0x000A
+#define  RCNF_DEVICE_DETACHED   0x000B
+
+QT_BEGIN_NAMESPACE
+
+QOS2FileSystemWatcherEngine::QOS2FileSystemWatcherEngine()
+    : notifyPipe(NULLHANDLE), eventSem(NULLHANDLE), finish(false)
+{
+    ULONG dummy;
+    APIRET arc = DosOpen(PIPE_CHANGENOTIFY, &notifyPipe, &dummy, 0, FILE_OPEN,
+                         OPEN_ACTION_OPEN_IF_EXISTS,
+                         OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, NULL);
+    if (arc == NO_ERROR) {
+        // make sure the pipe is non-blocking so that we can get ERROR_NO_DATA
+        arc = DosSetNPHState(notifyPipe, NP_NOWAIT);
+        Q_ASSERT(arc == NO_ERROR);
+        // connect the pipe to the semaphore
+        arc = DosCreateEventSem(NULL, &eventSem,
+                                DC_SEM_SHARED | DCE_AUTORESET | DCE_POSTONE,
+                                FALSE);
+        Q_ASSERT(arc == NO_ERROR);
+        arc = DosSetNPipeSem(notifyPipe, (HSEM)eventSem, 0);
+        Q_ASSERT(arc == NO_ERROR);
+    } else {
+        notifyPipe = NULLHANDLE; // sanity (used by isOk())
+        if (arc != ERROR_FILE_NOT_FOUND)
+            qWarning("QOS2FileSystemWatcherEngine:: "
+                     "DosOpen("PIPE_CHANGENOTIFY") returned %lu", arc);
+    }
+}
+
+QOS2FileSystemWatcherEngine::~QOS2FileSystemWatcherEngine()
+{
+    DosCloseEventSem(eventSem);
+    if (notifyPipe != NULLHANDLE)
+        DosClose(notifyPipe);
+}
+
+QStringList QOS2FileSystemWatcherEngine::addPaths(const QStringList &paths,
+                                                  QStringList *files,
+                                                  QStringList *directories)
+{
+    QMutexLocker locker(&mutex);
+
+    QStringList p = paths;
+    QMutableListIterator<QString> it(p);
+    while (it.hasNext()) {
+        QString path = it.next();
+        QFileInfo fi(path);
+        if (!fi.exists())
+            continue;
+        QString normalPath = fi.absoluteFilePath();
+        normalPath = QDir::toNativeSeparators(QDir::cleanPath(path)).toUpper();
+        Type type;
+        if (fi.isDir()) {
+            type = Dir;
+            if (!directories->contains(path))
+                directories->append(path);
+        } else {
+            type = File;
+            if (!files->contains(path))
+                files->append(path);
+        }
+        QList<PathInfo> &variants = watchedPaths[normalPath];
+        foreach (const PathInfo &pi, variants) {
+            if (pi.path == path)
+                continue;
+        }
+        variants << PathInfo(path, type);
+        it.remove();
+    }
+
+    start(IdlePriority);
+
+    return p;
+}
+
+QStringList QOS2FileSystemWatcherEngine::removePaths(const QStringList &paths,
+                                                     QStringList *files,
+                                                     QStringList *directories)
+{
+    QMutexLocker locker(&mutex);
+
+    QStringList p = paths;
+    QMutableListIterator<QString> it(p);
+    while (it.hasNext()) {
+        QString path = it.next();
+        QString normalPath = QDir::current().absoluteFilePath(path);
+        normalPath = QDir::toNativeSeparators(QDir::cleanPath(path)).toUpper();
+        if (watchedPaths.contains(normalPath)) {
+            QList<PathInfo> &variants = watchedPaths[normalPath];
+            for (QList<PathInfo>::iterator pathIt = variants.begin();
+                 pathIt != variants.end(); ++pathIt) {
+                if (pathIt->path == path) {
+                    files->removeAll(path);
+                    directories->removeAll(path);
+                    variants.erase(pathIt);
+                    it.remove();
+                    break;
+                }
+            }
+            if (variants.isEmpty())
+                watchedPaths.remove(normalPath);
+        }
+    }
+
+    if (watchedPaths.isEmpty()) {
+        // stop the thread
+        finish = true;
+        DosPostEventSem(eventSem);
+        locker.unlock();
+        wait();
+    }
+
+    return p;
+}
+
+void QOS2FileSystemWatcherEngine::run()
+{
+    QByteArray buffer(sizeof(CNINFO) + _MAX_PATH + 2, 0);
+    PCNINFO	info = (PCNINFO)buffer.data();
+    APIRET arc;
+    ULONG cbActual;
+
+    QMutexLocker locker(&mutex);
+
+    forever {
+        locker.unlock();
+        qDosNI(arc = DosWaitEventSem(eventSem, SEM_INDEFINITE_WAIT));
+        locker.relock();
+
+        if (finish)
+            break;
+
+        forever {
+            buffer.fill(0);
+            arc = DosRead(notifyPipe, buffer.data(), buffer.size(), &cbActual);
+            if (arc == ERROR_NO_DATA) // no more records?
+                break;
+            if (arc == NO_ERROR && cbActual >= sizeof(CNINFO) && info->cbName) {
+                Type type = None;
+                switch (info->bAction) {
+                case RCNF_FILE_ADDED:
+                case RCNF_FILE_DELETED:
+                    type = File;
+                    break;
+                case RCNF_DIR_ADDED:
+                case RCNF_DIR_DELETED:
+                    type = Dir;
+                    break;
+                case RCNF_CHANGED:
+                case RCNF_NEWNAME: {
+                    FILESTATUS3 stat;
+                    arc = DosQueryPathInfo(info->szName, FIL_STANDARD, &stat, sizeof(stat));
+                    if (arc == NO_ERROR)
+                        type = (stat.attrFile & FILE_DIRECTORY) ? Dir : File;
+                    break;
+                }
+                default:
+                    break;
+                }
+
+                QString normalPath = QString::fromLocal8Bit(info->szName).toUpper();
+
+                switch (info->bAction) {
+                case RCNF_FILE_DELETED:
+                case RCNF_DIR_DELETED:
+                case RCNF_OLDNAME:
+                case RCNF_CHANGED:
+                    // signal the change or deletion
+                    if (watchedPaths.contains(normalPath)) {
+                        QList<PathInfo> &variants = watchedPaths[normalPath];
+                        QList<PathInfo> deletedVariants;
+                        bool deleted = info->bAction != RCNF_CHANGED;
+                        if (deleted) {
+                            deletedVariants = variants;
+                            variants = deletedVariants;
+                            watchedPaths.remove(normalPath);
+                        }
+                        foreach(const PathInfo &pi, variants) {
+                            if (type == None)
+                                type = pi.type;
+                            if (type == pi.type) {
+                                if (type == File)
+                                    emit fileChanged(pi.path, deleted);
+                                else
+                                    emit directoryChanged(pi.path, deleted);
+                            }
+                        }
+                    }
+                    // deliberately fall through:
+                case RCNF_FILE_ADDED:
+                case RCNF_DIR_ADDED:
+                case RCNF_NEWNAME:
+                    // signal a change if we watch the parent directory
+                    normalPath = normalPath.
+                        left(qMax(normalPath.lastIndexOf(QLatin1Char('\\')), 0));
+                    if (watchedPaths.contains(normalPath)) {
+                        foreach(const PathInfo &pi, watchedPaths[normalPath]) {
+                            if (pi.type == Dir)
+                                emit directoryChanged(pi.path, false);
+                        }
+                    }
+                    break;
+                default:
+                    break;
+                }
+            } else {
+                qWarning() << "QOS2FileSystemWatcherEngine: "
+                              "DosRead("PIPE_CHANGENOTIFY") failed:"
+                           << "arc" << arc << "cbActual" << cbActual
+                           << "info->cbName" << info->cbName;
+                break;
+            }
+        }
+    }
+}
+
+void QOS2FileSystemWatcherEngine::stop()
+{
+    QMutexLocker locker(&mutex);
+    if (!finish) {
+        finish = true;
+        DosPostEventSem(eventSem);
+        locker.unlock();
+        wait();
+    }
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_FILESYSTEMWATCHER
Index: trunk/src/corelib/io/qfilesystemwatcher_os2_p.h
===================================================================
--- trunk/src/corelib/io/qfilesystemwatcher_os2_p.h	(revision 616)
+++ trunk/src/corelib/io/qfilesystemwatcher_os2_p.h	(revision 616)
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Copyright (C) 2009 netlabs.org. OS/2 parts.
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QFILESYSTEMWATCHER_OS2_P_H
+#define QFILESYSTEMWATCHER_OS2_P_H
+
+//
+//  W A R N I N G
+//  -------------
+//
+// This file is not part of the Qt API.  It exists for the convenience
+// of the QLibrary class.  This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qfilesystemwatcher_p.h"
+
+#ifndef QT_NO_FILESYSTEMWATCHER
+
+#include "qt_os2.h"
+#include "QtCore/qmutex.h"
+#include "QtCore/qlist.h"
+
+QT_BEGIN_NAMESPACE
+
+class QOS2FileSystemWatcherEngine : public QFileSystemWatcherEngine
+{
+    Q_OBJECT
+public:
+    QOS2FileSystemWatcherEngine();
+    ~QOS2FileSystemWatcherEngine();
+
+    QStringList addPaths(const QStringList &paths, QStringList *files,
+                         QStringList *directories);
+    QStringList removePaths(const QStringList &paths, QStringList *files,
+                            QStringList *directories);
+
+    void run();
+    void stop();
+
+    bool isOk() const { return notifyPipe != NULLHANDLE; };
+
+private:
+    mutable QMutex mutex;
+    HFILE notifyPipe;
+    HEV eventSem;
+    bool finish;
+
+    enum Type { None = 0, Dir, File };
+    struct PathInfo
+    {
+        PathInfo(const QString &p, Type t) : path(p), type(t) {}
+        QString path;
+        Type type;
+    };
+    QHash<QString, QList<PathInfo> > watchedPaths;
+};
+
+#endif // QT_NO_FILESYSTEMWATCHER
+
+QT_END_NAMESPACE
+
+#endif // QFILESYSTEMWATCHER_OS2_P_H
