Changeset 64 for trunk


Ignore:
Timestamp:
Mar 12, 2006, 2:26:37 PM (19 years ago)
Author:
dmik
Message:

Implemented QWidget::setMask() functionality.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/qwidget.h

    r63 r64  
    599599    friend class QDragManager;
    600600#elif defined (Q_WS_PM)
    601     enum ClipMode { ClipDefault, Unclipped, ClipAll, ClipSiblings };
     601#if !defined (QT_PM_NO_WIDGETMASK)
     602    void validateObstacles();
     603    LONG combineObstacles( HRGN hrgn, LONG op );
     604#endif   
     605    enum ClipMode { ClipDefault, Unclipped, ClipAll };
    602606    HPS getTargetPS( ClipMode m = ClipDefault );   
    603607    friend Q_EXPORT void bitBlt( QPaintDevice *, int, int,
  • trunk/src/kernel/qapplication_pm.cpp

    r61 r64  
    958958//@@TODO (dmik): are they all available in Warp3?
    959959enum {
    960     // sent to hwnd that has been entered by mouse.
     960    // sent to hwnd that has been entered to by a mouse pointer.
    961961    // FID_CLIENT also receives enter messages of its WC_FRAME.
    962962    // mp1 = hwnd that is entered, mp2 = hwnd that is left
    963963    WM_U_MOUSEENTER = 0x41E,
    964     // sent to hwnd that has been left by mouse.
     964    // sent to hwnd that has been left by a mouse pointer.
    965965    // FID_CLIENT also receives leave messages of its WC_FRAME.
    966966    // mp1 = hwnd that is left, mp2 = hwnd that is entered
     
    14371437            break;
    14381438        case WM_ERASEBACKGROUND:                // erase window background
     1439#if defined (QT_PM_NO_WIDGETMASK)
    14391440            // flush WM_PAINT messages here to update window contents
    14401441            // instantly while tracking the resize frame (normally these
     
    14471448            // clients only, so we would have to do all calculations ourselves).
    14481449            WinUpdateWindow( widget->winId() );
     1450#else
     1451            // We flush WM_PAINT messages in QETWidget::translateConfigEvent().
     1452#endif
    14491453            RETURN( FALSE );
    14501454            break;
     
    17291733                    QPoint cpos = QCursor::pos();
    17301734                    dispatch = !geom.contains( cpos );
    1731 //@@TODO (dmik): later, window regions (WinQueryClipRegion())
    1732 //                  if ( !dispatch ) {
    1733 //                      HRGN hrgn = CreateRectRgn(0,0,0,0);
    1734 //                      if ( GetWindowRgn( curWin, hrgn ) != ERROR ) {
    1735 //                          QPoint lcpos = widget->mapFromGlobal( cpos );
    1736 //                          dispatch = !PtInRegion( hrgn, lcpos.x(), lcpos.y() );
    1737 //                      }
    1738 //                      DeleteObject(hrgn);
    1739 //                  }
    17401735                }
    17411736                if ( dispatch ) {
     
    32113206bool QETWidget::translatePaintEvent( const QMSG & )
    32123207{
    3213     HRGN hrgn;
    3214     hrgn = GpiCreateRegion( qt_display_ps(), 0, NULL );
     3208    HPS displayPS = qt_display_ps();
     3209   
     3210#if !defined (QT_PM_NO_WIDGETMASK)
     3211    // Since we don't use WS_CLIPSIBLINGS and WS_CLIPCHILDREN bits (see
     3212    // qwidget_pm.cpp), we have to validate areas that intersect with our
     3213    // children and siblings, taking their clip regions into account.
     3214    validateObstacles();
     3215#endif
     3216   
     3217    HRGN hrgn = GpiCreateRegion( displayPS, 0, NULL );
    32153218    LONG rc = WinQueryUpdateRegion( winId(), hrgn );
    3216     if ( rc == RGN_ERROR || rc == RGN_NULL ) {
    3217         GpiDestroyRegion( qt_display_ps(), hrgn );
     3219    if ( rc == RGN_ERROR ) {
     3220        GpiDestroyRegion( displayPS, hrgn );
    32183221        hps = 0;
    32193222        clearWState( WState_InPaintEvent );
     
    32323235    if ( !rcl.xRight || !rcl.yTop ) {
    32333236        WinEndPaint( hps );
    3234         GpiDestroyRegion( qt_display_ps(), hrgn );
     3237        GpiDestroyRegion( displayPS, hrgn );
    32353238        hps = 0;
    32363239        clearWState( WState_InPaintEvent );
     
    32383241    }
    32393242
     3243#if !defined (QT_PM_NO_WIDGETMASK)
     3244    if ( WinQueryClipRegion( winId(), 0 ) != QCRGN_NO_CLIP_REGION ) {
     3245        // Correct the update region by intersecting it with the clip
     3246        // region (PM doesn't do that itself). It is necessary
     3247        // to have a correct QRegion in QPaintEvent.
     3248        HRGN hcrgn = GpiCreateRegion( displayPS, 0, NULL );
     3249        WinQueryClipRegion( winId(), hcrgn );
     3250        GpiCombineRegion( displayPS, hrgn, hrgn, hcrgn, CRGN_AND );
     3251        GpiDestroyRegion( displayPS, hcrgn );
     3252    }
     3253#endif
     3254   
    32403255    // flip y coordinate
    32413256    rcl.yBottom = height() - (rcl.yBottom + rcl.yTop);
     
    32913306        // that sends WM_SIZE).
    32923307        QSize newSize( SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2) );
    3293         if ( qmsg.msg == WM_SIZE && size() != newSize )
     3308        if ( qmsg.msg == WM_SIZE && size() != newSize ) {
    32943309            if ( !(fStyle & WS_MINIMIZED) )
    32953310                crect.setSize( newSize );
     3311        }
    32963312        return TRUE;
    32973313    }
     
    33183334        }
    33193335        if ( !(fStyle & WS_MINIMIZED) && oldSize != newSize) {
     3336#if !defined (QT_PM_NO_WIDGETMASK)
     3337            // Spontaneous (external to Qt) WM_SIZE messages should occur only
     3338            // on top-level widgets. If we get them for a non top-level widget,
     3339            // the result will most likely be incorrect because widget masks will
     3340            // not be properly processed (i.e. in the way it is done in
     3341            // QWidget::internalSetGeometry() when the geometry is changed from
     3342            // within Qt). So far, I see no need to support this (who will ever
     3343            // need to move a non top-level window of a foreign process?).
     3344            Q_ASSERT( isTopLevel() );
     3345#endif   
    33203346            if ( isVisible() ) {
    33213347                QResizeEvent e( newSize, oldSize );
     
    33233349                if ( !testWFlags( WStaticContents ) )
    33243350                    repaint( !testWFlags(WResizeNoErase) );
     3351#if !defined (QT_PM_NO_WIDGETMASK)
     3352                // Flush WM_PAINT messages here to update window contents
     3353                // instantly while tracking the resize frame (normally these
     3354                // messages are delivered after resizing is stopped for some
     3355                // time). It makes resizing a bit slower but gives a better look
     3356                // (no invalid window contents can be seen during resize).
     3357                // The alternative could be to erase the background only
     3358                // (similarly to Win32), but we need to do it for every
     3359                // non-toplevel window, which can be also time-consuming
     3360                WinUpdateWindow( winId() );
     3361#endif
    33253362            } else {
    33263363                QResizeEvent *e = new QResizeEvent( newSize, oldSize );
  • trunk/src/kernel/qwidget_pm.cpp

    r63 r64  
    5151#include "qcursor.h"
    5252#include <private/qapplication_p.h>
    53 //@@TODO (dmik): remove?
     53/// @todo (dmik) remove?
    5454//#include <private/qinputcontext_p.h>
    5555
    5656const QString qt_reg_winclass( int );           // defined in qapplication_pm.cpp
    57 //@@TODO (dmik): later?
     57/// @todo (dmik) later?
    5858//void      qt_olednd_unregister( QWidget* widget, QOleDropTarget *dst ); // dnd_win
    5959//QOleDropTarget* qt_olednd_register( QWidget* widget );
     
    6161
    6262extern bool qt_nograb();
    63 //@@TODO (dmik): later (qregion_pm.cpp)
    64 //extern HRGN qt_win_bitmapToRegion(const QBitmap& bitmap);
    6563
    6664// defined in qapplication_pm.cpp
     
    8482    return QtOldSysMenuProc( hwnd, msg, mp1, mp2 );
    8583}
     84
     85#if !defined (QT_PM_NO_WIDGETMASK)
     86
     87//#define DEBUG_WIDGETMASK
     88
     89/**
     90 *  \internal
     91 *  Extended version of WinQueryClipRegion(). If the given window has a
     92 *  clip region, the given region will receive a copy of the clip region
     93 *  clipped to the current window rectangle. If there is no clip region,
     94 *  the given region will contain only the window rectangle on return.
     95 */
     96static void qt_WinQueryClipRegionOrRect( HWND hwnd, HRGN hrgn )
     97{
     98    RECTL rcl;
     99    WinQueryWindowRect( hwnd, &rcl );
     100
     101    HPS hps = qt_display_ps();
     102    GpiSetRegion( hps, hrgn, 1, &rcl );
     103    if ( WinQueryClipRegion( hwnd, 0 ) != QCRGN_NO_CLIP_REGION ) {
     104        HRGN hrgnTemp = GpiCreateRegion( hps, 0, NULL );
     105        WinQueryClipRegion( hwnd, hrgnTemp );
     106        GpiCombineRegion( hps, hrgn, hrgnTemp, hrgn, CRGN_AND );
     107        GpiDestroyRegion( hps, hrgnTemp );
     108    }   
     109}
     110
     111enum {
     112    PWO_Children = 0x01,
     113    PWO_Sibings = 0x02,
     114    PWO_Ancestors = 0x04,
     115    PWO_All = PWO_Children | PWO_Sibings | PWO_Ancestors,
     116};
     117
     118/**
     119 *  \internal
     120 *  Extended version of WinInvalidateRegion(): invalidates the specified region
     121 *  of the given window and regions of children from \a hwndFrom to \a hwndTo
     122 *  if they intersect with the invalid region. If either of child window
     123 *  handles is NULLHANDLE, children are not invalidated at all. Also, HWND_TOP
     124 *  can be used as \a hwndFrom, HWND_BOTTOM \a can be used as \a hwndTo.
     125 */
     126static BOOL qt_WinInvalidateRegionEx( HWND hwnd, HRGN hrgn,
     127                                      HWND hwndFrom, HWND hwndTo )
     128{
     129#if defined (DEBUG_WIDGETMASK)
     130    QWidget *w = QWidget::find( hwnd );
     131    qDebug( "qt_WinInvalidateRegionEx: hwnd=%08lX (%s/%s) "
     132            "hwndFrom=%08lX hwndTo=%08lX",
     133            hwnd, w ? w->name() : 0, w ? w->className() : 0, hwndFrom, hwndTo );
     134#endif
     135   
     136    if ( hwndFrom == HWND_TOP )
     137        hwndFrom = WinQueryWindow( hwnd, QW_TOP );
     138    if ( hwndTo == HWND_BOTTOM )
     139        hwndTo = WinQueryWindow( hwnd, QW_BOTTOM );
     140
     141    if ( hwndFrom == 0 || hwndTo == 0 )
     142        return WinInvalidateRegion( hwnd, hrgn, FALSE );
     143   
     144    if ( WinQueryWindow( hwndFrom, QW_PARENT ) != hwnd ||
     145         WinQueryWindow( hwndTo, QW_PARENT ) != hwnd )
     146        return FALSE;
     147   
     148    HPS hps = qt_display_ps();
     149   
     150    SWP swp;
     151    HWND child = hwndFrom;
     152    HRGN hrgnChild = GpiCreateRegion( hps, 0, NULL );
     153    HRGN hrgnInv = GpiCreateRegion( hps, 0, NULL );
     154    GpiCombineRegion( hps, hrgnInv, hrgn, 0, CRGN_COPY );
     155   
     156    LONG cmplx = RGN_RECT;
     157   
     158    while ( child ) {
     159        WinQueryWindowPos( child, &swp );
     160#if defined (DEBUG_WIDGETMASK)
     161        w = QWidget::find( child );
     162        qDebug( " child=%08lX [fl=%08lX] (%s/%s)", child, swp.fl,
     163                w ? w->name() : 0, w ? w->className() : 0 );
     164#endif
     165        // proceed only if not hidden
     166        if ( swp.fl & SWP_SHOW ) {
     167            // get sibling's bounds (clip region or rect)
     168            qt_WinQueryClipRegionOrRect( child, hrgnChild );
     169            // translate the region to the parent's coordinate system
     170            POINTL ptl = { swp.x, swp.y };
     171            GpiOffsetRegion( hps, hrgnChild, &ptl );
     172            // intersect the child's region with the invalid one
     173            // and invalidate if not NULL
     174            cmplx = GpiCombineRegion( hps, hrgnChild, hrgnChild, hrgnInv,
     175                                      CRGN_AND );
     176            if ( cmplx != RGN_NULL ) {
     177                POINTL ptl2 = { -swp.x, -swp.y };
     178                GpiOffsetRegion( hps, hrgnChild, &ptl2 );
     179                WinInvalidateRegion( child, hrgnChild, TRUE );
     180                GpiOffsetRegion( hps, hrgnChild, &ptl );
     181                // substract the invalidated area from the widget's region
     182                // (no need to invalidate it any more)
     183                cmplx = GpiCombineRegion( hps, hrgnInv, hrgnInv, hrgnChild,
     184                                          CRGN_DIFF );
     185#if defined (DEBUG_WIDGETMASK)
     186                qDebug( "  processed" );
     187#endif
     188                // finish if nothing left
     189                if ( cmplx == RGN_NULL )
     190                    break;
     191            }
     192        }
     193        // iterate to the next window (below)
     194        if ( child == hwndTo )
     195            break;
     196        child = WinQueryWindow( child, QW_NEXT );
     197    }
     198   
     199    BOOL ok = (cmplx == RGN_NULL) || (child == hwndTo);
     200   
     201    if ( ok ) {
     202        // invalidate what's left invalid after substracting children
     203        WinInvalidateRegion( hwnd, hrgnInv, FALSE );
     204    }
     205   
     206    GpiDestroyRegion( hps, hrgnInv );
     207    GpiDestroyRegion( hps, hrgnChild );
     208   
     209    return ok;
     210}
     211
     212/**
     213 *  \internal
     214 *  Helper function to collect all relative windows intersecting with the
     215 *  given window and placed above it in z-order.
     216 *
     217 *  \param hwnd  window in question
     218 *  \param prcl  rectangle (in window coordinates) to limit processing to
     219 *               (if null, the whole window rectange is used)
     220 *  \param hrgn  region where to combine all obstacles
     221 *               (if 0, obstacles are directly validated instead of collecting)
     222 *  \param op    region operation perfomed when combining obstacles (CRGN_*)
     223 *  \param flags flags defining the scope (PWO_* ORed together)
     224 *
     225 *  \return complexity of the combined region (only when \a hrgn is not 0)
     226 */
     227static LONG qt_WinProcessWindowObstacles( HWND hwnd, PRECTL prcl, HRGN hrgn,
     228                                          LONG op, LONG flags = PWO_All )
     229{
     230    Q_ASSERT( hwnd );
     231
     232    HPS displayPS = qt_display_ps();
     233   
     234#if defined (DEBUG_WIDGETMASK)
     235    QWidget *w = QWidget::find( hwnd );
     236    qDebug( "qt_WinProcessWindowObstacles: hwnd=%08lX (%s/%s), prcl=%p "
     237            "hrgn=%08lX, op=%ld flags=%08lX",
     238            hwnd, w->name(), w->className(), prcl, hrgn, op, flags );
     239#endif
     240 
     241    SWP swpSelf;
     242    WinQueryWindowPos( hwnd, &swpSelf );
     243   
     244    RECTL rclSelf = { 0, 0, swpSelf.cx, swpSelf.cy };
     245    if ( prcl )
     246        rclSelf = *prcl;
     247
     248    HRGN whrgn = GpiCreateRegion( displayPS, 0, NULL );
     249
     250    LONG cmplx = RGN_NULL;
     251    HWND relative;
     252    SWP swp;
     253   
     254    // first, go through all children (in z-order)
     255    if ( flags & PWO_Children ) {
     256        relative = WinQueryWindow( hwnd, QW_BOTTOM );
     257        if ( relative != NULLHANDLE ) {
     258            for ( ; relative != HWND_TOP; relative = swp.hwndInsertBehind ) {
     259                WinQueryWindowPos( relative, &swp );
     260#if defined (DEBUG_WIDGETMASK)
     261                w = QWidget::find( relative );
     262                qDebug( " child=%08lX [fl=%08lX] (%s/%s)", relative, swp.fl,
     263                        w ? w->name() : 0, w ? w->className() : 0 );
     264#endif
     265                // skip if hidden
     266                if ( !(swp.fl & SWP_SHOW) )
     267                    continue;
     268                // rough check for intersection
     269                if ( swp.x >= rclSelf.xRight || swp.y >= rclSelf.yTop ||
     270                     swp.x + swp.cx <= rclSelf.xLeft ||
     271                     swp.y + swp.cy <= rclSelf.yBottom )
     272                    continue;
     273                // get the bounds (clip region or rect)
     274                qt_WinQueryClipRegionOrRect( relative, whrgn );
     275                // translate the region to this window's coordinate system
     276                POINTL ptl = { swp.x, swp.y };
     277                GpiOffsetRegion( displayPS, whrgn, &ptl );
     278                // process the region
     279                if ( hrgn != NULLHANDLE ) {
     280                    cmplx = GpiCombineRegion( displayPS, hrgn, hrgn, whrgn, op );
     281                } else {
     282                    WinValidateRegion( hwnd, whrgn, FALSE );
     283                }
     284#if defined (DEBUG_WIDGETMASK)
     285                qDebug( "  extracted" );
     286#endif
     287            }
     288        }
     289    }
     290
     291    HWND desktop = WinQueryDesktopWindow( 0, 0 );
     292    HWND parent = WinQueryWindow( hwnd, QW_PARENT );
     293   
     294    // next, go through all siblings placed above (in z-order),
     295    // but only if they are not top-level windows (that cannot be
     296    // non-rectangular and thus are always correctly clipped by the system)
     297    if ( (flags & PWO_Sibings) && parent != desktop ) {
     298        for ( relative = swpSelf.hwndInsertBehind;
     299              relative != HWND_TOP; relative = swp.hwndInsertBehind ) {
     300            WinQueryWindowPos( relative, &swp );
     301#if defined (DEBUG_WIDGETMASK)
     302            w = QWidget::find( relative );
     303            qDebug( " sibling=%08lX [fl=%08lX] (%s/%s)", relative, swp.fl,
     304                    w ? w->name() : 0, w ? w->className() : 0 );
     305#endif
     306            // skip if hidden
     307            if ( !(swp.fl & SWP_SHOW) )
     308                continue;
     309            // rough check for intersection
     310            if ( swp.x >= swpSelf.x + rclSelf.xRight ||
     311                 swp.y >= swpSelf.y + rclSelf.yTop ||
     312                 swp.x + swp.cx <= swpSelf.x + rclSelf.xLeft ||
     313                 swp.y + swp.cy <= swpSelf.y + rclSelf.yBottom )
     314                continue;
     315            // get the bounds (clip region or rect)
     316            qt_WinQueryClipRegionOrRect( relative, whrgn );
     317            // translate the region to this window's coordinate system
     318            POINTL ptl = { swp.x - swpSelf.x, swp.y - swpSelf.y };
     319            GpiOffsetRegion( displayPS, whrgn, &ptl );
     320            // process the region
     321            if ( hrgn != NULLHANDLE ) {
     322                cmplx = GpiCombineRegion( displayPS, hrgn, hrgn, whrgn, op );
     323            } else {
     324                WinValidateRegion( hwnd, whrgn, FALSE );
     325            }
     326#if defined (DEBUG_WIDGETMASK)
     327            qDebug( "  extracted" );
     328#endif
     329        }
     330    }
     331   
     332    // last, go through all siblings of our parent and its ancestors
     333    // placed above (in z-order)
     334    if ( flags & PWO_Ancestors ) {
     335        POINTL delta = { swpSelf.x, swpSelf.y };
     336        while ( parent != desktop ) {
     337            HWND grandParent = WinQueryWindow( parent, QW_PARENT );
     338            // no need to clip top-level windows (that cannot be non-rectangular
     339            // and thus are always correctly clipped by the system)
     340            if ( grandParent == desktop )
     341                break;
     342           
     343            WinQueryWindowPos( parent, &swp );
     344#if defined (DEBUG_WIDGETMASK)
     345            w = QWidget::find( parent );
     346            qDebug( " parent=%08lX [fl=%08lX] (%s/%s)", parent, swp.fl,
     347                    w ? w->name() : 0, w ? w->className() : 0 );
     348#endif
     349            delta.x += swp.x;
     350            delta.y += swp.y;
     351            for ( relative = swp.hwndInsertBehind;
     352                  relative != HWND_TOP; relative = swp.hwndInsertBehind ) {
     353                WinQueryWindowPos( relative, &swp );
     354#if defined (DEBUG_WIDGETMASK)
     355                w = QWidget::find( relative );
     356                qDebug( " ancestor=%08lX [fl=%08lX] (%s/%s)", relative, swp.fl,
     357                        w ? w->name() : 0, w ? w->className() : 0 );
     358#endif
     359                // skip if hidden
     360                if ( !(swp.fl & SWP_SHOW) )
     361                    continue;
     362                // rough check for intersection
     363                if ( swp.x - delta.x >= rclSelf.xRight ||
     364                     swp.y - delta.y >= rclSelf.yTop ||
     365                     swp.x - delta.x + swp.cx <= rclSelf.xLeft ||
     366                     swp.y - delta.y + swp.cy <= rclSelf.yBottom )
     367                    continue;
     368                // get the bounds (clip region or rect)
     369                qt_WinQueryClipRegionOrRect( relative, whrgn );
     370                // translate the region to this window's coordinate system
     371                POINTL ptl = { swp.x - delta.x, swp.y - delta.y };
     372                GpiOffsetRegion( displayPS, whrgn, &ptl );
     373                // process the region
     374                if ( hrgn != NULLHANDLE ) {
     375                    cmplx = GpiCombineRegion( displayPS, hrgn, hrgn, whrgn, op );
     376                } else {
     377                    WinValidateRegion( hwnd, whrgn, FALSE );
     378                }
     379#if defined (DEBUG_WIDGETMASK)
     380                qDebug( "  extracted" );
     381#endif
     382            }
     383            parent = grandParent;
     384        }
     385    }
     386
     387    GpiDestroyRegion( displayPS, whrgn );
     388   
     389    return cmplx;
     390}
     391
     392/**
     393 *  \internal
     394 *  Partial reimplementation of the WinSetWindowPos() API that obeys window clip
     395 *  regions. Currently supported flags are SWP_ZORDER, SWP_SHOW and SWP_HIDE.
     396 *  Other flags should not be used. Note that if any other flag is specified
     397 *  (alone or in addition to the supported ones), or if the given window is a
     398 *  top-level window, this function acts exactly like the original
     399 *  WinSetWindowPos() function.
     400 */
     401static BOOL qt_WinSetWindowPos( HWND hwnd, HWND hwndInsertBehind,
     402                                LONG x, LONG y, LONG cx, LONG cy,
     403                                ULONG fl )
     404{
     405#if defined (DEBUG_WIDGETMASK)
     406    QWidget *w = QWidget::find( hwnd );
     407    qDebug( "qt_WinSetWindowPos: hwnd=%08lX (%s/%s) fl=%08lX",
     408            hwnd, w ? w->name() : 0, w ? w->className() : 0, fl );
     409#endif
     410
     411    Q_ASSERT( (fl & ~(SWP_ZORDER | SWP_SHOW | SWP_HIDE)) == 0 );
     412   
     413    HWND desktop = WinQueryDesktopWindow( 0, 0 );
     414    if ( (fl & ~(SWP_ZORDER | SWP_SHOW | SWP_HIDE)) != 0 ||
     415         hwnd == desktop || WinQueryWindow( hwnd, QW_PARENT ) == desktop ) {
     416        return WinSetWindowPos( hwnd, hwndInsertBehind, x, y, cx, cy, fl );
     417    }
     418   
     419    SWP swpOld;
     420    WinQueryWindowPos( hwnd, &swpOld );
     421
     422    // do some checks
     423    if ( (fl & SWP_ZORDER) && swpOld.hwndInsertBehind == hwndInsertBehind )
     424        fl &= ~SWP_ZORDER;
     425    if ( (fl & SWP_SHOW) && (swpOld.fl & SWP_SHOW) )
     426        fl &= ~SWP_SHOW;
     427    if ( (fl & SWP_HIDE) && (swpOld.fl & SWP_HIDE) )
     428        fl &= ~SWP_HIDE;
     429    if ( (fl & (SWP_SHOW | SWP_HIDE)) == (SWP_SHOW | SWP_HIDE) )
     430        fl &= ~SWP_HIDE;
     431   
     432    BOOL rc = WinSetWindowPos( hwnd, hwndInsertBehind, x, y, cx, cy,
     433                               fl | SWP_NOREDRAW );
     434    if ( rc == FALSE || (fl & SWP_NOREDRAW) )
     435        return rc;
     436
     437    SWP swpNew;
     438    WinQueryWindowPos( hwnd, &swpNew );
     439   
     440    if ( swpOld.hwndInsertBehind == swpNew.hwndInsertBehind )
     441        fl &= ~SWP_ZORDER;
     442   
     443    if ( (fl & (SWP_ZORDER | SWP_SHOW | SWP_HIDE)) == 0 )
     444        return rc;
     445
     446    HPS hps = qt_display_ps();
     447    HWND hwndParent = WinQueryWindow( hwnd, QW_PARENT );
     448   
     449    // get window bounds
     450    HRGN hrgnSelf = GpiCreateRegion( hps, 0, NULL );
     451    qt_WinQueryClipRegionOrRect( hwnd, hrgnSelf );
     452   
     453    if ( fl & SWP_SHOW ) {
     454        WinInvalidateRegion( hwnd, hrgnSelf, TRUE );
     455    } else if ( fl & SWP_HIDE ) {
     456        // translate the region to the parent coordinate system
     457        POINTL ptl = { swpNew.x, swpNew.y };
     458        GpiOffsetRegion( hps, hrgnSelf, &ptl );
     459        // invalidate the parent and children below this window
     460        qt_WinInvalidateRegionEx( hwndParent, hrgnSelf,
     461                                  WinQueryWindow( hwnd, QW_NEXT ), HWND_BOTTOM );
     462    } else { // fl & SWP_ZORDER
     463        // below we assume that WinSetWindowPos() returns FALSE if
     464        // an incorrect (unrelated) hwndInsertBehind is passed when SWP_ZORDER
     465        // is set
     466       
     467        // first, detect whether we are moving up or down
     468        BOOL up;
     469        HWND hwndFrom, hwndTo;
     470        if ( swpOld.hwndInsertBehind == HWND_TOP ) {
     471            up = FALSE;
     472            hwndFrom = WinQueryWindow( hwndParent, QW_TOP );
     473            hwndTo = swpNew.hwndInsertBehind;
     474        } else {
     475            up = TRUE;
     476            for ( HWND hwndAbove = hwnd;
     477                  (hwndAbove = WinQueryWindow( hwndAbove, QW_PREV )) != 0; ) {
     478                if ( hwndAbove == swpOld.hwndInsertBehind ) {
     479                    up = FALSE;
     480                    break;
     481                }
     482            }
     483            if ( up ) {
     484                hwndFrom = swpOld.hwndInsertBehind;
     485                hwndTo = WinQueryWindow( hwnd, QW_NEXT );
     486            } else {
     487                hwndFrom = WinQueryWindow( swpOld.hwndInsertBehind, QW_NEXT );
     488                hwndTo = swpNew.hwndInsertBehind;
     489            }
     490        }
     491#if defined (DEBUG_WIDGETMASK)
     492        qDebug( " moving up? %ld", up );
     493        w = QWidget::find( hwndFrom );
     494        qDebug( " hwndFrom=%08lX (%s/%s)", hwndFrom,
     495                    w ? w->name() : 0, w ? w->className() : 0 );
     496        w = QWidget::find( hwndTo );
     497        qDebug( " hwndTo=%08lX (%s/%s)", hwndTo,
     498                    w ? w->name() : 0, w ? w->className() : 0 );
     499#endif
     500
     501        SWP swp;
     502        HWND sibling = hwndFrom;
     503        HRGN hrgn = GpiCreateRegion( hps, 0, NULL );
     504        HRGN hrgnUpd = GpiCreateRegion( hps, 0, NULL );
     505       
     506        if ( up ) {
     507            // go upwards in z-order
     508            while ( 1 ) {
     509                WinQueryWindowPos( sibling, &swp );
     510#if defined (DEBUG_WIDGETMASK)
     511                w = QWidget::find( sibling );
     512                qDebug( " sibling=%08lX [fl=%08lX] (%s/%s)", sibling, swp.fl,
     513                        w ? w->name() : 0, w ? w->className() : 0 );
     514#endif
     515                // proceed only if not hidden
     516                if ( swp.fl & SWP_SHOW ) {
     517                    // get sibling's bounds (clip region or rect)
     518                    qt_WinQueryClipRegionOrRect( sibling, hrgn );
     519                    // translate the region to this window's coordinate system
     520                    POINTL ptl = { swp.x - swpNew.x, swp.y - swpNew.y };
     521                    GpiOffsetRegion( hps, hrgn, &ptl );
     522                    // add to the region of siblings we're moving on top of
     523                    GpiCombineRegion( hps, hrgnUpd, hrgnUpd, hrgn, CRGN_OR );
     524#if defined (DEBUG_WIDGETMASK)
     525                    qDebug( "  processed" );
     526#endif
     527                }
     528                // iterate to the prev window (above)
     529                if ( sibling == hwndTo )
     530                    break;
     531                sibling = swp.hwndInsertBehind;
     532            }
     533            // intersect the resulting region with the widget region and
     534            // invalidate
     535            GpiCombineRegion( hps, hrgnUpd, hrgnSelf, hrgnUpd, CRGN_AND );
     536            WinInvalidateRegion( hwnd, hrgnUpd, TRUE );
     537        } else {
     538            // go downwards in reverse z-order
     539            POINTL ptl = { 0, 0 };
     540            while ( 1 ) {
     541                WinQueryWindowPos( sibling, &swp );
     542#if defined (DEBUG_WIDGETMASK)
     543                w = QWidget::find( sibling );
     544                qDebug( " sibling=%08lX [fl=%08lX] (%s/%s)", sibling, swp.fl,
     545                        w ? w->name() : 0, w ? w->className() : 0 );
     546#endif
     547                // proceed only if not hidden
     548                if ( swp.fl & SWP_SHOW ) {
     549                    // get sibling's bounds (clip region or rect)
     550                    qt_WinQueryClipRegionOrRect( sibling, hrgn );
     551                    // undo the previous translation and translate this window's
     552                    // region to the siblings's coordinate system
     553                    ptl.x += swpNew.x - swp.x;
     554                    ptl.y += swpNew.y - swp.y;
     555                    GpiOffsetRegion( hps, hrgnSelf, &ptl );
     556                    // intersect the sibling's region with the translated one
     557                    // and invalidate the sibling
     558                    GpiCombineRegion( hps, hrgnUpd, hrgnSelf, hrgn, CRGN_AND );
     559                    WinInvalidateRegion( sibling, hrgnUpd, TRUE );
     560                    // substract the invalidated area from the widget's region
     561                    // (no need to invalidate it any more)
     562                    GpiCombineRegion( hps, hrgnSelf, hrgnSelf, hrgnUpd, CRGN_DIFF );
     563                    // prepare the translation from the sibling's
     564                    // coordinates back to this window's coordinates
     565                    ptl.x = swp.x - swpNew.x;
     566                    ptl.y = swp.y - swpNew.y;
     567#if defined (DEBUG_WIDGETMASK)
     568                    qDebug( "  processed" );
     569#endif
     570                }
     571                // iterate to the next window (below)
     572                if ( sibling == hwndTo )
     573                    break;
     574                sibling = WinQueryWindow( sibling, QW_NEXT );
     575            }
     576        }
     577
     578        GpiDestroyRegion( hps, hrgnUpd );
     579        GpiDestroyRegion( hps, hrgn );
     580    }
     581   
     582    GpiDestroyRegion( hps, hrgnSelf );
     583   
     584    return TRUE;
     585}
     586
     587#endif
    86588
    87589static void removeSysMenuAccels( HWND frame )
     
    216718    }
    217719    if ( !desktop ) {
     720#if !defined (QT_PM_NO_WIDGETMASK)
     721        // We don't use WS_CLIPSIBLINGS and WS_CLIPCHILDREN, because when these
     722        // styles are set and a child/sibling window has a non-NULL clip region,
     723        // PM still continues to exclude the entire child's rectangle from the
     724        // parent window's update region, ignoring its clip region. As a result,
     725        // areas outside the clip region are left unpainted. Instead, we correct
     726        // the update region of the window ourselves, on every WM_PAINT event.
     727#else
    218728        /// @todo (dmik)
    219729        //  this is temporarily commented out because QSplitter sets
     
    223733        /* if ( !testWFlags( WPaintUnclipped ) ) */
    224734            style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
     735#endif           
    225736        // for all top-level windows except popups we create a WC_FRAME
    226737        // as a parent and owner.
     
    325836            );
    326837#endif
     838            // note that we place the client on top (HWND_TOP) to exclude other
     839            // frame controls from being analysed in qt_WinProcessWindowObstacles
    327840            id = WinCreateWindow(
    328841                    fId, pszClassName, title, style, 0, 0, 0, 0,
    329                     fId, HWND_BOTTOM, FID_CLIENT, NULL, NULL
     842                    fId, HWND_TOP, FID_CLIENT, NULL, NULL
    330843            );
    331844        } else {
     
    9051418        RECTL rcl = { x, y, x + w, y + h };
    9061419
     1420#if !defined (QT_PM_NO_WIDGETMASK)
     1421        WinInvalidateRect( winId(), &rcl, FALSE );
     1422#else
    9071423        // WinInvalidateRect() has such a "feature" that children are not
    9081424        // actually extracted from the window's update region when it has
     
    9311447                    w = (QWidget*)object;
    9321448                    if ( !w->isTopLevel() && w->isShown() ) {
    933 //@@TODO (dmik): later: substract the region of the child window
    934 // (WinQueryClipRegion()) instead of the window rectangle.
    9351449                        const QRect &r = w->crect;
    9361450                        rcl.xLeft = r.left();
     
    9491463            WinInvalidateRect( winId(), &rcl, FALSE );
    9501464        }
     1465#endif           
    9511466    }
    9521467}
     
    11161631    deactivateWidgetCleanup();
    11171632    HWND id = winFId();
     1633   
     1634#if defined (QT_PM_NO_WIDGETMASK)
    11181635    WinShowWindow( id, FALSE );
     1636#else       
     1637    qt_WinSetWindowPos( id, 0, 0, 0, 0, 0, SWP_HIDE );
     1638#endif
     1639   
    11191640    if ( isTopLevel() )
    11201641        WinSetWindowPos( id, 0, 0, 0, 0, 0, SWP_DEACTIVATE );
     
    11371658void QWidget::showWindow()
    11381659{
     1660#if defined (QT_PM_NO_WIDGETMASK)
    11391661    WinShowWindow( winFId(), TRUE );
     1662#else       
     1663    qt_WinSetWindowPos( winFId(), 0, 0, 0, 0, 0, SWP_SHOW );
     1664#endif
     1665   
    11401666    ULONG fl = 0;
    11411667    if ( isTopLevel() ) {
     
    11781704    if ( fl )
    11791705        WinSetWindowPos( winFId(), 0, 0, 0, 0, 0, fl );
    1180 
    1181 //@@TODO (dmik): remove? in OS/2 WinShowWindow() does not influence
    1182 //  any other state flags of the window (such as maximized/minimized, active),
    1183 //  so, the window is always shown at its current state (i.e. if its state was
    1184 //  not changed while it was hidden it will be restored to that state upon
    1185 //  unhiding; if the state was changed, it will be restored to that new state).
    1186 //    int sm = SW_SHOWNORMAL;
    1187 //    if ( isTopLevel() ) {
    1188 //      if (testWState(WState_Minimized))
    1189 //          sm = SW_SHOWMINIMIZED;
    1190 //      else if (testWState(WState_Maximized))
    1191 //          sm = SW_SHOWMAXIMIZED;
    1192 //    }
    1193 //    if (testWFlags(WStyle_Tool) || isPopup())
    1194 //      sm = SW_SHOWNOACTIVATE;
    1195 //
    1196 //    ShowWindow( winId(), sm );
    1197 //    UpdateWindow( winId() );
    11981706}
    11991707
     
    12051713//@@TODO (dmik): remove? SWP_ZORDER doesn't cause activation in OS/2...
    12061714//    uint f = ( isPopup() || testWFlags(WStyle_Tool) ) ? SWP_NOACTIVATE : 0;
     1715
     1716#if defined (QT_PM_NO_WIDGETMASK)
    12071717    WinSetWindowPos( winFId(), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
     1718#else       
     1719    qt_WinSetWindowPos( winFId(), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER );
     1720#endif
    12081721}
    12091722
     
    12151728//@@TODO (dmik): remove? SWP_ZORDER doesn't cause activation in OS/2...
    12161729//    uint f = ( isPopup() || testWFlags(WStyle_Tool) ) ? SWP_NOACTIVATE : 0;
     1730
     1731#if defined (QT_PM_NO_WIDGETMASK)
    12171732    WinSetWindowPos( winFId(), HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER );
     1733#else       
     1734    qt_WinSetWindowPos( winFId(), HWND_BOTTOM, 0, 0, 0, 0, SWP_ZORDER );
     1735#endif
    12181736}
    12191737
     
    12271745        p->childObjects->insert( p->childObjects->findRef(w), this );
    12281746    }
     1747#if defined (QT_PM_NO_WIDGETMASK)
    12291748    WinSetWindowPos( winId(), w->winId(), 0, 0, 0, 0, SWP_ZORDER );
     1749#else       
     1750    qt_WinSetWindowPos( winId(), w->winId(), 0, 0, 0, 0, SWP_ZORDER );
     1751#endif
    12301752}
    12311753
     
    12531775    if ( !isTopLevel() )
    12541776        isMove = (crect.topLeft() != QPoint( x, y ));
    1255     if ( isMove == FALSE && oldSize.width()==w && oldSize.height()==h )
     1777    bool isResize = w != oldSize.width() || h != oldSize.height();
     1778    if ( isMove == FALSE && isResize == FALSE )
    12561779        return;
    12571780    clearWState(WState_Maximized);
     
    12641787        setWState( WState_ConfigPending );
    12651788        if ( isTopLevel() ) {
    1266 //@@TODO (dmik): remove, no need to check for extra...
    1267 //          QRect fr( frameGeometry() );
    1268 //          if ( extra ) {
    1269 //              fr.setLeft( fr.left() + x - crect.left() );
    1270 //              fr.setTop( fr.top() + y - crect.top() );
    1271 //              fr.setRight( fr.right() + ( x + w - 1 ) - crect.right() );
    1272 //              fr.setBottom( fr.bottom() + ( y + h - 1 ) - crect.bottom() );
    1273 //          }
    1274 //          MoveWindow( winId(), fr.x(), fr.y(), fr.width(), fr.height(), TRUE );
    1275 //          crect.setRect( x, y, w, h );
    1276 
    1277 //@@TODO (dmik): optimize: use extra->topextra directly (after updating fstrut
     1789/// @todo (dmik) optimize: use extra->topextra directly (after updating fstrut
    12781790//  if necessary) instead of calling frameGeometry()
    12791791            QRect fr( frameGeometry() );
     
    12871799            WinSetWindowPos( winFId(), 0, fx, fy, fw, fh, SWP_MOVE | SWP_SIZE );
    12881800        } else {
     1801#if defined (QT_PM_NO_WIDGETMASK)
    12891802            // flip y coordinate
    12901803            int fy = parentWidget()->height() - (y + h);
    12911804            crect.setRect( x, y, w, h );
    12921805            WinSetWindowPos( winId(), 0, x, fy, w, h, SWP_MOVE | SWP_SIZE );
     1806#else
     1807            // When WS_CLIPCHILDREN and WS_CLIPSIBLINGS are not used,
     1808            // WinSetWindowPos() does not correctly update involved windows.
     1809            // The fix is to do it ourselves, taking clip regions into account.
     1810           
     1811            QWidget *parent = parentWidget();
     1812            const int ph = parent->height();
     1813            // flip y coordinate
     1814            int fy = ph - (y + h);
     1815            // set new and old rectangles
     1816            const RECTL rcls [2] = {
     1817                // new (y flipped, relative to parent)
     1818                { x, fy, x + w, fy + h },   
     1819                // old (y flipped, relative to parent)
     1820                { crect.left(), ph - (crect.bottom() + 1),
     1821                  crect.right() + 1, ph - crect.top() }
     1822            };
     1823            const RECTL &rclNew = rcls [0];
     1824            const RECTL &rclOld = rcls [1];
     1825            // delta to shift coordinate space from parent to this widget
     1826            POINTL ptlToSelf = { -x, -fy };
     1827            // update crect and move the widget w/o redrawing
     1828            crect.setRect( x, y, w, h );
     1829            WinSetWindowPos( winId(), 0, x, fy, w, h,
     1830                             SWP_MOVE | SWP_SIZE | SWP_NOREDRAW );
     1831            // use parent PS for blitting 
     1832            HPS hps = WinGetPS( parent->winId() );
     1833            // get old and new clip regions (relative to parent)
     1834            HRGN hrgnOld = GpiCreateRegion( hps, 1, &rclOld );
     1835            HRGN hrgnNew = GpiCreateRegion( hps, 1, &rclNew );
     1836            if ( WinQueryClipRegion( winId(), 0 ) != QCRGN_NO_CLIP_REGION ) {
     1837                HRGN hrgnTemp = GpiCreateRegion( hps, 0, NULL );
     1838                // old (clipped to the old rect)
     1839                WinQueryClipRegion( winId(), hrgnTemp );
     1840                GpiOffsetRegion( hps, hrgnTemp, (PPOINTL) &rclOld );
     1841                GpiCombineRegion( hps, hrgnOld, hrgnTemp, hrgnOld, CRGN_AND );
     1842                // new (clipped to the new rect)
     1843                WinQueryClipRegion( winId(), hrgnTemp );
     1844                if ( oldSize.height() != h ) {
     1845                    // keep the clip region top-left aligned by adding the
     1846                    // height delta (new size - old size)
     1847                    POINTL ptl = { 0, h - oldSize.height() };
     1848                    GpiOffsetRegion( hps, hrgnTemp, &ptl );
     1849                    WinSetClipRegion( winId(), hrgnTemp );
     1850                }
     1851                GpiOffsetRegion( hps, hrgnTemp, (PPOINTL) &rclNew );
     1852                GpiCombineRegion( hps, hrgnNew, hrgnTemp, hrgnNew, CRGN_AND );
     1853                GpiDestroyRegion( hps, hrgnTemp );
     1854            }
     1855            // the rest is useful only when the widget is visible
     1856            if ( isVisible() ) {
     1857                // create affected region (old + new, relative to widget)
     1858                HRGN hrgnAff = GpiCreateRegion( hps, 0, NULL );
     1859                GpiCombineRegion( hps, hrgnAff, hrgnOld, hrgnNew, CRGN_OR );
     1860                GpiOffsetRegion( hps, hrgnAff, &ptlToSelf );
     1861                // get bounding rectangle of affected region
     1862                RECTL rclAff;
     1863                GpiQueryRegionBox( hps, hrgnAff, &rclAff );
     1864                // get region of obstacles limited to affected rectangle
     1865                HRGN hrgnObst = GpiCreateRegion( hps, 0, NULL );
     1866                qt_WinProcessWindowObstacles( winId(), &rclAff, hrgnObst, CRGN_OR,
     1867                                              PWO_Sibings | PWO_Ancestors );
     1868                // shift region of obstacles and affected region back to
     1869                // parent coords
     1870                GpiOffsetRegion( hps, hrgnObst, (PPOINTL) &rclNew );
     1871                GpiOffsetRegion( hps, hrgnAff, (PPOINTL) &rclNew );
     1872                // get parent bounds (clip region or rect)
     1873                HRGN hrgnUpd = GpiCreateRegion( hps, 0, NULL );
     1874                qt_WinQueryClipRegionOrRect( parent->winId(), hrgnUpd );
     1875                // add parts of old region beyond parent bounds to
     1876                // region of obstacles
     1877                GpiCombineRegion( hps, hrgnOld, hrgnOld, hrgnUpd, CRGN_DIFF );
     1878                GpiCombineRegion( hps, hrgnObst, hrgnObst, hrgnOld, CRGN_OR );
     1879                // substract region of obstacles from affected region
     1880                GpiCombineRegion( hps, hrgnAff, hrgnAff, hrgnObst, CRGN_DIFF );
     1881                // remember it as parent update region (need later)
     1882                GpiCombineRegion( hps, hrgnUpd, hrgnAff, 0, CRGN_COPY );
     1883                // copy region of obstacles to delta region and shift it by
     1884                // delta (note: movement is considered to be top-left aligned)
     1885                HRGN hrgnDelta = GpiCreateRegion( hps, 0, NULL );
     1886                GpiCombineRegion( hps, hrgnDelta, hrgnObst, 0, CRGN_COPY );
     1887                POINTL ptlDelta = { rclNew.xLeft - rclOld.xLeft,
     1888                                    rclNew.yTop - rclOld.yTop };
     1889                GpiOffsetRegion( hps, hrgnDelta, &ptlDelta );
     1890                // substract region of obstacles from delta region to get
     1891                // pure delta
     1892                GpiCombineRegion( hps, hrgnDelta, hrgnDelta, hrgnObst, CRGN_DIFF );
     1893                // calculate minimal rectangle to blit (top-left aligned)
     1894                int minw = QMIN( oldSize.width(), w );
     1895                int minh = QMIN( oldSize.height(), h );
     1896                POINTL blitPtls [4] = {
     1897                    // target (new)
     1898                    { rclNew.xLeft, rclNew.yTop - minh },
     1899                    { rclNew.xLeft + minw, rclNew.yTop },
     1900                    // source (old)
     1901                    { rclOld.xLeft, rclOld.yTop - minh },
     1902                };
     1903                // proceed with blitting only if target and source rects differ
     1904                if ( blitPtls[0].x !=  blitPtls[2].x ||
     1905                     blitPtls[0].y !=  blitPtls[2].y )
     1906                {
     1907                    // Substract delta region from affected region (to minimize
     1908                    // flicker)
     1909                    GpiCombineRegion( hps, hrgnAff, hrgnAff, hrgnDelta, CRGN_DIFF );
     1910                    // set affected region to parent PS
     1911                    GpiSetClipRegion( hps, hrgnAff, NULL );
     1912                    // blit minimal rectangle
     1913                    GpiBitBlt( hps, hps, 3, blitPtls, ROP_SRCCOPY, BBO_IGNORE );
     1914                    GpiSetClipRegion( hps, 0, NULL );
     1915                }
     1916                // substract new widget region from the parent update region
     1917                // and invalidate it (with underlying children)
     1918                GpiCombineRegion( hps, hrgnUpd, hrgnUpd, hrgnNew, CRGN_DIFF );
     1919                qt_WinInvalidateRegionEx( parent->winId(), hrgnUpd,
     1920                                          WinQueryWindow( winId(), QW_NEXT ),
     1921                                          HWND_BOTTOM );
     1922                // intersect pure delta region with new region
     1923                // (to detect areas clipped off to minimize flicker when blitting)
     1924                GpiCombineRegion( hps, hrgnDelta, hrgnDelta, hrgnNew, CRGN_AND );
     1925                // substract blitted rectangle from new region
     1926                GpiSetRegion( hps, hrgnAff, 1, (PRECTL) &blitPtls );
     1927                GpiCombineRegion( hps, hrgnNew, hrgnNew, hrgnAff, CRGN_DIFF );
     1928                // combine the rest with intersected delta region
     1929                GpiCombineRegion( hps, hrgnNew, hrgnNew, hrgnDelta, CRGN_OR );
     1930                // shift the result back to widget coords and invalidate
     1931                GpiOffsetRegion( hps, hrgnNew, &ptlToSelf );
     1932                WinInvalidateRegion( winId(), hrgnNew, TRUE );
     1933                // free resources
     1934                GpiDestroyRegion( hps, hrgnDelta );
     1935                GpiDestroyRegion( hps, hrgnUpd );
     1936                GpiDestroyRegion( hps, hrgnObst );
     1937                GpiDestroyRegion( hps, hrgnAff );
     1938            }
     1939            // free resources
     1940            GpiDestroyRegion( hps, hrgnOld );
     1941            GpiDestroyRegion( hps, hrgnNew );
     1942            WinReleasePS( hps );
     1943#endif
    12931944        }
    12941945        clearWState( WState_ConfigPending );
    12951946    }
    12961947
    1297     bool isResize = w != oldSize.width() || h != oldSize.height();
    12981948    if ( isVisible() ) {
    12991949        if ( isMove && pos() != oldPos ) {
     
    14562106        newRegion = rgn.handle( height() );
    14572107    }
    1458     GpiSetClipRegion( lhps, newRegion, &oldRegion );
     2108    GpiSetClipRegion( lhps, newRegion, NULL );
    14592109
    14602110    QPoint offset = backgroundOffset();
     
    14752125}
    14762126
     2127#if defined (QT_PM_NO_WIDGETMASK)       
    14772128
    14782129// helper function to extract regions of all windows that overlap the given
     
    14902141        while( (i = WinQueryWindow( i, QW_PREV )) ) {
    14912142            if ( WinIsWindowShowing( i ) ) {
    1492 //@@TODO (dmik): probably we should use WinQueryClipRegion() here to
    1493 //  handle non-rectangular windows properly
    14942143                WinQueryWindowRect( i, &r );
    14952144                WinMapWindowPoints( i, hwnd, (PPOINTL) &r, 2 );
     
    15932242}
    15942243
     2244#else
     2245
     2246/**
     2247 *  \internal
     2248 *  Helper to scroll window contents.
     2249 *  All coordinates are GPI, not Qt.
     2250 */
     2251static void scrollWindow( HWND hwnd, int w, int h,
     2252                          int dx, int dy, const PRECTL clip = NULL )
     2253{
     2254    POINTL ptlDelta = { dx, dy };
     2255   
     2256    POINTL ptls[4];
     2257    RECTL &rclSrc = *(PRECTL) &ptls[2];
     2258    RECTL &rclDst = *(PRECTL) &ptls[0];
     2259
     2260    if ( clip ) {
     2261        rclSrc = *clip;
     2262    } else {
     2263        rclSrc.xLeft = rclSrc.yBottom = 0;
     2264        rclSrc.xRight = w;
     2265        rclSrc.yTop = h;
     2266    }
     2267    rclDst = rclSrc;
     2268    rclDst.xLeft += dx;
     2269    rclDst.xRight += dx;
     2270    rclDst.yBottom += dy;
     2271    rclDst.yTop += dy;
     2272   
     2273    if ( !clip ) {
     2274        // move all child widgets silently
     2275        SWP swp;
     2276        HWND child = WinQueryWindow( hwnd, QW_BOTTOM );
     2277        if ( child != NULLHANDLE ) {
     2278            for ( ; child != HWND_TOP; child = swp.hwndInsertBehind ) {
     2279                WinQueryWindowPos( child, &swp );
     2280                swp.x += dx;
     2281                swp.y += dy;
     2282                WinSetWindowPos( child, 0, swp.x, swp.y, 0, 0,
     2283                                 SWP_MOVE | SWP_NOADJUST | SWP_NOREDRAW );
     2284                // WinSetWindowPos() doesn't send WM_MOVE to windows w/o
     2285                // CS_MOVENOTIFY, but having this style for non-toplevel
     2286                // widgets is unwanted, so we send them WM_MOVE manually
     2287                // to let their geometry to be properly updated by
     2288                // QETWidget::translateConfigEvent().
     2289                WinSendMsg( child, WM_MOVE, 0, 0 );
     2290            }
     2291        }
     2292    }
     2293   
     2294    WinLockVisRegions( HWND_DESKTOP, TRUE );
     2295   
     2296    HPS hps = WinGetPS( hwnd );
     2297
     2298    // get widget bounds (clip region or rect)
     2299    HRGN hrgnClip = GpiCreateRegion( hps, 0, NULL );
     2300    qt_WinQueryClipRegionOrRect( hwnd, hrgnClip );
     2301    // compose a region uncovered after scrolling
     2302    HRGN hrgnUpd = GpiCreateRegion( hps, 0, NULL );
     2303    GpiCombineRegion( hps, hrgnUpd, hrgnClip, 0, CRGN_COPY );
     2304    GpiOffsetRegion( hps, hrgnUpd, &ptlDelta );
     2305    GpiCombineRegion( hps, hrgnUpd, hrgnClip, hrgnUpd, CRGN_DIFF );
     2306   
     2307    if ( clip ) {
     2308        // intersect it with the given clip rect
     2309        HRGN hrgn = GpiCreateRegion( hps, 1, clip );
     2310        GpiCombineRegion( hps, hrgnUpd, hrgnClip, hrgnUpd, CRGN_AND );
     2311        GpiDestroyRegion( hps, hrgn );
     2312    }
     2313   
     2314    int pwoFlags = PWO_Ancestors | PWO_Sibings;
     2315    if ( clip )
     2316        pwoFlags |= PWO_Children;
     2317   
     2318    // get the region of obstacles
     2319    HRGN hrgnObst = GpiCreateRegion( hps, 0, NULL );
     2320    qt_WinProcessWindowObstacles( hwnd, &rclSrc, hrgnObst, CRGN_OR, pwoFlags );
     2321    // create the delta region of obstacles
     2322    HRGN hrgnDelta = GpiCreateRegion( hps, 0, NULL );
     2323    GpiCombineRegion( hps, hrgnDelta, hrgnObst, 0, CRGN_COPY );
     2324    GpiOffsetRegion( hps, hrgnDelta, &ptlDelta );
     2325    // substract the region of obstaces fro the delta region to get pure delta
     2326    GpiCombineRegion( hps, hrgnDelta, hrgnDelta, hrgnObst, CRGN_DIFF );
     2327    // substract obstacles the clip region
     2328    GpiCombineRegion( hps, hrgnClip, hrgnClip, hrgnObst, CRGN_DIFF );
     2329    // substract pure delta from the clip region (to reduce flicker)
     2330    GpiCombineRegion( hps, hrgnClip, hrgnClip, hrgnDelta, CRGN_DIFF );
     2331   
     2332    // scroll the area
     2333    GpiSetClipRegion( hps, hrgnClip, NULL );
     2334    GpiBitBlt( hps, hps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE );
     2335    GpiSetClipRegion( hps, 0, NULL );
     2336   
     2337    // invalidate the delta region (clipped off when blitting)
     2338    WinInvalidateRegion( hwnd, hrgnDelta, clip == NULL );
     2339
     2340    // invalidate the region uncovered after scrolling
     2341    WinInvalidateRegion( hwnd, hrgnUpd, clip == NULL );
     2342   
     2343    GpiDestroyRegion( hps, hrgnDelta );
     2344    GpiDestroyRegion( hps, hrgnObst );
     2345    GpiDestroyRegion( hps, hrgnUpd );
     2346    GpiDestroyRegion( hps, hrgnClip );
     2347    WinReleasePS( hps );
     2348   
     2349    WinLockVisRegions( HWND_DESKTOP, FALSE );
     2350   
     2351    WinUpdateWindow( hwnd );
     2352}
     2353
     2354#endif
     2355
    15952356void QWidget::scroll( int dx, int dy )
    15962357{
    15972358    if ( testWState( WState_BlockUpdates ) && !children() )
    15982359        return;
     2360
     2361#if defined (QT_PM_NO_WIDGETMASK)
    15992362
    16002363    // move non-toplevel children
     
    16282391
    16292392    qt_WinScrollWindowWell( winId(), dx, -dy, NULL );
     2393   
     2394#else
     2395
     2396    scrollWindow( winId(), width(), height(), dx, -dy, NULL );
     2397   
     2398#endif
    16302399}
    16312400
     
    16352404        return;
    16362405
     2406#if defined (QT_PM_NO_WIDGETMASK)
     2407   
    16372408    int h = crect.height();
    16382409    // flip y coordinate (all coordinates are inclusive)
    16392410    RECTL rcl = { r.left(), h - (r.bottom() + 1), r.right(), h - (r.top() + 1) };
    16402411    qt_WinScrollWindowWell( winId(), dx, -dy, &rcl );
     2412
     2413#else
     2414
     2415    int h = crect.height();
     2416    // flip y coordinate
     2417    RECTL rcl = { r.left(), h - (r.bottom() + 1),
     2418                  r.right() + 1, h - r.top() };
     2419    scrollWindow( winId(), width(), height(), dx, -dy, &rcl );
     2420   
     2421#endif
    16412422}
    16422423
     
    17272508{
    17282509    return 0;
    1729 //@@TODO (dmik): later
     2510/// @todo (dmik) later
    17302511//    return ( extra && extra->dropTarget );
    17312512}
     
    17332514void QWidget::setAcceptDrops( bool on )
    17342515{
    1735 //@@TODO (dmik): later
     2516/// @todo (dmik) later
    17362517//    // Enablement is defined by extra->dropTarget != 0.
    17372518//
     
    17522533}
    17532534
     2535#if !defined (QT_PM_NO_WIDGETMASK)       
     2536
     2537// helper for QWidget::setMask()
     2538static void setClipRegion( HWND hwnd, int x, int y, int w, int h, HRGN hrgn,
     2539                           HWND parent )
     2540{
     2541    if ( !WinIsWindowVisible( hwnd ) ) {
     2542        // if the window is hidden, no need to invalidate anything
     2543        WinSetClipRegion( hwnd, hrgn );
     2544        return;
     2545    }
     2546
     2547    HPS hps = qt_display_ps();
     2548    const RECTL rcl = { 0, 0, w, h };
     2549   
     2550    // get the old bounds (clip region or rect)
     2551    HRGN hrgnOld = GpiCreateRegion( hps, 0, NULL );
     2552    qt_WinQueryClipRegionOrRect( hwnd, hrgnOld );
     2553    // set the new clip region
     2554    WinSetClipRegion( hwnd, hrgn );
     2555   
     2556    HRGN hrgnUpd;
     2557    if ( hrgn != 0 ) {
     2558        hrgnUpd = GpiCreateRegion( hps, 0, NULL );
     2559        // substract the new clip region from the old one
     2560        GpiCombineRegion( hps, hrgnUpd, hrgnOld, hrgn, CRGN_DIFF );
     2561        // move the result to the parent coordinate space
     2562        POINTL ptl = { x, y };
     2563        GpiOffsetRegion( hps, hrgnUpd, &ptl );
     2564        // invalidate areas in parent uncovered by the new clip region
     2565        qt_WinInvalidateRegionEx( parent, hrgnUpd,
     2566                                  WinQueryWindow( hwnd, QW_NEXT ), HWND_BOTTOM );
     2567    } else {
     2568        // the new region is being set to NULL, which means to widget bounds
     2569        // (no need to substract new from old, because it will produce RGN_NULL)
     2570        hrgnUpd = GpiCreateRegion( hps, 1, &rcl );
     2571        hrgn = hrgnUpd;
     2572    }
     2573    // substract the old clip region from the new one
     2574    GpiCombineRegion( hps, hrgnUpd, hrgn, hrgnOld, CRGN_DIFF );
     2575    // invalidate areas in hwnd uncovered by the new clip region
     2576    WinInvalidateRegion( hwnd, hrgnUpd, TRUE );
     2577   
     2578    GpiDestroyRegion( hps, hrgnUpd );
     2579    GpiDestroyRegion( hps, hrgnOld );
     2580}
     2581
     2582#endif
     2583
     2584/*!
     2585    \overload
     2586
     2587    Causes only the parts of the widget which overlap \a region to be
     2588    visible. If the region includes pixels outside the rect() of the
     2589    widget, window system controls in that area may or may not be
     2590    visible, depending on the platform.
     2591
     2592    Note that this effect can be slow if the region is particularly
     2593    complex.
     2594
     2595    Note that on OS/2, masks for top-level widgets are not currently
     2596    supported, so setting a mask on such a widget has no effect.
     2597   
     2598    \sa setMask(), clearMask()
     2599*/
     2600
    17542601void QWidget::setMask( const QRegion &region )
    17552602{
    1756     qWarning( "QWidget::setMask() is not yet implemented on OS/2" );
    1757 //@@TODO (dmik): later (don't forget to offset region, see qregion_pm.cpp)
    1758 //    // Since SetWindowRegion takes ownership, and we need to translate,
    1759 //    // we take a copy.
    1760 //    HRGN wr = CreateRectRgn(0,0,1,1);
    1761 //    CombineRgn(wr, region.handle(), 0, RGN_COPY);
    1762 //
    1763 //    int fleft = 0, ftop = 0;
    1764 //    if (isTopLevel()) {
    1765 //      ftop = topData()->ftop;
    1766 //      fleft = topData()->fleft;
    1767 //    }
    1768 //    OffsetRgn(wr, fleft, ftop );
    1769 //    SetWindowRgn( winId(), wr, TRUE );
    1770 }
     2603#if !defined (QT_PM_NO_WIDGETMASK)       
     2604    if (isTopLevel()) {
     2605#if defined (QT_CHECK_STATE)       
     2606        qWarning( "QWidget::setMask() for top-level widgets "
     2607                  "is not implemented on OS/2" );
     2608#endif       
     2609        return;
     2610    }
     2611    setClipRegion( winId(), x(), parentWidget()->height() - (y() + height()),
     2612                   width(), height(), region.handle( height() ),
     2613                   parentWidget()->winId() );
     2614#else
     2615    Q_UNUSED( region );
     2616#endif   
     2617}
     2618
     2619/*!
     2620    Causes only the pixels of the widget for which \a bitmap has a
     2621    corresponding 1 bit to be visible. If the region includes pixels
     2622    outside the rect() of the widget, window system controls in that
     2623    area may or may not be visible, depending on the platform.
     2624
     2625    Note that this effect can be slow if the region is particularly
     2626    complex.
     2627
     2628    Note that on OS/2, masks for top-level widgets are not currently
     2629    supported, so setting a mask on such a widget has no effect.
     2630   
     2631    See \c examples/tux for an example of masking for transparency.
     2632
     2633    \sa setMask(), clearMask()
     2634*/
    17712635
    17722636void QWidget::setMask( const QBitmap &bitmap )
    17732637{
    1774     qWarning( "QWidget::setMask() is not yet implemented on OS/2" );
    1775 //@@TODO (dmik): later
    1776 //    HRGN wr = qt_win_bitmapToRegion(bitmap);
    1777 //
    1778 //    int fleft = 0, ftop = 0;
    1779 //    if (isTopLevel()) {
    1780 //      ftop = topData()->ftop;
    1781 //      fleft = topData()->fleft;
    1782 //    }
    1783 //    OffsetRgn(wr, fleft, ftop );
    1784 //    SetWindowRgn( winId(), wr, TRUE );
     2638#if !defined (QT_PM_NO_WIDGETMASK)
     2639    if (isTopLevel()) {
     2640#if defined (QT_CHECK_STATE)       
     2641        qWarning( "QWidget::setMask() for top-level widgets "
     2642                  "is not implemented on OS/2" );
     2643#endif       
     2644        return;
     2645    }
     2646    QRegion rgn = QRegion( bitmap );
     2647    setClipRegion( winId(), x(), parentWidget()->height() - (y() + height()),
     2648                   width(), height(), rgn.handle( height() ),
     2649                   parentWidget()->winId() );
     2650#else
     2651    Q_UNUSED( bitmap );
     2652#endif   
    17852653}
    17862654
    17872655void QWidget::clearMask()
    17882656{
    1789     qWarning( "QWidget::clearMask() is not yet implemented on OS/2" );
    1790 //@@TODO (dmik): later
    1791 //    SetWindowRgn( winId(), 0, TRUE );
     2657#if !defined (QT_PM_NO_WIDGETMASK)
     2658    if (isTopLevel())
     2659        return;
     2660    setClipRegion( winId(), x(), parentWidget()->height() - (y() + height()),
     2661                   width(), height(), 0,
     2662                   parentWidget()->winId() );
     2663#endif   
    17922664}
    17932665
     
    18462718}
    18472719
    1848 /*
    1849   \internal
    1850   Returns the frame wihdow handle if this widget is a top-level widget and
    1851   has the standard WC_FRAME as its parent/owner (where it is FID_CLIENT).
    1852   If the widget does not have the standard frame or it is not top-level, this
    1853   function simply retuns the winId() value.
    1854 */
     2720/**
     2721 *  \internal 
     2722 * Returns the frame wihdow handle if this widget is a top-level widget and
     2723 * has the standard WC_FRAME as its parent/owner (where it is FID_CLIENT).
     2724 * If the widget does not have the standard frame or it is not top-level, this
     2725 * function simply retuns the winId() value.
     2726 */
    18552727WId QWidget::winFId()
    18562728{
     
    18632735}
    18642736
     2737#if !defined (QT_PM_NO_WIDGETMASK)
     2738
     2739/*!
     2740 *  \internal
     2741 *
     2742 *  Validates areas of this widget covered by (intersected with) its children
     2743 *  and sibling widgets.
     2744 *
     2745 *  Clip regions of all relative widgets (set by WinSetClipRegion()) are taken
     2746 *  into account.
     2747 */
     2748void QWidget::validateObstacles()
     2749{
     2750    RECTL updateRcl;
     2751    if ( WinQueryUpdateRect( winId(), &updateRcl ) ) {
     2752        // the update rectangle may be empty
     2753        if ( updateRcl.xLeft != updateRcl.xRight &&
     2754             updateRcl.yBottom != updateRcl.yTop ) {
     2755            qt_WinProcessWindowObstacles( winId(), &updateRcl, 0, 0 );
     2756        }
     2757    }
     2758}
     2759
     2760/*!
     2761 *  \internal
     2762 *
     2763 *  Combines areas of this widget covered by (intersected with) its children
     2764 *  and sibling widgets to a region \a hrgn using an operation \a op
     2765 *  (see GpiCombineRegion()). Returns the complexity of the combined region.
     2766 *
     2767 *  Clip regions of all relative widgets (set by WinSetClipRegion()) are taken
     2768 *  into account.
     2769 */
     2770/// @todo (dmik) is it really necessary somewhere?
     2771LONG QWidget::combineObstacles( HRGN hrgn, LONG op )
     2772{
     2773    return qt_WinProcessWindowObstacles( winId(), NULL, hrgn, op );
     2774}
     2775
     2776#endif // !defined (QT_PM_NO_WIDGETMASK)
     2777
    18652778/*!
    18662779 *  \internal
    18672780 *
    18682781 *  Obtains a presentaiton space to draw on this widget, set up according
    1869  *  to widget flags. If \a m != Unclipped and WPaintUnclipped flag is not
    1870  *  set, a clip region is set on the returned PS according to \a m.
     2782 *  mode \a m and to widget flags.
    18712783 *
    18722784 *  The returned handle must be freed using WinReleasePS() after usage.
     
    18782790    if ( isDesktop() ) {
    18792791        widgetPS = WinGetScreenPS( HWND_DESKTOP );
     2792        return widgetPS;
    18802793    } else {
    18812794        if ( m == Unclipped || (m == ClipDefault &&
    18822795                                testWFlags( WPaintUnclipped )) ) {
    18832796            widgetPS = WinGetClipPS( winId(), 0, PSF_PARENTCLIP );
     2797            return widgetPS;
    18842798        } else {
    18852799            widgetPS = WinGetPS( winId() );
     
    18872801    }
    18882802
     2803#if !defined (QT_PM_NO_WIDGETMASK)
     2804    RECTL rcl = { 0, 0, crect.width(), crect.height() };
     2805    HRGN hrgn = GpiCreateRegion( widgetPS, 1, &rcl );
     2806    qt_WinProcessWindowObstacles( winId(), NULL, hrgn, CRGN_DIFF );
     2807    HRGN hrgnOld = 0;
     2808    GpiSetClipRegion( widgetPS, hrgn, &hrgnOld );
     2809    Q_ASSERT( !hrgnOld );
     2810    if ( hrgnOld )
     2811        GpiDestroyRegion( widgetPS, hrgnOld );
     2812#endif   
     2813   
    18892814    return widgetPS;
    18902815}
Note: See TracChangeset for help on using the changeset viewer.