From 60cbb66cdc0aec1226f20fdb53652710aeefd06a Mon Sep 17 00:00:00 2001 From: "roc+%cs.cmu.edu" Date: Thu, 13 May 2004 15:39:12 +0000 Subject: [PATCH] Bug 242833. Make nsDOMEvent::GetClientX/Y handle cases where a subdocument's widget is not an ancestor of the event's widget. Also forward all mouse grabbing to the root view manager of a view manager hierarchy so that subdocuments can grab the mouse when an event occurs in an outer document. git-svn-id: svn://10.0.0.236/trunk@156357 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/content/events/src/nsDOMEvent.cpp | 162 ++++++++-------------- mozilla/content/events/src/nsDOMEvent.h | 2 + mozilla/view/src/nsViewManager.cpp | 10 ++ 3 files changed, 68 insertions(+), 106 deletions(-) diff --git a/mozilla/content/events/src/nsDOMEvent.cpp b/mozilla/content/events/src/nsDOMEvent.cpp index aacb9ffcea4..48c01241fec 100644 --- a/mozilla/content/events/src/nsDOMEvent.cpp +++ b/mozilla/content/events/src/nsDOMEvent.cpp @@ -620,162 +620,112 @@ nsDOMEvent::GetReconversionReply(nsReconversionEventReply** aReply) return NS_OK; } - -NS_METHOD nsDOMEvent::GetScreenX(PRInt32* aScreenX) -{ - NS_ENSURE_ARG_POINTER(aScreenX); +nsPoint nsDOMEvent::GetScreenPoint() { if (!mEvent || (mEvent->eventStructType != NS_MOUSE_EVENT && mEvent->eventStructType != NS_POPUP_EVENT && !NS_IS_DRAG_EVENT(mEvent))) { - *aScreenX = 0; - return NS_OK; + return nsPoint(0, 0); } if (!((nsGUIEvent*)mEvent)->widget ) { - *aScreenX = mScreenPoint.x; - return NS_OK; + return mScreenPoint; } - nsRect bounds, offset; - bounds.x = mEvent->refPoint.x; - + nsRect bounds(mEvent->refPoint, nsSize(1, 1)); + nsRect offset; ((nsGUIEvent*)mEvent)->widget->WidgetToScreen ( bounds, offset ); - *aScreenX = offset.x; - + return offset.TopLeft(); +} + +NS_METHOD nsDOMEvent::GetScreenX(PRInt32* aScreenX) +{ + NS_ENSURE_ARG_POINTER(aScreenX); + *aScreenX = GetScreenPoint().x; return NS_OK; } NS_METHOD nsDOMEvent::GetScreenY(PRInt32* aScreenY) { NS_ENSURE_ARG_POINTER(aScreenY); - if (!mEvent || - (mEvent->eventStructType != NS_MOUSE_EVENT && - mEvent->eventStructType != NS_POPUP_EVENT && - !NS_IS_DRAG_EVENT(mEvent))) { - *aScreenY = 0; - return NS_OK; - } - - if (!((nsGUIEvent*)mEvent)->widget ) { - *aScreenY = mScreenPoint.y; - return NS_OK; - } - - nsRect bounds, offset; - bounds.y = mEvent->refPoint.y; - - ((nsGUIEvent*)mEvent)->widget->WidgetToScreen ( bounds, offset ); - *aScreenY = offset.y; - + *aScreenY = GetScreenPoint().y; return NS_OK; } -NS_METHOD nsDOMEvent::GetClientX(PRInt32* aClientX) -{ - NS_ENSURE_ARG_POINTER(aClientX); +nsPoint nsDOMEvent::GetClientPoint() { if (!mEvent || (mEvent->eventStructType != NS_MOUSE_EVENT && mEvent->eventStructType != NS_POPUP_EVENT && !NS_IS_DRAG_EVENT(mEvent)) || !mPresContext) { - *aClientX = 0; - return NS_OK; + return nsPoint(0, 0); } if (!((nsGUIEvent*)mEvent)->widget ) { - *aClientX = mClientPoint.x; - return NS_OK; + return mClientPoint; } //My god, man, there *must* be a better way to do this. - nsIWidget* rootWidget = nsnull; + nsCOMPtr docWidget; nsIPresShell *presShell = mPresContext->GetPresShell(); if (presShell) { nsIViewManager* vm = presShell->GetViewManager(); if (vm) { - vm->GetWidget(&rootWidget); + vm->GetWidget(getter_AddRefs(docWidget)); } } + nsPoint pt = mEvent->refPoint; - nsRect bounds, offset; - offset.x = 0; - - nsIWidget* parent = ((nsGUIEvent*)mEvent)->widget; - //Add extra ref since loop will free one. - NS_IF_ADDREF(parent); - nsIWidget* tmp; - while (rootWidget != parent && nsnull != parent) { + nsCOMPtr eventWidget = ((nsGUIEvent*)mEvent)->widget; + while (eventWidget && docWidget != eventWidget) { nsWindowType windowType; - parent->GetWindowType(windowType); + eventWidget->GetWindowType(windowType); if (windowType == eWindowType_popup) break; - parent->GetBounds(bounds); - offset.x += bounds.x; - tmp = parent; - parent = tmp->GetParent(); - NS_RELEASE(tmp); + nsRect bounds; + eventWidget->GetBounds(bounds); + pt += bounds.TopLeft(); + eventWidget = eventWidget->GetParent(); } - NS_IF_RELEASE(parent); - NS_IF_RELEASE(rootWidget); - *aClientX = mEvent->refPoint.x + offset.x; + if (eventWidget != docWidget) { + // docWidget wasn't on the chain from the event widget to the root + // of the widget tree (or the nearest popup). OK, so now pt is + // relative to eventWidget; to get it relative to docWidget, we + // need to subtract docWidget's offset from eventWidget. + while (docWidget && docWidget != eventWidget) { + nsWindowType windowType; + docWidget->GetWindowType(windowType); + if (windowType == eWindowType_popup) { + // oh dear. the doc and the event were in different popups? + // That shouldn't happen. + NS_NOTREACHED("doc widget and event widget are in different popups. That's dumb."); + break; + } + + nsRect bounds; + docWidget->GetBounds(bounds); + pt -= bounds.TopLeft(); + docWidget = docWidget->GetParent(); + } + } + + return pt; +} + +NS_METHOD nsDOMEvent::GetClientX(PRInt32* aClientX) +{ + NS_ENSURE_ARG_POINTER(aClientX); + *aClientX = GetClientPoint().x; return NS_OK; } NS_METHOD nsDOMEvent::GetClientY(PRInt32* aClientY) { NS_ENSURE_ARG_POINTER(aClientY); - if (!mEvent || - (mEvent->eventStructType != NS_MOUSE_EVENT && - mEvent->eventStructType != NS_POPUP_EVENT && - !NS_IS_DRAG_EVENT(mEvent)) || - !mPresContext) { - *aClientY = 0; - return NS_OK; - } - - if (!((nsGUIEvent*)mEvent)->widget ) { - *aClientY = mClientPoint.y; - return NS_OK; - } - - //My god, man, there *must* be a better way to do this. - nsIWidget* rootWidget = nsnull; - nsIPresShell *presShell = mPresContext->GetPresShell(); - if (presShell) { - nsIViewManager* vm = presShell->GetViewManager(); - if (vm) { - vm->GetWidget(&rootWidget); - } - } - - - nsRect bounds, offset; - offset.y = 0; - - nsIWidget* parent = ((nsGUIEvent*)mEvent)->widget; - //Add extra ref since loop will free one. - NS_IF_ADDREF(parent); - nsIWidget* tmp; - while (rootWidget != parent && nsnull != parent) { - nsWindowType windowType; - parent->GetWindowType(windowType); - if (windowType == eWindowType_popup) - break; - - parent->GetBounds(bounds); - offset.y += bounds.y; - tmp = parent; - parent = tmp->GetParent(); - NS_RELEASE(tmp); - } - NS_IF_RELEASE(parent); - NS_IF_RELEASE(rootWidget); - - *aClientY = mEvent->refPoint.y + offset.y; + *aClientY = GetClientPoint().y; return NS_OK; } diff --git a/mozilla/content/events/src/nsDOMEvent.h b/mozilla/content/events/src/nsDOMEvent.h index 140aee238a7..676e792e3b9 100644 --- a/mozilla/content/events/src/nsDOMEvent.h +++ b/mozilla/content/events/src/nsDOMEvent.h @@ -218,6 +218,8 @@ protected: const char* GetEventName(PRUint32 aEventType); already_AddRefed GetTargetFromFrame(); void AllocateEvent(const nsAString& aEventType); + nsPoint GetClientPoint(); + nsPoint GetScreenPoint(); nsEvent* mEvent; nsCOMPtr mPresContext; diff --git a/mozilla/view/src/nsViewManager.cpp b/mozilla/view/src/nsViewManager.cpp index 0e89fd6dfd7..bf7dd5f48c8 100644 --- a/mozilla/view/src/nsViewManager.cpp +++ b/mozilla/view/src/nsViewManager.cpp @@ -2233,6 +2233,11 @@ nsEventStatus nsViewManager::HandleEvent(nsView* aView, nsGUIEvent* aEvent, PRBo NS_IMETHODIMP nsViewManager::GrabMouseEvents(nsIView *aView, PRBool &aResult) { + nsView* rootParent = RootView()->GetParent(); + if (rootParent) { + return rootParent->GetViewManager()->GrabMouseEvents(aView, aResult); + } + // Along with nsView::SetVisibility, we enforce that the mouse grabber // can never be a hidden view. if (aView && NS_STATIC_CAST(nsView*, aView)->GetVisibility() @@ -2262,6 +2267,11 @@ NS_IMETHODIMP nsViewManager::GrabKeyEvents(nsIView *aView, PRBool &aResult) NS_IMETHODIMP nsViewManager::GetMouseEventGrabber(nsIView *&aView) { + nsView* rootParent = RootView()->GetParent(); + if (rootParent) { + return rootParent->GetViewManager()->GetMouseEventGrabber(aView); + } + aView = mMouseGrabber; return NS_OK; }