Index: /trunk/configure.cmd
===================================================================
--- /trunk/configure.cmd	(revision 427)
+++ /trunk/configure.cmd	(revision 428)
@@ -47,5 +47,4 @@
     "QT_NO_TABLET",
     "QT_NO_SYSTEMSEMAPHORE QT_NO_SHAREDMEMORY",
-    "QT_NO_SESSIONMANAGER",
     "QT_NO_IM QT_NO_ACCESSIBILITY QT_NO_IPV6",
     "QT_NO_PRINTER QT_NO_PRINTDIALOG QT_NO_DRAGANDDROP"
Index: /trunk/src/corelib/kernel/qcoreapplication.h
===================================================================
--- /trunk/src/corelib/kernel/qcoreapplication.h	(revision 427)
+++ /trunk/src/corelib/kernel/qcoreapplication.h	(revision 428)
@@ -207,4 +207,5 @@
 
     friend class QEventDispatcherUNIXPrivate;
+    friend class QEventDispatcherPM;
     friend class QApplication;
     friend class QApplicationPrivate;
Index: /trunk/src/corelib/kernel/qcoreapplication_p.h
===================================================================
--- /trunk/src/corelib/kernel/qcoreapplication_p.h	(revision 427)
+++ /trunk/src/corelib/kernel/qcoreapplication_p.h	(revision 428)
@@ -82,4 +82,7 @@
     static void removePostedTimerEvent(QObject *object, int timerId);
 #endif
+#ifdef Q_OS_OS2
+    virtual bool canQuit() { return true; }
+#endif
 
 #ifdef Q_OS_MAC
Index: /trunk/src/corelib/kernel/qeventdispatcher_pm.cpp
===================================================================
--- /trunk/src/corelib/kernel/qeventdispatcher_pm.cpp	(revision 427)
+++ /trunk/src/corelib/kernel/qeventdispatcher_pm.cpp	(revision 428)
@@ -1253,6 +1253,13 @@
             if (haveMessage) {
                 if (msg.msg == WM_QUIT) {
-                    if (QCoreApplication::instance())
-                        QCoreApplication::instance()->quit();
+                    if (QCoreApplication::instance()) {
+                        if (QCoreApplication::instance()->d_func()->canQuit()) {
+                            QCoreApplication::instance()->quit();
+                            return true;
+                        } else {
+                            WinCancelShutdown(d->hmq, FALSE);
+                            return true;
+                        }
+                    }
                     return false;
                 }
Index: /trunk/src/gui/kernel/qapplication.cpp
===================================================================
--- /trunk/src/gui/kernel/qapplication.cpp	(revision 427)
+++ /trunk/src/gui/kernel/qapplication.cpp	(revision 428)
@@ -4369,5 +4369,5 @@
  *****************************************************************************/
 #ifndef QT_NO_SESSIONMANAGER
-#if defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
+#if defined(Q_WS_WIN) || defined(Q_WS_PM) || defined(Q_WS_MAC) || defined(Q_WS_QWS)
 
 #if defined(Q_OS_WINCE)
@@ -4451,5 +4451,5 @@
 #endif
 
-#if !defined(Q_WS_WIN)
+#if !defined(Q_WS_WIN) && !defined(Q_WS_PM)
 bool QSessionManager::allowsInteraction()
 {
Index: /trunk/src/gui/kernel/qapplication_p.h
===================================================================
--- /trunk/src/gui/kernel/qapplication_p.h	(revision 427)
+++ /trunk/src/gui/kernel/qapplication_p.h	(revision 428)
@@ -425,4 +425,7 @@
     void sendSyntheticEnterLeave(QWidget *widget);
 #endif
+#if defined(Q_WS_PM) && !defined(QT_NO_SESSIONMANAGER)
+    bool canQuit();
+#endif
 
 private:
Index: /trunk/src/gui/kernel/qapplication_pm.cpp
===================================================================
--- /trunk/src/gui/kernel/qapplication_pm.cpp	(revision 427)
+++ /trunk/src/gui/kernel/qapplication_pm.cpp	(revision 428)
@@ -54,4 +54,5 @@
 #include "qpixmapcache.h"
 #include "qdesktopwidget.h"
+#include "qsessionmanager.h"
 
 #include "qset.h"
@@ -77,8 +78,15 @@
 #if !defined (QT_NO_SESSIONMANAGER)
 
+//#define DEBUG_SESSIONMANAGER
+
 // Session management
-static bool	sm_blockUserInput    = FALSE;
-
-//#define DEBUG_SESSIONMANAGER
+static bool	sm_blockUserInput    = false;
+static bool	sm_smActive          = false;
+static bool	sm_cancel            = false;
+static bool	sm_gracefulShutdown  = false;
+static bool	sm_quitSkipped       = false;
+
+extern QSessionManager *qt_session_manager_self; // defined in qapplication.cpp
+extern bool qt_about_to_destroy_wnd; // defined in qwidget_pm.cpp
 
 #endif
@@ -765,4 +773,56 @@
         switch(msg) {
 
+#if !defined(QT_NO_SESSIONMANAGER)
+        case WM_SAVEAPPLICATION: {
+#if defined(DEBUG_SESSIONMANAGER)
+            qDebug("WM_SAVEAPPLICATION: sm_gracefulShutdown %d, "
+                   "qt_about_to_destroy_wnd %d, (mp1 %p, mp2 %p)",
+                   sm_gracefulShutdown, qt_about_to_destroy_wnd, mp1, mp2);
+#endif
+            // PM seems to post this message to all top-level windows on system
+            // shutdown, so react only to the first one. Also, this message is
+            // always sent by WinDestroyWindow(), where it must be also ignored.
+            if (!qt_about_to_destroy_wnd && !sm_smActive &&
+                 !sm_gracefulShutdown) {
+                sm_smActive = true;
+                sm_gracefulShutdown = true;
+                sm_blockUserInput = true; // prevent user-interaction outside interaction windows
+                sm_cancel = false;
+                sm_quitSkipped = false;
+                if (qt_session_manager_self)
+                    qApp->commitData(*qt_session_manager_self);
+                sm_smActive = false; // session management has been finished
+                if (sm_cancel) {
+#if defined(DEBUG_SESSIONMANAGER)
+                    qDebug("WM_SAVEAPPLICATION: sm_cancel %d", sm_cancel);
+#endif
+                    // @todo propagate the patch that does the below to XWP
+                    // and enable the code when it appears upstream (see #100)
+#if 0
+                    // Here we try to cancel the Extended XWorkplace shutdown.
+                    // If it's XWorkplace who sent us WM_SAVEAPPLICATION, then
+                    // it probably passed us non-NULL parameters so that
+                    // mp1 = its window handle and mp2 = WM_COMMAND code to
+                    // cancel the shutdown procedure.
+                    HWND shutdownHwnd = HWNDFROMMP(mp1);
+                    if (WinIsWindow(0, shutdownHwnd)) {
+                        WinPostMsg(shutdownHwnd, WM_COMMAND, mp2, 0);
+                        // Ensure we will get WM_QUIT anyway, even if XWP was
+                        // not that fast to post it yet (we need it to correctly
+                        // finish the graceful shutdown procedure)
+                        sm_quitSkipped = true;
+                    }
+#endif
+                }
+                // repost WM_QUIT to ourselves because we might have ignored
+                // it in qt_app_canQuit(), so will not get one anymore
+                if (sm_quitSkipped)
+                    WinPostMsg(hwnd, WM_QUIT, 0, 0);
+            }
+            // PMREF recommends to pass it to WinDefWindowProc()
+            return WinDefWindowProc(hwnd, msg, mp1, mp2);
+        }
+#endif
+
         case WM_SYSVALUECHANGED: {
             // This message is sent to all top-level widgets, handle only once
@@ -785,4 +845,17 @@
             }
             #undef MY_IS_SV
+            break;
+        }
+
+        case WM_SYSCOLORCHANGE: {
+            // This message is sent to all top-level widgets, handle only once
+            QWidgetList list = QApplication::topLevelWidgets();
+            bool firstWidget = list.first()->winId() == hwnd;
+            if (!firstWidget)
+                break;
+            if (qApp->type() == QApplication::Tty)
+                break;
+            if (QApplication::desktopSettingsAware())
+                    qt_set_pm_resources();
             break;
         }
@@ -2222,4 +2295,104 @@
 }
 
+/*****************************************************************************
+  PM session management
+ *****************************************************************************/
+
+#if !defined(QT_NO_SESSIONMANAGER)
+
+bool QApplicationPrivate::canQuit()
+{
+#if defined (DEBUG_SESSIONMANAGER)
+    qDebug("QApplicationPrivate::canQuit: sm_smActive %d,"
+           "qt_about_to_destroy_wnd %d, sm_gracefulShutdown %d, sm_cancel %d",
+           sm_smActive, qt_about_to_destroy_wnd,
+           sm_gracefulShutdown, sm_cancel);
+#endif
+
+    bool quit = false;
+
+    // We can get multiple WM_QUIT messages while the "session termination
+    // procedure" (i.e. the QApplication::commitData() call) is still in
+    // progress. Ignore them.
+    if (!sm_smActive) {
+        if (sm_gracefulShutdown) {
+            // this is WM_QUIT after WM_SAVEAPPLICATION (either posted by the OS
+            // or by ourselves), confirm the quit depending on what the user wants
+            sm_quitSkipped = false;
+            quit = !sm_cancel;
+            if (sm_cancel) {
+                // the shutdown has been canceled, reset the flag to let the
+                // graceful shutdown happen again later
+                sm_gracefulShutdown = false;
+            }
+        } else {
+            // sm_gracefulShutdown is false, so allowsInteraction() and friends
+            // will return FALSE during commitData() (assuming that WM_QUIT w/o
+            // WM_SAVEAPPLICATION is an emergency termination)
+            sm_smActive = true;
+            sm_blockUserInput = true; // prevent user-interaction outside interaction windows
+            sm_cancel = false;
+            if (qt_session_manager_self)
+                qApp->commitData(*qt_session_manager_self);
+            sm_smActive = false;
+            quit = true; // ignore sm_cancel
+        }
+    } else {
+        // if this is a WM_QUIT received during WM_SAVEAPPLICATION handling,
+        // remember we've skipped (refused) it
+        if (sm_gracefulShutdown)
+            sm_quitSkipped = true;
+    }
+
+#if defined (DEBUG_SESSIONMANAGER)
+    qDebug("QApplicationPrivate::canQuit: returns %d", quit);
+#endif
+
+    return quit;
+}
+
+bool QSessionManager::allowsInteraction()
+{
+    // Allow interation only when the system is being normally shutdown
+    // and informs us using WM_SAVEAPPLICATION. When we receive WM_QUIT directly
+    // (so sm_gracefulShutdown is false), interaction is disallowed.
+    if (sm_smActive && sm_gracefulShutdown) {
+        sm_blockUserInput = false;
+        return true;
+    }
+
+    return false;
+}
+
+bool QSessionManager::allowsErrorInteraction()
+{
+    // Allow interation only when the system is being normally shutdown
+    // and informs us using WM_SAVEAPPLICATION. When we receive WM_QUIT directly
+    // (so sm_gracefulShutdown is false), interaction is disallowed.
+    if (sm_smActive && sm_gracefulShutdown) {
+        sm_blockUserInput = false;
+        return true;
+    }
+
+    return false;
+}
+
+void QSessionManager::release()
+{
+    if (sm_smActive && sm_gracefulShutdown)
+        sm_blockUserInput = true;
+}
+
+void QSessionManager::cancel()
+{
+    if (sm_smActive && sm_gracefulShutdown)
+        sm_cancel = true;
+}
+
+#endif // QT_NO_SESSIONMANAGER
+
+/*****************************************************************************
+  PM struct/message debug helpers
+ *****************************************************************************/
 
 /*!
@@ -2254,8 +2427,4 @@
     return QString(QLatin1String("<no-widget>"));
 }
-
-/*****************************************************************************
-  PM struct/message debug helpers
- *****************************************************************************/
 
 typedef QLatin1String QCStr;
Index: /trunk/src/gui/kernel/qwidget_pm.cpp
===================================================================
--- /trunk/src/gui/kernel/qwidget_pm.cpp	(revision 427)
+++ /trunk/src/gui/kernel/qwidget_pm.cpp	(revision 428)
@@ -71,4 +71,8 @@
 extern PFNWP QtOldFrameProc;
 extern MRESULT EXPENTRY QtFrameProc(HWND, ULONG, MPARAM, MPARAM);
+
+#if !defined(QT_NO_SESSIONMANAGER)
+bool qt_about_to_destroy_wnd = false;
+#endif
 
 typedef QSet<QString> WinClassNameHash;
