Commit 9f9e94ac authored by Peter Weilbacher's avatar Peter Weilbacher
Browse files

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

parent 829e02dc
Loading
Loading
Loading
Loading
+92 −52
Original line number Diff line number Diff line
@@ -79,6 +79,9 @@

#include "imgIContainer.h"

#include "nsTHashtable.h"
#include "nsHashKeys.h"

#include <stdlib.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
// 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);
    }
  }
  return WinEndEnumWindows(hEnum);
}
// 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.

//-------------------------------------------------------------------------
//
// Force a resize of child windows after a scroll to reset hover positions.
//
//-------------------------------------------------------------------------
void nsWindow::ScrollChildWindows(PRInt32 aX, PRInt32 aY)
nsresult
nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
{
  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();
  // 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 NS_OK;
}

//-------------------------------------------------------------------------
//
// 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;
  scrolledWidgets.Init();
  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");
    if (configuration.mBounds.TopLeft() == w->mBounds.TopLeft() + aDelta)
      scrolledWidgets.PutEntry(w);
  }

  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
  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
  // 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;
}

//-------------------------------------------------------------------------
+3 −4
Original line number Diff line number Diff line
@@ -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<Configuration>& aConfigurations);
   virtual void            Scroll(const nsIntPoint& aDelta, const nsIntRect& aSource,
                                  const nsTArray<Configuration>& 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,