diff --git a/layout/xul/base/public/nsXULPopupManager.h b/layout/xul/base/public/nsXULPopupManager.h index ef55868bb4f..6dc42957cec 100644 --- a/layout/xul/base/public/nsXULPopupManager.h +++ b/layout/xul/base/public/nsXULPopupManager.h @@ -46,6 +46,7 @@ #include "nsIRollupListener.h" #include "nsIMenuRollup.h" #include "nsIDOMKeyListener.h" +#include "nsPoint.h" #include "nsCOMPtr.h" #include "nsTArray.h" #include "nsITimer.h" @@ -359,8 +360,9 @@ public: // This is used by the implementation of nsIDOMXULDocument::GetPopupRangeParent // and nsIDOMXULDocument::GetPopupRangeOffset. void GetMouseLocation(nsIDOMNode** aNode, PRInt32* aOffset); - // set the mouse event that was used to activate the next popup to be opened. - void SetMouseLocation(nsIDOMEvent* aEvent); + // set the mouse event that was used to activate the next popup, specified by + // aPopup, to be opened. + void SetMouseLocation(nsIDOMEvent* aEvent, nsIContent* aPopup); /** * Open a given its content node. If aSelectFirstItem is @@ -626,6 +628,7 @@ protected: // range parent and offset set in SetMouseLocation nsCOMPtr mRangeParent; PRInt32 mRangeOffset; + nsPoint mCachedMousePoint; // set to the currently active menu bar, if any nsMenuBarFrame* mActiveMenuBar; diff --git a/layout/xul/base/src/nsXULPopupManager.cpp b/layout/xul/base/src/nsXULPopupManager.cpp index 69885c734ad..96b97ddca22 100644 --- a/layout/xul/base/src/nsXULPopupManager.cpp +++ b/layout/xul/base/src/nsXULPopupManager.cpp @@ -45,6 +45,7 @@ #include "nsIDOMDocument.h" #include "nsIDOMNSEvent.h" #include "nsIDOMNSUIEvent.h" +#include "nsIPrivateDOMEvent.h" #include "nsEventDispatcher.h" #include "nsCSSFrameConstructor.h" #include "nsLayoutUtils.h" @@ -236,13 +237,40 @@ nsXULPopupManager::GetMouseLocation(nsIDOMNode** aNode, PRInt32* aOffset) } void -nsXULPopupManager::SetMouseLocation(nsIDOMEvent* aEvent) +nsXULPopupManager::SetMouseLocation(nsIDOMEvent* aEvent, nsIContent* aPopup) { + mCachedMousePoint = nsPoint(0, 0); + nsCOMPtr uiEvent = do_QueryInterface(aEvent); - NS_ASSERTION(uiEvent, "Expected an nsIDOMNSUIEvent"); + NS_ASSERTION(!aEvent || uiEvent, "Expected an nsIDOMNSUIEvent"); if (uiEvent) { uiEvent->GetRangeParent(getter_AddRefs(mRangeParent)); uiEvent->GetRangeOffset(&mRangeOffset); + + // get the event coordinates relative to the root frame of the document + // containing the popup. + nsCOMPtr privateEvent(do_QueryInterface(aEvent)); + if (privateEvent) { + NS_ASSERTION(aPopup, "Expected a popup node"); + nsEvent* event; + nsresult rv = privateEvent->GetInternalNSEvent(&event); + if (NS_SUCCEEDED(rv) && event) { + nsIDocument* doc = aPopup->GetCurrentDoc(); + if (doc) { + nsIPresShell* presShell = doc->GetPrimaryShell(); + if (presShell) { + nsPresContext* presContext = presShell->GetPresContext(); + nsIFrame* rootFrame = presShell->GetRootFrame(); + if (rootFrame && presContext) { + nsPoint pnt = + nsLayoutUtils::GetEventCoordinatesRelativeTo(event, rootFrame); + mCachedMousePoint = nsPoint(presContext->AppUnitsToDevPixels(pnt.x), + presContext->AppUnitsToDevPixels(pnt.y)); + } + } + } + } + } } else { mRangeParent = nsnull; @@ -293,6 +321,7 @@ nsXULPopupManager::ShowMenu(nsIContent *aMenu, popupFrame->InitializePopup(aMenu, position, 0, 0, PR_TRUE); if (aAsynchronous) { + SetMouseLocation(nsnull, nsnull); nsCOMPtr event = new nsXULPopupShowingEvent(popupFrame->GetContent(), aMenu, parentIsContextMenu, aSelectFirstItem); @@ -539,7 +568,7 @@ nsXULPopupManager::HidePopupCallback(nsIContent* aPopup, // send the popuphidden event synchronously. This event has no default behaviour. nsEventStatus status = nsEventStatus_eIgnore; - nsEvent event(PR_TRUE, NS_XUL_POPUP_HIDDEN); + nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_HIDDEN, nsnull, nsMouseEvent::eReal); nsEventDispatcher::Dispatch(aPopup, aPopupFrame->PresContext(), &event, nsnull, &status); @@ -678,8 +707,13 @@ nsXULPopupManager::FirePopupShowingEvent(nsIContent* aPopup, // is where those details would be retrieved. This removes the need for // all the globals people keep adding to nsIDOMXULDocument. nsEventStatus status = nsEventStatus_eIgnore; - nsEvent event(PR_TRUE, NS_XUL_POPUP_SHOWING); + nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_SHOWING, nsnull, nsMouseEvent::eReal); + nsPoint pnt; + event.widget = presShell->GetRootFrame()-> + GetClosestView()->GetNearestWidget(&pnt); + event.refPoint = mCachedMousePoint; nsEventDispatcher::Dispatch(aPopup, aPresContext, &event, nsnull, &status); + mCachedMousePoint = nsPoint(0, 0); // it is common to append content to the menu during the popupshowing event. // Flush the notifications so that the frames are up to date before showing @@ -712,7 +746,7 @@ nsXULPopupManager::FirePopupHidingEvent(nsIContent* aPopup, nsCOMPtr presShell = aPresContext->PresShell(); nsEventStatus status = nsEventStatus_eIgnore; - nsEvent event(PR_TRUE, NS_XUL_POPUP_HIDING); + nsMouseEvent event(PR_TRUE, NS_XUL_POPUP_HIDING, nsnull, nsMouseEvent::eReal); nsEventDispatcher::Dispatch(aPopup, aPresContext, &event, nsnull, &status); // get frame again in case it went away diff --git a/toolkit/content/tests/widgets/Makefile.in b/toolkit/content/tests/widgets/Makefile.in index 8a7d5fb8c80..309052fc0a3 100644 --- a/toolkit/content/tests/widgets/Makefile.in +++ b/toolkit/content/tests/widgets/Makefile.in @@ -48,6 +48,7 @@ _TEST_FILES = test_bug360220.xul \ test_bug359754.xul \ test_bug365773.xul \ test_colorpicker_popup.xul \ + test_popup_coords.xul \ $(NULL) libs:: $(_TEST_FILES) diff --git a/toolkit/content/tests/widgets/test_popup_coords.xul b/toolkit/content/tests/widgets/test_popup_coords.xul new file mode 100644 index 00000000000..281149d1a06 --- /dev/null +++ b/toolkit/content/tests/widgets/test_popup_coords.xul @@ -0,0 +1,88 @@ + + + + + + + Popup Tests + + + + + + + + +