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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+