Changeset 183 for trunk/src


Ignore:
Timestamp:
Sep 16, 2009, 5:47:31 PM (16 years ago)
Author:
Dmitry A. Kuminov
Message:

gui: Implemented widget scrolling (QWidget::scroll() and friends).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/gui/kernel/qwidget_pm.cpp

    r182 r183  
    777777
    778778/*!
     779    \internal
     780
     781    Helper function to extract regions of all windows that overlap the given
     782    hwnd subject to their z-order (excluding children of hwnd) from the given
     783    hrgn. hps is the presentation space of hrgn.
     784 */
     785void qt_WinExcludeOverlappingWindows(HWND hwnd, HPS hps, HRGN hrgn)
     786{
     787    HRGN vr = GpiCreateRegion(hps, 0, NULL);
     788    RECTL r;
     789
     790    // enumerate all windows that are on top of this hwnd
     791    HWND id = hwnd, deskId = QApplication::desktop()->winId();
     792    do {
     793        HWND i = id;
     794        while((i = WinQueryWindow( i, QW_PREV ))) {
     795            if (WinIsWindowVisible(i)) {
     796                WinQueryWindowRect(i, &r);
     797                WinMapWindowPoints(i, hwnd, (PPOINTL) &r, 2);
     798                GpiSetRegion(hps, vr, 1, &r);
     799                GpiCombineRegion(hps, hrgn, hrgn, vr, CRGN_DIFF);
     800            }
     801        }
     802        id = WinQueryWindow(id, QW_PARENT);
     803    } while(id != deskId);
     804
     805    GpiDestroyRegion(hps, vr);
     806}
     807
     808/*!
     809    \internal
     810
     811    Helper function to scroll window contents. WinScrollWindow() is a bit
     812    buggy and corrupts update regions sometimes (which leaves some outdated
     813    areas unpainted after scrolling), so we reimplement its functionality in
     814    this function. dy and clip->yBottom/yTop should be GPI coordinates, not Qt.
     815    all clip coordinates are inclusive.
     816 */
     817void qt_WinScrollWindowWell(HWND hwnd, LONG dx, LONG dy, const PRECTL clip = NULL)
     818{
     819    WinLockVisRegions(HWND_DESKTOP, TRUE);
     820
     821    HPS lhps = WinGetClipPS(hwnd, HWND_TOP,
     822                            PSF_LOCKWINDOWUPDATE | PSF_CLIPSIBLINGS);
     823    if (clip)
     824        GpiIntersectClipRectangle(lhps, clip);
     825
     826    // remember the update region and validate it. it will be shifted and
     827    // invalidated again later
     828    HRGN update = GpiCreateRegion(lhps, 0, NULL);
     829    WinQueryUpdateRegion(hwnd, update);
     830    WinValidateRegion(hwnd, update, TRUE);
     831
     832    POINTL ptls[4];
     833    RECTL &sr = *(PRECTL) &ptls[2];
     834    RECTL &tr = *(PRECTL) &ptls[0];
     835
     836    // get the source rect for scrolling
     837    GpiQueryClipBox(lhps, &sr);
     838    sr.xRight++; sr.yTop++; // inclusive -> exclusive
     839
     840    // get the visible region ignoring areas covered by children
     841    HRGN visible = GpiCreateRegion(lhps, 1, &sr);
     842    qt_WinExcludeOverlappingWindows(hwnd, lhps, visible);
     843
     844    // scroll visible region rectangles separately to avoid the flicker
     845    // that could be produced by scrolling parts of overlapping windows
     846    RGNRECT ctl;
     847    ctl.ircStart = 1;
     848    ctl.crc = 0;
     849    ctl.crcReturned = 0;
     850    if (dx >= 0) {
     851        if (dy >= 0) ctl.ulDirection = RECTDIR_RTLF_TOPBOT;
     852        else ctl.ulDirection = RECTDIR_RTLF_BOTTOP;
     853    } else {
     854        if (dy >= 0) ctl.ulDirection = RECTDIR_LFRT_TOPBOT;
     855        else ctl.ulDirection = RECTDIR_LFRT_BOTTOP;
     856    }
     857    GpiQueryRegionRects(lhps, visible, NULL, &ctl, NULL);
     858    ctl.crc = ctl.crcReturned;
     859    int rclcnt = ctl.crcReturned;
     860    PRECTL rcls = new RECTL[rclcnt];
     861    GpiQueryRegionRects(lhps, visible, NULL, &ctl, rcls);
     862    PRECTL r = rcls;
     863    for (int i = 0; i < rclcnt; i++, r++) {
     864        // source rect
     865        sr = *r;
     866        // target rect
     867        tr.xLeft = sr.xLeft + dx;
     868        tr.xRight = sr.xRight + dx;
     869        tr.yBottom = sr.yBottom + dy;
     870        tr.yTop = sr.yTop + dy;
     871        GpiBitBlt(lhps, lhps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE);
     872    }
     873    delete [] rcls;
     874
     875    // make the scrolled version of the visible region
     876    HRGN scrolled = GpiCreateRegion(lhps, 0, NULL);
     877    GpiCombineRegion(lhps, scrolled, visible, 0, CRGN_COPY);
     878    // invalidate the initial update region
     879    GpiCombineRegion(lhps, scrolled, scrolled, update, CRGN_DIFF);
     880    // shift the region
     881    POINTL dp = { dx, dy };
     882    GpiOffsetRegion(lhps, scrolled, &dp);
     883    // substract scrolled from visible to get invalid areas
     884    GpiCombineRegion(lhps, scrolled, visible, scrolled, CRGN_DIFF);
     885
     886    WinInvalidateRegion(hwnd, scrolled, TRUE);
     887
     888    GpiDestroyRegion(lhps, scrolled);
     889    GpiDestroyRegion(lhps, visible);
     890    GpiDestroyRegion(lhps, update);
     891
     892    WinReleasePS(lhps);
     893
     894    WinLockVisRegions(HWND_DESKTOP, FALSE);
     895
     896    WinUpdateWindow(hwnd);
     897}
     898
     899/*!
    779900 * \internal
    780901 * For some unknown reason, PM sends WM_SAVEAPPLICATION to every window
     
    20842205void QWidgetPrivate::scroll_sys(int dx, int dy)
    20852206{
    2086     // @todo implement
     2207    Q_Q(QWidget);
     2208    scrollChildren(dx, dy);
     2209
     2210    if (!paintOnScreen()) {
     2211        scrollRect(q->rect(), dx, dy);
     2212    } else {
     2213        // @todo ask qt_WinScrollWindowWell() to erase background if
     2214        // WA_OpaquePaintEvent is reset?
     2215        //if (!q->testAttribute(Qt::WA_OpaquePaintEvent))
     2216        //    ;
     2217        Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
     2218        qt_WinScrollWindowWell(q->internalWinId(), dx, -dy, NULL);
     2219    }
    20872220}
    20882221
    20892222void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
    20902223{
    2091     // @todo implement
     2224    Q_Q(QWidget);
     2225
     2226    if (!paintOnScreen()) {
     2227        scrollRect(r, dx, dy);
     2228    } else {
     2229        int h = data.crect.height();
     2230        // flip y coordinate (all coordinates are inclusive)
     2231        RECTL rcl = { r.left(), h - (r.bottom() + 1), r.right(), h - (r.top() + 1) };
     2232
     2233        // @todo ask qt_WinScrollWindowWell() to erase background if
     2234        // WA_OpaquePaintEvent is reset?
     2235        //if (!q->testAttribute(Qt::WA_OpaquePaintEvent))
     2236        //    ;
     2237        Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
     2238        qt_WinScrollWindowWell(q->internalWinId(), dx, -dy, &rcl);
     2239    }
    20922240}
    20932241
Note: See TracChangeset for help on using the changeset viewer.