Index: /trunk/include/qwidget.h
===================================================================
--- /trunk/include/qwidget.h	(revision 63)
+++ /trunk/include/qwidget.h	(revision 64)
@@ -599,5 +599,9 @@
     friend class QDragManager;
 #elif defined (Q_WS_PM)
-    enum ClipMode { ClipDefault, Unclipped, ClipAll, ClipSiblings }; 
+#if !defined (QT_PM_NO_WIDGETMASK) 
+    void validateObstacles();
+    LONG combineObstacles( HRGN hrgn, LONG op );
+#endif    
+    enum ClipMode { ClipDefault, Unclipped, ClipAll }; 
     HPS getTargetPS( ClipMode m = ClipDefault );    
     friend Q_EXPORT void bitBlt( QPaintDevice *, int, int,
Index: /trunk/src/kernel/qapplication_pm.cpp
===================================================================
--- /trunk/src/kernel/qapplication_pm.cpp	(revision 63)
+++ /trunk/src/kernel/qapplication_pm.cpp	(revision 64)
@@ -958,9 +958,9 @@
 //@@TODO (dmik): are they all available in Warp3?
 enum {
-    // sent to hwnd that has been entered by mouse.
+    // sent to hwnd that has been entered to by a mouse pointer.
     // FID_CLIENT also receives enter messages of its WC_FRAME.
     // mp1 = hwnd that is entered, mp2 = hwnd that is left
     WM_U_MOUSEENTER = 0x41E,
-    // sent to hwnd that has been left by mouse.
+    // sent to hwnd that has been left by a mouse pointer.
     // FID_CLIENT also receives leave messages of its WC_FRAME.
     // mp1 = hwnd that is left, mp2 = hwnd that is entered
@@ -1437,4 +1437,5 @@
 	    break;
 	case WM_ERASEBACKGROUND:		// erase window background
+#if defined (QT_PM_NO_WIDGETMASK)
             // flush WM_PAINT messages here to update window contents
             // instantly while tracking the resize frame (normally these
@@ -1447,4 +1448,7 @@
             // clients only, so we would have to do all calculations ourselves).
             WinUpdateWindow( widget->winId() );
+#else
+            // We flush WM_PAINT messages in QETWidget::translateConfigEvent().
+#endif
             RETURN( FALSE );
 	    break;
@@ -1729,13 +1733,4 @@
 		    QPoint cpos = QCursor::pos();
 		    dispatch = !geom.contains( cpos );
-//@@TODO (dmik): later, window regions (WinQueryClipRegion())
-//		    if ( !dispatch ) {
-//			HRGN hrgn = CreateRectRgn(0,0,0,0);
-//			if ( GetWindowRgn( curWin, hrgn ) != ERROR ) {
-//			    QPoint lcpos = widget->mapFromGlobal( cpos );
-//			    dispatch = !PtInRegion( hrgn, lcpos.x(), lcpos.y() );
-//			}
-//			DeleteObject(hrgn);
-//		    }
 		}
 		if ( dispatch ) {
@@ -3211,9 +3206,17 @@
 bool QETWidget::translatePaintEvent( const QMSG & )
 {
-    HRGN hrgn;
-    hrgn = GpiCreateRegion( qt_display_ps(), 0, NULL );
+    HPS displayPS = qt_display_ps(); 
+    
+#if !defined (QT_PM_NO_WIDGETMASK)
+    // Since we don't use WS_CLIPSIBLINGS and WS_CLIPCHILDREN bits (see
+    // qwidget_pm.cpp), we have to validate areas that intersect with our
+    // children and siblings, taking their clip regions into account.
+    validateObstacles();
+#endif
+    
+    HRGN hrgn = GpiCreateRegion( displayPS, 0, NULL );
     LONG rc = WinQueryUpdateRegion( winId(), hrgn );
-    if ( rc == RGN_ERROR || rc == RGN_NULL ) {
-        GpiDestroyRegion( qt_display_ps(), hrgn );
+    if ( rc == RGN_ERROR ) {
+        GpiDestroyRegion( displayPS, hrgn );
 	hps = 0;
 	clearWState( WState_InPaintEvent );
@@ -3232,5 +3235,5 @@
     if ( !rcl.xRight || !rcl.yTop ) {
         WinEndPaint( hps );
-        GpiDestroyRegion( qt_display_ps(), hrgn );
+        GpiDestroyRegion( displayPS, hrgn );
         hps = 0;
         clearWState( WState_InPaintEvent );
@@ -3238,4 +3241,16 @@
     }
 
+#if !defined (QT_PM_NO_WIDGETMASK)
+    if ( WinQueryClipRegion( winId(), 0 ) != QCRGN_NO_CLIP_REGION ) {
+        // Correct the update region by intersecting it with the clip
+        // region (PM doesn't do that itself). It is necessary
+        // to have a correct QRegion in QPaintEvent.
+        HRGN hcrgn = GpiCreateRegion( displayPS, 0, NULL );
+        WinQueryClipRegion( winId(), hcrgn );
+        GpiCombineRegion( displayPS, hrgn, hrgn, hcrgn, CRGN_AND );
+        GpiDestroyRegion( displayPS, hcrgn );
+    }
+#endif
+    
     // flip y coordinate
     rcl.yBottom = height() - (rcl.yBottom + rcl.yTop);
@@ -3291,7 +3306,8 @@
         // that sends WM_SIZE).
 	QSize newSize( SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2) );
-        if ( qmsg.msg == WM_SIZE && size() != newSize )
+        if ( qmsg.msg == WM_SIZE && size() != newSize ) {
             if ( !(fStyle & WS_MINIMIZED) )
                 crect.setSize( newSize );
+        }
 	return TRUE;
     }
@@ -3318,4 +3334,14 @@
 	}
 	if ( !(fStyle & WS_MINIMIZED) && oldSize != newSize) {
+#if !defined (QT_PM_NO_WIDGETMASK)
+            // Spontaneous (external to Qt) WM_SIZE messages should occur only
+            // on top-level widgets. If we get them for a non top-level widget,
+            // the result will most likely be incorrect because widget masks will
+            // not be properly processed (i.e. in the way it is done in
+            // QWidget::internalSetGeometry() when the geometry is changed from
+            // within Qt). So far, I see no need to support this (who will ever
+            // need to move a non top-level window of a foreign process?).
+            Q_ASSERT( isTopLevel() );
+#endif   
 	    if ( isVisible() ) {
 		QResizeEvent e( newSize, oldSize );
@@ -3323,4 +3349,15 @@
 		if ( !testWFlags( WStaticContents ) )
 		    repaint( !testWFlags(WResizeNoErase) );
+#if !defined (QT_PM_NO_WIDGETMASK)
+                // Flush WM_PAINT messages here to update window contents
+                // instantly while tracking the resize frame (normally these
+                // messages are delivered after resizing is stopped for some
+                // time). It makes resizing a bit slower but gives a better look
+                // (no invalid window contents can be seen during resize).
+                // The alternative could be to erase the background only
+                // (similarly to Win32), but we need to do it for every
+                // non-toplevel window, which can be also time-consuming
+                WinUpdateWindow( winId() );
+#endif
 	    } else {
 		QResizeEvent *e = new QResizeEvent( newSize, oldSize );
Index: /trunk/src/kernel/qwidget_pm.cpp
===================================================================
--- /trunk/src/kernel/qwidget_pm.cpp	(revision 63)
+++ /trunk/src/kernel/qwidget_pm.cpp	(revision 64)
@@ -51,9 +51,9 @@
 #include "qcursor.h"
 #include <private/qapplication_p.h>
-//@@TODO (dmik): remove?
+/// @todo (dmik) remove?
 //#include <private/qinputcontext_p.h>
 
 const QString qt_reg_winclass( int );		// defined in qapplication_pm.cpp
-//@@TODO (dmik): later?
+/// @todo (dmik) later?
 //void	    qt_olednd_unregister( QWidget* widget, QOleDropTarget *dst ); // dnd_win
 //QOleDropTarget* qt_olednd_register( QWidget* widget );
@@ -61,6 +61,4 @@
 
 extern bool qt_nograb();
-//@@TODO (dmik): later (qregion_pm.cpp)
-//extern HRGN qt_win_bitmapToRegion(const QBitmap& bitmap);
 
 // defined in qapplication_pm.cpp
@@ -84,4 +82,508 @@
     return QtOldSysMenuProc( hwnd, msg, mp1, mp2 );
 }
+
+#if !defined (QT_PM_NO_WIDGETMASK)
+
+//#define DEBUG_WIDGETMASK
+
+/**
+ *  \internal
+ *  Extended version of WinQueryClipRegion(). If the given window has a
+ *  clip region, the given region will receive a copy of the clip region
+ *  clipped to the current window rectangle. If there is no clip region,
+ *  the given region will contain only the window rectangle on return.
+ */
+static void qt_WinQueryClipRegionOrRect( HWND hwnd, HRGN hrgn )
+{
+    RECTL rcl;
+    WinQueryWindowRect( hwnd, &rcl );
+
+    HPS hps = qt_display_ps();
+    GpiSetRegion( hps, hrgn, 1, &rcl );
+    if ( WinQueryClipRegion( hwnd, 0 ) != QCRGN_NO_CLIP_REGION ) {
+        HRGN hrgnTemp = GpiCreateRegion( hps, 0, NULL );
+        WinQueryClipRegion( hwnd, hrgnTemp );
+        GpiCombineRegion( hps, hrgn, hrgnTemp, hrgn, CRGN_AND );
+        GpiDestroyRegion( hps, hrgnTemp );
+    }    
+}
+
+enum {
+    PWO_Children = 0x01,
+    PWO_Sibings = 0x02,
+    PWO_Ancestors = 0x04,
+    PWO_All = PWO_Children | PWO_Sibings | PWO_Ancestors, 
+};
+
+/**
+ *  \internal
+ *  Extended version of WinInvalidateRegion(): invalidates the specified region
+ *  of the given window and regions of children from \a hwndFrom to \a hwndTo
+ *  if they intersect with the invalid region. If either of child window
+ *  handles is NULLHANDLE, children are not invalidated at all. Also, HWND_TOP
+ *  can be used as \a hwndFrom, HWND_BOTTOM \a can be used as \a hwndTo. 
+ */
+static BOOL qt_WinInvalidateRegionEx( HWND hwnd, HRGN hrgn,
+                                      HWND hwndFrom, HWND hwndTo )
+{
+#if defined (DEBUG_WIDGETMASK)
+    QWidget *w = QWidget::find( hwnd );
+    qDebug( "qt_WinInvalidateRegionEx: hwnd=%08lX (%s/%s) "
+            "hwndFrom=%08lX hwndTo=%08lX",
+            hwnd, w ? w->name() : 0, w ? w->className() : 0, hwndFrom, hwndTo );
+#endif
+    
+    if ( hwndFrom == HWND_TOP )
+        hwndFrom = WinQueryWindow( hwnd, QW_TOP );
+    if ( hwndTo == HWND_BOTTOM )
+        hwndTo = WinQueryWindow( hwnd, QW_BOTTOM );
+
+    if ( hwndFrom == 0 || hwndTo == 0 )
+        return WinInvalidateRegion( hwnd, hrgn, FALSE );
+    
+    if ( WinQueryWindow( hwndFrom, QW_PARENT ) != hwnd ||
+         WinQueryWindow( hwndTo, QW_PARENT ) != hwnd )
+        return FALSE;
+    
+    HPS hps = qt_display_ps();
+    
+    SWP swp;
+    HWND child = hwndFrom;
+    HRGN hrgnChild = GpiCreateRegion( hps, 0, NULL );
+    HRGN hrgnInv = GpiCreateRegion( hps, 0, NULL );
+    GpiCombineRegion( hps, hrgnInv, hrgn, 0, CRGN_COPY ); 
+    
+    LONG cmplx = RGN_RECT;
+    
+    while ( child ) {
+        WinQueryWindowPos( child, &swp );
+#if defined (DEBUG_WIDGETMASK)
+        w = QWidget::find( child );
+        qDebug( " child=%08lX [fl=%08lX] (%s/%s)", child, swp.fl,
+                w ? w->name() : 0, w ? w->className() : 0 );
+#endif
+        // proceed only if not hidden
+        if ( swp.fl & SWP_SHOW ) {
+            // get sibling's bounds (clip region or rect)
+            qt_WinQueryClipRegionOrRect( child, hrgnChild );
+            // translate the region to the parent's coordinate system
+            POINTL ptl = { swp.x, swp.y };
+            GpiOffsetRegion( hps, hrgnChild, &ptl );
+            // intersect the child's region with the invalid one
+            // and invalidate if not NULL
+            cmplx = GpiCombineRegion( hps, hrgnChild, hrgnChild, hrgnInv,
+                                      CRGN_AND );
+            if ( cmplx != RGN_NULL ) {
+                POINTL ptl2 = { -swp.x, -swp.y };
+                GpiOffsetRegion( hps, hrgnChild, &ptl2 );
+                WinInvalidateRegion( child, hrgnChild, TRUE );
+                GpiOffsetRegion( hps, hrgnChild, &ptl );
+                // substract the invalidated area from the widget's region
+                // (no need to invalidate it any more)
+                cmplx = GpiCombineRegion( hps, hrgnInv, hrgnInv, hrgnChild,
+                                          CRGN_DIFF );
+#if defined (DEBUG_WIDGETMASK)
+                qDebug( "  processed" );
+#endif
+                // finish if nothing left
+                if ( cmplx == RGN_NULL )
+                    break;
+            }
+        }
+        // iterate to the next window (below)
+        if ( child == hwndTo )
+            break;
+        child = WinQueryWindow( child, QW_NEXT );
+    }
+    
+    BOOL ok = (cmplx == RGN_NULL) || (child == hwndTo);
+    
+    if ( ok ) {
+        // invalidate what's left invalid after substracting children
+        WinInvalidateRegion( hwnd, hrgnInv, FALSE );
+    }
+    
+    GpiDestroyRegion( hps, hrgnInv );
+    GpiDestroyRegion( hps, hrgnChild );
+    
+    return ok;
+}
+
+/**
+ *  \internal
+ *  Helper function to collect all relative windows intersecting with the
+ *  given window and placed above it in z-order.
+ *
+ *  \param hwnd  window in question
+ *  \param prcl  rectangle (in window coordinates) to limit processing to
+ *               (if null, the whole window rectange is used)
+ *  \param hrgn  region where to combine all obstacles
+ *               (if 0, obstacles are directly validated instead of collecting)
+ *  \param op    region operation perfomed when combining obstacles (CRGN_*)
+ *  \param flags flags defining the scope (PWO_* ORed together)
+ *
+ *  \return complexity of the combined region (only when \a hrgn is not 0) 
+ */
+static LONG qt_WinProcessWindowObstacles( HWND hwnd, PRECTL prcl, HRGN hrgn,
+                                          LONG op, LONG flags = PWO_All )
+{
+    Q_ASSERT( hwnd );
+
+    HPS displayPS = qt_display_ps();
+    
+#if defined (DEBUG_WIDGETMASK)
+    QWidget *w = QWidget::find( hwnd );
+    qDebug( "qt_WinProcessWindowObstacles: hwnd=%08lX (%s/%s), prcl=%p "
+            "hrgn=%08lX, op=%ld flags=%08lX",
+            hwnd, w->name(), w->className(), prcl, hrgn, op, flags );
+#endif
+ 
+    SWP swpSelf;
+    WinQueryWindowPos( hwnd, &swpSelf ); 
+    
+    RECTL rclSelf = { 0, 0, swpSelf.cx, swpSelf.cy };
+    if ( prcl )
+        rclSelf = *prcl;
+
+    HRGN whrgn = GpiCreateRegion( displayPS, 0, NULL );
+
+    LONG cmplx = RGN_NULL;
+    HWND relative;
+    SWP swp;
+    
+    // first, go through all children (in z-order)
+    if ( flags & PWO_Children ) {
+        relative = WinQueryWindow( hwnd, QW_BOTTOM );
+        if ( relative != NULLHANDLE ) {
+            for ( ; relative != HWND_TOP; relative = swp.hwndInsertBehind ) {
+                WinQueryWindowPos( relative, &swp );
+#if defined (DEBUG_WIDGETMASK)
+                w = QWidget::find( relative );
+                qDebug( " child=%08lX [fl=%08lX] (%s/%s)", relative, swp.fl,
+                        w ? w->name() : 0, w ? w->className() : 0 );
+#endif
+                // skip if hidden
+                if ( !(swp.fl & SWP_SHOW) )
+                    continue;
+                // rough check for intersection
+                if ( swp.x >= rclSelf.xRight || swp.y >= rclSelf.yTop ||
+                     swp.x + swp.cx <= rclSelf.xLeft ||
+                     swp.y + swp.cy <= rclSelf.yBottom )
+                    continue;
+                // get the bounds (clip region or rect)
+                qt_WinQueryClipRegionOrRect( relative, whrgn );
+                // translate the region to this window's coordinate system
+                POINTL ptl = { swp.x, swp.y };
+                GpiOffsetRegion( displayPS, whrgn, &ptl );
+                // process the region
+                if ( hrgn != NULLHANDLE ) {
+                    cmplx = GpiCombineRegion( displayPS, hrgn, hrgn, whrgn, op );
+                } else {
+                    WinValidateRegion( hwnd, whrgn, FALSE ); 
+                }
+#if defined (DEBUG_WIDGETMASK)
+                qDebug( "  extracted" );
+#endif
+            }
+        }
+    }
+
+    HWND desktop = WinQueryDesktopWindow( 0, 0 );
+    HWND parent = WinQueryWindow( hwnd, QW_PARENT );
+    
+    // next, go through all siblings placed above (in z-order),
+    // but only if they are not top-level windows (that cannot be
+    // non-rectangular and thus are always correctly clipped by the system)
+    if ( (flags & PWO_Sibings) && parent != desktop ) {
+        for ( relative = swpSelf.hwndInsertBehind;
+              relative != HWND_TOP; relative = swp.hwndInsertBehind ) {
+            WinQueryWindowPos( relative, &swp );
+#if defined (DEBUG_WIDGETMASK)
+            w = QWidget::find( relative );
+            qDebug( " sibling=%08lX [fl=%08lX] (%s/%s)", relative, swp.fl,
+                    w ? w->name() : 0, w ? w->className() : 0 );
+#endif
+            // skip if hidden
+            if ( !(swp.fl & SWP_SHOW) )
+                continue;
+            // rough check for intersection
+            if ( swp.x >= swpSelf.x + rclSelf.xRight ||
+                 swp.y >= swpSelf.y + rclSelf.yTop ||
+                 swp.x + swp.cx <= swpSelf.x + rclSelf.xLeft ||
+                 swp.y + swp.cy <= swpSelf.y + rclSelf.yBottom )
+                continue;
+            // get the bounds (clip region or rect)
+            qt_WinQueryClipRegionOrRect( relative, whrgn );
+            // translate the region to this window's coordinate system
+            POINTL ptl = { swp.x - swpSelf.x, swp.y - swpSelf.y };
+            GpiOffsetRegion( displayPS, whrgn, &ptl );
+            // process the region
+            if ( hrgn != NULLHANDLE ) {
+                cmplx = GpiCombineRegion( displayPS, hrgn, hrgn, whrgn, op ); 
+            } else {
+                WinValidateRegion( hwnd, whrgn, FALSE ); 
+            }
+#if defined (DEBUG_WIDGETMASK)
+            qDebug( "  extracted" );
+#endif
+        }
+    }
+    
+    // last, go through all siblings of our parent and its ancestors
+    // placed above (in z-order)
+    if ( flags & PWO_Ancestors ) {
+        POINTL delta = { swpSelf.x, swpSelf.y };
+        while ( parent != desktop ) {
+            HWND grandParent = WinQueryWindow( parent, QW_PARENT );
+            // no need to clip top-level windows (that cannot be non-rectangular
+            // and thus are always correctly clipped by the system)
+            if ( grandParent == desktop )
+                break;
+            
+            WinQueryWindowPos( parent, &swp );
+#if defined (DEBUG_WIDGETMASK)
+            w = QWidget::find( parent );
+            qDebug( " parent=%08lX [fl=%08lX] (%s/%s)", parent, swp.fl,
+                    w ? w->name() : 0, w ? w->className() : 0 );
+#endif
+            delta.x += swp.x;
+            delta.y += swp.y;
+            for ( relative = swp.hwndInsertBehind;
+                  relative != HWND_TOP; relative = swp.hwndInsertBehind ) {
+                WinQueryWindowPos( relative, &swp );
+#if defined (DEBUG_WIDGETMASK)
+                w = QWidget::find( relative );
+                qDebug( " ancestor=%08lX [fl=%08lX] (%s/%s)", relative, swp.fl,
+                        w ? w->name() : 0, w ? w->className() : 0 );
+#endif
+                // skip if hidden
+                if ( !(swp.fl & SWP_SHOW) )
+                    continue;
+                // rough check for intersection
+                if ( swp.x - delta.x >= rclSelf.xRight ||
+                     swp.y - delta.y >= rclSelf.yTop ||
+                     swp.x - delta.x + swp.cx <= rclSelf.xLeft ||
+                     swp.y - delta.y + swp.cy <= rclSelf.yBottom )
+                    continue;
+                // get the bounds (clip region or rect)
+                qt_WinQueryClipRegionOrRect( relative, whrgn );
+                // translate the region to this window's coordinate system
+                POINTL ptl = { swp.x - delta.x, swp.y - delta.y };
+                GpiOffsetRegion( displayPS, whrgn, &ptl );
+                // process the region
+                if ( hrgn != NULLHANDLE ) {
+                    cmplx = GpiCombineRegion( displayPS, hrgn, hrgn, whrgn, op ); 
+                } else {
+                    WinValidateRegion( hwnd, whrgn, FALSE ); 
+                }
+#if defined (DEBUG_WIDGETMASK)
+                qDebug( "  extracted" );
+#endif
+            }
+            parent = grandParent;
+        }
+    }
+
+    GpiDestroyRegion( displayPS, whrgn );
+    
+    return cmplx;
+}
+
+/**
+ *  \internal
+ *  Partial reimplementation of the WinSetWindowPos() API that obeys window clip
+ *  regions. Currently supported flags are SWP_ZORDER, SWP_SHOW and SWP_HIDE.
+ *  Other flags should not be used. Note that if any other flag is specified
+ *  (alone or in addition to the supported ones), or if the given window is a
+ *  top-level window, this function acts exactly like the original
+ *  WinSetWindowPos() function.
+ */
+static BOOL qt_WinSetWindowPos( HWND hwnd, HWND hwndInsertBehind,
+                                LONG x, LONG y, LONG cx, LONG cy,
+                                ULONG fl )
+{
+#if defined (DEBUG_WIDGETMASK)
+    QWidget *w = QWidget::find( hwnd );
+    qDebug( "qt_WinSetWindowPos: hwnd=%08lX (%s/%s) fl=%08lX",
+            hwnd, w ? w->name() : 0, w ? w->className() : 0, fl );
+#endif
+
+    Q_ASSERT( (fl & ~(SWP_ZORDER | SWP_SHOW | SWP_HIDE)) == 0 );
+    
+    HWND desktop = WinQueryDesktopWindow( 0, 0 );
+    if ( (fl & ~(SWP_ZORDER | SWP_SHOW | SWP_HIDE)) != 0 ||
+         hwnd == desktop || WinQueryWindow( hwnd, QW_PARENT ) == desktop ) {
+        return WinSetWindowPos( hwnd, hwndInsertBehind, x, y, cx, cy, fl );
+    }
+    
+    SWP swpOld;
+    WinQueryWindowPos( hwnd, &swpOld );
+
+    // do some checks
+    if ( (fl & SWP_ZORDER) && swpOld.hwndInsertBehind == hwndInsertBehind )
+        fl &= ~SWP_ZORDER;
+    if ( (fl & SWP_SHOW) && (swpOld.fl & SWP_SHOW) ) 
+        fl &= ~SWP_SHOW;
+    if ( (fl & SWP_HIDE) && (swpOld.fl & SWP_HIDE) ) 
+        fl &= ~SWP_HIDE;
+    if ( (fl & (SWP_SHOW | SWP_HIDE)) == (SWP_SHOW | SWP_HIDE) ) 
+        fl &= ~SWP_HIDE;
+    
+    BOOL rc = WinSetWindowPos( hwnd, hwndInsertBehind, x, y, cx, cy,
+                               fl | SWP_NOREDRAW );
+    if ( rc == FALSE || (fl & SWP_NOREDRAW) )
+        return rc;
+
+    SWP swpNew;
+    WinQueryWindowPos( hwnd, &swpNew );
+    
+    if ( swpOld.hwndInsertBehind == swpNew.hwndInsertBehind )
+        fl &= ~SWP_ZORDER;
+    
+    if ( (fl & (SWP_ZORDER | SWP_SHOW | SWP_HIDE)) == 0 )
+        return rc;
+
+    HPS hps = qt_display_ps();
+    HWND hwndParent = WinQueryWindow( hwnd, QW_PARENT );
+    
+    // get window bounds
+    HRGN hrgnSelf = GpiCreateRegion( hps, 0, NULL );
+    qt_WinQueryClipRegionOrRect( hwnd, hrgnSelf );
+    
+    if ( fl & SWP_SHOW ) {
+        WinInvalidateRegion( hwnd, hrgnSelf, TRUE );
+    } else if ( fl & SWP_HIDE ) {
+        // translate the region to the parent coordinate system
+        POINTL ptl = { swpNew.x, swpNew.y };
+        GpiOffsetRegion( hps, hrgnSelf, &ptl );
+        // invalidate the parent and children below this window
+        qt_WinInvalidateRegionEx( hwndParent, hrgnSelf,
+                                  WinQueryWindow( hwnd, QW_NEXT ), HWND_BOTTOM );
+    } else { // fl & SWP_ZORDER
+        // below we assume that WinSetWindowPos() returns FALSE if
+        // an incorrect (unrelated) hwndInsertBehind is passed when SWP_ZORDER
+        // is set
+        
+        // first, detect whether we are moving up or down
+        BOOL up;
+        HWND hwndFrom, hwndTo;
+        if ( swpOld.hwndInsertBehind == HWND_TOP ) {
+            up = FALSE;
+            hwndFrom = WinQueryWindow( hwndParent, QW_TOP );
+            hwndTo = swpNew.hwndInsertBehind;
+        } else {
+            up = TRUE;
+            for ( HWND hwndAbove = hwnd;
+                  (hwndAbove = WinQueryWindow( hwndAbove, QW_PREV )) != 0; ) {
+                if ( hwndAbove == swpOld.hwndInsertBehind ) {
+                    up = FALSE;
+                    break;
+                }
+            }
+            if ( up ) {
+                hwndFrom = swpOld.hwndInsertBehind;
+                hwndTo = WinQueryWindow( hwnd, QW_NEXT );
+            } else {
+                hwndFrom = WinQueryWindow( swpOld.hwndInsertBehind, QW_NEXT );
+                hwndTo = swpNew.hwndInsertBehind;
+            }
+        }
+#if defined (DEBUG_WIDGETMASK)
+        qDebug( " moving up? %ld", up );
+        w = QWidget::find( hwndFrom );
+        qDebug( " hwndFrom=%08lX (%s/%s)", hwndFrom,
+                    w ? w->name() : 0, w ? w->className() : 0 );
+        w = QWidget::find( hwndTo );
+        qDebug( " hwndTo=%08lX (%s/%s)", hwndTo,
+                    w ? w->name() : 0, w ? w->className() : 0 );
+#endif
+
+        SWP swp;
+        HWND sibling = hwndFrom;
+        HRGN hrgn = GpiCreateRegion( hps, 0, NULL );
+        HRGN hrgnUpd = GpiCreateRegion( hps, 0, NULL );
+        
+        if ( up ) {
+            // go upwards in z-order
+            while ( 1 ) {
+                WinQueryWindowPos( sibling, &swp );
+#if defined (DEBUG_WIDGETMASK)
+                w = QWidget::find( sibling );
+                qDebug( " sibling=%08lX [fl=%08lX] (%s/%s)", sibling, swp.fl,
+                        w ? w->name() : 0, w ? w->className() : 0 );
+#endif
+                // proceed only if not hidden
+                if ( swp.fl & SWP_SHOW ) {
+                    // get sibling's bounds (clip region or rect)
+                    qt_WinQueryClipRegionOrRect( sibling, hrgn );
+                    // translate the region to this window's coordinate system
+                    POINTL ptl = { swp.x - swpNew.x, swp.y - swpNew.y };
+                    GpiOffsetRegion( hps, hrgn, &ptl );
+                    // add to the region of siblings we're moving on top of
+                    GpiCombineRegion( hps, hrgnUpd, hrgnUpd, hrgn, CRGN_OR );
+#if defined (DEBUG_WIDGETMASK)
+                    qDebug( "  processed" );
+#endif
+                }
+                // iterate to the prev window (above)
+                if ( sibling == hwndTo )
+                    break;
+                sibling = swp.hwndInsertBehind;
+            }
+            // intersect the resulting region with the widget region and
+            // invalidate
+            GpiCombineRegion( hps, hrgnUpd, hrgnSelf, hrgnUpd, CRGN_AND );
+            WinInvalidateRegion( hwnd, hrgnUpd, TRUE );
+        } else {
+            // go downwards in reverse z-order
+            POINTL ptl = { 0, 0 };
+            while ( 1 ) {
+                WinQueryWindowPos( sibling, &swp );
+#if defined (DEBUG_WIDGETMASK)
+                w = QWidget::find( sibling );
+                qDebug( " sibling=%08lX [fl=%08lX] (%s/%s)", sibling, swp.fl,
+                        w ? w->name() : 0, w ? w->className() : 0 );
+#endif
+                // proceed only if not hidden
+                if ( swp.fl & SWP_SHOW ) {
+                    // get sibling's bounds (clip region or rect)
+                    qt_WinQueryClipRegionOrRect( sibling, hrgn );
+                    // undo the previous translation and translate this window's
+                    // region to the siblings's coordinate system
+                    ptl.x += swpNew.x - swp.x;
+                    ptl.y += swpNew.y - swp.y;
+                    GpiOffsetRegion( hps, hrgnSelf, &ptl );
+                    // intersect the sibling's region with the translated one
+                    // and invalidate the sibling
+                    GpiCombineRegion( hps, hrgnUpd, hrgnSelf, hrgn, CRGN_AND );
+                    WinInvalidateRegion( sibling, hrgnUpd, TRUE );
+                    // substract the invalidated area from the widget's region
+                    // (no need to invalidate it any more)
+                    GpiCombineRegion( hps, hrgnSelf, hrgnSelf, hrgnUpd, CRGN_DIFF );
+                    // prepare the translation from the sibling's
+                    // coordinates back to this window's coordinates
+                    ptl.x = swp.x - swpNew.x;
+                    ptl.y = swp.y - swpNew.y;
+#if defined (DEBUG_WIDGETMASK)
+                    qDebug( "  processed" );
+#endif
+                }
+                // iterate to the next window (below)
+                if ( sibling == hwndTo )
+                    break;
+                sibling = WinQueryWindow( sibling, QW_NEXT );
+            }
+        }
+
+        GpiDestroyRegion( hps, hrgnUpd );
+        GpiDestroyRegion( hps, hrgn );
+    }
+    
+    GpiDestroyRegion( hps, hrgnSelf );
+    
+    return TRUE; 
+}
+
+#endif
 
 static void removeSysMenuAccels( HWND frame )
@@ -216,4 +718,12 @@
     }
     if ( !desktop ) {
+#if !defined (QT_PM_NO_WIDGETMASK)
+        // We don't use WS_CLIPSIBLINGS and WS_CLIPCHILDREN, because when these
+        // styles are set and a child/sibling window has a non-NULL clip region,
+        // PM still continues to exclude the entire child's rectangle from the
+        // parent window's update region, ignoring its clip region. As a result,
+        // areas outside the clip region are left unpainted. Instead, we correct
+        // the update region of the window ourselves, on every WM_PAINT event.
+#else
         /// @todo (dmik)
         //  this is temporarily commented out because QSplitter sets
@@ -223,4 +733,5 @@
 	/* if ( !testWFlags( WPaintUnclipped ) ) */
 	    style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
+#endif            
         // for all top-level windows except popups we create a WC_FRAME
         // as a parent and owner.
@@ -325,7 +836,9 @@
             );
 #endif
+            // note that we place the client on top (HWND_TOP) to exclude other
+            // frame controls from being analysed in qt_WinProcessWindowObstacles
             id = WinCreateWindow(
                     fId, pszClassName, title, style, 0, 0, 0, 0,
-                    fId, HWND_BOTTOM, FID_CLIENT, NULL, NULL
+                    fId, HWND_TOP, FID_CLIENT, NULL, NULL
             );
         } else {
@@ -905,4 +1418,7 @@
         RECTL rcl = { x, y, x + w, y + h };
 
+#if !defined (QT_PM_NO_WIDGETMASK)
+        WinInvalidateRect( winId(), &rcl, FALSE );
+#else
         // WinInvalidateRect() has such a "feature" that children are not
         // actually extracted from the window's update region when it has
@@ -931,6 +1447,4 @@
                     w = (QWidget*)object;
                     if ( !w->isTopLevel() && w->isShown() ) {
-//@@TODO (dmik): later: substract the region of the child window
-// (WinQueryClipRegion()) instead of the window rectangle.
                         const QRect &r = w->crect;
                         rcl.xLeft = r.left();
@@ -949,4 +1463,5 @@
             WinInvalidateRect( winId(), &rcl, FALSE );
         }
+#endif            
     }
 }
@@ -1116,5 +1631,11 @@
     deactivateWidgetCleanup();
     HWND id = winFId();
+    
+#if defined (QT_PM_NO_WIDGETMASK)
     WinShowWindow( id, FALSE );
+#else        
+    qt_WinSetWindowPos( id, 0, 0, 0, 0, 0, SWP_HIDE );
+#endif
+    
     if ( isTopLevel() )
         WinSetWindowPos( id, 0, 0, 0, 0, 0, SWP_DEACTIVATE );
@@ -1137,5 +1658,10 @@
 void QWidget::showWindow()
 {
+#if defined (QT_PM_NO_WIDGETMASK)
     WinShowWindow( winFId(), TRUE );
+#else        
+    qt_WinSetWindowPos( winFId(), 0, 0, 0, 0, 0, SWP_SHOW );
+#endif
+    
     ULONG fl = 0;
     if ( isTopLevel() ) {
@@ -1178,22 +1704,4 @@
     if ( fl )
         WinSetWindowPos( winFId(), 0, 0, 0, 0, 0, fl );
-
-//@@TODO (dmik): remove? in OS/2 WinShowWindow() does not influence
-//  any other state flags of the window (such as maximized/minimized, active),
-//  so, the window is always shown at its current state (i.e. if its state was
-//  not changed while it was hidden it will be restored to that state upon
-//  unhiding; if the state was changed, it will be restored to that new state).
-//    int sm = SW_SHOWNORMAL;
-//    if ( isTopLevel() ) {
-//	if (testWState(WState_Minimized))
-//	    sm = SW_SHOWMINIMIZED;
-//	else if (testWState(WState_Maximized))
-//	    sm = SW_SHOWMAXIMIZED;
-//    }
-//    if (testWFlags(WStyle_Tool) || isPopup())
-//	sm = SW_SHOWNOACTIVATE;
-//
-//    ShowWindow( winId(), sm );
-//    UpdateWindow( winId() );
 }
 
@@ -1205,5 +1713,10 @@
 //@@TODO (dmik): remove? SWP_ZORDER doesn't cause activation in OS/2...
 //    uint f = ( isPopup() || testWFlags(WStyle_Tool) ) ? SWP_NOACTIVATE : 0;
+
+#if defined (QT_PM_NO_WIDGETMASK)
     WinSetWindowPos( winFId(), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
+#else        
+    qt_WinSetWindowPos( winFId(), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
+#endif
 }
 
@@ -1215,5 +1728,10 @@
 //@@TODO (dmik): remove? SWP_ZORDER doesn't cause activation in OS/2...
 //    uint f = ( isPopup() || testWFlags(WStyle_Tool) ) ? SWP_NOACTIVATE : 0;
+
+#if defined (QT_PM_NO_WIDGETMASK)
     WinSetWindowPos( winFId(), HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER );
+#else        
+    qt_WinSetWindowPos( winFId(), HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER );
+#endif
 }
 
@@ -1227,5 +1745,9 @@
 	p->childObjects->insert( p->childObjects->findRef(w), this );
     }
+#if defined (QT_PM_NO_WIDGETMASK)
     WinSetWindowPos( winId(), w->winId(), 0, 0, 0, 0, SWP_ZORDER );
+#else        
+    qt_WinSetWindowPos( winId(), w->winId(), 0, 0, 0, 0, SWP_ZORDER );
+#endif
 }
 
@@ -1253,5 +1775,6 @@
     if ( !isTopLevel() )
 	isMove = (crect.topLeft() != QPoint( x, y ));
-    if ( isMove == FALSE && oldSize.width()==w && oldSize.height()==h )
+    bool isResize = w != oldSize.width() || h != oldSize.height();
+    if ( isMove == FALSE && isResize == FALSE )
 	return;
     clearWState(WState_Maximized);
@@ -1264,16 +1787,5 @@
 	setWState( WState_ConfigPending );
 	if ( isTopLevel() ) {
-//@@TODO (dmik): remove, no need to check for extra...
-//	    QRect fr( frameGeometry() );
-//	    if ( extra ) {
-//		fr.setLeft( fr.left() + x - crect.left() );
-//		fr.setTop( fr.top() + y - crect.top() );
-//		fr.setRight( fr.right() + ( x + w - 1 ) - crect.right() );
-//		fr.setBottom( fr.bottom() + ( y + h - 1 ) - crect.bottom() );
-//	    }
-//	    MoveWindow( winId(), fr.x(), fr.y(), fr.width(), fr.height(), TRUE );
-//	    crect.setRect( x, y, w, h );
-
-//@@TODO (dmik): optimize: use extra->topextra directly (after updating fstrut
+/// @todo (dmik) optimize: use extra->topextra directly (after updating fstrut
 //  if necessary) instead of calling frameGeometry()
 	    QRect fr( frameGeometry() );
@@ -1287,13 +1799,151 @@
             WinSetWindowPos( winFId(), 0, fx, fy, fw, fh, SWP_MOVE | SWP_SIZE );
 	} else {
+#if defined (QT_PM_NO_WIDGETMASK)
             // flip y coordinate
             int fy = parentWidget()->height() - (y + h);
 	    crect.setRect( x, y, w, h );
             WinSetWindowPos( winId(), 0, x, fy, w, h, SWP_MOVE | SWP_SIZE );
+#else
+            // When WS_CLIPCHILDREN and WS_CLIPSIBLINGS are not used,
+            // WinSetWindowPos() does not correctly update involved windows.
+            // The fix is to do it ourselves, taking clip regions into account.
+            
+            QWidget *parent = parentWidget();
+            const int ph = parent->height();
+            // flip y coordinate
+            int fy = ph - (y + h);
+            // set new and old rectangles
+            const RECTL rcls [2] = {
+                // new (y flipped, relative to parent)
+                { x, fy, x + w, fy + h },    
+                // old (y flipped, relative to parent)
+                { crect.left(), ph - (crect.bottom() + 1),
+                  crect.right() + 1, ph - crect.top() }
+            };
+            const RECTL &rclNew = rcls [0];
+            const RECTL &rclOld = rcls [1];
+            // delta to shift coordinate space from parent to this widget
+            POINTL ptlToSelf = { -x, -fy };
+            // update crect and move the widget w/o redrawing
+	    crect.setRect( x, y, w, h );
+            WinSetWindowPos( winId(), 0, x, fy, w, h,
+                             SWP_MOVE | SWP_SIZE | SWP_NOREDRAW );
+            // use parent PS for blitting  
+            HPS hps = WinGetPS( parent->winId() );
+            // get old and new clip regions (relative to parent)
+            HRGN hrgnOld = GpiCreateRegion( hps, 1, &rclOld );
+            HRGN hrgnNew = GpiCreateRegion( hps, 1, &rclNew );
+            if ( WinQueryClipRegion( winId(), 0 ) != QCRGN_NO_CLIP_REGION ) {
+                HRGN hrgnTemp = GpiCreateRegion( hps, 0, NULL );
+                // old (clipped to the old rect)
+                WinQueryClipRegion( winId(), hrgnTemp );
+                GpiOffsetRegion( hps, hrgnTemp, (PPOINTL) &rclOld );
+                GpiCombineRegion( hps, hrgnOld, hrgnTemp, hrgnOld, CRGN_AND ); 
+                // new (clipped to the new rect)
+                WinQueryClipRegion( winId(), hrgnTemp );
+                if ( oldSize.height() != h ) {
+                    // keep the clip region top-left aligned by adding the
+                    // height delta (new size - old size)
+                    POINTL ptl = { 0, h - oldSize.height() }; 
+                    GpiOffsetRegion( hps, hrgnTemp, &ptl );
+                    WinSetClipRegion( winId(), hrgnTemp );
+                }
+                GpiOffsetRegion( hps, hrgnTemp, (PPOINTL) &rclNew );
+                GpiCombineRegion( hps, hrgnNew, hrgnTemp, hrgnNew, CRGN_AND );
+                GpiDestroyRegion( hps, hrgnTemp );
+            }
+            // the rest is useful only when the widget is visible
+            if ( isVisible() ) {
+                // create affected region (old + new, relative to widget)
+                HRGN hrgnAff = GpiCreateRegion( hps, 0, NULL );
+                GpiCombineRegion( hps, hrgnAff, hrgnOld, hrgnNew, CRGN_OR );
+                GpiOffsetRegion( hps, hrgnAff, &ptlToSelf );
+                // get bounding rectangle of affected region
+                RECTL rclAff;
+                GpiQueryRegionBox( hps, hrgnAff, &rclAff );
+                // get region of obstacles limited to affected rectangle
+                HRGN hrgnObst = GpiCreateRegion( hps, 0, NULL );
+                qt_WinProcessWindowObstacles( winId(), &rclAff, hrgnObst, CRGN_OR,
+                                              PWO_Sibings | PWO_Ancestors );
+                // shift region of obstacles and affected region back to
+                // parent coords
+                GpiOffsetRegion( hps, hrgnObst, (PPOINTL) &rclNew );
+                GpiOffsetRegion( hps, hrgnAff, (PPOINTL) &rclNew );
+                // get parent bounds (clip region or rect)
+                HRGN hrgnUpd = GpiCreateRegion( hps, 0, NULL );
+                qt_WinQueryClipRegionOrRect( parent->winId(), hrgnUpd );
+                // add parts of old region beyond parent bounds to
+                // region of obstacles
+                GpiCombineRegion( hps, hrgnOld, hrgnOld, hrgnUpd, CRGN_DIFF );
+                GpiCombineRegion( hps, hrgnObst, hrgnObst, hrgnOld, CRGN_OR );
+                // substract region of obstacles from affected region
+                GpiCombineRegion( hps, hrgnAff, hrgnAff, hrgnObst, CRGN_DIFF );
+                // remember it as parent update region (need later)
+                GpiCombineRegion( hps, hrgnUpd, hrgnAff, 0, CRGN_COPY );
+                // copy region of obstacles to delta region and shift it by
+                // delta (note: movement is considered to be top-left aligned)
+                HRGN hrgnDelta = GpiCreateRegion( hps, 0, NULL );
+                GpiCombineRegion( hps, hrgnDelta, hrgnObst, 0, CRGN_COPY );
+                POINTL ptlDelta = { rclNew.xLeft - rclOld.xLeft,
+                                    rclNew.yTop - rclOld.yTop };
+                GpiOffsetRegion( hps, hrgnDelta, &ptlDelta );
+                // substract region of obstacles from delta region to get
+                // pure delta
+                GpiCombineRegion( hps, hrgnDelta, hrgnDelta, hrgnObst, CRGN_DIFF );
+                // calculate minimal rectangle to blit (top-left aligned)
+                int minw = QMIN( oldSize.width(), w );
+                int minh = QMIN( oldSize.height(), h );
+                POINTL blitPtls [4] = {
+                    // target (new)
+                    { rclNew.xLeft, rclNew.yTop - minh },
+                    { rclNew.xLeft + minw, rclNew.yTop },
+                    // source (old)
+                    { rclOld.xLeft, rclOld.yTop - minh },
+                };
+                // proceed with blitting only if target and source rects differ
+                if ( blitPtls[0].x !=  blitPtls[2].x ||
+                     blitPtls[0].y !=  blitPtls[2].y )
+                {
+                    // Substract delta region from affected region (to minimize
+                    // flicker)
+                    GpiCombineRegion( hps, hrgnAff, hrgnAff, hrgnDelta, CRGN_DIFF );
+                    // set affected region to parent PS
+                    GpiSetClipRegion( hps, hrgnAff, NULL );
+                    // blit minimal rectangle
+                    GpiBitBlt( hps, hps, 3, blitPtls, ROP_SRCCOPY, BBO_IGNORE );
+                    GpiSetClipRegion( hps, 0, NULL );
+                }
+                // substract new widget region from the parent update region
+                // and invalidate it (with underlying children)
+                GpiCombineRegion( hps, hrgnUpd, hrgnUpd, hrgnNew, CRGN_DIFF );
+                qt_WinInvalidateRegionEx( parent->winId(), hrgnUpd,
+                                          WinQueryWindow( winId(), QW_NEXT ),
+                                          HWND_BOTTOM );
+                // intersect pure delta region with new region
+                // (to detect areas clipped off to minimize flicker when blitting)
+                GpiCombineRegion( hps, hrgnDelta, hrgnDelta, hrgnNew, CRGN_AND );
+                // substract blitted rectangle from new region
+                GpiSetRegion( hps, hrgnAff, 1, (PRECTL) &blitPtls );
+                GpiCombineRegion( hps, hrgnNew, hrgnNew, hrgnAff, CRGN_DIFF );
+                // combine the rest with intersected delta region
+                GpiCombineRegion( hps, hrgnNew, hrgnNew, hrgnDelta, CRGN_OR );
+                // shift the result back to widget coords and invalidate
+                GpiOffsetRegion( hps, hrgnNew, &ptlToSelf );
+                WinInvalidateRegion( winId(), hrgnNew, TRUE );
+                // free resources
+                GpiDestroyRegion( hps, hrgnDelta );
+                GpiDestroyRegion( hps, hrgnUpd );
+                GpiDestroyRegion( hps, hrgnObst );
+                GpiDestroyRegion( hps, hrgnAff );
+            }
+            // free resources
+            GpiDestroyRegion( hps, hrgnOld );
+            GpiDestroyRegion( hps, hrgnNew );
+            WinReleasePS( hps );
+#endif
 	}
 	clearWState( WState_ConfigPending );
     }
 
-    bool isResize = w != oldSize.width() || h != oldSize.height();
     if ( isVisible() ) {
 	if ( isMove && pos() != oldPos ) {
@@ -1456,5 +2106,5 @@
 	newRegion = rgn.handle( height() );
     }
-    GpiSetClipRegion( lhps, newRegion, &oldRegion );
+    GpiSetClipRegion( lhps, newRegion, NULL );
 
     QPoint offset = backgroundOffset();
@@ -1475,4 +2125,5 @@
 }
 
+#if defined (QT_PM_NO_WIDGETMASK)        
 
 // helper function to extract regions of all windows that overlap the given
@@ -1490,6 +2141,4 @@
         while( (i = WinQueryWindow( i, QW_PREV )) ) {
             if ( WinIsWindowShowing( i ) ) {
-//@@TODO (dmik): probably we should use WinQueryClipRegion() here to
-//  handle non-rectangular windows properly
                 WinQueryWindowRect( i, &r );
                 WinMapWindowPoints( i, hwnd, (PPOINTL) &r, 2 );
@@ -1593,8 +2242,122 @@
 }
 
+#else
+
+/**
+ *  \internal
+ *  Helper to scroll window contents.
+ *  All coordinates are GPI, not Qt.
+ */
+static void scrollWindow( HWND hwnd, int w, int h,
+                          int dx, int dy, const PRECTL clip = NULL )
+{
+    POINTL ptlDelta = { dx, dy }; 
+    
+    POINTL ptls[4];
+    RECTL &rclSrc = *(PRECTL) &ptls[2];
+    RECTL &rclDst = *(PRECTL) &ptls[0];
+
+    if ( clip ) {
+        rclSrc = *clip;
+    } else {
+        rclSrc.xLeft = rclSrc.yBottom = 0;
+        rclSrc.xRight = w;
+        rclSrc.yTop = h;
+    }
+    rclDst = rclSrc;
+    rclDst.xLeft += dx;
+    rclDst.xRight += dx;
+    rclDst.yBottom += dy;
+    rclDst.yTop += dy;
+    
+    if ( !clip ) {
+        // move all child widgets silently
+        SWP swp;
+        HWND child = WinQueryWindow( hwnd, QW_BOTTOM );
+        if ( child != NULLHANDLE ) {
+            for ( ; child != HWND_TOP; child = swp.hwndInsertBehind ) {
+                WinQueryWindowPos( child, &swp );
+                swp.x += dx;
+                swp.y += dy;
+                WinSetWindowPos( child, 0, swp.x, swp.y, 0, 0, 
+                                 SWP_MOVE | SWP_NOADJUST | SWP_NOREDRAW );
+                // WinSetWindowPos() doesn't send WM_MOVE to windows w/o
+                // CS_MOVENOTIFY, but having this style for non-toplevel
+                // widgets is unwanted, so we send them WM_MOVE manually
+                // to let their geometry to be properly updated by
+                // QETWidget::translateConfigEvent().
+                WinSendMsg( child, WM_MOVE, 0, 0 );
+            }
+        }
+    }
+    
+    WinLockVisRegions( HWND_DESKTOP, TRUE );
+    
+    HPS hps = WinGetPS( hwnd );
+
+    // get widget bounds (clip region or rect)
+    HRGN hrgnClip = GpiCreateRegion( hps, 0, NULL );
+    qt_WinQueryClipRegionOrRect( hwnd, hrgnClip );
+    // compose a region uncovered after scrolling
+    HRGN hrgnUpd = GpiCreateRegion( hps, 0, NULL );
+    GpiCombineRegion( hps, hrgnUpd, hrgnClip, 0, CRGN_COPY );
+    GpiOffsetRegion( hps, hrgnUpd, &ptlDelta );
+    GpiCombineRegion( hps, hrgnUpd, hrgnClip, hrgnUpd, CRGN_DIFF );
+    
+    if ( clip ) {
+        // intersect it with the given clip rect
+        HRGN hrgn = GpiCreateRegion( hps, 1, clip );
+        GpiCombineRegion( hps, hrgnUpd, hrgnClip, hrgnUpd, CRGN_AND );
+        GpiDestroyRegion( hps, hrgn );
+    }
+    
+    int pwoFlags = PWO_Ancestors | PWO_Sibings;
+    if ( clip )
+        pwoFlags |= PWO_Children;
+    
+    // get the region of obstacles
+    HRGN hrgnObst = GpiCreateRegion( hps, 0, NULL );
+    qt_WinProcessWindowObstacles( hwnd, &rclSrc, hrgnObst, CRGN_OR, pwoFlags );
+    // create the delta region of obstacles
+    HRGN hrgnDelta = GpiCreateRegion( hps, 0, NULL );
+    GpiCombineRegion( hps, hrgnDelta, hrgnObst, 0, CRGN_COPY );
+    GpiOffsetRegion( hps, hrgnDelta, &ptlDelta );
+    // substract the region of obstaces fro the delta region to get pure delta
+    GpiCombineRegion( hps, hrgnDelta, hrgnDelta, hrgnObst, CRGN_DIFF );
+    // substract obstacles the clip region 
+    GpiCombineRegion( hps, hrgnClip, hrgnClip, hrgnObst, CRGN_DIFF );
+    // substract pure delta from the clip region (to reduce flicker) 
+    GpiCombineRegion( hps, hrgnClip, hrgnClip, hrgnDelta, CRGN_DIFF );
+    
+    // scroll the area
+    GpiSetClipRegion( hps, hrgnClip, NULL );
+    GpiBitBlt( hps, hps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE );
+    GpiSetClipRegion( hps, 0, NULL );
+    
+    // invalidate the delta region (clipped off when blitting)
+    WinInvalidateRegion( hwnd, hrgnDelta, clip == NULL );
+
+    // invalidate the region uncovered after scrolling
+    WinInvalidateRegion( hwnd, hrgnUpd, clip == NULL );
+    
+    GpiDestroyRegion( hps, hrgnDelta );
+    GpiDestroyRegion( hps, hrgnObst );
+    GpiDestroyRegion( hps, hrgnUpd );
+    GpiDestroyRegion( hps, hrgnClip );
+    WinReleasePS( hps );
+    
+    WinLockVisRegions( HWND_DESKTOP, FALSE );
+    
+    WinUpdateWindow( hwnd );
+}
+
+#endif
+
 void QWidget::scroll( int dx, int dy )
 {
     if ( testWState( WState_BlockUpdates ) && !children() )
 	return;
+
+#if defined (QT_PM_NO_WIDGETMASK)
 
     // move non-toplevel children
@@ -1628,4 +2391,10 @@
 
     qt_WinScrollWindowWell( winId(), dx, -dy, NULL );
+    
+#else
+
+    scrollWindow( winId(), width(), height(), dx, -dy, NULL );
+    
+#endif
 }
 
@@ -1635,8 +2404,20 @@
 	return;
 
+#if defined (QT_PM_NO_WIDGETMASK)
+    
     int h = crect.height();
     // flip y coordinate (all coordinates are inclusive)
     RECTL rcl = { r.left(), h - (r.bottom() + 1), r.right(), h - (r.top() + 1) };
     qt_WinScrollWindowWell( winId(), dx, -dy, &rcl );
+
+#else
+
+    int h = crect.height();
+    // flip y coordinate
+    RECTL rcl = { r.left(), h - (r.bottom() + 1),
+                  r.right() + 1, h - r.top() };
+    scrollWindow( winId(), width(), height(), dx, -dy, &rcl );
+    
+#endif
 }
 
@@ -1727,5 +2508,5 @@
 {
     return 0;
-//@@TODO (dmik): later
+/// @todo (dmik) later
 //    return ( extra && extra->dropTarget );
 }
@@ -1733,5 +2514,5 @@
 void QWidget::setAcceptDrops( bool on )
 {
-//@@TODO (dmik): later
+/// @todo (dmik) later
 //    // Enablement is defined by extra->dropTarget != 0.
 //
@@ -1752,42 +2533,133 @@
 }
 
+#if !defined (QT_PM_NO_WIDGETMASK)        
+
+// helper for QWidget::setMask()
+static void setClipRegion( HWND hwnd, int x, int y, int w, int h, HRGN hrgn,
+                           HWND parent )
+{
+    if ( !WinIsWindowVisible( hwnd ) ) {
+        // if the window is hidden, no need to invalidate anything
+        WinSetClipRegion( hwnd, hrgn );
+        return;
+    }
+
+    HPS hps = qt_display_ps();
+    const RECTL rcl = { 0, 0, w, h };
+    
+    // get the old bounds (clip region or rect)
+    HRGN hrgnOld = GpiCreateRegion( hps, 0, NULL );
+    qt_WinQueryClipRegionOrRect( hwnd, hrgnOld );
+    // set the new clip region
+    WinSetClipRegion( hwnd, hrgn );
+    
+    HRGN hrgnUpd;
+    if ( hrgn != 0 ) {
+        hrgnUpd = GpiCreateRegion( hps, 0, NULL );
+        // substract the new clip region from the old one
+        GpiCombineRegion( hps, hrgnUpd, hrgnOld, hrgn, CRGN_DIFF );
+        // move the result to the parent coordinate space
+        POINTL ptl = { x, y }; 
+        GpiOffsetRegion( hps, hrgnUpd, &ptl );
+        // invalidate areas in parent uncovered by the new clip region
+        qt_WinInvalidateRegionEx( parent, hrgnUpd,
+                                  WinQueryWindow( hwnd, QW_NEXT ), HWND_BOTTOM );
+    } else {
+        // the new region is being set to NULL, which means to widget bounds
+        // (no need to substract new from old, because it will produce RGN_NULL)
+        hrgnUpd = GpiCreateRegion( hps, 1, &rcl );
+        hrgn = hrgnUpd;
+    }
+    // substract the old clip region from the new one
+    GpiCombineRegion( hps, hrgnUpd, hrgn, hrgnOld, CRGN_DIFF );
+    // invalidate areas in hwnd uncovered by the new clip region
+    WinInvalidateRegion( hwnd, hrgnUpd, TRUE );
+    
+    GpiDestroyRegion( hps, hrgnUpd );
+    GpiDestroyRegion( hps, hrgnOld );
+}
+
+#endif
+
+/*!
+    \overload
+
+    Causes only the parts of the widget which overlap \a region to be
+    visible. If the region includes pixels outside the rect() of the
+    widget, window system controls in that area may or may not be
+    visible, depending on the platform.
+
+    Note that this effect can be slow if the region is particularly
+    complex.
+
+    Note that on OS/2, masks for top-level widgets are not currently
+    supported, so setting a mask on such a widget has no effect.
+    
+    \sa setMask(), clearMask()
+*/
+
 void QWidget::setMask( const QRegion &region )
 {
-    qWarning( "QWidget::setMask() is not yet implemented on OS/2" );
-//@@TODO (dmik): later (don't forget to offset region, see qregion_pm.cpp)
-//    // Since SetWindowRegion takes ownership, and we need to translate,
-//    // we take a copy.
-//    HRGN wr = CreateRectRgn(0,0,1,1);
-//    CombineRgn(wr, region.handle(), 0, RGN_COPY);
-//
-//    int fleft = 0, ftop = 0;
-//    if (isTopLevel()) {
-//	ftop = topData()->ftop;
-//	fleft = topData()->fleft;
-//    }
-//    OffsetRgn(wr, fleft, ftop );
-//    SetWindowRgn( winId(), wr, TRUE );
-}
+#if !defined (QT_PM_NO_WIDGETMASK)        
+    if (isTopLevel()) {
+#if defined (QT_CHECK_STATE)        
+        qWarning( "QWidget::setMask() for top-level widgets "
+                  "is not implemented on OS/2" );
+#endif        
+        return;
+    }
+    setClipRegion( winId(), x(), parentWidget()->height() - (y() + height()),
+                   width(), height(), region.handle( height() ),
+                   parentWidget()->winId() );
+#else
+    Q_UNUSED( region );
+#endif    
+}
+
+/*!
+    Causes only the pixels of the widget for which \a bitmap has a
+    corresponding 1 bit to be visible. If the region includes pixels
+    outside the rect() of the widget, window system controls in that
+    area may or may not be visible, depending on the platform.
+
+    Note that this effect can be slow if the region is particularly
+    complex.
+
+    Note that on OS/2, masks for top-level widgets are not currently
+    supported, so setting a mask on such a widget has no effect.
+    
+    See \c examples/tux for an example of masking for transparency.
+
+    \sa setMask(), clearMask()
+*/
 
 void QWidget::setMask( const QBitmap &bitmap )
 {
-    qWarning( "QWidget::setMask() is not yet implemented on OS/2" );
-//@@TODO (dmik): later
-//    HRGN wr = qt_win_bitmapToRegion(bitmap);
-//
-//    int fleft = 0, ftop = 0;
-//    if (isTopLevel()) {
-//	ftop = topData()->ftop;
-//	fleft = topData()->fleft;
-//    }
-//    OffsetRgn(wr, fleft, ftop );
-//    SetWindowRgn( winId(), wr, TRUE );
+#if !defined (QT_PM_NO_WIDGETMASK)
+    if (isTopLevel()) {
+#if defined (QT_CHECK_STATE)        
+        qWarning( "QWidget::setMask() for top-level widgets "
+                  "is not implemented on OS/2" );
+#endif        
+        return;
+    }
+    QRegion rgn = QRegion( bitmap );
+    setClipRegion( winId(), x(), parentWidget()->height() - (y() + height()),
+                   width(), height(), rgn.handle( height() ),
+                   parentWidget()->winId() );
+#else
+    Q_UNUSED( bitmap );
+#endif    
 }
 
 void QWidget::clearMask()
 {
-    qWarning( "QWidget::clearMask() is not yet implemented on OS/2" );
-//@@TODO (dmik): later
-//    SetWindowRgn( winId(), 0, TRUE );
+#if !defined (QT_PM_NO_WIDGETMASK)
+    if (isTopLevel())
+        return;
+    setClipRegion( winId(), x(), parentWidget()->height() - (y() + height()),
+                   width(), height(), 0,
+                   parentWidget()->winId() );
+#endif    
 }
 
@@ -1846,11 +2718,11 @@
 }
 
-/*
-  \internal
-  Returns the frame wihdow handle if this widget is a top-level widget and
-  has the standard WC_FRAME as its parent/owner (where it is FID_CLIENT).
-  If the widget does not have the standard frame or it is not top-level, this
-  function simply retuns the winId() value.
-*/
+/**
+ *  \internal  
+ *  Returns the frame wihdow handle if this widget is a top-level widget and
+ *  has the standard WC_FRAME as its parent/owner (where it is FID_CLIENT).
+ *  If the widget does not have the standard frame or it is not top-level, this
+ *  function simply retuns the winId() value.
+ */
 WId QWidget::winFId()
 {
@@ -1863,10 +2735,50 @@
 }
 
+#if !defined (QT_PM_NO_WIDGETMASK)
+
+/*!
+ *  \internal
+ *
+ *  Validates areas of this widget covered by (intersected with) its children
+ *  and sibling widgets.
+ *
+ *  Clip regions of all relative widgets (set by WinSetClipRegion()) are taken
+ *  into account.
+ */
+void QWidget::validateObstacles()
+{
+    RECTL updateRcl;
+    if ( WinQueryUpdateRect( winId(), &updateRcl ) ) {
+        // the update rectangle may be empty
+        if ( updateRcl.xLeft != updateRcl.xRight &&
+             updateRcl.yBottom != updateRcl.yTop ) {
+            qt_WinProcessWindowObstacles( winId(), &updateRcl, 0, 0 );
+        }
+    }
+}
+
+/*!
+ *  \internal
+ *
+ *  Combines areas of this widget covered by (intersected with) its children
+ *  and sibling widgets to a region \a hrgn using an operation \a op
+ *  (see GpiCombineRegion()). Returns the complexity of the combined region.
+ *
+ *  Clip regions of all relative widgets (set by WinSetClipRegion()) are taken
+ *  into account.
+ */
+/// @todo (dmik) is it really necessary somewhere?
+LONG QWidget::combineObstacles( HRGN hrgn, LONG op )
+{
+    return qt_WinProcessWindowObstacles( winId(), NULL, hrgn, op );
+}
+
+#endif // !defined (QT_PM_NO_WIDGETMASK)
+
 /*!
  *  \internal
  *
  *  Obtains a presentaiton space to draw on this widget, set up according
- *  to widget flags. If \a m != Unclipped and WPaintUnclipped flag is not
- *  set, a clip region is set on the returned PS according to \a m.
+ *  mode \a m and to widget flags.
  *
  *  The returned handle must be freed using WinReleasePS() after usage.
@@ -1878,8 +2790,10 @@
     if ( isDesktop() ) {
         widgetPS = WinGetScreenPS( HWND_DESKTOP );
+        return widgetPS;
     } else {
         if ( m == Unclipped || (m == ClipDefault &&
                                 testWFlags( WPaintUnclipped )) ) {
             widgetPS = WinGetClipPS( winId(), 0, PSF_PARENTCLIP );
+            return widgetPS;
         } else {
             widgetPS = WinGetPS( winId() );
@@ -1887,4 +2801,15 @@
     }
 
+#if !defined (QT_PM_NO_WIDGETMASK)
+    RECTL rcl = { 0, 0, crect.width(), crect.height() };
+    HRGN hrgn = GpiCreateRegion( widgetPS, 1, &rcl );
+    qt_WinProcessWindowObstacles( winId(), NULL, hrgn, CRGN_DIFF );
+    HRGN hrgnOld = 0;
+    GpiSetClipRegion( widgetPS, hrgn, &hrgnOld );
+    Q_ASSERT( !hrgnOld );
+    if ( hrgnOld )
+        GpiDestroyRegion( widgetPS, hrgnOld );
+#endif    
+    
     return widgetPS;
 }
