Index: trunk/src/kernel/qapplication_pm.cpp
===================================================================
--- trunk/src/kernel/qapplication_pm.cpp	(revision 77)
+++ trunk/src/kernel/qapplication_pm.cpp	(revision 78)
@@ -241,5 +241,6 @@
 static bool	sm_cancel            = FALSE;
 static bool	sm_gracefulShutdown  = FALSE;
-bool            qt_about_to_destroy_wnd = FALSE;
+static bool	sm_quitSkipped       = FALSE;
+bool qt_about_to_destroy_wnd     = FALSE;
 
 //#define DEBUG_SESSIONMANAGER
@@ -1034,14 +1035,42 @@
 #if !defined (QT_NO_SESSIONMANAGER)
         case WM_SAVEAPPLICATION: {
-#if defined (DEBUG_SESSIONMANAGER)                
+#if defined (DEBUG_SESSIONMANAGER)
             qDebug( "WM_SAVEAPPLICATION: sm_gracefulShutdown=%d "
-                    "qt_about_to_destroy_wnd=%d",
-                    sm_gracefulShutdown, qt_about_to_destroy_wnd );
-#endif            
+                    "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 ( !sm_gracefulShutdown && !qt_about_to_destroy_wnd ) {
+            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 ) {
+                    // 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 = it's 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;
+                    }
+                }
+                // 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()
@@ -1050,5 +1079,5 @@
         }
 #endif
-        
+
 /// @todo (dmik) later
 //    case WM_SETTINGCHANGE:
@@ -1434,15 +1463,15 @@
 #if 0
             qDebug( "WM_ACTIVATE: [%s] %d", widget->name(), SHORT1FROMMP(mp1) );
-#endif            
+#endif
 	    qApp->pmFocus( widget, SHORT1FROMMP(mp1) );
 	    break;
 
         case WM_SETFOCUS:
-#if 0            
+#if 0
             qDebug( "WM_SETFOCUS: [%s] %s [%s]", widget->name(),
                     SHORT1FROMMP(mp2) ? "<=" : "=>",
                     QWidget::find( (HWND)mp1 ) ? QWidget::find( (HWND)mp1 )->name()
                                                : "{foreign}" );
-#endif            
+#endif
             result = FALSE;
             if ( !SHORT1FROMMP(mp2) ) {
@@ -2278,5 +2307,5 @@
             SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2) );
 #endif
-    
+
     static QPoint pos;                          // window pos (y flipped)
     static POINTL gpos = { -1, -1 };            // global pos (y flipped)
@@ -2288,5 +2317,5 @@
     // candidate for a double click event
     static HWND dblClickCandidateWin = 0;
-    
+
     if ( sm_blockUserInput ) //block user interaction during session management
 	return TRUE;
@@ -2364,5 +2393,5 @@
         dblClickCandidateWin = 0;
     }
-    
+
     if ( type == QEvent::ContextMenu ) {
 	QPoint g = QPoint( qmsg.ptl.x, qmsg.ptl.y );
@@ -2407,5 +2436,5 @@
         // otherwise the specified window gets it unless it is already under the
         // pointer. We use this info to check whether the window can be a double
-        // click candidate (see above). 
+        // click candidate (see above).
         if ( qmsg.ptl.x == gpos.x && qmsg.ptl.y == gpos.y ) {
             if ( dblClickCandidateWin != qmsg.hwnd )
@@ -2547,5 +2576,5 @@
 	QMouseEvent e( type, pos, QPoint(gpos.x,gpos.y), button, state );
 	QApplication::sendSpontaneousEvent( widget, &e );
-        
+
 	if ( type != QEvent::MouseMove )
 	    pos.rx() = pos.ry() = -9999;	// init for move compression
@@ -3115,6 +3144,6 @@
 bool QETWidget::translatePaintEvent( const QMSG & )
 {
-    HPS displayPS = qt_display_ps(); 
-    
+    HPS displayPS = qt_display_ps();
+
 #if !defined (QT_PM_NO_WIDGETMASK)
     // Since we don't use WS_CLIPSIBLINGS and WS_CLIPCHILDREN bits (see
@@ -3123,5 +3152,5 @@
     validateObstacles();
 #endif
-    
+
     HRGN hrgn = GpiCreateRegion( displayPS, 0, NULL );
     LONG rc = WinQueryUpdateRegion( winId(), hrgn );
@@ -3161,5 +3190,5 @@
     }
 #endif
-    
+
     // flip y coordinate
     rcl.yBottom = height() - (rcl.yBottom + rcl.yTop);
@@ -3252,5 +3281,5 @@
             // need to move a non top-level window of a foreign process?).
             Q_ASSERT( isTopLevel() );
-#endif   
+#endif
 	    if ( isVisible() ) {
 		QResizeEvent e( newSize, oldSize );
@@ -3430,9 +3459,9 @@
 bool qt_app_canQuit()
 {
-#if defined (DEBUG_SESSIONMANAGER)                
+#if defined (DEBUG_SESSIONMANAGER)
     qDebug( "qt_app_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 );                
+            sm_gracefulShutdown, sm_cancel );
 #endif
 
@@ -3443,15 +3472,34 @@
     // progress. Ignore them.
     if ( !sm_smActive ) {
-        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;
-        sm_gracefulShutdown = FALSE;
-        answer = !sm_cancel;
-    }
-    
-#if defined (DEBUG_SESSIONMANAGER)                
+        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;
+            answer = !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;
+            answer = 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( "qt_app_canQuit(): answer=%ld", answer );
 #endif
