Bug 501618: Follow up child widget removal on OS/2, p=dragtext@e-vertise, r=pweilbacher

This commit is contained in:
Peter Weilbacher 2009-07-26 21:28:24 +03:00
Родитель 829e02dcea
Коммит 9f9e94acf7
2 изменённых файлов: 95 добавлений и 56 удалений

Просмотреть файл

@ -79,6 +79,9 @@
#include "imgIContainer.h" #include "imgIContainer.h"
#include "nsTHashtable.h"
#include "nsHashKeys.h"
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
@ -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 // Configure the child widgets used for plugins
// message. Only do that if it's not one of ours like e.g. plugin windows.
// //
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
BOOL nsWindow::NotifyForeignChildWindows(HWND aWnd)
{
HENUM hEnum = WinBeginEnumWindows(aWnd);
HWND hwnd;
while ((hwnd = WinGetNextWindow(hEnum)) != NULLHANDLE) { // This is _supposed_ to set a clipping region for the child windows used
char className[19]; // by plugins. However, on OS/2, clipping regions aren't associated with
WinQueryClassName(hwnd, 19, className); // windows, usually aren't persistent, & have no effect on drawing done
if (strcmp(className, WindowClass()) != 0) { // into children of the clipped window (which is where OS/2 plugins paint).
// This window is not one of our windows so notify it (and wait for // As an alternative, this implementation uses the child windows' dimensions
// the call to return so that the plugin has time to react) // as clipping rectangles, adjusting them to match the bounding boxes of the
WinSendMsg(hwnd, WM_VRNDISABLED, MPVOID, MPVOID); // supplied arrays of rectangles. This should suffice in most situations.
} else {
// Recurse starting at this Mozilla child window. nsresult
NotifyForeignChildWindows(hwnd); nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
} {
// for each child window
for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
const Configuration& configuration = aConfigurations[i];
nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
NS_ASSERTION(w->GetParent() == this,
"Configured widget is not a child");
// create the bounding box
const nsTArray<nsIntRect>& 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 // 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<Configuration>& aConfigurations)
{ {
RECTL rcl; // Build the set of widgets that are to be moved by the scroll amount.
nsTHashtable<nsPtrHashKey<nsWindow> > scrolledWidgets;
if (nsnull != aClipRect) scrolledWidgets.Init();
{ for (PRUint32 i = 0; i < aConfigurations.Length(); ++i) {
rcl.xLeft = aClipRect->x; const Configuration& configuration = aConfigurations[i];
rcl.yBottom = aClipRect->y + aClipRect->height; nsWindow* w = static_cast<nsWindow*>(configuration.mChild);
rcl.xRight = rcl.xLeft + aClipRect->width; NS_ASSERTION(w->GetParent() == this,
rcl.yTop = rcl.yBottom + aClipRect->height; "Configured widget is not a child");
NS2PM(rcl); if (configuration.mBounds.TopLeft() == w->mBounds.TopLeft() + aDelta)
// this rect is inex 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<nsWindow*>(GetFirstChild()); w;
w = static_cast<nsWindow*>(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 // this prevents screen corruption while scrolling during a
// Moz-originated drag - during a native drag, the screen // Moz-originated drag - the hps isn't actually used but
// isn't updated until the drag ends. so there's no corruption // fetching it unlocks the screen so it can be updated
HPS hps = 0; HPS hps = 0;
CheckDragStatus(ACTION_SCROLL, &hps); CheckDragStatus(ACTION_SCROLL, &hps);
::WinScrollWindow(mWnd, aDelta.x, -aDelta.y, &clip, &clip, NULL, NULL, flags);
NotifyForeignChildWindows(mWnd); // Now make sure all children actually get positioned, sized, and clipped
WinScrollWindow(mWnd, aDx, -aDy, aClipRect ? &rcl : 0, 0, 0, // correctly. If SW_SCROLLCHILDREN was in effect, they may already be.
0, SW_SCROLLCHILDREN | SW_INVALIDATERGN); ConfigureChildren(aConfigurations);
ScrollChildWindows(aDx, aDy);
Update(); Update();
if (hps) if (hps)
ReleaseIfDragHPS(hps); ReleaseIfDragHPS(hps);
return NS_OK;
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------

Просмотреть файл

@ -172,7 +172,9 @@ class nsWindow : public nsBaseWidget,
NS_IMETHOD Invalidate( PRBool aIsSynchronous); NS_IMETHOD Invalidate( PRBool aIsSynchronous);
NS_IMETHOD Invalidate( const nsIntRect & aRect, PRBool aIsSynchronous); NS_IMETHOD Invalidate( const nsIntRect & aRect, PRBool aIsSynchronous);
NS_IMETHOD Update(); NS_IMETHOD Update();
NS_IMETHOD Scroll( PRInt32 aDx, PRInt32 aDy, nsIntRect *aClipRect); virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations);
virtual void Scroll(const nsIntPoint& aDelta, const nsIntRect& aSource,
const nsTArray<Configuration>& aConfigurations);
NS_IMETHOD GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState); NS_IMETHOD GetToggledKeyState(PRUint32 aKeyCode, PRBool* aLEDState);
// Get a HWND or a HPS. // Get a HWND or a HPS.
@ -314,9 +316,6 @@ protected:
HBITMAP CreateTransparencyMask(gfxASurface::gfxImageFormat format, HBITMAP CreateTransparencyMask(gfxASurface::gfxImageFormat format,
PRUint8* aImageData, PRUint32 aWidth, PRUint32 aHeight); 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 // Enumeration of the methods which are accessible on the PM thread
enum { enum {
CREATE, CREATE,