diff --git a/widget/src/os2/nsWindow.cpp b/widget/src/os2/nsWindow.cpp index 7cb6da81f6ed..96324b8c26cf 100644 --- a/widget/src/os2/nsWindow.cpp +++ b/widget/src/os2/nsWindow.cpp @@ -79,6 +79,9 @@ #include "imgIContainer.h" +#include "nsTHashtable.h" +#include "nsHashKeys.h" + #include #include @@ -2064,80 +2067,117 @@ void nsWindow::FreeNativeData(void * data, PRUint32 aDataType) //------------------------------------------------------------------------- // -// Notify a child window of a coming move by sending it a WM_VRNDISABLED -// message. Only do that if it's not one of ours like e.g. plugin windows. +// Configure the child widgets used for plugins // //------------------------------------------------------------------------- -BOOL nsWindow::NotifyForeignChildWindows(HWND aWnd) -{ - HENUM hEnum = WinBeginEnumWindows(aWnd); - HWND hwnd; - while ((hwnd = WinGetNextWindow(hEnum)) != NULLHANDLE) { - char className[19]; - WinQueryClassName(hwnd, 19, className); - if (strcmp(className, WindowClass()) != 0) { - // This window is not one of our windows so notify it (and wait for - // the call to return so that the plugin has time to react) - WinSendMsg(hwnd, WM_VRNDISABLED, MPVOID, MPVOID); - } else { - // Recurse starting at this Mozilla child window. - NotifyForeignChildWindows(hwnd); - } +// This is _supposed_ to set a clipping region for the child windows used +// by plugins. However, on OS/2, clipping regions aren't associated with +// windows, usually aren't persistent, & have no effect on drawing done +// into children of the clipped window (which is where OS/2 plugins paint). +// As an alternative, this implementation uses the child windows' dimensions +// as clipping rectangles, adjusting them to match the bounding boxes of the +// supplied arrays of rectangles. This should suffice in most situations. + +nsresult +nsWindow::ConfigureChildren(const nsTArray& aConfigurations) +{ + // for each child window + for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) { + const Configuration& configuration = aConfigurations[i]; + nsWindow* w = static_cast(configuration.mChild); + NS_ASSERTION(w->GetParent() == this, + "Configured widget is not a child"); + + // create the bounding box + const nsTArray& rects = configuration.mClipRegion; + nsIntRect r; + for (PRUint32 i = 0; i < rects.Length(); ++i) + r.UnionRect(r, rects[i]); + + // resize the child; mBounds.x/y contain the child's correct origin; + // r.x/y are always <= zero - adding them to r.width/height produces + // the actual clipped width/height this window should have + w->Resize(configuration.mBounds.x, configuration.mBounds.y, + r.width + r.x, r.height + r.y, PR_TRUE); + + // some plugins may shrink their window when the Mozilla widget window + // shrinks, then fail to reinflate when the widget window reinflates; + // this ensures the plugin's window is always at its full size and is + // clipped correctly by the widget's bounds + HWND hwnd = WinQueryWindow( w->mWnd, QW_TOP); + ::WinSetWindowPos(hwnd, 0, 0, 0, + configuration.mBounds.width, configuration.mBounds.height, + SWP_MOVE | SWP_SIZE); + + // show or hide the window, then save the array of rects + // for future reference + w->Show(!configuration.mClipRegion.IsEmpty()); + w->StoreWindowClipRegion(configuration.mClipRegion); } - return WinEndEnumWindows(hEnum); + + return NS_OK; } -//------------------------------------------------------------------------- -// -// Force a resize of child windows after a scroll to reset hover positions. -// -//------------------------------------------------------------------------- -void nsWindow::ScrollChildWindows(PRInt32 aX, PRInt32 aY) -{ - nsIWidget *child = GetFirstChild(); - while (child) { - nsIntRect rect; - child->GetBounds(rect); - child->Resize(rect.x + aX, rect.y + aY, rect.width, rect.height, PR_FALSE); - child = child->GetNextSibling(); - } -} //------------------------------------------------------------------------- // // Scroll the bits of a window // //------------------------------------------------------------------------- -NS_METHOD nsWindow::Scroll(PRInt32 aDx, PRInt32 aDy, nsIntRect *aClipRect) +void nsWindow::Scroll(const nsIntPoint& aDelta, const nsIntRect& aSource, + const nsTArray& aConfigurations) { - RECTL rcl; - - if (nsnull != aClipRect) - { - rcl.xLeft = aClipRect->x; - rcl.yBottom = aClipRect->y + aClipRect->height; - rcl.xRight = rcl.xLeft + aClipRect->width; - rcl.yTop = rcl.yBottom + aClipRect->height; - NS2PM(rcl); - // this rect is inex + // Build the set of widgets that are to be moved by the scroll amount. + nsTHashtable > scrolledWidgets; + scrolledWidgets.Init(); + for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) { + const Configuration& configuration = aConfigurations[i]; + nsWindow* w = static_cast(configuration.mChild); + NS_ASSERTION(w->GetParent() == this, + "Configured widget is not a child"); + if (configuration.mBounds.TopLeft() == w->mBounds.TopLeft() + aDelta) + scrolledWidgets.PutEntry(w); } + nsIntRect affectedRect; + affectedRect.UnionRect(aSource, aSource + aDelta); + ULONG flags = SW_INVALIDATERGN; + + // We can use SW_SCROLLCHILDREN if all the windows that intersect + // the affected area are moving by the scroll amount. Check if + // any of our children would be affected by SW_SCROLLCHILDREN but + // are not supposed to scroll. + for (nsWindow* w = static_cast(GetFirstChild()); w; + w = static_cast(w->GetNextSibling())) { + if (w->mBounds.Intersects(affectedRect)) { + flags |= SW_SCROLLCHILDREN; + if (!scrolledWidgets.GetEntry(w)) { + flags &= ~SW_SCROLLCHILDREN; + break; + } + } + } + + RECTL clip; + clip.xLeft = affectedRect.x; + clip.xRight = affectedRect.x + affectedRect.width; + clip.yTop = mBounds.height - affectedRect.y; + clip.yBottom = clip.yTop - affectedRect.height; + // this prevents screen corruption while scrolling during a - // Moz-originated drag - during a native drag, the screen - // isn't updated until the drag ends. so there's no corruption + // Moz-originated drag - the hps isn't actually used but + // fetching it unlocks the screen so it can be updated HPS hps = 0; CheckDragStatus(ACTION_SCROLL, &hps); + ::WinScrollWindow(mWnd, aDelta.x, -aDelta.y, &clip, &clip, NULL, NULL, flags); - NotifyForeignChildWindows(mWnd); - WinScrollWindow(mWnd, aDx, -aDy, aClipRect ? &rcl : 0, 0, 0, - 0, SW_SCROLLCHILDREN | SW_INVALIDATERGN); - ScrollChildWindows(aDx, aDy); + // Now make sure all children actually get positioned, sized, and clipped + // correctly. If SW_SCROLLCHILDREN was in effect, they may already be. + ConfigureChildren(aConfigurations); Update(); if (hps) ReleaseIfDragHPS(hps); - - return NS_OK; } //------------------------------------------------------------------------- diff --git a/widget/src/os2/nsWindow.h b/widget/src/os2/nsWindow.h index faf7101795d1..88e7bc37fd83 100644 --- a/widget/src/os2/nsWindow.h +++ b/widget/src/os2/nsWindow.h @@ -172,7 +172,9 @@ class nsWindow : public nsBaseWidget, NS_IMETHOD Invalidate( PRBool aIsSynchronous); NS_IMETHOD Invalidate( const nsIntRect & aRect, PRBool aIsSynchronous); NS_IMETHOD Update(); - NS_IMETHOD Scroll( PRInt32 aDx, PRInt32 aDy, nsIntRect *aClipRect); + virtual nsresult ConfigureChildren(const nsTArray& aConfigurations); + virtual void Scroll(const nsIntPoint& aDelta, const nsIntRect& aSource, + const nsTArray& aConfigurations); NS_IMETHOD GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState); // Get a HWND or a HPS. @@ -314,9 +316,6 @@ protected: HBITMAP CreateTransparencyMask(gfxASurface::gfxImageFormat format, PRUint8* aImageData, PRUint32 aWidth, PRUint32 aHeight); - BOOL NotifyForeignChildWindows(HWND aWnd); - void ScrollChildWindows(PRInt32 aX, PRInt32 aY); - // Enumeration of the methods which are accessible on the PM thread enum { CREATE,