зеркало из https://github.com/mozilla/gecko-dev.git
Bug 513162 - Widget additions for recycling top level widgets as content containers. r=dbaron.
This commit is contained in:
Родитель
b6fd12e643
Коммит
8c631afae5
|
@ -63,8 +63,8 @@ enum nsViewVisibility {
|
|||
|
||||
// IID for the nsIView interface
|
||||
#define NS_IVIEW_IID \
|
||||
{ 0xe981334b, 0x756e, 0x417a, \
|
||||
{ 0xbf, 0x18, 0x47, 0x4a, 0x2d, 0xfe, 0xc3, 0x87 } }
|
||||
{ 0xdb512cfa, 0xe00c, 0x4eff, \
|
||||
{ 0xa2, 0x9c, 0x18, 0x74, 0x96, 0x63, 0x17, 0x69 } }
|
||||
|
||||
// Public view flags are defined in this file
|
||||
#define NS_VIEW_FLAGS_PUBLIC 0x00FF
|
||||
|
@ -291,6 +291,26 @@ public:
|
|||
nsContentType aWindowType = eContentTypeInherit,
|
||||
nsIWidget* aParentWidget = nsnull);
|
||||
|
||||
/**
|
||||
* Attach/detach a top level widget from this view. When attached, the view
|
||||
* updates the widget's device context and allows the view to begin receiving
|
||||
* gecko events. The underlying base window associated with the widget will
|
||||
* continues to receive events it expects.
|
||||
*
|
||||
* An attached widget will not be destroyed when the view is destroyed,
|
||||
* allowing the recycling of a single top level widget over multiple views.
|
||||
*
|
||||
* @param aWidget The widget to attach to / detach from.
|
||||
*/
|
||||
nsresult AttachToTopLevelWidget(nsIWidget* aWidget);
|
||||
nsresult DetachFromTopLevelWidget();
|
||||
|
||||
/**
|
||||
* Returns a flag indicating whether the view owns it's widget
|
||||
* or is attached to an existing top level widget.
|
||||
*/
|
||||
PRBool IsAttachedToTopLevel() const { return mWidgetIsTopLevel; }
|
||||
|
||||
/**
|
||||
* In 4.0, the "cutout" nature of a view is queryable.
|
||||
* If we believe that all cutout view have a native widget, this
|
||||
|
@ -373,6 +393,7 @@ protected:
|
|||
float mOpacity;
|
||||
PRUint32 mVFlags;
|
||||
nsWeakView* mDeletionObserver;
|
||||
PRBool mWidgetIsTopLevel;
|
||||
|
||||
virtual ~nsIView() {}
|
||||
};
|
||||
|
|
|
@ -144,15 +144,47 @@ static ViewWrapper* GetWrapperFor(nsIWidget* aWidget)
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
//
|
||||
// Main events handler
|
||||
//
|
||||
nsEventStatus HandleEvent(nsGUIEvent *aEvent)
|
||||
{
|
||||
//printf(" %d %d %d (%d,%d) \n", aEvent->widget, aEvent->widgetSupports,
|
||||
// aEvent->message, aEvent->point.x, aEvent->point.y);
|
||||
static nsEventStatus HandleEvent(nsGUIEvent *aEvent)
|
||||
{
|
||||
#if 0
|
||||
printf(" %d %d %d (%d,%d) \n", aEvent->widget, aEvent->widgetSupports,
|
||||
aEvent->message, aEvent->point.x, aEvent->point.y);
|
||||
#endif
|
||||
nsEventStatus result = nsEventStatus_eIgnore;
|
||||
nsView *view = nsView::GetViewFor(aEvent->widget);
|
||||
nsView *view = nsView::GetViewFor(aEvent->widget);
|
||||
|
||||
if (view)
|
||||
{
|
||||
nsCOMPtr<nsIViewManager> vm = view->GetViewManager();
|
||||
vm->DispatchEvent(aEvent, view, &result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Attached widget event helpers
|
||||
static ViewWrapper* GetAttachedWrapperFor(nsIWidget* aWidget)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aWidget, "null widget ptr");
|
||||
return aWidget->GetAttachedViewPtr();
|
||||
}
|
||||
|
||||
static nsView* GetAttachedViewFor(nsIWidget* aWidget)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aWidget, "null widget ptr");
|
||||
|
||||
ViewWrapper* wrapper = GetAttachedWrapperFor(aWidget);
|
||||
if (!wrapper)
|
||||
return nsnull;
|
||||
return wrapper->GetView();
|
||||
}
|
||||
|
||||
// event handler
|
||||
static nsEventStatus AttachedHandleEvent(nsGUIEvent *aEvent)
|
||||
{
|
||||
nsEventStatus result = nsEventStatus_eIgnore;
|
||||
nsView *view = GetAttachedViewFor(aEvent->widget);
|
||||
|
||||
if (view)
|
||||
{
|
||||
|
@ -176,6 +208,7 @@ nsView::nsView(nsViewManager* aViewManager, nsViewVisibility aVisibility)
|
|||
mViewManager = aViewManager;
|
||||
mDirtyRegion = nsnull;
|
||||
mDeletionObserver = nsnull;
|
||||
mWidgetIsTopLevel = PR_FALSE;
|
||||
}
|
||||
|
||||
void nsView::DropMouseGrabbing()
|
||||
|
@ -240,8 +273,21 @@ nsView::~nsView()
|
|||
ViewWrapper* wrapper = GetWrapperFor(mWindow);
|
||||
NS_IF_RELEASE(wrapper);
|
||||
|
||||
mWindow->SetClientData(nsnull);
|
||||
mWindow->Destroy();
|
||||
// If we are not attached to a base window, we're going to tear down our
|
||||
// widget here. However, if we're attached to somebody elses widget, we
|
||||
// want to leave the widget alone: don't reset the client data or call
|
||||
// Destroy. Just clear our event view ptr and free our reference to it.
|
||||
if (mWidgetIsTopLevel) {
|
||||
ViewWrapper* wrapper = GetAttachedWrapperFor(mWindow);
|
||||
NS_IF_RELEASE(wrapper);
|
||||
|
||||
mWindow->SetAttachedViewPtr(nsnull);
|
||||
}
|
||||
else {
|
||||
mWindow->SetClientData(nsnull);
|
||||
mWindow->Destroy();
|
||||
}
|
||||
|
||||
NS_RELEASE(mWindow);
|
||||
}
|
||||
delete mDirtyRegion;
|
||||
|
@ -275,8 +321,13 @@ nsIView* nsIView::GetViewFor(nsIWidget* aWidget)
|
|||
NS_PRECONDITION(nsnull != aWidget, "null widget ptr");
|
||||
|
||||
ViewWrapper* wrapper = GetWrapperFor(aWidget);
|
||||
|
||||
if (!wrapper)
|
||||
wrapper = GetAttachedWrapperFor(aWidget);
|
||||
|
||||
if (wrapper)
|
||||
return wrapper->GetView();
|
||||
return wrapper->GetView();
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
|
@ -354,7 +405,7 @@ nsIntRect nsIView::CalcWidgetBounds(nsWindowType aType)
|
|||
|
||||
if (parentWidget && aType == eWindowType_popup &&
|
||||
IsEffectivelyVisible()) {
|
||||
// put offset into screen coordinates
|
||||
// put offset into screen coordinates. (based on client area origin)
|
||||
nsIntPoint screenPoint = parentWidget->WidgetToScreenOffset();
|
||||
viewBounds += nsPoint(NSIntPixelsToAppUnits(screenPoint.x, p2a),
|
||||
NSIntPixelsToAppUnits(screenPoint.y, p2a));
|
||||
|
@ -390,6 +441,7 @@ void nsView::DoResetWidgetBounds(PRBool aMoveOnly,
|
|||
|
||||
nsIntRect curBounds;
|
||||
mWindow->GetBounds(curBounds);
|
||||
|
||||
nsWindowType type;
|
||||
mWindow->GetWindowType(type);
|
||||
|
||||
|
@ -409,6 +461,7 @@ void nsView::DoResetWidgetBounds(PRBool aMoveOnly,
|
|||
PRBool changedPos = curBounds.TopLeft() != newBounds.TopLeft();
|
||||
PRBool changedSize = curBounds.Size() != newBounds.Size();
|
||||
|
||||
// Child views are never attached to top level widgets, this is safe.
|
||||
if (changedPos) {
|
||||
if (changedSize && !aMoveOnly) {
|
||||
mWindow->Resize(newBounds.x, newBounds.y, newBounds.width, newBounds.height,
|
||||
|
@ -704,6 +757,62 @@ nsresult nsIView::CreateWidget(const nsIID &aWindowIID,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Attach to a top level widget and start receiving mirrored events.
|
||||
nsresult nsIView::AttachToTopLevelWidget(nsIWidget* aWidget)
|
||||
{
|
||||
NS_PRECONDITION(nsnull != aWidget, "null widget ptr");
|
||||
/// XXXjimm This is a temporary workaround to an issue w/document
|
||||
// viewer (bug 513162).
|
||||
nsIView *oldView = GetAttachedViewFor(aWidget);
|
||||
if (oldView) {
|
||||
oldView->DetachFromTopLevelWidget();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDeviceContext> dx;
|
||||
mViewManager->GetDeviceContext(*getter_AddRefs(dx));
|
||||
|
||||
// Note, the previous device context will be released. Detaching
|
||||
// will not restore the old one.
|
||||
nsresult rv = aWidget->AttachViewToTopLevel(::AttachedHandleEvent, dx);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
mWindow = aWidget;
|
||||
NS_ADDREF(mWindow);
|
||||
|
||||
nsView* v = static_cast<nsView*>(this);
|
||||
ViewWrapper* wrapper = new ViewWrapper(v);
|
||||
NS_ADDREF(wrapper);
|
||||
mWindow->SetAttachedViewPtr(wrapper);
|
||||
mWindow->EnableDragDrop(PR_TRUE);
|
||||
mWidgetIsTopLevel = PR_TRUE;
|
||||
|
||||
// Refresh the view bounds
|
||||
nsWindowType type;
|
||||
mWindow->GetWindowType(type);
|
||||
CalcWidgetBounds(type);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Detach this view from an attached widget.
|
||||
nsresult nsIView::DetachFromTopLevelWidget()
|
||||
{
|
||||
NS_PRECONDITION(mWidgetIsTopLevel, "Not attached currently!");
|
||||
NS_PRECONDITION(mWindow, "null mWindow for DetachFromTopLevelWidget!");
|
||||
|
||||
// Release memory for the view wrapper
|
||||
ViewWrapper* wrapper = GetAttachedWrapperFor(mWindow);
|
||||
NS_IF_RELEASE(wrapper);
|
||||
|
||||
mWindow->SetAttachedViewPtr(nsnull);
|
||||
NS_RELEASE(mWindow);
|
||||
|
||||
mWidgetIsTopLevel = PR_FALSE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsView::SetZIndex(PRBool aAuto, PRInt32 aZIndex, PRBool aTopMost)
|
||||
{
|
||||
PRBool oldIsAuto = GetZIndexIsAuto();
|
||||
|
@ -834,6 +943,8 @@ nsIntPoint nsIView::GetScreenPosition() const
|
|||
PRInt32 p2a = dx->AppUnitsPerDevPixel();
|
||||
nsIntPoint ourPoint(NSAppUnitsToIntPixels(toWidgetOffset.x, p2a),
|
||||
NSAppUnitsToIntPixels(toWidgetOffset.y, p2a));
|
||||
// WidgetToScreenOffset is at the origin of the client area of
|
||||
// the widget.
|
||||
screenPoint = ourPoint + widget->WidgetToScreenOffset();
|
||||
}
|
||||
|
||||
|
@ -842,6 +953,9 @@ nsIntPoint nsIView::GetScreenPosition() const
|
|||
|
||||
nsIWidget* nsIView::GetNearestWidget(nsPoint* aOffset) const
|
||||
{
|
||||
// aOffset is based on the view's position, which ignores any chrome on
|
||||
// attached parent widgets.
|
||||
|
||||
nsPoint pt(0, 0);
|
||||
const nsView* v;
|
||||
for (v = static_cast<const nsView*>(this);
|
||||
|
@ -855,9 +969,9 @@ nsIWidget* nsIView::GetNearestWidget(nsPoint* aOffset) const
|
|||
return nsnull;
|
||||
}
|
||||
|
||||
// pt is now the offset from v's origin to this's origin
|
||||
// The widget's origin is the top left corner of v's bounds, which may
|
||||
// not coincide with v's origin
|
||||
// pt is now the offset from v's origin to this view's origin. The widget's
|
||||
// origin is the top left corner of v's bounds, which may not coincide with
|
||||
// the view's origin.
|
||||
if (aOffset) {
|
||||
nsRect vBounds = v->GetBounds();
|
||||
*aOffset = pt + v->GetPosition() - nsPoint(vBounds.x, vBounds.y) +
|
||||
|
|
|
@ -304,6 +304,20 @@ NS_IMETHODIMP nsViewManager::GetWindowDimensions(nscoord *aWidth, nscoord *aHeig
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsViewManager::DoSetWindowDimensions(nscoord aWidth, nscoord aHeight)
|
||||
{
|
||||
nsRect oldDim;
|
||||
nsRect newDim(0, 0, aWidth, aHeight);
|
||||
mRootView->GetDimensions(oldDim);
|
||||
// We care about resizes even when one dimension is already zero.
|
||||
if (!oldDim.IsExactEqual(newDim)) {
|
||||
// Don't resize the widget. It is already being set elsewhere.
|
||||
mRootView->SetDimensions(newDim, PR_TRUE, PR_FALSE);
|
||||
if (mObserver)
|
||||
mObserver->ResizeReflow(mRootView, aWidth, aHeight);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsViewManager::SetWindowDimensions(nscoord aWidth, nscoord aHeight)
|
||||
{
|
||||
if (mRootView) {
|
||||
|
@ -578,6 +592,13 @@ nsViewManager::UpdateWidgetArea(nsView *aWidgetView, nsIWidget* aWidget,
|
|||
const nsRegion &aDamagedRegion,
|
||||
nsView* aIgnoreWidgetView)
|
||||
{
|
||||
#if 0
|
||||
nsRect dbgBounds = aDamagedRegion.GetBounds();
|
||||
printf("UpdateWidgetArea view:%X (%d) widget:%X region: %d, %d, %d, %d\n",
|
||||
aWidgetView, aWidgetView->IsAttachedToTopLevel(),
|
||||
aWidget, dbgBounds.x, dbgBounds.y, dbgBounds.width, dbgBounds.height);
|
||||
#endif
|
||||
|
||||
if (!IsRefreshEnabled()) {
|
||||
// accumulate this rectangle in the view's dirty region, so we can
|
||||
// process it later.
|
||||
|
@ -639,14 +660,19 @@ nsViewManager::UpdateWidgetArea(nsView *aWidgetView, nsIWidget* aWidget,
|
|||
// Don't mess with views that are in completely different view
|
||||
// manager trees
|
||||
if (view->GetViewManager()->RootViewManager() == RootViewManager()) {
|
||||
// get the damage region into 'view's coordinate system
|
||||
// get the damage region into view's coordinate system
|
||||
nsRegion damage = intersection;
|
||||
|
||||
nsPoint offset = view->GetOffsetTo(aWidgetView);
|
||||
damage.MoveBy(-offset);
|
||||
|
||||
// Update the child and it's children
|
||||
UpdateWidgetArea(view, childWidget, damage, aIgnoreWidgetView);
|
||||
|
||||
// GetBounds should compensate for chrome on a toplevel widget
|
||||
nsIntRect bounds;
|
||||
childWidget->GetBounds(bounds);
|
||||
|
||||
nsTArray<nsIntRect> clipRects;
|
||||
childWidget->GetWindowClipRegion(&clipRects);
|
||||
for (PRUint32 i = 0; i < clipRects.Length(); ++i) {
|
||||
|
@ -741,10 +767,9 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
|
|||
{
|
||||
if (aView)
|
||||
{
|
||||
// client area dimensions are set on the view
|
||||
nscoord width = ((nsSizeEvent*)aEvent)->windowSize->width;
|
||||
nscoord height = ((nsSizeEvent*)aEvent)->windowSize->height;
|
||||
width = ((nsSizeEvent*)aEvent)->mWinWidth;
|
||||
height = ((nsSizeEvent*)aEvent)->mWinHeight;
|
||||
|
||||
// The root view may not be set if this is the resize associated with
|
||||
// window creation
|
||||
|
@ -1011,9 +1036,10 @@ NS_IMETHODIMP nsViewManager::DispatchEvent(nsGUIEvent *aEvent,
|
|||
|
||||
nsEventStatus nsViewManager::HandleEvent(nsView* aView, nsGUIEvent* aEvent)
|
||||
{
|
||||
//printf(" %d %d %d %d (%d,%d) \n", this, event->widget, event->widgetSupports,
|
||||
// event->message, event->point.x, event->point.y);
|
||||
|
||||
#if 0
|
||||
printf(" %d %d %d %d (%d,%d) \n", this, event->widget, event->widgetSupports,
|
||||
event->message, event->point.x, event->point.y);
|
||||
#endif
|
||||
// Hold a refcount to the observer. The continued existence of the observer will
|
||||
// delay deletion of this view hierarchy should the event want to cause its
|
||||
// destruction in, say, some JavaScript event handler.
|
||||
|
|
|
@ -209,19 +209,7 @@ private:
|
|||
*/
|
||||
nsIntRect ViewToWidget(nsView *aView, nsView* aWidgetView, const nsRect &aRect) const;
|
||||
|
||||
void DoSetWindowDimensions(nscoord aWidth, nscoord aHeight)
|
||||
{
|
||||
nsRect oldDim;
|
||||
nsRect newDim(0, 0, aWidth, aHeight);
|
||||
mRootView->GetDimensions(oldDim);
|
||||
// We care about resizes even when one dimension is already zero.
|
||||
if (!oldDim.IsExactEqual(newDim)) {
|
||||
// Don't resize the widget. It is already being set elsewhere.
|
||||
mRootView->SetDimensions(newDim, PR_TRUE, PR_FALSE);
|
||||
if (mObserver)
|
||||
mObserver->ResizeReflow(mRootView, aWidth, aHeight);
|
||||
}
|
||||
}
|
||||
void DoSetWindowDimensions(nscoord aWidth, nscoord aHeight);
|
||||
|
||||
// Safety helpers
|
||||
void IncrementUpdateCount() {
|
||||
|
|
Загрузка…
Ссылка в новой задаче